diff --git a/frontend-wasm2/src/code_translator/mod.rs b/frontend-wasm2/src/code_translator/mod.rs index d4bac4fc..adccd8d8 100644 --- a/frontend-wasm2/src/code_translator/mod.rs +++ b/frontend-wasm2/src/code_translator/mod.rs @@ -28,6 +28,7 @@ use wasmparser::{MemArg, Operator}; use crate::{ error::WasmResult, + intrinsics::{convert_intrinsics_call, is_miden_intrinsics_module}, miden_abi::{is_miden_abi_module, transform::transform_miden_abi_call}, module::{ func_translation_state::{ControlStackFrame, ElseData, FuncTranslationState}, @@ -675,15 +676,16 @@ fn translate_call( span: SourceSpan, diagnostics: &DiagnosticsHandler, ) -> WasmResult<()> { - let func_ref = module_state.get_direct_func(function_index, diagnostics)?; - let sig = func_ref.borrow().signature().clone(); - let num_args = sig.params().len(); - let args = func_state.peekn(num_args); - // if is_miden_intrinsics_module(func_id.module.as_symbol()) { - // let results = convert_intrinsics_call(func_id, args, builder, span); - // func_state.popn(num_wasm_args); - // func_state.pushn(&results); - // } else if is_miden_abi_module(func_id.module.as_symbol()) { + let defined_func = module_state.get_direct_func(function_index, diagnostics)?; + let wasm_sig = defined_func.signature.clone(); + let num_wasm_args = wasm_sig.params().len(); + let args = func_state.peekn(num_wasm_args); + if is_miden_intrinsics_module(defined_func.wasm_id.module.as_symbol()) { + let results = convert_intrinsics_call(&defined_func, args, builder, span)?; + func_state.popn(num_wasm_args); + func_state.pushn(&results); + } + // else if is_miden_abi_module(func_id.module.as_symbol()) { // // Miden SDK function call, transform the call to the Miden ABI if needed // let results = transform_miden_abi_call(func_id, args, builder, span, diagnostics); // assert_eq!( @@ -702,15 +704,18 @@ fn translate_call( // ); // func_state.popn(num_wasm_args); // func_state.pushn(&results); - // } else { code below } - - let exec = builder.ins().exec(func_ref, sig, args.to_vec(), span)?; - let borrow = exec.borrow(); - let results = borrow.as_ref().results(); - func_state.popn(num_args); - let result_vals: Vec = - results.iter().map(|op_res| op_res.borrow().as_value_ref()).collect(); - func_state.pushn(&result_vals); + else { + let func_ref = defined_func + .function_ref + .expect("expected DefinedFunction::function_ref to be set"); + let exec = builder.ins().exec(func_ref, wasm_sig, args.to_vec(), span)?; + let borrow = exec.borrow(); + let results = borrow.as_ref().results(); + func_state.popn(num_wasm_args); + let result_vals: Vec = + results.iter().map(|op_res| op_res.borrow().as_value_ref()).collect(); + func_state.pushn(&result_vals); + } Ok(()) } diff --git a/frontend-wasm2/src/intrinsics/felt.rs b/frontend-wasm2/src/intrinsics/felt.rs index c2c7547a..5e3d4504 100644 --- a/frontend-wasm2/src/intrinsics/felt.rs +++ b/frontend-wasm2/src/intrinsics/felt.rs @@ -1,9 +1,9 @@ use std::vec; -use midenc_hir::{FunctionIdent, InstBuilder, SourceSpan, Type::*, Value}; -use midenc_hir2::ValueRef; +use midenc_dialect_hir::InstBuilder; +use midenc_hir2::{FunctionIdent, SourceSpan, Type, ValueRef}; -use crate::module::function_builder_ext::FunctionBuilderExt; +use crate::{error::WasmResult, module::function_builder_ext::FunctionBuilderExt}; pub(crate) const MODULE_ID: &str = "intrinsics::felt"; @@ -13,121 +13,120 @@ pub(crate) fn convert_felt_intrinsics( args: &[ValueRef], builder: &mut FunctionBuilderExt<'_>, span: SourceSpan, -) -> Vec { - todo!() - // match func_id.function.as_symbol().as_str() { - // // Conversion operations - // "from_u64_unchecked" => { - // assert_eq!(args.len(), 1, "{} takes exactly one argument", func_id); - // let inst = builder.ins().cast(args[0], Felt, span); - // vec![inst] - // } - // "from_u32" => { - // assert_eq!(args.len(), 1, "{} takes exactly one argument", func_id); - // let inst = builder.ins().bitcast(args[0], Felt, span); - // vec![inst] - // } - // "as_u64" => { - // assert_eq!(args.len(), 1, "{} takes exactly one argument", func_id); - // // we're casting to i64 instead of u64 because Wasm doesn't have u64 - // // and this value will be used in Wasm ops or local vars that expect i64 - // let inst = builder.ins().cast(args[0], I64, span); - // vec![inst] - // } - // // Arithmetic operations - // "add" => { - // assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id); - // let inst = builder.ins().add_unchecked(args[0], args[1], span); - // vec![inst] - // } - // "sub" => { - // assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id); - // let inst = builder.ins().sub_unchecked(args[0], args[1], span); - // vec![inst] - // } - // "mul" => { - // assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id); - // let inst = builder.ins().mul_unchecked(args[0], args[1], span); - // vec![inst] - // } - // "div" => { - // assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id); - // let inst = builder.ins().div_unchecked(args[0], args[1], span); - // vec![inst] - // } - // "neg" => { - // assert_eq!(args.len(), 1, "{} takes exactly one argument", func_id); - // let inst = builder.ins().neg(args[0], span); - // vec![inst] - // } - // "inv" => { - // assert_eq!(args.len(), 1, "{} takes exactly one argument", func_id); - // let inst = builder.ins().inv(args[0], span); - // vec![inst] - // } - // "pow2" => { - // assert_eq!(args.len(), 1, "{} takes exactly one argument", func_id); - // let inst = builder.ins().pow2(args[0], span); - // vec![inst] - // } - // "exp" => { - // assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id); - // let inst = builder.ins().exp(args[0], args[1], span); - // vec![inst] - // } - // // Comparison operations - // "eq" => { - // assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id); - // let inst = builder.ins().eq(args[0], args[1], span); - // let cast = builder.ins().cast(inst, I32, span); - // vec![cast] - // } - // "gt" => { - // assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id); - // let inst = builder.ins().gt(args[0], args[1], span); - // let cast = builder.ins().cast(inst, I32, span); - // vec![cast] - // } - // "ge" => { - // assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id); - // let inst = builder.ins().gte(args[0], args[1], span); - // let cast = builder.ins().cast(inst, I32, span); - // vec![cast] - // } - // "lt" => { - // assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id); - // let inst = builder.ins().lt(args[0], args[1], span); - // let cast = builder.ins().cast(inst, I32, span); - // vec![cast] - // } - // "le" => { - // assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id); - // let inst = builder.ins().lte(args[0], args[1], span); - // let cast = builder.ins().cast(inst, I32, span); - // vec![cast] - // } - // "is_odd" => { - // assert_eq!(args.len(), 1, "{} takes exactly one argument", func_id); - // let inst = builder.ins().is_odd(args[0], span); - // let cast = builder.ins().cast(inst, I32, span); - // vec![cast] - // } - // // Assert operations - // "assert" => { - // assert_eq!(args.len(), 1, "{} takes exactly one argument", func_id); - // builder.ins().assert(args[0], span); - // vec![] - // } - // "assertz" => { - // assert_eq!(args.len(), 1, "{} takes exactly one argument", func_id); - // builder.ins().assertz(args[0], span); - // vec![] - // } - // "assert_eq" => { - // assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id); - // builder.ins().assert_eq(args[0], args[1], span); - // vec![] - // } - // _ => panic!("No felt op intrinsics found for {}", func_id), - // } +) -> WasmResult> { + match func_id.function.as_symbol().as_str() { + // Conversion operations + "from_u64_unchecked" => { + assert_eq!(args.len(), 1, "{} takes exactly one argument", func_id); + let inst = builder.ins().cast(args[0], Type::Felt, span)?; + Ok(vec![inst]) + } + "from_u32" => { + assert_eq!(args.len(), 1, "{} takes exactly one argument", func_id); + let inst = builder.ins().bitcast(args[0], Type::Felt, span)?; + Ok(vec![inst]) + } + "as_u64" => { + assert_eq!(args.len(), 1, "{} takes exactly one argument", func_id); + // we're casting to i64 instead of u64 because Wasm doesn't have u64 + // and this value will be used in Wasm ops or local vars that expect i64 + let inst = builder.ins().cast(args[0], Type::I64, span)?; + Ok(vec![inst]) + } + // Arithmetic operations + "add" => { + assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id); + let inst = builder.ins().add_unchecked(args[0], args[1], span)?; + Ok(vec![inst]) + } + "sub" => { + assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id); + let inst = builder.ins().sub_unchecked(args[0], args[1], span)?; + Ok(vec![inst]) + } + "mul" => { + assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id); + let inst = builder.ins().mul_unchecked(args[0], args[1], span)?; + Ok(vec![inst]) + } + "div" => { + assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id); + let inst = builder.ins().div(args[0], args[1], span)?; + Ok(vec![inst]) + } + "neg" => { + assert_eq!(args.len(), 1, "{} takes exactly one argument", func_id); + let inst = builder.ins().neg(args[0], span)?; + Ok(vec![inst]) + } + "inv" => { + assert_eq!(args.len(), 1, "{} takes exactly one argument", func_id); + let inst = builder.ins().inv(args[0], span)?; + Ok(vec![inst]) + } + "pow2" => { + assert_eq!(args.len(), 1, "{} takes exactly one argument", func_id); + let inst = builder.ins().pow2(args[0], span)?; + Ok(vec![inst]) + } + "exp" => { + assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id); + let inst = builder.ins().exp(args[0], args[1], span)?; + Ok(vec![inst]) + } + // Comparison operations + "eq" => { + assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id); + let inst = builder.ins().eq(args[0], args[1], span)?; + let cast = builder.ins().cast(inst, Type::I32, span)?; + Ok(vec![cast]) + } + "gt" => { + assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id); + let inst = builder.ins().gt(args[0], args[1], span)?; + let cast = builder.ins().cast(inst, Type::I32, span)?; + Ok(vec![cast]) + } + "ge" => { + assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id); + let inst = builder.ins().gte(args[0], args[1], span)?; + let cast = builder.ins().cast(inst, Type::I32, span)?; + Ok(vec![cast]) + } + "lt" => { + assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id); + let inst = builder.ins().lt(args[0], args[1], span)?; + let cast = builder.ins().cast(inst, Type::I32, span)?; + Ok(vec![cast]) + } + "le" => { + assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id); + let inst = builder.ins().lte(args[0], args[1], span)?; + let cast = builder.ins().cast(inst, Type::I32, span)?; + Ok(vec![cast]) + } + "is_odd" => { + assert_eq!(args.len(), 1, "{} takes exactly one argument", func_id); + let inst = builder.ins().is_odd(args[0], span)?; + let cast = builder.ins().cast(inst, Type::I32, span)?; + Ok(vec![cast]) + } + // Assert operations + "assert" => { + assert_eq!(args.len(), 1, "{} takes exactly one argument", func_id); + builder.ins().assert(args[0], span); + Ok(vec![]) + } + "assertz" => { + assert_eq!(args.len(), 1, "{} takes exactly one argument", func_id); + builder.ins().assertz(args[0], span); + Ok(vec![]) + } + "assert_eq" => { + assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id); + builder.ins().assert_eq(args[0], args[1], span); + Ok(vec![]) + } + _ => panic!("No felt op intrinsics found for {}", func_id), + } } diff --git a/frontend-wasm2/src/intrinsics/mem.rs b/frontend-wasm2/src/intrinsics/mem.rs index fa40d51c..cc753c25 100644 --- a/frontend-wasm2/src/intrinsics/mem.rs +++ b/frontend-wasm2/src/intrinsics/mem.rs @@ -1,9 +1,12 @@ -use midenc_hir::{ - AbiParam, FunctionIdent, FunctionType, InstBuilder, Signature, SourceSpan, Type, Value, -}; -use midenc_hir2::ValueRef; +use midenc_dialect_hir::InstBuilder; +use midenc_hir2::{AbiParam, FunctionIdent, FunctionType, Signature, SourceSpan, Type, ValueRef}; -use crate::module::function_builder_ext::FunctionBuilderExt; +use crate::{ + error::WasmResult, + module::{ + function_builder_ext::FunctionBuilderExt, module_translation_state::CallableFunction, + }, +}; pub const MODULE_ID: &str = "intrinsics::mem"; @@ -29,31 +32,26 @@ fn signature(func_id: &FunctionIdent) -> Signature { /// Convert a call to a memory intrinsic function pub(crate) fn convert_mem_intrinsics( - func_id: FunctionIdent, + def_func: &CallableFunction, args: &[ValueRef], builder: &mut FunctionBuilderExt, span: SourceSpan, -) -> Vec { - todo!() - // match func_id.function.as_symbol().as_str() { - // HEAP_BASE => { - // assert_eq!(args.len(), 0, "{} takes no arguments", func_id); - // if builder - // .data_flow_graph() - // .get_import_by_name(func_id.module, func_id.function) - // .is_none() - // { - // let signature = signature(&func_id); - // let _ = builder.data_flow_graph_mut().import_function( - // func_id.module, - // func_id.function, - // signature, - // ); - // } - // let call = builder.ins().exec(func_id, &[], span); - // let value = builder.data_flow_graph().first_result(call); - // vec![value] - // } - // _ => panic!("No allowed memory intrinsics found for {}", func_id), - // } +) -> WasmResult> { + match def_func.wasm_id.function.as_symbol().as_str() { + HEAP_BASE => { + assert_eq!(args.len(), 0, "{} takes no arguments", def_func.wasm_id); + + let func_ref = def_func.function_ref.unwrap_or_else(|| { + panic!("expected DefinedFunction::function_ref to be set for {}", def_func.wasm_id) + }); + let exec = + builder.ins().exec(func_ref, def_func.signature.clone(), args.to_vec(), span)?; + let borrow = exec.borrow(); + let results = borrow.as_ref().results(); + let result_vals: Vec = + results.iter().map(|op_res| op_res.borrow().as_value_ref()).collect(); + Ok(result_vals) + } + _ => panic!("No allowed memory intrinsics found for {}", def_func.wasm_id), + } } diff --git a/frontend-wasm2/src/intrinsics/mod.rs b/frontend-wasm2/src/intrinsics/mod.rs index 26bf7fc6..de529a03 100644 --- a/frontend-wasm2/src/intrinsics/mod.rs +++ b/frontend-wasm2/src/intrinsics/mod.rs @@ -3,10 +3,15 @@ pub mod mem; use std::{collections::HashSet, sync::OnceLock}; -use midenc_hir::{FunctionIdent, FunctionType, SourceSpan, Symbol, Value}; -use midenc_hir2::ValueRef; +use midenc_hir::{FunctionType, SourceSpan, Symbol, Value}; +use midenc_hir2::{FunctionIdent, ValueRef}; -use crate::module::function_builder_ext::FunctionBuilderExt; +use crate::{ + error::WasmResult, + module::{ + function_builder_ext::FunctionBuilderExt, module_translation_state::CallableFunction, + }, +}; /// Check if the given module is a Miden module that contains intrinsics pub fn is_miden_intrinsics_module(module_id: Symbol) -> bool { @@ -25,15 +30,15 @@ fn modules() -> &'static HashSet<&'static str> { /// Convert a call to a Miden intrinsic function into instruction(s) pub fn convert_intrinsics_call( - func_id: FunctionIdent, + def_func: &CallableFunction, args: &[ValueRef], builder: &mut FunctionBuilderExt, span: SourceSpan, -) -> Vec { - match func_id.module.as_symbol().as_str() { - mem::MODULE_ID => mem::convert_mem_intrinsics(func_id, args, builder, span), - felt::MODULE_ID => felt::convert_felt_intrinsics(func_id, args, builder, span), - _ => panic!("No intrinsics found for {}", func_id), +) -> WasmResult> { + match def_func.wasm_id.module.as_symbol().as_str() { + mem::MODULE_ID => mem::convert_mem_intrinsics(def_func, args, builder, span), + felt::MODULE_ID => felt::convert_felt_intrinsics(def_func.wasm_id, args, builder, span), + _ => panic!("No intrinsics found for {}", def_func.wasm_id), } } @@ -49,6 +54,16 @@ pub enum IntrinsicsConversionResult { MidenVmOp, } +impl IntrinsicsConversionResult { + pub fn is_function(&self) -> bool { + matches!(self, IntrinsicsConversionResult::FunctionType(_)) + } + + pub fn is_operation(&self) -> bool { + matches!(self, IntrinsicsConversionResult::MidenVmOp) + } +} + pub fn intrinsics_conversion_result(func_id: &FunctionIdent) -> IntrinsicsConversionResult { match func_id.module.as_symbol().as_str() { mem::MODULE_ID => { diff --git a/frontend-wasm2/src/module/module_translation_state.rs b/frontend-wasm2/src/module/module_translation_state.rs index 3407633d..d3b50e59 100644 --- a/frontend-wasm2/src/module/module_translation_state.rs +++ b/frontend-wasm2/src/module/module_translation_state.rs @@ -8,22 +8,27 @@ use midenc_hir2::{ use super::{instance::ModuleArgument, ir_func_type, EntityIndex, FuncIndex, Module, ModuleTypes}; use crate::{ error::WasmResult, - intrinsics::is_miden_intrinsics_module, + intrinsics::{ + intrinsics_conversion_result, is_miden_intrinsics_module, IntrinsicsConversionResult, + }, miden_abi::{is_miden_abi_module, miden_abi_function_type, recover_imported_masm_function_id}, translation_utils::sig_from_func_type, }; -#[derive(Clone, Debug)] -struct DefinedFunction { - wasm_id: FunctionIdent, - symbol_path: SymbolPath, - signature: Signature, +/// Local or imported core Wasm module function +#[derive(Clone)] +pub struct CallableFunction { + /// Module and function name parsed from the core Wasm module + pub wasm_id: FunctionIdent, + /// Defined IR function or None if it's an intrinsic that will be represented with an op + pub function_ref: Option, + /// Function signature parsed from the core Wasm module + pub signature: Signature, } pub struct ModuleTranslationState<'a> { /// Imported and local functions - /// Stores both the function reference and its signature - functions: FxHashMap, + functions: FxHashMap, pub module_builder: &'a mut ModuleBuilder, } @@ -71,14 +76,33 @@ impl<'a> ModuleTranslationState<'a> { let import = &module.imports[index.as_u32() as usize]; let func_id = recover_imported_masm_function_id(import.module.as_str(), &import.field); - component_builder.define_import(func_id, sig.clone()); - - let root_component = component_builder.component.borrow().name().as_symbol(); - let path = function_ident_to_sympol_path(root_component, &func_id); - let defined_function = DefinedFunction { - wasm_id: func_id, - symbol_path: path, - signature: sig, + let defined_function = if is_miden_intrinsics_module(func_id.module.as_symbol()) + && intrinsics_conversion_result(&func_id).is_operation() + { + CallableFunction { + wasm_id: func_id, + function_ref: None, + signature: sig, + } + } else { + let import_module_ref = if let Some(found_module_ref) = + component_builder.find_module(func_id.module.as_symbol()) + { + found_module_ref + } else { + component_builder + .define_module(func_id.module) + .expect("failed to create a module for imports") + }; + let mut import_module_builder = ModuleBuilder::new(import_module_ref); + let import_func_ref = import_module_builder + .define_function(func_id.function, sig.clone()) + .expect("failed to create an import function"); + CallableFunction { + wasm_id: func_id, + function_ref: Some(import_func_ref), + signature: sig, + } }; functions.insert(index, defined_function); } else { @@ -87,17 +111,15 @@ impl<'a> ModuleTranslationState<'a> { module: Ident::from(module.name().as_str()), function: Ident::from(func_name.as_str()), }; - let root_component = component_builder.component.borrow().name().as_symbol(); - let path = function_ident_to_sympol_path(root_component, &func_id); - let defined_function = DefinedFunction { + let func_ref = module_builder + .define_function(func_id.function, sig.clone()) + .expect("adding new function failed"); + let defined_function = CallableFunction { wasm_id: func_id, - symbol_path: path, + function_ref: Some(func_ref), signature: sig.clone(), }; functions.insert(index, defined_function); - module_builder - .define_function(func_id.function, sig) - .expect("adding new function failed"); }; } Self { @@ -108,80 +130,12 @@ impl<'a> ModuleTranslationState<'a> { /// Get the `FunctionIdent` that should be used to make a direct call to function /// `index`. - /// - /// Import the callee into `func`'s DFG if it is not already present. pub(crate) fn get_direct_func( &mut self, index: FuncIndex, diagnostics: &DiagnosticsHandler, - ) -> WasmResult { + ) -> WasmResult { let defined_func = self.functions[&index].clone(); - let symbol_ref = self - .module_builder - .module - .borrow() - .resolve(&defined_func.symbol_path) - .unwrap_or_else(|| { - panic!("Failed to resolve function {:?}", defined_func); - }); - - let op = symbol_ref.borrow(); - let func = op - .as_symbol_operation() - .downcast_ref::() - .expect("expected resolved symbol to be a Function"); - let func_ref = func.as_function_ref(); - Ok(func_ref) - - // let function = symbol_ref.borrow().downcast_ref::().unwrap().as_symbol_ref(); - // let (func_id, wasm_sig) = self.functions[&index].clone(); - // let (func_id, sig) = if is_miden_abi_module(func_id.module.as_symbol()) { - // let func_id = FunctionIdent { - // module: func_id.module, - // function: Ident::from(func_id.function.as_str().replace("-", "_").as_str()), - // }; - // let ft = - // miden_abi_function_type(func_id.module.as_symbol(), func_id.function.as_symbol()); - // ( - // func_id, - // Signature::new( - // ft.params.into_iter().map(AbiParam::new), - // ft.results.into_iter().map(AbiParam::new), - // ), - // ) - // } else { - // (func_id, wasm_sig.clone()) - // }; - // - // if is_miden_intrinsics_module(func_id.module.as_symbol()) { - // // Exit and do not import intrinsics functions into the DFG - // return Ok(func_id); - // } - // - // if dfg.get_import(&func_id).is_none() { - // dfg.import_function(func_id.module, func_id.function, sig.clone()) - // .map_err(|_e| { - // let message = format!( - // "Function with name {} in module {} with signature {sig:?} is already \ - // imported (function call) with a different signature", - // func_id.function, func_id.module - // ); - // diagnostics.diagnostic(Severity::Error).with_message(message).into_report() - // })?; - // } - // Ok(func_id) + Ok(defined_func) } } - -fn function_ident_to_sympol_path( - root_component: SymbolName, - func_id: &FunctionIdent, -) -> SymbolPath { - SymbolPath::new(vec![ - SymbolNameComponent::Root, - SymbolNameComponent::Component(root_component), - SymbolNameComponent::Component(func_id.module.as_symbol()), - SymbolNameComponent::Leaf(func_id.function.as_symbol()), - ]) - .unwrap() -} diff --git a/hir2/src/dialects/builtin/builders/component.rs b/hir2/src/dialects/builtin/builders/component.rs index d6a6a102..f2220e75 100644 --- a/hir2/src/dialects/builtin/builders/component.rs +++ b/hir2/src/dialects/builtin/builders/component.rs @@ -1,9 +1,8 @@ -use super::ModuleBuilder; use crate::{ dialects::builtin::{ - ComponentRef, InterfaceRef, ModuleRef, PrimInterfaceBuilder, PrimModuleBuilder, + ComponentRef, InterfaceRef, Module, ModuleRef, PrimInterfaceBuilder, PrimModuleBuilder, }, - Builder, FunctionIdent, Ident, Op, OpBuilder, Report, Signature, Spanned, SymbolTable, + Builder, Ident, Op, OpBuilder, Report, Spanned, SymbolName, SymbolTable, }; pub struct ComponentBuilder { @@ -49,11 +48,10 @@ impl ComponentBuilder { Ok(module_ref) } - pub fn define_import(&mut self, func_id: FunctionIdent, sig: Signature) { - let module_ref = self.define_module(func_id.module).expect("failed to define module"); - let mut module_builder = ModuleBuilder::new(module_ref); - module_builder - .define_function(func_id.function, sig) - .expect("failed to define function"); + pub fn find_module(&self, name: SymbolName) -> Option { + self.component.borrow().get(name).and_then(|symbol_ref| { + let op = symbol_ref.borrow(); + op.as_symbol_operation().downcast_ref::().map(|m| m.as_module_ref()) + }) } } diff --git a/hir2/src/dialects/builtin/ops/module.rs b/hir2/src/dialects/builtin/ops/module.rs index 88b1612a..b302661a 100644 --- a/hir2/src/dialects/builtin/ops/module.rs +++ b/hir2/src/dialects/builtin/ops/module.rs @@ -74,6 +74,13 @@ pub struct Module { uses: SymbolUseList, } +impl Module { + #[inline(always)] + pub fn as_module_ref(&self) -> ModuleRef { + unsafe { ModuleRef::from_raw(self) } + } +} + impl RegionKindInterface for Module { #[inline(always)] fn kind(&self) -> RegionKind { diff --git a/tests/integration/expected/felt_intrinsics.hir b/tests/integration/expected/felt_intrinsics.hir new file mode 100644 index 00000000..e19fb887 --- /dev/null +++ b/tests/integration/expected/felt_intrinsics.hir @@ -0,0 +1,20 @@ +builtin.component #[name = #root] #[namespace = #root_ns] #[version = 1.0.0] #[visibility = public] { + + builtin.module #[name = #felt_intrinsics] #[visibility = public] { + + builtin.function public @entrypoint(v0: felt, v1: felt) -> felt { + ^block3(v0: felt, v1: felt): + v3 = hir.mul v0, v1 : felt #[overflow = unchecked]; + v4 = hir.sub v3, v0 : felt #[overflow = unchecked]; + v5 = hir.add v4, v1 : felt #[overflow = unchecked]; + v6 = hir.div v0, v5 : felt; + hir.br block4 v6; + ^block4(v2: felt): + hir.ret v2; + }; + builtin.global_variable #[name = #__stack_pointer] #[ty = i32] #[visibility = private] { + + hir.ret_imm #[value = 1048576]; + }; + }; +}; \ No newline at end of file diff --git a/tests/integration/expected/felt_intrinsics.wat b/tests/integration/expected/felt_intrinsics.wat new file mode 100644 index 00000000..f9ede10e --- /dev/null +++ b/tests/integration/expected/felt_intrinsics.wat @@ -0,0 +1,23 @@ +(module $felt_intrinsics.wasm + (type (;0;) (func (param f32 f32) (result f32))) + (import "miden:core-import/intrinsics-felt@1.0.0" "mul" (func $miden_stdlib_sys::intrinsics::felt::extern_mul (;0;) (type 0))) + (import "miden:core-import/intrinsics-felt@1.0.0" "sub" (func $miden_stdlib_sys::intrinsics::felt::extern_sub (;1;) (type 0))) + (import "miden:core-import/intrinsics-felt@1.0.0" "add" (func $miden_stdlib_sys::intrinsics::felt::extern_add (;2;) (type 0))) + (import "miden:core-import/intrinsics-felt@1.0.0" "div" (func $miden_stdlib_sys::intrinsics::felt::extern_div (;3;) (type 0))) + (func $entrypoint (;4;) (type 0) (param f32 f32) (result f32) + local.get 0 + local.get 0 + local.get 1 + call $miden_stdlib_sys::intrinsics::felt::extern_mul + local.get 0 + call $miden_stdlib_sys::intrinsics::felt::extern_sub + local.get 1 + call $miden_stdlib_sys::intrinsics::felt::extern_add + call $miden_stdlib_sys::intrinsics::felt::extern_div + ) + (table (;0;) 1 1 funcref) + (memory (;0;) 16) + (global $__stack_pointer (;0;) (mut i32) i32.const 1048576) + (export "memory" (memory 0)) + (export "entrypoint" (func $entrypoint)) +) \ No newline at end of file diff --git a/tests/integration/src/rust_masm_tests/apps.rs b/tests/integration/src/rust_masm_tests/apps.rs index eb4c9826..b8c39fa7 100644 --- a/tests/integration/src/rust_masm_tests/apps.rs +++ b/tests/integration/src/rust_masm_tests/apps.rs @@ -7,11 +7,14 @@ use midenc_hir::Felt; use proptest::{prelude::*, test_runner::TestRunner}; use crate::{ - cargo_proj::project, compiler_test::sdk_alloc_crate_path, CompilerTest, CompilerTestBuilder, + cargo_proj::project, + compiler_test::{sdk_alloc_crate_path, sdk_crate_path}, + CompilerTest, CompilerTestBuilder, }; fn cargo_toml(name: &str) -> String { let sdk_alloc_path = sdk_alloc_crate_path(); + let sdk_path = sdk_crate_path(); format!( r#" [package] @@ -25,6 +28,7 @@ fn cargo_toml(name: &str) -> String { [dependencies] miden-sdk-alloc = {{ path = "{sdk_alloc_path}" }} + miden = {{ path = "{sdk_path}" }} [profile.release] # optimize the output for size @@ -38,7 +42,8 @@ fn cargo_toml(name: &str) -> String { overflow-checks = false debug = true "#, - sdk_alloc_path = sdk_alloc_path.display() + sdk_alloc_path = sdk_alloc_path.display(), + sdk_path = sdk_path.display() ) } @@ -130,3 +135,44 @@ fn mem_intrinsics_heap_base() { test.expect_wasm(expect_file![format!("../../expected/{artifact_name}.wat")]); test.expect_ir2(expect_file![format!("../../expected/{artifact_name}.hir")]); } + +#[test] +fn felt_intrinsics() { + let name = "felt_intrinsics"; + let cargo_proj = project(name) + .file("Cargo.toml", &cargo_toml(name)) + .file( + "src/lib.rs", + r#" + #![no_std] + + // Required for no-std crates + #[panic_handler] + fn my_panic(_info: &core::panic::PanicInfo) -> ! { + loop {} + } + + // Global allocator to use heap memory in no-std environment + #[global_allocator] + static ALLOC: miden::BumpAlloc = miden::BumpAlloc::new(); + + use miden::*; + + #[no_mangle] + pub fn entrypoint(a: Felt, b: Felt) -> Felt { + a / (a * b - a + b) + } + "#, + ) + .build(); + let mut test = CompilerTestBuilder::rust_source_cargo_miden( + cargo_proj.root(), + WasmTranslationConfig::default(), + [], + ) + .build(); + + let artifact_name = name; + test.expect_wasm(expect_file![format!("../../expected/{artifact_name}.wat")]); + test.expect_ir2(expect_file![format!("../../expected/{artifact_name}.hir")]); +} diff --git a/tools/cargo-miden/src/commands/new_project.rs b/tools/cargo-miden/src/commands/new_project.rs index 22e44b5d..1c5fe88f 100644 --- a/tools/cargo-miden/src/commands/new_project.rs +++ b/tools/cargo-miden/src/commands/new_project.rs @@ -4,7 +4,11 @@ use anyhow::Context; use cargo_generate::{GenerateArgs, TemplatePath}; use clap::Args; -const TEMPLATES_REPO_TAG: &str = "v0.6.0"; +/// The tag used in checkout of the new project template. +/// +/// Before changing it make sure the new tag exists in the rust-templates repo and points to the +/// desired commit. +const TEMPLATES_REPO_TAG: &str = "v0.7.0"; // This should have been an enum but I could not bend `clap` to expose variants as flags /// Project template