diff --git a/Cargo.lock b/Cargo.lock index 5b05e59e64..db774853b7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3171,6 +3171,7 @@ dependencies = [ "inlinable_string", "libc", "maplit", + "morphic_lib", "pretty_assertions 0.5.1", "quickcheck 0.8.5", "quickcheck_macros 0.8.0", diff --git a/compiler/gen/Cargo.toml b/compiler/gen/Cargo.toml index 685b00fa3a..608038af0e 100644 --- a/compiler/gen/Cargo.toml +++ b/compiler/gen/Cargo.toml @@ -15,6 +15,7 @@ roc_builtins = { path = "../builtins" } roc_unify = { path = "../unify" } roc_solve = { path = "../solve" } roc_mono = { path = "../mono" } +morphic_lib = { path = "../../vendor/morphic_lib" } im = "14" # im and im-rc should always have the same version! im-rc = "14" # im and im-rc should always have the same version! bumpalo = { version = "3.6.1", features = ["collections"] } diff --git a/compiler/gen/src/llvm/build.rs b/compiler/gen/src/llvm/build.rs index 06e08dcdd5..bf17221a4f 100644 --- a/compiler/gen/src/llvm/build.rs +++ b/compiler/gen/src/llvm/build.rs @@ -43,6 +43,7 @@ use inkwell::values::{ }; use inkwell::OptimizationLevel; use inkwell::{AddressSpace, IntPredicate}; +use morphic_lib::FuncName; use roc_builtins::bitcode; use roc_collections::all::{ImMap, MutMap, MutSet}; use roc_module::ident::TagName; @@ -795,21 +796,32 @@ pub fn build_exp_call<'a, 'ctx, 'env>( match call_type { CallType::ByName { - name, full_layout, .. + name, + full_layout, + arg_layouts, + ret_layout, + .. } => { let mut arg_tuples: Vec = Vec::with_capacity_in(arguments.len(), env.arena); + let name_bytes = roc_mono::alias_analysis::func_name_bytes_help( + *name, + arg_layouts.iter().copied(), + *ret_layout, + ); + let func_name = FuncName(&name_bytes); + for symbol in arguments.iter() { arg_tuples.push(load_symbol(scope, symbol)); } - call_with_args( + roc_call_with_args( env, layout_ids, &full_layout, *name, - parent, + func_name, arg_tuples.into_bump_slice(), ) } @@ -3035,18 +3047,6 @@ pub fn build_procedures_return_main<'a, 'ctx, 'env>( .unwrap() } -// Coming soon -// pub enum AliasAnalysisSolutions { -// NotAvailable, -// Available(morphic_lib::Solutions), -// } -// -// impl std::fmt::Debug for AliasAnalysisSolutions { -// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { -// write!(f, "AliasAnalysisSolutions {{}}") -// } -// } - fn build_procedures_help<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, opt_level: OptLevel, @@ -3056,19 +3056,16 @@ fn build_procedures_help<'a, 'ctx, 'env>( let mut layout_ids = roc_mono::layout::LayoutIds::default(); let mut scope = Scope::default(); - // Coming Soon - // - // if false { - // let it = state.procedures.iter().map(|x| x.1); - // - // match roc_mono::alias_analysis::spec_program(it) { - // Err(e) => panic!("Error in alias analysis: {:?}", e), - // Ok(solutions) => { - // state.alias_analysis_solutions = - // AliasAnalysisSolutions::Available(solutions) - // } - // } - // } + let it = procedures.iter().map(|x| x.1); + + let solutions = match roc_mono::alias_analysis::spec_program(it) { + Err(e) => panic!("Error in alias analysis: {:?}", e), + Ok(solutions) => solutions, + }; + + let mod_solutions = solutions + .mod_solutions(roc_mono::alias_analysis::MOD_APP) + .unwrap(); // Add all the Proc headers to the module. // We have to do this in a separate pass first, @@ -3080,6 +3077,9 @@ fn build_procedures_help<'a, 'ctx, 'env>( for (proc, fn_val) in headers { let mut current_scope = scope.clone(); + let name_bytes = roc_mono::alias_analysis::func_name_bytes(&proc); + let func_name = FuncName(&name_bytes); + // only have top-level thunks for this proc's module in scope // this retain is not needed for correctness, but will cause less confusion when debugging let home = proc.name.module_id(); @@ -3569,12 +3569,12 @@ fn function_value_by_name_help<'a, 'ctx, 'env>( // #[allow(clippy::cognitive_complexity)] #[inline(always)] -fn call_with_args<'a, 'ctx, 'env>( +fn roc_call_with_args<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, layout_ids: &mut LayoutIds<'a>, layout: &Layout<'a>, symbol: Symbol, - _parent: FunctionValue<'ctx>, + _func_name: FuncName<'_>, args: &[BasicValueEnum<'ctx>], ) -> BasicValueEnum<'ctx> { let fn_val = function_value_by_name(env, layout_ids, *layout, symbol); diff --git a/compiler/mono/src/alias_analysis.rs b/compiler/mono/src/alias_analysis.rs index a044571023..6154b6b84b 100644 --- a/compiler/mono/src/alias_analysis.rs +++ b/compiler/mono/src/alias_analysis.rs @@ -17,6 +17,50 @@ pub const MOD_APP: ModName = ModName(b"UserApp"); pub const STATIC_STR_NAME: ConstName = ConstName(&Symbol::STR_ALIAS_ANALYSIS_STATIC.to_ne_bytes()); +pub fn func_name_bytes(proc: &Proc) -> [u8; 16] { + func_name_bytes_help(proc.name, proc.args.iter().map(|x| x.0), proc.ret_layout) +} + +pub fn func_name_bytes_help<'a, I>( + symbol: Symbol, + argument_layouts: I, + return_layout: Layout<'a>, +) -> [u8; 16] +where + I: Iterator>, +{ + let mut name_bytes = [0u8; 16]; + + use std::collections::hash_map::DefaultHasher; + use std::hash::Hash; + use std::hash::Hasher; + + let layout_hash = { + let mut hasher = DefaultHasher::new(); + + for layout in argument_layouts { + layout.hash(&mut hasher); + } + return_layout.hash(&mut hasher); + + hasher.finish() + }; + + let sbytes = symbol.to_ne_bytes(); + let lbytes = layout_hash.to_ne_bytes(); + + let it = sbytes + .iter() + .chain(lbytes.iter()) + .zip(name_bytes.iter_mut()); + + for (source, target) in it { + *target = *source; + } + + return name_bytes; +} + pub fn spec_program<'a, I>(procs: I) -> Result where I: Iterator>, @@ -40,36 +84,7 @@ where for proc in procs { let spec = proc_spec(proc)?; - let mut name_bytes = [0u8; 16]; - - use std::collections::hash_map::DefaultHasher; - use std::hash::Hash; - use std::hash::Hasher; - - let layout_hash = { - let mut hasher = DefaultHasher::new(); - - for (layout, _) in proc.args.iter() { - layout.hash(&mut hasher); - } - proc.ret_layout.hash(&mut hasher); - - hasher.finish() - }; - - let sbytes = proc.name.to_ne_bytes(); - let lbytes = layout_hash.to_ne_bytes(); - - let it = sbytes - .iter() - .chain(lbytes.iter()) - .zip(name_bytes.iter_mut()); - - for (source, target) in it { - *target = *source; - } - - m.add_func(FuncName(&name_bytes), spec)?; + m.add_func(FuncName(&func_name_bytes(proc)), spec)?; if format!("{:?}", proc.name).contains("mainForHost") { main_function = Some(proc.name); @@ -345,16 +360,17 @@ fn call_spec( ByName { name: symbol, full_layout: _, - ret_layout: _, - arg_layouts: _, + ret_layout, + arg_layouts, specialization_id, } => { let array = specialization_id.to_bytes(); let spec_var = CalleeSpecVar(&array); let arg_value_id = build_tuple_value(builder, env, block, call.arguments)?; - let slice = &symbol.to_ne_bytes(); - let name = FuncName(slice); + let it = arg_layouts.iter().copied(); + let bytes = func_name_bytes_help(*symbol, it, *ret_layout); + let name = FuncName(&bytes); let module = MOD_APP; builder.add_call(block, spec_var, module, name, arg_value_id) }