diff --git a/CHANGELOG.md b/CHANGELOG.md index 3082c51..d2957c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,15 @@ This is a development pre-release. +Supported `polkadot-sdk` rev:`c29e72a8628835e34deb6aa7db9a78a2e4eabcee` + +### Added + +### Changed + +### Fixed +- Constructors avoid storing zero sized immutable data on exit. + ## v0.1.0-dev.13 This is a development pre-release. diff --git a/crates/benchmarks/BENCHMARKS.md b/crates/benchmarks/BENCHMARKS.md index 76eab6d..be529a2 100644 --- a/crates/benchmarks/BENCHMARKS.md +++ b/crates/benchmarks/BENCHMARKS.md @@ -15,58 +15,58 @@ ### Baseline -| | `EVM` | `PVMInterpreter` | -|:--------|:------------------------|:-------------------------------- | -| **`0`** | `3.36 us` (✅ **1.00x**) | `11.84 us` (❌ *3.52x slower*) | +| | `EVM` | `PVMInterpreter` | +|:--------|:-------------------------|:-------------------------------- | +| **`0`** | `10.63 us` (✅ **1.00x**) | `10.35 us` (✅ **1.03x faster**) | ### OddPorduct -| | `EVM` | `PVMInterpreter` | -|:-------------|:-------------------------|:-------------------------------- | -| **`10000`** | `3.11 ms` (✅ **1.00x**) | `1.53 ms` (🚀 **2.03x faster**) | -| **`100000`** | `30.70 ms` (✅ **1.00x**) | `15.54 ms` (🚀 **1.98x faster**) | -| **`300000`** | `92.68 ms` (✅ **1.00x**) | `45.47 ms` (🚀 **2.04x faster**) | +| | `EVM` | `PVMInterpreter` | +|:-------------|:--------------------------|:-------------------------------- | +| **`10000`** | `3.63 ms` (✅ **1.00x**) | `1.66 ms` (🚀 **2.19x faster**) | +| **`100000`** | `36.66 ms` (✅ **1.00x**) | `16.39 ms` (🚀 **2.24x faster**) | +| **`300000`** | `108.64 ms` (✅ **1.00x**) | `50.48 ms` (🚀 **2.15x faster**) | ### TriangleNumber | | `EVM` | `PVMInterpreter` | |:-------------|:-------------------------|:-------------------------------- | -| **`10000`** | `2.29 ms` (✅ **1.00x**) | `1.09 ms` (🚀 **2.11x faster**) | -| **`100000`** | `22.84 ms` (✅ **1.00x**) | `10.66 ms` (🚀 **2.14x faster**) | -| **`360000`** | `82.29 ms` (✅ **1.00x**) | `37.01 ms` (🚀 **2.22x faster**) | +| **`10000`** | `2.59 ms` (✅ **1.00x**) | `1.20 ms` (🚀 **2.17x faster**) | +| **`100000`** | `25.50 ms` (✅ **1.00x**) | `11.82 ms` (🚀 **2.16x faster**) | +| **`360000`** | `91.57 ms` (✅ **1.00x**) | `42.11 ms` (🚀 **2.17x faster**) | ### FibonacciRecursive | | `EVM` | `PVMInterpreter` | |:---------|:--------------------------|:--------------------------------- | -| **`12`** | `135.67 us` (✅ **1.00x**) | `125.02 us` (✅ **1.09x faster**) | -| **`16`** | `903.75 us` (✅ **1.00x**) | `762.79 us` (✅ **1.18x faster**) | -| **`20`** | `6.12 ms` (✅ **1.00x**) | `4.96 ms` (✅ **1.23x faster**) | -| **`24`** | `42.05 ms` (✅ **1.00x**) | `33.86 ms` (✅ **1.24x faster**) | +| **`12`** | `149.13 us` (✅ **1.00x**) | `154.35 us` (✅ **1.04x slower**) | +| **`16`** | `972.01 us` (✅ **1.00x**) | `924.33 us` (✅ **1.05x faster**) | +| **`20`** | `6.62 ms` (✅ **1.00x**) | `6.23 ms` (✅ **1.06x faster**) | +| **`24`** | `45.25 ms` (✅ **1.00x**) | `43.44 ms` (✅ **1.04x faster**) | ### FibonacciIterative | | `EVM` | `PVMInterpreter` | |:----------|:-------------------------|:-------------------------------- | -| **`64`** | `15.04 us` (✅ **1.00x**) | `29.45 us` (❌ *1.96x slower*) | -| **`128`** | `26.36 us` (✅ **1.00x**) | `42.19 us` (❌ *1.60x slower*) | -| **`256`** | `48.61 us` (✅ **1.00x**) | `65.71 us` (❌ *1.35x slower*) | +| **`64`** | `22.71 us` (✅ **1.00x**) | `31.48 us` (❌ *1.39x slower*) | +| **`128`** | `35.32 us` (✅ **1.00x**) | `41.87 us` (❌ *1.19x slower*) | +| **`256`** | `59.58 us` (✅ **1.00x**) | `63.43 us` (✅ **1.06x slower**) | ### FibonacciBinet | | `EVM` | `PVMInterpreter` | |:----------|:-------------------------|:-------------------------------- | -| **`64`** | `15.22 us` (✅ **1.00x**) | `41.46 us` (❌ *2.72x slower*) | -| **`128`** | `17.05 us` (✅ **1.00x**) | `42.84 us` (❌ *2.51x slower*) | -| **`256`** | `19.00 us` (✅ **1.00x**) | `44.36 us` (❌ *2.34x slower*) | +| **`64`** | `23.18 us` (✅ **1.00x**) | `47.33 us` (❌ *2.04x slower*) | +| **`128`** | `24.97 us` (✅ **1.00x**) | `50.37 us` (❌ *2.02x slower*) | +| **`256`** | `28.25 us` (✅ **1.00x**) | `53.69 us` (❌ *1.90x slower*) | ### SHA1 | | `EVM` | `PVMInterpreter` | |:----------|:--------------------------|:--------------------------------- | -| **`1`** | `110.04 us` (✅ **1.00x**) | `216.11 us` (❌ *1.96x slower*) | -| **`64`** | `209.04 us` (✅ **1.00x**) | `309.48 us` (❌ *1.48x slower*) | -| **`512`** | `903.65 us` (✅ **1.00x**) | `980.49 us` (✅ **1.09x slower**) | +| **`1`** | `132.75 us` (✅ **1.00x**) | `232.17 us` (❌ *1.75x slower*) | +| **`64`** | `240.82 us` (✅ **1.00x**) | `328.19 us` (❌ *1.36x slower*) | +| **`512`** | `1.03 ms` (✅ **1.00x**) | `1.03 ms` (✅ **1.01x faster**) | --- Made with [criterion-table](https://github.com/nu11ptr/criterion-table) diff --git a/crates/integration/codesize.json b/crates/integration/codesize.json index d9eaafc..4e2d0cd 100644 --- a/crates/integration/codesize.json +++ b/crates/integration/codesize.json @@ -1,10 +1,10 @@ { - "Baseline": 1443, - "Computation": 2788, - "DivisionArithmetics": 9748, - "ERC20": 19150, - "Events": 2201, - "FibonacciIterative": 2041, - "Flipper": 2691, - "SHA1": 8997 + "Baseline": 1365, + "Computation": 2710, + "DivisionArithmetics": 9672, + "ERC20": 19131, + "Events": 2123, + "FibonacciIterative": 1964, + "Flipper": 2590, + "SHA1": 8918 } \ No newline at end of file diff --git a/crates/llvm-context/src/polkavm/context/argument.rs b/crates/llvm-context/src/polkavm/context/argument.rs index 003d6a9..8dfd18b 100644 --- a/crates/llvm-context/src/polkavm/context/argument.rs +++ b/crates/llvm-context/src/polkavm/context/argument.rs @@ -4,61 +4,98 @@ #[derive(Debug, Clone)] pub struct Argument<'ctx> { /// The actual LLVM operand. - pub value: inkwell::values::BasicValueEnum<'ctx>, + pub value: Value<'ctx>, /// The original AST value. Used mostly for string literals. pub original: Option, /// The preserved constant value, if available. pub constant: Option, } +/// The function argument can be either a pointer or a integer value. +/// This disambiguation allows for lazy loading of variables. +#[derive(Clone, Debug)] +pub enum Value<'ctx> { + Register(inkwell::values::BasicValueEnum<'ctx>), + Pointer { + pointer: crate::polkavm::context::Pointer<'ctx>, + id: String, + }, +} + impl<'ctx> Argument<'ctx> { - /// The calldata offset argument index. - pub const ARGUMENT_INDEX_CALLDATA_OFFSET: usize = 0; - - /// The calldata length argument index. - pub const ARGUMENT_INDEX_CALLDATA_LENGTH: usize = 1; - - /// A shortcut constructor. - pub fn new(value: inkwell::values::BasicValueEnum<'ctx>) -> Self { + /// A shortcut constructor for register arguments. + pub fn value(value: inkwell::values::BasicValueEnum<'ctx>) -> Self { Self { - value, + value: Value::Register(value), original: None, constant: None, } } - /// A shortcut constructor. - pub fn new_with_original( - value: inkwell::values::BasicValueEnum<'ctx>, - original: String, - ) -> Self { + /// A shortcut constructor for stack arguments. + pub fn pointer(pointer: crate::polkavm::context::Pointer<'ctx>, id: String) -> Self { Self { - value, - original: Some(original), + value: Value::Pointer { pointer, id }, + original: None, constant: None, } } - /// A shortcut constructor. - pub fn new_with_constant( - value: inkwell::values::BasicValueEnum<'ctx>, - constant: num::BigUint, - ) -> Self { - Self { - value, - original: None, - constant: Some(constant), - } + /// Set the original decleratation value. + pub fn with_original(mut self, original: String) -> Self { + self.original = Some(original); + self + } + + /// Set the constant value. + pub fn with_constant(mut self, constant: num::BigUint) -> Self { + self.constant = Some(constant); + self } /// Returns the inner LLVM value. - pub fn to_llvm(&self) -> inkwell::values::BasicValueEnum<'ctx> { - self.value + /// + /// Panics if `self` is a pointer argument. + pub fn _to_llvm_value(&self) -> inkwell::values::BasicValueEnum<'ctx> { + match &self.value { + Value::Register(value) => *value, + Value::Pointer { .. } => unreachable!("invalid register value access"), + } + } + + /// Access the underlying value. + /// + /// Will emit a stack load if `self` is a pointer argument. + pub fn access( + &self, + context: &crate::polkavm::context::Context<'ctx, D>, + ) -> anyhow::Result> { + match &self.value { + Value::Register(value) => Ok(*value), + Value::Pointer { pointer, id } => context.build_load(*pointer, id), + } + } + + /// Access the underlying value. + /// + /// Will emit a stack load if `self` is a pointer argument. + pub fn as_pointer( + &self, + context: &crate::polkavm::context::Context<'ctx, D>, + ) -> anyhow::Result> { + match &self.value { + Value::Register(value) => { + let pointer = context.build_alloca_at_entry(context.word_type(), "pvm_arg"); + context.build_store(pointer, *value)?; + Ok(pointer) + } + Value::Pointer { pointer, .. } => Ok(*pointer), + } } } impl<'ctx> From> for Argument<'ctx> { fn from(value: inkwell::values::BasicValueEnum<'ctx>) -> Self { - Self::new(value) + Self::value(value) } } diff --git a/crates/llvm-context/src/polkavm/context/mod.rs b/crates/llvm-context/src/polkavm/context/mod.rs index e533b9c..de83e4f 100644 --- a/crates/llvm-context/src/polkavm/context/mod.rs +++ b/crates/llvm-context/src/polkavm/context/mod.rs @@ -101,6 +101,9 @@ where solidity_data: Option, /// The Yul data. yul_data: Option, + + /// Hints whether the contracts deploy function stores immutables. + immutables: bool, } impl<'ctx, D> Context<'ctx, D> @@ -263,6 +266,8 @@ where solidity_data: None, yul_data: None, + + immutables: false, } } @@ -1426,4 +1431,14 @@ where pub fn optimizer_settings(&self) -> &OptimizerSettings { self.optimizer.settings() } + + /// Hint the deploy code exit routine to emit storing the immutables. + pub fn enable_immutables(&mut self) { + self.immutables = true; + } + + /// Returns if the contract stores or loads immutables. + pub fn has_immutables(&self) -> bool { + self.immutables + } } diff --git a/crates/llvm-context/src/polkavm/context/pointer/storage.rs b/crates/llvm-context/src/polkavm/context/pointer/storage.rs index a28c1cb..01ea8a5 100644 --- a/crates/llvm-context/src/polkavm/context/pointer/storage.rs +++ b/crates/llvm-context/src/polkavm/context/pointer/storage.rs @@ -19,7 +19,7 @@ where fn r#type<'ctx>(context: &Context<'ctx, D>) -> inkwell::types::FunctionType<'ctx> { context .word_type() - .fn_type(&[context.word_type().into()], false) + .fn_type(&[context.llvm().ptr_type(Default::default()).into()], false) } fn emit_body<'ctx>( @@ -59,7 +59,7 @@ where fn r#type<'ctx>(context: &Context<'ctx, D>) -> inkwell::types::FunctionType<'ctx> { context .word_type() - .fn_type(&[context.word_type().into()], false) + .fn_type(&[context.llvm().ptr_type(Default::default()).into()], false) } fn emit_body<'ctx>( @@ -94,7 +94,10 @@ where fn r#type<'ctx>(context: &Context<'ctx, D>) -> inkwell::types::FunctionType<'ctx> { context.void_type().fn_type( - &[context.word_type().into(), context.word_type().into()], + &[ + context.llvm().ptr_type(Default::default()).into(), + context.llvm().ptr_type(Default::default()).into(), + ], false, ) } @@ -138,7 +141,10 @@ where fn r#type<'ctx>(context: &Context<'ctx, D>) -> inkwell::types::FunctionType<'ctx> { context.void_type().fn_type( - &[context.word_type().into(), context.word_type().into()], + &[ + context.llvm().ptr_type(Default::default()).into(), + context.llvm().ptr_type(Default::default()).into(), + ], false, ) } @@ -173,9 +179,17 @@ where fn emit_load<'ctx, D: Dependency + Clone>( context: &mut Context<'ctx, D>, - mut key: BasicValueEnum<'ctx>, + key: BasicValueEnum<'ctx>, transient: bool, ) -> anyhow::Result> { + let mut key = context.build_load( + super::Pointer::new( + context.word_type(), + Default::default(), + key.into_pointer_value(), + ), + "key", + )?; if !transient { key = context.build_byte_swap(key)?; } @@ -217,10 +231,26 @@ fn emit_load<'ctx, D: Dependency + Clone>( fn emit_store<'ctx, D: Dependency + Clone>( context: &mut Context<'ctx, D>, - mut key: BasicValueEnum<'ctx>, - mut value: BasicValueEnum<'ctx>, + key: BasicValueEnum<'ctx>, + value: BasicValueEnum<'ctx>, transient: bool, ) -> anyhow::Result<()> { + let mut key = context.build_load( + super::Pointer::new( + context.word_type(), + Default::default(), + key.into_pointer_value(), + ), + "key", + )?; + let mut value = context.build_load( + super::Pointer::new( + context.word_type(), + Default::default(), + value.into_pointer_value(), + ), + "key", + )?; if !transient { key = context.build_byte_swap(key)?; value = context.build_byte_swap(value)?; diff --git a/crates/llvm-context/src/polkavm/evm/create.rs b/crates/llvm-context/src/polkavm/evm/create.rs index 26b3255..7d859d6 100644 --- a/crates/llvm-context/src/polkavm/evm/create.rs +++ b/crates/llvm-context/src/polkavm/evm/create.rs @@ -119,10 +119,8 @@ where _ => error, })?; if contract_path.as_str() == parent { - return Ok(Argument::new_with_constant( - context.word_const(0).as_basic_value_enum(), - num::BigUint::zero(), - )); + return Ok(Argument::value(context.word_const(0).as_basic_value_enum()) + .with_constant(num::BigUint::zero())); } else if identifier.ends_with("_deployed") && code_type == CodeType::Runtime { anyhow::bail!("type({}).runtimeCode is not supported", identifier); } @@ -131,7 +129,7 @@ where let hash_value = context .word_const_str_hex(hash_string.as_str()) .as_basic_value_enum(); - Ok(Argument::new_with_original(hash_value, hash_string)) + Ok(Argument::value(hash_value).with_original(hash_string)) } /// Translates the deploy call header size instruction. the header consists of @@ -160,10 +158,8 @@ where _ => error, })?; if contract_path.as_str() == parent { - return Ok(Argument::new_with_constant( - context.word_const(0).as_basic_value_enum(), - num::BigUint::zero(), - )); + return Ok(Argument::value(context.word_const(0).as_basic_value_enum()) + .with_constant(num::BigUint::zero())); } else if identifier.ends_with("_deployed") && code_type == CodeType::Runtime { anyhow::bail!("type({}).runtimeCode is not supported", identifier); } @@ -172,5 +168,5 @@ where let size_value = context .word_const(crate::polkavm::DEPLOYER_CALL_HEADER_SIZE as u64) .as_basic_value_enum(); - Ok(Argument::new_with_constant(size_value, size_bigint)) + Ok(Argument::value(size_value).with_constant(size_bigint)) } diff --git a/crates/llvm-context/src/polkavm/evm/immutable.rs b/crates/llvm-context/src/polkavm/evm/immutable.rs index 60f2827..40343d9 100644 --- a/crates/llvm-context/src/polkavm/evm/immutable.rs +++ b/crates/llvm-context/src/polkavm/evm/immutable.rs @@ -257,6 +257,7 @@ where anyhow::bail!("Immutables are not available if the contract part is undefined"); } Some(CodeType::Deploy) => { + context.enable_immutables(); let immutable_data_pointer = context .get_global(revive_runtime_api::immutable_data::GLOBAL_IMMUTABLE_DATA_POINTER)? .value diff --git a/crates/llvm-context/src/polkavm/evm/return.rs b/crates/llvm-context/src/polkavm/evm/return.rs index 717ce81..9dacd1e 100644 --- a/crates/llvm-context/src/polkavm/evm/return.rs +++ b/crates/llvm-context/src/polkavm/evm/return.rs @@ -18,11 +18,13 @@ where match context.code_type() { None => anyhow::bail!("Return is not available if the contract part is undefined"), Some(CodeType::Deploy) => { - context.build_call( - >::declaration(context), - Default::default(), - "store_immutable_data", - ); + if context.has_immutables() { + context.build_call( + >::declaration(context), + Default::default(), + "store_immutable_data", + ); + } } Some(CodeType::Runtime) => {} } diff --git a/crates/llvm-context/src/polkavm/evm/storage.rs b/crates/llvm-context/src/polkavm/evm/storage.rs index 09f795e..a934f64 100644 --- a/crates/llvm-context/src/polkavm/evm/storage.rs +++ b/crates/llvm-context/src/polkavm/evm/storage.rs @@ -3,6 +3,7 @@ use crate::polkavm::context::runtime::RuntimeFunction; use crate::polkavm::context::Context; use crate::polkavm::Dependency; +use crate::PolkaVMArgument; use crate::PolkaVMLoadStorageWordFunction; use crate::PolkaVMLoadTransientStorageWordFunction; use crate::PolkaVMStoreStorageWordFunction; @@ -11,14 +12,14 @@ use crate::PolkaVMStoreTransientStorageWordFunction; /// Translates the storage load. pub fn load<'ctx, D>( context: &mut Context<'ctx, D>, - position: inkwell::values::IntValue<'ctx>, + position: &PolkaVMArgument<'ctx>, ) -> anyhow::Result> where D: Dependency + Clone, { let name = >::NAME; let declaration = >::declaration(context); - let arguments = [position.into()]; + let arguments = [position.as_pointer(context)?.value.into()]; Ok(context .build_call(declaration, &arguments, "storage_load") .unwrap_or_else(|| panic!("runtime function {name} should return a value"))) @@ -27,14 +28,17 @@ where /// Translates the storage store. pub fn store<'ctx, D>( context: &mut Context<'ctx, D>, - position: inkwell::values::IntValue<'ctx>, - value: inkwell::values::IntValue<'ctx>, + position: &PolkaVMArgument<'ctx>, + value: &PolkaVMArgument<'ctx>, ) -> anyhow::Result<()> where D: Dependency + Clone, { let declaration = >::declaration(context); - let arguments = [position.into(), value.into()]; + let arguments = [ + position.as_pointer(context)?.value.into(), + value.as_pointer(context)?.value.into(), + ]; context.build_call(declaration, &arguments, "storage_store"); Ok(()) } @@ -42,13 +46,13 @@ where /// Translates the transient storage load. pub fn transient_load<'ctx, D>( context: &mut Context<'ctx, D>, - position: inkwell::values::IntValue<'ctx>, + position: &PolkaVMArgument<'ctx>, ) -> anyhow::Result> where D: Dependency + Clone, { let name = >::NAME; - let arguments = [position.into()]; + let arguments = [position.as_pointer(context)?.value.into()]; let declaration = >::declaration(context); Ok(context @@ -59,15 +63,18 @@ where /// Translates the transient storage store. pub fn transient_store<'ctx, D>( context: &mut Context<'ctx, D>, - position: inkwell::values::IntValue<'ctx>, - value: inkwell::values::IntValue<'ctx>, + position: &PolkaVMArgument<'ctx>, + value: &PolkaVMArgument<'ctx>, ) -> anyhow::Result<()> where D: Dependency + Clone, { let declaration = >::declaration(context); - let arguments = [position.into(), value.into()]; + let arguments = [ + position.as_pointer(context)?.value.into(), + value.as_pointer(context)?.value.into(), + ]; context.build_call(declaration, &arguments, "transient_storage_store"); Ok(()) } diff --git a/crates/solidity/src/yul/parser/statement/assignment.rs b/crates/solidity/src/yul/parser/statement/assignment.rs index d93d34c..0a13d18 100644 --- a/crates/solidity/src/yul/parser/statement/assignment.rs +++ b/crates/solidity/src/yul/parser/statement/assignment.rs @@ -139,13 +139,14 @@ where identifier.inner, ) })?; - context.build_store(pointer, value.to_llvm())?; + context.build_store(pointer, value.access(context)?)?; return Ok(()); } - let llvm_type = value.to_llvm().into_struct_value().get_type(); + let value = value.access(context)?; + let llvm_type = value.into_struct_value().get_type(); let tuple_pointer = context.build_alloca(llvm_type, "assignment_pointer"); - context.build_store(tuple_pointer, value.to_llvm())?; + context.build_store(tuple_pointer, value)?; for (index, binding) in self.bindings.into_iter().enumerate() { context.set_debug_location(self.location.line, 0, None)?; 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 b9aea78..9ddb1a2 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 @@ -128,7 +128,10 @@ impl FunctionCall { Name::UserDefined(name) => { let mut values = Vec::with_capacity(self.arguments.len()); for argument in self.arguments.into_iter().rev() { - let value = argument.into_llvm(context)?.expect("Always exists").value; + let value = argument + .into_llvm(context)? + .expect("Always exists") + .access(context)?; values.push(value); } values.reverse(); @@ -461,36 +464,29 @@ impl FunctionCall { } Name::SLoad => { - let arguments = self.pop_arguments_llvm::(context)?; - revive_llvm_context::polkavm_evm_storage::load( - context, - arguments[0].into_int_value(), - ) - .map(Some) + let arguments = self.pop_arguments::(context)?; + revive_llvm_context::polkavm_evm_storage::load(context, &arguments[0]).map(Some) } Name::SStore => { - let arguments = self.pop_arguments_llvm::(context)?; + let arguments = self.pop_arguments::(context)?; revive_llvm_context::polkavm_evm_storage::store( context, - arguments[0].into_int_value(), - arguments[1].into_int_value(), + &arguments[0], + &arguments[1], ) .map(|_| None) } Name::TLoad => { - let arguments = self.pop_arguments_llvm::(context)?; - revive_llvm_context::polkavm_evm_storage::transient_load( - context, - arguments[0].into_int_value(), - ) - .map(Some) + let arguments = self.pop_arguments::(context)?; + revive_llvm_context::polkavm_evm_storage::transient_load(context, &arguments[0]) + .map(Some) } Name::TStore => { - let arguments = self.pop_arguments_llvm::(context)?; + let arguments = self.pop_arguments::(context)?; revive_llvm_context::polkavm_evm_storage::transient_store( context, - arguments[0].into_int_value(), - arguments[1].into_int_value(), + &arguments[0], + &arguments[1], ) .map(|_| None) } @@ -514,7 +510,7 @@ impl FunctionCall { let offset = context.solidity_mut().allocate_immutable(key.as_str()) / revive_common::BYTE_LENGTH_WORD; let index = context.xlen_type().const_int(offset as u64, false); - let value = arguments[2].value.into_int_value(); + let value = arguments[2].access(context)?.into_int_value(); revive_llvm_context::polkavm_evm_immutable::store(context, index, value) .map(|_| None) } @@ -720,13 +716,13 @@ impl FunctionCall { Name::Call => { let arguments = self.pop_arguments::(context)?; - let gas = arguments[0].value.into_int_value(); - let address = arguments[1].value.into_int_value(); - let value = arguments[2].value.into_int_value(); - let input_offset = arguments[3].value.into_int_value(); - let input_size = arguments[4].value.into_int_value(); - let output_offset = arguments[5].value.into_int_value(); - let output_size = arguments[6].value.into_int_value(); + let gas = arguments[0].access(context)?.into_int_value(); + let address = arguments[1].access(context)?.into_int_value(); + let value = arguments[2].access(context)?.into_int_value(); + let input_offset = arguments[3].access(context)?.into_int_value(); + let input_size = arguments[4].access(context)?.into_int_value(); + let output_offset = arguments[5].access(context)?.into_int_value(); + let output_size = arguments[6].access(context)?.into_int_value(); let simulation_address: Vec> = arguments .into_iter() @@ -750,12 +746,12 @@ impl FunctionCall { Name::StaticCall => { let arguments = self.pop_arguments::(context)?; - let gas = arguments[0].value.into_int_value(); - let address = arguments[1].value.into_int_value(); - let input_offset = arguments[2].value.into_int_value(); - let input_size = arguments[3].value.into_int_value(); - let output_offset = arguments[4].value.into_int_value(); - let output_size = arguments[5].value.into_int_value(); + let gas = arguments[0].access(context)?.into_int_value(); + let address = arguments[1].access(context)?.into_int_value(); + let input_offset = arguments[2].access(context)?.into_int_value(); + let input_size = arguments[3].access(context)?.into_int_value(); + let output_offset = arguments[4].access(context)?.into_int_value(); + let output_size = arguments[5].access(context)?.into_int_value(); let simulation_address: Vec> = arguments .into_iter() @@ -779,12 +775,12 @@ impl FunctionCall { Name::DelegateCall => { let arguments = self.pop_arguments::(context)?; - let gas = arguments[0].value.into_int_value(); - let address = arguments[1].value.into_int_value(); - let input_offset = arguments[2].value.into_int_value(); - let input_size = arguments[3].value.into_int_value(); - let output_offset = arguments[4].value.into_int_value(); - let output_size = arguments[5].value.into_int_value(); + let gas = arguments[0].access(context)?.into_int_value(); + let address = arguments[1].access(context)?.into_int_value(); + let input_offset = arguments[2].access(context)?.into_int_value(); + let input_size = arguments[3].access(context)?.into_int_value(); + let output_offset = arguments[4].access(context)?.into_int_value(); + let output_size = arguments[5].access(context)?.into_int_value(); let simulation_address: Vec> = arguments .into_iter() @@ -845,7 +841,8 @@ impl FunctionCall { })?; revive_llvm_context::polkavm_evm_create::contract_hash(context, identifier) - .map(|argument| Some(argument.value)) + .and_then(|argument| argument.access(context)) + .map(Some) } Name::DataSize => { let mut arguments = self.pop_arguments::(context)?; @@ -855,7 +852,8 @@ impl FunctionCall { })?; revive_llvm_context::polkavm_evm_create::header_size(context, identifier) - .map(|argument| Some(argument.value)) + .and_then(|argument| argument.access(context)) + .map(Some) } Name::DataCopy => { let arguments = self.pop_arguments_llvm::(context)?; @@ -989,7 +987,12 @@ impl FunctionCall { { let mut arguments = Vec::with_capacity(N); for expression in self.arguments.drain(0..N).rev() { - arguments.push(expression.into_llvm(context)?.expect("Always exists").value); + arguments.push( + expression + .into_llvm(context)? + .expect("Always exists") + .access(context)?, + ); } arguments.reverse(); diff --git a/crates/solidity/src/yul/parser/statement/expression/literal.rs b/crates/solidity/src/yul/parser/statement/expression/literal.rs index 88e5935..9df512c 100644 --- a/crates/solidity/src/yul/parser/statement/expression/literal.rs +++ b/crates/solidity/src/yul/parser/statement/expression/literal.rs @@ -97,9 +97,7 @@ impl Literal { BooleanLiteral::True => num::BigUint::one(), }; - Ok(revive_llvm_context::PolkaVMArgument::new_with_constant( - value, constant, - )) + Ok(revive_llvm_context::PolkaVMArgument::value(value).with_constant(constant)) } LexicalLiteral::Integer(inner) => { let r#type = self.yul_type.unwrap_or_default().into_llvm(context); @@ -127,9 +125,7 @@ impl Literal { } .expect("Always valid"); - Ok(revive_llvm_context::PolkaVMArgument::new_with_constant( - value, constant, - )) + Ok(revive_llvm_context::PolkaVMArgument::value(value).with_constant(constant)) } LexicalLiteral::String(inner) => { let string = inner.inner; @@ -200,10 +196,10 @@ impl Literal { }; if hex_string.len() > revive_common::BYTE_LENGTH_WORD * 2 { - return Ok(revive_llvm_context::PolkaVMArgument::new_with_original( + return Ok(revive_llvm_context::PolkaVMArgument::value( r#type.const_zero().as_basic_value_enum(), - string, - )); + ) + .with_original(string)); } if hex_string.len() < revive_common::BYTE_LENGTH_WORD * 2 { @@ -220,9 +216,7 @@ impl Literal { ) .expect("The value is valid") .as_basic_value_enum(); - Ok(revive_llvm_context::PolkaVMArgument::new_with_original( - value, string, - )) + Ok(revive_llvm_context::PolkaVMArgument::value(value).with_original(string)) } } } diff --git a/crates/solidity/src/yul/parser/statement/expression/mod.rs b/crates/solidity/src/yul/parser/statement/expression/mod.rs index 80a5a62..c26820e 100644 --- a/crates/solidity/src/yul/parser/statement/expression/mod.rs +++ b/crates/solidity/src/yul/parser/statement/expression/mod.rs @@ -119,36 +119,28 @@ impl Expression { }) .map(Some), Self::Identifier(identifier) => { + let id = identifier.inner; + let pointer = context .current_function() .borrow() - .get_stack_pointer(identifier.inner.as_str()) + .get_stack_pointer(&id) .ok_or_else(|| { - anyhow::anyhow!( - "{} Undeclared variable `{}`", - identifier.location, - identifier.inner, - ) + anyhow::anyhow!("{} Undeclared variable `{}`", identifier.location, id) })?; - let constant = context - .current_function() - .borrow() - .yul() - .get_constant(identifier.inner.as_str()); + let constant = context.current_function().borrow().yul().get_constant(&id); - let value = context.build_load(pointer, identifier.inner.as_str())?; + let argument = revive_llvm_context::PolkaVMArgument::pointer(pointer, id); - match constant { - Some(constant) => Ok(Some( - revive_llvm_context::PolkaVMArgument::new_with_constant(value, constant), - )), - None => Ok(Some(value.into())), - } + Ok(Some(match constant { + Some(constant) => argument.with_constant(constant), + _ => argument, + })) } Self::FunctionCall(call) => Ok(call .into_llvm(context)? - .map(revive_llvm_context::PolkaVMArgument::new)), + .map(revive_llvm_context::PolkaVMArgument::value)), } } } diff --git a/crates/solidity/src/yul/parser/statement/for_loop.rs b/crates/solidity/src/yul/parser/statement/for_loop.rs index b901eed..c3d0c35 100644 --- a/crates/solidity/src/yul/parser/statement/for_loop.rs +++ b/crates/solidity/src/yul/parser/statement/for_loop.rs @@ -78,7 +78,7 @@ where .condition .into_llvm(context)? .expect("Always exists") - .to_llvm() + .access(context)? .into_int_value(); let condition = context.builder().build_int_z_extend_or_bit_cast( condition, diff --git a/crates/solidity/src/yul/parser/statement/if_conditional.rs b/crates/solidity/src/yul/parser/statement/if_conditional.rs index 056d66c..96178c7 100644 --- a/crates/solidity/src/yul/parser/statement/if_conditional.rs +++ b/crates/solidity/src/yul/parser/statement/if_conditional.rs @@ -57,7 +57,7 @@ where .condition .into_llvm(context)? .expect("Always exists") - .to_llvm() + .access(context)? .into_int_value(); let condition = context.builder().build_int_z_extend_or_bit_cast( condition, diff --git a/crates/solidity/src/yul/parser/statement/switch/mod.rs b/crates/solidity/src/yul/parser/statement/switch/mod.rs index e3173e4..177003c 100644 --- a/crates/solidity/src/yul/parser/statement/switch/mod.rs +++ b/crates/solidity/src/yul/parser/statement/switch/mod.rs @@ -137,7 +137,7 @@ where let mut branches = Vec::with_capacity(self.cases.len()); for (index, case) in self.cases.into_iter().enumerate() { - let constant = case.literal.into_llvm(context)?.to_llvm(); + let constant = case.literal.into_llvm(context)?.access(context)?; let expression_block = context .append_basic_block(format!("switch_case_branch_{}_block", index + 1).as_str()); @@ -161,7 +161,10 @@ where context.set_basic_block(current_block); context.builder().build_switch( - scrutinee.expect("Always exists").to_llvm().into_int_value(), + scrutinee + .expect("Always exists") + .access(context)? + .into_int_value(), default_block, branches.as_slice(), )?; diff --git a/crates/solidity/src/yul/parser/statement/variable_declaration.rs b/crates/solidity/src/yul/parser/statement/variable_declaration.rs index 8232fda..3024bc0 100644 --- a/crates/solidity/src/yul/parser/statement/variable_declaration.rs +++ b/crates/solidity/src/yul/parser/statement/variable_declaration.rs @@ -121,7 +121,7 @@ where .insert_constant(identifier.inner.clone(), constant); } - value.to_llvm() + value.access(context)? } None => r#type.const_zero().as_basic_value_enum(), } @@ -175,7 +175,8 @@ where .collect::>>() .as_slice(), ); - if expression.value.get_type() != llvm_type.as_basic_type_enum() { + let value = expression.access(context)?; + if value.get_type() != llvm_type.as_basic_type_enum() { anyhow::bail!( "{} Assignment to {:?} received an invalid number of arguments", location, @@ -183,7 +184,7 @@ where ); } let pointer = context.build_alloca(llvm_type, "bindings_pointer"); - context.build_store(pointer, expression.to_llvm())?; + context.build_store(pointer, value)?; for (index, binding) in self.bindings.into_iter().enumerate() { let pointer = context.build_gep(