Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
This commit is contained in:
Cyrill Leutwiler
2025-07-15 10:15:30 +02:00
parent a0396dd6d0
commit 94dda20880
13 changed files with 128 additions and 79 deletions
+7 -7
View File
@@ -1,10 +1,10 @@
{
"Baseline": 939,
"Computation": 2282,
"DivisionArithmetics": 8849,
"ERC20": 18308,
"Events": 1640,
"FibonacciIterative": 1497,
"Baseline": 945,
"Computation": 2308,
"DivisionArithmetics": 2334,
"ERC20": 21363,
"Events": 1677,
"FibonacciIterative": 1516,
"Flipper": 2099,
"SHA1": 8243
"SHA1": 8268
}
@@ -15,6 +15,8 @@ use crate::optimizer::settings::size_level::SizeLevel;
use crate::optimizer::Optimizer;
use crate::polkavm::context::attribute::Attribute;
use crate::polkavm::context::pointer::Pointer;
use crate::polkavm::context::Context;
use crate::polkavm::Dependency;
use self::declaration::Declaration;
use self::r#return::Return;
@@ -28,7 +30,9 @@ pub struct Function<'ctx> {
/// The LLVM function declaration.
declaration: Declaration<'ctx>,
/// The stack representation.
stack: HashMap<String, Pointer<'ctx>>,
stack: HashMap<String, u64>,
/// The stack variables pointer.
stack_variables: Pointer<'ctx>,
/// The return value entity.
r#return: Return<'ctx>,
@@ -56,11 +60,14 @@ impl<'ctx> Function<'ctx> {
entry_block: inkwell::basic_block::BasicBlock<'ctx>,
return_block: inkwell::basic_block::BasicBlock<'ctx>,
stack_variables: Pointer<'ctx>,
) -> Self {
Self {
name,
declaration,
stack: HashMap::with_capacity(Self::STACK_HASHMAP_INITIAL_CAPACITY),
stack_variables,
r#return,
entry_block,
@@ -210,22 +217,49 @@ impl<'ctx> Function<'ctx> {
/// Saves the pointer to a stack variable, returning the pointer to the shadowed variable,
/// if it exists.
pub fn insert_stack_pointer(
pub fn insert_stack_pointer<D: Dependency + Clone>(
&mut self,
context: &mut Context<'ctx, D>,
name: String,
pointer: Pointer<'ctx>,
) -> Option<Pointer<'ctx>> {
self.stack.insert(name, pointer)
) -> Pointer<'ctx> {
let pointer_name = format!("{}_stack_pointer", &name);
let len = self.stack.len();
let index = *self.stack.entry(name).or_insert_with(|| len as u64);
let indices = &[
context.xlen_type().const_zero(),
context.xlen_type().const_int(index, false),
];
context.build_gep(
self.stack_variables,
indices,
context.word_type(),
&pointer_name,
)
}
/// Gets the pointer to a stack variable.
pub fn get_stack_pointer(&self, name: &str) -> Option<Pointer<'ctx>> {
self.stack.get(name).copied()
}
pub fn get_stack_pointer<D: Dependency + Clone>(
&self,
context: &mut Context<'ctx, D>,
name: String,
) -> Pointer<'ctx> {
let pointer_name = format!("{}_stack_pointer", &name);
let index = *self
.stack
.get(&name)
.unwrap_or_else(|| panic!("stack pointer access prior to insertion: {name}"));
let indices = &[
context.xlen_type().const_zero(),
context.xlen_type().const_int(index, false),
];
/// Removes the pointer to a stack variable.
pub fn remove_stack_pointer(&mut self, name: &str) {
self.stack.remove(name);
context.build_gep(
self.stack_variables,
indices,
context.word_type(),
&pointer_name,
)
}
/// Returns the return entity representation.
@@ -48,6 +48,7 @@ where
function_type,
0,
Some(inkwell::module::Linkage::External),
1024,
)?;
self.inner.declare(context)
@@ -145,6 +145,7 @@ where
entry_function_type,
0,
Some(inkwell::module::Linkage::External),
0,
)?;
context.declare_global(
@@ -48,6 +48,7 @@ where
function_type,
0,
Some(inkwell::module::Linkage::External),
1024,
)?;
self.inner.declare(context)
+38 -4
View File
@@ -463,6 +463,7 @@ where
r#type: inkwell::types::FunctionType<'ctx>,
return_values_length: usize,
linkage: Option<inkwell::module::Linkage>,
stack_variables: u32,
) -> anyhow::Result<Rc<RefCell<Function<'ctx>>>> {
let value = self.module().add_function(name, r#type, linkage);
@@ -484,15 +485,30 @@ where
let entry_block = self.llvm.append_basic_block(value, "entry");
let return_block = self.llvm.append_basic_block(value, "return");
self.builder().position_at_end(entry_block);
let stack_variables_pointer = self.build_alloca(
self.word_type().array_type(stack_variables),
"stack_variables",
);
let r#return = match return_values_length {
0 => FunctionReturn::none(),
1 => {
self.set_basic_block(entry_block);
let pointer = self.build_alloca(self.word_type(), "return_pointer");
FunctionReturn::primitive(pointer)
//self.set_basic_block(entry_block);
//let pointer = self
// .current_function()
// .borrow_mut()
// .insert_stack_pointer(self, format!("{name}_return_pointer"));
FunctionReturn::primitive(self.build_gep(
stack_variables_pointer,
&[self.xlen_type().const_zero(), self.xlen_type().const_zero()],
self.word_type(),
"return_pointer",
))
}
size => {
self.set_basic_block(entry_block);
//self.set_basic_block(entry_block);
let pointer = self.build_alloca(
self.structure_type(
vec![self.word_type().as_basic_type_enum(); size].as_slice(),
@@ -509,6 +525,7 @@ where
r#return,
entry_block,
return_block,
stack_variables_pointer,
);
Function::set_default_attributes(self.llvm, function.declaration(), &self.optimizer);
let function = Rc::new(RefCell::new(function));
@@ -736,6 +753,23 @@ where
pointer
}
pub fn variable_decl<T: BasicType<'ctx> + Clone + Copy>(
&self,
r#type: T,
name: &str,
) -> Pointer<'ctx> {
let pointer = self.builder.build_alloca(r#type, name).unwrap();
pointer
.as_instruction()
.unwrap()
.set_alignment(revive_common::BYTE_LENGTH_STACK_ALIGN as u32)
.expect("Alignment is valid");
Pointer::new(r#type, AddressSpace::Stack, pointer)
}
/// Truncate `address` to the ethereum address length and store it as bytes on the stack.
/// Builds an aligned stack allocation at the current position.
/// Use this if [`build_alloca_at_entry`] might change program semantics.
/// Otherwise, alloca should always be built at the function prelude!
@@ -35,6 +35,7 @@ where
Self::r#type(context),
0,
Some(inkwell::module::Linkage::External),
0,
)?;
let mut attributes = Self::ATTRIBUTES.to_vec();
@@ -40,6 +40,7 @@ pub fn check_attribute_null_pointer_is_invalid() {
.fn_type(&[context.word_type().into()], false),
1,
Some(inkwell::module::Linkage::External),
16,
)
.expect("Failed to add function");
assert!(!function
@@ -63,6 +64,7 @@ pub fn check_attribute_optimize_for_size_mode_3() {
.fn_type(&[context.word_type().into()], false),
1,
Some(inkwell::module::Linkage::External),
16,
)
.expect("Failed to add function");
assert!(!function
@@ -86,6 +88,7 @@ pub fn check_attribute_optimize_for_size_mode_z() {
.fn_type(&[context.word_type().into()], false),
1,
Some(inkwell::module::Linkage::External),
16,
)
.expect("Failed to add function");
assert!(function
@@ -109,6 +112,7 @@ pub fn check_attribute_min_size_mode_3() {
.fn_type(&[context.word_type().into()], false),
1,
Some(inkwell::module::Linkage::External),
16,
)
.expect("Failed to add function");
assert!(!function
@@ -132,6 +136,7 @@ pub fn check_attribute_min_size_mode_z() {
.fn_type(&[context.word_type().into()], false),
1,
Some(inkwell::module::Linkage::External),
16,
)
.expect("Failed to add function");
assert!(function
+4 -18
View File
@@ -130,15 +130,8 @@ where
let identifier = self.bindings.remove(0);
let pointer = context
.current_function()
.borrow()
.get_stack_pointer(identifier.inner.as_str())
.ok_or_else(|| {
anyhow::anyhow!(
"{} Assignment to an undeclared variable `{}`",
identifier.location,
identifier.inner,
)
})?;
.borrow_mut()
.get_stack_pointer(context, identifier.inner.clone());
context.build_store(pointer, value.access(context)?)?;
return Ok(());
}
@@ -165,15 +158,8 @@ where
let binding_pointer = context
.current_function()
.borrow()
.get_stack_pointer(binding.inner.as_str())
.ok_or_else(|| {
anyhow::anyhow!(
"{} Assignment to an undeclared variable `{}`",
binding.location,
binding.inner,
)
})?;
.borrow_mut()
.get_stack_pointer(context, binding.inner.clone());
let value = context.build_load(
field_pointer,
format!("assignment_binding_{index}_value").as_str(),
@@ -123,11 +123,8 @@ impl Expression {
let pointer = context
.current_function()
.borrow()
.get_stack_pointer(&id)
.ok_or_else(|| {
anyhow::anyhow!("{} Undeclared variable `{}`", identifier.location, id)
})?;
.borrow_mut()
.get_stack_pointer(context, id.clone());
let constant = context.current_function().borrow().yul().get_constant(&id);
@@ -212,6 +212,7 @@ where
function_type,
self.result.len(),
Some(inkwell::module::Linkage::External),
1024,
)?;
revive_llvm_context::PolkaVMFunction::set_attributes(
context.llvm(),
@@ -244,7 +245,7 @@ where
context
.current_function()
.borrow_mut()
.insert_stack_pointer(identifier.inner, pointer);
.insert_stack_pointer(context, identifier.inner);
}
revive_llvm_context::PolkaVMFunctionReturn::Compound { pointer, .. } => {
for (index, identifier) in self.result.into_iter().enumerate() {
@@ -264,25 +265,24 @@ where
context
.current_function()
.borrow_mut()
.insert_stack_pointer(identifier.inner.clone(), pointer);
.insert_stack_pointer(context, identifier.inner.clone());
}
}
};
let argument_types: Vec<_> = self
.arguments
.iter()
.map(|argument| {
let yul_type = argument.r#type.to_owned().unwrap_or_default();
yul_type.into_llvm(context)
})
.collect();
//let argument_types: Vec<_> = self
// .arguments
// .iter()
// .map(|argument| {
// let yul_type = argument.r#type.to_owned().unwrap_or_default();
// yul_type.into_llvm(context)
// })
// .collect();
for (index, argument) in self.arguments.iter().enumerate() {
let pointer = context.build_alloca(argument_types[index], argument.inner.as_str());
context
let pointer = context
.current_function()
.borrow_mut()
.insert_stack_pointer(argument.inner.clone(), pointer);
.insert_stack_pointer(context, argument.inner.clone());
context.build_store(
pointer,
context.current_function().borrow().get_nth_param(index),
@@ -104,11 +104,10 @@ where
context.set_debug_location(self.location.line, 0, None)?;
let identifier_type = identifier.r#type.clone().unwrap_or_default();
let r#type = identifier_type.into_llvm(context);
let pointer = context.build_alloca(r#type, identifier.inner.as_str());
context
let pointer = context
.current_function()
.borrow_mut()
.insert_stack_pointer(identifier.inner.clone(), pointer);
.insert_stack_pointer(context, identifier.inner.clone());
let value = if let Some(expression) = self.expression {
match expression.into_llvm(context)? {
@@ -140,15 +139,11 @@ where
.to_owned()
.unwrap_or_default()
.into_llvm(context);
let pointer = context.build_alloca(
yul_type.as_basic_type_enum(),
format!("binding_{index}_pointer").as_str(),
);
context.build_store(pointer, yul_type.const_zero())?;
context
let pointer = context
.current_function()
.borrow_mut()
.insert_stack_pointer(binding.inner.to_owned(), pointer);
.insert_stack_pointer(context, binding.inner.to_owned());
context.build_store(pointer, yul_type.const_zero())?;
}
let expression = match self.expression.take() {
@@ -203,14 +198,7 @@ where
let pointer = context
.current_function()
.borrow_mut()
.get_stack_pointer(binding.inner.as_str())
.ok_or_else(|| {
anyhow::anyhow!(
"{} Assignment to an undeclared variable `{}`",
binding.location,
binding.inner
)
})?;
.get_stack_pointer(context, binding.inner.to_owned());
context.build_store(pointer, value)?;
}
+4 -3
View File
@@ -70,10 +70,11 @@ impl Type {
D: revive_llvm_context::PolkaVMDependency + Clone,
{
match self {
Self::Bool => context.integer_type(revive_common::BIT_LENGTH_BOOLEAN),
Self::Int(bitlength) => context.integer_type(bitlength),
//Self::Bool => context.integer_type(revive_common::BIT_LENGTH_BOOLEAN),
//Self::Int(bitlength) => context.integer_type(bitlength),
Self::UInt(bitlength) => context.integer_type(bitlength),
Self::Custom(_) => context.word_type(),
//Self::Custom(_) => context.word_type(),
_ => unreachable!("no other YUL type is supported"),
}
}
}