From c4ec9aa8983ed83db07c20a7be607584347bf416 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sat, 20 Nov 2021 23:25:30 +0100 Subject: [PATCH] working mono --- Cargo.lock | 1 + cli/src/repl/eval.rs | 6 +- compiler/builtins/src/bitcode.rs | 98 +++++++ compiler/gen_dev/src/lib.rs | 4 +- compiler/gen_llvm/src/llvm/build.rs | 12 +- compiler/gen_llvm/src/llvm/build_hash.rs | 2 +- compiler/gen_llvm/src/llvm/compare.rs | 4 +- compiler/gen_llvm/src/llvm/convert.rs | 2 +- compiler/gen_wasm/src/backend.rs | 2 +- compiler/gen_wasm/src/layout.rs | 2 +- compiler/mono/Cargo.toml | 1 + compiler/mono/src/alias_analysis.rs | 12 +- compiler/mono/src/decision_tree.rs | 24 +- compiler/mono/src/ir.rs | 270 ++++++------------ compiler/mono/src/layout.rs | 349 ++++++++++++++--------- 15 files changed, 431 insertions(+), 358 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ebbca7c3e8..a040ff2432 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3458,6 +3458,7 @@ dependencies = [ "bumpalo", "hashbrown 0.11.2", "morphic_lib", + "roc_builtins", "roc_can", "roc_collections", "roc_module", diff --git a/cli/src/repl/eval.rs b/cli/src/repl/eval.rs index 271efc7c9b..f3bf3d0b4c 100644 --- a/cli/src/repl/eval.rs +++ b/cli/src/repl/eval.rs @@ -71,7 +71,7 @@ fn jit_to_ast_help<'a>( content: &Content, ) -> Result, ToAstProblem> { match layout { - Layout::Builtin(Builtin::Int1) => Ok(run_jit_function!(lib, main_fn_name, bool, |num| { + Layout::Builtin(Builtin::Bool) => Ok(run_jit_function!(lib, main_fn_name, bool, |num| { bool_to_ast(env, num, content) })), Layout::Builtin(Builtin::Int8) => { @@ -248,7 +248,7 @@ fn jit_to_ast_help<'a>( .unwrap_or(0); let tag_id = match union_layout.tag_id_builtin() { - Builtin::Int1 => { + Builtin::Bool => { *(ptr.add(offset as usize) as *const i8) as i64 } Builtin::Int8 => { @@ -406,7 +406,7 @@ fn ptr_to_ast<'a>( num_to_ast(env, number_literal_to_ast(env.arena, num), content) } - Layout::Builtin(Builtin::Int1) => { + Layout::Builtin(Builtin::Bool) => { // TODO: bits are not as expected here. // num is always false at the moment. let num = unsafe { *(ptr as *const bool) }; diff --git a/compiler/builtins/src/bitcode.rs b/compiler/builtins/src/bitcode.rs index 46ee44bf3f..708c44720f 100644 --- a/compiler/builtins/src/bitcode.rs +++ b/compiler/builtins/src/bitcode.rs @@ -1,3 +1,4 @@ +use roc_module::symbol::Symbol; use std::ops::Index; pub const BUILTINS_HOST_OBJ_PATH: &str = env!( @@ -27,13 +28,55 @@ pub enum DecWidth { } #[repr(u8)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub enum FloatWidth { F32, F64, F128, } +impl FloatWidth { + pub const fn stack_size(&self) -> u32 { + use FloatWidth::*; + + match self { + F32 => 4, + F64 => 8, + F128 => 16, + } + } + + pub const fn alignment_bytes(&self) -> u32 { + use std::mem::align_of; + use FloatWidth::*; + + // TODO actually alignment is architecture-specific + match self { + F32 => align_of::() as u32, + F64 => align_of::() as u32, + F128 => align_of::() as u32, + } + } + + pub const fn try_from_symbol(symbol: Symbol) -> Option { + match symbol { + Symbol::NUM_FLOAT => Some(FloatWidth::F64), + + Symbol::NUM_F64 | Symbol::NUM_BINARY64 | Symbol::NUM_AT_BINARY64 => { + Some(FloatWidth::F64) + } + + Symbol::NUM_F32 | Symbol::NUM_BINARY32 | Symbol::NUM_AT_BINARY32 => { + Some(FloatWidth::F32) + } + + _ => None, + } + } +} + #[repr(u8)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub enum IntWidth { U8, U16, @@ -47,6 +90,61 @@ pub enum IntWidth { I128, } +impl IntWidth { + pub const fn stack_size(&self) -> u32 { + use IntWidth::*; + + match self { + U8 | I8 => 1, + U16 | I16 => 2, + U32 | I32 => 4, + U64 | I64 => 8, + U128 | I128 => 16, + } + } + + pub const fn alignment_bytes(&self) -> u32 { + use std::mem::align_of; + use IntWidth::*; + + // TODO actually alignment is architecture-specific + match self { + U8 | I8 => align_of::() as u32, + U16 | I16 => align_of::() as u32, + U32 | I32 => align_of::() as u32, + U64 | I64 => align_of::() as u32, + U128 | I128 => align_of::() as u32, + } + } + + pub const fn try_from_symbol(symbol: Symbol) -> Option { + match symbol { + Symbol::NUM_INT => Some(IntWidth::I64), + Symbol::NUM_I128 | Symbol::NUM_SIGNED128 | Symbol::NUM_AT_SIGNED128 => { + Some(IntWidth::I128) + } + Symbol::NUM_I64 | Symbol::NUM_SIGNED64 | Symbol::NUM_AT_SIGNED64 => Some(IntWidth::I64), + Symbol::NUM_I32 | Symbol::NUM_SIGNED32 | Symbol::NUM_AT_SIGNED32 => Some(IntWidth::I32), + Symbol::NUM_I16 | Symbol::NUM_SIGNED16 | Symbol::NUM_AT_SIGNED16 => Some(IntWidth::I16), + Symbol::NUM_I8 | Symbol::NUM_SIGNED8 | Symbol::NUM_AT_SIGNED8 => Some(IntWidth::I8), + Symbol::NUM_U128 | Symbol::NUM_UNSIGNED128 | Symbol::NUM_AT_UNSIGNED128 => { + Some(IntWidth::U128) + } + Symbol::NUM_U64 | Symbol::NUM_UNSIGNED64 | Symbol::NUM_AT_UNSIGNED64 => { + Some(IntWidth::U64) + } + Symbol::NUM_U32 | Symbol::NUM_UNSIGNED32 | Symbol::NUM_AT_UNSIGNED32 => { + Some(IntWidth::U32) + } + Symbol::NUM_U16 | Symbol::NUM_UNSIGNED16 | Symbol::NUM_AT_UNSIGNED16 => { + Some(IntWidth::U16) + } + Symbol::NUM_U8 | Symbol::NUM_UNSIGNED8 | Symbol::NUM_AT_UNSIGNED8 => Some(IntWidth::U8), + _ => None, + } + } +} + impl Index for IntrinsicName { type Output = str; diff --git a/compiler/gen_dev/src/lib.rs b/compiler/gen_dev/src/lib.rs index e8dff1d967..142ead9cd7 100644 --- a/compiler/gen_dev/src/lib.rs +++ b/compiler/gen_dev/src/lib.rs @@ -410,7 +410,7 @@ where "Eq: expected all arguments of to have the same layout" ); debug_assert_eq!( - Layout::Builtin(Builtin::Int1), + Layout::Builtin(Builtin::Bool), *ret_layout, "Eq: expected to have return layout of type I1" ); @@ -427,7 +427,7 @@ where "NotEq: expected all arguments of to have the same layout" ); debug_assert_eq!( - Layout::Builtin(Builtin::Int1), + Layout::Builtin(Builtin::Bool), *ret_layout, "NotEq: expected to have return layout of type I1" ); diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index 3bac18c03b..d7baeff601 100644 --- a/compiler/gen_llvm/src/llvm/build.rs +++ b/compiler/gen_llvm/src/llvm/build.rs @@ -715,7 +715,7 @@ pub fn int_with_precision<'a, 'ctx, 'env>( Builtin::Int32 => env.context.i32_type().const_int(value as u64, false), Builtin::Int16 => env.context.i16_type().const_int(value as u64, false), Builtin::Int8 => env.context.i8_type().const_int(value as u64, false), - Builtin::Int1 => env.context.bool_type().const_int(value as u64, false), + Builtin::Bool => env.context.bool_type().const_int(value as u64, false), _ => panic!("Invalid layout for int literal = {:?}", precision), } } @@ -3072,7 +3072,7 @@ fn build_switch_ir<'a, 'ctx, 'env>( // Build the cases let mut incoming = Vec::with_capacity_in(branches.len(), arena); - if let Layout::Builtin(Builtin::Int1) = cond_layout { + if let Layout::Builtin(Builtin::Bool) = cond_layout { match (branches, default_branch) { ([(0, _, false_branch)], true_branch) | ([(1, _, true_branch)], false_branch) => { let then_block = context.append_basic_block(parent, "then_block"); @@ -5133,7 +5133,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>( closure_layout, function_owns_closure_data, argument_layouts, - Layout::Builtin(Builtin::Int1), + Layout::Builtin(Builtin::Bool), ); list_any(env, roc_function_call, list, element_layout) @@ -5160,7 +5160,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>( closure_layout, function_owns_closure_data, argument_layouts, - Layout::Builtin(Builtin::Int1), + Layout::Builtin(Builtin::Bool), ); list_all(env, roc_function_call, list, element_layout) @@ -5193,7 +5193,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>( closure_layout, function_owns_closure_data, argument_layouts, - Layout::Builtin(Builtin::Int1), + Layout::Builtin(Builtin::Bool), ); list_find_unsafe(env, layout_ids, roc_function_call, list, element_layout) } @@ -6101,7 +6101,7 @@ fn to_cc_type_builtin<'a, 'ctx, 'env>( | Builtin::Int32 | Builtin::Int16 | Builtin::Int8 - | Builtin::Int1 + | Builtin::Bool | Builtin::Usize | Builtin::Decimal | Builtin::Float128 diff --git a/compiler/gen_llvm/src/llvm/build_hash.rs b/compiler/gen_llvm/src/llvm/build_hash.rs index 261af4e7d4..a0edb060c5 100644 --- a/compiler/gen_llvm/src/llvm/build_hash.rs +++ b/compiler/gen_llvm/src/llvm/build_hash.rs @@ -128,7 +128,7 @@ fn hash_builtin<'a, 'ctx, 'env>( | Builtin::Int32 | Builtin::Int16 | Builtin::Int8 - | Builtin::Int1 + | Builtin::Bool | Builtin::Float64 | Builtin::Float32 | Builtin::Float128 diff --git a/compiler/gen_llvm/src/llvm/compare.rs b/compiler/gen_llvm/src/llvm/compare.rs index c624890616..688bc4a0b3 100644 --- a/compiler/gen_llvm/src/llvm/compare.rs +++ b/compiler/gen_llvm/src/llvm/compare.rs @@ -93,7 +93,7 @@ fn build_eq_builtin<'a, 'ctx, 'env>( Builtin::Int32 => int_cmp(IntPredicate::EQ, "eq_i32"), Builtin::Int16 => int_cmp(IntPredicate::EQ, "eq_i16"), Builtin::Int8 => int_cmp(IntPredicate::EQ, "eq_i8"), - Builtin::Int1 => int_cmp(IntPredicate::EQ, "eq_i1"), + Builtin::Bool => int_cmp(IntPredicate::EQ, "eq_i1"), Builtin::Usize => int_cmp(IntPredicate::EQ, "eq_usize"), @@ -236,7 +236,7 @@ fn build_neq_builtin<'a, 'ctx, 'env>( Builtin::Int32 => int_cmp(IntPredicate::NE, "neq_i32"), Builtin::Int16 => int_cmp(IntPredicate::NE, "neq_i16"), Builtin::Int8 => int_cmp(IntPredicate::NE, "neq_i8"), - Builtin::Int1 => int_cmp(IntPredicate::NE, "neq_i1"), + Builtin::Bool => int_cmp(IntPredicate::NE, "neq_i1"), Builtin::Usize => int_cmp(IntPredicate::NE, "neq_usize"), diff --git a/compiler/gen_llvm/src/llvm/convert.rs b/compiler/gen_llvm/src/llvm/convert.rs index 98306210ad..989e0414e7 100644 --- a/compiler/gen_llvm/src/llvm/convert.rs +++ b/compiler/gen_llvm/src/llvm/convert.rs @@ -151,7 +151,7 @@ pub fn basic_type_from_builtin<'a, 'ctx, 'env>( Int32 => context.i32_type().as_basic_type_enum(), Int16 => context.i16_type().as_basic_type_enum(), Int8 => context.i8_type().as_basic_type_enum(), - Int1 => context.bool_type().as_basic_type_enum(), + Bool => context.bool_type().as_basic_type_enum(), Usize => ptr_int(context, ptr_bytes).as_basic_type_enum(), Decimal => context.i128_type().as_basic_type_enum(), Float128 => context.f128_type().as_basic_type_enum(), diff --git a/compiler/gen_wasm/src/backend.rs b/compiler/gen_wasm/src/backend.rs index 6a516e543d..2bc4fd6357 100644 --- a/compiler/gen_wasm/src/backend.rs +++ b/compiler/gen_wasm/src/backend.rs @@ -328,7 +328,7 @@ impl<'a> WasmBackend<'a> { self.start_block(BlockType::NoResult) } - let is_bool = matches!(cond_layout, Layout::Builtin(Builtin::Int1)); + let is_bool = matches!(cond_layout, Layout::Builtin(Builtin::Bool)); let cond_type = WasmLayout::new(cond_layout).value_type(); // then, we jump whenever the value under scrutiny is equal to the value of a branch diff --git a/compiler/gen_wasm/src/layout.rs b/compiler/gen_wasm/src/layout.rs index 2cd562dcc8..5ad6930478 100644 --- a/compiler/gen_wasm/src/layout.rs +++ b/compiler/gen_wasm/src/layout.rs @@ -26,7 +26,7 @@ impl WasmLayout { let alignment_bytes = layout.alignment_bytes(PTR_SIZE); match layout { - Layout::Builtin(Int32 | Int16 | Int8 | Int1 | Usize) => Self::Primitive(I32, size), + Layout::Builtin(Int32 | Int16 | Int8 | Bool | Usize) => Self::Primitive(I32, size), Layout::Builtin(Int64) => Self::Primitive(I64, size), diff --git a/compiler/mono/Cargo.toml b/compiler/mono/Cargo.toml index 02045363d6..6cd3129ed3 100644 --- a/compiler/mono/Cargo.toml +++ b/compiler/mono/Cargo.toml @@ -15,6 +15,7 @@ roc_unify = { path = "../unify" } roc_solve = { path = "../solve" } roc_std = { path = "../../roc_std" } roc_problem = { path = "../problem" } +roc_builtins = { path = "../builtins" } ven_pretty = { path = "../../vendor/pretty" } morphic_lib = { path = "../../vendor/morphic_lib" } bumpalo = { version = "3.8.0", features = ["collections"] } diff --git a/compiler/mono/src/alias_analysis.rs b/compiler/mono/src/alias_analysis.rs index 306b2a52ae..66d915bce9 100644 --- a/compiler/mono/src/alias_analysis.rs +++ b/compiler/mono/src/alias_analysis.rs @@ -590,7 +590,7 @@ impl<'a> ResultRepr<'a> { err: tags[ERR_TAG_ID as usize][0], ok: tags[OK_TAG_ID as usize][0], }, - Layout::Builtin(Builtin::Int1) => ResultRepr::Int1, + Layout::Builtin(Builtin::Bool) => ResultRepr::Int1, other => unreachable!("unexpected layout: {:?}", other), } } @@ -1086,7 +1086,7 @@ fn call_spec( Ok(new_state) }; - let state_layout = Layout::Builtin(Builtin::Int1); + let state_layout = Layout::Builtin(Builtin::Bool); let state_type = layout_spec(builder, &state_layout)?; let init_state = new_num(builder, block)?; @@ -1105,7 +1105,7 @@ fn call_spec( Ok(new_state) }; - let state_layout = Layout::Builtin(Builtin::Int1); + let state_layout = Layout::Builtin(Builtin::Bool); let state_type = layout_spec(builder, &state_layout)?; let init_state = new_num(builder, block)?; @@ -1116,7 +1116,7 @@ fn call_spec( let list = env.symbols[xs]; // ListFindUnsafe returns { value: v, found: Bool=Int1 } - let output_layouts = vec![arg_layouts[0], Layout::Builtin(Builtin::Int1)]; + let output_layouts = vec![arg_layouts[0], Layout::Builtin(Builtin::Bool)]; let output_layout = Layout::Struct(&output_layouts); let output_type = layout_spec(builder, &output_layout)?; @@ -1718,8 +1718,8 @@ fn builtin_spec( use Builtin::*; match builtin { - Int128 | Int64 | Int32 | Int16 | Int8 | Int1 | Usize => builder.add_tuple_type(&[]), - Decimal | Float128 | Float64 | Float32 => builder.add_tuple_type(&[]), + Int(_) | Usize | Bool => builder.add_tuple_type(&[]), + Decimal | Float(_) => builder.add_tuple_type(&[]), Str | EmptyStr => str_type(builder), Dict(key_layout, value_layout) => { let value_type = layout_spec_help(builder, value_layout, when_recursive)?; diff --git a/compiler/mono/src/decision_tree.rs b/compiler/mono/src/decision_tree.rs index 841866353b..8f78a32458 100644 --- a/compiler/mono/src/decision_tree.rs +++ b/compiler/mono/src/decision_tree.rs @@ -1,9 +1,9 @@ use crate::exhaustive::{Ctor, RenderAs, TagId, Union}; use crate::ir::{ - BranchInfo, DestructType, Env, Expr, FloatPrecision, IntPrecision, JoinPointId, Literal, Param, - Pattern, Procs, Stmt, + BranchInfo, DestructType, Env, Expr, JoinPointId, Literal, Param, Pattern, Procs, Stmt, }; use crate::layout::{Builtin, Layout, LayoutCache, TagIdIntType, UnionLayout}; +use roc_builtins::bitcode::{FloatWidth, IntWidth}; use roc_collections::all::{MutMap, MutSet}; use roc_module::ident::TagName; use roc_module::low_level::LowLevel; @@ -86,8 +86,8 @@ enum Test<'a> { union: crate::exhaustive::Union, arguments: Vec<(Pattern<'a>, Layout<'a>)>, }, - IsInt(i128, IntPrecision), - IsFloat(u64, FloatPrecision), + IsInt(i128, IntWidth), + IsFloat(u64, FloatWidth), IsDecimal(RocDec), IsStr(Box), IsBit(bool), @@ -1300,7 +1300,7 @@ fn test_to_equality<'a>( debug_assert!(test_int <= i64::MAX as i128); let lhs = Expr::Literal(Literal::Int(test_int as i128)); let lhs_symbol = env.unique_symbol(); - stores.push((lhs_symbol, precision.as_layout(), lhs)); + stores.push((lhs_symbol, Layout::int_width(precision), lhs)); (stores, lhs_symbol, rhs_symbol, None) } @@ -1310,7 +1310,7 @@ fn test_to_equality<'a>( let test_float = f64::from_bits(test_int as u64); let lhs = Expr::Literal(Literal::Float(test_float)); let lhs_symbol = env.unique_symbol(); - stores.push((lhs_symbol, precision.as_layout(), lhs)); + stores.push((lhs_symbol, Layout::float_width(precision), lhs)); (stores, lhs_symbol, rhs_symbol, None) } @@ -1330,7 +1330,7 @@ fn test_to_equality<'a>( let lhs = Expr::Literal(Literal::Byte(test_byte as u8)); let lhs_symbol = env.unique_symbol(); - stores.push((lhs_symbol, Layout::Builtin(Builtin::Int8), lhs)); + stores.push((lhs_symbol, Layout::u8(), lhs)); (stores, lhs_symbol, rhs_symbol, None) } @@ -1338,7 +1338,7 @@ fn test_to_equality<'a>( Test::IsBit(test_bit) => { let lhs = Expr::Literal(Literal::Bool(test_bit)); let lhs_symbol = env.unique_symbol(); - stores.push((lhs_symbol, Layout::Builtin(Builtin::Int1), lhs)); + stores.push((lhs_symbol, Layout::Builtin(Builtin::Bool), lhs)); (stores, lhs_symbol, rhs_symbol, None) } @@ -1459,7 +1459,7 @@ fn compile_test_help<'a>( cond = Stmt::Switch { cond_symbol: test_symbol, - cond_layout: Layout::Builtin(Builtin::Int1), + cond_layout: Layout::Builtin(Builtin::Bool), ret_layout, branches, default_branch, @@ -1478,7 +1478,7 @@ fn compile_test_help<'a>( cond = Stmt::Let( test_symbol, test, - Layout::Builtin(Builtin::Int1), + Layout::Builtin(Builtin::Bool), arena.alloc(cond), ); @@ -1622,7 +1622,7 @@ fn decide_to_branching<'a>( let decide = crate::ir::cond( env, test_symbol, - Layout::Builtin(Builtin::Int1), + Layout::Builtin(Builtin::Bool), pass_expr, fail_expr, ret_layout, @@ -1631,7 +1631,7 @@ fn decide_to_branching<'a>( // calculate the guard value let param = Param { symbol: test_symbol, - layout: Layout::Builtin(Builtin::Int1), + layout: Layout::Builtin(Builtin::Bool), borrow: false, }; diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index bb319a4370..d4e40f2245 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -7,6 +7,7 @@ use crate::layout::{ }; use bumpalo::collections::Vec; use bumpalo::Bump; +use roc_builtins::bitcode::{FloatWidth, IntWidth}; use roc_can::expr::ClosureData; use roc_collections::all::{default_hasher, BumpMap, BumpMapDefault, MutMap}; use roc_module::ident::{ForeignSymbol, Lowercase, TagName}; @@ -2424,11 +2425,11 @@ fn specialize_external<'a>( } ClosureRepresentation::Other(layout) => match layout { - Layout::Builtin(Builtin::Int1) => { + Layout::Builtin(Builtin::Bool) => { // just ignore this value // IDEA don't pass this value in the future } - Layout::Builtin(Builtin::Int8) => { + Layout::Builtin(Builtin::Int(IntWidth::U8)) => { // just ignore this value // IDEA don't pass this value in the future } @@ -2953,16 +2954,14 @@ fn try_make_literal<'a>( match can_expr { Int(_, precision, _, int) => { match num_argument_to_int_or_float(env.subs, env.ptr_bytes, *precision, false) { - IntOrFloat::SignedIntType(_) | IntOrFloat::UnsignedIntType(_) => { - Some(Literal::Int(*int)) - } + IntOrFloat::Int(_) | IntOrFloat::Natural => Some(Literal::Int(*int)), _ => unreachable!("unexpected float precision for integer"), } } Float(_, precision, float_str, float) => { match num_argument_to_int_or_float(env.subs, env.ptr_bytes, *precision, true) { - IntOrFloat::BinaryFloatType(_) => Some(Literal::Float(*float)), + IntOrFloat::Float(_) => Some(Literal::Float(*float)), IntOrFloat::DecimalFloatType => { let dec = match RocDec::from_str(float_str) { Some(d) => d, @@ -2980,10 +2979,8 @@ fn try_make_literal<'a>( Num(var, num_str, num) => { // first figure out what kind of number this is match num_argument_to_int_or_float(env.subs, env.ptr_bytes, *var, false) { - IntOrFloat::SignedIntType(_) | IntOrFloat::UnsignedIntType(_) => { - Some(Literal::Int((*num).into())) - } - IntOrFloat::BinaryFloatType(_) => Some(Literal::Float(*num as f64)), + IntOrFloat::Int(_) | IntOrFloat::Natural => Some(Literal::Int((*num).into())), + IntOrFloat::Float(_) => Some(Literal::Float(*num as f64)), IntOrFloat::DecimalFloatType => { let dec = match RocDec::from_str(num_str) { Some(d) => d, @@ -3017,16 +3014,16 @@ pub fn with_hole<'a>( match can_expr { Int(_, precision, _, int) => { match num_argument_to_int_or_float(env.subs, env.ptr_bytes, precision, false) { - IntOrFloat::SignedIntType(precision) => Stmt::Let( + IntOrFloat::Int(precision) => Stmt::Let( assigned, Expr::Literal(Literal::Int(int)), - precision.as_layout(), + Layout::Builtin(Builtin::Int(precision)), hole, ), - IntOrFloat::UnsignedIntType(precision) => Stmt::Let( + IntOrFloat::Natural => Stmt::Let( assigned, Expr::Literal(Literal::Int(int)), - precision.as_layout(), + Layout::usize(), hole, ), _ => unreachable!("unexpected float precision for integer"), @@ -3035,10 +3032,10 @@ pub fn with_hole<'a>( Float(_, precision, float_str, float) => { match num_argument_to_int_or_float(env.subs, env.ptr_bytes, precision, true) { - IntOrFloat::BinaryFloatType(precision) => Stmt::Let( + IntOrFloat::Float(precision) => Stmt::Let( assigned, Expr::Literal(Literal::Float(float)), - precision.as_layout(), + Layout::Builtin(Builtin::Float(precision)), hole, ), IntOrFloat::DecimalFloatType => { @@ -3067,22 +3064,22 @@ pub fn with_hole<'a>( Num(var, num_str, num) => { // first figure out what kind of number this is match num_argument_to_int_or_float(env.subs, env.ptr_bytes, var, false) { - IntOrFloat::SignedIntType(precision) => Stmt::Let( + IntOrFloat::Int(precision) => Stmt::Let( assigned, Expr::Literal(Literal::Int(num.into())), - precision.as_layout(), + Layout::int_width(precision), hole, ), - IntOrFloat::UnsignedIntType(precision) => Stmt::Let( + IntOrFloat::Natural => Stmt::Let( assigned, Expr::Literal(Literal::Int(num.into())), - precision.as_layout(), + Layout::usize(), hole, ), - IntOrFloat::BinaryFloatType(precision) => Stmt::Let( + IntOrFloat::Float(precision) => Stmt::Let( assigned, Expr::Literal(Literal::Float(num as f64)), - precision.as_layout(), + Layout::float_width(precision), hole, ), IntOrFloat::DecimalFloatType => { @@ -4467,7 +4464,7 @@ fn construct_closure_data<'a>( Stmt::Let(assigned, expr, lambda_set_layout, hole) } - ClosureRepresentation::Other(Layout::Builtin(Builtin::Int1)) => { + ClosureRepresentation::Other(Layout::Builtin(Builtin::Bool)) => { debug_assert_eq!(symbols.len(), 0); debug_assert_eq!(lambda_set.set.len(), 2); @@ -4476,7 +4473,7 @@ fn construct_closure_data<'a>( Stmt::Let(assigned, expr, lambda_set_layout, hole) } - ClosureRepresentation::Other(Layout::Builtin(Builtin::Int8)) => { + ClosureRepresentation::Other(Layout::Builtin(Builtin::Int(IntWidth::U8))) => { debug_assert_eq!(symbols.len(), 0); debug_assert!(lambda_set.set.len() > 2); @@ -4533,7 +4530,7 @@ fn convert_tag_union<'a>( BoolUnion { ttrue, .. } => Stmt::Let( assigned, Expr::Literal(Literal::Bool(tag_name == ttrue)), - Layout::Builtin(Builtin::Int1), + Layout::Builtin(Builtin::Bool), hole, ), ByteUnion(tag_names) => { @@ -4543,7 +4540,7 @@ fn convert_tag_union<'a>( Some(tag_id) => Stmt::Let( assigned, Expr::Literal(Literal::Byte(tag_id as u8)), - Layout::Builtin(Builtin::Int8), + Layout::Builtin(Builtin::Int(IntWidth::U8)), hole, ), None => Stmt::RuntimeError("tag must be in its own type"), @@ -5054,7 +5051,7 @@ pub fn from_can<'a>( Expect(condition, rest) => { let rest = from_can(env, variable, rest.value, procs, layout_cache); - let bool_layout = Layout::Builtin(Builtin::Int1); + let bool_layout = Layout::Builtin(Builtin::Bool); let cond_symbol = env.unique_symbol(); let op = LowLevel::ExpectTrue; @@ -7237,8 +7234,8 @@ fn call_specialized_proc<'a>( pub enum Pattern<'a> { Identifier(Symbol), Underscore, - IntLiteral(i128, IntPrecision), - FloatLiteral(u64, FloatPrecision), + IntLiteral(i128, IntWidth), + FloatLiteral(u64, FloatWidth), DecimalLiteral(RocDec), BitLiteral { value: bool, @@ -7318,9 +7315,8 @@ fn from_can_pattern_help<'a>( Identifier(symbol) => Ok(Pattern::Identifier(*symbol)), IntLiteral(var, _, int) => { match num_argument_to_int_or_float(env.subs, env.ptr_bytes, *var, false) { - IntOrFloat::SignedIntType(precision) | IntOrFloat::UnsignedIntType(precision) => { - Ok(Pattern::IntLiteral(*int as i128, precision)) - } + IntOrFloat::Natural => todo!(), + IntOrFloat::Int(precision) => Ok(Pattern::IntLiteral(*int as i128, precision)), other => { panic!( "Invalid precision for int pattern: {:?} has {:?}", @@ -7332,10 +7328,10 @@ fn from_can_pattern_help<'a>( FloatLiteral(var, float_str, float) => { // TODO: Can I reuse num_argument_to_int_or_float here if I pass in true? match num_argument_to_int_or_float(env.subs, env.ptr_bytes, *var, true) { - IntOrFloat::SignedIntType(_) | IntOrFloat::UnsignedIntType(_) => { + IntOrFloat::Int(_) | IntOrFloat::Natural => { panic!("Invalid precision for float pattern {:?}", var) } - IntOrFloat::BinaryFloatType(precision) => { + IntOrFloat::Float(precision) => { Ok(Pattern::FloatLiteral(f64::to_bits(*float), precision)) } IntOrFloat::DecimalFloatType => { @@ -7362,15 +7358,9 @@ fn from_can_pattern_help<'a>( } NumLiteral(var, num_str, num) => { match num_argument_to_int_or_float(env.subs, env.ptr_bytes, *var, false) { - IntOrFloat::SignedIntType(precision) => { - Ok(Pattern::IntLiteral(*num as i128, precision)) - } - IntOrFloat::UnsignedIntType(precision) => { - Ok(Pattern::IntLiteral(*num as i128, precision)) - } - IntOrFloat::BinaryFloatType(precision) => { - Ok(Pattern::FloatLiteral(*num as u64, precision)) - } + IntOrFloat::Int(precision) => Ok(Pattern::IntLiteral(*num as i128, precision)), + IntOrFloat::Float(precision) => Ok(Pattern::FloatLiteral(*num as u64, precision)), + IntOrFloat::Natural => todo!(), IntOrFloat::DecimalFloatType => { let dec = match RocDec::from_str(num_str) { Some(d) => d, @@ -7952,60 +7942,12 @@ fn from_can_record_destruct<'a>( }) } -#[derive(Debug, Clone, Copy, PartialEq, Hash)] -pub enum IntPrecision { - Usize, - I128, - I64, - I32, - I16, - I8, -} - -impl IntPrecision { - pub fn as_layout(&self) -> Layout<'static> { - Layout::Builtin(self.as_builtin()) - } - - pub fn as_builtin(&self) -> Builtin<'static> { - use IntPrecision::*; - match self { - I128 => Builtin::Int128, - I64 => Builtin::Int64, - I32 => Builtin::Int32, - I16 => Builtin::Int16, - I8 => Builtin::Int8, - Usize => Builtin::Usize, - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Hash)] -pub enum FloatPrecision { - F64, - F32, -} - -impl FloatPrecision { - pub fn as_layout(&self) -> Layout<'static> { - Layout::Builtin(self.as_builtin()) - } - - pub fn as_builtin(&self) -> Builtin<'static> { - use FloatPrecision::*; - match self { - F64 => Builtin::Float64, - F32 => Builtin::Float32, - } - } -} - #[derive(Debug)] pub enum IntOrFloat { - SignedIntType(IntPrecision), - UnsignedIntType(IntPrecision), - BinaryFloatType(FloatPrecision), + Int(IntWidth), + Float(FloatWidth), DecimalFloatType, + Natural, } /// Given the `a` in `Num a`, determines whether it's an int or a float @@ -8015,11 +7957,13 @@ pub fn num_argument_to_int_or_float( var: Variable, known_to_be_float: bool, ) -> IntOrFloat { - match subs.get_content_without_compacting(var){ - Content::FlexVar(_) | Content::RigidVar(_) if known_to_be_float => IntOrFloat::BinaryFloatType(FloatPrecision::F64), - Content::FlexVar(_) | Content::RigidVar(_) => IntOrFloat::SignedIntType(IntPrecision::I64), // We default (Num *) to I64 + match subs.get_content_without_compacting(var) { + Content::FlexVar(_) | Content::RigidVar(_) if known_to_be_float => { + IntOrFloat::Float(FloatWidth::F64) + } + Content::FlexVar(_) | Content::RigidVar(_) => IntOrFloat::Int(IntWidth::I64), // We default (Num *) to I64 - Content::Alias(Symbol::NUM_INTEGER, args, _) => { + Content::Alias(Symbol::NUM_INTEGER, args, _) => { debug_assert!(args.len() == 1); // Recurse on the second argument @@ -8027,85 +7971,39 @@ pub fn num_argument_to_int_or_float( num_argument_to_int_or_float(subs, ptr_bytes, var, false) } - Content::Alias(Symbol::NUM_I128, _, _) - | Content::Alias(Symbol::NUM_SIGNED128, _, _) - | Content::Alias(Symbol::NUM_AT_SIGNED128, _, _) => { - IntOrFloat::SignedIntType(IntPrecision::I128) - } - Content::Alias(Symbol::NUM_INT, _, _)// We default Integer to I64 - | Content::Alias(Symbol::NUM_I64, _, _) - | Content::Alias(Symbol::NUM_SIGNED64, _, _) - | Content::Alias(Symbol::NUM_AT_SIGNED64, _, _) => { - IntOrFloat::SignedIntType(IntPrecision::I64) - } - Content::Alias(Symbol::NUM_I32, _, _) - | Content::Alias(Symbol::NUM_SIGNED32, _, _) - | Content::Alias(Symbol::NUM_AT_SIGNED32, _, _) => { - IntOrFloat::SignedIntType(IntPrecision::I32) - } - Content::Alias(Symbol::NUM_I16, _, _) - | Content::Alias(Symbol::NUM_SIGNED16, _, _) - | Content::Alias(Symbol::NUM_AT_SIGNED16, _, _) => { - IntOrFloat::SignedIntType(IntPrecision::I16) - } - Content::Alias(Symbol::NUM_I8, _, _) - | Content::Alias(Symbol::NUM_SIGNED8, _, _) - | Content::Alias(Symbol::NUM_AT_SIGNED8, _, _) => { - IntOrFloat::SignedIntType(IntPrecision::I8) - } - Content::Alias(Symbol::NUM_U128, _, _) - | Content::Alias(Symbol::NUM_UNSIGNED128, _, _) - | Content::Alias(Symbol::NUM_AT_UNSIGNED128, _, _) => { - IntOrFloat::UnsignedIntType(IntPrecision::I128) - } - Content::Alias(Symbol::NUM_U64, _, _) - | Content::Alias(Symbol::NUM_UNSIGNED64, _, _) - | Content::Alias(Symbol::NUM_AT_UNSIGNED64, _, _) => { - IntOrFloat::UnsignedIntType(IntPrecision::I64) - } - Content::Alias(Symbol::NUM_U32, _, _) - | Content::Alias(Symbol::NUM_UNSIGNED32, _, _) - | Content::Alias(Symbol::NUM_AT_UNSIGNED32, _, _) => { - IntOrFloat::UnsignedIntType(IntPrecision::I32) - } - Content::Alias(Symbol::NUM_U16, _, _) - | Content::Alias(Symbol::NUM_UNSIGNED16, _, _) - | Content::Alias(Symbol::NUM_AT_UNSIGNED16, _, _) => { - IntOrFloat::UnsignedIntType(IntPrecision::I16) - } - Content::Alias(Symbol::NUM_U8, _, _) - | Content::Alias(Symbol::NUM_UNSIGNED8, _, _) - | Content::Alias(Symbol::NUM_AT_UNSIGNED8, _, _) => { - IntOrFloat::UnsignedIntType(IntPrecision::I8) - } - Content::Alias(Symbol::NUM_FLOATINGPOINT, args, _) => { - debug_assert!(args.len() == 1); + other @ Content::Alias(symbol, args, _) => { + if let Some(int_width) = IntWidth::try_from_symbol(*symbol) { + return IntOrFloat::Int(int_width); + } - // Recurse on the second argument - let var = subs[args.variables().into_iter().next().unwrap()]; - num_argument_to_int_or_float(subs, ptr_bytes, var, true) - } - Content::Alias(Symbol::NUM_FLOAT, _, _) // We default FloatingPoint to F64 - | Content::Alias(Symbol::NUM_F64, _, _) - | Content::Alias(Symbol::NUM_BINARY64, _, _) - | Content::Alias(Symbol::NUM_AT_BINARY64, _, _) => { - IntOrFloat::BinaryFloatType(FloatPrecision::F64) - } - Content::Alias(Symbol::NUM_DECIMAL, _, _) - | Content::Alias(Symbol::NUM_AT_DECIMAL, _, _) => { - IntOrFloat::DecimalFloatType - } - Content::Alias(Symbol::NUM_F32, _, _) - | Content::Alias(Symbol::NUM_BINARY32, _, _) - | Content::Alias(Symbol::NUM_AT_BINARY32, _, _) => { - IntOrFloat::BinaryFloatType(FloatPrecision::F32) - } - Content::Alias(Symbol::NUM_NAT, _, _) - | Content::Alias(Symbol::NUM_NATURAL, _, _) - | Content::Alias(Symbol::NUM_AT_NATURAL, _, _) => { - IntOrFloat::UnsignedIntType(IntPrecision::Usize) + if let Some(float_width) = FloatWidth::try_from_symbol(*symbol) { + return IntOrFloat::Float(float_width); + } + match *symbol { + Symbol::NUM_FLOATINGPOINT => { + debug_assert!(args.len() == 1); + + // Recurse on the second argument + let var = subs[args.variables().into_iter().next().unwrap()]; + num_argument_to_int_or_float(subs, ptr_bytes, var, true) + } + + Symbol::NUM_DECIMAL | Symbol::NUM_AT_DECIMAL => { + return IntOrFloat::DecimalFloatType; + } + + Symbol::NUM_NAT | Symbol::NUM_NATURAL | Symbol::NUM_AT_NATURAL => { + return IntOrFloat::Natural; + } + + _ => panic!( + "Unrecognized Num type argument for var {:?} with Content: {:?}", + var, other + ), + } } + other => { panic!( "Unrecognized Num type argument for var {:?} with Content: {:?}", @@ -8187,14 +8085,14 @@ where hole.clone() } }, - Layout::Builtin(Builtin::Int1) => { + Layout::Builtin(Builtin::Bool) => { let closure_tag_id_symbol = closure_data_symbol; lowlevel_enum_lambda_set_to_switch( env, lambda_set.set, closure_tag_id_symbol, - Layout::Builtin(Builtin::Int1), + Layout::Builtin(Builtin::Bool), closure_data_symbol, lambda_set.is_represented(), to_lowlevel_call, @@ -8203,14 +8101,14 @@ where hole, ) } - Layout::Builtin(Builtin::Int8) => { + Layout::Builtin(Builtin::Int(IntWidth::U8)) => { let closure_tag_id_symbol = closure_data_symbol; lowlevel_enum_lambda_set_to_switch( env, lambda_set.set, closure_tag_id_symbol, - Layout::Builtin(Builtin::Int8), + Layout::Builtin(Builtin::Int(IntWidth::U8)), closure_data_symbol, lambda_set.is_represented(), to_lowlevel_call, @@ -8351,14 +8249,14 @@ fn match_on_lambda_set<'a>( hole, ) } - Layout::Builtin(Builtin::Int1) => { + Layout::Builtin(Builtin::Bool) => { let closure_tag_id_symbol = closure_data_symbol; enum_lambda_set_to_switch( env, lambda_set.set, closure_tag_id_symbol, - Layout::Builtin(Builtin::Int1), + Layout::Builtin(Builtin::Bool), closure_data_symbol, argument_symbols, argument_layouts, @@ -8367,14 +8265,14 @@ fn match_on_lambda_set<'a>( hole, ) } - Layout::Builtin(Builtin::Int8) => { + Layout::Builtin(Builtin::Int(IntWidth::U8)) => { let closure_tag_id_symbol = closure_data_symbol; enum_lambda_set_to_switch( env, lambda_set.set, closure_tag_id_symbol, - Layout::Builtin(Builtin::Int8), + Layout::Builtin(Builtin::Int(IntWidth::U8)), closure_data_symbol, argument_symbols, argument_layouts, @@ -8502,7 +8400,9 @@ fn union_lambda_set_branch_help<'a>( hole: &'a Stmt<'a>, ) -> Stmt<'a> { let (argument_layouts, argument_symbols) = match closure_data_layout { - Layout::Struct(&[]) | Layout::Builtin(Builtin::Int1) | Layout::Builtin(Builtin::Int8) => { + Layout::Struct(&[]) + | Layout::Builtin(Builtin::Bool) + | Layout::Builtin(Builtin::Int(IntWidth::U8)) => { (argument_layouts_slice, argument_symbols_slice) } _ if lambda_set.member_does_not_need_closure_argument(function_symbol) => { @@ -8627,7 +8527,9 @@ fn enum_lambda_set_branch<'a>( let assigned = result_symbol; let (argument_layouts, argument_symbols) = match closure_data_layout { - Layout::Struct(&[]) | Layout::Builtin(Builtin::Int1) | Layout::Builtin(Builtin::Int8) => { + Layout::Struct(&[]) + | Layout::Builtin(Builtin::Bool) + | Layout::Builtin(Builtin::Int(IntWidth::U8)) => { (argument_layouts_slice, argument_symbols_slice) } _ => { diff --git a/compiler/mono/src/layout.rs b/compiler/mono/src/layout.rs index 7ea9cc4e71..61218d7f93 100644 --- a/compiler/mono/src/layout.rs +++ b/compiler/mono/src/layout.rs @@ -1,6 +1,7 @@ use crate::ir::Parens; use bumpalo::collections::Vec; use bumpalo::Bump; +use roc_builtins::bitcode::{FloatWidth, IntWidth}; use roc_collections::all::{default_hasher, MutMap}; use roc_module::ident::{Lowercase, TagName}; use roc_module::symbol::{Interns, Symbol}; @@ -24,9 +25,6 @@ pub type TagIdIntType = u16; pub const MAX_ENUM_SIZE: usize = (std::mem::size_of::() * 8) as usize; const GENERATE_NULLABLE: bool = true; -/// If a (Num *) gets translated to a Layout, this is the numeric type it defaults to. -const DEFAULT_NUM_BUILTIN: Builtin<'_> = Builtin::Int64; - #[derive(Debug, Clone)] pub enum LayoutProblem { UnresolvedTypeVar(Variable), @@ -61,60 +59,61 @@ impl<'a> RawFunctionLayout<'a> { // Ints Alias(Symbol::NUM_I128, args, _) => { debug_assert!(args.is_empty()); - Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Int128))) + Ok(Self::ZeroArgumentThunk(Layout::i128())) } Alias(Symbol::NUM_I64, args, _) => { debug_assert!(args.is_empty()); - Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Int64))) + Ok(Self::ZeroArgumentThunk(Layout::i64())) } Alias(Symbol::NUM_I32, args, _) => { debug_assert!(args.is_empty()); - Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Int32))) + Ok(Self::ZeroArgumentThunk(Layout::i32())) } Alias(Symbol::NUM_I16, args, _) => { debug_assert!(args.is_empty()); - Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Int16))) + Ok(Self::ZeroArgumentThunk(Layout::i16())) } Alias(Symbol::NUM_I8, args, _) => { debug_assert!(args.is_empty()); - Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Int8))) + Ok(Self::ZeroArgumentThunk(Layout::i8())) } // I think unsigned and signed use the same layout Alias(Symbol::NUM_U128, args, _) => { debug_assert!(args.is_empty()); - Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Int128))) + Ok(Self::ZeroArgumentThunk(Layout::u128())) } Alias(Symbol::NUM_U64, args, _) => { debug_assert!(args.is_empty()); - Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Int64))) + Ok(Self::ZeroArgumentThunk(Layout::u64())) } Alias(Symbol::NUM_U32, args, _) => { debug_assert!(args.is_empty()); - Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Int32))) + Ok(Self::ZeroArgumentThunk(Layout::u32())) } Alias(Symbol::NUM_U16, args, _) => { debug_assert!(args.is_empty()); - Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Int16))) + Ok(Self::ZeroArgumentThunk(Layout::u16())) } Alias(Symbol::NUM_U8, args, _) => { debug_assert!(args.is_empty()); - Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Int8))) - } - - Alias(Symbol::NUM_NAT, args, _) => { - debug_assert!(args.is_empty()); - Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Usize))) + Ok(Self::ZeroArgumentThunk(Layout::u8())) } // Floats Alias(Symbol::NUM_F64, args, _) => { debug_assert!(args.is_empty()); - Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Float64))) + Ok(Self::ZeroArgumentThunk(Layout::f64())) } Alias(Symbol::NUM_F32, args, _) => { debug_assert!(args.is_empty()); - Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Float32))) + Ok(Self::ZeroArgumentThunk(Layout::f32())) + } + + // Nat + Alias(Symbol::NUM_NAT, args, _) => { + debug_assert!(args.is_empty()); + Ok(Self::ZeroArgumentThunk(Layout::usize())) } Alias(symbol, _, _) if symbol.is_builtin() => Ok(Self::ZeroArgumentThunk( @@ -315,9 +314,9 @@ impl<'a> UnionLayout<'a> { fn tag_id_builtin_help(union_size: usize) -> Builtin<'a> { if union_size <= u8::MAX as usize { - Builtin::Int8 + Builtin::Int(IntWidth::U8) } else if union_size <= u16::MAX as usize { - Builtin::Int16 + Builtin::Int(IntWidth::U16) } else { panic!("tag union is too big") } @@ -332,7 +331,7 @@ impl<'a> UnionLayout<'a> { // The quicksort-benchmarks version of Quicksort.roc segfaults when // this number is not I64. There must be some dependence on that fact // somewhere in the code, I have not found where that is yet... - Builtin::Int64 + Builtin::Int(IntWidth::U64) } UnionLayout::Recursive(tags) => { let union_size = tags.len(); @@ -343,8 +342,8 @@ impl<'a> UnionLayout<'a> { UnionLayout::NullableWrapped { other_tags, .. } => { Self::tag_id_builtin_help(other_tags.len() + 1) } - UnionLayout::NonNullableUnwrapped(_) => Builtin::Int1, - UnionLayout::NullableUnwrapped { .. } => Builtin::Int1, + UnionLayout::NonNullableUnwrapped(_) => Builtin::Bool, + UnionLayout::NullableUnwrapped { .. } => Builtin::Bool, } } @@ -546,7 +545,8 @@ impl<'a> LambdaSet<'a> { // singleton, so we pass no extra argument argument_layouts } - Layout::Builtin(Builtin::Int1) | Layout::Builtin(Builtin::Int8) => { + Layout::Builtin(Builtin::Bool) + | Layout::Builtin(Builtin::Int(IntWidth::I8 | IntWidth::U8)) => { // we don't pass this along either argument_layouts } @@ -628,8 +628,8 @@ impl<'a> LambdaSet<'a> { use UnionVariant::*; match variant { Never => Layout::Union(UnionLayout::NonRecursive(&[])), - BoolUnion { .. } => Layout::Builtin(Builtin::Int1), - ByteUnion { .. } => Layout::Builtin(Builtin::Int8), + BoolUnion { .. } => Layout::bool(), + ByteUnion { .. } => Layout::u8(), Unit | UnitWithArguments => { // no useful information to store Layout::Struct(&[]) @@ -680,17 +680,11 @@ impl<'a> LambdaSet<'a> { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum Builtin<'a> { - Int128, - Int64, - Int32, - Int16, - Int8, - Int1, + Int(IntWidth), + Float(FloatWidth), + Bool, Usize, Decimal, - Float128, - Float64, - Float32, Str, Dict(&'a Layout<'a>, &'a Layout<'a>), Set(&'a Layout<'a>), @@ -759,61 +753,61 @@ impl<'a> Layout<'a> { // Ints Alias(Symbol::NUM_I128, args, _) => { debug_assert!(args.is_empty()); - Ok(Layout::Builtin(Builtin::Int128)) + Ok(Layout::i128()) } Alias(Symbol::NUM_I64, args, _) => { debug_assert!(args.is_empty()); - Ok(Layout::Builtin(Builtin::Int64)) + Ok(Layout::i64()) } Alias(Symbol::NUM_I32, args, _) => { debug_assert!(args.is_empty()); - Ok(Layout::Builtin(Builtin::Int32)) + Ok(Layout::i32()) } Alias(Symbol::NUM_I16, args, _) => { debug_assert!(args.is_empty()); - Ok(Layout::Builtin(Builtin::Int16)) + Ok(Layout::i16()) } Alias(Symbol::NUM_I8, args, _) => { debug_assert!(args.is_empty()); - Ok(Layout::Builtin(Builtin::Int8)) + Ok(Layout::i8()) } // I think unsigned and signed use the same layout Alias(Symbol::NUM_U128, args, _) => { debug_assert!(args.is_empty()); - Ok(Layout::Builtin(Builtin::Int128)) + Ok(Layout::u128()) } Alias(Symbol::NUM_U64, args, _) => { debug_assert!(args.is_empty()); - Ok(Layout::Builtin(Builtin::Int64)) + Ok(Layout::u64()) } Alias(Symbol::NUM_U32, args, _) => { debug_assert!(args.is_empty()); - Ok(Layout::Builtin(Builtin::Int32)) + Ok(Layout::u32()) } Alias(Symbol::NUM_U16, args, _) => { debug_assert!(args.is_empty()); - Ok(Layout::Builtin(Builtin::Int16)) + Ok(Layout::u16()) } Alias(Symbol::NUM_U8, args, _) => { debug_assert!(args.is_empty()); - Ok(Layout::Builtin(Builtin::Int8)) + Ok(Layout::u8()) } // Floats Alias(Symbol::NUM_F64, args, _) => { debug_assert!(args.is_empty()); - Ok(Layout::Builtin(Builtin::Float64)) + Ok(Layout::f64()) } Alias(Symbol::NUM_F32, args, _) => { debug_assert!(args.is_empty()); - Ok(Layout::Builtin(Builtin::Float32)) + Ok(Layout::f32()) } // Nat Alias(Symbol::NUM_NAT, args, _) => { debug_assert!(args.is_empty()); - Ok(Layout::Builtin(Builtin::Usize)) + Ok(Layout::usize()) } Alias(_, _, var) => Self::from_var(env, var), @@ -1148,6 +1142,76 @@ impl<'a> LayoutCache<'a> { // placeholder for the type ven_ena::unify::Snapshot>> pub struct SnapshotKeyPlaceholder; +impl<'a> Layout<'a> { + pub fn int_width(width: IntWidth) -> Layout<'a> { + Layout::Builtin(Builtin::Int(width)) + } + + pub fn float_width(width: FloatWidth) -> Layout<'a> { + Layout::Builtin(Builtin::Float(width)) + } + + pub fn f64() -> Layout<'a> { + Layout::Builtin(Builtin::Float(FloatWidth::F64)) + } + + pub fn f32() -> Layout<'a> { + Layout::Builtin(Builtin::Float(FloatWidth::F32)) + } + + pub fn usize() -> Layout<'a> { + Layout::Builtin(Builtin::Usize) + } + + pub fn bool() -> Layout<'a> { + Layout::Builtin(Builtin::Bool) + } + + pub fn u8() -> Layout<'a> { + Layout::Builtin(Builtin::Int(IntWidth::U8)) + } + + pub fn u16() -> Layout<'a> { + Layout::Builtin(Builtin::Int(IntWidth::U16)) + } + + pub fn u32() -> Layout<'a> { + Layout::Builtin(Builtin::Int(IntWidth::U32)) + } + + pub fn u64() -> Layout<'a> { + Layout::Builtin(Builtin::Int(IntWidth::U64)) + } + + pub fn u128() -> Layout<'a> { + Layout::Builtin(Builtin::Int(IntWidth::U128)) + } + + pub fn i8() -> Layout<'a> { + Layout::Builtin(Builtin::Int(IntWidth::I8)) + } + + pub fn i16() -> Layout<'a> { + Layout::Builtin(Builtin::Int(IntWidth::I16)) + } + + pub fn i32() -> Layout<'a> { + Layout::Builtin(Builtin::Int(IntWidth::I32)) + } + + pub fn i64() -> Layout<'a> { + Layout::Builtin(Builtin::Int(IntWidth::I64)) + } + + pub fn i128() -> Layout<'a> { + Layout::Builtin(Builtin::Int(IntWidth::I128)) + } + + pub fn default_integer() -> Layout<'a> { + Layout::i64() + } +} + impl<'a> Builtin<'a> { const I128_SIZE: u32 = std::mem::size_of::() as u32; const I64_SIZE: u32 = std::mem::size_of::() as u32; @@ -1177,17 +1241,11 @@ impl<'a> Builtin<'a> { use Builtin::*; match self { - Int128 => Builtin::I128_SIZE, - Int64 => Builtin::I64_SIZE, - Int32 => Builtin::I32_SIZE, - Int16 => Builtin::I16_SIZE, - Int8 => Builtin::I8_SIZE, - Int1 => Builtin::I1_SIZE, + Int(int) => int.stack_size(), + Float(float) => float.stack_size(), + Bool => Builtin::I1_SIZE, Usize => pointer_size, Decimal => Builtin::DECIMAL_SIZE, - Float128 => Builtin::F128_SIZE, - Float64 => Builtin::F64_SIZE, - Float32 => Builtin::F32_SIZE, Str | EmptyStr => Builtin::STR_WORDS * pointer_size, Dict(_, _) | EmptyDict => Builtin::DICT_WORDS * pointer_size, Set(_) | EmptySet => Builtin::SET_WORDS * pointer_size, @@ -1203,17 +1261,11 @@ impl<'a> Builtin<'a> { // since both of those are one pointer size, the alignment of that structure is a pointer // size match self { - Int128 => align_of::() as u32, - Int64 => align_of::() as u32, - Int32 => align_of::() as u32, - Int16 => align_of::() as u32, - Int8 => align_of::() as u32, - Int1 => align_of::() as u32, + Int(int_width) => int_width.alignment_bytes(), + Float(float_width) => float_width.alignment_bytes(), + Bool => align_of::() as u32, Usize => pointer_size, Decimal => align_of::() as u32, - Float128 => align_of::() as u32, - Float64 => align_of::() as u32, - Float32 => align_of::() as u32, Dict(_, _) | EmptyDict => pointer_size, Set(_) | EmptySet => pointer_size, // we often treat these as i128 (64-bit systems) @@ -1230,8 +1282,9 @@ impl<'a> Builtin<'a> { use Builtin::*; match self { - Int128 | Int64 | Int32 | Int16 | Int8 | Int1 | Usize | Decimal | Float128 | Float64 - | Float32 | EmptyStr | EmptyDict | EmptyList | EmptySet => true, + Int(_) | Usize | Float(_) | Bool | Decimal | EmptyStr | EmptyDict | EmptyList + | EmptySet => true, + Str | Dict(_, _) | Set(_) | List(_) => false, } } @@ -1241,8 +1294,8 @@ impl<'a> Builtin<'a> { use Builtin::*; match self { - Int128 | Int64 | Int32 | Int16 | Int8 | Int1 | Usize | Decimal | Float128 | Float64 - | Float32 | EmptyStr | EmptyDict | EmptyList | EmptySet => false, + Int(_) | Usize | Float(_) | Bool | Decimal | EmptyStr | EmptyDict | EmptyList + | EmptySet => false, List(_) => true, Str | Dict(_, _) | Set(_) => true, @@ -1258,17 +1311,36 @@ impl<'a> Builtin<'a> { use Builtin::*; match self { - Int128 => alloc.text("Int128"), - Int64 => alloc.text("Int64"), - Int32 => alloc.text("Int32"), - Int16 => alloc.text("Int16"), - Int8 => alloc.text("Int8"), - Int1 => alloc.text("Int1"), + Int(int_width) => { + use IntWidth::*; + + match int_width { + I128 => alloc.text("I128"), + I64 => alloc.text("I64"), + I32 => alloc.text("I32"), + I16 => alloc.text("I16"), + I8 => alloc.text("I8"), + U128 => alloc.text("U128"), + U64 => alloc.text("U64"), + U32 => alloc.text("U32"), + U16 => alloc.text("U16"), + U8 => alloc.text("U8"), + } + } + + Float(float_width) => { + use FloatWidth::*; + + match float_width { + F128 => alloc.text("Float128"), + F64 => alloc.text("Float64"), + F32 => alloc.text("Float32"), + } + } + + Bool => alloc.text("Int1"), Usize => alloc.text("Usize"), Decimal => alloc.text("Decimal"), - Float128 => alloc.text("Float128"), - Float64 => alloc.text("Float64"), - Float32 => alloc.text("Float32"), EmptyStr => alloc.text("EmptyStr"), EmptyList => alloc.text("EmptyList"), @@ -1292,17 +1364,11 @@ impl<'a> Builtin<'a> { pub fn allocation_alignment_bytes(&self, pointer_size: u32) -> u32 { let allocation = match self { - Builtin::Int128 - | Builtin::Int64 - | Builtin::Int32 - | Builtin::Int16 - | Builtin::Int8 - | Builtin::Int1 + Builtin::Int(_) + | Builtin::Float(_) + | Builtin::Bool | Builtin::Usize - | Builtin::Decimal - | Builtin::Float128 - | Builtin::Float64 - | Builtin::Float32 => unreachable!("not heap-allocated"), + | Builtin::Decimal => unreachable!("not heap-allocated"), Builtin::Str => pointer_size, Builtin::Dict(k, v) => k .alignment_bytes(pointer_size) @@ -1342,44 +1408,44 @@ fn layout_from_flat_type<'a>( Symbol::NUM_I128 => { debug_assert_eq!(args.len(), 0); - Ok(Layout::Builtin(Builtin::Int128)) + Ok(Layout::i128()) } Symbol::NUM_I64 => { debug_assert_eq!(args.len(), 0); - Ok(Layout::Builtin(Builtin::Int64)) + Ok(Layout::i64()) } Symbol::NUM_I32 => { debug_assert_eq!(args.len(), 0); - Ok(Layout::Builtin(Builtin::Int32)) + Ok(Layout::i32()) } Symbol::NUM_I16 => { debug_assert_eq!(args.len(), 0); - Ok(Layout::Builtin(Builtin::Int16)) + Ok(Layout::i16()) } Symbol::NUM_I8 => { debug_assert_eq!(args.len(), 0); - Ok(Layout::Builtin(Builtin::Int8)) + Ok(Layout::i8()) } Symbol::NUM_U128 => { debug_assert_eq!(args.len(), 0); - Ok(Layout::Builtin(Builtin::Int128)) + Ok(Layout::u128()) } Symbol::NUM_U64 => { debug_assert_eq!(args.len(), 0); - Ok(Layout::Builtin(Builtin::Int64)) + Ok(Layout::u64()) } Symbol::NUM_U32 => { debug_assert_eq!(args.len(), 0); - Ok(Layout::Builtin(Builtin::Int32)) + Ok(Layout::u32()) } Symbol::NUM_U16 => { debug_assert_eq!(args.len(), 0); - Ok(Layout::Builtin(Builtin::Int16)) + Ok(Layout::u16()) } Symbol::NUM_U8 => { debug_assert_eq!(args.len(), 0); - Ok(Layout::Builtin(Builtin::Int8)) + Ok(Layout::u8()) } // Floats @@ -1389,11 +1455,11 @@ fn layout_from_flat_type<'a>( } Symbol::NUM_F64 => { debug_assert_eq!(args.len(), 0); - Ok(Layout::Builtin(Builtin::Float64)) + Ok(Layout::f64()) } Symbol::NUM_F32 => { debug_assert_eq!(args.len(), 0); - Ok(Layout::Builtin(Builtin::Float32)) + Ok(Layout::f32()) } Symbol::NUM_NUM | Symbol::NUM_AT_NUM => { @@ -2295,8 +2361,8 @@ fn layout_from_tag_union<'a>( match variant { Never => Layout::Union(UnionLayout::NonRecursive(&[])), Unit | UnitWithArguments => Layout::Struct(&[]), - BoolUnion { .. } => Layout::Builtin(Builtin::Int1), - ByteUnion(_) => Layout::Builtin(Builtin::Int8), + BoolUnion { .. } => Layout::bool(), + ByteUnion(_) => Layout::u8(), Newtype { arguments: field_layouts, .. @@ -2396,30 +2462,32 @@ fn layout_from_num_content<'a>(content: &Content) -> Result, LayoutPr // type variable, then assume it's a 64-bit integer. // // (e.g. for (5 + 5) assume both 5s are 64-bit integers.) - Ok(Layout::Builtin(DEFAULT_NUM_BUILTIN)) + Ok(Layout::default_integer()) } Structure(Apply(symbol, args)) => match *symbol { // Ints - Symbol::NUM_NAT => Ok(Layout::Builtin(Builtin::Usize)), + Symbol::NUM_NAT => Ok(Layout::usize()), - Symbol::NUM_INTEGER => Ok(Layout::Builtin(Builtin::Int64)), - Symbol::NUM_I128 => Ok(Layout::Builtin(Builtin::Int128)), - Symbol::NUM_I64 => Ok(Layout::Builtin(Builtin::Int64)), - Symbol::NUM_I32 => Ok(Layout::Builtin(Builtin::Int32)), - Symbol::NUM_I16 => Ok(Layout::Builtin(Builtin::Int16)), - Symbol::NUM_I8 => Ok(Layout::Builtin(Builtin::Int8)), + Symbol::NUM_INTEGER => Ok(Layout::i64()), + Symbol::NUM_I128 => Ok(Layout::i128()), + Symbol::NUM_I64 => Ok(Layout::i64()), + Symbol::NUM_I32 => Ok(Layout::i32()), + Symbol::NUM_I16 => Ok(Layout::i16()), + Symbol::NUM_I8 => Ok(Layout::i8()), - Symbol::NUM_U128 => Ok(Layout::Builtin(Builtin::Int128)), - Symbol::NUM_U64 => Ok(Layout::Builtin(Builtin::Int64)), - Symbol::NUM_U32 => Ok(Layout::Builtin(Builtin::Int32)), - Symbol::NUM_U16 => Ok(Layout::Builtin(Builtin::Int16)), - Symbol::NUM_U8 => Ok(Layout::Builtin(Builtin::Int8)), + Symbol::NUM_U128 => Ok(Layout::u128()), + Symbol::NUM_U64 => Ok(Layout::u64()), + Symbol::NUM_U32 => Ok(Layout::u32()), + Symbol::NUM_U16 => Ok(Layout::u16()), + Symbol::NUM_U8 => Ok(Layout::u8()), // Floats - Symbol::NUM_FLOATINGPOINT => Ok(Layout::Builtin(Builtin::Float64)), + Symbol::NUM_FLOATINGPOINT => Ok(Layout::f64()), + Symbol::NUM_F64 => Ok(Layout::f64()), + Symbol::NUM_F32 => Ok(Layout::f32()), + + // Dec Symbol::NUM_DEC => Ok(Layout::Builtin(Builtin::Decimal)), - Symbol::NUM_F64 => Ok(Layout::Builtin(Builtin::Float64)), - Symbol::NUM_F32 => Ok(Layout::Builtin(Builtin::Float32)), _ => { panic!( @@ -2451,26 +2519,29 @@ fn unwrap_num_tag<'a>(subs: &Subs, var: Variable) -> Result, LayoutPr Content::Alias(symbol, args, _) => { debug_assert!(args.is_empty()); - let builtin = match *symbol { - Symbol::NUM_SIGNED128 => Builtin::Int128, - Symbol::NUM_SIGNED64 => Builtin::Int64, - Symbol::NUM_SIGNED32 => Builtin::Int32, - Symbol::NUM_SIGNED16 => Builtin::Int16, - Symbol::NUM_SIGNED8 => Builtin::Int8, - Symbol::NUM_UNSIGNED128 => Builtin::Int128, - Symbol::NUM_UNSIGNED64 => Builtin::Int64, - Symbol::NUM_UNSIGNED32 => Builtin::Int32, - Symbol::NUM_UNSIGNED16 => Builtin::Int16, - Symbol::NUM_UNSIGNED8 => Builtin::Int8, - Symbol::NUM_NATURAL => Builtin::Usize, + let width = match *symbol { + Symbol::NUM_SIGNED128 => IntWidth::I128, + Symbol::NUM_SIGNED64 => IntWidth::I64, + Symbol::NUM_SIGNED32 => IntWidth::I32, + Symbol::NUM_SIGNED16 => IntWidth::I16, + Symbol::NUM_SIGNED8 => IntWidth::I8, + Symbol::NUM_UNSIGNED128 => IntWidth::U128, + Symbol::NUM_UNSIGNED64 => IntWidth::U64, + Symbol::NUM_UNSIGNED32 => IntWidth::U32, + Symbol::NUM_UNSIGNED16 => IntWidth::U16, + Symbol::NUM_UNSIGNED8 => IntWidth::U8, + Symbol::NUM_NATURAL => { + return Ok(Layout::usize()); + } + _ => unreachable!("not a valid int variant: {:?} {:?}", symbol, args), }; - Ok(Layout::Builtin(builtin)) + Ok(Layout::Builtin(Builtin::Int(width))) } Content::FlexVar(_) | Content::RigidVar(_) => { // default to i64 - Ok(Layout::Builtin(Builtin::Int64)) + Ok(Layout::i64()) } _ => unreachable!("not a valid int variant: {:?}", precision), } @@ -2486,12 +2557,12 @@ fn unwrap_num_tag<'a>(subs: &Subs, var: Variable) -> Result, LayoutPr Content::Alias(Symbol::NUM_BINARY32, args, _) => { debug_assert!(args.is_empty()); - Ok(Layout::Builtin(Builtin::Float32)) + Ok(Layout::f32()) } Content::Alias(Symbol::NUM_BINARY64, args, _) => { debug_assert!(args.is_empty()); - Ok(Layout::Builtin(Builtin::Float64)) + Ok(Layout::f64()) } Content::Alias(Symbol::NUM_DECIMAL, args, _) => { debug_assert!(args.is_empty()); @@ -2500,14 +2571,14 @@ fn unwrap_num_tag<'a>(subs: &Subs, var: Variable) -> Result, LayoutPr } Content::FlexVar(_) | Content::RigidVar(_) => { // default to f64 - Ok(Layout::Builtin(Builtin::Float64)) + Ok(Layout::f64()) } _ => unreachable!("not a valid float variant: {:?}", precision), } } Content::FlexVar(_) | Content::RigidVar(_) => { // If this was still a (Num *) then default to compiling it to i64 - Ok(Layout::Builtin(DEFAULT_NUM_BUILTIN)) + Ok(Layout::default_integer()) } other => { todo!("TODO non structure Num.@Num flat_type {:?}", other);