diff --git a/crates/integration/codesize.json b/crates/integration/codesize.json index 8b0c6a0..1570637 100644 --- a/crates/integration/codesize.json +++ b/crates/integration/codesize.json @@ -1,10 +1,10 @@ { - "Baseline": 960, - "Computation": 2356, - "DivisionArithmetics": 8964, - "ERC20": 17143, - "Events": 1680, - "FibonacciIterative": 1502, - "Flipper": 2137, - "SHA1": 7740 + "Baseline": 932, + "Computation": 2313, + "DivisionArithmetics": 8959, + "ERC20": 16993, + "Events": 1692, + "FibonacciIterative": 1474, + "Flipper": 2098, + "SHA1": 7751 } \ No newline at end of file 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 b445ee9..0bc8dd1 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 @@ -1,6 +1,5 @@ //! The deploy code function. -use crate::polkavm::context::code_type::CodeType; use crate::polkavm::context::function::runtime; use crate::polkavm::context::Context; use crate::polkavm::WriteLLVM; @@ -38,16 +37,16 @@ where 0, Some(inkwell::module::Linkage::Private), None, + false, )?; self.inner.declare(context) } fn into_llvm(self, context: &mut Context) -> anyhow::Result<()> { - context.set_current_function(runtime::FUNCTION_DEPLOY_CODE, None)?; + context.set_current_function(runtime::FUNCTION_DEPLOY_CODE, None, false)?; context.set_basic_block(context.current_function().borrow().entry_block()); - context.set_code_type(CodeType::Deploy); self.inner.into_llvm(context)?; context.set_debug_location(0, 0, None)?; 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 8c5827a..ada79a6 100644 --- a/crates/llvm-context/src/polkavm/context/function/runtime/entry.rs +++ b/crates/llvm-context/src/polkavm/context/function/runtime/entry.rs @@ -138,6 +138,7 @@ impl WriteLLVM for Entry { 0, Some(inkwell::module::Linkage::External), None, + false, )?; context.declare_global( @@ -160,7 +161,7 @@ impl WriteLLVM for Entry { /// The `entry` function loads calldata, sets globals and calls the runtime or deploy code. fn into_llvm(self, context: &mut Context) -> anyhow::Result<()> { let entry = context - .get_function(runtime::FUNCTION_ENTRY) + .get_function(runtime::FUNCTION_ENTRY, false) .expect("the entry function should already be declared") .borrow() .declaration; @@ -171,7 +172,7 @@ impl WriteLLVM for Entry { true, ); - context.set_current_function(runtime::FUNCTION_ENTRY, None)?; + context.set_current_function(runtime::FUNCTION_ENTRY, None, false)?; context.set_basic_block(context.current_function().borrow().entry_block()); Self::initialize_globals(context)?; 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 f3d56a4..994299a 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 @@ -1,6 +1,5 @@ //! The runtime code function. -use crate::polkavm::context::code_type::CodeType; use crate::polkavm::context::function::runtime; use crate::polkavm::context::Context; use crate::polkavm::WriteLLVM; @@ -38,16 +37,16 @@ where 0, Some(inkwell::module::Linkage::Private), None, + false, )?; self.inner.declare(context) } fn into_llvm(self, context: &mut Context) -> anyhow::Result<()> { - context.set_current_function(runtime::FUNCTION_RUNTIME_CODE, None)?; + context.set_current_function(runtime::FUNCTION_RUNTIME_CODE, None, false)?; context.set_basic_block(context.current_function().borrow().entry_block()); - context.set_code_type(CodeType::Runtime); self.inner.into_llvm(context)?; context.set_debug_location(0, 0, None)?; diff --git a/crates/llvm-context/src/polkavm/context/mod.rs b/crates/llvm-context/src/polkavm/context/mod.rs index 199d4a0..8da1dc3 100644 --- a/crates/llvm-context/src/polkavm/context/mod.rs +++ b/crates/llvm-context/src/polkavm/context/mod.rs @@ -426,8 +426,15 @@ impl<'ctx> Context<'ctx> { return_values_length: usize, linkage: Option, location: Option<(u32, u32)>, + is_frontend: bool, ) -> anyhow::Result>>> { - let value = self.module().add_function(name, r#type, linkage); + assert!( + self.get_function(name, is_frontend).is_none(), + "ICE: function '{name}' declared subsequentally" + ); + + let name = self.internal_function_name(name, is_frontend); + let value = self.module().add_function(&name, r#type, linkage); if self.debug_info().is_some() { self.builder().unset_current_debug_location(); @@ -468,7 +475,7 @@ impl<'ctx> Context<'ctx> { }; let function = Function::new( - name.to_owned(), + name.clone(), FunctionDeclaration::new(r#type, value), r#return, entry_block, @@ -476,7 +483,7 @@ impl<'ctx> Context<'ctx> { ); Function::set_default_attributes(self.llvm, function.declaration(), &self.optimizer); let function = Rc::new(RefCell::new(function)); - self.functions.insert(name.to_string(), function.clone()); + self.functions.insert(name, function.clone()); self.pop_debug_scope(); @@ -484,8 +491,14 @@ impl<'ctx> Context<'ctx> { } /// Returns a shared reference to the specified function. - pub fn get_function(&self, name: &str) -> Option>>> { - self.functions.get(name).cloned() + pub fn get_function( + &self, + name: &str, + is_frontend: bool, + ) -> Option>>> { + self.functions + .get(&self.internal_function_name(name, is_frontend)) + .cloned() } /// Returns a shared reference to the current active function. @@ -501,8 +514,9 @@ impl<'ctx> Context<'ctx> { &mut self, name: &str, location: Option<(u32, u32)>, + frontend: bool, ) -> anyhow::Result<()> { - let function = self.functions.get(name).cloned().ok_or_else(|| { + let function = self.get_function(name, frontend).ok_or_else(|| { anyhow::anyhow!("Failed to activate an undeclared function `{}`", name) })?; self.current_function = Some(function); @@ -1371,4 +1385,13 @@ impl<'ctx> Context<'ctx> { false, ) } + + /// Returns the internal function name. + fn internal_function_name(&self, name: &str, is_frontend: bool) -> String { + if is_frontend { + format!("{name}_{}", self.code_type().unwrap()) + } else { + name.to_string() + } + } } diff --git a/crates/llvm-context/src/polkavm/context/runtime.rs b/crates/llvm-context/src/polkavm/context/runtime.rs index b8d84b5..566e9d1 100644 --- a/crates/llvm-context/src/polkavm/context/runtime.rs +++ b/crates/llvm-context/src/polkavm/context/runtime.rs @@ -30,8 +30,9 @@ pub trait RuntimeFunction { Self::NAME, Self::r#type(context), 0, - Some(inkwell::module::Linkage::External), // TODO: `Private` emits unrelocated AUIPC? + Some(inkwell::module::Linkage::LinkOnceODR), None, + false, )?; let mut attributes = Self::ATTRIBUTES.to_vec(); @@ -45,6 +46,12 @@ pub trait RuntimeFunction { &attributes, true, ); + let function = function.borrow().declaration().function_value(); + let comdat = context + .module() + .get_or_insert_comdat(&format!("{}_comdat", Self::NAME)); + comdat.set_selection_kind(inkwell::comdat::ComdatSelectionKind::NoDuplicates); + function.as_global_value().set_comdat(comdat); Ok(()) } @@ -52,7 +59,7 @@ pub trait RuntimeFunction { /// Get the function declaration. fn declaration<'ctx>(context: &Context<'ctx>) -> Declaration<'ctx> { context - .get_function(Self::NAME) + .get_function(Self::NAME, false) .unwrap_or_else(|| panic!("runtime function {} should be declared", Self::NAME)) .borrow() .declaration() @@ -60,7 +67,7 @@ pub trait RuntimeFunction { /// Emit the function. fn emit(&self, context: &mut Context) -> anyhow::Result<()> { - context.set_current_function(Self::NAME, None)?; + context.set_current_function(Self::NAME, None, false)?; context.set_basic_block(context.current_function().borrow().entry_block()); let return_value = self.emit_body(context)?; @@ -99,7 +106,7 @@ pub trait RuntimeFunction { ) -> inkwell::values::BasicValueEnum<'ctx> { let name = Self::NAME; context - .get_function(name) + .get_function(name, false) .unwrap_or_else(|| panic!("runtime function {name} should be declared")) .borrow() .declaration() diff --git a/crates/llvm-context/src/polkavm/context/tests.rs b/crates/llvm-context/src/polkavm/context/tests.rs index 1ad4c39..eb7ba5d 100644 --- a/crates/llvm-context/src/polkavm/context/tests.rs +++ b/crates/llvm-context/src/polkavm/context/tests.rs @@ -38,6 +38,7 @@ pub fn check_attribute_null_pointer_is_invalid() { 1, Some(inkwell::module::Linkage::External), None, + false, ) .expect("Failed to add function"); assert!(!function @@ -62,6 +63,7 @@ pub fn check_attribute_optimize_for_size_mode_3() { 1, Some(inkwell::module::Linkage::External), None, + false, ) .expect("Failed to add function"); assert!(!function @@ -86,6 +88,7 @@ pub fn check_attribute_optimize_for_size_mode_z() { 1, Some(inkwell::module::Linkage::External), None, + false, ) .expect("Failed to add function"); assert!(function @@ -110,6 +113,7 @@ pub fn check_attribute_min_size_mode_3() { 1, Some(inkwell::module::Linkage::External), None, + false, ) .expect("Failed to add function"); assert!(!function @@ -134,6 +138,7 @@ pub fn check_attribute_min_size_mode_z() { 1, Some(inkwell::module::Linkage::External), None, + false, ) .expect("Failed to add function"); assert!(function diff --git a/crates/llvm-context/src/polkavm/evm/immutable.rs b/crates/llvm-context/src/polkavm/evm/immutable.rs index 2c336d3..bf3ba7b 100644 --- a/crates/llvm-context/src/polkavm/evm/immutable.rs +++ b/crates/llvm-context/src/polkavm/evm/immutable.rs @@ -210,7 +210,7 @@ pub fn load<'ctx>( let name = ::NAME; context.build_call( context - .get_function(name) + .get_function(name, false) .expect("is always declared for runtime code") .borrow() .declaration(), diff --git a/crates/yul/src/parser/statement/block.rs b/crates/yul/src/parser/statement/block.rs index 45e2ec3..6e9c0ca 100644 --- a/crates/yul/src/parser/statement/block.rs +++ b/crates/yul/src/parser/statement/block.rs @@ -159,6 +159,7 @@ impl PolkaVMWriteLLVM for Block { context.set_current_function( current_function.as_str(), Some((self.location.line, self.location.column)), + false, )?; if let Some(debug_info) = context.debug_info() { diff --git a/crates/yul/src/parser/statement/expression/function_call/mod.rs b/crates/yul/src/parser/statement/expression/function_call/mod.rs index ead528d..20bd34d 100644 --- a/crates/yul/src/parser/statement/expression/function_call/mod.rs +++ b/crates/yul/src/parser/statement/expression/function_call/mod.rs @@ -135,7 +135,7 @@ impl FunctionCall { values.push(value); } values.reverse(); - let function = context.get_function(name.as_str()).ok_or_else(|| { + let function = context.get_function(name.as_str(), true).ok_or_else(|| { anyhow::anyhow!("{} Undeclared function `{}`", location, name) })?; diff --git a/crates/yul/src/parser/statement/function_definition.rs b/crates/yul/src/parser/statement/function_definition.rs index 6dc56db..37c5033 100644 --- a/crates/yul/src/parser/statement/function_definition.rs +++ b/crates/yul/src/parser/statement/function_definition.rs @@ -215,8 +215,9 @@ impl PolkaVMWriteLLVM for FunctionDefinition { self.identifier.as_str(), function_type, self.result.len(), - Some(inkwell::module::Linkage::Private), + Some(inkwell::module::Linkage::External), Some((self.location.line, self.location.column)), + true, )?; PolkaVMFunction::set_attributes( context.llvm(), @@ -235,6 +236,7 @@ impl PolkaVMWriteLLVM for FunctionDefinition { context.set_current_function( self.identifier.as_str(), Some((self.location.line, self.location.column)), + true, )?; context.set_basic_block(context.current_function().borrow().entry_block()); diff --git a/crates/yul/src/parser/statement/object.rs b/crates/yul/src/parser/statement/object.rs index 22a72a0..658e7ca 100644 --- a/crates/yul/src/parser/statement/object.rs +++ b/crates/yul/src/parser/statement/object.rs @@ -4,6 +4,7 @@ use std::collections::BTreeSet; use std::collections::HashSet; use inkwell::debug_info::AsDIScope; +use revive_llvm_context::PolkaVMCodeType; use serde::Deserialize; use serde::Serialize; @@ -184,6 +185,12 @@ impl Object { impl PolkaVMWriteLLVM for Object { fn declare(&mut self, context: &mut PolkaVMContext) -> anyhow::Result<()> { + if self.identifier.ends_with("_deployed") { + context.set_code_type(PolkaVMCodeType::Runtime); + } else { + context.set_code_type(PolkaVMCodeType::Deploy); + } + revive_llvm_context::PolkaVMLoadImmutableDataFunction.declare(context)?; revive_llvm_context::PolkaVMStoreImmutableDataFunction.declare(context)?; @@ -230,40 +237,12 @@ impl PolkaVMWriteLLVM for Object { .into_iter() { context - .get_function(name) + .get_function(name, false) .expect("Always exists") .borrow_mut() .set_yul_data(revive_llvm_context::PolkaVMFunctionYulData::default()); } - entry.into_llvm(context)?; - - revive_llvm_context::PolkaVMLoadImmutableDataFunction.into_llvm(context)?; - revive_llvm_context::PolkaVMStoreImmutableDataFunction.into_llvm(context)?; - - revive_llvm_context::PolkaVMLoadHeapWordFunction.into_llvm(context)?; - revive_llvm_context::PolkaVMStoreHeapWordFunction.into_llvm(context)?; - revive_llvm_context::PolkaVMLoadStorageWordFunction.into_llvm(context)?; - revive_llvm_context::PolkaVMStoreStorageWordFunction.into_llvm(context)?; - revive_llvm_context::PolkaVMLoadTransientStorageWordFunction.into_llvm(context)?; - revive_llvm_context::PolkaVMStoreTransientStorageWordFunction.into_llvm(context)?; - - revive_llvm_context::PolkaVMWordToPointerFunction.into_llvm(context)?; - revive_llvm_context::PolkaVMExitFunction.into_llvm(context)?; - - revive_llvm_context::PolkaVMEventLogFunction::<0>.into_llvm(context)?; - revive_llvm_context::PolkaVMEventLogFunction::<1>.into_llvm(context)?; - revive_llvm_context::PolkaVMEventLogFunction::<2>.into_llvm(context)?; - revive_llvm_context::PolkaVMEventLogFunction::<3>.into_llvm(context)?; - revive_llvm_context::PolkaVMEventLogFunction::<4>.into_llvm(context)?; - - revive_llvm_context::PolkaVMDivisionFunction.into_llvm(context)?; - revive_llvm_context::PolkaVMSignedDivisionFunction.into_llvm(context)?; - revive_llvm_context::PolkaVMRemainderFunction.into_llvm(context)?; - revive_llvm_context::PolkaVMSignedRemainderFunction.into_llvm(context)?; - - revive_llvm_context::PolkaVMSbrkFunction.into_llvm(context)?; - Ok(()) } @@ -280,8 +259,37 @@ impl PolkaVMWriteLLVM for Object { context.set_debug_location(self.location.line, self.location.column, None)?; if self.identifier.ends_with("_deployed") { + context.set_code_type(PolkaVMCodeType::Runtime); revive_llvm_context::PolkaVMRuntimeCodeFunction::new(self.code).into_llvm(context)?; } else { + context.set_code_type(PolkaVMCodeType::Deploy); + revive_llvm_context::PolkaVMEntryFunction::default().into_llvm(context)?; + revive_llvm_context::PolkaVMLoadImmutableDataFunction.into_llvm(context)?; + revive_llvm_context::PolkaVMStoreImmutableDataFunction.into_llvm(context)?; + + revive_llvm_context::PolkaVMLoadHeapWordFunction.into_llvm(context)?; + revive_llvm_context::PolkaVMStoreHeapWordFunction.into_llvm(context)?; + revive_llvm_context::PolkaVMLoadStorageWordFunction.into_llvm(context)?; + revive_llvm_context::PolkaVMStoreStorageWordFunction.into_llvm(context)?; + revive_llvm_context::PolkaVMLoadTransientStorageWordFunction.into_llvm(context)?; + revive_llvm_context::PolkaVMStoreTransientStorageWordFunction.into_llvm(context)?; + + revive_llvm_context::PolkaVMWordToPointerFunction.into_llvm(context)?; + revive_llvm_context::PolkaVMExitFunction.into_llvm(context)?; + + revive_llvm_context::PolkaVMEventLogFunction::<0>.into_llvm(context)?; + revive_llvm_context::PolkaVMEventLogFunction::<1>.into_llvm(context)?; + revive_llvm_context::PolkaVMEventLogFunction::<2>.into_llvm(context)?; + revive_llvm_context::PolkaVMEventLogFunction::<3>.into_llvm(context)?; + revive_llvm_context::PolkaVMEventLogFunction::<4>.into_llvm(context)?; + + revive_llvm_context::PolkaVMDivisionFunction.into_llvm(context)?; + revive_llvm_context::PolkaVMSignedDivisionFunction.into_llvm(context)?; + revive_llvm_context::PolkaVMRemainderFunction.into_llvm(context)?; + revive_llvm_context::PolkaVMSignedRemainderFunction.into_llvm(context)?; + + revive_llvm_context::PolkaVMSbrkFunction.into_llvm(context)?; + revive_llvm_context::PolkaVMDeployCodeFunction::new(self.code).into_llvm(context)?; }