mirror of
https://github.com/pezkuwichain/revive.git
synced 2026-05-09 15:18:00 +00:00
llvm-context: lazy handling of function arguments and immutable data (#282)
- Lazily load function arguments so that they can be passed as pointers. - Lazily call the immutable store function to avoid storing zero sized immutable data. --------- Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
This commit is contained in:
@@ -139,13 +139,14 @@ where
|
||||
identifier.inner,
|
||||
)
|
||||
})?;
|
||||
context.build_store(pointer, value.to_llvm())?;
|
||||
context.build_store(pointer, value.access(context)?)?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let llvm_type = value.to_llvm().into_struct_value().get_type();
|
||||
let value = value.access(context)?;
|
||||
let llvm_type = value.into_struct_value().get_type();
|
||||
let tuple_pointer = context.build_alloca(llvm_type, "assignment_pointer");
|
||||
context.build_store(tuple_pointer, value.to_llvm())?;
|
||||
context.build_store(tuple_pointer, value)?;
|
||||
|
||||
for (index, binding) in self.bindings.into_iter().enumerate() {
|
||||
context.set_debug_location(self.location.line, 0, None)?;
|
||||
|
||||
@@ -128,7 +128,10 @@ impl FunctionCall {
|
||||
Name::UserDefined(name) => {
|
||||
let mut values = Vec::with_capacity(self.arguments.len());
|
||||
for argument in self.arguments.into_iter().rev() {
|
||||
let value = argument.into_llvm(context)?.expect("Always exists").value;
|
||||
let value = argument
|
||||
.into_llvm(context)?
|
||||
.expect("Always exists")
|
||||
.access(context)?;
|
||||
values.push(value);
|
||||
}
|
||||
values.reverse();
|
||||
@@ -461,36 +464,29 @@ impl FunctionCall {
|
||||
}
|
||||
|
||||
Name::SLoad => {
|
||||
let arguments = self.pop_arguments_llvm::<D, 1>(context)?;
|
||||
revive_llvm_context::polkavm_evm_storage::load(
|
||||
context,
|
||||
arguments[0].into_int_value(),
|
||||
)
|
||||
.map(Some)
|
||||
let arguments = self.pop_arguments::<D, 1>(context)?;
|
||||
revive_llvm_context::polkavm_evm_storage::load(context, &arguments[0]).map(Some)
|
||||
}
|
||||
Name::SStore => {
|
||||
let arguments = self.pop_arguments_llvm::<D, 2>(context)?;
|
||||
let arguments = self.pop_arguments::<D, 2>(context)?;
|
||||
revive_llvm_context::polkavm_evm_storage::store(
|
||||
context,
|
||||
arguments[0].into_int_value(),
|
||||
arguments[1].into_int_value(),
|
||||
&arguments[0],
|
||||
&arguments[1],
|
||||
)
|
||||
.map(|_| None)
|
||||
}
|
||||
Name::TLoad => {
|
||||
let arguments = self.pop_arguments_llvm::<D, 1>(context)?;
|
||||
revive_llvm_context::polkavm_evm_storage::transient_load(
|
||||
context,
|
||||
arguments[0].into_int_value(),
|
||||
)
|
||||
.map(Some)
|
||||
let arguments = self.pop_arguments::<D, 1>(context)?;
|
||||
revive_llvm_context::polkavm_evm_storage::transient_load(context, &arguments[0])
|
||||
.map(Some)
|
||||
}
|
||||
Name::TStore => {
|
||||
let arguments = self.pop_arguments_llvm::<D, 2>(context)?;
|
||||
let arguments = self.pop_arguments::<D, 2>(context)?;
|
||||
revive_llvm_context::polkavm_evm_storage::transient_store(
|
||||
context,
|
||||
arguments[0].into_int_value(),
|
||||
arguments[1].into_int_value(),
|
||||
&arguments[0],
|
||||
&arguments[1],
|
||||
)
|
||||
.map(|_| None)
|
||||
}
|
||||
@@ -514,7 +510,7 @@ impl FunctionCall {
|
||||
let offset = context.solidity_mut().allocate_immutable(key.as_str())
|
||||
/ revive_common::BYTE_LENGTH_WORD;
|
||||
let index = context.xlen_type().const_int(offset as u64, false);
|
||||
let value = arguments[2].value.into_int_value();
|
||||
let value = arguments[2].access(context)?.into_int_value();
|
||||
revive_llvm_context::polkavm_evm_immutable::store(context, index, value)
|
||||
.map(|_| None)
|
||||
}
|
||||
@@ -720,13 +716,13 @@ impl FunctionCall {
|
||||
Name::Call => {
|
||||
let arguments = self.pop_arguments::<D, 7>(context)?;
|
||||
|
||||
let gas = arguments[0].value.into_int_value();
|
||||
let address = arguments[1].value.into_int_value();
|
||||
let value = arguments[2].value.into_int_value();
|
||||
let input_offset = arguments[3].value.into_int_value();
|
||||
let input_size = arguments[4].value.into_int_value();
|
||||
let output_offset = arguments[5].value.into_int_value();
|
||||
let output_size = arguments[6].value.into_int_value();
|
||||
let gas = arguments[0].access(context)?.into_int_value();
|
||||
let address = arguments[1].access(context)?.into_int_value();
|
||||
let value = arguments[2].access(context)?.into_int_value();
|
||||
let input_offset = arguments[3].access(context)?.into_int_value();
|
||||
let input_size = arguments[4].access(context)?.into_int_value();
|
||||
let output_offset = arguments[5].access(context)?.into_int_value();
|
||||
let output_size = arguments[6].access(context)?.into_int_value();
|
||||
|
||||
let simulation_address: Vec<Option<num::BigUint>> = arguments
|
||||
.into_iter()
|
||||
@@ -750,12 +746,12 @@ impl FunctionCall {
|
||||
Name::StaticCall => {
|
||||
let arguments = self.pop_arguments::<D, 6>(context)?;
|
||||
|
||||
let gas = arguments[0].value.into_int_value();
|
||||
let address = arguments[1].value.into_int_value();
|
||||
let input_offset = arguments[2].value.into_int_value();
|
||||
let input_size = arguments[3].value.into_int_value();
|
||||
let output_offset = arguments[4].value.into_int_value();
|
||||
let output_size = arguments[5].value.into_int_value();
|
||||
let gas = arguments[0].access(context)?.into_int_value();
|
||||
let address = arguments[1].access(context)?.into_int_value();
|
||||
let input_offset = arguments[2].access(context)?.into_int_value();
|
||||
let input_size = arguments[3].access(context)?.into_int_value();
|
||||
let output_offset = arguments[4].access(context)?.into_int_value();
|
||||
let output_size = arguments[5].access(context)?.into_int_value();
|
||||
|
||||
let simulation_address: Vec<Option<num::BigUint>> = arguments
|
||||
.into_iter()
|
||||
@@ -779,12 +775,12 @@ impl FunctionCall {
|
||||
Name::DelegateCall => {
|
||||
let arguments = self.pop_arguments::<D, 6>(context)?;
|
||||
|
||||
let gas = arguments[0].value.into_int_value();
|
||||
let address = arguments[1].value.into_int_value();
|
||||
let input_offset = arguments[2].value.into_int_value();
|
||||
let input_size = arguments[3].value.into_int_value();
|
||||
let output_offset = arguments[4].value.into_int_value();
|
||||
let output_size = arguments[5].value.into_int_value();
|
||||
let gas = arguments[0].access(context)?.into_int_value();
|
||||
let address = arguments[1].access(context)?.into_int_value();
|
||||
let input_offset = arguments[2].access(context)?.into_int_value();
|
||||
let input_size = arguments[3].access(context)?.into_int_value();
|
||||
let output_offset = arguments[4].access(context)?.into_int_value();
|
||||
let output_size = arguments[5].access(context)?.into_int_value();
|
||||
|
||||
let simulation_address: Vec<Option<num::BigUint>> = arguments
|
||||
.into_iter()
|
||||
@@ -845,7 +841,8 @@ impl FunctionCall {
|
||||
})?;
|
||||
|
||||
revive_llvm_context::polkavm_evm_create::contract_hash(context, identifier)
|
||||
.map(|argument| Some(argument.value))
|
||||
.and_then(|argument| argument.access(context))
|
||||
.map(Some)
|
||||
}
|
||||
Name::DataSize => {
|
||||
let mut arguments = self.pop_arguments::<D, 1>(context)?;
|
||||
@@ -855,7 +852,8 @@ impl FunctionCall {
|
||||
})?;
|
||||
|
||||
revive_llvm_context::polkavm_evm_create::header_size(context, identifier)
|
||||
.map(|argument| Some(argument.value))
|
||||
.and_then(|argument| argument.access(context))
|
||||
.map(Some)
|
||||
}
|
||||
Name::DataCopy => {
|
||||
let arguments = self.pop_arguments_llvm::<D, 3>(context)?;
|
||||
@@ -989,7 +987,12 @@ impl FunctionCall {
|
||||
{
|
||||
let mut arguments = Vec::with_capacity(N);
|
||||
for expression in self.arguments.drain(0..N).rev() {
|
||||
arguments.push(expression.into_llvm(context)?.expect("Always exists").value);
|
||||
arguments.push(
|
||||
expression
|
||||
.into_llvm(context)?
|
||||
.expect("Always exists")
|
||||
.access(context)?,
|
||||
);
|
||||
}
|
||||
arguments.reverse();
|
||||
|
||||
|
||||
@@ -97,9 +97,7 @@ impl Literal {
|
||||
BooleanLiteral::True => num::BigUint::one(),
|
||||
};
|
||||
|
||||
Ok(revive_llvm_context::PolkaVMArgument::new_with_constant(
|
||||
value, constant,
|
||||
))
|
||||
Ok(revive_llvm_context::PolkaVMArgument::value(value).with_constant(constant))
|
||||
}
|
||||
LexicalLiteral::Integer(inner) => {
|
||||
let r#type = self.yul_type.unwrap_or_default().into_llvm(context);
|
||||
@@ -127,9 +125,7 @@ impl Literal {
|
||||
}
|
||||
.expect("Always valid");
|
||||
|
||||
Ok(revive_llvm_context::PolkaVMArgument::new_with_constant(
|
||||
value, constant,
|
||||
))
|
||||
Ok(revive_llvm_context::PolkaVMArgument::value(value).with_constant(constant))
|
||||
}
|
||||
LexicalLiteral::String(inner) => {
|
||||
let string = inner.inner;
|
||||
@@ -200,10 +196,10 @@ impl Literal {
|
||||
};
|
||||
|
||||
if hex_string.len() > revive_common::BYTE_LENGTH_WORD * 2 {
|
||||
return Ok(revive_llvm_context::PolkaVMArgument::new_with_original(
|
||||
return Ok(revive_llvm_context::PolkaVMArgument::value(
|
||||
r#type.const_zero().as_basic_value_enum(),
|
||||
string,
|
||||
));
|
||||
)
|
||||
.with_original(string));
|
||||
}
|
||||
|
||||
if hex_string.len() < revive_common::BYTE_LENGTH_WORD * 2 {
|
||||
@@ -220,9 +216,7 @@ impl Literal {
|
||||
)
|
||||
.expect("The value is valid")
|
||||
.as_basic_value_enum();
|
||||
Ok(revive_llvm_context::PolkaVMArgument::new_with_original(
|
||||
value, string,
|
||||
))
|
||||
Ok(revive_llvm_context::PolkaVMArgument::value(value).with_original(string))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,36 +119,28 @@ impl Expression {
|
||||
})
|
||||
.map(Some),
|
||||
Self::Identifier(identifier) => {
|
||||
let id = identifier.inner;
|
||||
|
||||
let pointer = context
|
||||
.current_function()
|
||||
.borrow()
|
||||
.get_stack_pointer(identifier.inner.as_str())
|
||||
.get_stack_pointer(&id)
|
||||
.ok_or_else(|| {
|
||||
anyhow::anyhow!(
|
||||
"{} Undeclared variable `{}`",
|
||||
identifier.location,
|
||||
identifier.inner,
|
||||
)
|
||||
anyhow::anyhow!("{} Undeclared variable `{}`", identifier.location, id)
|
||||
})?;
|
||||
|
||||
let constant = context
|
||||
.current_function()
|
||||
.borrow()
|
||||
.yul()
|
||||
.get_constant(identifier.inner.as_str());
|
||||
let constant = context.current_function().borrow().yul().get_constant(&id);
|
||||
|
||||
let value = context.build_load(pointer, identifier.inner.as_str())?;
|
||||
let argument = revive_llvm_context::PolkaVMArgument::pointer(pointer, id);
|
||||
|
||||
match constant {
|
||||
Some(constant) => Ok(Some(
|
||||
revive_llvm_context::PolkaVMArgument::new_with_constant(value, constant),
|
||||
)),
|
||||
None => Ok(Some(value.into())),
|
||||
}
|
||||
Ok(Some(match constant {
|
||||
Some(constant) => argument.with_constant(constant),
|
||||
_ => argument,
|
||||
}))
|
||||
}
|
||||
Self::FunctionCall(call) => Ok(call
|
||||
.into_llvm(context)?
|
||||
.map(revive_llvm_context::PolkaVMArgument::new)),
|
||||
.map(revive_llvm_context::PolkaVMArgument::value)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ where
|
||||
.condition
|
||||
.into_llvm(context)?
|
||||
.expect("Always exists")
|
||||
.to_llvm()
|
||||
.access(context)?
|
||||
.into_int_value();
|
||||
let condition = context.builder().build_int_z_extend_or_bit_cast(
|
||||
condition,
|
||||
|
||||
@@ -57,7 +57,7 @@ where
|
||||
.condition
|
||||
.into_llvm(context)?
|
||||
.expect("Always exists")
|
||||
.to_llvm()
|
||||
.access(context)?
|
||||
.into_int_value();
|
||||
let condition = context.builder().build_int_z_extend_or_bit_cast(
|
||||
condition,
|
||||
|
||||
@@ -137,7 +137,7 @@ where
|
||||
|
||||
let mut branches = Vec::with_capacity(self.cases.len());
|
||||
for (index, case) in self.cases.into_iter().enumerate() {
|
||||
let constant = case.literal.into_llvm(context)?.to_llvm();
|
||||
let constant = case.literal.into_llvm(context)?.access(context)?;
|
||||
|
||||
let expression_block = context
|
||||
.append_basic_block(format!("switch_case_branch_{}_block", index + 1).as_str());
|
||||
@@ -161,7 +161,10 @@ where
|
||||
|
||||
context.set_basic_block(current_block);
|
||||
context.builder().build_switch(
|
||||
scrutinee.expect("Always exists").to_llvm().into_int_value(),
|
||||
scrutinee
|
||||
.expect("Always exists")
|
||||
.access(context)?
|
||||
.into_int_value(),
|
||||
default_block,
|
||||
branches.as_slice(),
|
||||
)?;
|
||||
|
||||
@@ -121,7 +121,7 @@ where
|
||||
.insert_constant(identifier.inner.clone(), constant);
|
||||
}
|
||||
|
||||
value.to_llvm()
|
||||
value.access(context)?
|
||||
}
|
||||
None => r#type.const_zero().as_basic_value_enum(),
|
||||
}
|
||||
@@ -175,7 +175,8 @@ where
|
||||
.collect::<Vec<inkwell::types::BasicTypeEnum<'ctx>>>()
|
||||
.as_slice(),
|
||||
);
|
||||
if expression.value.get_type() != llvm_type.as_basic_type_enum() {
|
||||
let value = expression.access(context)?;
|
||||
if value.get_type() != llvm_type.as_basic_type_enum() {
|
||||
anyhow::bail!(
|
||||
"{} Assignment to {:?} received an invalid number of arguments",
|
||||
location,
|
||||
@@ -183,7 +184,7 @@ where
|
||||
);
|
||||
}
|
||||
let pointer = context.build_alloca(llvm_type, "bindings_pointer");
|
||||
context.build_store(pointer, expression.to_llvm())?;
|
||||
context.build_store(pointer, value)?;
|
||||
|
||||
for (index, binding) in self.bindings.into_iter().enumerate() {
|
||||
let pointer = context.build_gep(
|
||||
|
||||
Reference in New Issue
Block a user