From 52bf16a3833c519f75e81dc4f61aa6dcf6b64abb Mon Sep 17 00:00:00 2001 From: Cyrill Leutwiler Date: Thu, 17 Apr 2025 12:43:26 +0200 Subject: [PATCH] wip Signed-off-by: Cyrill Leutwiler --- crates/integration/codesize.json | 10 +-- .../llvm-context/src/polkavm/context/mod.rs | 62 ++++++++++++++----- .../src/polkavm/context/pointer/heap.rs | 19 ++++-- crates/llvm-context/src/polkavm/evm/memory.rs | 5 +- .../llvm-context/src/polkavm/evm/storage.rs | 4 +- .../src/yul/parser/statement/assignment.rs | 25 ++++++-- .../src/yul/parser/statement/block.rs | 2 +- .../statement/expression/function_call/mod.rs | 14 +++-- .../yul/parser/statement/expression/mod.rs | 2 +- .../src/yul/parser/statement/for_loop.rs | 2 +- .../yul/parser/statement/if_conditional.rs | 2 +- .../src/yul/parser/statement/switch/mod.rs | 2 +- .../parser/statement/variable_declaration.rs | 9 ++- 13 files changed, 112 insertions(+), 46 deletions(-) diff --git a/crates/integration/codesize.json b/crates/integration/codesize.json index 28819e3..985982f 100644 --- a/crates/integration/codesize.json +++ b/crates/integration/codesize.json @@ -1,10 +1,10 @@ { "Baseline": 950, - "Computation": 2222, - "DivisionArithmetics": 8802, - "ERC20": 17602, + "Computation": 2262, + "DivisionArithmetics": 8915, + "ERC20": 17233, "Events": 1628, "FibonacciIterative": 1485, - "Flipper": 2082, - "SHA1": 8230 + "Flipper": 2132, + "SHA1": 8381 } \ No newline at end of file diff --git a/crates/llvm-context/src/polkavm/context/mod.rs b/crates/llvm-context/src/polkavm/context/mod.rs index d58623c..6d65f21 100644 --- a/crates/llvm-context/src/polkavm/context/mod.rs +++ b/crates/llvm-context/src/polkavm/context/mod.rs @@ -773,27 +773,49 @@ where .into()) } - /// Builds a stack load instruction. + /// Builds a stack load instruction with a direct assignment. /// Sets the alignment to 256 bits for the stack and 1 bit for the heap, parent, and child. - pub fn build_load( + pub fn build_load_assign( &self, pointer: Pointer<'ctx>, name: &str, - ) -> anyhow::Result> { + assignment_pointer: &mut Option>, + ) -> anyhow::Result>> { match pointer.address_space { AddressSpace::Heap => { - let name = >::NAME; let declaration = >::declaration(self); - let arguments = [self - .builder() - .build_ptr_to_int(pointer.value, self.xlen_type(), "offset_ptrtoint")? - .as_basic_value_enum()]; - Ok(self - .build_call(declaration, &arguments, "heap_load") - .unwrap_or_else(|| { - panic!("revive runtime function {name} should return a value") - })) + match assignment_pointer.take() { + Some(assignment_pointer) => { + let arguments = [ + self.builder() + .build_ptr_to_int( + pointer.value, + self.xlen_type(), + "offset_ptrtoint", + )? + .as_basic_value_enum(), + assignment_pointer.into(), + ]; + self.build_call(declaration, &arguments, "heap_load"); + Ok(None) + } + None => { + let pointer = self.build_alloca_at_entry(self.word_type(), "pointer"); + let arguments = [ + self.builder() + .build_ptr_to_int( + pointer.value, + self.xlen_type(), + "offset_ptrtoint", + )? + .as_basic_value_enum(), + pointer.value.into(), + ]; + self.build_call(declaration, &arguments, "heap_load"); + Ok(Some(self.build_load(pointer, "storage_value")?)) + } + } } AddressSpace::Stack => { let value = self @@ -806,11 +828,23 @@ where .set_alignment(revive_common::BYTE_LENGTH_STACK_ALIGN as u32) .expect("Alignment is valid"); - Ok(value) + Ok(Some(value)) } } } + /// Builds a stack load instruction. + /// Sets the alignment to 256 bits for the stack and 1 bit for the heap, parent, and child. + pub fn build_load( + &self, + pointer: Pointer<'ctx>, + name: &str, + ) -> anyhow::Result> { + Ok(self + .build_load_assign(pointer, name, &mut None)? + .expect("without an assignment pointer loads return a value")) + } + /// Builds a stack store instruction. /// Sets the alignment to 256 bits for the stack and 1 bit for the heap, parent, and child. pub fn build_store(&self, pointer: Pointer<'ctx>, value: V) -> anyhow::Result<()> diff --git a/crates/llvm-context/src/polkavm/context/pointer/heap.rs b/crates/llvm-context/src/polkavm/context/pointer/heap.rs index a143e89..e2dc49a 100644 --- a/crates/llvm-context/src/polkavm/context/pointer/heap.rs +++ b/crates/llvm-context/src/polkavm/context/pointer/heap.rs @@ -2,6 +2,8 @@ use inkwell::values::BasicValueEnum; +use crate::polkavm::context::address_space::AddressSpace; +use crate::polkavm::context::pointer::Pointer; use crate::polkavm::context::runtime::RuntimeFunction; use crate::polkavm::context::Context; use crate::polkavm::Dependency; @@ -17,9 +19,13 @@ where const NAME: &'static str = "__revive_load_heap_word"; fn r#type<'ctx>(context: &Context<'ctx, D>) -> inkwell::types::FunctionType<'ctx> { - context - .word_type() - .fn_type(&[context.xlen_type().into()], false) + context.void_type().fn_type( + &[ + context.xlen_type().into(), + context.llvm().ptr_type(Default::default()).into(), + ], + false, + ) } fn emit_body<'ctx>( @@ -27,6 +33,7 @@ where context: &mut Context<'ctx, D>, ) -> anyhow::Result>> { let offset = Self::paramater(context, 0).into_int_value(); + let assignment_pointer = Self::paramater(context, 1).into_pointer_value(); let length = context .xlen_type() .const_int(revive_common::BYTE_LENGTH_WORD as u64, false); @@ -42,7 +49,11 @@ where .expect("Alignment is valid"); let swapped_value = context.build_byte_swap(value)?; - Ok(Some(swapped_value)) + context.build_store( + Pointer::new(context.word_type(), AddressSpace::Stack, assignment_pointer), + swapped_value, + )?; + Ok(None) } } diff --git a/crates/llvm-context/src/polkavm/evm/memory.rs b/crates/llvm-context/src/polkavm/evm/memory.rs index 9182f08..ee351ba 100644 --- a/crates/llvm-context/src/polkavm/evm/memory.rs +++ b/crates/llvm-context/src/polkavm/evm/memory.rs @@ -29,7 +29,8 @@ where pub fn load<'ctx, D>( context: &mut Context<'ctx, D>, offset: inkwell::values::IntValue<'ctx>, -) -> anyhow::Result> + assignment_pointer: &mut Option>, +) -> anyhow::Result>> where D: Dependency + Clone, { @@ -40,7 +41,7 @@ where offset, "memory_load_pointer", ); - context.build_load(pointer, "memory_load_result") + context.build_load_assign(pointer, "memory_load_result", assignment_pointer) } /// Translates the `mstore` instruction. diff --git a/crates/llvm-context/src/polkavm/evm/storage.rs b/crates/llvm-context/src/polkavm/evm/storage.rs index 0f5c3f0..8505301 100644 --- a/crates/llvm-context/src/polkavm/evm/storage.rs +++ b/crates/llvm-context/src/polkavm/evm/storage.rs @@ -13,14 +13,14 @@ use crate::PolkaVMStoreTransientStorageWordFunction; pub fn load<'ctx, D>( context: &mut Context<'ctx, D>, position: &PolkaVMArgument<'ctx>, - assignment_pointer: Option>, + assignment_pointer: &mut Option>, ) -> anyhow::Result>> where D: Dependency + Clone, { let _name = >::NAME; let declaration = >::declaration(context); - match assignment_pointer { + match assignment_pointer.take() { Some(assignment_pointer) => { let arguments = [ position.as_pointer(context)?.value.into(), diff --git a/crates/solidity/src/yul/parser/statement/assignment.rs b/crates/solidity/src/yul/parser/statement/assignment.rs index 6937a09..ecfd581 100644 --- a/crates/solidity/src/yul/parser/statement/assignment.rs +++ b/crates/solidity/src/yul/parser/statement/assignment.rs @@ -121,11 +121,6 @@ where ) -> anyhow::Result<()> { context.set_debug_location(self.location.line, 0, None)?; - let value = match self.initializer.into_llvm(context, None)? { - Some(value) => value, - None => return Ok(()), - }; - if self.bindings.len() == 1 { let identifier = self.bindings.remove(0); let pointer = context @@ -139,9 +134,27 @@ where identifier.inner, ) })?; - context.build_store(pointer, value.access(context)?)?; + + let mut assignment_pointer = Some(pointer.value); + let value = match self + .initializer + .into_llvm(context, &mut assignment_pointer)? + { + Some(value) => value, + None => return Ok(()), + }; + + if assignment_pointer.is_some() { + context.build_store(pointer, value.access(context)?)?; + } + return Ok(()); } + + let value = match self.initializer.into_llvm(context, &mut None)? { + Some(value) => value, + None => return Ok(()), + }; let value = value.access(context)?; let llvm_type = value.into_struct_value().get_type(); let tuple_pointer = context.build_alloca(llvm_type, "assignment_pointer"); diff --git a/crates/solidity/src/yul/parser/statement/block.rs b/crates/solidity/src/yul/parser/statement/block.rs index 7b1bbf4..26881be 100644 --- a/crates/solidity/src/yul/parser/statement/block.rs +++ b/crates/solidity/src/yul/parser/statement/block.rs @@ -184,7 +184,7 @@ where block.into_llvm(context)?; } Statement::Expression(expression) => { - expression.into_llvm(context, None)?; + expression.into_llvm(context, &mut None)?; } Statement::VariableDeclaration(statement) => statement.into_llvm(context)?, Statement::Assignment(statement) => statement.into_llvm(context)?, diff --git a/crates/solidity/src/yul/parser/statement/expression/function_call/mod.rs b/crates/solidity/src/yul/parser/statement/expression/function_call/mod.rs index ad3b5c9..6ed45fa 100644 --- a/crates/solidity/src/yul/parser/statement/expression/function_call/mod.rs +++ b/crates/solidity/src/yul/parser/statement/expression/function_call/mod.rs @@ -118,7 +118,7 @@ impl FunctionCall { pub fn into_llvm<'ctx, D>( mut self, context: &mut revive_llvm_context::PolkaVMContext<'ctx, D>, - assignment_pointer: Option>, + assignment_pointer: &mut Option>, ) -> anyhow::Result>> where D: revive_llvm_context::PolkaVMDependency + Clone, @@ -130,7 +130,7 @@ impl FunctionCall { let mut values = Vec::with_capacity(self.arguments.len()); for argument in self.arguments.into_iter().rev() { let value = argument - .into_llvm(context, None)? + .into_llvm(context, &mut None)? .expect("Always exists") .access(context)?; values.push(value); @@ -417,8 +417,8 @@ impl FunctionCall { revive_llvm_context::polkavm_evm_memory::load( context, arguments[0].into_int_value(), + assignment_pointer, ) - .map(Some) } Name::MStore => { let arguments = self.pop_arguments_llvm::(context)?; @@ -994,7 +994,7 @@ impl FunctionCall { for expression in self.arguments.drain(0..N).rev() { arguments.push( expression - .into_llvm(context, None)? + .into_llvm(context, &mut None)? .expect("Always exists") .access(context)?, ); @@ -1014,7 +1014,11 @@ impl FunctionCall { { let mut arguments = Vec::with_capacity(N); for expression in self.arguments.drain(0..N).rev() { - arguments.push(expression.into_llvm(context, None)?.expect("Always exists")); + arguments.push( + expression + .into_llvm(context, &mut None)? + .expect("Always exists"), + ); } arguments.reverse(); diff --git a/crates/solidity/src/yul/parser/statement/expression/mod.rs b/crates/solidity/src/yul/parser/statement/expression/mod.rs index b5dde2f..4243862 100644 --- a/crates/solidity/src/yul/parser/statement/expression/mod.rs +++ b/crates/solidity/src/yul/parser/statement/expression/mod.rs @@ -101,7 +101,7 @@ impl Expression { pub fn into_llvm<'ctx, D>( self, context: &mut revive_llvm_context::PolkaVMContext<'ctx, D>, - assignment_pointer: Option>, + assignment_pointer: &mut Option>, ) -> anyhow::Result>> where D: revive_llvm_context::PolkaVMDependency + Clone, diff --git a/crates/solidity/src/yul/parser/statement/for_loop.rs b/crates/solidity/src/yul/parser/statement/for_loop.rs index af3a7a7..f90a24c 100644 --- a/crates/solidity/src/yul/parser/statement/for_loop.rs +++ b/crates/solidity/src/yul/parser/statement/for_loop.rs @@ -76,7 +76,7 @@ where context.set_basic_block(condition_block); let condition = self .condition - .into_llvm(context, None)? + .into_llvm(context, &mut None)? .expect("Always exists") .access(context)? .into_int_value(); diff --git a/crates/solidity/src/yul/parser/statement/if_conditional.rs b/crates/solidity/src/yul/parser/statement/if_conditional.rs index 69543f3..8bc19cc 100644 --- a/crates/solidity/src/yul/parser/statement/if_conditional.rs +++ b/crates/solidity/src/yul/parser/statement/if_conditional.rs @@ -55,7 +55,7 @@ where fn into_llvm(self, context: &mut revive_llvm_context::PolkaVMContext) -> anyhow::Result<()> { let condition = self .condition - .into_llvm(context, None)? + .into_llvm(context, &mut None)? .expect("Always exists") .access(context)? .into_int_value(); diff --git a/crates/solidity/src/yul/parser/statement/switch/mod.rs b/crates/solidity/src/yul/parser/statement/switch/mod.rs index e0aca0b..ab3cdb8 100644 --- a/crates/solidity/src/yul/parser/statement/switch/mod.rs +++ b/crates/solidity/src/yul/parser/statement/switch/mod.rs @@ -123,7 +123,7 @@ where D: revive_llvm_context::PolkaVMDependency + Clone, { fn into_llvm(self, context: &mut revive_llvm_context::PolkaVMContext) -> anyhow::Result<()> { - let scrutinee = self.expression.into_llvm(context, None)?; + let scrutinee = self.expression.into_llvm(context, &mut None)?; if self.cases.is_empty() { if let Some(block) = self.default { diff --git a/crates/solidity/src/yul/parser/statement/variable_declaration.rs b/crates/solidity/src/yul/parser/statement/variable_declaration.rs index 0458a6e..9cfe166 100644 --- a/crates/solidity/src/yul/parser/statement/variable_declaration.rs +++ b/crates/solidity/src/yul/parser/statement/variable_declaration.rs @@ -110,8 +110,9 @@ where .borrow_mut() .insert_stack_pointer(identifier.inner.clone(), pointer); + let mut assignment_pointer = Some(pointer.value); let value = if let Some(expression) = self.expression { - match expression.into_llvm(context, None)? { + match expression.into_llvm(context, &mut assignment_pointer)? { Some(mut value) => { if let Some(constant) = value.constant.take() { context @@ -128,7 +129,9 @@ where } else { r#type.const_zero().as_basic_value_enum() }; - context.build_store(pointer, value)?; + if assignment_pointer.is_some() { + context.build_store(pointer, value)?; + } return Ok(()); } @@ -156,7 +159,7 @@ where None => return Ok(()), }; let location = expression.location(); - let expression = match expression.into_llvm(context, None)? { + let expression = match expression.into_llvm(context, &mut None)? { Some(expression) => expression, None => return Ok(()), };