diff --git a/compiler/constrain/src/module.rs b/compiler/constrain/src/module.rs index c8c1a24992..9a7e690d09 100644 --- a/compiler/constrain/src/module.rs +++ b/compiler/constrain/src/module.rs @@ -22,17 +22,7 @@ pub struct ConstrainedModule { pub constraint: Constraint, } -pub fn constrain_module( - aliases: &MutMap, - declarations: &[Declaration], - home: ModuleId, -) -> Constraint { - let mut send_aliases = SendMap::default(); - - for (symbol, alias) in aliases.iter() { - send_aliases.insert(*symbol, alias.clone()); - } - +pub fn constrain_module(declarations: &[Declaration], home: ModuleId) -> Constraint { constrain_decls(home, declarations) } diff --git a/compiler/gen_wasm/src/backend.rs b/compiler/gen_wasm/src/backend.rs index 2bc4fd6357..c94129e9e5 100644 --- a/compiler/gen_wasm/src/backend.rs +++ b/compiler/gen_wasm/src/backend.rs @@ -277,6 +277,7 @@ impl<'a> WasmBackend<'a> { location, size, alignment_bytes, + .. } => { let (from_ptr, from_offset) = location.local_and_offset(self.storage.stack_frame_pointer); @@ -623,6 +624,21 @@ impl<'a> WasmBackend<'a> { } StoredValue::StackMemory { location, .. } => match lit { + Literal::Decimal(decimal) => { + let (local_id, offset) = + location.local_and_offset(self.storage.stack_frame_pointer); + + let lower_bits = decimal.0 as i64; + let upper_bits = (decimal.0 >> 64) as i64; + + self.code_builder.get_local(local_id); + self.code_builder.i64_const(lower_bits); + self.code_builder.i64_store(Align::Bytes8, offset); + + self.code_builder.get_local(local_id); + self.code_builder.i64_const(upper_bits); + self.code_builder.i64_store(Align::Bytes8, offset + 8); + } Literal::Str(string) => { let (local_id, offset) = location.local_and_offset(self.storage.stack_frame_pointer); diff --git a/compiler/gen_wasm/src/layout.rs b/compiler/gen_wasm/src/layout.rs index 2d55db6294..20e8550109 100644 --- a/compiler/gen_wasm/src/layout.rs +++ b/compiler/gen_wasm/src/layout.rs @@ -3,6 +3,15 @@ use roc_mono::layout::{Layout, UnionLayout}; use crate::{wasm_module::ValueType, PTR_SIZE, PTR_TYPE}; +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum StackMemoryFormat { + /// Record, Str, List, Dict, etc. + Aggregate, + Int128, + Float128, + Decimal, +} + // See README for background information on Wasm locals, memory and function calls #[derive(Debug, Clone)] pub enum WasmLayout { @@ -11,7 +20,11 @@ pub enum WasmLayout { Primitive(ValueType, u32), // Local pointer to stack memory - StackMemory { size: u32, alignment_bytes: u32 }, + StackMemory { + size: u32, + alignment_bytes: u32, + format: StackMemoryFormat, + }, // Local pointer to heap memory HeapMemory, @@ -36,6 +49,7 @@ impl WasmLayout { I128 | U128 => Self::StackMemory { size, alignment_bytes, + format: StackMemoryFormat::Int128, }, } } @@ -51,26 +65,26 @@ impl WasmLayout { F128 => Self::StackMemory { size, alignment_bytes, + format: StackMemoryFormat::Float128, }, } } + Layout::Builtin(Decimal) => Self::StackMemory { + size, + alignment_bytes, + format: StackMemoryFormat::Decimal, + }, + Layout::Builtin( - Decimal - | Str - | Dict(_, _) - | Set(_) - | List(_) - | EmptyStr - | EmptyList - | EmptyDict - | EmptySet, + Str | Dict(_, _) | Set(_) | List(_) | EmptyStr | EmptyList | EmptyDict | EmptySet, ) | Layout::Struct(_) | Layout::LambdaSet(_) | Layout::Union(NonRecursive(_)) => Self::StackMemory { size, alignment_bytes, + format: StackMemoryFormat::Aggregate, }, Layout::Union( diff --git a/compiler/gen_wasm/src/storage.rs b/compiler/gen_wasm/src/storage.rs index cf4f336c06..8cb10d739e 100644 --- a/compiler/gen_wasm/src/storage.rs +++ b/compiler/gen_wasm/src/storage.rs @@ -4,7 +4,7 @@ use bumpalo::Bump; use roc_collections::all::MutMap; use roc_module::symbol::Symbol; -use crate::layout::WasmLayout; +use crate::layout::{StackMemoryFormat, WasmLayout}; use crate::wasm_module::{Align, CodeBuilder, LocalId, ValueType, VmSymbolState}; use crate::{copy_memory, round_up_to_alignment, CopyMemoryConfig, PTR_SIZE, PTR_TYPE}; @@ -50,6 +50,7 @@ pub enum StoredValue { location: StackMemoryLocation, size: u32, alignment_bytes: u32, + format: StackMemoryFormat, }, } @@ -147,6 +148,7 @@ impl<'a> Storage<'a> { WasmLayout::StackMemory { size, alignment_bytes, + format, } => { let location = match kind { StoredValueKind::Parameter => { @@ -175,6 +177,7 @@ impl<'a> Storage<'a> { location, size: *size, alignment_bytes: *alignment_bytes, + format: *format, } } }; @@ -239,13 +242,26 @@ impl<'a> Storage<'a> { code_builder.set_top_symbol(sym); } - StoredValue::StackMemory { location, .. } => { + StoredValue::StackMemory { + location, format, .. + } => { let (local_id, offset) = location.local_and_offset(self.stack_frame_pointer); + + // Load the address of the value code_builder.get_local(local_id); if offset != 0 { code_builder.i32_const(offset as i32); code_builder.i32_add(); } + + if format != StackMemoryFormat::Aggregate { + // It's one of the 128-bit numbers, all of which we load as two i64's + // Mark the same Symbol twice in the VM value stack! Shouldn't matter except debug. + code_builder.i64_load(Align::Bytes8, offset); + code_builder.set_top_symbol(sym); + code_builder.i64_load(Align::Bytes8, offset + 8); + } + code_builder.set_top_symbol(sym); } } @@ -292,6 +308,7 @@ impl<'a> Storage<'a> { location, size, alignment_bytes, + format: StackMemoryFormat::Aggregate, } = self.get(sym) { if *size == 0 { @@ -334,6 +351,7 @@ impl<'a> Storage<'a> { location, size, alignment_bytes, + .. } => { let (from_ptr, from_offset) = location.local_and_offset(self.stack_frame_pointer); copy_memory( @@ -390,6 +408,7 @@ impl<'a> Storage<'a> { location, size, alignment_bytes, + .. } => { let (to_ptr, to_offset) = location.local_and_offset(self.stack_frame_pointer); copy_memory( @@ -490,11 +509,13 @@ impl<'a> Storage<'a> { location: to_location, size: to_size, alignment_bytes: to_alignment_bytes, + .. }, StackMemory { location: from_location, size: from_size, alignment_bytes: from_alignment_bytes, + .. }, ) => { let (from_ptr, from_offset) = diff --git a/compiler/load/src/file.rs b/compiler/load/src/file.rs index 092153bb5f..06e66705c9 100644 --- a/compiler/load/src/file.rs +++ b/compiler/load/src/file.rs @@ -3627,11 +3627,7 @@ fn fabricate_effects_module<'a>( scope, }; - let constraint = constrain_module( - &module_output.aliases, - &module_output.declarations, - module_id, - ); + let constraint = constrain_module(&module_output.declarations, module_id); let module = Module { module_id, @@ -3764,11 +3760,7 @@ where )), }; - let constraint = constrain_module( - &module_output.aliases, - &module_output.declarations, - module_id, - ); + let constraint = constrain_module(&module_output.declarations, module_id); let module = Module { module_id, diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index 334d503fdf..2dddcdda24 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -1140,8 +1140,17 @@ impl<'a> BranchInfo<'a> { #[derive(Clone, Copy, Debug, PartialEq)] pub enum ModifyRc { + /// Increment a reference count Inc(Symbol, u64), + /// Decrement a reference count Dec(Symbol), + /// A DecRef is a non-recursive reference count decrement + /// e.g. If we Dec a list of lists, then if the reference count of the outer list is one, + /// a Dec will recursively decrement all elements, then free the memory of the outer list. + /// A DecRef would just free the outer list. + /// That is dangerous because you may not free the elements, but in our Zig builtins, + /// sometimes we know we already dealt with the elements (e.g. by copying them all over + /// to a new list) and so we can just do a DecRef, which is much cheaper in such a case. DecRef(Symbol), } diff --git a/compiler/test_gen/src/gen_num.rs b/compiler/test_gen/src/gen_num.rs index 1c283bac43..0adbf3e867 100644 --- a/compiler/test_gen/src/gen_num.rs +++ b/compiler/test_gen/src/gen_num.rs @@ -358,7 +358,7 @@ fn u8_hex_int_alias() { } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn dec_float_alias() { assert_evals_to!( indoc!( diff --git a/compiler/test_gen/src/helpers/dev.rs b/compiler/test_gen/src/helpers/dev.rs index 4dcab7ccd9..5b03b95eca 100644 --- a/compiler/test_gen/src/helpers/dev.rs +++ b/compiler/test_gen/src/helpers/dev.rs @@ -5,6 +5,9 @@ use roc_can::builtins::builtin_defs_map; use roc_collections::all::MutMap; use tempfile::tempdir; +#[allow(unused_imports)] +use roc_mono::ir::PRETTY_PRINT_IR_SYMBOLS; + #[allow(dead_code)] fn promote_expr_to_module(src: &str) -> String { let mut buffer = String::from("app \"test\" provides [ main ] to \"./platform\"\n\nmain =\n"); @@ -77,7 +80,14 @@ pub fn helper( // while you're working on the dev backend! { // println!("=========== Procedures =========="); - // println!("{:?}", procedures); + // if PRETTY_PRINT_IR_SYMBOLS { + // println!(""); + // for proc in procedures.values() { + // println!("{}", proc.to_pretty(200)); + // } + // } else { + // println!("{:?}", procedures.values()); + // } // println!("=================================\n"); // println!("=========== Interns =========="); diff --git a/compiler/test_gen/src/helpers/wasm.rs b/compiler/test_gen/src/helpers/wasm.rs index 9690803549..f1633301de 100644 --- a/compiler/test_gen/src/helpers/wasm.rs +++ b/compiler/test_gen/src/helpers/wasm.rs @@ -17,6 +17,9 @@ use roc_gen_wasm::wasm_module::{ }; use roc_gen_wasm::MEMORY_NAME; +#[allow(unused_imports)] +use roc_mono::ir::PRETTY_PRINT_IR_SYMBOLS; + const TEST_WRAPPER_NAME: &str = "test_wrapper"; std::thread_local! { @@ -84,19 +87,26 @@ pub fn helper_wasm<'a, T: Wasm32TestResult>( // You can comment and uncomment this block out to get more useful information // while you're working on the wasm backend! - // { - // println!("=========== Procedures =========="); - // println!("{:?}", procedures); - // println!("=================================\n"); + { + // println!("=========== Procedures =========="); + // if PRETTY_PRINT_IR_SYMBOLS { + // println!(""); + // for proc in procedures.values() { + // println!("{}", proc.to_pretty(200)); + // } + // } else { + // println!("{:?}", procedures.values()); + // } + // println!("=================================\n"); - // println!("=========== Interns =========="); - // println!("{:?}", interns); - // println!("=================================\n"); + // println!("=========== Interns =========="); + // println!("{:?}", interns); + // println!("=================================\n"); - // println!("=========== Exposed =========="); - // println!("{:?}", exposed_to_host); - // println!("=================================\n"); - // } + // println!("=========== Exposed =========="); + // println!("{:?}", exposed_to_host); + // println!("=================================\n"); + } debug_assert_eq!(exposed_to_host.len(), 1);