From e0efac79a4e07a6b954885cceb1dfe4aad66563d Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Thu, 2 Jan 2025 18:44:02 +0200 Subject: [PATCH 01/18] test: sketch new frontend translator (no inlining) producing HIR2 --- frontend-wasm/src/component/build_ir.rs | 19 +- frontend-wasm/src/component/inline.rs | 16 +- frontend-wasm/src/component/mod.rs | 1 + frontend-wasm/src/component/parser.rs | 69 +- frontend-wasm/src/component/translator2.rs | 318 ++++++ .../src/component/translator2/hir2_sketch.rs | 150 +++ frontend-wasm/src/component/types/mod.rs | 8 + frontend-wasm/src/lib.rs | 1 + .../expected/rust_sdk/hir2_sketch.hir | 34 + .../expected/rust_sdk/hir2_sketch.wat | 1003 +++++++++++++++++ tests/integration/src/compiler_test.rs | 12 + .../src/rust_masm_tests/rust_sdk.rs | 15 + 12 files changed, 1618 insertions(+), 28 deletions(-) create mode 100644 frontend-wasm/src/component/translator2.rs create mode 100644 frontend-wasm/src/component/translator2/hir2_sketch.rs create mode 100644 tests/integration/expected/rust_sdk/hir2_sketch.hir create mode 100644 tests/integration/expected/rust_sdk/hir2_sketch.wat diff --git a/frontend-wasm/src/component/build_ir.rs b/frontend-wasm/src/component/build_ir.rs index 0190cd55b..23024a3c6 100644 --- a/frontend-wasm/src/component/build_ir.rs +++ b/frontend-wasm/src/component/build_ir.rs @@ -2,8 +2,8 @@ use midenc_hir::diagnostics::Report; use midenc_session::Session; use super::{ - inline, translator::ComponentTranslator, ComponentTypesBuilder, LinearComponentTranslation, - ParsedRootComponent, + inline, translator::ComponentTranslator, translator2::ComponentTranslator2, + ComponentTypesBuilder, LinearComponentTranslation, ParsedRootComponent, }; use crate::{ component::ComponentParser, error::WasmResult, supported_component_model_features, @@ -61,3 +61,18 @@ fn inline( .map_err(Report::msg)?; Ok(component_dfg.finish()) } + +/// Translate a Wasm component binary into Miden IR component +pub fn translate_component2( + wasm: &[u8], + config: &WasmTranslationConfig, + session: &Session, +) -> WasmResult { + let (mut component_types_builder, parsed_component) = parse(config, wasm, session)?; + let translator = ComponentTranslator2::new(config, session); + translator.translate( + parsed_component, + &mut component_types_builder, + session.diagnostics.as_ref(), + ) +} diff --git a/frontend-wasm/src/component/inline.rs b/frontend-wasm/src/component/inline.rs index f080b22fe..d835dd79f 100644 --- a/frontend-wasm/src/component/inline.rs +++ b/frontend-wasm/src/component/inline.rs @@ -58,7 +58,7 @@ use super::{ LocalCanonicalOptions, ParsedComponent, StringEncoding, }; use crate::{ - component::{dfg, LocalInitializer}, + component::{dfg, CanonLift, CanonLower, ComponentInstantiation, LocalInitializer}, module::{module_env::ParsedModule, types::*, ModuleImport}, }; @@ -501,12 +501,12 @@ impl<'a> Inliner<'a> { // Lowering a component function to a core wasm function. Here // various metadata is recorded and then the final component gets an // initializer recording the lowering. - Lower { + Lower(CanonLower { func, options, canonical_abi, lower_ty, - } => { + }) => { let lower_ty = types.convert_component_func_type(frame.translation.types_ref(), *lower_ty)?; let options_lower = self.adapter_options(frame, options); @@ -580,7 +580,7 @@ impl<'a> Inliner<'a> { // Lifting a core wasm function is relatively easy for now in that // some metadata about the lifting is simply recorded. This'll get // plumbed through to exports or a fused adapter later on. - Lift(ty, func, options) => { + Lift(CanonLift { ty, func, options }) => { let ty = types.convert_component_func_type(frame.translation.types_ref(), *ty)?; let options = self.adapter_options(frame, options); frame.component_funcs.push(ComponentFuncDef::Lifted { @@ -732,7 +732,11 @@ impl<'a> Inliner<'a> { // of this entire module, so the "easy" step here is to simply // create a new inliner frame and return it to get pushed onto the // stack. - ComponentInstantiate(component, args, ty) => { + ComponentInstantiate(ComponentInstantiation { + component, + args, + ty, + }) => { let component: &ComponentDef<'a> = &frame.components[*component]; let index = RuntimeComponentInstanceIndex::from_u32( self.result.num_runtime_component_instances, @@ -826,7 +830,7 @@ impl<'a> Inliner<'a> { frame.components.push(frame.closed_over_component(idx)); } - Export(item) => match item { + Export(_, item) => match item { ComponentItem::Func(i) => { frame.component_funcs.push(frame.component_funcs[*i].clone()); } diff --git a/frontend-wasm/src/component/mod.rs b/frontend-wasm/src/component/mod.rs index 8b237754f..784dc83b4 100644 --- a/frontend-wasm/src/component/mod.rs +++ b/frontend-wasm/src/component/mod.rs @@ -9,6 +9,7 @@ pub mod info; mod inline; mod parser; mod translator; +mod translator2; mod types; pub use self::{info::*, parser::*, types::*}; diff --git a/frontend-wasm/src/component/parser.rs b/frontend-wasm/src/component/parser.rs index 51bd871c1..2812a15d1 100644 --- a/frontend-wasm/src/component/parser.rs +++ b/frontend-wasm/src/component/parser.rs @@ -183,23 +183,42 @@ pub struct ParsedComponent<'data> { pub types: Option, } +#[derive(Debug, Clone)] +pub struct CanonLower { + pub func: ComponentFuncIndex, + pub lower_ty: ComponentFuncTypeId, + pub canonical_abi: SignatureIndex, + pub options: LocalCanonicalOptions, +} + +#[derive(Debug, Clone)] +pub struct CanonLift { + pub ty: ComponentFuncTypeId, + pub func: FuncIndex, + pub options: LocalCanonicalOptions, +} + +#[derive(Debug, Clone)] +// component instances +pub struct ComponentInstantiation<'data> { + pub component: ComponentIndex, + pub args: FxHashMap<&'data str, ComponentItem>, + pub ty: ComponentInstanceTypeId, +} + // NB: the type information contained in `LocalInitializer` should always point // to `wasmparser`'s type information, not ours. Component types cannot be // fully determined due to resources until instantiations are known which is // tracked during the inlining phase. This means that all type information below // is straight from `wasmparser`'s passes. +#[derive(Debug)] pub enum LocalInitializer<'data> { // imports Import(ComponentImportName<'data>, ComponentEntityType), // canonical function sections - Lower { - func: ComponentFuncIndex, - lower_ty: ComponentFuncTypeId, - canonical_abi: SignatureIndex, - options: LocalCanonicalOptions, - }, - Lift(ComponentFuncTypeId, FuncIndex, LocalCanonicalOptions), + Lower(CanonLower), + Lift(CanonLift), // resources Resource(AliasableResourceId, WasmType, Option), @@ -217,12 +236,7 @@ pub enum LocalInitializer<'data> { // components ComponentStatic(StaticComponentIndex, ClosedOverVars), - // component instances - ComponentInstantiate( - ComponentIndex, - FxHashMap<&'data str, ComponentItem>, - ComponentInstanceTypeId, - ), + ComponentInstantiate(ComponentInstantiation<'data>), ComponentSynthetic(FxHashMap<&'data str, ComponentItem>), // alias section @@ -235,13 +249,13 @@ pub enum LocalInitializer<'data> { AliasComponent(ClosedOverComponent), // export section - Export(ComponentItem), + Export(&'data str, ComponentItem), } /// The "closure environment" of components themselves. /// /// For more information see `LexicalScope`. -#[derive(Default)] +#[derive(Default, Debug)] pub struct ClosedOverVars { pub components: PrimaryMap, pub modules: PrimaryMap, @@ -251,6 +265,7 @@ pub struct ClosedOverVars { /// a component are being created. /// /// For more information see `LexicalScope`. +#[derive(Debug)] pub enum ClosedOverComponent { /// A closed over component is coming from the local component's index /// space, meaning a previously defined component is being captured. @@ -263,12 +278,14 @@ pub enum ClosedOverComponent { } /// Same as `ClosedOverComponent`, but for modules. +#[derive(Debug)] pub enum ClosedOverModule { Local(ModuleIndex), Upvar(ModuleUpvarIndex), } /// Representation of canonical ABI options. +#[derive(Debug, Clone)] pub struct LocalCanonicalOptions { pub string_encoding: StringEncoding, pub memory: Option, @@ -349,6 +366,7 @@ impl<'a, 'data> ComponentParser<'a, 'data> { } => { self.validator.version(num, encoding, &range).into_diagnostic()?; + // dbg!(&encoding); match encoding { Encoding::Component => {} Encoding::Module => { @@ -470,6 +488,7 @@ impl<'a, 'data> ComponentParser<'a, 'data> { let import = import.into_diagnostic()?; let types = self.validator.types(0).unwrap(); let ty = types.component_entity_type_of_import(import.name.0).unwrap(); + // dbg!(&import.name, &ty); self.result.initializers.push(LocalInitializer::Import(import.name, ty)); } Ok(()) @@ -494,7 +513,7 @@ impl<'a, 'data> ComponentParser<'a, 'data> { let ty = types.component_any_type_at(type_index).unwrap_func(); let func = FuncIndex::from_u32(core_func_index); let options = canonical_options(&options); - LocalInitializer::Lift(ty, func, options) + LocalInitializer::Lift(CanonLift { ty, func, options }) } wasmparser::CanonicalFunction::Lower { func_index, @@ -506,12 +525,12 @@ impl<'a, 'data> ComponentParser<'a, 'data> { let canonical_abi = self.core_func_signature(core_func_index); core_func_index += 1; - LocalInitializer::Lower { + LocalInitializer::Lower(CanonLower { func, options, canonical_abi, lower_ty, - } + }) } wasmparser::CanonicalFunction::ResourceNew { resource } => { let resource = types.component_any_type_at(resource).unwrap_resource(); @@ -532,6 +551,7 @@ impl<'a, 'data> ComponentParser<'a, 'data> { LocalInitializer::ResourceRep(resource, ty) } }; + // dbg!(&init); self.result.initializers.push(init); } Ok(()) @@ -611,6 +631,7 @@ impl<'a, 'data> ComponentParser<'a, 'data> { instantiate_module_from_exports(&exports) } }; + // dbg!(&init); self.result.initializers.push(init); } Ok(()) @@ -637,6 +658,7 @@ impl<'a, 'data> ComponentParser<'a, 'data> { self.instantiate_component_from_exports(&exports)? } }; + // dbg!(&init); self.result.initializers.push(init); index += 1; } @@ -655,10 +677,11 @@ impl<'a, 'data> ComponentParser<'a, 'data> { self.validator.component_export_section(&s).into_diagnostic()?; for export in s { let export = export.into_diagnostic()?; + // dbg!(&export); let item = self.kind_to_item(export.kind, export.index)?; let prev = self.result.exports.insert(export.name.0, item); assert!(prev.is_none()); - self.result.initializers.push(LocalInitializer::Export(item)); + self.result.initializers.push(LocalInitializer::Export(export.name.0, item)); } Ok(()) } @@ -694,6 +717,7 @@ impl<'a, 'data> ComponentParser<'a, 'data> { alias_module_instance_export(kind, instance, name) } }; + // dbg!(&init); self.result.initializers.push(init); } Ok(()) @@ -712,7 +736,11 @@ impl<'a, 'data> ComponentParser<'a, 'data> { args.insert(arg.name, idx); } - Ok(LocalInitializer::ComponentInstantiate(component, args, ty)) + Ok(LocalInitializer::ComponentInstantiate(ComponentInstantiation { + component, + args, + ty, + })) } /// Creates a synthetic module from the list of items currently in the @@ -727,6 +755,7 @@ impl<'a, 'data> ComponentParser<'a, 'data> { map.insert(export.name.0, idx); } + // dbg!(&map); Ok(LocalInitializer::ComponentSynthetic(map)) } diff --git a/frontend-wasm/src/component/translator2.rs b/frontend-wasm/src/component/translator2.rs new file mode 100644 index 000000000..64b114411 --- /dev/null +++ b/frontend-wasm/src/component/translator2.rs @@ -0,0 +1,318 @@ +#![allow(unused)] + +use hir2_sketch::{Component, Interface, Module}; +use midenc_hir::{ + cranelift_entity::PrimaryMap, diagnostics::Report, CanonAbiImport, ComponentBuilder, + ComponentExport, FunctionIdent, FunctionType, Ident, InterfaceFunctionIdent, InterfaceIdent, + MidenAbiImport, Signature, SourceSpan, Symbol, +}; +use midenc_hir_type::Abi; +use midenc_session::{DiagnosticsHandler, Session}; +use rustc_hash::FxHashMap; +use wasmparser::types::ComponentEntityType; + +use super::{ + interface_type_to_ir, CanonLift, CanonLower, CanonicalOptions, ComponentFuncIndex, + ComponentIndex, ComponentInstanceIndex, ComponentInstantiation, ComponentTypes, + ComponentTypesBuilder, CoreDef, CoreExport, Export, ExportItem, GlobalInitializer, ImportIndex, + InstantiateModule, LinearComponent, LinearComponentTranslation, LoweredIndex, + ModuleInstanceIndex, ParsedRootComponent, RuntimeImportIndex, RuntimeInstanceIndex, + RuntimePostReturnIndex, RuntimeReallocIndex, StaticModuleIndex, Trampoline, TypeDef, + TypeFuncIndex, +}; +use crate::{ + component::{ComponentItem, LocalInitializer, StaticComponentIndex, StringEncoding}, + error::WasmResult, + intrinsics::{ + intrinsics_conversion_result, is_miden_intrinsics_module, IntrinsicsConversionResult, + }, + miden_abi::{is_miden_abi_module, miden_abi_function_type, recover_imported_masm_function_id}, + module::{ + build_ir::build_ir_module, + instance::ModuleArgument, + module_translation_state::ModuleTranslationState, + types::{EntityIndex, FuncIndex}, + }, + unsupported_diag, WasmTranslationConfig, +}; + +pub mod hir2_sketch; + +/// A translator from the linearized Wasm component model to the Miden IR component +pub struct ComponentTranslator2<'a> { + /// The translation configuration + config: &'a WasmTranslationConfig, + + // TODO: extract into a separate struct ComponentTranslationState + /// The runtime module instances index mapped to the static module index + module_instances_source: PrimaryMap, + /// The lower imports index mapped to the runtime import index + lower_imports: FxHashMap, + /// The realloc functions used in CanonicalOptions in this component + reallocs: FxHashMap, + /// The post return functions used in CanonicalOptions in this component + post_returns: FxHashMap, + + session: &'a Session, +} + +impl<'a> ComponentTranslator2<'a> { + pub fn new(config: &'a WasmTranslationConfig, session: &'a Session) -> Self { + Self { + config, + session, + module_instances_source: PrimaryMap::new(), + lower_imports: FxHashMap::default(), + reallocs: FxHashMap::default(), + post_returns: FxHashMap::default(), + } + } + + /// Translate the given parsed Wasm component to the Miden IR component + pub fn translate( + mut self, + parsed_root_component: ParsedRootComponent, + types: &mut ComponentTypesBuilder, + diagnostics: &DiagnosticsHandler, + ) -> WasmResult { + // dbg!(&parset_root_component.static_components.len()); + let mut component = hir2_sketch::Component { + name: "root".to_string(), + interfaces: vec![], + modules: vec![], + }; + let mut static_modules = Vec::new(); + let mut components: PrimaryMap = PrimaryMap::new(); + let mut component_instances: PrimaryMap = + PrimaryMap::new(); + let mut component_funcs: PrimaryMap = + PrimaryMap::new(); + let mut core_funcs: PrimaryMap = + PrimaryMap::new(); + let mut lowerings: PrimaryMap = PrimaryMap::new(); + let mut liftings: PrimaryMap = PrimaryMap::new(); + let types_ref = parsed_root_component.root_component.types_ref(); + for init in parsed_root_component.root_component.initializers.iter() { + // dbg!(&init); + + match init { + LocalInitializer::Import(name, ty) => { + // dbg!(name, ty); + assert!( + matches!(ty, ComponentEntityType::Instance(_)), + "only component instances imports supported yet" + ); + let ty = + types.convert_component_entity_type(types_ref, *ty).map_err(Report::msg)?; + // self.import_types.push((name.0.to_string(), ty)); + component_instances.push(ComponentInstance::Import(ComponentInstanceImport { + name: name.0.to_string(), + ty, + })); + } + LocalInitializer::Lower( + lower @ CanonLower { + func, + lower_ty, + canonical_abi, + ref options, + }, + ) => { + // dbg!(&init); + lowerings.push(lower.clone()); + } + LocalInitializer::Lift( + lift @ CanonLift { + ty: component_func_type_id, + func: func_index, + options: ref local_canonical_options, + }, + ) => { + // dbg!(&init); + liftings.push(lift.clone()); + } + LocalInitializer::Resource(aliasable_resource_id, wasm_type, func_index) => todo!(), + LocalInitializer::ResourceNew(aliasable_resource_id, signature_index) => todo!(), + LocalInitializer::ResourceRep(aliasable_resource_id, signature_index) => todo!(), + LocalInitializer::ResourceDrop(aliasable_resource_id, signature_index) => todo!(), + LocalInitializer::ModuleStatic(static_module_index) => { + let parsed_module = &parsed_root_component.static_modules[*static_module_index]; + let module = Module { + name: parsed_module.module.name(), + functions: vec![], + }; + static_modules.push(module); + } + LocalInitializer::ModuleInstantiate(module_idx, ref args) => { + // TODO: assert that module imports are satisfied by the args (every import has + // an argument of the correct type) + + // we don't support multiple instances of the same module, so it's safe to + // remove the module + component.modules.push(static_modules.remove(module_idx.as_u32() as usize)); + } + LocalInitializer::ModuleSynthetic(hash_map) => { + // dbg!(&hash_map); + let mut module_name: Option = None; + let functions_ids: Vec<(Ident, Signature)> = hash_map + .iter() + .map(|(k, v)| { + let func_id = v.unwrap_func(); + let canon_lower = &lowerings[func_id]; + let comp_func = &component_funcs[canon_lower.func]; + let import_instance = &component_instances[comp_func.0].unwrap_import(); + if let Some(module_name) = &module_name { + assert_eq!( + module_name, &import_instance.name, + "unexpected functions from different import instances in one \ + synthetic core module" + ); + } else { + module_name = Some(import_instance.name.clone()); + } + let func = Ident::new(Symbol::intern(*k), SourceSpan::default()); + // TODO: get the component function type + let signature = Signature::new(vec![], vec![]); + (func, signature) + }) + .collect(); + let module_id = + Ident::new(Symbol::intern(module_name.unwrap()), SourceSpan::default()); + let functions = functions_ids + .into_iter() + .map(|(function, signature)| { + let id = FunctionIdent { + module: module_id, + function, + }; + // TODO: generate lowering + hir2_sketch::Function { id, signature } + }) + .collect(); + let module = Module { + name: module_id, + functions, + }; + component.modules.push(module); + } + LocalInitializer::ComponentStatic(idx, ref closed_over_vars) => { + // dbg!(&init); + let comp = &parsed_root_component.static_components[*idx]; + // dbg!(&comp.initializers); + // dbg!(&comp.exports); + components.push((idx, closed_over_vars)); + } + LocalInitializer::ComponentInstantiate( + instance @ ComponentInstantiation { + component: component_index, + ref args, + ty: component_instance_type_id, + }, + ) => { + // dbg!(&init); + component_instances.push(ComponentInstance::Instantiated(instance.clone())); + } + LocalInitializer::ComponentSynthetic(hash_map) => { + dbg!(&init); + } + LocalInitializer::AliasExportFunc(module_instance_index, name) => { + // dbg!(&init); + core_funcs.push((*module_instance_index, name.to_string())); + // let module = component.modules[module_instance_index] + } + LocalInitializer::AliasExportTable(module_instance_index, _) => todo!(), + LocalInitializer::AliasExportGlobal(module_instance_index, _) => todo!(), + LocalInitializer::AliasExportMemory(module_instance_index, _) => { + // dbg!(&init); + } + LocalInitializer::AliasComponentExport(component_instance_index, name) => { + component_funcs.push((*component_instance_index, name.to_string())); + } + LocalInitializer::AliasModule(closed_over_module) => todo!(), + LocalInitializer::AliasComponent(closed_over_component) => todo!(), + LocalInitializer::Export(name, component_item) => { + // dbg!(&init); + assert!( + matches!(component_item, ComponentItem::ComponentInstance(_)), + "only component instances exports supported yet" + ); + let interface_name = name.to_string(); + let instance = &component_instances[component_item.unwrap_instance()] + .unwrap_instantiated(); + let static_component_idx = components[instance.component].0; + let parsed_component = + &parsed_root_component.static_components[*static_component_idx]; + dbg!(&parsed_component.exports); + // let name = + let functions = parsed_component + .exports + .iter() + .flat_map(|(name, item)| { + if let ComponentItem::Func(f) = item { + // let (component_instance_id, name) = component_funcs[*f]; + // let component_instance = component_instances[component_instance_id] + // .unwrap_instantiated(); + // TODO: get the component function type + let signature = Signature::new(vec![], vec![]); + let function_id = FunctionIdent { + module: Ident::new( + Symbol::intern(interface_name.clone()), + SourceSpan::default(), + ), + function: Ident::new( + Symbol::intern(name.to_string()), + SourceSpan::default(), + ), + }; + let function = hir2_sketch::Function { + id: function_id, + signature, + }; + vec![function] + } else { + // we're only interested in exported functions + vec![] + } + }) + .collect(); + let interface = Interface { + name: interface_name, + functions, + }; + component.interfaces.push(interface); + component_instances.push(ComponentInstance::Export); + // TODO: generate synth module with liftings + } + } + } + + Ok(component) + } +} + +enum ComponentInstance<'a> { + Import(ComponentInstanceImport), + Instantiated(ComponentInstantiation<'a>), + Export, +} +impl<'a> ComponentInstance<'a> { + fn unwrap_import(&self) -> ComponentInstanceImport { + match self { + ComponentInstance::Import(import) => import.clone(), + _ => panic!("expected import"), + } + } + + fn unwrap_instantiated(&self) -> ComponentInstantiation { + match self { + ComponentInstance::Instantiated(instantiated) => instantiated.clone(), + _ => panic!("expected instantiated"), + } + } +} + +#[derive(Debug, Clone)] +struct ComponentInstanceImport { + name: String, + ty: TypeDef, +} diff --git a/frontend-wasm/src/component/translator2/hir2_sketch.rs b/frontend-wasm/src/component/translator2/hir2_sketch.rs new file mode 100644 index 000000000..65fe9ba5d --- /dev/null +++ b/frontend-wasm/src/component/translator2/hir2_sketch.rs @@ -0,0 +1,150 @@ +use std::fmt; + +use midenc_hir::{formatter::PrettyPrint, FunctionIdent, Ident, Signature}; + +#[derive(Debug)] +pub struct Function { + pub id: FunctionIdent, + pub signature: Signature, +} + +impl fmt::Display for Function { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.pretty_print(f) + } +} + +impl PrettyPrint for Function { + fn render(&self) -> midenc_hir::formatter::Document { + use midenc_hir::formatter::*; + + const_text("(") + + const_text("func") + + const_text(" ") + + display(self.id) + + const_text(" ") + + self.signature.render() + + const_text(")") + } +} + +#[derive(Debug)] +pub struct Interface { + pub name: String, + pub functions: Vec, +} + +impl fmt::Display for Interface { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.pretty_print(f) + } +} + +impl PrettyPrint for Interface { + fn render(&self) -> midenc_hir::formatter::Document { + use midenc_hir::formatter::*; + + let functions = self + .functions + .iter() + .map(PrettyPrint::render) + .reduce(|acc, doc| acc + nl() + doc) + .unwrap_or(Document::Empty); + + const_text("(") + + const_text("interface") + + const_text(" ") + + text(&self.name) + + indent(4, nl() + functions) + + nl() + + const_text(")") + } +} + +#[derive(Debug)] +pub struct Module { + pub name: Ident, + pub functions: Vec, +} + +impl fmt::Display for Module { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.pretty_print(f) + } +} + +impl PrettyPrint for Module { + fn render(&self) -> midenc_hir::formatter::Document { + use midenc_hir::formatter::*; + + let functions = self + .functions + .iter() + .map(PrettyPrint::render) + .reduce(|acc, doc| acc + nl() + doc) + .unwrap_or(Document::Empty); + + const_text("(") + + const_text("module") + + const_text(" ") + + display(self.name) + + indent(4, nl() + functions) + + nl() + + const_text(")") + } +} + +#[derive(Debug, Default)] +pub struct Component { + pub name: String, + pub interfaces: Vec, + pub modules: Vec, +} + +impl fmt::Display for Component { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.pretty_print(f) + } +} + +impl PrettyPrint for Component { + fn render(&self) -> midenc_hir::formatter::Document { + use midenc_hir::formatter::*; + + let interfaces = self + .interfaces + .iter() + .map(PrettyPrint::render) + .reduce(|acc, doc| acc + nl() + doc) + .map(|doc| const_text(";; Interfaces") + nl() + doc) + .unwrap_or(Document::Empty); + + let modules = self + .modules + .iter() + .map(PrettyPrint::render) + .reduce(|acc, doc| acc + nl() + doc) + .map(|doc| const_text(";; Modules") + nl() + doc) + .unwrap_or(Document::Empty); + + let body = vec![interfaces, modules] + .into_iter() + .filter(|section| !section.is_empty()) + .fold(nl(), |a, b| { + if matches!(a, Document::Newline) { + indent(4, a + b) + } else { + a + nl() + indent(4, nl() + b) + } + }); + + const_text("(") + + const_text("component") + + const_text(" ") + + text(&self.name) + + body + + nl() + + const_text(")") + + nl() + } +} diff --git a/frontend-wasm/src/component/types/mod.rs b/frontend-wasm/src/component/types/mod.rs index 727c14d7b..58b03c5a8 100644 --- a/frontend-wasm/src/component/types/mod.rs +++ b/frontend-wasm/src/component/types/mod.rs @@ -248,6 +248,14 @@ pub enum ComponentItem { ComponentInstance(ComponentInstanceIndex), Type(types::ComponentAnyTypeId), } +impl ComponentItem { + pub(crate) fn unwrap_instance(&self) -> ComponentInstanceIndex { + match self { + ComponentItem::ComponentInstance(i) => *i, + _ => panic!("not a component instance"), + } + } +} /// Runtime information about the type information contained within a component. /// diff --git a/frontend-wasm/src/lib.rs b/frontend-wasm/src/lib.rs index 58c311f64..67bfb5e74 100644 --- a/frontend-wasm/src/lib.rs +++ b/frontend-wasm/src/lib.rs @@ -21,6 +21,7 @@ mod translation_utils; mod test_utils; use component::build_ir::translate_component; +pub use component::build_ir::translate_component2; use error::WasmResult; use midenc_session::Session; use module::build_ir::translate_module_as_component; diff --git a/tests/integration/expected/rust_sdk/hir2_sketch.hir b/tests/integration/expected/rust_sdk/hir2_sketch.hir new file mode 100644 index 000000000..b9396428f --- /dev/null +++ b/tests/integration/expected/rust_sdk/hir2_sketch.hir @@ -0,0 +1,34 @@ +(component root + ;; Interfaces + (interface miden:basic-wallet/basic-wallet@1.0.0 + (func (#miden:basic-wallet/basic-wallet@1.0.0 #receive-asset ) + (func (#miden:basic-wallet/basic-wallet@1.0.0 #send-asset ) + ) + (interface miden:basic-wallet/aux@1.0.0 + (func (#miden:basic-wallet/aux@1.0.0 #test-felt-intrinsics ) + (func (#miden:basic-wallet/aux@1.0.0 #test-stdlib ) + (func (#miden:basic-wallet/aux@1.0.0 #process-list-felt ) + (func (#miden:basic-wallet/aux@1.0.0 #process-core-asset ) + ) + + ;; Modules + (module #miden:core-import/intrinsics-felt@1.0.0 + (func (#miden:core-import/intrinsics-felt@1.0.0 #add ) + ) + (module #miden:core-import/stdlib-crypto-hashes-blake3@1.0.0 + (func (#miden:core-import/stdlib-crypto-hashes-blake3@1.0.0 #hash-one-to-one ) + ) + (module #miden:core-import/intrinsics-mem@1.0.0 + (func (#miden:core-import/intrinsics-mem@1.0.0 #heap-base ) + ) + (module #miden:core-import/account@1.0.0 + (func (#miden:core-import/account@1.0.0 #add-asset ) + (func (#miden:core-import/account@1.0.0 #remove-asset ) + ) + (module #miden:core-import/tx@1.0.0 + (func (#miden:core-import/tx@1.0.0 #create-note ) + ) + (module #basic_wallet + + ) +) diff --git a/tests/integration/expected/rust_sdk/hir2_sketch.wat b/tests/integration/expected/rust_sdk/hir2_sketch.wat new file mode 100644 index 000000000..8c21a7417 --- /dev/null +++ b/tests/integration/expected/rust_sdk/hir2_sketch.wat @@ -0,0 +1,1003 @@ +(component + (type (;0;) + (instance + (type (;0;) (record (field "inner" float32))) + (export (;1;) "felt" (type (eq 0))) + (type (;2;) (tuple 1 1 1 1)) + (type (;3;) (record (field "inner" 2))) + (export (;4;) "word" (type (eq 3))) + (type (;5;) (record (field "inner" 4))) + (export (;6;) "core-asset" (type (eq 5))) + (type (;7;) (record (field "inner" 1))) + (export (;8;) "tag" (type (eq 7))) + (type (;9;) (record (field "inner" 4))) + (export (;10;) "recipient" (type (eq 9))) + (type (;11;) (record (field "inner" 1))) + (export (;12;) "note-type" (type (eq 11))) + ) + ) + (import "miden:base/core-types@1.0.0" (instance (;0;) (type 0))) + (type (;1;) + (instance + (type (;0;) (func (result s32))) + (export (;0;) "heap-base" (func (type 0))) + ) + ) + (import "miden:core-import/intrinsics-mem@1.0.0" (instance (;1;) (type 1))) + (type (;2;) + (instance + (type (;0;) (func (param "a" float32) (param "b" float32) (result float32))) + (export (;0;) "add" (func (type 0))) + ) + ) + (import "miden:core-import/intrinsics-felt@1.0.0" (instance (;2;) (type 2))) + (type (;3;) + (instance + (type (;0;) (func (param "a0" s32) (param "a1" s32) (param "a2" s32) (param "a3" s32) (param "a4" s32) (param "a5" s32) (param "a6" s32) (param "a7" s32) (param "result-ptr" s32))) + (export (;0;) "hash-one-to-one" (func (type 0))) + ) + ) + (import "miden:core-import/stdlib-crypto-hashes-blake3@1.0.0" (instance (;3;) (type 3))) + (type (;4;) + (instance + (type (;0;) (func (param "asset0" float32) (param "asset1" float32) (param "asset2" float32) (param "asset3" float32) (param "result-ptr" s32))) + (export (;0;) "add-asset" (func (type 0))) + (export (;1;) "remove-asset" (func (type 0))) + ) + ) + (import "miden:core-import/account@1.0.0" (instance (;4;) (type 4))) + (type (;5;) + (instance + (type (;0;) (func (param "asset0" float32) (param "asset1" float32) (param "asset2" float32) (param "asset3" float32) (param "tag" float32) (param "note-type" float32) (param "recipient0" float32) (param "recipient1" float32) (param "recipient2" float32) (param "recipient3" float32) (result float32))) + (export (;0;) "create-note" (func (type 0))) + ) + ) + (import "miden:core-import/tx@1.0.0" (instance (;5;) (type 5))) + (core module (;0;) + (type (;0;) (func (param f32 f32) (result f32))) + (type (;1;) (func (param i32 i32 i32 i32 i32 i32 i32 i32 i32))) + (type (;2;) (func (result i32))) + (type (;3;) (func (param f32 f32 f32 f32 i32))) + (type (;4;) (func (param f32 f32 f32 f32 f32 f32 f32 f32 f32 f32) (result f32))) + (type (;5;) (func)) + (type (;6;) (func (param i32 i32) (result i32))) + (type (;7;) (func (param i32 i32 i32))) + (type (;8;) (func (param i32 i32 i32 i32) (result i32))) + (type (;9;) (func (param f32 f32 f32 f32))) + (type (;10;) (func (param f32 f32 f32 f32 f32 f32 f32 f32 f32 f32))) + (type (;11;) (func (param i32))) + (type (;12;) (func (param f32 f32 f32 f32) (result i32))) + (type (;13;) (func (param i32 i32 i32) (result i32))) + (type (;14;) (func (param i32 i32))) + (type (;15;) (func (param i32 f32 f32 i32) (result f32))) + (type (;16;) (func (param i32 i32 i32 i32))) + (import "miden:core-import/intrinsics-felt@1.0.0" "add" (func $miden_stdlib_sys::intrinsics::felt::extern_add (;0;) (type 0))) + (import "miden:core-import/stdlib-crypto-hashes-blake3@1.0.0" "hash-one-to-one" (func $miden_stdlib_sys::stdlib::crypto::hashes::extern_blake3_hash_1to1 (;1;) (type 1))) + (import "miden:core-import/intrinsics-mem@1.0.0" "heap-base" (func $miden_sdk_alloc::heap_base (;2;) (type 2))) + (import "miden:core-import/account@1.0.0" "add-asset" (func $miden_base_sys::bindings::account::extern_account_add_asset (;3;) (type 3))) + (import "miden:core-import/account@1.0.0" "remove-asset" (func $miden_base_sys::bindings::account::extern_account_remove_asset (;4;) (type 3))) + (import "miden:core-import/tx@1.0.0" "create-note" (func $miden_base_sys::bindings::tx::extern_tx_create_note (;5;) (type 4))) + (func $__wasm_call_ctors (;6;) (type 5)) + (func $basic_wallet::bindings::__link_custom_section_describing_imports (;7;) (type 5)) + (func $__rust_alloc (;8;) (type 6) (param i32 i32) (result i32) + i32.const 1048632 + local.get 1 + local.get 0 + call $::alloc + ) + (func $__rust_dealloc (;9;) (type 7) (param i32 i32 i32)) + (func $__rust_realloc (;10;) (type 8) (param i32 i32 i32 i32) (result i32) + block ;; label = @1 + i32.const 1048632 + local.get 2 + local.get 3 + call $::alloc + local.tee 2 + i32.eqz + br_if 0 (;@1;) + local.get 2 + local.get 0 + local.get 1 + local.get 3 + local.get 1 + local.get 3 + i32.lt_u + select + memory.copy + end + local.get 2 + ) + (func $__rust_alloc_zeroed (;11;) (type 6) (param i32 i32) (result i32) + block ;; label = @1 + i32.const 1048632 + local.get 1 + local.get 0 + call $::alloc + local.tee 1 + i32.eqz + br_if 0 (;@1;) + local.get 1 + i32.const 0 + local.get 0 + memory.fill + end + local.get 1 + ) + (func $miden:basic-wallet/basic-wallet@1.0.0#receive-asset (;12;) (type 9) (param f32 f32 f32 f32) + (local i32 i32) + global.get $__stack_pointer + local.tee 4 + i32.const 64 + i32.sub + i32.const -32 + i32.and + local.tee 5 + global.set $__stack_pointer + call $wit_bindgen_rt::run_ctors_once + local.get 5 + local.get 3 + f32.store offset=12 + local.get 5 + local.get 2 + f32.store offset=8 + local.get 5 + local.get 1 + f32.store offset=4 + local.get 5 + local.get 0 + f32.store + local.get 5 + i32.const 32 + i32.add + local.get 5 + call $miden_base_sys::bindings::account::add_asset + local.get 4 + global.set $__stack_pointer + ) + (func $miden:basic-wallet/basic-wallet@1.0.0#send-asset (;13;) (type 10) (param f32 f32 f32 f32 f32 f32 f32 f32 f32 f32) + (local i32 i32) + global.get $__stack_pointer + local.tee 10 + i32.const 96 + i32.sub + i32.const -32 + i32.and + local.tee 11 + global.set $__stack_pointer + call $wit_bindgen_rt::run_ctors_once + local.get 11 + local.get 3 + f32.store offset=12 + local.get 11 + local.get 2 + f32.store offset=8 + local.get 11 + local.get 1 + f32.store offset=4 + local.get 11 + local.get 0 + f32.store + local.get 11 + local.get 9 + f32.store offset=44 + local.get 11 + local.get 8 + f32.store offset=40 + local.get 11 + local.get 7 + f32.store offset=36 + local.get 11 + local.get 6 + f32.store offset=32 + local.get 11 + i32.const 64 + i32.add + local.get 11 + call $miden_base_sys::bindings::account::remove_asset + local.get 11 + i32.const 64 + i32.add + local.get 4 + local.get 5 + local.get 11 + i32.const 32 + i32.add + call $miden_base_sys::bindings::tx::create_note + drop + local.get 10 + global.set $__stack_pointer + ) + (func $miden:basic-wallet/aux@1.0.0#test-felt-intrinsics (;14;) (type 0) (param f32 f32) (result f32) + call $wit_bindgen_rt::run_ctors_once + local.get 0 + local.get 1 + call $miden_stdlib_sys::intrinsics::felt::extern_add + ) + (func $miden:basic-wallet/aux@1.0.0#test-stdlib (;15;) (type 6) (param i32 i32) (result i32) + (local i32 i32 i32 i32 i32 i32 i32 i32) + global.get $__stack_pointer + local.tee 2 + local.set 3 + local.get 2 + i32.const 96 + i32.sub + i32.const -32 + i32.and + local.tee 2 + global.set $__stack_pointer + call $wit_bindgen_rt::run_ctors_once + local.get 2 + local.get 0 + i32.store offset=24 + local.get 2 + local.get 1 + i32.store offset=20 + block ;; label = @1 + block ;; label = @2 + local.get 1 + i32.const 32 + i32.ne + br_if 0 (;@2;) + local.get 2 + i32.const 0 + i32.store offset=28 + local.get 0 + i32.load align=1 + local.set 1 + local.get 0 + i32.load offset=4 align=1 + local.set 4 + local.get 0 + i32.load offset=8 align=1 + local.set 5 + local.get 0 + i32.load offset=12 align=1 + local.set 6 + local.get 0 + i32.load offset=16 align=1 + local.set 7 + local.get 0 + i32.load offset=20 align=1 + local.set 8 + local.get 0 + i32.load offset=24 align=1 + local.set 9 + local.get 0 + i32.load offset=28 align=1 + local.set 0 + local.get 2 + i32.const 20 + i32.add + call $ as core::ops::drop::Drop>::drop + local.get 2 + i32.const 20 + i32.add + call $ as core::ops::drop::Drop>::drop + local.get 1 + local.get 4 + local.get 5 + local.get 6 + local.get 7 + local.get 8 + local.get 9 + local.get 0 + local.get 2 + i32.const 32 + i32.add + call $miden_stdlib_sys::stdlib::crypto::hashes::extern_blake3_hash_1to1 + local.get 2 + i32.const 84 + i32.add + i32.const 32 + i32.const 0 + call $alloc::raw_vec::RawVec::try_allocate_in + local.get 2 + i32.load offset=88 + local.set 1 + local.get 2 + i32.load offset=84 + i32.const 1 + i32.eq + br_if 1 (;@1;) + local.get 2 + i32.load offset=92 + local.tee 0 + i32.const 24 + i32.add + local.get 2 + i64.load offset=56 + i64.store align=1 + local.get 0 + i32.const 16 + i32.add + local.get 2 + i64.load offset=48 + i64.store align=1 + local.get 0 + i32.const 8 + i32.add + local.get 2 + i64.load offset=40 + i64.store align=1 + local.get 0 + local.get 2 + i64.load offset=32 + i64.store align=1 + local.get 2 + i32.const 32 + i32.store offset=92 + local.get 2 + local.get 0 + i32.store offset=88 + local.get 2 + local.get 1 + i32.store offset=84 + local.get 2 + i32.const 8 + i32.add + local.get 2 + i32.const 84 + i32.add + call $alloc::vec::Vec::into_boxed_slice + i32.const 0 + local.get 2 + i64.load offset=8 + i64.store offset=1048616 align=4 + local.get 3 + global.set $__stack_pointer + i32.const 1048616 + return + end + unreachable + end + local.get 1 + local.get 2 + i32.load offset=92 + call $alloc::raw_vec::handle_error + unreachable + ) + (func $miden:basic-wallet/aux@1.0.0#process-list-felt (;16;) (type 6) (param i32 i32) (result i32) + call $wit_bindgen_rt::run_ctors_once + unreachable + ) + (func $cabi_post_miden:basic-wallet/aux@1.0.0#process-list-felt (;17;) (type 11) (param i32)) + (func $miden:basic-wallet/aux@1.0.0#process-core-asset (;18;) (type 12) (param f32 f32 f32 f32) (result i32) + call $wit_bindgen_rt::run_ctors_once + unreachable + ) + (func $cabi_realloc_wit_bindgen_0_28_0 (;19;) (type 8) (param i32 i32 i32 i32) (result i32) + local.get 0 + local.get 1 + local.get 2 + local.get 3 + call $wit_bindgen_rt::cabi_realloc + ) + (func $wit_bindgen_rt::cabi_realloc (;20;) (type 8) (param i32 i32 i32 i32) (result i32) + block ;; label = @1 + block ;; label = @2 + block ;; label = @3 + local.get 1 + br_if 0 (;@3;) + local.get 3 + i32.eqz + br_if 2 (;@1;) + i32.const 0 + i32.load8_u offset=1048636 + drop + local.get 3 + local.get 2 + call $__rust_alloc + local.set 2 + br 1 (;@2;) + end + local.get 0 + local.get 1 + local.get 2 + local.get 3 + call $__rust_realloc + local.set 2 + end + local.get 2 + br_if 0 (;@1;) + unreachable + end + local.get 2 + ) + (func $wit_bindgen_rt::run_ctors_once (;21;) (type 5) + block ;; label = @1 + i32.const 0 + i32.load8_u offset=1048637 + br_if 0 (;@1;) + call $__wasm_call_ctors + i32.const 0 + i32.const 1 + i32.store8 offset=1048637 + end + ) + (func $::alloc (;22;) (type 13) (param i32 i32 i32) (result i32) + (local i32 i32) + block ;; label = @1 + local.get 1 + i32.const 32 + local.get 1 + i32.const 32 + i32.gt_u + select + local.tee 1 + i32.popcnt + i32.const 1 + i32.ne + br_if 0 (;@1;) + i32.const -2147483648 + local.get 1 + i32.sub + local.get 2 + i32.lt_u + br_if 0 (;@1;) + i32.const 0 + local.set 3 + local.get 1 + local.get 2 + i32.add + i32.const -1 + i32.add + i32.const 0 + local.get 1 + i32.sub + i32.and + local.set 2 + block ;; label = @2 + local.get 0 + i32.load + br_if 0 (;@2;) + local.get 0 + call $miden_sdk_alloc::heap_base + memory.size + i32.const 16 + i32.shl + i32.add + i32.store + end + block ;; label = @2 + i32.const 268435456 + local.get 0 + i32.load + local.tee 4 + i32.sub + local.get 2 + i32.lt_u + br_if 0 (;@2;) + local.get 0 + local.get 4 + local.get 2 + i32.add + i32.store + local.get 4 + local.get 1 + i32.add + local.set 3 + end + local.get 3 + return + end + unreachable + ) + (func $miden_base_sys::bindings::account::add_asset (;23;) (type 14) (param i32 i32) + local.get 1 + f32.load + local.get 1 + f32.load offset=4 + local.get 1 + f32.load offset=8 + local.get 1 + f32.load offset=12 + local.get 0 + call $miden_base_sys::bindings::account::extern_account_add_asset + ) + (func $miden_base_sys::bindings::account::remove_asset (;24;) (type 14) (param i32 i32) + local.get 1 + f32.load + local.get 1 + f32.load offset=4 + local.get 1 + f32.load offset=8 + local.get 1 + f32.load offset=12 + local.get 0 + call $miden_base_sys::bindings::account::extern_account_remove_asset + ) + (func $miden_base_sys::bindings::tx::create_note (;25;) (type 15) (param i32 f32 f32 i32) (result f32) + local.get 0 + f32.load + local.get 0 + f32.load offset=4 + local.get 0 + f32.load offset=8 + local.get 0 + f32.load offset=12 + local.get 1 + local.get 2 + local.get 3 + f32.load + local.get 3 + f32.load offset=4 + local.get 3 + f32.load offset=8 + local.get 3 + f32.load offset=12 + call $miden_base_sys::bindings::tx::extern_tx_create_note + ) + (func $alloc::vec::Vec::into_boxed_slice (;26;) (type 14) (param i32 i32) + (local i32 i32) + global.get $__stack_pointer + i32.const 16 + i32.sub + local.tee 2 + global.set $__stack_pointer + block ;; label = @1 + block ;; label = @2 + local.get 1 + i32.load + local.get 1 + i32.load offset=8 + local.tee 3 + i32.le_u + br_if 0 (;@2;) + local.get 2 + i32.const 8 + i32.add + local.get 1 + local.get 3 + call $alloc::raw_vec::RawVec::shrink_unchecked + local.get 2 + i32.load offset=8 + i32.const -2147483647 + i32.ne + br_if 1 (;@1;) + local.get 1 + i32.load offset=8 + local.set 3 + end + local.get 0 + local.get 3 + i32.store offset=4 + local.get 0 + local.get 1 + i32.load offset=4 + i32.store + local.get 2 + i32.const 16 + i32.add + global.set $__stack_pointer + return + end + unreachable + ) + (func $ as core::ops::drop::Drop>::drop (;27;) (type 11) (param i32)) + (func $ as core::ops::drop::Drop>::drop (;28;) (type 11) (param i32) + (local i32) + block ;; label = @1 + local.get 0 + i32.load + local.tee 1 + i32.eqz + br_if 0 (;@1;) + local.get 0 + i32.load offset=4 + i32.const 1 + local.get 1 + call $::deallocate + end + ) + (func $alloc::raw_vec::RawVec::try_allocate_in (;29;) (type 7) (param i32 i32 i32) + (local i32 i32) + global.get $__stack_pointer + i32.const 16 + i32.sub + local.tee 3 + global.set $__stack_pointer + block ;; label = @1 + block ;; label = @2 + local.get 1 + br_if 0 (;@2;) + local.get 0 + i64.const 4294967296 + i64.store offset=4 align=4 + i32.const 0 + local.set 1 + br 1 (;@1;) + end + block ;; label = @2 + block ;; label = @3 + local.get 1 + i32.const -1 + i32.gt_s + local.tee 4 + br_if 0 (;@3;) + local.get 0 + i32.const 0 + i32.store offset=4 + br 1 (;@2;) + end + block ;; label = @3 + block ;; label = @4 + local.get 2 + br_if 0 (;@4;) + local.get 3 + i32.const 8 + i32.add + local.get 4 + local.get 1 + call $::allocate + local.get 3 + i32.load offset=8 + local.set 2 + br 1 (;@3;) + end + local.get 3 + local.get 4 + local.get 1 + i32.const 1 + call $alloc::alloc::Global::alloc_impl + local.get 3 + i32.load + local.set 2 + end + block ;; label = @3 + local.get 2 + i32.eqz + br_if 0 (;@3;) + local.get 0 + local.get 2 + i32.store offset=8 + local.get 0 + local.get 1 + i32.store offset=4 + i32.const 0 + local.set 1 + br 2 (;@1;) + end + local.get 0 + local.get 1 + i32.store offset=8 + local.get 0 + local.get 4 + i32.store offset=4 + end + i32.const 1 + local.set 1 + end + local.get 0 + local.get 1 + i32.store + local.get 3 + i32.const 16 + i32.add + global.set $__stack_pointer + ) + (func $::allocate (;30;) (type 7) (param i32 i32 i32) + (local i32) + global.get $__stack_pointer + i32.const 16 + i32.sub + local.tee 3 + global.set $__stack_pointer + local.get 3 + i32.const 8 + i32.add + local.get 1 + local.get 2 + i32.const 0 + call $alloc::alloc::Global::alloc_impl + local.get 3 + i32.load offset=12 + local.set 2 + local.get 0 + local.get 3 + i32.load offset=8 + i32.store + local.get 0 + local.get 2 + i32.store offset=4 + local.get 3 + i32.const 16 + i32.add + global.set $__stack_pointer + ) + (func $alloc::alloc::Global::alloc_impl (;31;) (type 16) (param i32 i32 i32 i32) + block ;; label = @1 + local.get 2 + i32.eqz + br_if 0 (;@1;) + block ;; label = @2 + local.get 3 + br_if 0 (;@2;) + i32.const 0 + i32.load8_u offset=1048636 + drop + local.get 2 + local.get 1 + call $__rust_alloc + local.set 1 + br 1 (;@1;) + end + local.get 2 + local.get 1 + call $__rust_alloc_zeroed + local.set 1 + end + local.get 0 + local.get 2 + i32.store offset=4 + local.get 0 + local.get 1 + i32.store + ) + (func $alloc::raw_vec::RawVec::shrink_unchecked (;32;) (type 7) (param i32 i32 i32) + (local i32 i32 i32 i32) + i32.const -2147483647 + local.set 3 + block ;; label = @1 + local.get 1 + i32.load + local.tee 4 + i32.eqz + br_if 0 (;@1;) + local.get 1 + i32.load offset=4 + local.set 5 + block ;; label = @2 + block ;; label = @3 + local.get 2 + br_if 0 (;@3;) + i32.const 1 + local.set 6 + local.get 5 + i32.const 1 + local.get 4 + call $::deallocate + br 1 (;@2;) + end + i32.const 1 + local.set 3 + local.get 5 + local.get 4 + i32.const 1 + local.get 2 + call $__rust_realloc + local.tee 6 + i32.eqz + br_if 1 (;@1;) + end + local.get 1 + local.get 2 + i32.store + local.get 1 + local.get 6 + i32.store offset=4 + i32.const -2147483647 + local.set 3 + end + local.get 0 + local.get 2 + i32.store offset=4 + local.get 0 + local.get 3 + i32.store + ) + (func $::deallocate (;33;) (type 7) (param i32 i32 i32) + block ;; label = @1 + local.get 2 + i32.eqz + br_if 0 (;@1;) + local.get 0 + local.get 2 + local.get 1 + call $__rust_dealloc + end + ) + (func $alloc::raw_vec::handle_error (;34;) (type 14) (param i32 i32) + unreachable + ) + (func $cabi_realloc (;35;) (type 8) (param i32 i32 i32 i32) (result i32) + local.get 0 + local.get 1 + local.get 2 + local.get 3 + call $cabi_realloc_wit_bindgen_0_28_0 + ) + (table (;0;) 3 3 funcref) + (memory (;0;) 17) + (global $__stack_pointer (;0;) (mut i32) i32.const 1048576) + (export "memory" (memory 0)) + (export "miden:basic-wallet/basic-wallet@1.0.0#receive-asset" (func $miden:basic-wallet/basic-wallet@1.0.0#receive-asset)) + (export "miden:basic-wallet/basic-wallet@1.0.0#send-asset" (func $miden:basic-wallet/basic-wallet@1.0.0#send-asset)) + (export "miden:basic-wallet/aux@1.0.0#test-felt-intrinsics" (func $miden:basic-wallet/aux@1.0.0#test-felt-intrinsics)) + (export "miden:basic-wallet/aux@1.0.0#test-stdlib" (func $miden:basic-wallet/aux@1.0.0#test-stdlib)) + (export "miden:basic-wallet/aux@1.0.0#process-list-felt" (func $miden:basic-wallet/aux@1.0.0#process-list-felt)) + (export "cabi_post_miden:basic-wallet/aux@1.0.0#process-list-felt" (func $cabi_post_miden:basic-wallet/aux@1.0.0#process-list-felt)) + (export "miden:basic-wallet/aux@1.0.0#process-core-asset" (func $miden:basic-wallet/aux@1.0.0#process-core-asset)) + (export "cabi_post_miden:basic-wallet/aux@1.0.0#test-stdlib" (func $cabi_post_miden:basic-wallet/aux@1.0.0#process-list-felt)) + (export "cabi_realloc_wit_bindgen_0_28_0" (func $cabi_realloc_wit_bindgen_0_28_0)) + (export "cabi_realloc" (func $cabi_realloc)) + (elem (;0;) (i32.const 1) func $basic_wallet::bindings::__link_custom_section_describing_imports $cabi_realloc) + (data $.rodata (;0;) (i32.const 1048576) "\01\00\00\00\01\00\00\00\01\00\00\00\01\00\00\00\01\00\00\00\01\00\00\00\01\00\00\00\01\00\00\00\01\00\00\00\02\00\00\00") + ) + (alias export 2 "add" (func (;0;))) + (core func (;0;) (canon lower (func 0))) + (core instance (;0;) + (export "add" (func 0)) + ) + (alias export 3 "hash-one-to-one" (func (;1;))) + (core func (;1;) (canon lower (func 1))) + (core instance (;1;) + (export "hash-one-to-one" (func 1)) + ) + (alias export 1 "heap-base" (func (;2;))) + (core func (;2;) (canon lower (func 2))) + (core instance (;2;) + (export "heap-base" (func 2)) + ) + (alias export 4 "add-asset" (func (;3;))) + (core func (;3;) (canon lower (func 3))) + (alias export 4 "remove-asset" (func (;4;))) + (core func (;4;) (canon lower (func 4))) + (core instance (;3;) + (export "add-asset" (func 3)) + (export "remove-asset" (func 4)) + ) + (alias export 5 "create-note" (func (;5;))) + (core func (;5;) (canon lower (func 5))) + (core instance (;4;) + (export "create-note" (func 5)) + ) + (core instance (;5;) (instantiate 0 + (with "miden:core-import/intrinsics-felt@1.0.0" (instance 0)) + (with "miden:core-import/stdlib-crypto-hashes-blake3@1.0.0" (instance 1)) + (with "miden:core-import/intrinsics-mem@1.0.0" (instance 2)) + (with "miden:core-import/account@1.0.0" (instance 3)) + (with "miden:core-import/tx@1.0.0" (instance 4)) + ) + ) + (alias core export 5 "memory" (core memory (;0;))) + (alias core export 5 "cabi_realloc" (core func (;6;))) + (alias export 0 "core-asset" (type (;6;))) + (type (;7;) (func (param "core-asset" 6))) + (alias core export 5 "miden:basic-wallet/basic-wallet@1.0.0#receive-asset" (core func (;7;))) + (func (;6;) (type 7) (canon lift (core func 7))) + (alias export 0 "tag" (type (;8;))) + (alias export 0 "note-type" (type (;9;))) + (alias export 0 "recipient" (type (;10;))) + (type (;11;) (func (param "core-asset" 6) (param "tag" 8) (param "note-type" 9) (param "recipient" 10))) + (alias core export 5 "miden:basic-wallet/basic-wallet@1.0.0#send-asset" (core func (;8;))) + (func (;7;) (type 11) (canon lift (core func 8))) + (alias export 0 "felt" (type (;12;))) + (alias export 0 "word" (type (;13;))) + (alias export 0 "core-asset" (type (;14;))) + (alias export 0 "tag" (type (;15;))) + (alias export 0 "recipient" (type (;16;))) + (alias export 0 "note-type" (type (;17;))) + (component (;0;) + (type (;0;) (record (field "inner" float32))) + (import "import-type-felt" (type (;1;) (eq 0))) + (type (;2;) (tuple 1 1 1 1)) + (type (;3;) (record (field "inner" 2))) + (import "import-type-word" (type (;4;) (eq 3))) + (type (;5;) (record (field "inner" 4))) + (import "import-type-core-asset" (type (;6;) (eq 5))) + (type (;7;) (record (field "inner" 1))) + (import "import-type-tag" (type (;8;) (eq 7))) + (type (;9;) (record (field "inner" 4))) + (import "import-type-recipient" (type (;10;) (eq 9))) + (type (;11;) (record (field "inner" 1))) + (import "import-type-note-type" (type (;12;) (eq 11))) + (import "import-type-core-asset0" (type (;13;) (eq 6))) + (type (;14;) (func (param "core-asset" 13))) + (import "import-func-receive-asset" (func (;0;) (type 14))) + (import "import-type-tag0" (type (;15;) (eq 8))) + (import "import-type-note-type0" (type (;16;) (eq 12))) + (import "import-type-recipient0" (type (;17;) (eq 10))) + (type (;18;) (func (param "core-asset" 13) (param "tag" 15) (param "note-type" 16) (param "recipient" 17))) + (import "import-func-send-asset" (func (;1;) (type 18))) + (export (;19;) "core-asset" (type 6)) + (export (;20;) "tag" (type 8)) + (export (;21;) "recipient" (type 10)) + (export (;22;) "note-type" (type 12)) + (export (;23;) "felt" (type 1)) + (type (;24;) (func (param "core-asset" 19))) + (export (;2;) "receive-asset" (func 0) (func (type 24))) + (type (;25;) (func (param "core-asset" 19) (param "tag" 20) (param "note-type" 22) (param "recipient" 21))) + (export (;3;) "send-asset" (func 1) (func (type 25))) + ) + (instance (;6;) (instantiate 0 + (with "import-func-receive-asset" (func 6)) + (with "import-func-send-asset" (func 7)) + (with "import-type-felt" (type 12)) + (with "import-type-word" (type 13)) + (with "import-type-core-asset" (type 14)) + (with "import-type-tag" (type 15)) + (with "import-type-recipient" (type 16)) + (with "import-type-note-type" (type 17)) + (with "import-type-core-asset0" (type 6)) + (with "import-type-tag0" (type 8)) + (with "import-type-note-type0" (type 9)) + (with "import-type-recipient0" (type 10)) + ) + ) + (export (;7;) "miden:basic-wallet/basic-wallet@1.0.0" (instance 6)) + (alias export 0 "felt" (type (;18;))) + (type (;19;) (func (param "a" 18) (param "b" 18) (result 18))) + (alias core export 5 "miden:basic-wallet/aux@1.0.0#test-felt-intrinsics" (core func (;9;))) + (func (;8;) (type 19) (canon lift (core func 9))) + (type (;20;) (list u8)) + (type (;21;) (func (param "input" 20) (result 20))) + (alias core export 5 "miden:basic-wallet/aux@1.0.0#test-stdlib" (core func (;10;))) + (alias core export 5 "cabi_post_miden:basic-wallet/aux@1.0.0#test-stdlib" (core func (;11;))) + (func (;9;) (type 21) (canon lift (core func 10) (memory 0) (realloc 6) (post-return 11))) + (type (;22;) (list 18)) + (type (;23;) (func (param "input" 22) (result 22))) + (alias core export 5 "miden:basic-wallet/aux@1.0.0#process-list-felt" (core func (;12;))) + (alias core export 5 "cabi_post_miden:basic-wallet/aux@1.0.0#process-list-felt" (core func (;13;))) + (func (;10;) (type 23) (canon lift (core func 12) (memory 0) (realloc 6) (post-return 13))) + (type (;24;) (func (param "input" 6) (result 6))) + (alias core export 5 "miden:basic-wallet/aux@1.0.0#process-core-asset" (core func (;14;))) + (func (;11;) (type 24) (canon lift (core func 14) (memory 0))) + (component (;1;) + (type (;0;) (record (field "inner" float32))) + (import "import-type-felt" (type (;1;) (eq 0))) + (type (;2;) (tuple 1 1 1 1)) + (type (;3;) (record (field "inner" 2))) + (import "import-type-word" (type (;4;) (eq 3))) + (type (;5;) (record (field "inner" 4))) + (import "import-type-core-asset" (type (;6;) (eq 5))) + (type (;7;) (record (field "inner" 1))) + (import "import-type-tag" (type (;8;) (eq 7))) + (type (;9;) (record (field "inner" 4))) + (import "import-type-recipient" (type (;10;) (eq 9))) + (type (;11;) (record (field "inner" 1))) + (import "import-type-note-type" (type (;12;) (eq 11))) + (import "import-type-felt0" (type (;13;) (eq 1))) + (type (;14;) (func (param "a" 13) (param "b" 13) (result 13))) + (import "import-func-test-felt-intrinsics" (func (;0;) (type 14))) + (type (;15;) (list u8)) + (type (;16;) (func (param "input" 15) (result 15))) + (import "import-func-test-stdlib" (func (;1;) (type 16))) + (type (;17;) (list 13)) + (type (;18;) (func (param "input" 17) (result 17))) + (import "import-func-process-list-felt" (func (;2;) (type 18))) + (import "import-type-core-asset0" (type (;19;) (eq 6))) + (type (;20;) (func (param "input" 19) (result 19))) + (import "import-func-process-core-asset" (func (;3;) (type 20))) + (export (;21;) "core-asset" (type 6)) + (export (;22;) "tag" (type 8)) + (export (;23;) "recipient" (type 10)) + (export (;24;) "note-type" (type 12)) + (export (;25;) "felt" (type 1)) + (type (;26;) (func (param "a" 25) (param "b" 25) (result 25))) + (export (;4;) "test-felt-intrinsics" (func 0) (func (type 26))) + (type (;27;) (list u8)) + (type (;28;) (func (param "input" 27) (result 27))) + (export (;5;) "test-stdlib" (func 1) (func (type 28))) + (type (;29;) (list 25)) + (type (;30;) (func (param "input" 29) (result 29))) + (export (;6;) "process-list-felt" (func 2) (func (type 30))) + (type (;31;) (func (param "input" 21) (result 21))) + (export (;7;) "process-core-asset" (func 3) (func (type 31))) + ) + (instance (;8;) (instantiate 1 + (with "import-func-test-felt-intrinsics" (func 8)) + (with "import-func-test-stdlib" (func 9)) + (with "import-func-process-list-felt" (func 10)) + (with "import-func-process-core-asset" (func 11)) + (with "import-type-felt" (type 12)) + (with "import-type-word" (type 13)) + (with "import-type-core-asset" (type 14)) + (with "import-type-tag" (type 15)) + (with "import-type-recipient" (type 16)) + (with "import-type-note-type" (type 17)) + (with "import-type-felt0" (type 18)) + (with "import-type-core-asset0" (type 6)) + ) + ) + (export (;9;) "miden:basic-wallet/aux@1.0.0" (instance 8)) +) \ No newline at end of file diff --git a/tests/integration/src/compiler_test.rs b/tests/integration/src/compiler_test.rs index 3ed91aa43..9c4888c40 100644 --- a/tests/integration/src/compiler_test.rs +++ b/tests/integration/src/compiler_test.rs @@ -1081,6 +1081,18 @@ impl CompilerTest { } } + /// Expect test that builds the IR2(sketch) + pub fn expect_ir2(&mut self, expected_hir_file: expect_test::ExpectFile) { + let ir = midenc_frontend_wasm::translate_component2( + &self.wasm_bytes(), + &self.config, + &self.session, + ) + .expect("Failed to translate Wasm binary to IR component"); + // let txt = ir_components.into_iter().map(|c| c.to_string()).collect::>().join("\n"); + expected_hir_file.assert_eq(&ir.to_string()); + } + /// Compare the compiled MASM against the expected output pub fn expect_masm(&mut self, expected_masm_file: expect_test::ExpectFile) { let program = demangle(self.masm_src().as_str()); diff --git a/tests/integration/src/rust_masm_tests/rust_sdk.rs b/tests/integration/src/rust_masm_tests/rust_sdk.rs index ee8836028..c4766975b 100644 --- a/tests/integration/src/rust_masm_tests/rust_sdk.rs +++ b/tests/integration/src/rust_masm_tests/rust_sdk.rs @@ -218,3 +218,18 @@ fn rust_sdk_cross_ctx_note() { let trace = exec.execute(&package.unwrap_program(), &test.session); } + +// Testing the new frontend's Wasm component translator producing HIR2(sketch) +#[test] +fn rust_sdk_hir2_sketch() { + let _ = env_logger::builder().is_test(true).try_init(); + let config = WasmTranslationConfig::default(); + let mut test = CompilerTest::rust_source_cargo_miden( + "../rust-apps-wasm/rust-sdk/basic-wallet", + config, + [], + ); + let artifact_name = "hir2_sketch"; + test.expect_wasm(expect_file![format!("../../expected/rust_sdk/{artifact_name}.wat")]); + test.expect_ir2(expect_file![format!("../../expected/rust_sdk/{artifact_name}.hir")]); +} From 6510b26fdbf8875946e1f07fa34bb402a61c043c Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Fri, 3 Jan 2025 07:36:33 +0200 Subject: [PATCH 02/18] refactor: move module id creation out of the loop --- frontend-wasm/src/component/translator2.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/frontend-wasm/src/component/translator2.rs b/frontend-wasm/src/component/translator2.rs index 64b114411..bfc50014a 100644 --- a/frontend-wasm/src/component/translator2.rs +++ b/frontend-wasm/src/component/translator2.rs @@ -243,7 +243,8 @@ impl<'a> ComponentTranslator2<'a> { let parsed_component = &parsed_root_component.static_components[*static_component_idx]; dbg!(&parsed_component.exports); - // let name = + let module = + Ident::new(Symbol::intern(interface_name.clone()), SourceSpan::default()); let functions = parsed_component .exports .iter() @@ -254,11 +255,9 @@ impl<'a> ComponentTranslator2<'a> { // .unwrap_instantiated(); // TODO: get the component function type let signature = Signature::new(vec![], vec![]); + let function_id = FunctionIdent { - module: Ident::new( - Symbol::intern(interface_name.clone()), - SourceSpan::default(), - ), + module, function: Ident::new( Symbol::intern(name.to_string()), SourceSpan::default(), From 209d6969fad716d2bb23f17e239d16c5bd237edf Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Fri, 3 Jan 2025 09:58:18 +0200 Subject: [PATCH 03/18] feature: function signatures in the `CanonLower` synthetic modules (imports) --- frontend-wasm/src/component/translator.rs | 5 ++- frontend-wasm/src/component/translator2.rs | 38 +++++++++++++------ .../expected/rust_sdk/hir2_sketch.hir | 12 +++--- 3 files changed, 36 insertions(+), 19 deletions(-) diff --git a/frontend-wasm/src/component/translator.rs b/frontend-wasm/src/component/translator.rs index e5c3c3153..ef4a4024d 100644 --- a/frontend-wasm/src/component/translator.rs +++ b/frontend-wasm/src/component/translator.rs @@ -487,7 +487,10 @@ fn function_id_from_export(exporting_module: &Module, func_idx: FuncIndex) -> Fu } /// Convert the given Wasm component function type to the Miden IR lifted function type -fn convert_lifted_func_ty(ty: &TypeFuncIndex, component_types: &ComponentTypes) -> FunctionType { +pub fn convert_lifted_func_ty( + ty: &TypeFuncIndex, + component_types: &ComponentTypes, +) -> FunctionType { let type_func = component_types[*ty].clone(); let params_types = component_types[type_func.params].clone().types; let results_types = component_types[type_func.results].clone().types; diff --git a/frontend-wasm/src/component/translator2.rs b/frontend-wasm/src/component/translator2.rs index bfc50014a..669556e28 100644 --- a/frontend-wasm/src/component/translator2.rs +++ b/frontend-wasm/src/component/translator2.rs @@ -2,9 +2,9 @@ use hir2_sketch::{Component, Interface, Module}; use midenc_hir::{ - cranelift_entity::PrimaryMap, diagnostics::Report, CanonAbiImport, ComponentBuilder, - ComponentExport, FunctionIdent, FunctionType, Ident, InterfaceFunctionIdent, InterfaceIdent, - MidenAbiImport, Signature, SourceSpan, Symbol, + cranelift_entity::PrimaryMap, diagnostics::Report, AbiParam, CallConv, CanonAbiImport, + ComponentBuilder, ComponentExport, FunctionIdent, FunctionType, Ident, InterfaceFunctionIdent, + InterfaceIdent, Linkage, MidenAbiImport, Signature, SourceSpan, Symbol, }; use midenc_hir_type::Abi; use midenc_session::{DiagnosticsHandler, Session}; @@ -12,13 +12,13 @@ use rustc_hash::FxHashMap; use wasmparser::types::ComponentEntityType; use super::{ - interface_type_to_ir, CanonLift, CanonLower, CanonicalOptions, ComponentFuncIndex, - ComponentIndex, ComponentInstanceIndex, ComponentInstantiation, ComponentTypes, - ComponentTypesBuilder, CoreDef, CoreExport, Export, ExportItem, GlobalInitializer, ImportIndex, - InstantiateModule, LinearComponent, LinearComponentTranslation, LoweredIndex, - ModuleInstanceIndex, ParsedRootComponent, RuntimeImportIndex, RuntimeInstanceIndex, - RuntimePostReturnIndex, RuntimeReallocIndex, StaticModuleIndex, Trampoline, TypeDef, - TypeFuncIndex, + interface_type_to_ir, translator::convert_lifted_func_ty, CanonLift, CanonLower, + CanonicalOptions, ComponentFuncIndex, ComponentIndex, ComponentInstanceIndex, + ComponentInstantiation, ComponentTypes, ComponentTypesBuilder, CoreDef, CoreExport, Export, + ExportItem, GlobalInitializer, ImportIndex, InstantiateModule, LinearComponent, + LinearComponentTranslation, LoweredIndex, ModuleInstanceIndex, ParsedRootComponent, + RuntimeImportIndex, RuntimeInstanceIndex, RuntimePostReturnIndex, RuntimeReallocIndex, + StaticModuleIndex, Trampoline, TypeDef, TypeFuncIndex, }; use crate::{ component::{ComponentItem, LocalInitializer, StaticComponentIndex, StringEncoding}, @@ -171,8 +171,22 @@ impl<'a> ComponentTranslator2<'a> { module_name = Some(import_instance.name.clone()); } let func = Ident::new(Symbol::intern(*k), SourceSpan::default()); - // TODO: get the component function type - let signature = Signature::new(vec![], vec![]); + // TODO: handle error + let type_func_idx = types + .convert_component_func_type( + parsed_root_component.root_component.types_ref(), + canon_lower.lower_ty, + ) + .unwrap(); + + let component_types = types.resources_mut_and_types().1; + let func_ty = convert_lifted_func_ty(&type_func_idx, component_types); + let signature = Signature { + params: func_ty.params.into_iter().map(AbiParam::new).collect(), + results: func_ty.results.into_iter().map(AbiParam::new).collect(), + cc: CallConv::CanonLower, + linkage: Linkage::External, + }; (func, signature) }) .collect(); diff --git a/tests/integration/expected/rust_sdk/hir2_sketch.hir b/tests/integration/expected/rust_sdk/hir2_sketch.hir index b9396428f..fa6be144d 100644 --- a/tests/integration/expected/rust_sdk/hir2_sketch.hir +++ b/tests/integration/expected/rust_sdk/hir2_sketch.hir @@ -13,20 +13,20 @@ ;; Modules (module #miden:core-import/intrinsics-felt@1.0.0 - (func (#miden:core-import/intrinsics-felt@1.0.0 #add ) + (func (#miden:core-import/intrinsics-felt@1.0.0 #add (cc lower) (param felt) (param felt) (result felt)) ) (module #miden:core-import/stdlib-crypto-hashes-blake3@1.0.0 - (func (#miden:core-import/stdlib-crypto-hashes-blake3@1.0.0 #hash-one-to-one ) + (func (#miden:core-import/stdlib-crypto-hashes-blake3@1.0.0 #hash-one-to-one (cc lower) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32)) ) (module #miden:core-import/intrinsics-mem@1.0.0 - (func (#miden:core-import/intrinsics-mem@1.0.0 #heap-base ) + (func (#miden:core-import/intrinsics-mem@1.0.0 #heap-base (cc lower) (result i32)) ) (module #miden:core-import/account@1.0.0 - (func (#miden:core-import/account@1.0.0 #add-asset ) - (func (#miden:core-import/account@1.0.0 #remove-asset ) + (func (#miden:core-import/account@1.0.0 #add-asset (cc lower) (param felt) (param felt) (param felt) (param felt) (param i32)) + (func (#miden:core-import/account@1.0.0 #remove-asset (cc lower) (param felt) (param felt) (param felt) (param felt) (param i32)) ) (module #miden:core-import/tx@1.0.0 - (func (#miden:core-import/tx@1.0.0 #create-note ) + (func (#miden:core-import/tx@1.0.0 #create-note (cc lower) (param felt) (param felt) (param felt) (param felt) (param felt) (param felt) (param felt) (param felt) (param felt) (param felt) (result felt)) ) (module #basic_wallet From ffd5de81cd58a1b3079b427151d6693a551eb7be Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Fri, 3 Jan 2025 15:40:02 +0200 Subject: [PATCH 04/18] feature: add function signatures in the export interface --- frontend-wasm/src/component/translator2.rs | 72 ++++++++++++++++++---- 1 file changed, 61 insertions(+), 11 deletions(-) diff --git a/frontend-wasm/src/component/translator2.rs b/frontend-wasm/src/component/translator2.rs index 669556e28..5689a07cb 100644 --- a/frontend-wasm/src/component/translator2.rs +++ b/frontend-wasm/src/component/translator2.rs @@ -82,15 +82,16 @@ impl<'a> ComponentTranslator2<'a> { modules: vec![], }; let mut static_modules = Vec::new(); + // TODO: extract into a frame (new frame on `ComponentInstantiate`) let mut components: PrimaryMap = PrimaryMap::new(); let mut component_instances: PrimaryMap = PrimaryMap::new(); - let mut component_funcs: PrimaryMap = + let mut component_funcs: PrimaryMap = PrimaryMap::new(); let mut core_funcs: PrimaryMap = PrimaryMap::new(); + // TODO: move to core_funcs let mut lowerings: PrimaryMap = PrimaryMap::new(); - let mut liftings: PrimaryMap = PrimaryMap::new(); let types_ref = parsed_root_component.root_component.types_ref(); for init in parsed_root_component.root_component.initializers.iter() { // dbg!(&init); @@ -129,7 +130,7 @@ impl<'a> ComponentTranslator2<'a> { }, ) => { // dbg!(&init); - liftings.push(lift.clone()); + component_funcs.push(ComponentFuncDef::Lifted(lift.clone())); } LocalInitializer::Resource(aliasable_resource_id, wasm_type, func_index) => todo!(), LocalInitializer::ResourceNew(aliasable_resource_id, signature_index) => todo!(), @@ -159,8 +160,9 @@ impl<'a> ComponentTranslator2<'a> { .map(|(k, v)| { let func_id = v.unwrap_func(); let canon_lower = &lowerings[func_id]; - let comp_func = &component_funcs[canon_lower.func]; - let import_instance = &component_instances[comp_func.0].unwrap_import(); + let comp_func = &component_funcs[canon_lower.func].unwrap_import(); + let import_instance = + &component_instances[*comp_func.0].unwrap_import(); if let Some(module_name) = &module_name { assert_eq!( module_name, &import_instance.name, @@ -240,7 +242,10 @@ impl<'a> ComponentTranslator2<'a> { // dbg!(&init); } LocalInitializer::AliasComponentExport(component_instance_index, name) => { - component_funcs.push((*component_instance_index, name.to_string())); + component_funcs.push(ComponentFuncDef::Import( + *component_instance_index, + name.to_string(), + )); } LocalInitializer::AliasModule(closed_over_module) => todo!(), LocalInitializer::AliasComponent(closed_over_component) => todo!(), @@ -256,7 +261,7 @@ impl<'a> ComponentTranslator2<'a> { let static_component_idx = components[instance.component].0; let parsed_component = &parsed_root_component.static_components[*static_component_idx]; - dbg!(&parsed_component.exports); + // dbg!(&parsed_component.exports); let module = Ident::new(Symbol::intern(interface_name.clone()), SourceSpan::default()); let functions = parsed_component @@ -264,10 +269,31 @@ impl<'a> ComponentTranslator2<'a> { .iter() .flat_map(|(name, item)| { if let ComponentItem::Func(f) = item { - // let (component_instance_id, name) = component_funcs[*f]; - // let component_instance = component_instances[component_instance_id] - // .unwrap_instantiated(); - // TODO: get the component function type + // dbg!(&component_funcs, f, name); + dbg!(&parsed_component.initializers); + let canon_lift = component_funcs[*f].unwrap_canon_lift(); + // TODO: extract into a function + // TODO: handle error + let type_func_idx = types + .convert_component_func_type( + parsed_root_component.root_component.types_ref(), + canon_lift.ty, + ) + .unwrap(); + + let component_types = types.resources_mut_and_types().1; + let func_ty = + convert_lifted_func_ty(&type_func_idx, component_types); + let signature = Signature { + params: func_ty.params.into_iter().map(AbiParam::new).collect(), + results: func_ty + .results + .into_iter() + .map(AbiParam::new) + .collect(), + cc: CallConv::CanonLower, + linkage: Linkage::External, + }; let signature = Signature::new(vec![], vec![]); let function_id = FunctionIdent { @@ -329,3 +355,27 @@ struct ComponentInstanceImport { name: String, ty: TypeDef, } + +#[derive(Clone, Debug)] +enum ComponentFuncDef { + /// A host-imported component function. + Import(ComponentInstanceIndex, String), + + /// A core wasm function was lifted into a component function. + Lifted(CanonLift), +} +impl ComponentFuncDef { + fn unwrap_import(&self) -> (&ComponentInstanceIndex, &String) { + match self { + ComponentFuncDef::Import(idx, name) => (idx, name), + _ => panic!("expected import"), + } + } + + fn unwrap_canon_lift(&self) -> &CanonLift { + match self { + ComponentFuncDef::Lifted(lift) => lift, + _ => panic!("expected lift"), + } + } +} From bc484b2b2d1198d74fb40b15ae3e8f3a5afb5c6f Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Fri, 10 Jan 2025 15:09:05 +0200 Subject: [PATCH 05/18] feature: translate Wasm component with multiple export interfaces to HIR2(sketch) --- frontend-wasm/src/component/build_ir.rs | 13 +- frontend-wasm/src/component/translator2.rs | 912 ++++++++++++------ frontend-wasm/src/component/types/mod.rs | 2 +- .../expected/rust_sdk/hir2_sketch.hir | 34 - .../rust_sdk/hir2_sketch_multi_interface.hir | 23 + ...ch.wat => hir2_sketch_multi_interface.wat} | 0 .../rust_sdk/hir2_sketch_single_interface.hir | 13 + .../rust_sdk/hir2_sketch_single_interface.wat | 249 +++++ tests/integration/src/compiler_test.rs | 3 +- .../src/rust_masm_tests/rust_sdk.rs | 23 +- 10 files changed, 945 insertions(+), 327 deletions(-) delete mode 100644 tests/integration/expected/rust_sdk/hir2_sketch.hir create mode 100644 tests/integration/expected/rust_sdk/hir2_sketch_multi_interface.hir rename tests/integration/expected/rust_sdk/{hir2_sketch.wat => hir2_sketch_multi_interface.wat} (100%) create mode 100644 tests/integration/expected/rust_sdk/hir2_sketch_single_interface.hir create mode 100644 tests/integration/expected/rust_sdk/hir2_sketch_single_interface.wat diff --git a/frontend-wasm/src/component/build_ir.rs b/frontend-wasm/src/component/build_ir.rs index 23024a3c6..fd69f1ad8 100644 --- a/frontend-wasm/src/component/build_ir.rs +++ b/frontend-wasm/src/component/build_ir.rs @@ -68,10 +68,15 @@ pub fn translate_component2( config: &WasmTranslationConfig, session: &Session, ) -> WasmResult { - let (mut component_types_builder, parsed_component) = parse(config, wasm, session)?; - let translator = ComponentTranslator2::new(config, session); - translator.translate( - parsed_component, + let (mut component_types_builder, parsed_root_component) = parse(config, wasm, session)?; + let translator = ComponentTranslator2::new( + &parsed_root_component.static_modules, + &parsed_root_component.static_components, + config, + session, + ); + translator.translate2( + &parsed_root_component.root_component, &mut component_types_builder, session.diagnostics.as_ref(), ) diff --git a/frontend-wasm/src/component/translator2.rs b/frontend-wasm/src/component/translator2.rs index 5689a07cb..e64e7d951 100644 --- a/frontend-wasm/src/component/translator2.rs +++ b/frontend-wasm/src/component/translator2.rs @@ -1,39 +1,30 @@ +// TODO: remove when it is completed #![allow(unused)] use hir2_sketch::{Component, Interface, Module}; use midenc_hir::{ - cranelift_entity::PrimaryMap, diagnostics::Report, AbiParam, CallConv, CanonAbiImport, - ComponentBuilder, ComponentExport, FunctionIdent, FunctionType, Ident, InterfaceFunctionIdent, - InterfaceIdent, Linkage, MidenAbiImport, Signature, SourceSpan, Symbol, + cranelift_entity::PrimaryMap, diagnostics::Report, AbiParam, CallConv, FunctionIdent, Ident, + Linkage, Signature, SourceSpan, Symbol, }; -use midenc_hir_type::Abi; use midenc_session::{DiagnosticsHandler, Session}; use rustc_hash::FxHashMap; use wasmparser::types::ComponentEntityType; use super::{ - interface_type_to_ir, translator::convert_lifted_func_ty, CanonLift, CanonLower, - CanonicalOptions, ComponentFuncIndex, ComponentIndex, ComponentInstanceIndex, - ComponentInstantiation, ComponentTypes, ComponentTypesBuilder, CoreDef, CoreExport, Export, - ExportItem, GlobalInitializer, ImportIndex, InstantiateModule, LinearComponent, - LinearComponentTranslation, LoweredIndex, ModuleInstanceIndex, ParsedRootComponent, - RuntimeImportIndex, RuntimeInstanceIndex, RuntimePostReturnIndex, RuntimeReallocIndex, - StaticModuleIndex, Trampoline, TypeDef, TypeFuncIndex, + translator::convert_lifted_func_ty, CanonLift, CanonLower, ClosedOverComponent, + ClosedOverModule, ComponentFuncIndex, ComponentIndex, ComponentInstanceIndex, + ComponentInstantiation, ComponentTypesBuilder, ComponentUpvarIndex, ModuleIndex, + ModuleInstanceIndex, ModuleUpvarIndex, ParsedComponent, StaticModuleIndex, + TypeComponentInstanceIndex, TypeDef, TypeModuleIndex, }; use crate::{ - component::{ComponentItem, LocalInitializer, StaticComponentIndex, StringEncoding}, + component::{ComponentItem, LocalInitializer, StaticComponentIndex}, error::WasmResult, - intrinsics::{ - intrinsics_conversion_result, is_miden_intrinsics_module, IntrinsicsConversionResult, - }, - miden_abi::{is_miden_abi_module, miden_abi_function_type, recover_imported_masm_function_id}, module::{ - build_ir::build_ir_module, - instance::ModuleArgument, - module_translation_state::ModuleTranslationState, + module_env::ParsedModule, types::{EntityIndex, FuncIndex}, }, - unsupported_diag, WasmTranslationConfig, + WasmTranslationConfig, }; pub mod hir2_sketch; @@ -43,142 +34,394 @@ pub struct ComponentTranslator2<'a> { /// The translation configuration config: &'a WasmTranslationConfig, - // TODO: extract into a separate struct ComponentTranslationState - /// The runtime module instances index mapped to the static module index - module_instances_source: PrimaryMap, - /// The lower imports index mapped to the runtime import index - lower_imports: FxHashMap, - /// The realloc functions used in CanonicalOptions in this component - reallocs: FxHashMap, - /// The post return functions used in CanonicalOptions in this component - post_returns: FxHashMap, + /// The list of static modules that were found during initial translation of + /// the component. + /// + /// This is used during the instantiation of these modules to ahead-of-time + /// order the arguments precisely according to what the module is defined as + /// needing which avoids the need to do string lookups or permute arguments + /// at runtime. + nested_modules: &'a PrimaryMap>, + + /// The list of static components that were found during initial translation of + /// the component. + /// + /// This is used when instantiating nested components to push a new + /// `ComponentFrame` with the `ParsedComponent`s here. + nested_components: &'a PrimaryMap>, + + result: hir2_sketch::Component, session: &'a Session, } impl<'a> ComponentTranslator2<'a> { - pub fn new(config: &'a WasmTranslationConfig, session: &'a Session) -> Self { + pub fn new( + nested_modules: &'a PrimaryMap>, + nested_components: &'a PrimaryMap>, + config: &'a WasmTranslationConfig, + session: &'a Session, + ) -> Self { + let component = hir2_sketch::Component { + name: "root".to_string(), + interfaces: vec![], + modules: vec![], + }; Self { config, session, - module_instances_source: PrimaryMap::new(), - lower_imports: FxHashMap::default(), - reallocs: FxHashMap::default(), - post_returns: FxHashMap::default(), + nested_modules, + nested_components, + result: component, } } - /// Translate the given parsed Wasm component to the Miden IR component - pub fn translate( + pub fn translate2( mut self, - parsed_root_component: ParsedRootComponent, + root_component: &'a ParsedComponent, types: &mut ComponentTypesBuilder, - diagnostics: &DiagnosticsHandler, + _diagnostics: &DiagnosticsHandler, ) -> WasmResult { - // dbg!(&parset_root_component.static_components.len()); - let mut component = hir2_sketch::Component { - name: "root".to_string(), - interfaces: vec![], - modules: vec![], - }; - let mut static_modules = Vec::new(); - // TODO: extract into a frame (new frame on `ComponentInstantiate`) - let mut components: PrimaryMap = PrimaryMap::new(); - let mut component_instances: PrimaryMap = - PrimaryMap::new(); - let mut component_funcs: PrimaryMap = - PrimaryMap::new(); - let mut core_funcs: PrimaryMap = - PrimaryMap::new(); - // TODO: move to core_funcs - let mut lowerings: PrimaryMap = PrimaryMap::new(); - let types_ref = parsed_root_component.root_component.types_ref(); - for init in parsed_root_component.root_component.initializers.iter() { - // dbg!(&init); - - match init { - LocalInitializer::Import(name, ty) => { - // dbg!(name, ty); - assert!( - matches!(ty, ComponentEntityType::Instance(_)), - "only component instances imports supported yet" - ); - let ty = - types.convert_component_entity_type(types_ref, *ty).map_err(Report::msg)?; - // self.import_types.push((name.0.to_string(), ty)); - component_instances.push(ComponentInstance::Import(ComponentInstanceImport { - name: name.0.to_string(), - ty, - })); - } - LocalInitializer::Lower( - lower @ CanonLower { - func, - lower_ty, - canonical_abi, - ref options, - }, - ) => { - // dbg!(&init); - lowerings.push(lower.clone()); - } - LocalInitializer::Lift( - lift @ CanonLift { - ty: component_func_type_id, - func: func_index, - options: ref local_canonical_options, + let mut frame = ComponentFrame::new(root_component, FxHashMap::default()); + + for init in &root_component.initializers { + self.initializer(&mut frame, types, init)?; + } + + Ok(self.result) + } + + fn initializer( + &mut self, + frame: &mut ComponentFrame<'a>, + types: &mut ComponentTypesBuilder, + init: &'a LocalInitializer<'a>, + ) -> WasmResult<()> { + // dbg!(&init); + + let types_ref = frame.translation.types_ref(); + match init { + LocalInitializer::Import(name, ty) => { + // dbg!(name, ty); + match frame.args.get(name.0) { + Some(arg) => { + frame.push_item(arg.clone()); + } + + // Not all arguments need to be provided for instantiation, + // namely the root component doesn't require + // structural type imports to be satisfied. + None => { + match ty { + ComponentEntityType::Instance(_) => { + // TODO: Create an empty component exporting functions (for each imported interface) + let ty = types + .convert_component_entity_type(types_ref, *ty) + .map_err(Report::msg)?; + // self.import_types.push((name.0.to_string(), ty)); + let ty = match ty { + TypeDef::ComponentInstance(type_component_instance_index) => { + type_component_instance_index + } + _ => panic!("expected component instance"), + }; + frame.component_instances.push(ComponentInstanceDef::Import( + ComponentInstanceImport { + name: name.0.to_string(), + ty, + }, + )); + } + // ComponentEntityType::Module(component_core_module_type_id) => todo!(), + ComponentEntityType::Func(_component_func_type_id) => { + // frame.component_funcs.push(); + panic!("unhandled component import function"); + } + // ComponentEntityType::Value(component_val_type) => todo!(), + // ComponentEntityType::Type { + // referenced, + // created, + // } => (), // do nothing + // ComponentEntityType::Component(component_type_id) => todo!(), + _ => (), + }; + } + }; + } + LocalInitializer::Lower(lower) => { + // dbg!(&init); + frame.funcs.push(CoreDef::Lower(lower.clone())); + } + LocalInitializer::Lift(lift) => { + // dbg!(&init); + frame.component_funcs.push(ComponentFuncDef::Lifted(lift.clone())); + } + LocalInitializer::Resource(..) => todo!(), + LocalInitializer::ResourceNew(..) => todo!(), + LocalInitializer::ResourceRep(..) => todo!(), + LocalInitializer::ResourceDrop(..) => todo!(), + LocalInitializer::ModuleStatic(static_module_index) => { + frame.modules.push(ModuleDef::Static(*static_module_index)); + } + LocalInitializer::ModuleInstantiate(module_idx, ref args) => { + frame.module_instances.push(ModuleInstanceDef::Instantiated { + module_idx: *module_idx, + args: args.clone(), + }); + + // TODO: use (Symbol, Symbol) as a key? + let mut import_canon_lower_args: FxHashMap = + FxHashMap::default(); + match &frame.modules[*module_idx] { + ModuleDef::Static(static_module_index) => { + let parsed_module = &self.nested_modules[*static_module_index]; + let mut module = Module { + name: parsed_module.module.name(), + functions: vec![], + }; + for module_arg in args { + let arg_module_name = module_arg.0; + let module_ident = + Ident::new(Symbol::intern(*arg_module_name), SourceSpan::default()); + let arg_module = &frame.module_instances[*module_arg.1]; + match arg_module { + ModuleInstanceDef::Instantiated { + module_idx: _, + args: _, + } => todo!(), + ModuleInstanceDef::Synthetic(hash_map) => { + // module with CanonLower synthetic functions + for (func_name, entity) in hash_map.iter() { + let func_id = entity.unwrap_func(); + let canon_lower = frame.funcs[func_id].unwrap_canon_lower(); + let func_name_ident = Ident::new( + Symbol::intern(*func_name), + SourceSpan::default(), + ); + // TODO: handle error + let type_func_idx = types + .convert_component_func_type( + types_ref, + canon_lower.lower_ty, + ) + .unwrap(); + + let component_types = types.resources_mut_and_types().1; + let func_ty = + convert_lifted_func_ty(&type_func_idx, component_types); + let signature = Signature { + params: func_ty + .params + .into_iter() + .map(AbiParam::new) + .collect(), + results: func_ty + .results + .into_iter() + .map(AbiParam::new) + .collect(), + cc: CallConv::CanonLower, + linkage: Linkage::External, + }; + + let func_id = FunctionIdent { + module: module_ident, + function: func_name_ident, + }; + import_canon_lower_args.insert(func_id, signature); + } + } + } + } + + // TODO: the part below happens inside `build_ir` while translating the + // core module with `import_canon_lower_args` passed as a parameter. + for import in &parsed_module.module.imports { + // find the CanonLower function signature in the instantiation args for + // every core module function import + let internal_import_func_name = match import.index { + EntityIndex::Function(func_index) => { + parsed_module.module.func_name(func_index) + } + _ => panic!( + "only function import supported in Wasm core modules yet, got \ + {:?}", + import.index + ), + }; + let import_func_id = FunctionIdent { + module: Ident::new( + Symbol::intern(&import.module), + SourceSpan::default(), + ), + function: Ident::new( + Symbol::intern(&import.field), + SourceSpan::default(), + ), + }; + // TODO: handle error + let import_canon_lower_func_sig = + &import_canon_lower_args.remove(&import_func_id).unwrap(); + + let internal_func_id = FunctionIdent { + module: module.name, + function: Ident::new( + internal_import_func_name, + SourceSpan::default(), + ), + }; + let function = hir2_sketch::Function { + id: internal_func_id, + signature: import_canon_lower_func_sig.clone(), + }; + // TODO: generate synthetic function body with a call to imported + // function + module.functions.push(function); + } + + self.result.modules.push(module); + } + ModuleDef::Import(_type_module_index) => { + panic!("Module import instantiation is not supported yet") + } + }; + } + LocalInitializer::ModuleSynthetic(hash_map) => { + frame.module_instances.push(ModuleInstanceDef::Synthetic(hash_map)); + } + LocalInitializer::ComponentStatic(idx, ref vars) => { + // dbg!(&init); + // let comp = &parsed_root_component.static_components[*idx]; + // dbg!(&comp.initializers); + // dbg!(&comp.exports); + frame.components.push(ComponentDef { + index: *idx, + closure: ComponentClosure { + modules: vars + .modules + .iter() + .map(|(_, m)| frame.closed_over_module(m)) + .collect(), + components: vars + .components + .iter() + .map(|(_, m)| frame.closed_over_component(m)) + .collect(), }, - ) => { - // dbg!(&init); - component_funcs.push(ComponentFuncDef::Lifted(lift.clone())); - } - LocalInitializer::Resource(aliasable_resource_id, wasm_type, func_index) => todo!(), - LocalInitializer::ResourceNew(aliasable_resource_id, signature_index) => todo!(), - LocalInitializer::ResourceRep(aliasable_resource_id, signature_index) => todo!(), - LocalInitializer::ResourceDrop(aliasable_resource_id, signature_index) => todo!(), - LocalInitializer::ModuleStatic(static_module_index) => { - let parsed_module = &parsed_root_component.static_modules[*static_module_index]; - let module = Module { - name: parsed_module.module.name(), - functions: vec![], - }; - static_modules.push(module); + }); + } + LocalInitializer::ComponentInstantiate( + instance @ ComponentInstantiation { + component, + ref args, + ty: _, + }, + ) => { + // dbg!(&init); + let component: &ComponentDef = &frame.components[*component]; + + let translation = &self.nested_components[component.index]; + let mut new_frame = ComponentFrame::new( + translation, + args.iter() + .map(|(name, item)| Ok((*name, frame.item(*item, types)?))) + .collect::>()?, + ); + for init in &translation.initializers { + self.initializer(&mut new_frame, types, init)?; } - LocalInitializer::ModuleInstantiate(module_idx, ref args) => { - // TODO: assert that module imports are satisfied by the args (every import has - // an argument of the correct type) + let instance_idx = frame.component_instances.push( + ComponentInstanceDef::Instantiated(InstantiatedComponent { + component_inst: instance.clone(), + }), + ); + frame.frames.insert(instance_idx, new_frame); + } + LocalInitializer::ComponentSynthetic(_hash_map) => { + dbg!(&init); + } + LocalInitializer::AliasExportFunc(module_instance_index, name) => { + // dbg!(&init); + frame.funcs.push(CoreDef::Export(*module_instance_index, name)); + } + LocalInitializer::AliasExportTable(..) => todo!(), + LocalInitializer::AliasExportGlobal(..) => todo!(), + LocalInitializer::AliasExportMemory(..) => { + // dbg!(&init); + } + LocalInitializer::AliasComponentExport(component_instance_index, name) => { + match &frame.component_instances[*component_instance_index] { + // Aliasing an export from an imported instance means that + // we're extending the `ImportPath` by one name, represented + // with the clone + push here. Afterwards an appropriate + // item is then pushed in the relevant index space. + ComponentInstanceDef::Import(import) => { + dbg!(&import); + // let path = path.push(*name); + let def = ComponentItemDef::from_import( + name, + types[import.ty].exports[*name], + *component_instance_index, + ); + frame.push_item(def); + } - // we don't support multiple instances of the same module, so it's safe to - // remove the module - component.modules.push(static_modules.remove(module_idx.as_u32() as usize)); + // Given a component instance which was either created + // through instantiation of a component or through a + // synthetic renaming of items we just schlep around the + // definitions of various items here. + // ComponentInstanceDef::Items(map) => frame.push_item(map[*name].clone()), + ComponentInstanceDef::Instantiated(inst) => { + dbg!(&inst); + } + ComponentInstanceDef::Export => todo!(), } - LocalInitializer::ModuleSynthetic(hash_map) => { - // dbg!(&hash_map); - let mut module_name: Option = None; - let functions_ids: Vec<(Ident, Signature)> = hash_map - .iter() - .map(|(k, v)| { - let func_id = v.unwrap_func(); - let canon_lower = &lowerings[func_id]; - let comp_func = &component_funcs[canon_lower.func].unwrap_import(); - let import_instance = - &component_instances[*comp_func.0].unwrap_import(); - if let Some(module_name) = &module_name { - assert_eq!( - module_name, &import_instance.name, - "unexpected functions from different import instances in one \ - synthetic core module" - ); - } else { - module_name = Some(import_instance.name.clone()); - } - let func = Ident::new(Symbol::intern(*k), SourceSpan::default()); - // TODO: handle error + } + LocalInitializer::AliasModule(_) => todo!(), + LocalInitializer::AliasComponent(_) => todo!(), + LocalInitializer::Export(name, component_item) => { + // dbg!(&init); + match component_item { + ComponentItem::Func(i) => { + frame.component_funcs.push(frame.component_funcs[*i].clone()); + return Ok(()); + } + ComponentItem::Module(_) => todo!(), + ComponentItem::Component(_) => todo!(), + ComponentItem::ComponentInstance(_) => { + // handle below + } + ComponentItem::Type(_) => return Ok(()), // do nothing + } + // FIX: ugly + assert!( + matches!(component_item, ComponentItem::ComponentInstance(_)), + "only component instances exports supported here" + ); + let interface_name = name.to_string(); + let instance = &frame.component_instances[component_item.unwrap_instance()] + .unwrap_instantiated(); + let static_component_idx = + frame.components[instance.component_inst.component].index; + let parsed_component = &self.nested_components[static_component_idx]; + // dbg!(&parsed_component.exports); + let module = + Ident::new(Symbol::intern(interface_name.clone()), SourceSpan::default()); + dbg!(&parsed_component.exports); + let functions = parsed_component + .exports + .iter() + .flat_map(|(name, item)| { + if let ComponentItem::Func(f) = item { + // dbg!(&component_funcs, f, name); + dbg!(&parsed_component.initializers); + let component_instance_idx = component_item.unwrap_instance(); + let nested_frame = &frame.frames[&component_instance_idx]; + dbg!(&nested_frame.component_funcs); + dbg!(&f); + let canon_lift = nested_frame.component_funcs[*f].unwrap_canon_lift(); let type_func_idx = types - .convert_component_func_type( - parsed_root_component.root_component.types_ref(), - canon_lower.lower_ty, - ) + .convert_component_func_type(types_ref, canon_lift.ty) .unwrap(); let component_types = types.resources_mut_and_types().1; @@ -186,165 +429,64 @@ impl<'a> ComponentTranslator2<'a> { let signature = Signature { params: func_ty.params.into_iter().map(AbiParam::new).collect(), results: func_ty.results.into_iter().map(AbiParam::new).collect(), - cc: CallConv::CanonLower, + cc: CallConv::CanonLift, linkage: Linkage::External, }; - (func, signature) - }) - .collect(); - let module_id = - Ident::new(Symbol::intern(module_name.unwrap()), SourceSpan::default()); - let functions = functions_ids - .into_iter() - .map(|(function, signature)| { - let id = FunctionIdent { - module: module_id, - function, + + let function_id = FunctionIdent { + module, + function: Ident::new( + Symbol::intern(name.to_string()), + SourceSpan::default(), + ), }; - // TODO: generate lowering - hir2_sketch::Function { id, signature } - }) - .collect(); - let module = Module { - name: module_id, - functions, - }; - component.modules.push(module); - } - LocalInitializer::ComponentStatic(idx, ref closed_over_vars) => { - // dbg!(&init); - let comp = &parsed_root_component.static_components[*idx]; - // dbg!(&comp.initializers); - // dbg!(&comp.exports); - components.push((idx, closed_over_vars)); - } - LocalInitializer::ComponentInstantiate( - instance @ ComponentInstantiation { - component: component_index, - ref args, - ty: component_instance_type_id, - }, - ) => { - // dbg!(&init); - component_instances.push(ComponentInstance::Instantiated(instance.clone())); - } - LocalInitializer::ComponentSynthetic(hash_map) => { - dbg!(&init); - } - LocalInitializer::AliasExportFunc(module_instance_index, name) => { - // dbg!(&init); - core_funcs.push((*module_instance_index, name.to_string())); - // let module = component.modules[module_instance_index] - } - LocalInitializer::AliasExportTable(module_instance_index, _) => todo!(), - LocalInitializer::AliasExportGlobal(module_instance_index, _) => todo!(), - LocalInitializer::AliasExportMemory(module_instance_index, _) => { - // dbg!(&init); - } - LocalInitializer::AliasComponentExport(component_instance_index, name) => { - component_funcs.push(ComponentFuncDef::Import( - *component_instance_index, - name.to_string(), - )); - } - LocalInitializer::AliasModule(closed_over_module) => todo!(), - LocalInitializer::AliasComponent(closed_over_component) => todo!(), - LocalInitializer::Export(name, component_item) => { - // dbg!(&init); - assert!( - matches!(component_item, ComponentItem::ComponentInstance(_)), - "only component instances exports supported yet" - ); - let interface_name = name.to_string(); - let instance = &component_instances[component_item.unwrap_instance()] - .unwrap_instantiated(); - let static_component_idx = components[instance.component].0; - let parsed_component = - &parsed_root_component.static_components[*static_component_idx]; - // dbg!(&parsed_component.exports); - let module = - Ident::new(Symbol::intern(interface_name.clone()), SourceSpan::default()); - let functions = parsed_component - .exports - .iter() - .flat_map(|(name, item)| { - if let ComponentItem::Func(f) = item { - // dbg!(&component_funcs, f, name); - dbg!(&parsed_component.initializers); - let canon_lift = component_funcs[*f].unwrap_canon_lift(); - // TODO: extract into a function - // TODO: handle error - let type_func_idx = types - .convert_component_func_type( - parsed_root_component.root_component.types_ref(), - canon_lift.ty, - ) - .unwrap(); - - let component_types = types.resources_mut_and_types().1; - let func_ty = - convert_lifted_func_ty(&type_func_idx, component_types); - let signature = Signature { - params: func_ty.params.into_iter().map(AbiParam::new).collect(), - results: func_ty - .results - .into_iter() - .map(AbiParam::new) - .collect(), - cc: CallConv::CanonLower, - linkage: Linkage::External, - }; - let signature = Signature::new(vec![], vec![]); - - let function_id = FunctionIdent { - module, - function: Ident::new( - Symbol::intern(name.to_string()), - SourceSpan::default(), - ), - }; - let function = hir2_sketch::Function { - id: function_id, - signature, - }; - vec![function] - } else { - // we're only interested in exported functions - vec![] - } - }) - .collect(); - let interface = Interface { - name: interface_name, - functions, - }; - component.interfaces.push(interface); - component_instances.push(ComponentInstance::Export); - // TODO: generate synth module with liftings - } + // TODO: generate body with a call to the core module export + let function = hir2_sketch::Function { + id: function_id, + signature, + }; + vec![function] + } else { + // we're only interested in exported functions + vec![] + } + }) + .collect(); + let interface = Interface { + name: interface_name, + functions, + }; + self.result.interfaces.push(interface); + frame.component_instances.push(ComponentInstanceDef::Export); } } - - Ok(component) + Ok(()) } } -enum ComponentInstance<'a> { +#[derive(Clone, Debug)] +struct InstantiatedComponent<'a> { + // TODO: inline + component_inst: ComponentInstantiation<'a>, +} + +#[derive(Clone, Debug)] +enum ComponentInstanceDef<'a> { Import(ComponentInstanceImport), - Instantiated(ComponentInstantiation<'a>), + Instantiated(InstantiatedComponent<'a>), Export, } -impl<'a> ComponentInstance<'a> { +impl<'a> ComponentInstanceDef<'a> { fn unwrap_import(&self) -> ComponentInstanceImport { match self { - ComponentInstance::Import(import) => import.clone(), + ComponentInstanceDef::Import(import) => import.clone(), _ => panic!("expected import"), } } - fn unwrap_instantiated(&self) -> ComponentInstantiation { + fn unwrap_instantiated(&self) -> &InstantiatedComponent { match self { - ComponentInstance::Instantiated(instantiated) => instantiated.clone(), + ComponentInstanceDef::Instantiated(i) => i, _ => panic!("expected instantiated"), } } @@ -353,19 +495,20 @@ impl<'a> ComponentInstance<'a> { #[derive(Debug, Clone)] struct ComponentInstanceImport { name: String, - ty: TypeDef, + // ty: TypeDef, + ty: TypeComponentInstanceIndex, } #[derive(Clone, Debug)] -enum ComponentFuncDef { +enum ComponentFuncDef<'a> { /// A host-imported component function. - Import(ComponentInstanceIndex, String), + Import(ComponentInstanceIndex, &'a str), /// A core wasm function was lifted into a component function. Lifted(CanonLift), } -impl ComponentFuncDef { - fn unwrap_import(&self) -> (&ComponentInstanceIndex, &String) { +impl<'a> ComponentFuncDef<'a> { + fn unwrap_import(&self) -> (&ComponentInstanceIndex, &'a str) { match self { ComponentFuncDef::Import(idx, name) => (idx, name), _ => panic!("expected import"), @@ -375,7 +518,208 @@ impl ComponentFuncDef { fn unwrap_canon_lift(&self) -> &CanonLift { match self { ComponentFuncDef::Lifted(lift) => lift, - _ => panic!("expected lift"), + _ => panic!("expected lift, got {:?}", self), + } + } +} + +#[derive(Clone)] +enum ModuleDef { + /// A core wasm module statically defined within the original component. + /// + /// The `StaticModuleIndex` indexes into the `static_modules` map in the + /// `Inliner`. + Static(StaticModuleIndex), + + /// A core wasm module that was imported from the host. + Import(TypeModuleIndex), +} + +/// "Closure state" for a component which is resolved from the `ClosedOverVars` +/// state that was calculated during translation. +#[derive(Default, Clone)] +struct ComponentClosure { + modules: PrimaryMap, + components: PrimaryMap, +} + +#[derive(Clone)] +struct ComponentDef { + index: StaticComponentIndex, + closure: ComponentClosure, +} + +/// Definition of a core wasm item and where it can come from within a +/// component. +#[derive(Debug, Clone)] +pub enum CoreDef<'a> { + /// This item refers to an export of a previously instantiated core wasm + /// instance. + Export(ModuleInstanceIndex, &'a str), + Lower(CanonLower), +} + +impl<'a> CoreDef<'a> { + pub fn unwrap_canon_lower(&self) -> &CanonLower { + match self { + CoreDef::Lower(lower) => lower, + _ => panic!("expected lower"), + } + } +} + +enum ModuleInstanceDef<'a> { + /// A core wasm module instance was created through the instantiation of a + /// module. + Instantiated { + module_idx: ModuleIndex, + args: FxHashMap<&'a str, ModuleInstanceIndex>, + }, + + /// A "synthetic" core wasm module which is just a bag of named indices. + Synthetic(&'a FxHashMap<&'a str, EntityIndex>), +} + +/// Representation of all items which can be defined within a component. +/// +/// This is the "value" of an item defined within a component and is used to +/// represent both imports and exports. +#[derive(Clone)] +enum ComponentItemDef<'a> { + Component(ComponentDef), + Instance(ComponentInstanceDef<'a>), + Func(ComponentFuncDef<'a>), + Module(ModuleDef), + Type(TypeDef), +} + +impl<'a> ComponentItemDef<'a> { + fn from_import( + name: &'a str, + ty: TypeDef, + component_instance_idx: ComponentInstanceIndex, + ) -> ComponentItemDef<'a> { + let item = match ty { + TypeDef::Module(ty) => ComponentItemDef::Module(ModuleDef::Import(ty)), + TypeDef::ComponentInstance(ty) => { + ComponentItemDef::Instance(ComponentInstanceDef::Import(ComponentInstanceImport { + name: name.to_string(), + ty, + })) + } + TypeDef::ComponentFunc(_ty) => { + ComponentItemDef::Func(ComponentFuncDef::Import(component_instance_idx, name)) + } + TypeDef::Component(_ty) => panic!("root-level component imports are not supported"), + TypeDef::Interface(_) | TypeDef::Resource(_) => ComponentItemDef::Type(ty), + }; + item + } +} + +struct ComponentFrame<'a> { + // TODO: can we get away without the whole ParsedComponent but only ComponentTypes*? + /// The component being instantiated. + translation: &'a ParsedComponent<'a>, + + /// The "closure arguments" to this component, or otherwise the maps indexed + /// by `ModuleUpvarIndex` and `ComponentUpvarIndex`. This is created when + /// a component is created and stored as part of a component's state during + /// inlining. + closure: ComponentClosure, + + /// The arguments to the creation of this component. + /// + /// At the root level these are all imports from the host and between + /// components this otherwise tracks how all the arguments are defined. + args: FxHashMap<&'a str, ComponentItemDef<'a>>, + + // core wasm index spaces + funcs: PrimaryMap>, + // memories: PrimaryMap>, + // tables: PrimaryMap>, + // globals: PrimaryMap>, + modules: PrimaryMap, + + // component model index spaces + component_funcs: PrimaryMap>, + module_instances: PrimaryMap>, + component_instances: PrimaryMap>, + frames: FxHashMap>, + components: PrimaryMap, +} + +impl<'a> ComponentFrame<'a> { + fn new( + translation: &'a ParsedComponent<'a>, + args: FxHashMap<&'a str, ComponentItemDef<'a>>, + ) -> Self { + Self { + // initializers: translation.initializers.iter(), + translation, + funcs: PrimaryMap::new(), + component_funcs: PrimaryMap::new(), + component_instances: PrimaryMap::new(), + components: PrimaryMap::new(), + modules: PrimaryMap::new(), + closure: Default::default(), + module_instances: Default::default(), + args, + frames: Default::default(), + } + } + + fn closed_over_module(&self, index: &ClosedOverModule) -> ModuleDef { + match *index { + ClosedOverModule::Local(i) => self.modules[i].clone(), + ClosedOverModule::Upvar(i) => self.closure.modules[i].clone(), + } + } + + fn closed_over_component(&self, index: &ClosedOverComponent) -> ComponentDef { + match *index { + ClosedOverComponent::Local(i) => self.components[i].clone(), + ClosedOverComponent::Upvar(i) => self.closure.components[i].clone(), + } + } + + fn item( + &self, + index: ComponentItem, + types: &mut ComponentTypesBuilder, + ) -> WasmResult> { + Ok(match index { + ComponentItem::Func(i) => ComponentItemDef::Func(self.component_funcs[i].clone()), + ComponentItem::Component(i) => ComponentItemDef::Component(self.components[i].clone()), + ComponentItem::ComponentInstance(i) => { + ComponentItemDef::Instance(self.component_instances[i].clone()) + } + ComponentItem::Module(i) => ComponentItemDef::Module(self.modules[i].clone()), + ComponentItem::Type(t) => { + let types_ref = self.translation.types_ref(); + // TODO: handle error + ComponentItemDef::Type(types.convert_type(types_ref, t).unwrap()) + } + }) + } + + /// Pushes the component `item` definition provided into the appropriate + /// index space within this component. + fn push_item(&mut self, item: ComponentItemDef<'a>) { + match item { + ComponentItemDef::Func(i) => { + self.component_funcs.push(i); + } + ComponentItemDef::Module(i) => { + self.modules.push(i); + } + ComponentItemDef::Component(i) => { + self.components.push(i); + } + ComponentItemDef::Instance(i) => { + self.component_instances.push(i); + } + ComponentItemDef::Type(_ty) => {} } } } diff --git a/frontend-wasm/src/component/types/mod.rs b/frontend-wasm/src/component/types/mod.rs index 58b03c5a8..3485f1ed9 100644 --- a/frontend-wasm/src/component/types/mod.rs +++ b/frontend-wasm/src/component/types/mod.rs @@ -252,7 +252,7 @@ impl ComponentItem { pub(crate) fn unwrap_instance(&self) -> ComponentInstanceIndex { match self { ComponentItem::ComponentInstance(i) => *i, - _ => panic!("not a component instance"), + _ => panic!("expected a component instance, got {:?}", self), } } } diff --git a/tests/integration/expected/rust_sdk/hir2_sketch.hir b/tests/integration/expected/rust_sdk/hir2_sketch.hir deleted file mode 100644 index fa6be144d..000000000 --- a/tests/integration/expected/rust_sdk/hir2_sketch.hir +++ /dev/null @@ -1,34 +0,0 @@ -(component root - ;; Interfaces - (interface miden:basic-wallet/basic-wallet@1.0.0 - (func (#miden:basic-wallet/basic-wallet@1.0.0 #receive-asset ) - (func (#miden:basic-wallet/basic-wallet@1.0.0 #send-asset ) - ) - (interface miden:basic-wallet/aux@1.0.0 - (func (#miden:basic-wallet/aux@1.0.0 #test-felt-intrinsics ) - (func (#miden:basic-wallet/aux@1.0.0 #test-stdlib ) - (func (#miden:basic-wallet/aux@1.0.0 #process-list-felt ) - (func (#miden:basic-wallet/aux@1.0.0 #process-core-asset ) - ) - - ;; Modules - (module #miden:core-import/intrinsics-felt@1.0.0 - (func (#miden:core-import/intrinsics-felt@1.0.0 #add (cc lower) (param felt) (param felt) (result felt)) - ) - (module #miden:core-import/stdlib-crypto-hashes-blake3@1.0.0 - (func (#miden:core-import/stdlib-crypto-hashes-blake3@1.0.0 #hash-one-to-one (cc lower) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32)) - ) - (module #miden:core-import/intrinsics-mem@1.0.0 - (func (#miden:core-import/intrinsics-mem@1.0.0 #heap-base (cc lower) (result i32)) - ) - (module #miden:core-import/account@1.0.0 - (func (#miden:core-import/account@1.0.0 #add-asset (cc lower) (param felt) (param felt) (param felt) (param felt) (param i32)) - (func (#miden:core-import/account@1.0.0 #remove-asset (cc lower) (param felt) (param felt) (param felt) (param felt) (param i32)) - ) - (module #miden:core-import/tx@1.0.0 - (func (#miden:core-import/tx@1.0.0 #create-note (cc lower) (param felt) (param felt) (param felt) (param felt) (param felt) (param felt) (param felt) (param felt) (param felt) (param felt) (result felt)) - ) - (module #basic_wallet - - ) -) diff --git a/tests/integration/expected/rust_sdk/hir2_sketch_multi_interface.hir b/tests/integration/expected/rust_sdk/hir2_sketch_multi_interface.hir new file mode 100644 index 000000000..2e0da1f0d --- /dev/null +++ b/tests/integration/expected/rust_sdk/hir2_sketch_multi_interface.hir @@ -0,0 +1,23 @@ +(component root + ;; Interfaces + (interface miden:basic-wallet/basic-wallet@1.0.0 + (func (#miden:basic-wallet/basic-wallet@1.0.0 #receive-asset (cc lift) (param (struct (struct (struct (struct felt) (struct felt) (struct felt) (struct felt)))))) + (func (#miden:basic-wallet/basic-wallet@1.0.0 #send-asset (cc lift) (param (struct (struct (struct (struct felt) (struct felt) (struct felt) (struct felt))))) (param (struct (struct felt))) (param (struct (struct felt))) (param (struct (struct (struct (struct felt) (struct felt) (struct felt) (struct felt)))))) + ) + (interface miden:basic-wallet/aux@1.0.0 + (func (#miden:basic-wallet/aux@1.0.0 #test-felt-intrinsics (cc lift) (param (struct felt)) (param (struct felt)) (result (struct felt))) + (func (#miden:basic-wallet/aux@1.0.0 #test-stdlib (cc lift) (param (list u8)) (result (list u8))) + (func (#miden:basic-wallet/aux@1.0.0 #process-list-felt (cc lift) (param (list (struct felt))) (result (list (struct felt)))) + (func (#miden:basic-wallet/aux@1.0.0 #process-core-asset (cc lift) (param (struct (struct (struct (struct felt) (struct felt) (struct felt) (struct felt))))) (result (struct (struct (struct (struct felt) (struct felt) (struct felt) (struct felt)))))) + ) + + ;; Modules + (module #basic_wallet + (func (#basic_wallet #miden_stdlib_sys::intrinsics::felt::extern_add (cc lower) (param felt) (param felt) (result felt)) + (func (#basic_wallet #miden_stdlib_sys::stdlib::crypto::hashes::extern_blake3_hash_1to1 (cc lower) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32)) + (func (#basic_wallet #miden_sdk_alloc::heap_base (cc lower) (result i32)) + (func (#basic_wallet #miden_base_sys::bindings::account::extern_account_add_asset (cc lower) (param felt) (param felt) (param felt) (param felt) (param i32)) + (func (#basic_wallet #miden_base_sys::bindings::account::extern_account_remove_asset (cc lower) (param felt) (param felt) (param felt) (param felt) (param i32)) + (func (#basic_wallet #miden_base_sys::bindings::tx::extern_tx_create_note (cc lower) (param felt) (param felt) (param felt) (param felt) (param felt) (param felt) (param felt) (param felt) (param felt) (param felt) (result felt)) + ) +) diff --git a/tests/integration/expected/rust_sdk/hir2_sketch.wat b/tests/integration/expected/rust_sdk/hir2_sketch_multi_interface.wat similarity index 100% rename from tests/integration/expected/rust_sdk/hir2_sketch.wat rename to tests/integration/expected/rust_sdk/hir2_sketch_multi_interface.wat diff --git a/tests/integration/expected/rust_sdk/hir2_sketch_single_interface.hir b/tests/integration/expected/rust_sdk/hir2_sketch_single_interface.hir new file mode 100644 index 000000000..ef5e6068e --- /dev/null +++ b/tests/integration/expected/rust_sdk/hir2_sketch_single_interface.hir @@ -0,0 +1,13 @@ +(component root + ;; Interfaces + (interface miden:cross-ctx-account/foo@1.0.0 + (func (#miden:cross-ctx-account/foo@1.0.0 #process-felt (cc lift) (param (struct felt)) (result (struct felt))) + ) + + ;; Modules + (module #cross_ctx_account + (func (#cross_ctx_account #miden_stdlib_sys::intrinsics::felt::extern_from_u32 (cc lower) (param u32) (result felt)) + (func (#cross_ctx_account #miden_stdlib_sys::intrinsics::felt::extern_add (cc lower) (param felt) (param felt) (result felt)) + (func (#cross_ctx_account #miden_sdk_alloc::heap_base (cc lower) (result i32)) + ) +) diff --git a/tests/integration/expected/rust_sdk/hir2_sketch_single_interface.wat b/tests/integration/expected/rust_sdk/hir2_sketch_single_interface.wat new file mode 100644 index 000000000..c46fcf3b0 --- /dev/null +++ b/tests/integration/expected/rust_sdk/hir2_sketch_single_interface.wat @@ -0,0 +1,249 @@ +(component + (type (;0;) + (instance + (type (;0;) (record (field "inner" float32))) + (export (;1;) "felt" (type (eq 0))) + ) + ) + (import "miden:base/core-types@1.0.0" (instance (;0;) (type 0))) + (type (;1;) + (instance + (type (;0;) (func (result s32))) + (export (;0;) "heap-base" (func (type 0))) + ) + ) + (import "miden:core-import/intrinsics-mem@1.0.0" (instance (;1;) (type 1))) + (type (;2;) + (instance + (type (;0;) (func (param "a" float32) (param "b" float32) (result float32))) + (export (;0;) "add" (func (type 0))) + (type (;1;) (func (param "a" u32) (result float32))) + (export (;1;) "from-u32" (func (type 1))) + ) + ) + (import "miden:core-import/intrinsics-felt@1.0.0" (instance (;2;) (type 2))) + (core module (;0;) + (type (;0;) (func (param i32) (result f32))) + (type (;1;) (func (param f32 f32) (result f32))) + (type (;2;) (func (result i32))) + (type (;3;) (func)) + (type (;4;) (func (param i32 i32) (result i32))) + (type (;5;) (func (param i32 i32 i32 i32) (result i32))) + (type (;6;) (func (param f32) (result f32))) + (type (;7;) (func (param i32 i32 i32) (result i32))) + (import "miden:core-import/intrinsics-felt@1.0.0" "from-u32" (func $miden_stdlib_sys::intrinsics::felt::extern_from_u32 (;0;) (type 0))) + (import "miden:core-import/intrinsics-felt@1.0.0" "add" (func $miden_stdlib_sys::intrinsics::felt::extern_add (;1;) (type 1))) + (import "miden:core-import/intrinsics-mem@1.0.0" "heap-base" (func $miden_sdk_alloc::heap_base (;2;) (type 2))) + (func $__wasm_call_ctors (;3;) (type 3)) + (func $cross_ctx_account::bindings::__link_custom_section_describing_imports (;4;) (type 3)) + (func $__rust_alloc (;5;) (type 4) (param i32 i32) (result i32) + i32.const 1048612 + local.get 1 + local.get 0 + call $::alloc + ) + (func $__rust_realloc (;6;) (type 5) (param i32 i32 i32 i32) (result i32) + block ;; label = @1 + i32.const 1048612 + local.get 2 + local.get 3 + call $::alloc + local.tee 2 + i32.eqz + br_if 0 (;@1;) + local.get 2 + local.get 0 + local.get 1 + local.get 3 + local.get 1 + local.get 3 + i32.lt_u + select + memory.copy + end + local.get 2 + ) + (func $miden:cross-ctx-account/foo@1.0.0#process-felt (;7;) (type 6) (param f32) (result f32) + call $wit_bindgen_rt::run_ctors_once + local.get 0 + i32.const 3 + call $miden_stdlib_sys::intrinsics::felt::extern_from_u32 + call $miden_stdlib_sys::intrinsics::felt::extern_add + ) + (func $cabi_realloc_wit_bindgen_0_28_0 (;8;) (type 5) (param i32 i32 i32 i32) (result i32) + local.get 0 + local.get 1 + local.get 2 + local.get 3 + call $wit_bindgen_rt::cabi_realloc + ) + (func $wit_bindgen_rt::cabi_realloc (;9;) (type 5) (param i32 i32 i32 i32) (result i32) + block ;; label = @1 + block ;; label = @2 + block ;; label = @3 + local.get 1 + br_if 0 (;@3;) + local.get 3 + i32.eqz + br_if 2 (;@1;) + i32.const 0 + i32.load8_u offset=1048616 + drop + local.get 3 + local.get 2 + call $__rust_alloc + local.set 2 + br 1 (;@2;) + end + local.get 0 + local.get 1 + local.get 2 + local.get 3 + call $__rust_realloc + local.set 2 + end + local.get 2 + br_if 0 (;@1;) + unreachable + end + local.get 2 + ) + (func $wit_bindgen_rt::run_ctors_once (;10;) (type 3) + block ;; label = @1 + i32.const 0 + i32.load8_u offset=1048617 + br_if 0 (;@1;) + call $__wasm_call_ctors + i32.const 0 + i32.const 1 + i32.store8 offset=1048617 + end + ) + (func $::alloc (;11;) (type 7) (param i32 i32 i32) (result i32) + (local i32 i32) + block ;; label = @1 + local.get 1 + i32.const 32 + local.get 1 + i32.const 32 + i32.gt_u + select + local.tee 1 + i32.popcnt + i32.const 1 + i32.ne + br_if 0 (;@1;) + i32.const -2147483648 + local.get 1 + i32.sub + local.get 2 + i32.lt_u + br_if 0 (;@1;) + i32.const 0 + local.set 3 + local.get 1 + local.get 2 + i32.add + i32.const -1 + i32.add + i32.const 0 + local.get 1 + i32.sub + i32.and + local.set 2 + block ;; label = @2 + local.get 0 + i32.load + br_if 0 (;@2;) + local.get 0 + call $miden_sdk_alloc::heap_base + memory.size + i32.const 16 + i32.shl + i32.add + i32.store + end + block ;; label = @2 + i32.const 268435456 + local.get 0 + i32.load + local.tee 4 + i32.sub + local.get 2 + i32.lt_u + br_if 0 (;@2;) + local.get 0 + local.get 4 + local.get 2 + i32.add + i32.store + local.get 4 + local.get 1 + i32.add + local.set 3 + end + local.get 3 + return + end + unreachable + ) + (func $cabi_realloc (;12;) (type 5) (param i32 i32 i32 i32) (result i32) + local.get 0 + local.get 1 + local.get 2 + local.get 3 + call $cabi_realloc_wit_bindgen_0_28_0 + ) + (table (;0;) 3 3 funcref) + (memory (;0;) 17) + (global $__stack_pointer (;0;) (mut i32) i32.const 1048576) + (export "memory" (memory 0)) + (export "miden:cross-ctx-account/foo@1.0.0#process-felt" (func $miden:cross-ctx-account/foo@1.0.0#process-felt)) + (export "cabi_realloc_wit_bindgen_0_28_0" (func $cabi_realloc_wit_bindgen_0_28_0)) + (export "cabi_realloc" (func $cabi_realloc)) + (elem (;0;) (i32.const 1) func $cross_ctx_account::bindings::__link_custom_section_describing_imports $cabi_realloc) + (data $.rodata (;0;) (i32.const 1048576) "\01\00\00\00\01\00\00\00\01\00\00\00\01\00\00\00\01\00\00\00\01\00\00\00\01\00\00\00\01\00\00\00\02\00\00\00") + ) + (alias export 2 "add" (func (;0;))) + (core func (;0;) (canon lower (func 0))) + (alias export 2 "from-u32" (func (;1;))) + (core func (;1;) (canon lower (func 1))) + (core instance (;0;) + (export "add" (func 0)) + (export "from-u32" (func 1)) + ) + (alias export 1 "heap-base" (func (;2;))) + (core func (;2;) (canon lower (func 2))) + (core instance (;1;) + (export "heap-base" (func 2)) + ) + (core instance (;2;) (instantiate 0 + (with "miden:core-import/intrinsics-felt@1.0.0" (instance 0)) + (with "miden:core-import/intrinsics-mem@1.0.0" (instance 1)) + ) + ) + (alias core export 2 "memory" (core memory (;0;))) + (alias core export 2 "cabi_realloc" (core func (;3;))) + (alias export 0 "felt" (type (;3;))) + (type (;4;) (func (param "input" 3) (result 3))) + (alias core export 2 "miden:cross-ctx-account/foo@1.0.0#process-felt" (core func (;4;))) + (func (;3;) (type 4) (canon lift (core func 4))) + (alias export 0 "felt" (type (;5;))) + (component (;0;) + (type (;0;) (record (field "inner" float32))) + (import "import-type-felt" (type (;1;) (eq 0))) + (import "import-type-felt0" (type (;2;) (eq 1))) + (type (;3;) (func (param "input" 2) (result 2))) + (import "import-func-process-felt" (func (;0;) (type 3))) + (export (;4;) "felt" (type 1)) + (type (;5;) (func (param "input" 4) (result 4))) + (export (;1;) "process-felt" (func 0) (func (type 5))) + ) + (instance (;3;) (instantiate 0 + (with "import-func-process-felt" (func 3)) + (with "import-type-felt" (type 5)) + (with "import-type-felt0" (type 3)) + ) + ) + (export (;4;) "miden:cross-ctx-account/foo@1.0.0" (instance 3)) +) \ No newline at end of file diff --git a/tests/integration/src/compiler_test.rs b/tests/integration/src/compiler_test.rs index 9c4888c40..55e1a9a7e 100644 --- a/tests/integration/src/compiler_test.rs +++ b/tests/integration/src/compiler_test.rs @@ -1090,7 +1090,8 @@ impl CompilerTest { ) .expect("Failed to translate Wasm binary to IR component"); // let txt = ir_components.into_iter().map(|c| c.to_string()).collect::>().join("\n"); - expected_hir_file.assert_eq(&ir.to_string()); + let src = demangle(ir.to_string()); + expected_hir_file.assert_eq(&src); } /// Compare the compiled MASM against the expected output diff --git a/tests/integration/src/rust_masm_tests/rust_sdk.rs b/tests/integration/src/rust_masm_tests/rust_sdk.rs index c4766975b..3b5ebcb2f 100644 --- a/tests/integration/src/rust_masm_tests/rust_sdk.rs +++ b/tests/integration/src/rust_masm_tests/rust_sdk.rs @@ -219,9 +219,10 @@ fn rust_sdk_cross_ctx_note() { let trace = exec.execute(&package.unwrap_program(), &test.session); } -// Testing the new frontend's Wasm component translator producing HIR2(sketch) #[test] -fn rust_sdk_hir2_sketch() { +fn rust_sdk_hir2_sketch_multiple_interface_exports() { + // Testing the new frontend's Wasm component translator producing HIR2(sketch) + // from a Wasm component exporting two interfaces let _ = env_logger::builder().is_test(true).try_init(); let config = WasmTranslationConfig::default(); let mut test = CompilerTest::rust_source_cargo_miden( @@ -229,7 +230,23 @@ fn rust_sdk_hir2_sketch() { config, [], ); - let artifact_name = "hir2_sketch"; + let artifact_name = "hir2_sketch_multi_interface"; + test.expect_wasm(expect_file![format!("../../expected/rust_sdk/{artifact_name}.wat")]); + test.expect_ir2(expect_file![format!("../../expected/rust_sdk/{artifact_name}.hir")]); +} + +#[test] +fn rust_sdk_hir2_sketch_single_interface_export() { + // Testing the new frontend's Wasm component translator producing HIR2(sketch) + // from a Wasm component exporting one interface + let _ = env_logger::builder().is_test(true).try_init(); + let config = WasmTranslationConfig::default(); + let mut test = CompilerTest::rust_source_cargo_miden( + "../rust-apps-wasm/rust-sdk/cross-ctx-account", + config, + [], + ); + let artifact_name = "hir2_sketch_single_interface"; test.expect_wasm(expect_file![format!("../../expected/rust_sdk/{artifact_name}.wat")]); test.expect_ir2(expect_file![format!("../../expected/rust_sdk/{artifact_name}.hir")]); } From 2f036b1959ea43f85f5aae9d4ffe7aa7a44d60bd Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Fri, 10 Jan 2025 18:14:21 +0200 Subject: [PATCH 06/18] feature: add inner_function for synthetic lower/lift functions --- frontend-wasm/src/component/translator2.rs | 44 +++++++++++++++++-- .../src/component/translator2/hir2_sketch.rs | 16 ++++--- .../rust_sdk/hir2_sketch_multi_interface.hir | 24 +++++----- .../rust_sdk/hir2_sketch_single_interface.hir | 8 ++-- 4 files changed, 66 insertions(+), 26 deletions(-) diff --git a/frontend-wasm/src/component/translator2.rs b/frontend-wasm/src/component/translator2.rs index e64e7d951..5eb48ccbd 100644 --- a/frontend-wasm/src/component/translator2.rs +++ b/frontend-wasm/src/component/translator2.rs @@ -270,12 +270,11 @@ impl<'a> ComponentTranslator2<'a> { SourceSpan::default(), ), }; - let function = hir2_sketch::Function { + let function = hir2_sketch::SyntheticFunction { id: internal_func_id, signature: import_canon_lower_func_sig.clone(), + inner_function: import_func_id, }; - // TODO: generate synthetic function body with a call to imported - // function module.functions.push(function); } @@ -420,6 +419,42 @@ impl<'a> ComponentTranslator2<'a> { dbg!(&nested_frame.component_funcs); dbg!(&f); let canon_lift = nested_frame.component_funcs[*f].unwrap_canon_lift(); + let core_func_id: FunctionIdent = match &frame.funcs[canon_lift.func] { + CoreDef::Export(module_instance_index, name) => { + match &frame.module_instances[*module_instance_index] { + ModuleInstanceDef::Instantiated { module_idx, args } => { + match frame.modules[*module_idx] { + ModuleDef::Static(static_module_index) => { + let parsed_module = + &self.nested_modules[static_module_index]; + let func_idx = parsed_module.module.exports + [*name] + .unwrap_func(); + let func_name = + parsed_module.module.func_name(func_idx); + let module_ident = parsed_module.module.name(); + FunctionIdent { + module: module_ident, + function: Ident::new( + func_name, + SourceSpan::default(), + ), + } + } + ModuleDef::Import(type_module_index) => { + panic!("expected static module") + } + } + } + ModuleInstanceDef::Synthetic(hash_map) => { + panic!("expected static module") + } + } + } + CoreDef::Lower(canon_lower) => { + panic!("expected export, got {:?}", canon_lower) + } + }; let type_func_idx = types .convert_component_func_type(types_ref, canon_lift.ty) .unwrap(); @@ -441,9 +476,10 @@ impl<'a> ComponentTranslator2<'a> { ), }; // TODO: generate body with a call to the core module export - let function = hir2_sketch::Function { + let function = hir2_sketch::SyntheticFunction { id: function_id, signature, + inner_function: core_func_id, }; vec![function] } else { diff --git a/frontend-wasm/src/component/translator2/hir2_sketch.rs b/frontend-wasm/src/component/translator2/hir2_sketch.rs index 65fe9ba5d..b28c85411 100644 --- a/frontend-wasm/src/component/translator2/hir2_sketch.rs +++ b/frontend-wasm/src/component/translator2/hir2_sketch.rs @@ -3,27 +3,31 @@ use std::fmt; use midenc_hir::{formatter::PrettyPrint, FunctionIdent, Ident, Signature}; #[derive(Debug)] -pub struct Function { +pub struct SyntheticFunction { pub id: FunctionIdent, pub signature: Signature, + pub inner_function: FunctionIdent, } -impl fmt::Display for Function { +impl fmt::Display for SyntheticFunction { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.pretty_print(f) } } -impl PrettyPrint for Function { +impl PrettyPrint for SyntheticFunction { fn render(&self) -> midenc_hir::formatter::Document { use midenc_hir::formatter::*; const_text("(") - + const_text("func") + + const_text("synth_func") + const_text(" ") + display(self.id) + const_text(" ") + self.signature.render() + + const_text(" (inner ") + + self.inner_function.render() + + const_text(")") + const_text(")") } } @@ -31,7 +35,7 @@ impl PrettyPrint for Function { #[derive(Debug)] pub struct Interface { pub name: String, - pub functions: Vec, + pub functions: Vec, } impl fmt::Display for Interface { @@ -64,7 +68,7 @@ impl PrettyPrint for Interface { #[derive(Debug)] pub struct Module { pub name: Ident, - pub functions: Vec, + pub functions: Vec, } impl fmt::Display for Module { diff --git a/tests/integration/expected/rust_sdk/hir2_sketch_multi_interface.hir b/tests/integration/expected/rust_sdk/hir2_sketch_multi_interface.hir index 2e0da1f0d..1ef319ba3 100644 --- a/tests/integration/expected/rust_sdk/hir2_sketch_multi_interface.hir +++ b/tests/integration/expected/rust_sdk/hir2_sketch_multi_interface.hir @@ -1,23 +1,23 @@ (component root ;; Interfaces (interface miden:basic-wallet/basic-wallet@1.0.0 - (func (#miden:basic-wallet/basic-wallet@1.0.0 #receive-asset (cc lift) (param (struct (struct (struct (struct felt) (struct felt) (struct felt) (struct felt)))))) - (func (#miden:basic-wallet/basic-wallet@1.0.0 #send-asset (cc lift) (param (struct (struct (struct (struct felt) (struct felt) (struct felt) (struct felt))))) (param (struct (struct felt))) (param (struct (struct felt))) (param (struct (struct (struct (struct felt) (struct felt) (struct felt) (struct felt)))))) + (synth_func (#miden:basic-wallet/basic-wallet@1.0.0 #receive-asset (cc lift) (param (struct (struct (struct (struct felt) (struct felt) (struct felt) (struct felt))))) (inner (#basic_wallet #miden:basic-wallet/basic-wallet@1.0.0#receive-asset)) + (synth_func (#miden:basic-wallet/basic-wallet@1.0.0 #send-asset (cc lift) (param (struct (struct (struct (struct felt) (struct felt) (struct felt) (struct felt))))) (param (struct (struct felt))) (param (struct (struct felt))) (param (struct (struct (struct (struct felt) (struct felt) (struct felt) (struct felt))))) (inner (#basic_wallet #miden:basic-wallet/basic-wallet@1.0.0#send-asset)) ) (interface miden:basic-wallet/aux@1.0.0 - (func (#miden:basic-wallet/aux@1.0.0 #test-felt-intrinsics (cc lift) (param (struct felt)) (param (struct felt)) (result (struct felt))) - (func (#miden:basic-wallet/aux@1.0.0 #test-stdlib (cc lift) (param (list u8)) (result (list u8))) - (func (#miden:basic-wallet/aux@1.0.0 #process-list-felt (cc lift) (param (list (struct felt))) (result (list (struct felt)))) - (func (#miden:basic-wallet/aux@1.0.0 #process-core-asset (cc lift) (param (struct (struct (struct (struct felt) (struct felt) (struct felt) (struct felt))))) (result (struct (struct (struct (struct felt) (struct felt) (struct felt) (struct felt)))))) + (synth_func (#miden:basic-wallet/aux@1.0.0 #test-felt-intrinsics (cc lift) (param (struct felt)) (param (struct felt)) (result (struct felt)) (inner (#basic_wallet #miden:basic-wallet/aux@1.0.0#test-felt-intrinsics)) + (synth_func (#miden:basic-wallet/aux@1.0.0 #test-stdlib (cc lift) (param (list u8)) (result (list u8)) (inner (#basic_wallet #miden:basic-wallet/aux@1.0.0#test-stdlib)) + (synth_func (#miden:basic-wallet/aux@1.0.0 #process-list-felt (cc lift) (param (list (struct felt))) (result (list (struct felt))) (inner (#basic_wallet #miden:basic-wallet/aux@1.0.0#process-list-felt)) + (synth_func (#miden:basic-wallet/aux@1.0.0 #process-core-asset (cc lift) (param (struct (struct (struct (struct felt) (struct felt) (struct felt) (struct felt))))) (result (struct (struct (struct (struct felt) (struct felt) (struct felt) (struct felt))))) (inner (#basic_wallet #miden:basic-wallet/aux@1.0.0#process-core-asset)) ) ;; Modules (module #basic_wallet - (func (#basic_wallet #miden_stdlib_sys::intrinsics::felt::extern_add (cc lower) (param felt) (param felt) (result felt)) - (func (#basic_wallet #miden_stdlib_sys::stdlib::crypto::hashes::extern_blake3_hash_1to1 (cc lower) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32)) - (func (#basic_wallet #miden_sdk_alloc::heap_base (cc lower) (result i32)) - (func (#basic_wallet #miden_base_sys::bindings::account::extern_account_add_asset (cc lower) (param felt) (param felt) (param felt) (param felt) (param i32)) - (func (#basic_wallet #miden_base_sys::bindings::account::extern_account_remove_asset (cc lower) (param felt) (param felt) (param felt) (param felt) (param i32)) - (func (#basic_wallet #miden_base_sys::bindings::tx::extern_tx_create_note (cc lower) (param felt) (param felt) (param felt) (param felt) (param felt) (param felt) (param felt) (param felt) (param felt) (param felt) (result felt)) + (synth_func (#basic_wallet #miden_stdlib_sys::intrinsics::felt::extern_add (cc lower) (param felt) (param felt) (result felt) (inner (#miden:core-import/intrinsics-felt@1.0.0 #add)) + (synth_func (#basic_wallet #miden_stdlib_sys::stdlib::crypto::hashes::extern_blake3_hash_1to1 (cc lower) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (inner (#miden:core-import/stdlib-crypto-hashes-blake3@1.0.0 #hash-one-to-one)) + (synth_func (#basic_wallet #miden_sdk_alloc::heap_base (cc lower) (result i32) (inner (#miden:core-import/intrinsics-mem@1.0.0 #heap-base)) + (synth_func (#basic_wallet #miden_base_sys::bindings::account::extern_account_add_asset (cc lower) (param felt) (param felt) (param felt) (param felt) (param i32) (inner (#miden:core-import/account@1.0.0 #add-asset)) + (synth_func (#basic_wallet #miden_base_sys::bindings::account::extern_account_remove_asset (cc lower) (param felt) (param felt) (param felt) (param felt) (param i32) (inner (#miden:core-import/account@1.0.0 #remove-asset)) + (synth_func (#basic_wallet #miden_base_sys::bindings::tx::extern_tx_create_note (cc lower) (param felt) (param felt) (param felt) (param felt) (param felt) (param felt) (param felt) (param felt) (param felt) (param felt) (result felt) (inner (#miden:core-import/tx@1.0.0 #create-note)) ) ) diff --git a/tests/integration/expected/rust_sdk/hir2_sketch_single_interface.hir b/tests/integration/expected/rust_sdk/hir2_sketch_single_interface.hir index ef5e6068e..f3123b378 100644 --- a/tests/integration/expected/rust_sdk/hir2_sketch_single_interface.hir +++ b/tests/integration/expected/rust_sdk/hir2_sketch_single_interface.hir @@ -1,13 +1,13 @@ (component root ;; Interfaces (interface miden:cross-ctx-account/foo@1.0.0 - (func (#miden:cross-ctx-account/foo@1.0.0 #process-felt (cc lift) (param (struct felt)) (result (struct felt))) + (synth_func (#miden:cross-ctx-account/foo@1.0.0 #process-felt (cc lift) (param (struct felt)) (result (struct felt)) (inner (#cross_ctx_account #miden:cross-ctx-account/foo@1.0.0#process-felt)) ) ;; Modules (module #cross_ctx_account - (func (#cross_ctx_account #miden_stdlib_sys::intrinsics::felt::extern_from_u32 (cc lower) (param u32) (result felt)) - (func (#cross_ctx_account #miden_stdlib_sys::intrinsics::felt::extern_add (cc lower) (param felt) (param felt) (result felt)) - (func (#cross_ctx_account #miden_sdk_alloc::heap_base (cc lower) (result i32)) + (synth_func (#cross_ctx_account #miden_stdlib_sys::intrinsics::felt::extern_from_u32 (cc lower) (param u32) (result felt) (inner (#miden:core-import/intrinsics-felt@1.0.0 #from-u32)) + (synth_func (#cross_ctx_account #miden_stdlib_sys::intrinsics::felt::extern_add (cc lower) (param felt) (param felt) (result felt) (inner (#miden:core-import/intrinsics-felt@1.0.0 #add)) + (synth_func (#cross_ctx_account #miden_sdk_alloc::heap_base (cc lower) (result i32) (inner (#miden:core-import/intrinsics-mem@1.0.0 #heap-base)) ) ) From ebb7abb6d00d407c8c0921bade12ad644d588a5e Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Mon, 13 Jan 2025 09:41:29 +0200 Subject: [PATCH 07/18] feature: introduce `hir2_sketch::World` and create a component with an `Interface` for each import component instance in the translated component --- frontend-wasm/src/component/build_ir.rs | 2 +- frontend-wasm/src/component/translator2.rs | 82 +++++++++++++++---- .../src/component/translator2/hir2_sketch.rs | 64 +++++++++++++++ .../rust_sdk/hir2_sketch_multi_interface.hir | 82 +++++++++++++++---- .../rust_sdk/hir2_sketch_single_interface.hir | 43 ++++++++-- 5 files changed, 231 insertions(+), 42 deletions(-) diff --git a/frontend-wasm/src/component/build_ir.rs b/frontend-wasm/src/component/build_ir.rs index fd69f1ad8..65f50e3d7 100644 --- a/frontend-wasm/src/component/build_ir.rs +++ b/frontend-wasm/src/component/build_ir.rs @@ -67,7 +67,7 @@ pub fn translate_component2( wasm: &[u8], config: &WasmTranslationConfig, session: &Session, -) -> WasmResult { +) -> WasmResult { let (mut component_types_builder, parsed_root_component) = parse(config, wasm, session)?; let translator = ComponentTranslator2::new( &parsed_root_component.static_modules, diff --git a/frontend-wasm/src/component/translator2.rs b/frontend-wasm/src/component/translator2.rs index 5eb48ccbd..2f2a290f3 100644 --- a/frontend-wasm/src/component/translator2.rs +++ b/frontend-wasm/src/component/translator2.rs @@ -50,7 +50,7 @@ pub struct ComponentTranslator2<'a> { /// `ComponentFrame` with the `ParsedComponent`s here. nested_components: &'a PrimaryMap>, - result: hir2_sketch::Component, + result: hir2_sketch::WorldBuilder, session: &'a Session, } @@ -62,17 +62,13 @@ impl<'a> ComponentTranslator2<'a> { config: &'a WasmTranslationConfig, session: &'a Session, ) -> Self { - let component = hir2_sketch::Component { - name: "root".to_string(), - interfaces: vec![], - modules: vec![], - }; + let mut builder = hir2_sketch::WorldBuilder::new("root".to_string()); Self { config, session, nested_modules, nested_components, - result: component, + result: builder, } } @@ -81,14 +77,14 @@ impl<'a> ComponentTranslator2<'a> { root_component: &'a ParsedComponent, types: &mut ComponentTypesBuilder, _diagnostics: &DiagnosticsHandler, - ) -> WasmResult { + ) -> WasmResult { let mut frame = ComponentFrame::new(root_component, FxHashMap::default()); for init in &root_component.initializers { self.initializer(&mut frame, types, init)?; } - Ok(self.result) + Ok(self.result.build()) } fn initializer( @@ -114,7 +110,6 @@ impl<'a> ComponentTranslator2<'a> { None => { match ty { ComponentEntityType::Instance(_) => { - // TODO: Create an empty component exporting functions (for each imported interface) let ty = types .convert_component_entity_type(types_ref, *ty) .map_err(Report::msg)?; @@ -131,11 +126,71 @@ impl<'a> ComponentTranslator2<'a> { ty, }, )); + let interface_name = name.0.to_string(); + let module = Ident::new( + Symbol::intern(interface_name.clone()), + SourceSpan::default(), + ); + let inner_function_empty = FunctionIdent { + module: Ident::new(Symbol::intern(""), SourceSpan::default()), + function: Ident::new(Symbol::intern(""), SourceSpan::default()), + }; + // Create a component with interfaces from the imported instance type + let component_types = types.resources_mut_and_types().1; + let instance_type = &component_types[ty]; + let functions = instance_type + .exports + .iter() + .filter_map(|(name, ty)| { + if let TypeDef::ComponentFunc(func_ty) = ty { + let func_ty = + convert_lifted_func_ty(func_ty, component_types); + let signature = Signature { + params: func_ty + .params + .into_iter() + .map(AbiParam::new) + .collect(), + results: func_ty + .results + .into_iter() + .map(AbiParam::new) + .collect(), + cc: CallConv::CanonLift, + linkage: Linkage::External, + }; + Some(hir2_sketch::SyntheticFunction { + id: FunctionIdent { + module, + function: Ident::new( + Symbol::intern(name), + SourceSpan::default(), + ), + }, + signature, + inner_function: inner_function_empty, + }) + } else { + None + } + }) + .collect(); + + let interface = Interface { + name: interface_name.clone(), + functions, + }; + let import_component = Component { + name: interface_name, + interfaces: vec![interface], + modules: Default::default(), + }; + self.result.add_import(import_component); } // ComponentEntityType::Module(component_core_module_type_id) => todo!(), ComponentEntityType::Func(_component_func_type_id) => { // frame.component_funcs.push(); - panic!("unhandled component import function"); + panic!(""); } // ComponentEntityType::Value(component_val_type) => todo!(), // ComponentEntityType::Type { @@ -278,7 +333,7 @@ impl<'a> ComponentTranslator2<'a> { module.functions.push(function); } - self.result.modules.push(module); + self.result.root_mut().modules.push(module); } ModuleDef::Import(_type_module_index) => { panic!("Module import instantiation is not supported yet") @@ -475,7 +530,6 @@ impl<'a> ComponentTranslator2<'a> { SourceSpan::default(), ), }; - // TODO: generate body with a call to the core module export let function = hir2_sketch::SyntheticFunction { id: function_id, signature, @@ -492,7 +546,7 @@ impl<'a> ComponentTranslator2<'a> { name: interface_name, functions, }; - self.result.interfaces.push(interface); + self.result.root_mut().interfaces.push(interface); frame.component_instances.push(ComponentInstanceDef::Export); } } diff --git a/frontend-wasm/src/component/translator2/hir2_sketch.rs b/frontend-wasm/src/component/translator2/hir2_sketch.rs index b28c85411..7bc9714af 100644 --- a/frontend-wasm/src/component/translator2/hir2_sketch.rs +++ b/frontend-wasm/src/component/translator2/hir2_sketch.rs @@ -152,3 +152,67 @@ impl PrettyPrint for Component { + nl() } } + +#[derive(Debug, Default)] +pub struct World { + pub components: Vec, +} + +impl fmt::Display for World { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.pretty_print(f) + } +} + +impl PrettyPrint for World { + fn render(&self) -> midenc_hir::formatter::Document { + use midenc_hir::formatter::*; + + let components = self + .components + .iter() + .map(PrettyPrint::render) + .reduce(|acc, doc| acc + nl() + doc) + .unwrap_or(Document::Empty); + + const_text("(") + + const_text("world") + + indent(4, nl() + components) + + nl() + + const_text(")") + + nl() + } +} + +pub struct WorldBuilder { + root: Component, + imports: Vec, +} + +impl WorldBuilder { + pub fn new(name: String) -> Self { + Self { + root: Component { + name, + interfaces: vec![], + modules: vec![], + }, + imports: vec![], + } + } + + pub fn root_mut(&mut self) -> &mut Component { + &mut self.root + } + + pub fn add_import(&mut self, component: Component) { + self.imports.push(component); + } + + pub fn build(self) -> World { + let mut components = Vec::with_capacity(1 + self.imports.len()); + components.extend(self.imports); + components.push(self.root); + World { components } + } +} diff --git a/tests/integration/expected/rust_sdk/hir2_sketch_multi_interface.hir b/tests/integration/expected/rust_sdk/hir2_sketch_multi_interface.hir index 1ef319ba3..398bdae67 100644 --- a/tests/integration/expected/rust_sdk/hir2_sketch_multi_interface.hir +++ b/tests/integration/expected/rust_sdk/hir2_sketch_multi_interface.hir @@ -1,23 +1,69 @@ -(component root - ;; Interfaces - (interface miden:basic-wallet/basic-wallet@1.0.0 - (synth_func (#miden:basic-wallet/basic-wallet@1.0.0 #receive-asset (cc lift) (param (struct (struct (struct (struct felt) (struct felt) (struct felt) (struct felt))))) (inner (#basic_wallet #miden:basic-wallet/basic-wallet@1.0.0#receive-asset)) - (synth_func (#miden:basic-wallet/basic-wallet@1.0.0 #send-asset (cc lift) (param (struct (struct (struct (struct felt) (struct felt) (struct felt) (struct felt))))) (param (struct (struct felt))) (param (struct (struct felt))) (param (struct (struct (struct (struct felt) (struct felt) (struct felt) (struct felt))))) (inner (#basic_wallet #miden:basic-wallet/basic-wallet@1.0.0#send-asset)) +(world + (component miden:base/core-types@1.0.0 + ;; Interfaces + (interface miden:base/core-types@1.0.0 + + ) + ) + + (component miden:core-import/intrinsics-mem@1.0.0 + ;; Interfaces + (interface miden:core-import/intrinsics-mem@1.0.0 + (synth_func (#miden:core-import/intrinsics-mem@1.0.0 #heap-base (cc lift) (result i32) (inner (# #)) + ) + ) + + (component miden:core-import/intrinsics-felt@1.0.0 + ;; Interfaces + (interface miden:core-import/intrinsics-felt@1.0.0 + (synth_func (#miden:core-import/intrinsics-felt@1.0.0 #add (cc lift) (param felt) (param felt) (result felt) (inner (# #)) + ) + ) + + (component miden:core-import/stdlib-crypto-hashes-blake3@1.0.0 + ;; Interfaces + (interface miden:core-import/stdlib-crypto-hashes-blake3@1.0.0 + (synth_func (#miden:core-import/stdlib-crypto-hashes-blake3@1.0.0 #hash-one-to-one (cc lift) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (inner (# #)) + ) + ) + + (component miden:core-import/account@1.0.0 + ;; Interfaces + (interface miden:core-import/account@1.0.0 + (synth_func (#miden:core-import/account@1.0.0 #add-asset (cc lift) (param felt) (param felt) (param felt) (param felt) (param i32) (inner (# #)) + (synth_func (#miden:core-import/account@1.0.0 #remove-asset (cc lift) (param felt) (param felt) (param felt) (param felt) (param i32) (inner (# #)) + ) ) - (interface miden:basic-wallet/aux@1.0.0 - (synth_func (#miden:basic-wallet/aux@1.0.0 #test-felt-intrinsics (cc lift) (param (struct felt)) (param (struct felt)) (result (struct felt)) (inner (#basic_wallet #miden:basic-wallet/aux@1.0.0#test-felt-intrinsics)) - (synth_func (#miden:basic-wallet/aux@1.0.0 #test-stdlib (cc lift) (param (list u8)) (result (list u8)) (inner (#basic_wallet #miden:basic-wallet/aux@1.0.0#test-stdlib)) - (synth_func (#miden:basic-wallet/aux@1.0.0 #process-list-felt (cc lift) (param (list (struct felt))) (result (list (struct felt))) (inner (#basic_wallet #miden:basic-wallet/aux@1.0.0#process-list-felt)) - (synth_func (#miden:basic-wallet/aux@1.0.0 #process-core-asset (cc lift) (param (struct (struct (struct (struct felt) (struct felt) (struct felt) (struct felt))))) (result (struct (struct (struct (struct felt) (struct felt) (struct felt) (struct felt))))) (inner (#basic_wallet #miden:basic-wallet/aux@1.0.0#process-core-asset)) + + (component miden:core-import/tx@1.0.0 + ;; Interfaces + (interface miden:core-import/tx@1.0.0 + (synth_func (#miden:core-import/tx@1.0.0 #create-note (cc lift) (param felt) (param felt) (param felt) (param felt) (param felt) (param felt) (param felt) (param felt) (param felt) (param felt) (result felt) (inner (# #)) + ) ) - ;; Modules - (module #basic_wallet - (synth_func (#basic_wallet #miden_stdlib_sys::intrinsics::felt::extern_add (cc lower) (param felt) (param felt) (result felt) (inner (#miden:core-import/intrinsics-felt@1.0.0 #add)) - (synth_func (#basic_wallet #miden_stdlib_sys::stdlib::crypto::hashes::extern_blake3_hash_1to1 (cc lower) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (inner (#miden:core-import/stdlib-crypto-hashes-blake3@1.0.0 #hash-one-to-one)) - (synth_func (#basic_wallet #miden_sdk_alloc::heap_base (cc lower) (result i32) (inner (#miden:core-import/intrinsics-mem@1.0.0 #heap-base)) - (synth_func (#basic_wallet #miden_base_sys::bindings::account::extern_account_add_asset (cc lower) (param felt) (param felt) (param felt) (param felt) (param i32) (inner (#miden:core-import/account@1.0.0 #add-asset)) - (synth_func (#basic_wallet #miden_base_sys::bindings::account::extern_account_remove_asset (cc lower) (param felt) (param felt) (param felt) (param felt) (param i32) (inner (#miden:core-import/account@1.0.0 #remove-asset)) - (synth_func (#basic_wallet #miden_base_sys::bindings::tx::extern_tx_create_note (cc lower) (param felt) (param felt) (param felt) (param felt) (param felt) (param felt) (param felt) (param felt) (param felt) (param felt) (result felt) (inner (#miden:core-import/tx@1.0.0 #create-note)) + (component root + ;; Interfaces + (interface miden:basic-wallet/basic-wallet@1.0.0 + (synth_func (#miden:basic-wallet/basic-wallet@1.0.0 #receive-asset (cc lift) (param (struct (struct (struct (struct felt) (struct felt) (struct felt) (struct felt))))) (inner (#basic_wallet #miden:basic-wallet/basic-wallet@1.0.0#receive-asset)) + (synth_func (#miden:basic-wallet/basic-wallet@1.0.0 #send-asset (cc lift) (param (struct (struct (struct (struct felt) (struct felt) (struct felt) (struct felt))))) (param (struct (struct felt))) (param (struct (struct felt))) (param (struct (struct (struct (struct felt) (struct felt) (struct felt) (struct felt))))) (inner (#basic_wallet #miden:basic-wallet/basic-wallet@1.0.0#send-asset)) + ) + (interface miden:basic-wallet/aux@1.0.0 + (synth_func (#miden:basic-wallet/aux@1.0.0 #test-felt-intrinsics (cc lift) (param (struct felt)) (param (struct felt)) (result (struct felt)) (inner (#basic_wallet #miden:basic-wallet/aux@1.0.0#test-felt-intrinsics)) + (synth_func (#miden:basic-wallet/aux@1.0.0 #test-stdlib (cc lift) (param (list u8)) (result (list u8)) (inner (#basic_wallet #miden:basic-wallet/aux@1.0.0#test-stdlib)) + (synth_func (#miden:basic-wallet/aux@1.0.0 #process-list-felt (cc lift) (param (list (struct felt))) (result (list (struct felt))) (inner (#basic_wallet #miden:basic-wallet/aux@1.0.0#process-list-felt)) + (synth_func (#miden:basic-wallet/aux@1.0.0 #process-core-asset (cc lift) (param (struct (struct (struct (struct felt) (struct felt) (struct felt) (struct felt))))) (result (struct (struct (struct (struct felt) (struct felt) (struct felt) (struct felt))))) (inner (#basic_wallet #miden:basic-wallet/aux@1.0.0#process-core-asset)) + ) + + ;; Modules + (module #basic_wallet + (synth_func (#basic_wallet #miden_stdlib_sys::intrinsics::felt::extern_add (cc lower) (param felt) (param felt) (result felt) (inner (#miden:core-import/intrinsics-felt@1.0.0 #add)) + (synth_func (#basic_wallet #miden_stdlib_sys::stdlib::crypto::hashes::extern_blake3_hash_1to1 (cc lower) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (inner (#miden:core-import/stdlib-crypto-hashes-blake3@1.0.0 #hash-one-to-one)) + (synth_func (#basic_wallet #miden_sdk_alloc::heap_base (cc lower) (result i32) (inner (#miden:core-import/intrinsics-mem@1.0.0 #heap-base)) + (synth_func (#basic_wallet #miden_base_sys::bindings::account::extern_account_add_asset (cc lower) (param felt) (param felt) (param felt) (param felt) (param i32) (inner (#miden:core-import/account@1.0.0 #add-asset)) + (synth_func (#basic_wallet #miden_base_sys::bindings::account::extern_account_remove_asset (cc lower) (param felt) (param felt) (param felt) (param felt) (param i32) (inner (#miden:core-import/account@1.0.0 #remove-asset)) + (synth_func (#basic_wallet #miden_base_sys::bindings::tx::extern_tx_create_note (cc lower) (param felt) (param felt) (param felt) (param felt) (param felt) (param felt) (param felt) (param felt) (param felt) (param felt) (result felt) (inner (#miden:core-import/tx@1.0.0 #create-note)) + ) ) + ) diff --git a/tests/integration/expected/rust_sdk/hir2_sketch_single_interface.hir b/tests/integration/expected/rust_sdk/hir2_sketch_single_interface.hir index f3123b378..d1a64dd40 100644 --- a/tests/integration/expected/rust_sdk/hir2_sketch_single_interface.hir +++ b/tests/integration/expected/rust_sdk/hir2_sketch_single_interface.hir @@ -1,13 +1,38 @@ -(component root - ;; Interfaces - (interface miden:cross-ctx-account/foo@1.0.0 - (synth_func (#miden:cross-ctx-account/foo@1.0.0 #process-felt (cc lift) (param (struct felt)) (result (struct felt)) (inner (#cross_ctx_account #miden:cross-ctx-account/foo@1.0.0#process-felt)) +(world + (component miden:base/core-types@1.0.0 + ;; Interfaces + (interface miden:base/core-types@1.0.0 + + ) + ) + + (component miden:core-import/intrinsics-mem@1.0.0 + ;; Interfaces + (interface miden:core-import/intrinsics-mem@1.0.0 + (synth_func (#miden:core-import/intrinsics-mem@1.0.0 #heap-base (cc lift) (result i32) (inner (# #)) + ) ) - ;; Modules - (module #cross_ctx_account - (synth_func (#cross_ctx_account #miden_stdlib_sys::intrinsics::felt::extern_from_u32 (cc lower) (param u32) (result felt) (inner (#miden:core-import/intrinsics-felt@1.0.0 #from-u32)) - (synth_func (#cross_ctx_account #miden_stdlib_sys::intrinsics::felt::extern_add (cc lower) (param felt) (param felt) (result felt) (inner (#miden:core-import/intrinsics-felt@1.0.0 #add)) - (synth_func (#cross_ctx_account #miden_sdk_alloc::heap_base (cc lower) (result i32) (inner (#miden:core-import/intrinsics-mem@1.0.0 #heap-base)) + (component miden:core-import/intrinsics-felt@1.0.0 + ;; Interfaces + (interface miden:core-import/intrinsics-felt@1.0.0 + (synth_func (#miden:core-import/intrinsics-felt@1.0.0 #add (cc lift) (param felt) (param felt) (result felt) (inner (# #)) + (synth_func (#miden:core-import/intrinsics-felt@1.0.0 #from-u32 (cc lift) (param u32) (result felt) (inner (# #)) + ) ) + + (component root + ;; Interfaces + (interface miden:cross-ctx-account/foo@1.0.0 + (synth_func (#miden:cross-ctx-account/foo@1.0.0 #process-felt (cc lift) (param (struct felt)) (result (struct felt)) (inner (#cross_ctx_account #miden:cross-ctx-account/foo@1.0.0#process-felt)) + ) + + ;; Modules + (module #cross_ctx_account + (synth_func (#cross_ctx_account #miden_stdlib_sys::intrinsics::felt::extern_from_u32 (cc lower) (param u32) (result felt) (inner (#miden:core-import/intrinsics-felt@1.0.0 #from-u32)) + (synth_func (#cross_ctx_account #miden_stdlib_sys::intrinsics::felt::extern_add (cc lower) (param felt) (param felt) (result felt) (inner (#miden:core-import/intrinsics-felt@1.0.0 #add)) + (synth_func (#cross_ctx_account #miden_sdk_alloc::heap_base (cc lower) (result i32) (inner (#miden:core-import/intrinsics-mem@1.0.0 #heap-base)) + ) + ) + ) From 08c80eef4eef60f2d5840204cbe5b56d653b1d57 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Mon, 13 Jan 2025 11:41:26 +0200 Subject: [PATCH 08/18] refactor: remove InstantiatedComponent --- frontend-wasm/src/component/translator2.rs | 25 ++++++++-------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/frontend-wasm/src/component/translator2.rs b/frontend-wasm/src/component/translator2.rs index 2f2a290f3..4c4fec288 100644 --- a/frontend-wasm/src/component/translator2.rs +++ b/frontend-wasm/src/component/translator2.rs @@ -1,6 +1,9 @@ // TODO: remove when it is completed #![allow(unused)] +// TODO: refactor +// TODO: document + use hir2_sketch::{Component, Interface, Module}; use midenc_hir::{ cranelift_entity::PrimaryMap, diagnostics::Report, AbiParam, CallConv, FunctionIdent, Ident, @@ -224,7 +227,6 @@ impl<'a> ComponentTranslator2<'a> { args: args.clone(), }); - // TODO: use (Symbol, Symbol) as a key? let mut import_canon_lower_args: FxHashMap = FxHashMap::default(); match &frame.modules[*module_idx] { @@ -384,11 +386,9 @@ impl<'a> ComponentTranslator2<'a> { for init in &translation.initializers { self.initializer(&mut new_frame, types, init)?; } - let instance_idx = frame.component_instances.push( - ComponentInstanceDef::Instantiated(InstantiatedComponent { - component_inst: instance.clone(), - }), - ); + let instance_idx = frame + .component_instances + .push(ComponentInstanceDef::Instantiated(instance.clone())); frame.frames.insert(instance_idx, new_frame); } LocalInitializer::ComponentSynthetic(_hash_map) => { @@ -455,8 +455,7 @@ impl<'a> ComponentTranslator2<'a> { let interface_name = name.to_string(); let instance = &frame.component_instances[component_item.unwrap_instance()] .unwrap_instantiated(); - let static_component_idx = - frame.components[instance.component_inst.component].index; + let static_component_idx = frame.components[instance.component].index; let parsed_component = &self.nested_components[static_component_idx]; // dbg!(&parsed_component.exports); let module = @@ -554,16 +553,10 @@ impl<'a> ComponentTranslator2<'a> { } } -#[derive(Clone, Debug)] -struct InstantiatedComponent<'a> { - // TODO: inline - component_inst: ComponentInstantiation<'a>, -} - #[derive(Clone, Debug)] enum ComponentInstanceDef<'a> { Import(ComponentInstanceImport), - Instantiated(InstantiatedComponent<'a>), + Instantiated(ComponentInstantiation<'a>), Export, } impl<'a> ComponentInstanceDef<'a> { @@ -574,7 +567,7 @@ impl<'a> ComponentInstanceDef<'a> { } } - fn unwrap_instantiated(&self) -> &InstantiatedComponent { + fn unwrap_instantiated(&self) -> &ComponentInstantiation { match self { ComponentInstanceDef::Instantiated(i) => i, _ => panic!("expected instantiated"), From 40a936f3d1e417a7ac8df15e62d317ebfd1e70e6 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Mon, 13 Jan 2025 11:46:14 +0200 Subject: [PATCH 09/18] refactor: store `TypesRef` instead of `ParsedComponent` in `ComponentFrame` --- frontend-wasm/src/component/translator2.rs | 27 ++++++++-------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/frontend-wasm/src/component/translator2.rs b/frontend-wasm/src/component/translator2.rs index 4c4fec288..3133b851f 100644 --- a/frontend-wasm/src/component/translator2.rs +++ b/frontend-wasm/src/component/translator2.rs @@ -11,7 +11,7 @@ use midenc_hir::{ }; use midenc_session::{DiagnosticsHandler, Session}; use rustc_hash::FxHashMap; -use wasmparser::types::ComponentEntityType; +use wasmparser::types::{ComponentEntityType, TypesRef}; use super::{ translator::convert_lifted_func_ty, CanonLift, CanonLower, ClosedOverComponent, @@ -81,7 +81,7 @@ impl<'a> ComponentTranslator2<'a> { types: &mut ComponentTypesBuilder, _diagnostics: &DiagnosticsHandler, ) -> WasmResult { - let mut frame = ComponentFrame::new(root_component, FxHashMap::default()); + let mut frame = ComponentFrame::new(root_component.types_ref(), FxHashMap::default()); for init in &root_component.initializers { self.initializer(&mut frame, types, init)?; @@ -98,7 +98,6 @@ impl<'a> ComponentTranslator2<'a> { ) -> WasmResult<()> { // dbg!(&init); - let types_ref = frame.translation.types_ref(); match init { LocalInitializer::Import(name, ty) => { // dbg!(name, ty); @@ -114,7 +113,7 @@ impl<'a> ComponentTranslator2<'a> { match ty { ComponentEntityType::Instance(_) => { let ty = types - .convert_component_entity_type(types_ref, *ty) + .convert_component_entity_type(frame.types, *ty) .map_err(Report::msg)?; // self.import_types.push((name.0.to_string(), ty)); let ty = match ty { @@ -258,7 +257,7 @@ impl<'a> ComponentTranslator2<'a> { // TODO: handle error let type_func_idx = types .convert_component_func_type( - types_ref, + frame.types, canon_lower.lower_ty, ) .unwrap(); @@ -378,7 +377,7 @@ impl<'a> ComponentTranslator2<'a> { let translation = &self.nested_components[component.index]; let mut new_frame = ComponentFrame::new( - translation, + translation.types_ref(), args.iter() .map(|(name, item)| Ok((*name, frame.item(*item, types)?))) .collect::>()?, @@ -510,7 +509,7 @@ impl<'a> ComponentTranslator2<'a> { } }; let type_func_idx = types - .convert_component_func_type(types_ref, canon_lift.ty) + .convert_component_func_type(frame.types, canon_lift.ty) .unwrap(); let component_types = types.resources_mut_and_types().1; @@ -701,9 +700,7 @@ impl<'a> ComponentItemDef<'a> { } struct ComponentFrame<'a> { - // TODO: can we get away without the whole ParsedComponent but only ComponentTypes*? - /// The component being instantiated. - translation: &'a ParsedComponent<'a>, + types: TypesRef<'a>, /// The "closure arguments" to this component, or otherwise the maps indexed /// by `ModuleUpvarIndex` and `ComponentUpvarIndex`. This is created when @@ -733,13 +730,10 @@ struct ComponentFrame<'a> { } impl<'a> ComponentFrame<'a> { - fn new( - translation: &'a ParsedComponent<'a>, - args: FxHashMap<&'a str, ComponentItemDef<'a>>, - ) -> Self { + fn new(types: TypesRef<'a>, args: FxHashMap<&'a str, ComponentItemDef<'a>>) -> Self { Self { // initializers: translation.initializers.iter(), - translation, + types, funcs: PrimaryMap::new(), component_funcs: PrimaryMap::new(), component_instances: PrimaryMap::new(), @@ -779,9 +773,8 @@ impl<'a> ComponentFrame<'a> { } ComponentItem::Module(i) => ComponentItemDef::Module(self.modules[i].clone()), ComponentItem::Type(t) => { - let types_ref = self.translation.types_ref(); // TODO: handle error - ComponentItemDef::Type(types.convert_type(types_ref, t).unwrap()) + ComponentItemDef::Type(types.convert_type(self.types, t).unwrap()) } }) } From 0ca3e429d50e251f93aad19abc3038ddbbbc0e5c Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Mon, 13 Jan 2025 11:59:49 +0200 Subject: [PATCH 10/18] refactor: remove unused code --- frontend-wasm/src/component/translator2.rs | 92 ++++++++-------------- 1 file changed, 33 insertions(+), 59 deletions(-) diff --git a/frontend-wasm/src/component/translator2.rs b/frontend-wasm/src/component/translator2.rs index 3133b851f..f951d412b 100644 --- a/frontend-wasm/src/component/translator2.rs +++ b/frontend-wasm/src/component/translator2.rs @@ -1,4 +1,4 @@ -// TODO: remove when it is completed +// TODO: remove after its completed #![allow(unused)] // TODO: refactor @@ -65,7 +65,7 @@ impl<'a> ComponentTranslator2<'a> { config: &'a WasmTranslationConfig, session: &'a Session, ) -> Self { - let mut builder = hir2_sketch::WorldBuilder::new("root".to_string()); + let builder = hir2_sketch::WorldBuilder::new("root".to_string()); Self { config, session, @@ -391,7 +391,7 @@ impl<'a> ComponentTranslator2<'a> { frame.frames.insert(instance_idx, new_frame); } LocalInitializer::ComponentSynthetic(_hash_map) => { - dbg!(&init); + // dbg!(&init); } LocalInitializer::AliasExportFunc(module_instance_index, name) => { // dbg!(&init); @@ -403,32 +403,13 @@ impl<'a> ComponentTranslator2<'a> { // dbg!(&init); } LocalInitializer::AliasComponentExport(component_instance_index, name) => { - match &frame.component_instances[*component_instance_index] { - // Aliasing an export from an imported instance means that - // we're extending the `ImportPath` by one name, represented - // with the clone + push here. Afterwards an appropriate - // item is then pushed in the relevant index space. - ComponentInstanceDef::Import(import) => { - dbg!(&import); - // let path = path.push(*name); - let def = ComponentItemDef::from_import( - name, - types[import.ty].exports[*name], - *component_instance_index, - ); - frame.push_item(def); - } - - // Given a component instance which was either created - // through instantiation of a component or through a - // synthetic renaming of items we just schlep around the - // definitions of various items here. - // ComponentInstanceDef::Items(map) => frame.push_item(map[*name].clone()), - ComponentInstanceDef::Instantiated(inst) => { - dbg!(&inst); - } - ComponentInstanceDef::Export => todo!(), - } + let import = &frame.component_instances[*component_instance_index].unwrap_import(); + let def = ComponentItemDef::from_import( + name, + types[import.ty].exports[*name], + *component_instance_index, + ); + frame.push_item(def); } LocalInitializer::AliasModule(_) => todo!(), LocalInitializer::AliasComponent(_) => todo!(), @@ -475,31 +456,31 @@ impl<'a> ComponentTranslator2<'a> { let core_func_id: FunctionIdent = match &frame.funcs[canon_lift.func] { CoreDef::Export(module_instance_index, name) => { match &frame.module_instances[*module_instance_index] { - ModuleInstanceDef::Instantiated { module_idx, args } => { - match frame.modules[*module_idx] { - ModuleDef::Static(static_module_index) => { - let parsed_module = - &self.nested_modules[static_module_index]; - let func_idx = parsed_module.module.exports - [*name] - .unwrap_func(); - let func_name = - parsed_module.module.func_name(func_idx); - let module_ident = parsed_module.module.name(); - FunctionIdent { - module: module_ident, - function: Ident::new( - func_name, - SourceSpan::default(), - ), - } - } - ModuleDef::Import(type_module_index) => { - panic!("expected static module") + ModuleInstanceDef::Instantiated { + module_idx, + args: _, + } => match frame.modules[*module_idx] { + ModuleDef::Static(static_module_index) => { + let parsed_module = + &self.nested_modules[static_module_index]; + let func_idx = parsed_module.module.exports[*name] + .unwrap_func(); + let func_name = + parsed_module.module.func_name(func_idx); + let module_ident = parsed_module.module.name(); + FunctionIdent { + module: module_ident, + function: Ident::new( + func_name, + SourceSpan::default(), + ), } } - } - ModuleInstanceDef::Synthetic(hash_map) => { + ModuleDef::Import(_type_module_index) => { + panic!("expected static module") + } + }, + ModuleInstanceDef::Synthetic(_hash_map) => { panic!("expected static module") } } @@ -590,13 +571,6 @@ enum ComponentFuncDef<'a> { Lifted(CanonLift), } impl<'a> ComponentFuncDef<'a> { - fn unwrap_import(&self) -> (&ComponentInstanceIndex, &'a str) { - match self { - ComponentFuncDef::Import(idx, name) => (idx, name), - _ => panic!("expected import"), - } - } - fn unwrap_canon_lift(&self) -> &CanonLift { match self { ComponentFuncDef::Lifted(lift) => lift, From 03dbb7b49a7f1383122684f522502f572468bd16 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Mon, 13 Jan 2025 12:09:33 +0200 Subject: [PATCH 11/18] refactor: use qualified Severity in unsupported_diag! macro --- frontend-wasm/src/code_translator/mod.rs | 2 +- frontend-wasm/src/error.rs | 2 +- frontend-wasm/src/module/mod.rs | 2 +- frontend-wasm/src/translation_utils.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend-wasm/src/code_translator/mod.rs b/frontend-wasm/src/code_translator/mod.rs index 3ca0ad106..05e250176 100644 --- a/frontend-wasm/src/code_translator/mod.rs +++ b/frontend-wasm/src/code_translator/mod.rs @@ -15,7 +15,7 @@ use midenc_hir::{ cranelift_entity::packed_option::ReservedValue, - diagnostics::{DiagnosticsHandler, IntoDiagnostic, Report, Severity, SourceSpan}, + diagnostics::{DiagnosticsHandler, IntoDiagnostic, Report, SourceSpan}, Block, FieldElement, Immediate, Inst, InstBuilder, Type, Type::*, Value, diff --git a/frontend-wasm/src/error.rs b/frontend-wasm/src/error.rs index a42b399cf..ec83bfdfb 100644 --- a/frontend-wasm/src/error.rs +++ b/frontend-wasm/src/error.rs @@ -72,7 +72,7 @@ pub type WasmResult = Result; macro_rules! unsupported_diag { ($diagnostics:expr, $($arg:tt)*) => {{ return Err($diagnostics - .diagnostic(Severity::Error) + .diagnostic(midenc_hir::diagnostics::Severity::Error) .with_message(format!($($arg)*)) .into_report()); }} diff --git a/frontend-wasm/src/module/mod.rs b/frontend-wasm/src/module/mod.rs index 7cb100efe..115c83267 100644 --- a/frontend-wasm/src/module/mod.rs +++ b/frontend-wasm/src/module/mod.rs @@ -8,7 +8,7 @@ use std::{borrow::Cow, collections::BTreeMap, ops::Range}; use indexmap::IndexMap; use midenc_hir::{ cranelift_entity::{packed_option::ReservedValue, EntityRef, PrimaryMap}, - diagnostics::{DiagnosticsHandler, Severity}, + diagnostics::DiagnosticsHandler, FxHashMap, Ident, Symbol, }; diff --git a/frontend-wasm/src/translation_utils.rs b/frontend-wasm/src/translation_utils.rs index e4861aeb5..452fb7df2 100644 --- a/frontend-wasm/src/translation_utils.rs +++ b/frontend-wasm/src/translation_utils.rs @@ -1,7 +1,7 @@ //! Helper functions and structures for the translation. use midenc_hir::{ - diagnostics::{DiagnosticsHandler, Severity, SourceSpan}, + diagnostics::{DiagnosticsHandler, SourceSpan}, AbiParam, CallConv, Felt, FieldElement, InstBuilder, Linkage, Signature, Value, }; use midenc_hir_type::{FunctionType, Type}; From 4455db70f7bbd9527a395f8bcdf183295086d41f Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Mon, 13 Jan 2025 12:31:44 +0200 Subject: [PATCH 12/18] refactor: gracefully handle not supported Wasm component shapes --- frontend-wasm/src/component/translator2.rs | 231 +++++++++++---------- 1 file changed, 124 insertions(+), 107 deletions(-) diff --git a/frontend-wasm/src/component/translator2.rs b/frontend-wasm/src/component/translator2.rs index f951d412b..c6eb195ab 100644 --- a/frontend-wasm/src/component/translator2.rs +++ b/frontend-wasm/src/component/translator2.rs @@ -1,9 +1,6 @@ // TODO: remove after its completed #![allow(unused)] -// TODO: refactor -// TODO: document - use hir2_sketch::{Component, Interface, Module}; use midenc_hir::{ cranelift_entity::PrimaryMap, diagnostics::Report, AbiParam, CallConv, FunctionIdent, Ident, @@ -27,7 +24,7 @@ use crate::{ module_env::ParsedModule, types::{EntityIndex, FuncIndex}, }, - WasmTranslationConfig, + unsupported_diag, WasmTranslationConfig, }; pub mod hir2_sketch; @@ -110,97 +107,83 @@ impl<'a> ComponentTranslator2<'a> { // namely the root component doesn't require // structural type imports to be satisfied. None => { - match ty { - ComponentEntityType::Instance(_) => { - let ty = types - .convert_component_entity_type(frame.types, *ty) - .map_err(Report::msg)?; - // self.import_types.push((name.0.to_string(), ty)); - let ty = match ty { - TypeDef::ComponentInstance(type_component_instance_index) => { - type_component_instance_index + if let ComponentEntityType::Instance(_) = ty { + let ty = types + .convert_component_entity_type(frame.types, *ty) + .map_err(Report::msg)?; + // self.import_types.push((name.0.to_string(), ty)); + let ty = match ty { + TypeDef::ComponentInstance(type_component_instance_index) => { + type_component_instance_index + } + _ => panic!("expected component instance"), + }; + frame.component_instances.push(ComponentInstanceDef::Import( + ComponentInstanceImport { + name: name.0.to_string(), + ty, + }, + )); + let interface_name = name.0.to_string(); + let module = Ident::new( + Symbol::intern(interface_name.clone()), + SourceSpan::default(), + ); + let inner_function_empty = FunctionIdent { + module: Ident::new(Symbol::intern(""), SourceSpan::default()), + function: Ident::new(Symbol::intern(""), SourceSpan::default()), + }; + // Create a component with interfaces from the imported instance type + let component_types = types.resources_mut_and_types().1; + let instance_type = &component_types[ty]; + let functions = instance_type + .exports + .iter() + .filter_map(|(name, ty)| { + if let TypeDef::ComponentFunc(func_ty) = ty { + let func_ty = + convert_lifted_func_ty(func_ty, component_types); + let signature = Signature { + params: func_ty + .params + .into_iter() + .map(AbiParam::new) + .collect(), + results: func_ty + .results + .into_iter() + .map(AbiParam::new) + .collect(), + cc: CallConv::CanonLift, + linkage: Linkage::External, + }; + Some(hir2_sketch::SyntheticFunction { + id: FunctionIdent { + module, + function: Ident::new( + Symbol::intern(name), + SourceSpan::default(), + ), + }, + signature, + inner_function: inner_function_empty, + }) + } else { + None } - _ => panic!("expected component instance"), - }; - frame.component_instances.push(ComponentInstanceDef::Import( - ComponentInstanceImport { - name: name.0.to_string(), - ty, - }, - )); - let interface_name = name.0.to_string(); - let module = Ident::new( - Symbol::intern(interface_name.clone()), - SourceSpan::default(), - ); - let inner_function_empty = FunctionIdent { - module: Ident::new(Symbol::intern(""), SourceSpan::default()), - function: Ident::new(Symbol::intern(""), SourceSpan::default()), - }; - // Create a component with interfaces from the imported instance type - let component_types = types.resources_mut_and_types().1; - let instance_type = &component_types[ty]; - let functions = instance_type - .exports - .iter() - .filter_map(|(name, ty)| { - if let TypeDef::ComponentFunc(func_ty) = ty { - let func_ty = - convert_lifted_func_ty(func_ty, component_types); - let signature = Signature { - params: func_ty - .params - .into_iter() - .map(AbiParam::new) - .collect(), - results: func_ty - .results - .into_iter() - .map(AbiParam::new) - .collect(), - cc: CallConv::CanonLift, - linkage: Linkage::External, - }; - Some(hir2_sketch::SyntheticFunction { - id: FunctionIdent { - module, - function: Ident::new( - Symbol::intern(name), - SourceSpan::default(), - ), - }, - signature, - inner_function: inner_function_empty, - }) - } else { - None - } - }) - .collect(); - - let interface = Interface { - name: interface_name.clone(), - functions, - }; - let import_component = Component { - name: interface_name, - interfaces: vec![interface], - modules: Default::default(), - }; - self.result.add_import(import_component); - } - // ComponentEntityType::Module(component_core_module_type_id) => todo!(), - ComponentEntityType::Func(_component_func_type_id) => { - // frame.component_funcs.push(); - panic!(""); - } - // ComponentEntityType::Value(component_val_type) => todo!(), - // ComponentEntityType::Type { - // referenced, - // created, - // } => (), // do nothing - // ComponentEntityType::Component(component_type_id) => todo!(), - _ => (), + }) + .collect(); + + let interface = Interface { + name: interface_name.clone(), + functions, + }; + let import_component = Component { + name: interface_name, + interfaces: vec![interface], + modules: Default::default(), + }; + self.result.add_import(import_component); }; } }; @@ -213,10 +196,24 @@ impl<'a> ComponentTranslator2<'a> { // dbg!(&init); frame.component_funcs.push(ComponentFuncDef::Lifted(lift.clone())); } - LocalInitializer::Resource(..) => todo!(), - LocalInitializer::ResourceNew(..) => todo!(), - LocalInitializer::ResourceRep(..) => todo!(), - LocalInitializer::ResourceDrop(..) => todo!(), + LocalInitializer::Resource(..) => { + unsupported_diag!( + &self.session.diagnostics, + "Resource initializers are not supported" + ) + } + LocalInitializer::ResourceNew(..) => { + unsupported_diag!(&self.session.diagnostics, "Resource creation is not supported") + } + LocalInitializer::ResourceRep(..) => { + unsupported_diag!( + &self.session.diagnostics, + "Resource representation is not supported" + ) + } + LocalInitializer::ResourceDrop(..) => { + unsupported_diag!(&self.session.diagnostics, "Resource dropping is not supported") + } LocalInitializer::ModuleStatic(static_module_index) => { frame.modules.push(ModuleDef::Static(*static_module_index)); } @@ -244,7 +241,13 @@ impl<'a> ComponentTranslator2<'a> { ModuleInstanceDef::Instantiated { module_idx: _, args: _, - } => todo!(), + } => { + unsupported_diag!( + &self.session.diagnostics, + "Instantiated module as another module instantiation \ + argument is not supported yet" + ) + } ModuleInstanceDef::Synthetic(hash_map) => { // module with CanonLower synthetic functions for (func_name, entity) in hash_map.iter() { @@ -397,10 +400,15 @@ impl<'a> ComponentTranslator2<'a> { // dbg!(&init); frame.funcs.push(CoreDef::Export(*module_instance_index, name)); } - LocalInitializer::AliasExportTable(..) => todo!(), - LocalInitializer::AliasExportGlobal(..) => todo!(), + LocalInitializer::AliasExportTable(..) => { + unsupported_diag!(&self.session.diagnostics, "Table exports are not yet supported") + } + LocalInitializer::AliasExportGlobal(..) => { + unsupported_diag!(&self.session.diagnostics, "Global exports are not yet supported") + } LocalInitializer::AliasExportMemory(..) => { // dbg!(&init); + // Do nothing, assuming Rust compiled code having one memory instance. } LocalInitializer::AliasComponentExport(component_instance_index, name) => { let import = &frame.component_instances[*component_instance_index].unwrap_import(); @@ -411,8 +419,15 @@ impl<'a> ComponentTranslator2<'a> { ); frame.push_item(def); } - LocalInitializer::AliasModule(_) => todo!(), - LocalInitializer::AliasComponent(_) => todo!(), + LocalInitializer::AliasModule(_) => { + unsupported_diag!(&self.session.diagnostics, "Module aliases are not yet supported") + } + LocalInitializer::AliasComponent(_) => { + unsupported_diag!( + &self.session.diagnostics, + "Component aliases are not yet supported" + ) + } LocalInitializer::Export(name, component_item) => { // dbg!(&init); match component_item { @@ -420,12 +435,15 @@ impl<'a> ComponentTranslator2<'a> { frame.component_funcs.push(frame.component_funcs[*i].clone()); return Ok(()); } - ComponentItem::Module(_) => todo!(), - ComponentItem::Component(_) => todo!(), ComponentItem::ComponentInstance(_) => { // handle below } ComponentItem::Type(_) => return Ok(()), // do nothing + _ => unsupported_diag!( + &self.session.diagnostics, + "Exporting of {:?} is not yet supported", + component_item + ), } // FIX: ugly assert!( @@ -481,7 +499,7 @@ impl<'a> ComponentTranslator2<'a> { } }, ModuleInstanceDef::Synthetic(_hash_map) => { - panic!("expected static module") + panic!("expected instantiated module") } } } @@ -558,7 +576,6 @@ impl<'a> ComponentInstanceDef<'a> { #[derive(Debug, Clone)] struct ComponentInstanceImport { name: String, - // ty: TypeDef, ty: TypeComponentInstanceIndex, } From 7cf7ba850be2ed9d970048e02714d15445690b68 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Mon, 13 Jan 2025 15:23:22 +0200 Subject: [PATCH 13/18] refactor: extract most LocalInitializer variant translation --- frontend-wasm/src/component/translator2.rs | 676 +++++++++++---------- 1 file changed, 344 insertions(+), 332 deletions(-) diff --git a/frontend-wasm/src/component/translator2.rs b/frontend-wasm/src/component/translator2.rs index c6eb195ab..e2d1e42dc 100644 --- a/frontend-wasm/src/component/translator2.rs +++ b/frontend-wasm/src/component/translator2.rs @@ -1,6 +1,8 @@ // TODO: remove after its completed #![allow(unused)] +// TODO: document + use hir2_sketch::{Component, Interface, Module}; use midenc_hir::{ cranelift_entity::PrimaryMap, diagnostics::Report, AbiParam, CallConv, FunctionIdent, Ident, @@ -93,107 +95,35 @@ impl<'a> ComponentTranslator2<'a> { types: &mut ComponentTypesBuilder, init: &'a LocalInitializer<'a>, ) -> WasmResult<()> { - // dbg!(&init); - match init { LocalInitializer::Import(name, ty) => { - // dbg!(name, ty); match frame.args.get(name.0) { Some(arg) => { frame.push_item(arg.clone()); } - // Not all arguments need to be provided for instantiation, - // namely the root component doesn't require - // structural type imports to be satisfied. + // Not all arguments need to be provided for instantiation, namely the root + // component doesn't require structural type imports to be satisfied. None => { - if let ComponentEntityType::Instance(_) = ty { - let ty = types - .convert_component_entity_type(frame.types, *ty) - .map_err(Report::msg)?; - // self.import_types.push((name.0.to_string(), ty)); - let ty = match ty { - TypeDef::ComponentInstance(type_component_instance_index) => { - type_component_instance_index - } - _ => panic!("expected component instance"), - }; - frame.component_instances.push(ComponentInstanceDef::Import( - ComponentInstanceImport { - name: name.0.to_string(), - ty, - }, - )); - let interface_name = name.0.to_string(); - let module = Ident::new( - Symbol::intern(interface_name.clone()), - SourceSpan::default(), - ); - let inner_function_empty = FunctionIdent { - module: Ident::new(Symbol::intern(""), SourceSpan::default()), - function: Ident::new(Symbol::intern(""), SourceSpan::default()), - }; - // Create a component with interfaces from the imported instance type - let component_types = types.resources_mut_and_types().1; - let instance_type = &component_types[ty]; - let functions = instance_type - .exports - .iter() - .filter_map(|(name, ty)| { - if let TypeDef::ComponentFunc(func_ty) = ty { - let func_ty = - convert_lifted_func_ty(func_ty, component_types); - let signature = Signature { - params: func_ty - .params - .into_iter() - .map(AbiParam::new) - .collect(), - results: func_ty - .results - .into_iter() - .map(AbiParam::new) - .collect(), - cc: CallConv::CanonLift, - linkage: Linkage::External, - }; - Some(hir2_sketch::SyntheticFunction { - id: FunctionIdent { - module, - function: Ident::new( - Symbol::intern(name), - SourceSpan::default(), - ), - }, - signature, - inner_function: inner_function_empty, - }) - } else { - None - } - }) - .collect(); - - let interface = Interface { - name: interface_name.clone(), - functions, - }; - let import_component = Component { - name: interface_name, - interfaces: vec![interface], - modules: Default::default(), - }; - self.result.add_import(import_component); + match ty { + ComponentEntityType::Instance(_) => { + self.component_import(frame, types, name, ty)?; + } + _ => { + unsupported_diag!( + &self.session.diagnostics, + "Importing of {:?} is not yet supported", + ty + ) + } }; } }; } LocalInitializer::Lower(lower) => { - // dbg!(&init); frame.funcs.push(CoreDef::Lower(lower.clone())); } LocalInitializer::Lift(lift) => { - // dbg!(&init); frame.component_funcs.push(ComponentFuncDef::Lifted(lift.clone())); } LocalInitializer::Resource(..) => { @@ -214,144 +144,16 @@ impl<'a> ComponentTranslator2<'a> { LocalInitializer::ResourceDrop(..) => { unsupported_diag!(&self.session.diagnostics, "Resource dropping is not supported") } - LocalInitializer::ModuleStatic(static_module_index) => { - frame.modules.push(ModuleDef::Static(*static_module_index)); + LocalInitializer::ModuleStatic(static_module_idx) => { + frame.modules.push(ModuleDef::Static(*static_module_idx)); } LocalInitializer::ModuleInstantiate(module_idx, ref args) => { - frame.module_instances.push(ModuleInstanceDef::Instantiated { - module_idx: *module_idx, - args: args.clone(), - }); - - let mut import_canon_lower_args: FxHashMap = - FxHashMap::default(); - match &frame.modules[*module_idx] { - ModuleDef::Static(static_module_index) => { - let parsed_module = &self.nested_modules[*static_module_index]; - let mut module = Module { - name: parsed_module.module.name(), - functions: vec![], - }; - for module_arg in args { - let arg_module_name = module_arg.0; - let module_ident = - Ident::new(Symbol::intern(*arg_module_name), SourceSpan::default()); - let arg_module = &frame.module_instances[*module_arg.1]; - match arg_module { - ModuleInstanceDef::Instantiated { - module_idx: _, - args: _, - } => { - unsupported_diag!( - &self.session.diagnostics, - "Instantiated module as another module instantiation \ - argument is not supported yet" - ) - } - ModuleInstanceDef::Synthetic(hash_map) => { - // module with CanonLower synthetic functions - for (func_name, entity) in hash_map.iter() { - let func_id = entity.unwrap_func(); - let canon_lower = frame.funcs[func_id].unwrap_canon_lower(); - let func_name_ident = Ident::new( - Symbol::intern(*func_name), - SourceSpan::default(), - ); - // TODO: handle error - let type_func_idx = types - .convert_component_func_type( - frame.types, - canon_lower.lower_ty, - ) - .unwrap(); - - let component_types = types.resources_mut_and_types().1; - let func_ty = - convert_lifted_func_ty(&type_func_idx, component_types); - let signature = Signature { - params: func_ty - .params - .into_iter() - .map(AbiParam::new) - .collect(), - results: func_ty - .results - .into_iter() - .map(AbiParam::new) - .collect(), - cc: CallConv::CanonLower, - linkage: Linkage::External, - }; - - let func_id = FunctionIdent { - module: module_ident, - function: func_name_ident, - }; - import_canon_lower_args.insert(func_id, signature); - } - } - } - } - - // TODO: the part below happens inside `build_ir` while translating the - // core module with `import_canon_lower_args` passed as a parameter. - for import in &parsed_module.module.imports { - // find the CanonLower function signature in the instantiation args for - // every core module function import - let internal_import_func_name = match import.index { - EntityIndex::Function(func_index) => { - parsed_module.module.func_name(func_index) - } - _ => panic!( - "only function import supported in Wasm core modules yet, got \ - {:?}", - import.index - ), - }; - let import_func_id = FunctionIdent { - module: Ident::new( - Symbol::intern(&import.module), - SourceSpan::default(), - ), - function: Ident::new( - Symbol::intern(&import.field), - SourceSpan::default(), - ), - }; - // TODO: handle error - let import_canon_lower_func_sig = - &import_canon_lower_args.remove(&import_func_id).unwrap(); - - let internal_func_id = FunctionIdent { - module: module.name, - function: Ident::new( - internal_import_func_name, - SourceSpan::default(), - ), - }; - let function = hir2_sketch::SyntheticFunction { - id: internal_func_id, - signature: import_canon_lower_func_sig.clone(), - inner_function: import_func_id, - }; - module.functions.push(function); - } - - self.result.root_mut().modules.push(module); - } - ModuleDef::Import(_type_module_index) => { - panic!("Module import instantiation is not supported yet") - } - }; + self.module_instantiation(frame, types, module_idx, args)?; } - LocalInitializer::ModuleSynthetic(hash_map) => { - frame.module_instances.push(ModuleInstanceDef::Synthetic(hash_map)); + LocalInitializer::ModuleSynthetic(entities) => { + frame.module_instances.push(ModuleInstanceDef::Synthetic(entities)); } LocalInitializer::ComponentStatic(idx, ref vars) => { - // dbg!(&init); - // let comp = &parsed_root_component.static_components[*idx]; - // dbg!(&comp.initializers); - // dbg!(&comp.exports); frame.components.push(ComponentDef { index: *idx, closure: ComponentClosure { @@ -375,7 +177,6 @@ impl<'a> ComponentTranslator2<'a> { ty: _, }, ) => { - // dbg!(&init); let component: &ComponentDef = &frame.components[*component]; let translation = &self.nested_components[component.index]; @@ -393,12 +194,14 @@ impl<'a> ComponentTranslator2<'a> { .push(ComponentInstanceDef::Instantiated(instance.clone())); frame.frames.insert(instance_idx, new_frame); } - LocalInitializer::ComponentSynthetic(_hash_map) => { - // dbg!(&init); + LocalInitializer::ComponentSynthetic(_) => { + unsupported_diag!( + &self.session.diagnostics, + "Synthetic components are not yet supported" + ) } - LocalInitializer::AliasExportFunc(module_instance_index, name) => { - // dbg!(&init); - frame.funcs.push(CoreDef::Export(*module_instance_index, name)); + LocalInitializer::AliasExportFunc(module_instance_idx, name) => { + frame.funcs.push(CoreDef::Export(*module_instance_idx, name)); } LocalInitializer::AliasExportTable(..) => { unsupported_diag!(&self.session.diagnostics, "Table exports are not yet supported") @@ -407,15 +210,14 @@ impl<'a> ComponentTranslator2<'a> { unsupported_diag!(&self.session.diagnostics, "Global exports are not yet supported") } LocalInitializer::AliasExportMemory(..) => { - // dbg!(&init); // Do nothing, assuming Rust compiled code having one memory instance. } - LocalInitializer::AliasComponentExport(component_instance_index, name) => { - let import = &frame.component_instances[*component_instance_index].unwrap_import(); + LocalInitializer::AliasComponentExport(component_instance_idx, name) => { + let import = &frame.component_instances[*component_instance_idx].unwrap_import(); let def = ComponentItemDef::from_import( name, types[import.ty].exports[*name], - *component_instance_index, + *component_instance_idx, ); frame.push_item(def); } @@ -429,128 +231,339 @@ impl<'a> ComponentTranslator2<'a> { ) } LocalInitializer::Export(name, component_item) => { - // dbg!(&init); match component_item { ComponentItem::Func(i) => { frame.component_funcs.push(frame.component_funcs[*i].clone()); - return Ok(()); } ComponentItem::ComponentInstance(_) => { - // handle below + let unwrap_instance = component_item.unwrap_instance(); + let interface_name = name.to_string(); + self.component_export(frame, types, unwrap_instance, interface_name)?; + } + ComponentItem::Type(_) => { + // do nothing } - ComponentItem::Type(_) => return Ok(()), // do nothing _ => unsupported_diag!( &self.session.diagnostics, "Exporting of {:?} is not yet supported", component_item ), } - // FIX: ugly - assert!( - matches!(component_item, ComponentItem::ComponentInstance(_)), - "only component instances exports supported here" - ); - let interface_name = name.to_string(); - let instance = &frame.component_instances[component_item.unwrap_instance()] - .unwrap_instantiated(); - let static_component_idx = frame.components[instance.component].index; - let parsed_component = &self.nested_components[static_component_idx]; - // dbg!(&parsed_component.exports); - let module = - Ident::new(Symbol::intern(interface_name.clone()), SourceSpan::default()); - dbg!(&parsed_component.exports); - let functions = parsed_component - .exports - .iter() - .flat_map(|(name, item)| { - if let ComponentItem::Func(f) = item { - // dbg!(&component_funcs, f, name); - dbg!(&parsed_component.initializers); - let component_instance_idx = component_item.unwrap_instance(); - let nested_frame = &frame.frames[&component_instance_idx]; - dbg!(&nested_frame.component_funcs); - dbg!(&f); - let canon_lift = nested_frame.component_funcs[*f].unwrap_canon_lift(); - let core_func_id: FunctionIdent = match &frame.funcs[canon_lift.func] { - CoreDef::Export(module_instance_index, name) => { - match &frame.module_instances[*module_instance_index] { - ModuleInstanceDef::Instantiated { - module_idx, - args: _, - } => match frame.modules[*module_idx] { - ModuleDef::Static(static_module_index) => { - let parsed_module = - &self.nested_modules[static_module_index]; - let func_idx = parsed_module.module.exports[*name] - .unwrap_func(); - let func_name = - parsed_module.module.func_name(func_idx); - let module_ident = parsed_module.module.name(); - FunctionIdent { - module: module_ident, - function: Ident::new( - func_name, - SourceSpan::default(), - ), - } - } - ModuleDef::Import(_type_module_index) => { - panic!("expected static module") - } - }, - ModuleInstanceDef::Synthetic(_hash_map) => { - panic!("expected instantiated module") - } - } - } - CoreDef::Lower(canon_lower) => { - panic!("expected export, got {:?}", canon_lower) - } - }; - let type_func_idx = types - .convert_component_func_type(frame.types, canon_lift.ty) - .unwrap(); - - let component_types = types.resources_mut_and_types().1; - let func_ty = convert_lifted_func_ty(&type_func_idx, component_types); - let signature = Signature { - params: func_ty.params.into_iter().map(AbiParam::new).collect(), - results: func_ty.results.into_iter().map(AbiParam::new).collect(), - cc: CallConv::CanonLift, - linkage: Linkage::External, - }; - - let function_id = FunctionIdent { - module, - function: Ident::new( - Symbol::intern(name.to_string()), - SourceSpan::default(), - ), - }; - let function = hir2_sketch::SyntheticFunction { - id: function_id, - signature, - inner_function: core_func_id, - }; - vec![function] - } else { - // we're only interested in exported functions - vec![] + } + } + Ok(()) + } + + fn component_export( + &mut self, + frame: &mut ComponentFrame<'a>, + types: &mut ComponentTypesBuilder, + component_instance_idx: ComponentInstanceIndex, + interface_name: String, + ) -> Result<(), Report> { + let instance = &frame.component_instances[component_instance_idx].unwrap_instantiated(); + let static_component_idx = frame.components[instance.component].index; + let parsed_component = &self.nested_components[static_component_idx]; + let module = Ident::new(Symbol::intern(interface_name.clone()), SourceSpan::default()); + let functions = parsed_component + .exports + .iter() + .flat_map(|(name, item)| { + if let ComponentItem::Func(f) = item { + self.component_export_func( + frame, + types, + component_instance_idx, + module, + name, + f, + ) + } else { + // we're only interested in exported functions + vec![] + } + }) + .collect(); + let interface = Interface { + name: interface_name, + functions, + }; + self.result.root_mut().interfaces.push(interface); + frame.component_instances.push(ComponentInstanceDef::Export); + Ok(()) + } + + fn component_export_func( + &self, + frame: &ComponentFrame<'a>, + types: &mut ComponentTypesBuilder, + component_instance_idx: ComponentInstanceIndex, + module: Ident, + name: &str, + f: &ComponentFuncIndex, + ) -> Vec { + let nested_frame = &frame.frames[&component_instance_idx]; + let canon_lift = nested_frame.component_funcs[*f].unwrap_canon_lift(); + let type_func_idx = types.convert_component_func_type(frame.types, canon_lift.ty).unwrap(); + + let component_types = types.resources_mut_and_types().1; + let func_ty = convert_lifted_func_ty(&type_func_idx, component_types); + let signature = Signature { + params: func_ty.params.into_iter().map(AbiParam::new).collect(), + results: func_ty.results.into_iter().map(AbiParam::new).collect(), + cc: CallConv::CanonLift, + linkage: Linkage::External, + }; + + let function_id = FunctionIdent { + module, + function: Ident::new(Symbol::intern(name.to_string()), SourceSpan::default()), + }; + let function = hir2_sketch::SyntheticFunction { + id: function_id, + signature, + inner_function: self.core_module_export_func_id(frame, canon_lift), + }; + vec![function] + } + + fn core_module_export_func_id( + &self, + frame: &ComponentFrame<'a>, + canon_lift: &CanonLift, + ) -> FunctionIdent { + let core_func_id: FunctionIdent = match &frame.funcs[canon_lift.func] { + CoreDef::Export(module_instance_idx, name) => { + match &frame.module_instances[*module_instance_idx] { + ModuleInstanceDef::Instantiated { + module_idx, + args: _, + } => match frame.modules[*module_idx] { + ModuleDef::Static(static_module_idx) => { + let parsed_module = &self.nested_modules[static_module_idx]; + let func_idx = parsed_module.module.exports[*name].unwrap_func(); + let func_name = parsed_module.module.func_name(func_idx); + let module_ident = parsed_module.module.name(); + FunctionIdent { + module: module_ident, + function: Ident::new(func_name, SourceSpan::default()), + } + } + ModuleDef::Import(_) => { + panic!("expected static module") } - }) - .collect(); - let interface = Interface { - name: interface_name, - functions, + }, + ModuleInstanceDef::Synthetic(_hash_map) => { + panic!("expected instantiated module") + } + } + } + CoreDef::Lower(canon_lower) => { + panic!("expected export, got {:?}", canon_lower) + } + }; + core_func_id + } + + fn module_instantiation( + &mut self, + frame: &mut ComponentFrame<'a>, + types: &mut ComponentTypesBuilder, + module_idx: &ModuleIndex, + args: &'a FxHashMap<&str, ModuleInstanceIndex>, + ) -> Result<(), Report> { + frame.module_instances.push(ModuleInstanceDef::Instantiated { + module_idx: *module_idx, + args: args.clone(), + }); + + let mut import_canon_lower_args: FxHashMap = FxHashMap::default(); + match &frame.modules[*module_idx] { + ModuleDef::Static(static_module_idx) => { + let parsed_module = &self.nested_modules[*static_module_idx]; + let mut module = Module { + name: parsed_module.module.name(), + functions: vec![], }; - self.result.root_mut().interfaces.push(interface); - frame.component_instances.push(ComponentInstanceDef::Export); + for module_arg in args { + let arg_module_name = module_arg.0; + let module_ident = + Ident::new(Symbol::intern(*arg_module_name), SourceSpan::default()); + let arg_module = &frame.module_instances[*module_arg.1]; + match arg_module { + ModuleInstanceDef::Instantiated { + module_idx: _, + args: _, + } => { + unsupported_diag!( + &self.session.diagnostics, + "Instantiated module as another module instantiation argument is \ + not supported yet" + ) + } + ModuleInstanceDef::Synthetic(entities) => { + // module with CanonLower synthetic functions + for (func_name, entity) in entities.iter() { + let (signature, func_id) = + canon_lower_func(frame, types, module_ident, func_name, entity); + import_canon_lower_args.insert(func_id, signature); + } + } + } + } + + // TODO: the part below happens inside `build_ir` while translating the + // core module with `import_canon_lower_args` passed as a parameter. + for import in &parsed_module.module.imports { + // find the CanonLower function signature in the instantiation args for + // every core module function import + let internal_import_func_name = match import.index { + EntityIndex::Function(func_idx) => parsed_module.module.func_name(func_idx), + _ => panic!( + "only function import supported in Wasm core modules yet, got {:?}", + import.index + ), + }; + let import_func_id = FunctionIdent { + module: Ident::new(Symbol::intern(&import.module), SourceSpan::default()), + function: Ident::new(Symbol::intern(&import.field), SourceSpan::default()), + }; + // TODO: handle error + let import_canon_lower_func_sig = + &import_canon_lower_args.remove(&import_func_id).unwrap(); + + let internal_func_id = FunctionIdent { + module: module.name, + function: Ident::new(internal_import_func_name, SourceSpan::default()), + }; + let function = hir2_sketch::SyntheticFunction { + id: internal_func_id, + signature: import_canon_lower_func_sig.clone(), + inner_function: import_func_id, + }; + module.functions.push(function); + } + + self.result.root_mut().modules.push(module); } - } + ModuleDef::Import(_) => { + panic!("Module import instantiation is not supported yet") + } + }; + Ok(()) + } + + fn component_import( + &mut self, + frame: &mut ComponentFrame<'a>, + types: &mut ComponentTypesBuilder, + name: &wasmparser::ComponentImportName<'_>, + ty: &ComponentEntityType, + ) -> Result<(), Report> { + let ty = types.convert_component_entity_type(frame.types, *ty).map_err(Report::msg)?; + let ty = match ty { + TypeDef::ComponentInstance(type_component_instance_idx) => type_component_instance_idx, + _ => panic!("expected component instance"), + }; + frame + .component_instances + .push(ComponentInstanceDef::Import(ComponentInstanceImport { + name: name.0.to_string(), + ty, + })); + let interface_name = name.0.to_string(); + let module = Ident::new(Symbol::intern(interface_name.clone()), SourceSpan::default()); + let inner_function_empty = FunctionIdent { + module: Ident::new(Symbol::intern(""), SourceSpan::default()), + function: Ident::new(Symbol::intern(""), SourceSpan::default()), + }; + let component_types = types.resources_mut_and_types().1; + let instance_type = &component_types[ty]; + let functions = instance_type + .exports + .iter() + .filter_map(|(name, ty)| { + import_component_export_func( + module, + inner_function_empty, + component_types, + name, + ty, + ) + }) + .collect(); + let interface = Interface { + name: interface_name.clone(), + functions, + }; + let import_component = Component { + name: interface_name, + interfaces: vec![interface], + modules: Default::default(), + }; + self.result.add_import(import_component); Ok(()) } } +fn import_component_export_func( + module: Ident, + inner_function_empty: FunctionIdent, + component_types: &super::ComponentTypes, + name: &String, + ty: &TypeDef, +) -> Option { + if let TypeDef::ComponentFunc(func_ty) = ty { + let func_ty = convert_lifted_func_ty(func_ty, component_types); + let signature = Signature { + params: func_ty.params.into_iter().map(AbiParam::new).collect(), + results: func_ty.results.into_iter().map(AbiParam::new).collect(), + cc: CallConv::CanonLift, + linkage: Linkage::External, + }; + Some(hir2_sketch::SyntheticFunction { + id: FunctionIdent { + module, + function: Ident::new(Symbol::intern(name), SourceSpan::default()), + }, + signature, + inner_function: inner_function_empty, + }) + } else { + None + } +} + +fn canon_lower_func( + frame: &mut ComponentFrame, + types: &mut ComponentTypesBuilder, + module_ident: Ident, + func_name: &str, + entity: &EntityIndex, +) -> (Signature, FunctionIdent) { + let func_id = entity.unwrap_func(); + let canon_lower = frame.funcs[func_id].unwrap_canon_lower(); + let func_name_ident = Ident::new(Symbol::intern(func_name), SourceSpan::default()); + // TODO: handle error + let type_func_idx = + types.convert_component_func_type(frame.types, canon_lower.lower_ty).unwrap(); + + let component_types = types.resources_mut_and_types().1; + let func_ty = convert_lifted_func_ty(&type_func_idx, component_types); + let signature = Signature { + params: func_ty.params.into_iter().map(AbiParam::new).collect(), + results: func_ty.results.into_iter().map(AbiParam::new).collect(), + cc: CallConv::CanonLower, + linkage: Linkage::External, + }; + + let func_id = FunctionIdent { + module: module_ident, + function: func_name_ident, + }; + (signature, func_id) +} + #[derive(Clone, Debug)] enum ComponentInstanceDef<'a> { Import(ComponentInstanceImport), @@ -723,7 +736,6 @@ struct ComponentFrame<'a> { impl<'a> ComponentFrame<'a> { fn new(types: TypesRef<'a>, args: FxHashMap<&'a str, ComponentItemDef<'a>>) -> Self { Self { - // initializers: translation.initializers.iter(), types, funcs: PrimaryMap::new(), component_funcs: PrimaryMap::new(), From 96afbe1d08128d04f1ae98779a86f69c10a966ec Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Tue, 14 Jan 2025 16:33:05 +0200 Subject: [PATCH 14/18] chore: fix the build after the rebase --- frontend-wasm/src/component/parser.rs | 4 +--- frontend-wasm/src/component/translator.rs | 5 ++--- frontend-wasm/src/component/translator2.rs | 5 ++--- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/frontend-wasm/src/component/parser.rs b/frontend-wasm/src/component/parser.rs index 2812a15d1..baa8462b1 100644 --- a/frontend-wasm/src/component/parser.rs +++ b/frontend-wasm/src/component/parser.rs @@ -7,9 +7,7 @@ use std::mem; use indexmap::IndexMap; use midenc_hir::{ - cranelift_entity::PrimaryMap, - diagnostics::{IntoDiagnostic, Severity}, - FxBuildHasher, FxHashMap, + cranelift_entity::PrimaryMap, diagnostics::IntoDiagnostic, FxBuildHasher, FxHashMap, }; use midenc_session::Session; use wasmparser::{ diff --git a/frontend-wasm/src/component/translator.rs b/frontend-wasm/src/component/translator.rs index ef4a4024d..ad4aa3019 100644 --- a/frontend-wasm/src/component/translator.rs +++ b/frontend-wasm/src/component/translator.rs @@ -1,7 +1,6 @@ use midenc_hir::{ - cranelift_entity::PrimaryMap, diagnostics::Severity, CanonAbiImport, ComponentBuilder, - ComponentExport, FunctionIdent, FunctionType, FxHashMap, Ident, InterfaceFunctionIdent, - InterfaceIdent, MidenAbiImport, Symbol, + cranelift_entity::PrimaryMap, CanonAbiImport, ComponentBuilder, ComponentExport, FunctionIdent, + FunctionType, FxHashMap, Ident, InterfaceFunctionIdent, InterfaceIdent, MidenAbiImport, Symbol, }; use midenc_hir_type::Abi; use midenc_session::{DiagnosticsHandler, Session}; diff --git a/frontend-wasm/src/component/translator2.rs b/frontend-wasm/src/component/translator2.rs index e2d1e42dc..bab04f8cf 100644 --- a/frontend-wasm/src/component/translator2.rs +++ b/frontend-wasm/src/component/translator2.rs @@ -5,11 +5,10 @@ use hir2_sketch::{Component, Interface, Module}; use midenc_hir::{ - cranelift_entity::PrimaryMap, diagnostics::Report, AbiParam, CallConv, FunctionIdent, Ident, - Linkage, Signature, SourceSpan, Symbol, + cranelift_entity::PrimaryMap, diagnostics::Report, AbiParam, CallConv, FunctionIdent, + FxHashMap, Ident, Linkage, Signature, SourceSpan, Symbol, }; use midenc_session::{DiagnosticsHandler, Session}; -use rustc_hash::FxHashMap; use wasmparser::types::{ComponentEntityType, TypesRef}; use super::{ From 01a43621bc0f0a2e095c2652eedd5f6b91764155 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Fri, 17 Jan 2025 21:15:01 +0200 Subject: [PATCH 15/18] draft: start hir2 Component building --- Cargo.lock | 1 + frontend-wasm/Cargo.toml | 1 + frontend-wasm/src/component/build_ir.rs | 21 +- frontend-wasm/src/component/translator2.rs | 220 ++++++++++-------- .../dialects/builtin/builders/component.rs | 19 +- hir2/src/dialects/builtin/ops.rs | 2 +- hir2/src/dialects/builtin/ops/component.rs | 7 +- .../rust_sdk/hir2_sketch_multi_interface.hir | 43 ---- .../rust_sdk/hir2_sketch_single_interface.hir | 22 -- tests/integration/src/compiler_test.rs | 10 +- .../src/rust_masm_tests/rust_sdk.rs | 2 +- 11 files changed, 164 insertions(+), 184 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4c5a55d0d..651ec4310 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3380,6 +3380,7 @@ dependencies = [ "miden-thiserror", "midenc-hir", "midenc-hir-type", + "midenc-hir2", "midenc-session", "rustc-hash", "smallvec", diff --git a/frontend-wasm/Cargo.toml b/frontend-wasm/Cargo.toml index 55f45e443..793b20f64 100644 --- a/frontend-wasm/Cargo.toml +++ b/frontend-wasm/Cargo.toml @@ -24,6 +24,7 @@ log.workspace = true hashbrown.workspace = true miden-core.workspace = true midenc-hir.workspace = true +midenc-hir2.workspace = true midenc-hir-type.workspace = true midenc-session.workspace = true rustc-hash.workspace = true diff --git a/frontend-wasm/src/component/build_ir.rs b/frontend-wasm/src/component/build_ir.rs index 65f50e3d7..74ebf81aa 100644 --- a/frontend-wasm/src/component/build_ir.rs +++ b/frontend-wasm/src/component/build_ir.rs @@ -1,4 +1,7 @@ +use std::rc::Rc; + use midenc_hir::diagnostics::Report; +use midenc_hir2::{dialects::builtin::BuiltinDialect, Context}; use midenc_session::Session; use super::{ @@ -66,18 +69,18 @@ fn inline( pub fn translate_component2( wasm: &[u8], config: &WasmTranslationConfig, - session: &Session, -) -> WasmResult { - let (mut component_types_builder, parsed_root_component) = parse(config, wasm, session)?; + session: Rc, +) -> WasmResult { + let (mut component_types_builder, parsed_root_component) = parse(config, wasm, &session)?; + let context = Rc::new(Context::new(session)); + let dialect = context.get_or_register_dialect::(); + dialect.expect_registered_name::(); + // context.get_or_register_dialect::(); let translator = ComponentTranslator2::new( &parsed_root_component.static_modules, &parsed_root_component.static_components, config, - session, + context, ); - translator.translate2( - &parsed_root_component.root_component, - &mut component_types_builder, - session.diagnostics.as_ref(), - ) + translator.translate2(&parsed_root_component.root_component, &mut component_types_builder) } diff --git a/frontend-wasm/src/component/translator2.rs b/frontend-wasm/src/component/translator2.rs index bab04f8cf..9c84330f8 100644 --- a/frontend-wasm/src/component/translator2.rs +++ b/frontend-wasm/src/component/translator2.rs @@ -1,13 +1,20 @@ -// TODO: remove after its completed +// TODO:remove after its completed #![allow(unused)] // TODO: document -use hir2_sketch::{Component, Interface, Module}; +use std::{borrow::BorrowMut, rc::Rc}; + use midenc_hir::{ cranelift_entity::PrimaryMap, diagnostics::Report, AbiParam, CallConv, FunctionIdent, FxHashMap, Ident, Linkage, Signature, SourceSpan, Symbol, }; +use midenc_hir2::{ + self as hir2, + dialects::builtin::{Component, ComponentBuilder, ComponentRef}, + version::Version, + BuilderExt, Context, EntityMut, OpBuilder, +}; use midenc_session::{DiagnosticsHandler, Session}; use wasmparser::types::{ComponentEntityType, TypesRef}; @@ -51,9 +58,9 @@ pub struct ComponentTranslator2<'a> { /// `ComponentFrame` with the `ParsedComponent`s here. nested_components: &'a PrimaryMap>, - result: hir2_sketch::WorldBuilder, + result: ComponentBuilder, - session: &'a Session, + context: Rc, } impl<'a> ComponentTranslator2<'a> { @@ -61,15 +68,23 @@ impl<'a> ComponentTranslator2<'a> { nested_modules: &'a PrimaryMap>, nested_components: &'a PrimaryMap>, config: &'a WasmTranslationConfig, - session: &'a Session, + context: Rc, ) -> Self { - let builder = hir2_sketch::WorldBuilder::new("root".to_string()); + let mut builder = context.clone().builder(); + let component_builder = + builder.create::(Default::default()); + // TODO: get proper ns and name (from exported interfaces?) + let ns = hir2::Ident::from("root_ns"); + let name = hir2::Ident::from("root"); + let ver = Version::parse("1.0.0").unwrap(); + let mut raw_entity_ref = component_builder(ns, name, ver).unwrap(); + let result = ComponentBuilder::new(raw_entity_ref); Self { config, - session, + context, nested_modules, nested_components, - result: builder, + result, } } @@ -77,15 +92,14 @@ impl<'a> ComponentTranslator2<'a> { mut self, root_component: &'a ParsedComponent, types: &mut ComponentTypesBuilder, - _diagnostics: &DiagnosticsHandler, - ) -> WasmResult { + ) -> WasmResult { let mut frame = ComponentFrame::new(root_component.types_ref(), FxHashMap::default()); for init in &root_component.initializers { self.initializer(&mut frame, types, init)?; } - Ok(self.result.build()) + Ok(self.result.component) } fn initializer( @@ -110,7 +124,7 @@ impl<'a> ComponentTranslator2<'a> { } _ => { unsupported_diag!( - &self.session.diagnostics, + &self.context.session.diagnostics, "Importing of {:?} is not yet supported", ty ) @@ -127,21 +141,27 @@ impl<'a> ComponentTranslator2<'a> { } LocalInitializer::Resource(..) => { unsupported_diag!( - &self.session.diagnostics, + &self.context.session.diagnostics, "Resource initializers are not supported" ) } LocalInitializer::ResourceNew(..) => { - unsupported_diag!(&self.session.diagnostics, "Resource creation is not supported") + unsupported_diag!( + &self.context.session.diagnostics, + "Resource creation is not supported" + ) } LocalInitializer::ResourceRep(..) => { unsupported_diag!( - &self.session.diagnostics, + &self.context.session.diagnostics, "Resource representation is not supported" ) } LocalInitializer::ResourceDrop(..) => { - unsupported_diag!(&self.session.diagnostics, "Resource dropping is not supported") + unsupported_diag!( + &self.context.session.diagnostics, + "Resource dropping is not supported" + ) } LocalInitializer::ModuleStatic(static_module_idx) => { frame.modules.push(ModuleDef::Static(*static_module_idx)); @@ -195,7 +215,7 @@ impl<'a> ComponentTranslator2<'a> { } LocalInitializer::ComponentSynthetic(_) => { unsupported_diag!( - &self.session.diagnostics, + &self.context.session.diagnostics, "Synthetic components are not yet supported" ) } @@ -203,10 +223,16 @@ impl<'a> ComponentTranslator2<'a> { frame.funcs.push(CoreDef::Export(*module_instance_idx, name)); } LocalInitializer::AliasExportTable(..) => { - unsupported_diag!(&self.session.diagnostics, "Table exports are not yet supported") + unsupported_diag!( + &self.context.session.diagnostics, + "Table exports are not yet supported" + ) } LocalInitializer::AliasExportGlobal(..) => { - unsupported_diag!(&self.session.diagnostics, "Global exports are not yet supported") + unsupported_diag!( + &self.context.session.diagnostics, + "Global exports are not yet supported" + ) } LocalInitializer::AliasExportMemory(..) => { // Do nothing, assuming Rust compiled code having one memory instance. @@ -221,11 +247,14 @@ impl<'a> ComponentTranslator2<'a> { frame.push_item(def); } LocalInitializer::AliasModule(_) => { - unsupported_diag!(&self.session.diagnostics, "Module aliases are not yet supported") + unsupported_diag!( + &self.context.session.diagnostics, + "Module aliases are not yet supported" + ) } LocalInitializer::AliasComponent(_) => { unsupported_diag!( - &self.session.diagnostics, + &self.context.session.diagnostics, "Component aliases are not yet supported" ) } @@ -243,7 +272,7 @@ impl<'a> ComponentTranslator2<'a> { // do nothing } _ => unsupported_diag!( - &self.session.diagnostics, + &self.context.session.diagnostics, "Exporting of {:?} is not yet supported", component_item ), @@ -264,30 +293,30 @@ impl<'a> ComponentTranslator2<'a> { let static_component_idx = frame.components[instance.component].index; let parsed_component = &self.nested_components[static_component_idx]; let module = Ident::new(Symbol::intern(interface_name.clone()), SourceSpan::default()); - let functions = parsed_component - .exports - .iter() - .flat_map(|(name, item)| { - if let ComponentItem::Func(f) = item { - self.component_export_func( - frame, - types, - component_instance_idx, - module, - name, - f, - ) - } else { - // we're only interested in exported functions - vec![] - } - }) - .collect(); - let interface = Interface { - name: interface_name, - functions, - }; - self.result.root_mut().interfaces.push(interface); + // let functions = parsed_component + // .exports + // .iter() + // .flat_map(|(name, item)| { + // if let ComponentItem::Func(f) = item { + // self.component_export_func( + // frame, + // types, + // component_instance_idx, + // module, + // name, + // f, + // ) + // } else { + // // we're only interested in exported functions + // vec![] + // } + // }) + // .collect(); + // let interface = Interface { + // name: interface_name, + // functions, + // }; + // self.result.root_mut().interfaces.push(interface); frame.component_instances.push(ComponentInstanceDef::Export); Ok(()) } @@ -380,10 +409,10 @@ impl<'a> ComponentTranslator2<'a> { match &frame.modules[*module_idx] { ModuleDef::Static(static_module_idx) => { let parsed_module = &self.nested_modules[*static_module_idx]; - let mut module = Module { - name: parsed_module.module.name(), - functions: vec![], - }; + // let mut module = Module { + // name: parsed_module.module.name(), + // functions: vec![], + // }; for module_arg in args { let arg_module_name = module_arg.0; let module_ident = @@ -395,7 +424,7 @@ impl<'a> ComponentTranslator2<'a> { args: _, } => { unsupported_diag!( - &self.session.diagnostics, + &self.context.session.diagnostics, "Instantiated module as another module instantiation argument is \ not supported yet" ) @@ -431,19 +460,19 @@ impl<'a> ComponentTranslator2<'a> { let import_canon_lower_func_sig = &import_canon_lower_args.remove(&import_func_id).unwrap(); - let internal_func_id = FunctionIdent { - module: module.name, - function: Ident::new(internal_import_func_name, SourceSpan::default()), - }; - let function = hir2_sketch::SyntheticFunction { - id: internal_func_id, - signature: import_canon_lower_func_sig.clone(), - inner_function: import_func_id, - }; - module.functions.push(function); + // let internal_func_id = FunctionIdent { + // module: module.name, + // function: Ident::new(internal_import_func_name, SourceSpan::default()), + // }; + // let function = hir2_sketch::SyntheticFunction { + // id: internal_func_id, + // signature: import_canon_lower_func_sig.clone(), + // inner_function: import_func_id, + // }; + // module.functions.push(function); } - self.result.root_mut().modules.push(module); + // self.result.root_mut().modules.push(module); } ModuleDef::Import(_) => { panic!("Module import instantiation is not supported yet") @@ -470,37 +499,42 @@ impl<'a> ComponentTranslator2<'a> { name: name.0.to_string(), ty, })); - let interface_name = name.0.to_string(); - let module = Ident::new(Symbol::intern(interface_name.clone()), SourceSpan::default()); - let inner_function_empty = FunctionIdent { - module: Ident::new(Symbol::intern(""), SourceSpan::default()), - function: Ident::new(Symbol::intern(""), SourceSpan::default()), - }; - let component_types = types.resources_mut_and_types().1; - let instance_type = &component_types[ty]; - let functions = instance_type - .exports - .iter() - .filter_map(|(name, ty)| { - import_component_export_func( - module, - inner_function_empty, - component_types, - name, - ty, - ) - }) - .collect(); - let interface = Interface { - name: interface_name.clone(), - functions, - }; - let import_component = Component { - name: interface_name, - interfaces: vec![interface], - modules: Default::default(), - }; - self.result.add_import(import_component); + // TODO: create World in hir2 + // + // let interface_name = name.0.to_string(); + // let module = Ident::new(Symbol::intern(interface_name.clone()), SourceSpan::default()); + // let inner_function_empty = FunctionIdent { + // module: Ident::new(Symbol::intern(""), SourceSpan::default()), + // function: Ident::new(Symbol::intern(""), SourceSpan::default()), + // }; + // let component_types = types.resources_mut_and_types().1; + // let instance_type = &component_types[ty]; + // let functions = instance_type + // // TODO: need `exports` to have a stable order or find a different source for the + // // function list + // // + // .exports + // .iter() + // .filter_map(|(name, ty)| { + // import_component_export_func( + // module, + // inner_function_empty, + // component_types, + // name, + // ty, + // ) + // }) + // .collect(); + // let interface = Interface { + // name: interface_name.clone(), + // functions, + // }; + // let import_component = Component { + // name: interface_name, + // interfaces: vec![interface], + // modules: Default::default(), + // }; + // self.result.add_import(import_component); Ok(()) } } diff --git a/hir2/src/dialects/builtin/builders/component.rs b/hir2/src/dialects/builtin/builders/component.rs index c12bfa7a9..26b5eaf72 100644 --- a/hir2/src/dialects/builtin/builders/component.rs +++ b/hir2/src/dialects/builtin/builders/component.rs @@ -1,23 +1,24 @@ use crate::{ dialects::builtin::{ - Component, InterfaceRef, ModuleRef, PrimInterfaceBuilder, PrimModuleBuilder, + ComponentRef, InterfaceRef, ModuleRef, PrimInterfaceBuilder, PrimModuleBuilder, }, Builder, Ident, Op, OpBuilder, Report, Spanned, }; -pub struct ComponentBuilder<'b> { - pub component: &'b mut Component, +pub struct ComponentBuilder { + pub component: ComponentRef, builder: OpBuilder, } -impl<'b> ComponentBuilder<'b> { - pub fn new(component: &'b mut Component) -> Self { - let context = component.as_operation().context_rc(); +impl ComponentBuilder { + pub fn new(mut component: ComponentRef) -> Self { + let component_ref = component.borrow_mut(); + let context = component_ref.as_operation().context_rc(); let mut builder = OpBuilder::new(context); - if component.body().is_empty() { - builder.create_block(component.body().as_region_ref(), None, &[]); + if component_ref.body().is_empty() { + builder.create_block(component_ref.body().as_region_ref(), None, &[]); } else { - let current_block = component.body().entry_block_ref().unwrap(); + let current_block = component_ref.body().entry_block_ref().unwrap(); builder.set_insertion_point_to_end(current_block); } diff --git a/hir2/src/dialects/builtin/ops.rs b/hir2/src/dialects/builtin/ops.rs index 1e81fef3b..46bc0cc14 100644 --- a/hir2/src/dialects/builtin/ops.rs +++ b/hir2/src/dialects/builtin/ops.rs @@ -8,7 +8,7 @@ mod segment; pub use self::{ component::{ Component, ComponentBuilder as PrimComponentBuilder, ComponentExport, ComponentId, - ComponentInterface, ModuleExport, ModuleInterface, + ComponentInterface, ComponentRef, ModuleExport, ModuleInterface, }, function::{Function, FunctionBuilder as PrimFunctionBuilder, FunctionRef, LocalId}, global_variable::*, diff --git a/hir2/src/dialects/builtin/ops/component.rs b/hir2/src/dialects/builtin/ops/component.rs index 7fc5fba99..d278b4507 100644 --- a/hir2/src/dialects/builtin/ops/component.rs +++ b/hir2/src/dialects/builtin/ops/component.rs @@ -12,9 +12,12 @@ use crate::{ }, version::Version, Ident, Operation, RegionKind, RegionKindInterface, Symbol, SymbolManager, SymbolManagerMut, - SymbolMap, SymbolName, SymbolRef, SymbolTable, SymbolUseList, Usable, Visibility, + SymbolMap, SymbolName, SymbolRef, SymbolTable, SymbolUseList, UnsafeIntrusiveEntityRef, Usable, + Visibility, }; +pub type ComponentRef = UnsafeIntrusiveEntityRef; + /// A [Component] is a modular abstraction operation, i.e. it is designed to model shared-nothing /// boundaries between groups of shared-everything modules in a system. /// @@ -61,7 +64,7 @@ use crate::{ traits( SingleRegion, SingleBlock, - NoRegionArguments, + // NoRegionArguments, NoTerminator, HasOnlyGraphRegion, GraphRegionNoTerminator, diff --git a/tests/integration/expected/rust_sdk/hir2_sketch_multi_interface.hir b/tests/integration/expected/rust_sdk/hir2_sketch_multi_interface.hir index 398bdae67..aaad43c6a 100644 --- a/tests/integration/expected/rust_sdk/hir2_sketch_multi_interface.hir +++ b/tests/integration/expected/rust_sdk/hir2_sketch_multi_interface.hir @@ -1,47 +1,4 @@ (world - (component miden:base/core-types@1.0.0 - ;; Interfaces - (interface miden:base/core-types@1.0.0 - - ) - ) - - (component miden:core-import/intrinsics-mem@1.0.0 - ;; Interfaces - (interface miden:core-import/intrinsics-mem@1.0.0 - (synth_func (#miden:core-import/intrinsics-mem@1.0.0 #heap-base (cc lift) (result i32) (inner (# #)) - ) - ) - - (component miden:core-import/intrinsics-felt@1.0.0 - ;; Interfaces - (interface miden:core-import/intrinsics-felt@1.0.0 - (synth_func (#miden:core-import/intrinsics-felt@1.0.0 #add (cc lift) (param felt) (param felt) (result felt) (inner (# #)) - ) - ) - - (component miden:core-import/stdlib-crypto-hashes-blake3@1.0.0 - ;; Interfaces - (interface miden:core-import/stdlib-crypto-hashes-blake3@1.0.0 - (synth_func (#miden:core-import/stdlib-crypto-hashes-blake3@1.0.0 #hash-one-to-one (cc lift) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (inner (# #)) - ) - ) - - (component miden:core-import/account@1.0.0 - ;; Interfaces - (interface miden:core-import/account@1.0.0 - (synth_func (#miden:core-import/account@1.0.0 #add-asset (cc lift) (param felt) (param felt) (param felt) (param felt) (param i32) (inner (# #)) - (synth_func (#miden:core-import/account@1.0.0 #remove-asset (cc lift) (param felt) (param felt) (param felt) (param felt) (param i32) (inner (# #)) - ) - ) - - (component miden:core-import/tx@1.0.0 - ;; Interfaces - (interface miden:core-import/tx@1.0.0 - (synth_func (#miden:core-import/tx@1.0.0 #create-note (cc lift) (param felt) (param felt) (param felt) (param felt) (param felt) (param felt) (param felt) (param felt) (param felt) (param felt) (result felt) (inner (# #)) - ) - ) - (component root ;; Interfaces (interface miden:basic-wallet/basic-wallet@1.0.0 diff --git a/tests/integration/expected/rust_sdk/hir2_sketch_single_interface.hir b/tests/integration/expected/rust_sdk/hir2_sketch_single_interface.hir index d1a64dd40..a5c554435 100644 --- a/tests/integration/expected/rust_sdk/hir2_sketch_single_interface.hir +++ b/tests/integration/expected/rust_sdk/hir2_sketch_single_interface.hir @@ -1,26 +1,4 @@ (world - (component miden:base/core-types@1.0.0 - ;; Interfaces - (interface miden:base/core-types@1.0.0 - - ) - ) - - (component miden:core-import/intrinsics-mem@1.0.0 - ;; Interfaces - (interface miden:core-import/intrinsics-mem@1.0.0 - (synth_func (#miden:core-import/intrinsics-mem@1.0.0 #heap-base (cc lift) (result i32) (inner (# #)) - ) - ) - - (component miden:core-import/intrinsics-felt@1.0.0 - ;; Interfaces - (interface miden:core-import/intrinsics-felt@1.0.0 - (synth_func (#miden:core-import/intrinsics-felt@1.0.0 #add (cc lift) (param felt) (param felt) (result felt) (inner (# #)) - (synth_func (#miden:core-import/intrinsics-felt@1.0.0 #from-u32 (cc lift) (param u32) (result felt) (inner (# #)) - ) - ) - (component root ;; Interfaces (interface miden:cross-ctx-account/foo@1.0.0 diff --git a/tests/integration/src/compiler_test.rs b/tests/integration/src/compiler_test.rs index 55e1a9a7e..aaad22e40 100644 --- a/tests/integration/src/compiler_test.rs +++ b/tests/integration/src/compiler_test.rs @@ -1086,11 +1086,10 @@ impl CompilerTest { let ir = midenc_frontend_wasm::translate_component2( &self.wasm_bytes(), &self.config, - &self.session, + self.session.clone(), ) .expect("Failed to translate Wasm binary to IR component"); - // let txt = ir_components.into_iter().map(|c| c.to_string()).collect::>().join("\n"); - let src = demangle(ir.to_string()); + let src = demangle(ir.borrow().as_ref().as_operation_ref().to_string()); expected_hir_file.assert_eq(&src); } @@ -1254,7 +1253,10 @@ where { use midenc_hir::diagnostics::reporting::{self, ReportHandlerOpts}; - let result = reporting::set_hook(Box::new(|_| Box::new(ReportHandlerOpts::new().build()))); + let result = reporting::set_hook(Box::new(|_| { + let wrapping_width = 300; // avoid wrapped file paths in the backtrace + Box::new(ReportHandlerOpts::new().width(wrapping_width).build()) + })); if result.is_ok() { reporting::set_panic_hook(); } diff --git a/tests/integration/src/rust_masm_tests/rust_sdk.rs b/tests/integration/src/rust_masm_tests/rust_sdk.rs index 3b5ebcb2f..d53f21c30 100644 --- a/tests/integration/src/rust_masm_tests/rust_sdk.rs +++ b/tests/integration/src/rust_masm_tests/rust_sdk.rs @@ -236,7 +236,7 @@ fn rust_sdk_hir2_sketch_multiple_interface_exports() { } #[test] -fn rust_sdk_hir2_sketch_single_interface_export() { +fn rust_sdk_hir2_single_interface_export() { // Testing the new frontend's Wasm component translator producing HIR2(sketch) // from a Wasm component exporting one interface let _ = env_logger::builder().is_test(true).try_init(); From abc5f789eed4668dcb1e255c6306aae30275cbed Mon Sep 17 00:00:00 2001 From: Paul Schoenfelder Date: Fri, 17 Jan 2025 15:11:13 -0500 Subject: [PATCH 16/18] fix: improve location tracking of aliasing violations --- hir2/src/ir/block.rs | 4 ++++ hir2/src/ir/entity.rs | 2 ++ hir2/src/ir/entity/list.rs | 3 ++- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/hir2/src/ir/block.rs b/hir2/src/ir/block.rs index 7253e7d3e..3f7c95b75 100644 --- a/hir2/src/ir/block.rs +++ b/hir2/src/ir/block.rs @@ -624,6 +624,7 @@ impl Block { /// Insert this block after `after` in its containing region. /// /// Panics if this block is already attached to a region, or if `after` is not attached. + #[track_caller] pub fn insert_after(&mut self, after: BlockRef) { assert!( self.region.is_none(), @@ -643,6 +644,7 @@ impl Block { /// Insert this block before `before` in its containing region. /// /// Panics if this block is already attached to a region, or if `before` is not attached. + #[track_caller] pub fn insert_before(&mut self, before: BlockRef) { assert!( self.region.is_none(), @@ -662,6 +664,7 @@ impl Block { /// Insert this block at the end of `region`. /// /// Panics if this block is already attached to a region. + #[track_caller] pub fn insert_at_end(&mut self, mut region: RegionRef) { assert!( self.region.is_none(), @@ -675,6 +678,7 @@ impl Block { } /// Unlink this block from its current region and insert it right before `before` + #[track_caller] pub fn move_before(&mut self, before: BlockRef) { self.unlink(); self.insert_before(before); diff --git a/hir2/src/ir/entity.rs b/hir2/src/ir/entity.rs index e6c3d9685..2b8b9ce38 100644 --- a/hir2/src/ir/entity.rs +++ b/hir2/src/ir/entity.rs @@ -1132,11 +1132,13 @@ impl RawEntityMetadata { } } impl RawEntityMetadata { + #[track_caller] pub(crate) fn borrow(&self) -> EntityRef<'_, T> { let ptr = self as *const Self; unsafe { (*core::ptr::addr_of!((*ptr).entity)).borrow() } } + #[track_caller] pub(crate) fn borrow_mut(&self) -> EntityMut<'_, T> { let ptr = (self as *const Self).cast_mut(); unsafe { (*core::ptr::addr_of_mut!((*ptr).entity)).borrow_mut() } diff --git a/hir2/src/ir/entity/list.rs b/hir2/src/ir/entity/list.rs index d6d8b43ec..0307345b3 100644 --- a/hir2/src/ir/entity/list.rs +++ b/hir2/src/ir/entity/list.rs @@ -251,8 +251,9 @@ impl<'a, T> EntityCursor<'a, T> { /// Consume the cursor and convert it into a borrow of the current entity, or `None` if null. #[inline] + #[track_caller] pub fn into_borrow(self) -> Option> { - self.cursor.get().map(|item| item.borrow()) + Some(self.cursor.get()?.borrow()) } /// Moves the cursor to the next element of the [EntityList]. From 2087adacefaca5bd5e761ce3643962b508aa8b44 Mon Sep 17 00:00:00 2001 From: Paul Schoenfelder Date: Fri, 17 Jan 2025 15:11:36 -0500 Subject: [PATCH 17/18] fix: restructure component builder creation to avoid aliasing violation --- hir2/src/dialects/builtin/builders/component.rs | 14 ++++++++------ hir2/src/dialects/builtin/ops/component.rs | 4 ++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/hir2/src/dialects/builtin/builders/component.rs b/hir2/src/dialects/builtin/builders/component.rs index 26b5eaf72..8fea49ade 100644 --- a/hir2/src/dialects/builtin/builders/component.rs +++ b/hir2/src/dialects/builtin/builders/component.rs @@ -10,16 +10,18 @@ pub struct ComponentBuilder { builder: OpBuilder, } impl ComponentBuilder { - pub fn new(mut component: ComponentRef) -> Self { - let component_ref = component.borrow_mut(); + pub fn new(component: ComponentRef) -> Self { + let component_ref = component.borrow(); let context = component_ref.as_operation().context_rc(); let mut builder = OpBuilder::new(context); - if component_ref.body().is_empty() { - builder.create_block(component_ref.body().as_region_ref(), None, &[]); - } else { - let current_block = component_ref.body().entry_block_ref().unwrap(); + let body = component_ref.body(); + if let Some(current_block) = body.entry_block_ref() { builder.set_insertion_point_to_end(current_block); + } else { + let body_ref = body.as_region_ref(); + drop(body); + builder.create_block(body_ref, None, &[]); } Self { component, builder } diff --git a/hir2/src/dialects/builtin/ops/component.rs b/hir2/src/dialects/builtin/ops/component.rs index d278b4507..61def999f 100644 --- a/hir2/src/dialects/builtin/ops/component.rs +++ b/hir2/src/dialects/builtin/ops/component.rs @@ -7,8 +7,8 @@ use crate::{ derive::operation, dialects::builtin::BuiltinDialect, traits::{ - GraphRegionNoTerminator, HasOnlyGraphRegion, IsolatedFromAbove, NoRegionArguments, - NoTerminator, SingleBlock, SingleRegion, + GraphRegionNoTerminator, HasOnlyGraphRegion, IsolatedFromAbove, NoTerminator, SingleBlock, + SingleRegion, }, version::Version, Ident, Operation, RegionKind, RegionKindInterface, Symbol, SymbolManager, SymbolManagerMut, From 769c7148c81fe6e914f7095749c00360e2c00dd3 Mon Sep 17 00:00:00 2001 From: Paul Schoenfelder Date: Fri, 17 Jan 2025 15:22:05 -0500 Subject: [PATCH 18/18] fix: update expect test for hir2 integration --- .../rust_sdk/hir2_sketch_single_interface.wat | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/tests/integration/expected/rust_sdk/hir2_sketch_single_interface.wat b/tests/integration/expected/rust_sdk/hir2_sketch_single_interface.wat index c46fcf3b0..2dd920661 100644 --- a/tests/integration/expected/rust_sdk/hir2_sketch_single_interface.wat +++ b/tests/integration/expected/rust_sdk/hir2_sketch_single_interface.wat @@ -128,21 +128,24 @@ i32.const 32 i32.gt_u select - local.tee 1 + local.tee 3 i32.popcnt i32.const 1 i32.ne br_if 0 (;@1;) i32.const -2147483648 local.get 1 + local.get 3 + call $core::ptr::alignment::Alignment::max + local.tee 1 i32.sub local.get 2 i32.lt_u br_if 0 (;@1;) i32.const 0 local.set 3 - local.get 1 local.get 2 + local.get 1 i32.add i32.const -1 i32.add @@ -187,7 +190,15 @@ end unreachable ) - (func $cabi_realloc (;12;) (type 5) (param i32 i32 i32 i32) (result i32) + (func $core::ptr::alignment::Alignment::max (;12;) (type 4) (param i32 i32) (result i32) + local.get 0 + local.get 1 + local.get 0 + local.get 1 + i32.gt_u + select + ) + (func $cabi_realloc (;13;) (type 5) (param i32 i32 i32 i32) (result i32) local.get 0 local.get 1 local.get 2