mirror of
https://github.com/pezkuwichain/revive.git
synced 2026-04-25 19:57:57 +00:00
llvm-context: modularize compiler builtin functions (#234)
- Add the revive runtime function interface to minimize boiler plate code. - Outline heavily repeated code into dedicated functions to bring down code size. - The code size tests builds optimized for size. - Function attributes are passed as slices. This significantly brings down the code size for all OpenZeppelin wizard contracts (using all possible features) compiled against OpenZeppelin `v5.0.0` with size optimizations. |contract|| `-Oz` main | `-Oz` PR || `-O3` main | `-O3` PR | |-|-|-|-|-|-|-| |erc1155.sol||100K|67K||114K|147K| |erc20.sol||120K|90K||160K|191K| |erc721.sol||128K|101K||178K|214K| |governor.sol||226K|165K||293K|349K| |rwa.sol||116K|85K||154K|185K| |stable.sol||116K|86K||155K|192K| On the flip side this introduces a heavy penalty for cycle optimized builds. Setting the no-inline attributes for cycle optimized builds helps a lot but heavily penalizes runtime speed (LLVM does not yet inline everything properly - to be investigated later on). Next steps: - Modularize more functions - Refactor the YUL function arguments to use pointers instead of values - Afterwards check if LLVM still has trouble inline-ing properly on O3 or set the no-inline attribute if it does not penalize runtime performance too bad.
This commit is contained in:
@@ -6,6 +6,7 @@ use std::path::PathBuf;
|
||||
use std::sync::Mutex;
|
||||
|
||||
use once_cell::sync::Lazy;
|
||||
use revive_llvm_context::OptimizerSettings;
|
||||
|
||||
use crate::project::Project;
|
||||
use crate::solc::solc_compiler::SolcCompiler;
|
||||
@@ -31,6 +32,7 @@ struct CachedBlob {
|
||||
contract_name: String,
|
||||
solidity: String,
|
||||
solc_optimizer_enabled: bool,
|
||||
opt: String,
|
||||
}
|
||||
|
||||
/// Checks if the required executables are present in `${PATH}`.
|
||||
@@ -254,7 +256,12 @@ pub fn check_solidity_warning(
|
||||
/// Compile the blob of `contract_name` found in given `source_code`.
|
||||
/// The `solc` optimizer will be enabled
|
||||
pub fn compile_blob(contract_name: &str, source_code: &str) -> Vec<u8> {
|
||||
compile_blob_with_options(contract_name, source_code, true)
|
||||
compile_blob_with_options(
|
||||
contract_name,
|
||||
source_code,
|
||||
true,
|
||||
OptimizerSettings::cycles(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Compile the EVM bin-runtime of `contract_name` found in given `source_code`.
|
||||
@@ -283,6 +290,7 @@ fn compile_evm(
|
||||
contract_name: contract_name.to_owned(),
|
||||
solidity: source_code.to_owned(),
|
||||
solc_optimizer_enabled,
|
||||
opt: String::new(),
|
||||
};
|
||||
|
||||
let cache = if runtime {
|
||||
@@ -322,11 +330,13 @@ pub fn compile_blob_with_options(
|
||||
contract_name: &str,
|
||||
source_code: &str,
|
||||
solc_optimizer_enabled: bool,
|
||||
optimizer_settings: revive_llvm_context::OptimizerSettings,
|
||||
) -> Vec<u8> {
|
||||
let id = CachedBlob {
|
||||
contract_name: contract_name.to_owned(),
|
||||
solidity: source_code.to_owned(),
|
||||
solc_optimizer_enabled,
|
||||
opt: optimizer_settings.middle_end_as_string(),
|
||||
};
|
||||
|
||||
if let Some(blob) = PVM_BLOB_CACHE.lock().unwrap().get(&id) {
|
||||
@@ -338,7 +348,7 @@ pub fn compile_blob_with_options(
|
||||
[(file_name.into(), source_code.into())].into(),
|
||||
Default::default(),
|
||||
None,
|
||||
revive_llvm_context::OptimizerSettings::cycles(),
|
||||
optimizer_settings,
|
||||
solc_optimizer_enabled,
|
||||
)
|
||||
.expect("source should compile")
|
||||
|
||||
@@ -672,7 +672,7 @@ impl FunctionCall {
|
||||
context,
|
||||
arguments[0].into_int_value(),
|
||||
arguments[1].into_int_value(),
|
||||
vec![],
|
||||
[],
|
||||
)
|
||||
.map(|_| None)
|
||||
}
|
||||
@@ -682,10 +682,7 @@ impl FunctionCall {
|
||||
context,
|
||||
arguments[0].into_int_value(),
|
||||
arguments[1].into_int_value(),
|
||||
arguments[2..]
|
||||
.iter()
|
||||
.map(|argument| argument.into_int_value())
|
||||
.collect(),
|
||||
[arguments[2]],
|
||||
)
|
||||
.map(|_| None)
|
||||
}
|
||||
@@ -695,10 +692,7 @@ impl FunctionCall {
|
||||
context,
|
||||
arguments[0].into_int_value(),
|
||||
arguments[1].into_int_value(),
|
||||
arguments[2..]
|
||||
.iter()
|
||||
.map(|argument| argument.into_int_value())
|
||||
.collect(),
|
||||
[arguments[2], arguments[3]],
|
||||
)
|
||||
.map(|_| None)
|
||||
}
|
||||
@@ -708,10 +702,7 @@ impl FunctionCall {
|
||||
context,
|
||||
arguments[0].into_int_value(),
|
||||
arguments[1].into_int_value(),
|
||||
arguments[2..]
|
||||
.iter()
|
||||
.map(|argument| argument.into_int_value())
|
||||
.collect(),
|
||||
[arguments[2], arguments[3], arguments[4]],
|
||||
)
|
||||
.map(|_| None)
|
||||
}
|
||||
@@ -721,10 +712,7 @@ impl FunctionCall {
|
||||
context,
|
||||
arguments[0].into_int_value(),
|
||||
arguments[1].into_int_value(),
|
||||
arguments[2..]
|
||||
.iter()
|
||||
.map(|argument| argument.into_int_value())
|
||||
.collect(),
|
||||
[arguments[2], arguments[3], arguments[4], arguments[5]],
|
||||
)
|
||||
.map(|_| None)
|
||||
}
|
||||
|
||||
@@ -216,7 +216,7 @@ where
|
||||
revive_llvm_context::PolkaVMFunction::set_attributes(
|
||||
context.llvm(),
|
||||
function.borrow().declaration(),
|
||||
self.attributes.clone().into_iter().collect(),
|
||||
&self.attributes.clone().into_iter().collect::<Vec<_>>(),
|
||||
true,
|
||||
);
|
||||
function
|
||||
|
||||
@@ -185,7 +185,28 @@ where
|
||||
&mut self,
|
||||
context: &mut revive_llvm_context::PolkaVMContext<D>,
|
||||
) -> anyhow::Result<()> {
|
||||
revive_llvm_context::PolkaVMImmutableDataLoadFunction.declare(context)?;
|
||||
revive_llvm_context::PolkaVMLoadImmutableDataFunction.declare(context)?;
|
||||
revive_llvm_context::PolkaVMStoreImmutableDataFunction.declare(context)?;
|
||||
|
||||
revive_llvm_context::PolkaVMLoadHeapWordFunction.declare(context)?;
|
||||
revive_llvm_context::PolkaVMStoreHeapWordFunction.declare(context)?;
|
||||
revive_llvm_context::PolkaVMLoadStorageWordFunction.declare(context)?;
|
||||
revive_llvm_context::PolkaVMStoreStorageWordFunction.declare(context)?;
|
||||
|
||||
revive_llvm_context::PolkaVMWordToPointerFunction.declare(context)?;
|
||||
revive_llvm_context::PolkaVMExitFunction.declare(context)?;
|
||||
|
||||
revive_llvm_context::PolkaVMEventLogFunction::<0>.declare(context)?;
|
||||
revive_llvm_context::PolkaVMEventLogFunction::<1>.declare(context)?;
|
||||
revive_llvm_context::PolkaVMEventLogFunction::<2>.declare(context)?;
|
||||
revive_llvm_context::PolkaVMEventLogFunction::<3>.declare(context)?;
|
||||
revive_llvm_context::PolkaVMEventLogFunction::<4>.declare(context)?;
|
||||
|
||||
revive_llvm_context::PolkaVMDivisionFunction.declare(context)?;
|
||||
revive_llvm_context::PolkaVMSignedDivisionFunction.declare(context)?;
|
||||
revive_llvm_context::PolkaVMRemainderFunction.declare(context)?;
|
||||
revive_llvm_context::PolkaVMSignedRemainderFunction.declare(context)?;
|
||||
|
||||
let mut entry = revive_llvm_context::PolkaVMEntryFunction::default();
|
||||
entry.declare(context)?;
|
||||
|
||||
@@ -202,7 +223,6 @@ where
|
||||
revive_llvm_context::PolkaVMFunctionDeployCode,
|
||||
revive_llvm_context::PolkaVMFunctionRuntimeCode,
|
||||
revive_llvm_context::PolkaVMFunctionEntry,
|
||||
revive_llvm_context::PolkaVMFunctionImmutableDataLoad,
|
||||
]
|
||||
.into_iter()
|
||||
{
|
||||
@@ -215,6 +235,28 @@ where
|
||||
|
||||
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::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)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -230,7 +272,6 @@ where
|
||||
}
|
||||
|
||||
if self.identifier.ends_with("_deployed") {
|
||||
revive_llvm_context::PolkaVMImmutableDataLoadFunction.into_llvm(context)?;
|
||||
revive_llvm_context::PolkaVMRuntimeCodeFunction::new(self.code).into_llvm(context)?;
|
||||
} else {
|
||||
revive_llvm_context::PolkaVMDeployCodeFunction::new(self.code).into_llvm(context)?;
|
||||
|
||||
Reference in New Issue
Block a user