mirror of
https://github.com/pezkuwichain/revive.git
synced 2026-06-14 18:01:05 +00:00
b560d72139
Function symbols can clash as we compile multiple YUL `object` definition into the same `LLVM` module. - Disambiguate via unique function symbols based its location (runtime or deploy code). - Use `LinkOnceODR` linkage for compiler builtin helpers. --------- Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
118 lines
4.0 KiB
Rust
118 lines
4.0 KiB
Rust
//! The revive compiler runtime function interface definition.
|
|
//!
|
|
//! Common routines should not be inlined but extracted into smaller functions.
|
|
//! This benefits contract code size.
|
|
|
|
use crate::optimizer::settings::size_level::SizeLevel;
|
|
use crate::polkavm::context::function::declaration::Declaration;
|
|
use crate::polkavm::context::function::Function;
|
|
use crate::polkavm::context::Attribute;
|
|
use crate::polkavm::context::Context;
|
|
|
|
/// The revive runtime function interface simplifies declaring runtime functions
|
|
/// and code emitting by providing helpful default implementations.
|
|
pub trait RuntimeFunction {
|
|
/// The function name.
|
|
const NAME: &'static str;
|
|
|
|
const ATTRIBUTES: &'static [Attribute] = &[
|
|
Attribute::NoFree,
|
|
Attribute::NoRecurse,
|
|
Attribute::WillReturn,
|
|
];
|
|
|
|
/// The function type.
|
|
fn r#type<'ctx>(context: &Context<'ctx>) -> inkwell::types::FunctionType<'ctx>;
|
|
|
|
/// Declare the function.
|
|
fn declare(&self, context: &mut Context) -> anyhow::Result<()> {
|
|
let function = context.add_function(
|
|
Self::NAME,
|
|
Self::r#type(context),
|
|
0,
|
|
Some(inkwell::module::Linkage::LinkOnceODR),
|
|
None,
|
|
false,
|
|
)?;
|
|
|
|
let mut attributes = Self::ATTRIBUTES.to_vec();
|
|
attributes.extend_from_slice(match context.optimizer_settings().level_middle_end_size {
|
|
SizeLevel::Zero => &[],
|
|
_ => &[Attribute::OptimizeForSize, Attribute::MinSize],
|
|
});
|
|
Function::set_attributes(
|
|
context.llvm(),
|
|
function.borrow().declaration(),
|
|
&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(())
|
|
}
|
|
|
|
/// Get the function declaration.
|
|
fn declaration<'ctx>(context: &Context<'ctx>) -> Declaration<'ctx> {
|
|
context
|
|
.get_function(Self::NAME, false)
|
|
.unwrap_or_else(|| panic!("runtime function {} should be declared", Self::NAME))
|
|
.borrow()
|
|
.declaration()
|
|
}
|
|
|
|
/// Emit the function.
|
|
fn emit(&self, context: &mut Context) -> anyhow::Result<()> {
|
|
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)?;
|
|
self.emit_epilogue(context, return_value);
|
|
|
|
context.pop_debug_scope();
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Emit the function body.
|
|
fn emit_body<'ctx>(
|
|
&self,
|
|
context: &mut Context<'ctx>,
|
|
) -> anyhow::Result<Option<inkwell::values::BasicValueEnum<'ctx>>>;
|
|
|
|
/// Emit the function return instructions.
|
|
fn emit_epilogue<'ctx>(
|
|
&self,
|
|
context: &mut Context<'ctx>,
|
|
return_value: Option<inkwell::values::BasicValueEnum<'ctx>>,
|
|
) {
|
|
let return_block = context.current_function().borrow().return_block();
|
|
context.build_unconditional_branch(return_block);
|
|
context.set_basic_block(return_block);
|
|
match return_value {
|
|
Some(value) => context.build_return(Some(&value)),
|
|
None => context.build_return(None),
|
|
}
|
|
}
|
|
|
|
/// Get the nth function paramater.
|
|
fn paramater<'ctx>(
|
|
context: &Context<'ctx>,
|
|
index: usize,
|
|
) -> inkwell::values::BasicValueEnum<'ctx> {
|
|
let name = Self::NAME;
|
|
context
|
|
.get_function(name, false)
|
|
.unwrap_or_else(|| panic!("runtime function {name} should be declared"))
|
|
.borrow()
|
|
.declaration()
|
|
.function_value()
|
|
.get_nth_param(index as u32)
|
|
.unwrap_or_else(|| panic!("runtime function {name} should have parameter #{index}"))
|
|
}
|
|
}
|