Compare commits

...

1 Commits

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