mirror of
https://github.com/pezkuwichain/revive.git
synced 2026-06-14 16:51:04 +00:00
a07968205b
- 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.
99 lines
2.5 KiB
Rust
99 lines
2.5 KiB
Rust
//! Translates the heap memory operations.
|
|
|
|
use inkwell::values::BasicValue;
|
|
|
|
use crate::polkavm::context::address_space::AddressSpace;
|
|
use crate::polkavm::context::pointer::Pointer;
|
|
use crate::polkavm::context::Context;
|
|
use crate::polkavm::Dependency;
|
|
|
|
/// Translates the `msize` instruction.
|
|
pub fn msize<'ctx, D>(
|
|
context: &mut Context<'ctx, D>,
|
|
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
|
|
where
|
|
D: Dependency + Clone,
|
|
{
|
|
Ok(context
|
|
.builder()
|
|
.build_int_z_extend(
|
|
context.build_msize()?,
|
|
context.word_type(),
|
|
"heap_size_extended",
|
|
)?
|
|
.as_basic_value_enum())
|
|
}
|
|
|
|
/// Translates the `mload` instruction.
|
|
/// Uses the main heap.
|
|
pub fn load<'ctx, D>(
|
|
context: &mut Context<'ctx, D>,
|
|
offset: inkwell::values::IntValue<'ctx>,
|
|
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
|
|
where
|
|
D: Dependency + Clone,
|
|
{
|
|
let pointer = Pointer::new_with_offset(
|
|
context,
|
|
AddressSpace::Heap,
|
|
context.word_type(),
|
|
offset,
|
|
"memory_load_pointer",
|
|
);
|
|
context.build_load(pointer, "memory_load_result")
|
|
}
|
|
|
|
/// Translates the `mstore` instruction.
|
|
/// Uses the main heap.
|
|
pub fn store<'ctx, D>(
|
|
context: &mut Context<'ctx, D>,
|
|
offset: inkwell::values::IntValue<'ctx>,
|
|
value: inkwell::values::IntValue<'ctx>,
|
|
) -> anyhow::Result<()>
|
|
where
|
|
D: Dependency + Clone,
|
|
{
|
|
let pointer = Pointer::new_with_offset(
|
|
context,
|
|
AddressSpace::Heap,
|
|
context.word_type(),
|
|
offset,
|
|
"memory_store_pointer",
|
|
);
|
|
context.build_store(pointer, value)?;
|
|
Ok(())
|
|
}
|
|
|
|
/// Translates the `mstore8` instruction.
|
|
/// Uses the main heap.
|
|
pub fn store_byte<'ctx, D>(
|
|
context: &mut Context<'ctx, D>,
|
|
offset: inkwell::values::IntValue<'ctx>,
|
|
value: inkwell::values::IntValue<'ctx>,
|
|
) -> anyhow::Result<()>
|
|
where
|
|
D: Dependency + Clone,
|
|
{
|
|
let byte_type = context.byte_type();
|
|
let value = context
|
|
.builder()
|
|
.build_int_truncate(value, byte_type, "mstore8_value")?;
|
|
let pointer = Pointer::new_with_offset(
|
|
context,
|
|
AddressSpace::Heap,
|
|
byte_type,
|
|
offset,
|
|
"mstore8_destination",
|
|
);
|
|
let pointer = context.build_sbrk(
|
|
pointer.to_int(context),
|
|
context.xlen_type().const_int(1, false),
|
|
)?;
|
|
context
|
|
.builder()
|
|
.build_store(pointer, value)?
|
|
.set_alignment(revive_common::BYTE_LENGTH_BYTE as u32)
|
|
.expect("Alignment is valid");
|
|
Ok(())
|
|
}
|