mirror of
https://github.com/pezkuwichain/revive.git
synced 2026-06-15 06:51:07 +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:
@@ -81,8 +81,7 @@ impl<'ctx> Function<'ctx> {
|
||||
|| (name.starts_with("__")
|
||||
&& name != self::runtime::FUNCTION_ENTRY
|
||||
&& name != self::runtime::FUNCTION_DEPLOY_CODE
|
||||
&& name != self::runtime::FUNCTION_RUNTIME_CODE
|
||||
&& name != self::runtime::FUNCTION_LOAD_IMMUTABLE_DATA)
|
||||
&& name != self::runtime::FUNCTION_RUNTIME_CODE)
|
||||
}
|
||||
|
||||
/// Returns the LLVM function declaration.
|
||||
@@ -110,30 +109,21 @@ impl<'ctx> Function<'ctx> {
|
||||
pub fn set_attributes(
|
||||
llvm: &'ctx inkwell::context::Context,
|
||||
declaration: Declaration<'ctx>,
|
||||
attributes: Vec<Attribute>,
|
||||
attributes: &[Attribute],
|
||||
force: bool,
|
||||
) {
|
||||
for attribute_kind in attributes.into_iter() {
|
||||
for attribute_kind in attributes {
|
||||
match attribute_kind {
|
||||
Attribute::Memory => unimplemented!("`memory` attributes are not implemented"),
|
||||
attribute_kind @ Attribute::AlwaysInline if force => {
|
||||
let is_optimize_none_set = declaration
|
||||
.value
|
||||
.get_enum_attribute(
|
||||
inkwell::attributes::AttributeLoc::Function,
|
||||
Attribute::OptimizeNone as u32,
|
||||
)
|
||||
.is_some();
|
||||
if !is_optimize_none_set {
|
||||
declaration.value.remove_enum_attribute(
|
||||
inkwell::attributes::AttributeLoc::Function,
|
||||
Attribute::NoInline as u32,
|
||||
);
|
||||
declaration.value.add_attribute(
|
||||
inkwell::attributes::AttributeLoc::Function,
|
||||
llvm.create_enum_attribute(attribute_kind as u32, 0),
|
||||
);
|
||||
}
|
||||
declaration.value.remove_enum_attribute(
|
||||
inkwell::attributes::AttributeLoc::Function,
|
||||
Attribute::NoInline as u32,
|
||||
);
|
||||
declaration.value.add_attribute(
|
||||
inkwell::attributes::AttributeLoc::Function,
|
||||
llvm.create_enum_attribute(*attribute_kind as u32, 0),
|
||||
);
|
||||
}
|
||||
attribute_kind @ Attribute::NoInline if force => {
|
||||
declaration.value.remove_enum_attribute(
|
||||
@@ -142,12 +132,12 @@ impl<'ctx> Function<'ctx> {
|
||||
);
|
||||
declaration.value.add_attribute(
|
||||
inkwell::attributes::AttributeLoc::Function,
|
||||
llvm.create_enum_attribute(attribute_kind as u32, 0),
|
||||
llvm.create_enum_attribute(*attribute_kind as u32, 0),
|
||||
);
|
||||
}
|
||||
attribute_kind => declaration.value.add_attribute(
|
||||
inkwell::attributes::AttributeLoc::Function,
|
||||
llvm.create_enum_attribute(attribute_kind as u32, 0),
|
||||
llvm.create_enum_attribute(*attribute_kind as u32, 0),
|
||||
),
|
||||
}
|
||||
}
|
||||
@@ -178,27 +168,16 @@ impl<'ctx> Function<'ctx> {
|
||||
declaration: Declaration<'ctx>,
|
||||
optimizer: &Optimizer,
|
||||
) {
|
||||
if optimizer.settings().level_middle_end == inkwell::OptimizationLevel::None {
|
||||
Self::remove_attributes(
|
||||
declaration,
|
||||
&[Attribute::OptimizeForSize, Attribute::AlwaysInline],
|
||||
);
|
||||
if optimizer.settings().level_middle_end_size == SizeLevel::Z {
|
||||
Self::set_attributes(
|
||||
llvm,
|
||||
declaration,
|
||||
vec![Attribute::OptimizeNone, Attribute::NoInline],
|
||||
false,
|
||||
);
|
||||
} else if optimizer.settings().level_middle_end_size == SizeLevel::Z {
|
||||
Self::set_attributes(
|
||||
llvm,
|
||||
declaration,
|
||||
vec![Attribute::OptimizeForSize, Attribute::MinSize],
|
||||
&[Attribute::OptimizeForSize, Attribute::MinSize],
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
Self::set_attributes(llvm, declaration, vec![Attribute::NoFree], false);
|
||||
Self::set_attributes(llvm, declaration, &[Attribute::NoFree], false);
|
||||
}
|
||||
|
||||
/// Sets the front-end runtime attributes.
|
||||
@@ -208,7 +187,7 @@ impl<'ctx> Function<'ctx> {
|
||||
optimizer: &Optimizer,
|
||||
) {
|
||||
if optimizer.settings().level_middle_end_size == SizeLevel::Z {
|
||||
Self::set_attributes(llvm, declaration, vec![Attribute::NoInline], false);
|
||||
Self::set_attributes(llvm, declaration, &[Attribute::NoInline], false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,7 +199,7 @@ impl<'ctx> Function<'ctx> {
|
||||
Self::set_attributes(
|
||||
llvm,
|
||||
declaration,
|
||||
vec![
|
||||
&[
|
||||
Attribute::MustProgress,
|
||||
Attribute::NoUnwind,
|
||||
Attribute::WillReturn,
|
||||
|
||||
Reference in New Issue
Block a user