diff --git a/crates/llvm-context/src/polkavm/context/function/mod.rs b/crates/llvm-context/src/polkavm/context/function/mod.rs index fec49e0..5c65de7 100644 --- a/crates/llvm-context/src/polkavm/context/function/mod.rs +++ b/crates/llvm-context/src/polkavm/context/function/mod.rs @@ -298,11 +298,16 @@ impl<'ctx> Function<'ctx> { *self.stack_slots.entry(name).or_insert_with(|| len) } + /// References the stack variable `name`. pub fn stack_variable_pointer( &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( diff --git a/crates/llvm-context/src/polkavm/context/mod.rs b/crates/llvm-context/src/polkavm/context/mod.rs index 798961a..7861f46 100644 --- a/crates/llvm-context/src/polkavm/context/mod.rs +++ b/crates/llvm-context/src/polkavm/context/mod.rs @@ -1278,6 +1278,20 @@ where where T: BasicType<'ctx>, { + let argument_types: Vec = + 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 = argument_types .as_slice() .iter() @@ -1294,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. diff --git a/crates/yul/src/parser/statement/assignment.rs b/crates/yul/src/parser/statement/assignment.rs index c3079e2..810c2d7 100644 --- a/crates/yul/src/parser/statement/assignment.rs +++ b/crates/yul/src/parser/statement/assignment.rs @@ -115,13 +115,29 @@ impl revive_llvm_context::PolkaVMWriteLLVM for Assignment where D: revive_llvm_context::PolkaVMDependency + Clone, { - fn into_llvm( + fn into_llvm<'ctx>( mut self, - context: &mut revive_llvm_context::PolkaVMContext, + 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(()), }; @@ -181,6 +197,8 @@ where context.build_store(binding_pointer, value)?; } + */ + Ok(()) } } diff --git a/crates/yul/src/parser/statement/block.rs b/crates/yul/src/parser/statement/block.rs index 07d38c2..a3817a8 100644 --- a/crates/yul/src/parser/statement/block.rs +++ b/crates/yul/src/parser/statement/block.rs @@ -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)?, diff --git a/crates/yul/src/parser/statement/expression/function_call/mod.rs b/crates/yul/src/parser/statement/expression/function_call/mod.rs index 44bbf98..d704e5e 100644 --- a/crates/yul/src/parser/statement/expression/function_call/mod.rs +++ b/crates/yul/src/parser/statement/expression/function_call/mod.rs @@ -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>> + ) -> anyhow::Result<()> where D: revive_llvm_context::PolkaVMDependency + Clone, { @@ -126,15 +127,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::>(); + let function = context.get_function(name.as_str()).ok_or_else(|| { anyhow::anyhow!("{} Undeclared function `{}`", location, name) })?; @@ -151,13 +163,13 @@ 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 => { diff --git a/crates/yul/src/parser/statement/expression/literal.rs b/crates/yul/src/parser/statement/expression/literal.rs index d7b10de..e90e5bf 100644 --- a/crates/yul/src/parser/statement/expression/literal.rs +++ b/crates/yul/src/parser/statement/expression/literal.rs @@ -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> 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) + ), + } } } } diff --git a/crates/yul/src/parser/statement/expression/mod.rs b/crates/yul/src/parser/statement/expression/mod.rs index 33886ad..2a27ae4 100644 --- a/crates/yul/src/parser/statement/expression/mod.rs +++ b/crates/yul/src/parser/statement/expression/mod.rs @@ -100,7 +100,7 @@ impl Expression { /// Converts the expression into an LLVM value. pub fn into_llvm<'ctx, D>( self, - //bindings: &[String], + bindings: &[(String, revive_llvm_context::PolkaVMPointer<'ctx>)], context: &mut revive_llvm_context::PolkaVMContext<'ctx, D>, ) -> anyhow::Result>> where @@ -109,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 `{}`: {}", @@ -139,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) + } } } } diff --git a/crates/yul/src/parser/statement/for_loop.rs b/crates/yul/src/parser/statement/for_loop.rs index 822e9b9..b49d99b 100644 --- a/crates/yul/src/parser/statement/for_loop.rs +++ b/crates/yul/src/parser/statement/for_loop.rs @@ -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(); diff --git a/crates/yul/src/parser/statement/function_definition.rs b/crates/yul/src/parser/statement/function_definition.rs index e776e4b..840a3f3 100644 --- a/crates/yul/src/parser/statement/function_definition.rs +++ b/crates/yul/src/parser/statement/function_definition.rs @@ -231,8 +231,80 @@ where context: &mut revive_llvm_context::PolkaVMContext, ) -> 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 => {} @@ -319,6 +391,7 @@ where } context.pop_debug_scope(); + */ Ok(()) } diff --git a/crates/yul/src/parser/statement/if_conditional.rs b/crates/yul/src/parser/statement/if_conditional.rs index 6703152..42de195 100644 --- a/crates/yul/src/parser/statement/if_conditional.rs +++ b/crates/yul/src/parser/statement/if_conditional.rs @@ -53,9 +53,10 @@ where D: revive_llvm_context::PolkaVMDependency + Clone, { fn into_llvm(self, context: &mut revive_llvm_context::PolkaVMContext) -> anyhow::Result<()> { + 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(); diff --git a/crates/yul/src/parser/statement/switch/mod.rs b/crates/yul/src/parser/statement/switch/mod.rs index 5c63edf..a5440e2 100644 --- a/crates/yul/src/parser/statement/switch/mod.rs +++ b/crates/yul/src/parser/statement/switch/mod.rs @@ -123,7 +123,7 @@ where D: revive_llvm_context::PolkaVMDependency + Clone, { fn into_llvm(self, context: &mut revive_llvm_context::PolkaVMContext) -> 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()); diff --git a/crates/yul/src/parser/statement/variable_declaration.rs b/crates/yul/src/parser/statement/variable_declaration.rs index c982f34..5006002 100644 --- a/crates/yul/src/parser/statement/variable_declaration.rs +++ b/crates/yul/src/parser/statement/variable_declaration.rs @@ -99,16 +99,25 @@ where mut self, context: &mut revive_llvm_context::PolkaVMContext<'ctx, D>, ) -> anyhow::Result<()> { - let _pointers: Vec> = self + let bindings: Vec<(String, revive_llvm_context::PolkaVMPointer<'ctx>)> = self .bindings - .iter() + .into_iter() .map(|binding| { - context - .current_function() - .borrow_mut() - .stack_variable_pointer(binding.inner.to_string(), context) + ( + 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)?; @@ -223,6 +232,7 @@ where })?; context.build_store(pointer, value)?; } + */ Ok(()) }