Compare commits

..

5 Commits

Author SHA1 Message Date
xermicus af8074cfde Merge branch 'main' into cl/optsize 2025-07-14 22:01:32 +02:00
Cyrill Leutwiler bb3b6ddb41 wip evm builtins
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-07-03 15:36:11 +02:00
Cyrill Leutwiler dfe56f9306 wip: args and returns
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-07-03 10:08:26 +02:00
Cyrill Leutwiler 63011b6d24 type fix
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-07-02 21:22:02 +02:00
Cyrill Leutwiler d40ef3e462 wip: variables
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-07-02 20:16:06 +02:00
25 changed files with 535 additions and 162 deletions
+7 -7
View File
@@ -1,10 +1,10 @@
{
"Baseline": 945,
"Computation": 2308,
"DivisionArithmetics": 2334,
"ERC20": 21363,
"Events": 1677,
"FibonacciIterative": 1516,
"Baseline": 939,
"Computation": 2282,
"DivisionArithmetics": 8849,
"ERC20": 18308,
"Events": 1640,
"FibonacciIterative": 1497,
"Flipper": 2099,
"SHA1": 8268
"SHA1": 8243
}
+1
View File
@@ -19,6 +19,7 @@ pub use self::polkavm::context::function::declaration::Declaration as PolkaVMFun
pub use self::polkavm::context::function::intrinsics::Intrinsics as PolkaVMIntrinsicFunction;
pub use self::polkavm::context::function::llvm_runtime::LLVMRuntime as PolkaVMLLVMRuntime;
pub use self::polkavm::context::function::r#return::Return as PolkaVMFunctionReturn;
pub use self::polkavm::context::function::runtime::arithmetics::Addition as PolkaVMAdditionFunction;
pub use self::polkavm::context::function::runtime::arithmetics::Division as PolkaVMDivisionFunction;
pub use self::polkavm::context::function::runtime::arithmetics::Remainder as PolkaVMRemainderFunction;
pub use self::polkavm::context::function::runtime::arithmetics::SignedDivision as PolkaVMSignedDivisionFunction;
@@ -7,7 +7,7 @@ pub mod r#return;
pub mod runtime;
pub mod yul_data;
use std::collections::HashMap;
use std::collections::{BTreeMap, HashMap};
use inkwell::debug_info::AsDIScope;
@@ -15,8 +15,6 @@ use crate::optimizer::settings::size_level::SizeLevel;
use crate::optimizer::Optimizer;
use crate::polkavm::context::attribute::Attribute;
use crate::polkavm::context::pointer::Pointer;
use crate::polkavm::context::Context;
use crate::polkavm::Dependency;
use self::declaration::Declaration;
use self::r#return::Return;
@@ -30,9 +28,11 @@ pub struct Function<'ctx> {
/// The LLVM function declaration.
declaration: Declaration<'ctx>,
/// The stack representation.
stack: HashMap<String, u64>,
/// The stack variables pointer.
stack_variables: Pointer<'ctx>,
stack: HashMap<String, Pointer<'ctx>>,
/// The stack variables buffer.
stack_variables: inkwell::values::GlobalValue<'ctx>,
/// The stack variable names to slot mapping.
stack_slots: BTreeMap<String, usize>,
/// The return value entity.
r#return: Return<'ctx>,
@@ -57,17 +57,17 @@ impl<'ctx> Function<'ctx> {
name: String,
declaration: Declaration<'ctx>,
r#return: Return<'ctx>,
stack_variables: inkwell::values::GlobalValue<'ctx>,
entry_block: inkwell::basic_block::BasicBlock<'ctx>,
return_block: inkwell::basic_block::BasicBlock<'ctx>,
stack_variables: Pointer<'ctx>,
) -> Self {
Self {
name,
declaration,
stack: HashMap::with_capacity(Self::STACK_HASHMAP_INITIAL_CAPACITY),
stack_variables,
stack_slots: BTreeMap::new(),
r#return,
entry_block,
@@ -217,49 +217,22 @@ impl<'ctx> Function<'ctx> {
/// Saves the pointer to a stack variable, returning the pointer to the shadowed variable,
/// if it exists.
pub fn insert_stack_pointer<D: Dependency + Clone>(
pub fn insert_stack_pointer(
&mut self,
context: &mut Context<'ctx, D>,
name: String,
) -> Pointer<'ctx> {
let pointer_name = format!("{}_stack_pointer", &name);
let len = self.stack.len();
let index = *self.stack.entry(name).or_insert_with(|| len as u64);
let indices = &[
context.xlen_type().const_zero(),
context.xlen_type().const_int(index, false),
];
context.build_gep(
self.stack_variables,
indices,
context.word_type(),
&pointer_name,
)
pointer: Pointer<'ctx>,
) -> Option<Pointer<'ctx>> {
self.stack.insert(name, pointer)
}
/// Gets the pointer to a stack variable.
pub fn get_stack_pointer<D: Dependency + Clone>(
&self,
context: &mut Context<'ctx, D>,
name: String,
) -> Pointer<'ctx> {
let pointer_name = format!("{}_stack_pointer", &name);
let index = *self
.stack
.get(&name)
.unwrap_or_else(|| panic!("stack pointer access prior to insertion: {name}"));
let indices = &[
context.xlen_type().const_zero(),
context.xlen_type().const_int(index, false),
];
pub fn get_stack_pointer(&self, name: &str) -> Option<Pointer<'ctx>> {
self.stack.get(name).copied()
}
context.build_gep(
self.stack_variables,
indices,
context.word_type(),
&pointer_name,
)
/// Removes the pointer to a stack variable.
pub fn remove_stack_pointer(&mut self, name: &str) {
self.stack.remove(name);
}
/// Returns the return entity representation.
@@ -313,4 +286,45 @@ impl<'ctx> Function<'ctx> {
.as_mut()
.expect("The Yul data must have been initialized")
}
/// Returns the stack variables global value.
pub fn stack_variables(&self) -> inkwell::values::GlobalValue<'ctx> {
self.stack_variables
}
/// Returns the slot for the given variable name.
pub fn stack_variable_slot(&mut self, name: String) -> usize {
let len = self.stack_slots.len();
*self.stack_slots.entry(name).or_insert_with(|| len)
}
/// References the stack variable `name`.
pub fn stack_variable_pointer<D: crate::PolkaVMDependency + Clone>(
&mut self,
name: String,
context: &mut super::Context<'ctx, D>,
) -> Pointer<'ctx> {
if let Some(pointer) = self.get_stack_pointer(&name) {
return pointer;
}
let pointer_name = format!("var_{}", &name);
let slot = self.stack_variable_slot(name);
Pointer::new(
context.word_type(),
Default::default(),
unsafe {
context.builder().build_gep(
context.word_type().array_type(0),
self.stack_variables().as_pointer_value(),
&[
context.xlen_type().const_zero(),
context.xlen_type().const_int(slot as u64, false),
],
&pointer_name,
)
}
.unwrap(),
)
}
}
@@ -7,6 +7,65 @@ use crate::polkavm::context::Context;
use crate::polkavm::Dependency;
use crate::polkavm::WriteLLVM;
/// Implements the division operator according to the EVM specification.
pub struct Addition;
impl<D> RuntimeFunction<D> for Addition
where
D: Dependency + Clone,
{
const NAME: &'static str = "__revive_addition";
fn r#type<'ctx>(context: &Context<'ctx, D>) -> inkwell::types::FunctionType<'ctx> {
context.void_type().fn_type(
&[
context.llvm().ptr_type(Default::default()).into(),
context.llvm().ptr_type(Default::default()).into(),
context.llvm().ptr_type(Default::default()).into(),
],
false,
)
}
fn emit_body<'ctx>(
&self,
context: &mut Context<'ctx, D>,
) -> anyhow::Result<Option<inkwell::values::BasicValueEnum<'ctx>>> {
let result_pointer = Self::paramater(context, 0).into_pointer_value();
let operand_1 = Self::paramater(context, 1).into_pointer_value();
let operand_2 = Self::paramater(context, 2).into_pointer_value();
let operand_1 = context
.builder()
.build_load(context.word_type(), operand_1, "operand_1")?
.into_int_value();
let operand_2 = context
.builder()
.build_load(context.word_type(), operand_2, "operand_2")?
.into_int_value();
let result = context
.builder()
.build_int_add(operand_1, operand_2, "addition_result")?;
context.builder().build_store(result_pointer, result)?;
Ok(None)
}
}
impl<D> WriteLLVM<D> for Addition
where
D: Dependency + Clone,
{
fn declare(&mut self, context: &mut Context<D>) -> anyhow::Result<()> {
<Self as RuntimeFunction<_>>::declare(self, context)
}
fn into_llvm(self, context: &mut Context<D>) -> anyhow::Result<()> {
<Self as RuntimeFunction<_>>::emit(&self, context)
}
}
/// Implements the division operator according to the EVM specification.
pub struct Division;
@@ -48,7 +48,6 @@ where
function_type,
0,
Some(inkwell::module::Linkage::External),
1024,
)?;
self.inner.declare(context)
@@ -145,7 +145,6 @@ where
entry_function_type,
0,
Some(inkwell::module::Linkage::External),
0,
)?;
context.declare_global(
@@ -48,7 +48,6 @@ where
function_type,
0,
Some(inkwell::module::Linkage::External),
1024,
)?;
self.inner.declare(context)
+26 -38
View File
@@ -463,7 +463,6 @@ where
r#type: inkwell::types::FunctionType<'ctx>,
return_values_length: usize,
linkage: Option<inkwell::module::Linkage>,
stack_variables: u32,
) -> anyhow::Result<Rc<RefCell<Function<'ctx>>>> {
let value = self.module().add_function(name, r#type, linkage);
@@ -485,30 +484,15 @@ where
let entry_block = self.llvm.append_basic_block(value, "entry");
let return_block = self.llvm.append_basic_block(value, "return");
self.builder().position_at_end(entry_block);
let stack_variables_pointer = self.build_alloca(
self.word_type().array_type(stack_variables),
"stack_variables",
);
let r#return = match return_values_length {
0 => FunctionReturn::none(),
1 => {
//self.set_basic_block(entry_block);
//let pointer = self
// .current_function()
// .borrow_mut()
// .insert_stack_pointer(self, format!("{name}_return_pointer"));
FunctionReturn::primitive(self.build_gep(
stack_variables_pointer,
&[self.xlen_type().const_zero(), self.xlen_type().const_zero()],
self.word_type(),
"return_pointer",
))
self.set_basic_block(entry_block);
let pointer = self.build_alloca(self.word_type(), "return_pointer");
FunctionReturn::primitive(pointer)
}
size => {
//self.set_basic_block(entry_block);
self.set_basic_block(entry_block);
let pointer = self.build_alloca(
self.structure_type(
vec![self.word_type().as_basic_type_enum(); size].as_slice(),
@@ -519,13 +503,19 @@ where
}
};
let stack_variables = format!("__vars_{name}");
self.declare_global(
&stack_variables,
self.word_type().array_type(0),
Default::default(),
);
let function = Function::new(
name.to_owned(),
FunctionDeclaration::new(r#type, value),
r#return,
self.get_global(&stack_variables).unwrap().value,
entry_block,
return_block,
stack_variables_pointer,
);
Function::set_default_attributes(self.llvm, function.declaration(), &self.optimizer);
let function = Rc::new(RefCell::new(function));
@@ -753,23 +743,6 @@ where
pointer
}
pub fn variable_decl<T: BasicType<'ctx> + Clone + Copy>(
&self,
r#type: T,
name: &str,
) -> Pointer<'ctx> {
let pointer = self.builder.build_alloca(r#type, name).unwrap();
pointer
.as_instruction()
.unwrap()
.set_alignment(revive_common::BYTE_LENGTH_STACK_ALIGN as u32)
.expect("Alignment is valid");
Pointer::new(r#type, AddressSpace::Stack, pointer)
}
/// Truncate `address` to the ethereum address length and store it as bytes on the stack.
/// Builds an aligned stack allocation at the current position.
/// Use this if [`build_alloca_at_entry`] might change program semantics.
/// Otherwise, alloca should always be built at the function prelude!
@@ -1305,6 +1278,20 @@ where
where
T: BasicType<'ctx>,
{
let argument_types: Vec<inkwell::types::BasicMetadataTypeEnum> =
vec![self.llvm().ptr_type(Default::default()).into(); return_values_size]
.into_iter()
.chain(
argument_types
.as_slice()
.iter()
.map(T::as_basic_type_enum)
.map(inkwell::types::BasicMetadataTypeEnum::from),
)
.collect();
self.void_type().fn_type(&argument_types.as_slice(), false)
/*
let argument_types: Vec<inkwell::types::BasicMetadataTypeEnum> = argument_types
.as_slice()
.iter()
@@ -1321,6 +1308,7 @@ where
.structure_type(vec![self.word_type().as_basic_type_enum(); size].as_slice())
.fn_type(argument_types.as_slice(), false),
}
*/
}
/// Modifies the call site value, setting the default attributes.
@@ -8,6 +8,7 @@ use crate::polkavm::context::Context;
use crate::polkavm::Dependency;
pub mod heap;
//pub mod stack;
pub mod storage;
/// The LLVM pointer.
@@ -0,0 +1,111 @@
//! The revive simulated EVM stack variable functions.
use inkwell::values::BasicValueEnum;
use crate::polkavm::context::runtime::RuntimeFunction;
use crate::polkavm::context::Context;
use crate::polkavm::Dependency;
use crate::polkavm::WriteLLVM;
/// Load a word size value from a heap pointer.
pub struct DeclareVariable;
impl<D> RuntimeFunction<D> for DeclareVariable
where
D: Dependency + Clone,
{
const NAME: &'static str = "__revive_declare_variable";
fn r#type<'ctx>(context: &Context<'ctx, D>) -> inkwell::types::FunctionType<'ctx> {
context
.llvm
.ptr_type(Default::default())
.fn_type(&[context.xlen_type().into()], false)
}
fn emit_body<'ctx>(
&self,
context: &mut Context<'ctx, D>,
) -> anyhow::Result<Option<BasicValueEnum<'ctx>>> {
let offset = Self::paramater(context, 0).into_int_value();
let length = context
.xlen_type()
.const_int(revive_common::BYTE_LENGTH_WORD as u64, false);
let pointer = context.build_heap_gep(offset, length)?;
let value = context
.builder()
.build_load(context.word_type(), pointer.value, "value")?;
context
.basic_block()
.get_last_instruction()
.expect("Always exists")
.set_alignment(revive_common::BYTE_LENGTH_BYTE as u32)
.expect("Alignment is valid");
let swapped_value = context.build_byte_swap(value)?;
Ok(Some(swapped_value))
}
}
impl<D> WriteLLVM<D> for LoadWord
where
D: Dependency + Clone,
{
fn declare(&mut self, context: &mut Context<D>) -> anyhow::Result<()> {
<Self as RuntimeFunction<_>>::declare(self, context)
}
fn into_llvm(self, context: &mut Context<D>) -> anyhow::Result<()> {
<Self as RuntimeFunction<_>>::emit(&self, context)
}
}
/// Store a word size value through a heap pointer.
pub struct StoreWord;
impl<D> RuntimeFunction<D> for StoreWord
where
D: Dependency + Clone,
{
const NAME: &'static str = "__revive_store_heap_word";
fn r#type<'ctx>(context: &Context<'ctx, D>) -> inkwell::types::FunctionType<'ctx> {
context.void_type().fn_type(
&[context.xlen_type().into(), context.word_type().into()],
false,
)
}
fn emit_body<'ctx>(
&self,
context: &mut Context<'ctx, D>,
) -> anyhow::Result<Option<BasicValueEnum<'ctx>>> {
let offset = Self::paramater(context, 0).into_int_value();
let length = context
.xlen_type()
.const_int(revive_common::BYTE_LENGTH_WORD as u64, false);
let pointer = context.build_heap_gep(offset, length)?;
let value = context.build_byte_swap(Self::paramater(context, 1))?;
context
.builder()
.build_store(pointer.value, value)?
.set_alignment(revive_common::BYTE_LENGTH_BYTE as u32)
.expect("Alignment is valid");
Ok(None)
}
}
impl<D> WriteLLVM<D> for StoreWord
where
D: Dependency + Clone,
{
fn declare(&mut self, context: &mut Context<D>) -> anyhow::Result<()> {
<Self as RuntimeFunction<_>>::declare(self, context)
}
fn into_llvm(self, context: &mut Context<D>) -> anyhow::Result<()> {
<Self as RuntimeFunction<_>>::emit(&self, context)
}
}
@@ -35,7 +35,6 @@ where
Self::r#type(context),
0,
Some(inkwell::module::Linkage::External),
0,
)?;
let mut attributes = Self::ATTRIBUTES.to_vec();
@@ -40,7 +40,6 @@ pub fn check_attribute_null_pointer_is_invalid() {
.fn_type(&[context.word_type().into()], false),
1,
Some(inkwell::module::Linkage::External),
16,
)
.expect("Failed to add function");
assert!(!function
@@ -64,7 +63,6 @@ pub fn check_attribute_optimize_for_size_mode_3() {
.fn_type(&[context.word_type().into()], false),
1,
Some(inkwell::module::Linkage::External),
16,
)
.expect("Failed to add function");
assert!(!function
@@ -88,7 +86,6 @@ pub fn check_attribute_optimize_for_size_mode_z() {
.fn_type(&[context.word_type().into()], false),
1,
Some(inkwell::module::Linkage::External),
16,
)
.expect("Failed to add function");
assert!(function
@@ -112,7 +109,6 @@ pub fn check_attribute_min_size_mode_3() {
.fn_type(&[context.word_type().into()], false),
1,
Some(inkwell::module::Linkage::External),
16,
)
.expect("Failed to add function");
assert!(!function
@@ -136,7 +132,6 @@ pub fn check_attribute_min_size_mode_z() {
.fn_type(&[context.word_type().into()], false),
1,
Some(inkwell::module::Linkage::External),
16,
)
.expect("Failed to add function");
assert!(function
@@ -5,6 +5,7 @@ use inkwell::values::BasicValue;
use crate::polkavm::context::runtime::RuntimeFunction;
use crate::polkavm::context::Context;
use crate::polkavm::Dependency;
use crate::PolkaVMAdditionFunction;
use crate::PolkaVMDivisionFunction;
use crate::PolkaVMRemainderFunction;
use crate::PolkaVMSignedDivisionFunction;
@@ -13,16 +14,20 @@ use crate::PolkaVMSignedRemainderFunction;
/// Translates the arithmetic addition.
pub fn addition<'ctx, D>(
context: &mut Context<'ctx, D>,
operand_1: inkwell::values::IntValue<'ctx>,
operand_2: inkwell::values::IntValue<'ctx>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
binding: inkwell::values::PointerValue<'ctx>,
operand_1: inkwell::values::PointerValue<'ctx>,
operand_2: inkwell::values::PointerValue<'ctx>,
) -> anyhow::Result<()>
where
D: Dependency + Clone,
{
Ok(context
.builder()
.build_int_add(operand_1, operand_2, "addition_result")?
.as_basic_value_enum())
let declaration = <PolkaVMAdditionFunction as RuntimeFunction<D>>::declaration(context);
context.build_call(
declaration,
&[binding.into(), operand_1.into(), operand_2.into()],
"add",
);
Ok(())
}
/// Translates the arithmetic subtraction.
+39 -7
View File
@@ -115,13 +115,29 @@ impl<D> revive_llvm_context::PolkaVMWriteLLVM<D> for Assignment
where
D: revive_llvm_context::PolkaVMDependency + Clone,
{
fn into_llvm(
fn into_llvm<'ctx>(
mut self,
context: &mut revive_llvm_context::PolkaVMContext<D>,
context: &mut revive_llvm_context::PolkaVMContext<'ctx, D>,
) -> anyhow::Result<()> {
context.set_debug_location(self.location.line, 0, None)?;
let value = match self.initializer.into_llvm(context)? {
let bindings: Vec<(String, revive_llvm_context::PolkaVMPointer<'ctx>)> = self
.bindings
.into_iter()
.map(|binding| {
(
binding.inner.clone(),
context
.current_function()
.borrow_mut()
.stack_variable_pointer(binding.inner, context),
)
})
.collect();
self.initializer.into_llvm(bindings.as_slice(), context)?;
/*
let value = match self.initializer.into_llvm(bindings.as_slice(), context)? {
Some(value) => value,
None => return Ok(()),
};
@@ -130,8 +146,15 @@ where
let identifier = self.bindings.remove(0);
let pointer = context
.current_function()
.borrow_mut()
.get_stack_pointer(context, identifier.inner.clone());
.borrow()
.get_stack_pointer(identifier.inner.as_str())
.ok_or_else(|| {
anyhow::anyhow!(
"{} Assignment to an undeclared variable `{}`",
identifier.location,
identifier.inner,
)
})?;
context.build_store(pointer, value.access(context)?)?;
return Ok(());
}
@@ -158,8 +181,15 @@ where
let binding_pointer = context
.current_function()
.borrow_mut()
.get_stack_pointer(context, binding.inner.clone());
.borrow()
.get_stack_pointer(binding.inner.as_str())
.ok_or_else(|| {
anyhow::anyhow!(
"{} Assignment to an undeclared variable `{}`",
binding.location,
binding.inner,
)
})?;
let value = context.build_load(
field_pointer,
format!("assignment_binding_{index}_value").as_str(),
@@ -167,6 +197,8 @@ where
context.build_store(binding_pointer, value)?;
}
*/
Ok(())
}
}
+1 -1
View File
@@ -184,7 +184,7 @@ where
block.into_llvm(context)?;
}
Statement::Expression(expression) => {
expression.into_llvm(context)?;
expression.into_llvm(&[], context)?;
}
Statement::VariableDeclaration(statement) => statement.into_llvm(context)?,
Statement::Assignment(statement) => statement.into_llvm(context)?,
@@ -117,8 +117,9 @@ impl FunctionCall {
/// Converts the function call into an LLVM value.
pub fn into_llvm<'ctx, D>(
mut self,
bindings: &[(String, revive_llvm_context::PolkaVMPointer<'ctx>)],
context: &mut revive_llvm_context::PolkaVMContext<'ctx, D>,
) -> anyhow::Result<Option<inkwell::values::BasicValueEnum<'ctx>>>
) -> anyhow::Result<()>
where
D: revive_llvm_context::PolkaVMDependency + Clone,
{
@@ -127,15 +128,26 @@ impl FunctionCall {
match self.name {
Name::UserDefined(name) => {
let mut values = Vec::with_capacity(self.arguments.len());
for argument in self.arguments.into_iter().rev() {
let mut values = Vec::with_capacity(bindings.len() + self.arguments.len());
for (n, argument) in self.arguments.into_iter().rev().enumerate() {
let id = format!("arg_{n}");
let binding_pointer = context.build_alloca(context.word_type(), &id);
let value = argument
.into_llvm(context)?
.into_llvm(&[(id, binding_pointer)], context)?
.expect("Always exists")
.access(context)?;
.as_pointer(context)?
.value
.as_basic_value_enum();
values.push(value);
}
values.reverse();
let values = bindings
.into_iter()
.map(|(_, pointer)| pointer.value.as_basic_value_enum())
.chain(values.into_iter())
.collect::<Vec<_>>();
let function = context.get_function(name.as_str()).ok_or_else(|| {
anyhow::anyhow!("{} Undeclared function `{}`", location, name)
})?;
@@ -152,23 +164,24 @@ impl FunctionCall {
);
}
let return_value = context.build_call(
let _return_value = context.build_call(
function.borrow().declaration(),
values.as_slice(),
format!("{name}_call").as_str(),
);
Ok(return_value)
Ok(())
}
Name::Add => {
let arguments = self.pop_arguments_llvm::<D, 2>(context)?;
revive_llvm_context::polkavm_evm_arithmetic::addition(
context,
arguments[0].into_int_value(),
arguments[1].into_int_value(),
)
.map(Some)
bindings,
arguments[0].into_pointer_value(),
arguments[1].into_pointer_value(),
)?;
Ok(())
}
Name::Sub => {
let arguments = self.pop_arguments_llvm::<D, 2>(context)?;
@@ -987,10 +1000,12 @@ impl FunctionCall {
D: revive_llvm_context::PolkaVMDependency + Clone,
{
let mut arguments = Vec::with_capacity(N);
for expression in self.arguments.drain(0..N).rev() {
for (index, expression) in self.arguments.drain(0..N).rev().enumerate() {
let name = format!("arg_{index}");
let pointer = context.build_alloca(context.word_type(), &name);
arguments.push(
expression
.into_llvm(context)?
.into_llvm(&[(name, pointer)], context)?
.expect("Always exists")
.access(context)?,
);
@@ -1009,8 +1024,14 @@ impl FunctionCall {
D: revive_llvm_context::PolkaVMDependency + Clone,
{
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"));
for (index, expression) in self.arguments.drain(0..N).rev().enumerate() {
let name = format!("arg_{index}");
let pointer = context.build_alloca(context.word_type(), &name);
arguments.push(
expression
.into_llvm(&[(name, pointer)], context)?
.expect("Always exists"),
);
}
arguments.reverse();
@@ -72,6 +72,7 @@ impl Literal {
/// Converts the literal into its LLVM.
pub fn into_llvm<'ctx, D>(
self,
binding: Option<(String, revive_llvm_context::PolkaVMPointer<'ctx>)>,
context: &revive_llvm_context::PolkaVMContext<'ctx, D>,
) -> anyhow::Result<revive_llvm_context::PolkaVMArgument<'ctx>>
where
@@ -97,7 +98,17 @@ impl Literal {
BooleanLiteral::True => num::BigUint::one(),
};
Ok(revive_llvm_context::PolkaVMArgument::value(value).with_constant(constant))
match binding {
Some((id, pointer)) => {
context.build_store(pointer, value)?;
Ok(revive_llvm_context::PolkaVMArgument::pointer(pointer, id)
.with_constant(constant))
}
None => {
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);
@@ -125,7 +136,17 @@ impl Literal {
}
.expect("Always valid");
Ok(revive_llvm_context::PolkaVMArgument::value(value).with_constant(constant))
match binding {
Some((id, pointer)) => {
context.build_store(pointer, value)?;
Ok(revive_llvm_context::PolkaVMArgument::pointer(pointer, id)
.with_constant(constant))
}
None => {
Ok(revive_llvm_context::PolkaVMArgument::value(value)
.with_constant(constant))
}
}
}
LexicalLiteral::String(inner) => {
let string = inner.inner;
@@ -216,7 +237,16 @@ impl Literal {
)
.expect("The value is valid")
.as_basic_value_enum();
Ok(revive_llvm_context::PolkaVMArgument::value(value).with_original(string))
match binding {
Some((id, pointer)) => {
context.build_store(pointer, value)?;
Ok(revive_llvm_context::PolkaVMArgument::pointer(pointer, id)
.with_original(string))
}
None => Ok(
revive_llvm_context::PolkaVMArgument::value(value).with_original(string)
),
}
}
}
}
@@ -100,6 +100,7 @@ impl Expression {
/// Converts the expression into an LLVM value.
pub fn into_llvm<'ctx, D>(
self,
bindings: &[(String, revive_llvm_context::PolkaVMPointer<'ctx>)],
context: &mut revive_llvm_context::PolkaVMContext<'ctx, D>,
) -> anyhow::Result<Option<revive_llvm_context::PolkaVMArgument<'ctx>>>
where
@@ -108,7 +109,13 @@ impl Expression {
match self {
Self::Literal(literal) => literal
.clone()
.into_llvm(context)
.into_llvm(
bindings
.first()
.to_owned()
.map(|(id, binding)| (id.to_string(), *binding)),
context,
)
.map_err(|error| {
anyhow::anyhow!(
"{} Invalid literal `{}`: {}",
@@ -123,8 +130,11 @@ impl Expression {
let pointer = context
.current_function()
.borrow_mut()
.get_stack_pointer(context, id.clone());
.borrow()
.get_stack_pointer(&id)
.ok_or_else(|| {
anyhow::anyhow!("{} Undeclared variable `{}`", identifier.location, id)
})?;
let constant = context.current_function().borrow().yul().get_constant(&id);
@@ -135,9 +145,10 @@ impl Expression {
_ => argument,
}))
}
Self::FunctionCall(call) => Ok(call
.into_llvm(context)?
.map(revive_llvm_context::PolkaVMArgument::value)),
Self::FunctionCall(call) => {
call.into_llvm(bindings, context)?;
Ok(None)
}
}
}
}
+2 -1
View File
@@ -74,9 +74,10 @@ where
context.build_unconditional_branch(condition_block);
context.set_basic_block(condition_block);
let binding_pointer = context.build_alloca(context.word_type(), "if_condition");
let condition = self
.condition
.into_llvm(context)?
.into_llvm(&[("todo".to_string(), binding_pointer)], context)?
.expect("Always exists")
.access(context)?
.into_int_value();
@@ -212,7 +212,6 @@ where
function_type,
self.result.len(),
Some(inkwell::module::Linkage::External),
1024,
)?;
revive_llvm_context::PolkaVMFunction::set_attributes(
context.llvm(),
@@ -232,8 +231,80 @@ where
context: &mut revive_llvm_context::PolkaVMContext<D>,
) -> anyhow::Result<()> {
context.set_current_function(self.identifier.as_str(), Some(self.location.line))?;
context.set_basic_block(context.current_function().borrow().entry_block());
let return_types: Vec<_> = self
.arguments
.iter()
.map(|argument| {
let yul_type = argument.r#type.to_owned().unwrap_or_default();
yul_type.into_llvm(context)
})
.collect();
for (index, argument) in self.result.iter().enumerate() {
let pointer = context
.current_function()
.borrow()
.get_nth_param(index)
.into_pointer_value();
let pointer = revive_llvm_context::PolkaVMPointer::new(
return_types[index],
Default::default(),
pointer,
);
context.build_store(pointer, pointer.r#type.const_zero())?;
context
.current_function()
.borrow_mut()
.insert_stack_pointer(argument.inner.clone(), pointer);
}
let argument_types: Vec<_> = self
.arguments
.iter()
.map(|argument| {
let yul_type = argument.r#type.to_owned().unwrap_or_default();
yul_type.into_llvm(context)
})
.collect();
for (index, argument) in self.arguments.iter().enumerate() {
let pointer = context
.current_function()
.borrow()
.get_nth_param(index + self.result.len())
.into_pointer_value();
let pointer = revive_llvm_context::PolkaVMPointer::new(
argument_types[index],
Default::default(),
pointer,
);
context
.current_function()
.borrow_mut()
.insert_stack_pointer(argument.inner.clone(), pointer);
}
self.body.into_llvm(context)?;
context.set_debug_location(self.location.line, 0, None)?;
match context
.basic_block()
.get_last_instruction()
.map(|instruction| instruction.get_opcode())
{
Some(inkwell::values::InstructionOpcode::Br) => {}
Some(inkwell::values::InstructionOpcode::Switch) => {}
_ => context
.build_unconditional_branch(context.current_function().borrow().return_block()),
}
context.set_basic_block(context.current_function().borrow().return_block());
context.build_return(None);
context.pop_debug_scope();
/*
let r#return = context.current_function().borrow().r#return();
match r#return {
revive_llvm_context::PolkaVMFunctionReturn::None => {}
@@ -245,7 +316,7 @@ where
context
.current_function()
.borrow_mut()
.insert_stack_pointer(context, identifier.inner);
.insert_stack_pointer(identifier.inner, pointer);
}
revive_llvm_context::PolkaVMFunctionReturn::Compound { pointer, .. } => {
for (index, identifier) in self.result.into_iter().enumerate() {
@@ -265,24 +336,25 @@ where
context
.current_function()
.borrow_mut()
.insert_stack_pointer(context, identifier.inner.clone());
.insert_stack_pointer(identifier.inner.clone(), pointer);
}
}
};
//let argument_types: Vec<_> = self
// .arguments
// .iter()
// .map(|argument| {
// let yul_type = argument.r#type.to_owned().unwrap_or_default();
// yul_type.into_llvm(context)
// })
// .collect();
let argument_types: Vec<_> = self
.arguments
.iter()
.map(|argument| {
let yul_type = argument.r#type.to_owned().unwrap_or_default();
yul_type.into_llvm(context)
})
.collect();
for (index, argument) in self.arguments.iter().enumerate() {
let pointer = context
let pointer = context.build_alloca(argument_types[index], argument.inner.as_str());
context
.current_function()
.borrow_mut()
.insert_stack_pointer(context, argument.inner.clone());
.insert_stack_pointer(argument.inner.clone(), pointer);
context.build_store(
pointer,
context.current_function().borrow().get_nth_param(index),
@@ -319,6 +391,7 @@ where
}
context.pop_debug_scope();
*/
Ok(())
}
@@ -53,10 +53,11 @@ where
D: revive_llvm_context::PolkaVMDependency + Clone,
{
fn into_llvm(self, context: &mut revive_llvm_context::PolkaVMContext<D>) -> anyhow::Result<()> {
let binding_pointer = context.build_alloca(context.word_type(), "if_condition");
context.set_debug_location(self.location.line, 0, None)?;
let condition = self
.condition
.into_llvm(context)?
.into_llvm(&[("todo".to_string(), binding_pointer)], context)?
.expect("Always exists")
.access(context)?
.into_int_value();
@@ -204,6 +204,7 @@ where
revive_llvm_context::PolkaVMEventLogFunction::<3>.declare(context)?;
revive_llvm_context::PolkaVMEventLogFunction::<4>.declare(context)?;
revive_llvm_context::PolkaVMAdditionFunction.declare(context)?;
revive_llvm_context::PolkaVMDivisionFunction.declare(context)?;
revive_llvm_context::PolkaVMSignedDivisionFunction.declare(context)?;
revive_llvm_context::PolkaVMRemainderFunction.declare(context)?;
@@ -258,6 +259,7 @@ where
revive_llvm_context::PolkaVMEventLogFunction::<3>.into_llvm(context)?;
revive_llvm_context::PolkaVMEventLogFunction::<4>.into_llvm(context)?;
revive_llvm_context::PolkaVMAdditionFunction.into_llvm(context)?;
revive_llvm_context::PolkaVMDivisionFunction.into_llvm(context)?;
revive_llvm_context::PolkaVMSignedDivisionFunction.into_llvm(context)?;
revive_llvm_context::PolkaVMRemainderFunction.into_llvm(context)?;
@@ -123,7 +123,7 @@ where
D: revive_llvm_context::PolkaVMDependency + Clone,
{
fn into_llvm(self, context: &mut revive_llvm_context::PolkaVMContext<D>) -> anyhow::Result<()> {
let scrutinee = self.expression.into_llvm(context)?;
let scrutinee = self.expression.into_llvm(&[], context)?;
if self.cases.is_empty() {
if let Some(block) = self.default {
@@ -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)?.access(context)?;
let constant = case.literal.into_llvm(None, context)?.access(context)?;
let expression_block = context
.append_basic_block(format!("switch_case_branch_{}_block", index + 1).as_str());
@@ -99,15 +99,35 @@ where
mut self,
context: &mut revive_llvm_context::PolkaVMContext<'ctx, D>,
) -> anyhow::Result<()> {
let bindings: Vec<(String, revive_llvm_context::PolkaVMPointer<'ctx>)> = self
.bindings
.into_iter()
.map(|binding| {
(
binding.inner.clone(),
context
.current_function()
.borrow_mut()
.stack_variable_pointer(binding.inner, context),
)
})
.collect();
if let Some(expression) = self.expression {
expression.into_llvm(&bindings, context)?;
}
/*
if self.bindings.len() == 1 {
let identifier = self.bindings.remove(0);
context.set_debug_location(self.location.line, 0, None)?;
let identifier_type = identifier.r#type.clone().unwrap_or_default();
let r#type = identifier_type.into_llvm(context);
let pointer = context
let pointer = context.build_alloca(r#type, identifier.inner.as_str());
context
.current_function()
.borrow_mut()
.insert_stack_pointer(context, identifier.inner.clone());
.insert_stack_pointer(identifier.inner.clone(), pointer);
let value = if let Some(expression) = self.expression {
match expression.into_llvm(context)? {
@@ -139,11 +159,15 @@ where
.to_owned()
.unwrap_or_default()
.into_llvm(context);
let pointer = context
let pointer = context.build_alloca(
yul_type.as_basic_type_enum(),
format!("binding_{index}_pointer").as_str(),
);
context.build_store(pointer, yul_type.const_zero())?;
context
.current_function()
.borrow_mut()
.insert_stack_pointer(context, binding.inner.to_owned());
context.build_store(pointer, yul_type.const_zero())?;
.insert_stack_pointer(binding.inner.to_owned(), pointer);
}
let expression = match self.expression.take() {
@@ -198,9 +222,17 @@ where
let pointer = context
.current_function()
.borrow_mut()
.get_stack_pointer(context, binding.inner.to_owned());
.get_stack_pointer(binding.inner.as_str())
.ok_or_else(|| {
anyhow::anyhow!(
"{} Assignment to an undeclared variable `{}`",
binding.location,
binding.inner
)
})?;
context.build_store(pointer, value)?;
}
*/
Ok(())
}
+1 -1
View File
@@ -74,7 +74,7 @@ impl Type {
//Self::Int(bitlength) => context.integer_type(bitlength),
Self::UInt(bitlength) => context.integer_type(bitlength),
//Self::Custom(_) => context.word_type(),
_ => unreachable!("no other YUL type is supported"),
_ => panic!("oh no"),
}
}
}