diff --git a/crates/integration/codesize.json b/crates/integration/codesize.json index 11e9545..1d35c89 100644 --- a/crates/integration/codesize.json +++ b/crates/integration/codesize.json @@ -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 } \ No newline at end of file diff --git a/crates/llvm-context/src/polkavm/context/function/mod.rs b/crates/llvm-context/src/polkavm/context/function/mod.rs index 15a3222..d089977 100644 --- a/crates/llvm-context/src/polkavm/context/function/mod.rs +++ b/crates/llvm-context/src/polkavm/context/function/mod.rs @@ -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>, + stack: HashMap, + /// 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( &mut self, + context: &mut Context<'ctx, D>, name: String, - pointer: Pointer<'ctx>, - ) -> Option> { - 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> { - self.stack.get(name).copied() - } + pub fn get_stack_pointer( + &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. diff --git a/crates/llvm-context/src/polkavm/context/function/runtime/deploy_code.rs b/crates/llvm-context/src/polkavm/context/function/runtime/deploy_code.rs index 279b1e8..612fe22 100644 --- a/crates/llvm-context/src/polkavm/context/function/runtime/deploy_code.rs +++ b/crates/llvm-context/src/polkavm/context/function/runtime/deploy_code.rs @@ -48,6 +48,7 @@ where function_type, 0, Some(inkwell::module::Linkage::External), + 1024, )?; self.inner.declare(context) diff --git a/crates/llvm-context/src/polkavm/context/function/runtime/entry.rs b/crates/llvm-context/src/polkavm/context/function/runtime/entry.rs index ae40a99..92c7f33 100644 --- a/crates/llvm-context/src/polkavm/context/function/runtime/entry.rs +++ b/crates/llvm-context/src/polkavm/context/function/runtime/entry.rs @@ -145,6 +145,7 @@ where entry_function_type, 0, Some(inkwell::module::Linkage::External), + 0, )?; context.declare_global( diff --git a/crates/llvm-context/src/polkavm/context/function/runtime/runtime_code.rs b/crates/llvm-context/src/polkavm/context/function/runtime/runtime_code.rs index 8cf1435..d8c6a0d 100644 --- a/crates/llvm-context/src/polkavm/context/function/runtime/runtime_code.rs +++ b/crates/llvm-context/src/polkavm/context/function/runtime/runtime_code.rs @@ -48,6 +48,7 @@ where function_type, 0, Some(inkwell::module::Linkage::External), + 1024, )?; self.inner.declare(context) diff --git a/crates/llvm-context/src/polkavm/context/mod.rs b/crates/llvm-context/src/polkavm/context/mod.rs index 4560bc2..3928576 100644 --- a/crates/llvm-context/src/polkavm/context/mod.rs +++ b/crates/llvm-context/src/polkavm/context/mod.rs @@ -463,6 +463,7 @@ where r#type: inkwell::types::FunctionType<'ctx>, return_values_length: usize, linkage: Option, + stack_variables: u32, ) -> anyhow::Result>>> { 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 + 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! diff --git a/crates/llvm-context/src/polkavm/context/runtime.rs b/crates/llvm-context/src/polkavm/context/runtime.rs index 1617eb0..948647a 100644 --- a/crates/llvm-context/src/polkavm/context/runtime.rs +++ b/crates/llvm-context/src/polkavm/context/runtime.rs @@ -35,6 +35,7 @@ where Self::r#type(context), 0, Some(inkwell::module::Linkage::External), + 0, )?; let mut attributes = Self::ATTRIBUTES.to_vec(); diff --git a/crates/llvm-context/src/polkavm/context/tests.rs b/crates/llvm-context/src/polkavm/context/tests.rs index 9060a3d..ab977a8 100644 --- a/crates/llvm-context/src/polkavm/context/tests.rs +++ b/crates/llvm-context/src/polkavm/context/tests.rs @@ -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 diff --git a/crates/yul/src/parser/statement/assignment.rs b/crates/yul/src/parser/statement/assignment.rs index c3079e2..30a5b15 100644 --- a/crates/yul/src/parser/statement/assignment.rs +++ b/crates/yul/src/parser/statement/assignment.rs @@ -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(), diff --git a/crates/yul/src/parser/statement/expression/mod.rs b/crates/yul/src/parser/statement/expression/mod.rs index 0bc0bd1..0d1c372 100644 --- a/crates/yul/src/parser/statement/expression/mod.rs +++ b/crates/yul/src/parser/statement/expression/mod.rs @@ -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); diff --git a/crates/yul/src/parser/statement/function_definition.rs b/crates/yul/src/parser/statement/function_definition.rs index e776e4b..f24d51b 100644 --- a/crates/yul/src/parser/statement/function_definition.rs +++ b/crates/yul/src/parser/statement/function_definition.rs @@ -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), diff --git a/crates/yul/src/parser/statement/variable_declaration.rs b/crates/yul/src/parser/statement/variable_declaration.rs index fdf917e..93bf92e 100644 --- a/crates/yul/src/parser/statement/variable_declaration.rs +++ b/crates/yul/src/parser/statement/variable_declaration.rs @@ -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)?; } diff --git a/crates/yul/src/parser/type.rs b/crates/yul/src/parser/type.rs index ec4d8c4..8f7928a 100644 --- a/crates/yul/src/parser/type.rs +++ b/crates/yul/src/parser/type.rs @@ -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"), } } }