diff --git a/crates/llvm-context/src/polkavm/context/function/mod.rs b/crates/llvm-context/src/polkavm/context/function/mod.rs index 15a3222..3fc16e8 100644 --- a/crates/llvm-context/src/polkavm/context/function/mod.rs +++ b/crates/llvm-context/src/polkavm/context/function/mod.rs @@ -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; @@ -29,6 +29,10 @@ pub struct Function<'ctx> { declaration: Declaration<'ctx>, /// The stack representation. stack: HashMap>, + /// The stack variables buffer. + stack_variables: inkwell::values::GlobalValue<'ctx>, + /// The stack variable names to slot mapping. + stack_slots: BTreeMap, /// The return value entity. r#return: Return<'ctx>, @@ -53,6 +57,7 @@ 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>, @@ -61,6 +66,8 @@ impl<'ctx> Function<'ctx> { name, declaration, stack: HashMap::with_capacity(Self::STACK_HASHMAP_INITIAL_CAPACITY), + stack_variables, + stack_slots: BTreeMap::new(), r#return, entry_block, @@ -279,4 +286,40 @@ 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) + } + + pub fn stack_variable_pointer( + &mut self, + name: String, + context: &mut super::Context<'ctx, D>, + ) -> Pointer<'ctx> { + 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(), + self.stack_variables().as_pointer_value(), + &[ + context.xlen_type().const_zero(), + context.xlen_type().const_int(slot as u64, false), + ], + &pointer_name, + ) + } + .unwrap(), + ) + } } diff --git a/crates/llvm-context/src/polkavm/context/mod.rs b/crates/llvm-context/src/polkavm/context/mod.rs index 368c390..798961a 100644 --- a/crates/llvm-context/src/polkavm/context/mod.rs +++ b/crates/llvm-context/src/polkavm/context/mod.rs @@ -503,10 +503,17 @@ 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, ); diff --git a/crates/llvm-context/src/polkavm/context/pointer/mod.rs b/crates/llvm-context/src/polkavm/context/pointer/mod.rs index afd1e5e..044b86c 100644 --- a/crates/llvm-context/src/polkavm/context/pointer/mod.rs +++ b/crates/llvm-context/src/polkavm/context/pointer/mod.rs @@ -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. diff --git a/crates/llvm-context/src/polkavm/context/pointer/stack.rs b/crates/llvm-context/src/polkavm/context/pointer/stack.rs new file mode 100644 index 0000000..a5d8561 --- /dev/null +++ b/crates/llvm-context/src/polkavm/context/pointer/stack.rs @@ -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 RuntimeFunction 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>> { + 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 WriteLLVM for LoadWord +where + D: Dependency + Clone, +{ + fn declare(&mut self, context: &mut Context) -> anyhow::Result<()> { + >::declare(self, context) + } + + fn into_llvm(self, context: &mut Context) -> anyhow::Result<()> { + >::emit(&self, context) + } +} + +/// Store a word size value through a heap pointer. +pub struct StoreWord; + +impl RuntimeFunction 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>> { + 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 WriteLLVM for StoreWord +where + D: Dependency + Clone, +{ + fn declare(&mut self, context: &mut Context) -> anyhow::Result<()> { + >::declare(self, context) + } + + fn into_llvm(self, context: &mut Context) -> anyhow::Result<()> { + >::emit(&self, context) + } +} diff --git a/crates/yul/src/parser/statement/expression/mod.rs b/crates/yul/src/parser/statement/expression/mod.rs index 0bc0bd1..33886ad 100644 --- a/crates/yul/src/parser/statement/expression/mod.rs +++ b/crates/yul/src/parser/statement/expression/mod.rs @@ -100,6 +100,7 @@ impl Expression { /// Converts the expression into an LLVM value. pub fn into_llvm<'ctx, D>( self, + //bindings: &[String], context: &mut revive_llvm_context::PolkaVMContext<'ctx, D>, ) -> anyhow::Result>> where diff --git a/crates/yul/src/parser/statement/variable_declaration.rs b/crates/yul/src/parser/statement/variable_declaration.rs index fdf917e..013d1fe 100644 --- a/crates/yul/src/parser/statement/variable_declaration.rs +++ b/crates/yul/src/parser/statement/variable_declaration.rs @@ -99,6 +99,17 @@ where mut self, context: &mut revive_llvm_context::PolkaVMContext<'ctx, D>, ) -> anyhow::Result<()> { + let pointers: Vec> = self + .bindings + .into_iter() + .map(|binding| { + context + .current_function() + .borrow_mut() + .stack_variable_pointer(binding.inner, context) + }) + .collect(); + /* if self.bindings.len() == 1 { let identifier = self.bindings.remove(0); context.set_debug_location(self.location.line, 0, None)?; @@ -213,6 +224,7 @@ where })?; context.build_store(pointer, value)?; } + */ Ok(()) } diff --git a/crates/yul/src/parser/type.rs b/crates/yul/src/parser/type.rs index ec4d8c4..7a76b03 100644 --- a/crates/yul/src/parser/type.rs +++ b/crates/yul/src/parser/type.rs @@ -70,10 +70,11 @@ impl Type { D: revive_llvm_context::PolkaVMDependency + Clone, { match self { - Self::Bool => context.integer_type(revive_common::BIT_LENGTH_BOOLEAN), - Self::Int(bitlength) => context.integer_type(bitlength), + //Self::Bool => context.integer_type(revive_common::BIT_LENGTH_BOOLEAN), + //Self::Int(bitlength) => context.integer_type(bitlength), Self::UInt(bitlength) => context.integer_type(bitlength), - Self::Custom(_) => context.word_type(), + //Self::Custom(_) => context.word_type(), + _ => panic!("oh no"), } } }