From 9b1769b3fb6713764b81875c3a0ef9ff395f82bd Mon Sep 17 00:00:00 2001 From: Jared Ramirez Date: Thu, 17 Dec 2020 19:39:39 -0800 Subject: [PATCH 1/4] Add basic tests for number gen --- compiler/gen/src/llvm/build.rs | 31 ++++++++++++++++-- compiler/gen/tests/gen_num.rs | 57 ++++++++++++++++++++++++++++++++++ compiler/mono/src/layout.rs | 8 +++++ 3 files changed, 93 insertions(+), 3 deletions(-) diff --git a/compiler/gen/src/llvm/build.rs b/compiler/gen/src/llvm/build.rs index a14c7fae26..bca2859bc2 100644 --- a/compiler/gen/src/llvm/build.rs +++ b/compiler/gen/src/llvm/build.rs @@ -477,13 +477,27 @@ fn get_inplace_from_layout(layout: &Layout<'_>) -> InPlace { pub fn build_exp_literal<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout: &Layout<'_>, literal: &roc_mono::ir::Literal<'a>, ) -> BasicValueEnum<'ctx> { use roc_mono::ir::Literal::*; match literal { - Int(num) => env.context.i64_type().const_int(*num as u64, true).into(), - Float(num) => env.context.f64_type().const_float(*num).into(), + Int(int) => + (match layout { + Layout::Builtin(Builtin::Int128) => env.context.i128_type(), /* TODO file an issue: you can't currently have an int literal bigger than 64 bits long, and also (as we see here), you can't currently have (at least in Inkwell) a when-branch with an i128 literal in its pattren */ + Layout::Builtin(Builtin::Int64) => env.context.i64_type(), + Layout::Builtin(Builtin::Int32) => env.context.i32_type(), + Layout::Builtin(Builtin::Int16) => env.context.i16_type(), + Layout::Builtin(Builtin::Int8) => env.context.i8_type(), + _ => panic!("Invalid layout for int literal = {:?}", layout), + }).const_int(*int as u64, false).into(), + Float(num) => + (match layout { + Layout::Builtin(Builtin::Float64) => env.context.f64_type(), + Layout::Builtin(Builtin::Float32) => env.context.f32_type(), + _ => panic!("Invalid layout for float literal = {:?}", layout), + }).const_float(*num).into(), Bool(b) => env.context.bool_type().const_int(*b as u64, false).into(), Byte(b) => env.context.i8_type().const_int(*b as u64, false).into(), Str(str_literal) => { @@ -622,7 +636,7 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( use roc_mono::ir::Expr::*; match expr { - Literal(literal) => build_exp_literal(env, literal), + Literal(literal) => build_exp_literal(env, layout, literal), RunLowLevel(op, symbols) => { run_low_level(env, layout_ids, scope, parent, layout, *op, symbols) } @@ -1691,6 +1705,15 @@ fn build_switch_ir<'a, 'ctx, 'env>( .build_bitcast(full_cond, env.context.i64_type(), "") .into_int_value() } + Layout::Builtin(Builtin::Float32) => { + // float matches are done on the bit pattern + cond_layout = Layout::Builtin(Builtin::Int32); + let full_cond = load_symbol(env, scope, cond_symbol); + + builder + .build_bitcast(full_cond, env.context.i32_type(), "") + .into_int_value() + } Layout::Union(_) => { // we match on the discriminant, not the whole Tag cond_layout = Layout::Builtin(Builtin::Int64); @@ -3622,6 +3645,7 @@ fn build_int_unary_op<'a, 'ctx, 'env>( int_abs_raise_on_overflow(env, arg, arg_layout) } NumToFloat => { + // TODO: Handle differnt sized numbers // This is an Int, so we need to convert it. bd.build_cast( InstructionOpcode::SIToFP, @@ -3748,6 +3772,7 @@ fn build_float_unary_op<'a, 'ctx, 'env>( let bd = env.builder; + // TODO: Handle differnt sized floats match op { NumNeg => bd.build_float_neg(arg, "negate_float").into(), NumAbs => env.call_intrinsic(LLVM_FABS_F64, &[arg.into()]), diff --git a/compiler/gen/tests/gen_num.rs b/compiler/gen/tests/gen_num.rs index 2dc79e07f8..92422dec3e 100644 --- a/compiler/gen/tests/gen_num.rs +++ b/compiler/gen/tests/gen_num.rs @@ -15,6 +15,63 @@ mod helpers; mod gen_num { use roc_std::RocOrder; + #[test] + fn i128_signed_int_alias() { + assert_evals_to!("15 : I128", 15, i128); + } + #[test] + fn i64_signed_int_alias() { + assert_evals_to!("15 : I64", 15, i64); + } + #[test] + fn i32_signed_int_alias() { + assert_evals_to!("15 : I32", 15, i32); + } + #[test] + fn i16_signed_int_alias() { + assert_evals_to!("15 : I16", 15, i16); + } + #[test] + fn i8_signed_int_alias() { + assert_evals_to!("15 : I8", 15, i8); + } + + #[test] + fn i8_signed_int_alias_overflow() { + // TODO: How/where do we handle overflow + assert_evals_to!("(127 + 1): I8", -128, i8); + } + + #[test] + fn u128_unsigned_int_alias() { + assert_evals_to!("15 : U128", 15, u128); + } + #[test] + fn u64_unsigned_int_alias() { + assert_evals_to!("15 : U64", 15, u64); + } + #[test] + fn u32_unsigned_int_alias() { + assert_evals_to!("15 : U32", 15, u32); + } + #[test] + fn u16_unsigned_int_alias() { + assert_evals_to!("15 : U16", 15, u16); + } + #[test] + fn u8_unsigned_int_alias() { + assert_evals_to!("15 : u8", 15, u8); + } + + #[test] + fn f64_float_alias() { + assert_evals_to!("3.6 : F64", 3.6, f64); + } + #[test] + fn f32_float_alias() { + assert_evals_to!("3.6 : F32", 3.6, f32); + } + #[test] fn f64_sqrt() { // FIXME this works with normal types, but fails when checking uniqueness types diff --git a/compiler/mono/src/layout.rs b/compiler/mono/src/layout.rs index 2d746d1a29..ec725bf6f3 100644 --- a/compiler/mono/src/layout.rs +++ b/compiler/mono/src/layout.rs @@ -370,6 +370,10 @@ impl<'a> Layout<'a> { debug_assert!(args.is_empty()); Ok(Layout::Builtin(Builtin::Float64)) } + Alias(Symbol::NUM_F32, args, _) => { + debug_assert!(args.is_empty()); + Ok(Layout::Builtin(Builtin::Float32)) + } Alias(_, _, var) => Self::from_var(env, var), Error => Err(LayoutProblem::Erroneous), } @@ -771,6 +775,10 @@ fn layout_from_flat_type<'a>( debug_assert_eq!(args.len(), 0); Ok(Layout::Builtin(Builtin::Float64)) } + Symbol::NUM_F32 => { + debug_assert_eq!(args.len(), 0); + Ok(Layout::Builtin(Builtin::Float32)) + } Symbol::NUM_NUM | Symbol::NUM_AT_NUM => { // Num.Num should only ever have 1 argument, e.g. Num.Num Int.Integer debug_assert_eq!(args.len(), 1); From 5e332cbad9f0e445b562bdfae758ae04fa3f5995 Mon Sep 17 00:00:00 2001 From: Jared Ramirez Date: Thu, 24 Dec 2020 15:32:09 -0500 Subject: [PATCH 2/4] [WIP] F32 gen --- compiler/gen/src/llvm/build.rs | 12 +++- compiler/gen/tests/gen_num.rs | 26 +++++++- compiler/gen/tests/helpers/eval.rs | 7 ++ compiler/mono/src/layout.rs | 103 +++++++++++++++++++++++++++++ 4 files changed, 145 insertions(+), 3 deletions(-) diff --git a/compiler/gen/src/llvm/build.rs b/compiler/gen/src/llvm/build.rs index bca2859bc2..3fbba6c7de 100644 --- a/compiler/gen/src/llvm/build.rs +++ b/compiler/gen/src/llvm/build.rs @@ -495,7 +495,7 @@ pub fn build_exp_literal<'a, 'ctx, 'env>( Float(num) => (match layout { Layout::Builtin(Builtin::Float64) => env.context.f64_type(), - Layout::Builtin(Builtin::Float32) => env.context.f32_type(), + // Layout::Builtin(Builtin::Float32) => env.context.f32_type(), _ => panic!("Invalid layout for float literal = {:?}", layout), }).const_float(*num).into(), Bool(b) => env.context.bool_type().const_int(*b as u64, false).into(), @@ -1312,6 +1312,10 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>( Let(first_symbol, first_expr, first_layout, mut cont) => { let mut queue = Vec::new_in(env.arena); + dbg!(first_expr); + dbg!(first_layout); + + queue.push((first_symbol, first_expr, first_layout)); while let Let(symbol, expr, layout, new_cont) = cont { @@ -2203,6 +2207,9 @@ pub fn build_proc_header<'a, 'ctx, 'env>( .get(symbol, layout) .to_symbol_string(symbol, &env.interns); + dbg!("build_proc_header"); + dbg!(&fn_name); + use roc_mono::ir::HostExposedLayouts; match &proc.host_exposed_layouts { HostExposedLayouts::NotHostExposed => {} @@ -2602,6 +2609,9 @@ pub fn build_proc<'a, 'ctx, 'env>( scope.insert(*arg_symbol, (layout.clone(), alloca)); } + dbg!("build_proc"); + dbg!(&proc.body); + let body = build_exp_stmt(env, layout_ids, &mut scope, fn_val, &proc.body); // only add a return if codegen did not already add one diff --git a/compiler/gen/tests/gen_num.rs b/compiler/gen/tests/gen_num.rs index 92422dec3e..1b7be86555 100644 --- a/compiler/gen/tests/gen_num.rs +++ b/compiler/gen/tests/gen_num.rs @@ -65,11 +65,33 @@ mod gen_num { #[test] fn f64_float_alias() { - assert_evals_to!("3.6 : F64", 3.6, f64); + assert_evals_to!( + indoc!( + r#" + f : F64 + f = 3.6 + + f + "# + ), + 3.6, + f64 + ); } #[test] fn f32_float_alias() { - assert_evals_to!("3.6 : F32", 3.6, f32); + assert_evals_to!( + indoc!( + r#" + f : F32 + f = 3.6 + + f + "# + ), + 3.6, + f32 + ); } #[test] diff --git a/compiler/gen/tests/helpers/eval.rs b/compiler/gen/tests/helpers/eval.rs index fe22eebc85..63d3cd2ecc 100644 --- a/compiler/gen/tests/helpers/eval.rs +++ b/compiler/gen/tests/helpers/eval.rs @@ -201,6 +201,10 @@ pub fn helper<'a>( // because their bodies may reference each other. let mut scope = Scope::default(); for ((symbol, layout), proc) in procedures.drain() { + dbg!("helper: build_proc_header"); + dbg!(&proc); + dbg!(&layout); + let fn_val = build_proc_header(&env, &mut layout_ids, symbol, &layout, &proc); if proc.args.is_empty() { @@ -221,6 +225,9 @@ pub fn helper<'a>( let home = proc.name.module_id(); current_scope.retain_top_level_thunks_for_module(home); + dbg!("helper: build_proc"); + dbg!(&proc); + build_proc(&env, &mut layout_ids, scope.clone(), proc, fn_val); // call finalize() before any code generation/verification diff --git a/compiler/mono/src/layout.rs b/compiler/mono/src/layout.rs index ec725bf6f3..3cfd1c9c29 100644 --- a/compiler/mono/src/layout.rs +++ b/compiler/mono/src/layout.rs @@ -362,10 +362,51 @@ impl<'a> Layout<'a> { } Structure(flat_type) => layout_from_flat_type(env, flat_type), + // Ints + Alias(Symbol::NUM_I128, args, _) => { + debug_assert!(args.is_empty()); + Ok(Layout::Builtin(Builtin::Int128)) + } Alias(Symbol::NUM_I64, args, _) => { debug_assert!(args.is_empty()); Ok(Layout::Builtin(Builtin::Int64)) } + Alias(Symbol::NUM_I32, args, _) => { + debug_assert!(args.is_empty()); + Ok(Layout::Builtin(Builtin::Int32)) + } + Alias(Symbol::NUM_I16, args, _) => { + debug_assert!(args.is_empty()); + Ok(Layout::Builtin(Builtin::Int16)) + } + Alias(Symbol::NUM_I8, args, _) => { + debug_assert!(args.is_empty()); + Ok(Layout::Builtin(Builtin::Int8)) + } + + // I think unsigned and signed use the same layout + Alias(Symbol::NUM_U128, args, _) => { + debug_assert!(args.is_empty()); + Ok(Layout::Builtin(Builtin::Int128)) + } + Alias(Symbol::NUM_U64, args, _) => { + debug_assert!(args.is_empty()); + Ok(Layout::Builtin(Builtin::Int64)) + } + Alias(Symbol::NUM_U32, args, _) => { + debug_assert!(args.is_empty()); + Ok(Layout::Builtin(Builtin::Int32)) + } + Alias(Symbol::NUM_U16, args, _) => { + debug_assert!(args.is_empty()); + Ok(Layout::Builtin(Builtin::Int16)) + } + Alias(Symbol::NUM_U8, args, _) => { + debug_assert!(args.is_empty()); + Ok(Layout::Builtin(Builtin::Int8)) + } + + // Floats Alias(Symbol::NUM_F64, args, _) => { debug_assert!(args.is_empty()); Ok(Layout::Builtin(Builtin::Float64)) @@ -374,6 +415,7 @@ impl<'a> Layout<'a> { debug_assert!(args.is_empty()); Ok(Layout::Builtin(Builtin::Float32)) } + Alias(_, _, var) => Self::from_var(env, var), Error => Err(LayoutProblem::Erroneous), } @@ -767,10 +809,51 @@ fn layout_from_flat_type<'a>( match flat_type { Apply(symbol, args) => { match symbol { + // Ints + Symbol::NUM_I128 => { + debug_assert_eq!(args.len(), 0); + Ok(Layout::Builtin(Builtin::Int128)) + } Symbol::NUM_I64 => { debug_assert_eq!(args.len(), 0); Ok(Layout::Builtin(Builtin::Int64)) } + Symbol::NUM_I32 => { + debug_assert_eq!(args.len(), 0); + Ok(Layout::Builtin(Builtin::Int64)) + } + Symbol::NUM_I16 => { + debug_assert_eq!(args.len(), 0); + Ok(Layout::Builtin(Builtin::Int64)) + } + Symbol::NUM_I8 => { + debug_assert_eq!(args.len(), 0); + Ok(Layout::Builtin(Builtin::Int64)) + } + + // I think unsigned and signed use the same layout + Symbol::NUM_U128 => { + debug_assert_eq!(args.len(), 0); + Ok(Layout::Builtin(Builtin::Int128)) + } + Symbol::NUM_U64 => { + debug_assert_eq!(args.len(), 0); + Ok(Layout::Builtin(Builtin::Int64)) + } + Symbol::NUM_U32 => { + debug_assert_eq!(args.len(), 0); + Ok(Layout::Builtin(Builtin::Int64)) + } + Symbol::NUM_U16 => { + debug_assert_eq!(args.len(), 0); + Ok(Layout::Builtin(Builtin::Int64)) + } + Symbol::NUM_U8 => { + debug_assert_eq!(args.len(), 0); + Ok(Layout::Builtin(Builtin::Int64)) + } + + // Floats Symbol::NUM_F64 => { debug_assert_eq!(args.len(), 0); Ok(Layout::Builtin(Builtin::Float64)) @@ -779,6 +862,7 @@ fn layout_from_flat_type<'a>( debug_assert_eq!(args.len(), 0); Ok(Layout::Builtin(Builtin::Float32)) } + Symbol::NUM_NUM | Symbol::NUM_AT_NUM => { // Num.Num should only ever have 1 argument, e.g. Num.Num Int.Integer debug_assert_eq!(args.len(), 1); @@ -788,6 +872,7 @@ fn layout_from_flat_type<'a>( layout_from_num_content(content) } + Symbol::STR_STR => Ok(Layout::Builtin(Builtin::Str)), Symbol::LIST_LIST => list_layout_from_elem(env, args[0]), Symbol::ATTR_ATTR => { @@ -1271,8 +1356,26 @@ fn layout_from_num_content<'a>(content: Content) -> Result, LayoutPro Ok(Layout::Builtin(DEFAULT_NUM_BUILTIN)) } Structure(Apply(symbol, args)) => match symbol { + // Ints 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)), + + // I think unsigned and signed use the same layout + 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)), + + // Floats Symbol::NUM_FLOATINGPOINT => Ok(Layout::Builtin(Builtin::Float64)), + Symbol::NUM_F64 => Ok(Layout::Builtin(Builtin::Float64)), + Symbol::NUM_F32 => Ok(Layout::Builtin(Builtin::Float32)), + _ => { panic!( "Invalid Num.Num type application: {:?}", From 48f964adf49faab14cf3eea5474183cba03caf57 Mon Sep 17 00:00:00 2001 From: Jared Ramirez Date: Mon, 28 Dec 2020 16:22:34 -0600 Subject: [PATCH 3/4] Add percision variable in fp/integer eq constraints --- compiler/can/src/builtins.rs | 33 +++++++++++++------ compiler/can/src/def.rs | 2 +- compiler/can/src/expr.rs | 8 ++--- compiler/can/src/module.rs | 6 ++-- compiler/can/src/num.rs | 4 +-- compiler/can/src/pattern.rs | 8 ++--- compiler/constrain/src/builtins.rs | 51 ++++++++++++++++++++---------- compiler/constrain/src/expr.rs | 4 +-- compiler/constrain/src/pattern.rs | 8 ++--- compiler/constrain/src/uniq.rs | 16 ++++------ compiler/gen/tests/gen_num.rs | 16 ++++++++++ compiler/load/src/file.rs | 1 + compiler/mono/src/decision_tree.rs | 6 ++-- compiler/mono/src/exhaustive.rs | 2 +- compiler/mono/src/ir.rs | 18 +++++------ compiler/mono/src/layout.rs | 2 ++ compiler/uniq/src/sharing.rs | 6 ++-- 17 files changed, 120 insertions(+), 71 deletions(-) diff --git a/compiler/can/src/builtins.rs b/compiler/can/src/builtins.rs index 8d9a0ae2f1..007c48bee8 100644 --- a/compiler/can/src/builtins.rs +++ b/compiler/can/src/builtins.rs @@ -212,7 +212,8 @@ pub fn builtin_defs(var_store: &mut VarStore) -> MutMap { /// Num.maxInt : Int fn num_max_int(symbol: Symbol, var_store: &mut VarStore) -> Def { let int_var = var_store.fresh(); - let body = Int(int_var, i64::MAX); + let int_percision_var = var_store.fresh(); + let body = Int(int_var, int_percision_var, i64::MAX); Def { annotation: None, @@ -226,7 +227,8 @@ fn num_max_int(symbol: Symbol, var_store: &mut VarStore) -> Def { /// Num.minInt : Int fn num_min_int(symbol: Symbol, var_store: &mut VarStore) -> Def { let int_var = var_store.fresh(); - let body = Int(int_var, i64::MIN); + let int_percision_var = var_store.fresh(); + let body = Int(int_var, int_percision_var, i64::MIN); Def { annotation: None, @@ -846,7 +848,7 @@ fn num_is_odd(symbol: Symbol, var_store: &mut VarStore) -> Def { let body = RunLowLevel { op: LowLevel::Eq, args: vec![ - (arg_var, Int(var_store.fresh(), 1)), + (arg_var, Int(var_store.fresh(), var_store.fresh(), 1)), ( arg_var, RunLowLevel { @@ -930,6 +932,7 @@ fn num_sqrt(symbol: Symbol, var_store: &mut VarStore) -> Def { let bool_var = var_store.fresh(); let float_var = var_store.fresh(); let unbound_zero_var = var_store.fresh(); + let percision_var = var_store.fresh(); let ret_var = var_store.fresh(); let body = If { @@ -943,7 +946,7 @@ fn num_sqrt(symbol: Symbol, var_store: &mut VarStore) -> Def { op: LowLevel::NotEq, args: vec![ (float_var, Var(Symbol::ARG_1)), - (float_var, Float(unbound_zero_var, 0.0)), + (float_var, Float(unbound_zero_var, percision_var, 0.0)), ], ret_var: bool_var, }, @@ -1896,6 +1899,7 @@ fn num_div_float(symbol: Symbol, var_store: &mut VarStore) -> Def { let bool_var = var_store.fresh(); let num_var = var_store.fresh(); let unbound_zero_var = var_store.fresh(); + let percision_var = var_store.fresh(); let ret_var = var_store.fresh(); let body = If { @@ -1909,7 +1913,7 @@ fn num_div_float(symbol: Symbol, var_store: &mut VarStore) -> Def { op: LowLevel::NotEq, args: vec![ (num_var, Var(Symbol::ARG_2)), - (num_var, Float(unbound_zero_var, 0.0)), + (num_var, Float(unbound_zero_var, percision_var, 0.0)), ], ret_var: bool_var, }, @@ -1958,6 +1962,7 @@ fn num_div_int(symbol: Symbol, var_store: &mut VarStore) -> Def { let bool_var = var_store.fresh(); let num_var = var_store.fresh(); let unbound_zero_var = var_store.fresh(); + let unbound_zero_percision_var = var_store.fresh(); let ret_var = var_store.fresh(); let body = If { @@ -1971,7 +1976,10 @@ fn num_div_int(symbol: Symbol, var_store: &mut VarStore) -> Def { op: LowLevel::NotEq, args: vec![ (num_var, Var(Symbol::ARG_2)), - (num_var, Int(unbound_zero_var, 0)), + ( + num_var, + Int(unbound_zero_var, unbound_zero_percision_var, 0), + ), ], ret_var: bool_var, }, @@ -2025,6 +2033,7 @@ fn list_first(symbol: Symbol, var_store: &mut VarStore) -> Def { let list_var = var_store.fresh(); let len_var = var_store.fresh(); let zero_var = var_store.fresh(); + let zero_percision_var = var_store.fresh(); let list_elem_var = var_store.fresh(); let ret_var = var_store.fresh(); @@ -2039,7 +2048,7 @@ fn list_first(symbol: Symbol, var_store: &mut VarStore) -> Def { RunLowLevel { op: LowLevel::NotEq, args: vec![ - (len_var, Int(zero_var, 0)), + (len_var, Int(zero_var, zero_percision_var, 0)), ( len_var, RunLowLevel { @@ -2061,7 +2070,10 @@ fn list_first(symbol: Symbol, var_store: &mut VarStore) -> Def { // List.#getUnsafe list 0 RunLowLevel { op: LowLevel::ListGetUnsafe, - args: vec![(list_var, Var(Symbol::ARG_1)), (len_var, Int(zero_var, 0))], + args: vec![ + (list_var, Var(Symbol::ARG_1)), + (len_var, Int(zero_var, zero_percision_var, 0)), + ], ret_var: list_elem_var, }, ], @@ -2102,6 +2114,7 @@ fn list_last(symbol: Symbol, var_store: &mut VarStore) -> Def { let list_var = var_store.fresh(); let len_var = var_store.fresh(); let num_var = var_store.fresh(); + let num_percision_var = var_store.fresh(); let list_elem_var = var_store.fresh(); let ret_var = var_store.fresh(); @@ -2116,7 +2129,7 @@ fn list_last(symbol: Symbol, var_store: &mut VarStore) -> Def { RunLowLevel { op: LowLevel::NotEq, args: vec![ - (len_var, Int(num_var, 0)), + (len_var, Int(num_var, num_percision_var, 0)), ( len_var, RunLowLevel { @@ -2155,7 +2168,7 @@ fn list_last(symbol: Symbol, var_store: &mut VarStore) -> Def { ret_var: len_var, }, ), - (arg_var, Int(num_var, 1)), + (arg_var, Int(num_var, num_percision_var, 1)), ], ret_var: len_var, }, diff --git a/compiler/can/src/def.rs b/compiler/can/src/def.rs index e58cb21df1..42675cd2b0 100644 --- a/compiler/can/src/def.rs +++ b/compiler/can/src/def.rs @@ -736,7 +736,7 @@ fn pattern_to_vars_by_symbol( NumLiteral(_, _) | IntLiteral(_) - | FloatLiteral(_) + | FloatLiteral(_, _) | StrLiteral(_) | Underscore | MalformedPattern(_, _) diff --git a/compiler/can/src/expr.rs b/compiler/can/src/expr.rs index cf1cc2d02b..bea498d237 100644 --- a/compiler/can/src/expr.rs +++ b/compiler/can/src/expr.rs @@ -56,8 +56,8 @@ pub enum Expr { Num(Variable, i64), // Int and Float store a variable to generate better error messages - Int(Variable, i64), - Float(Variable, f64), + Int(Variable, Variable, i64), + Float(Variable, Variable, f64), Str(InlinableString), List { list_var: Variable, // required for uniqueness of the list @@ -1170,8 +1170,8 @@ pub fn inline_calls(var_store: &mut VarStore, scope: &mut Scope, expr: Expr) -> // Num stores the `a` variable in `Num a`. Not the same as the variable // stored in Int and Float below, which is strictly for better error messages other @ Num(_, _) - | other @ Int(_, _) - | other @ Float(_, _) + | other @ Int(_, _, _) + | other @ Float(_, _, _) | other @ Str { .. } | other @ RuntimeError(_) | other @ EmptyRecord diff --git a/compiler/can/src/module.rs b/compiler/can/src/module.rs index 5f100a7a1b..c89977a233 100644 --- a/compiler/can/src/module.rs +++ b/compiler/can/src/module.rs @@ -364,7 +364,7 @@ fn fix_values_captured_in_closure_pattern( Identifier(_) | NumLiteral(_, _) | IntLiteral(_) - | FloatLiteral(_) + | FloatLiteral(_, _) | StrLiteral(_) | Underscore | Shadowed(_, _) @@ -414,8 +414,8 @@ fn fix_values_captured_in_closure_expr( } Num(_, _) - | Int(_, _) - | Float(_, _) + | Int(_, _, _) + | Float(_, _, _) | Str(_) | Var(_) | EmptyRecord diff --git a/compiler/can/src/num.rs b/compiler/can/src/num.rs index 9a0b810a6f..8d42b9775a 100644 --- a/compiler/can/src/num.rs +++ b/compiler/can/src/num.rs @@ -45,7 +45,7 @@ pub fn int_expr_from_result( ) -> Expr { // Int stores a variable to generate better error messages match result { - Ok(int) => Expr::Int(var_store.fresh(), int), + Ok(int) => Expr::Int(var_store.fresh(), var_store.fresh(), int), Err((raw, error)) => { let runtime_error = InvalidInt(error, base, region, raw.into()); @@ -65,7 +65,7 @@ pub fn float_expr_from_result( ) -> Expr { // Float stores a variable to generate better error messages match result { - Ok(float) => Expr::Float(var_store.fresh(), float), + Ok(float) => Expr::Float(var_store.fresh(), var_store.fresh(), float), Err((raw, error)) => { let runtime_error = InvalidFloat(error, region, raw.into()); diff --git a/compiler/can/src/pattern.rs b/compiler/can/src/pattern.rs index b082d9c628..8ff8da7226 100644 --- a/compiler/can/src/pattern.rs +++ b/compiler/can/src/pattern.rs @@ -27,7 +27,7 @@ pub enum Pattern { }, IntLiteral(i64), NumLiteral(Variable, i64), - FloatLiteral(f64), + FloatLiteral(Variable, f64), StrLiteral(Box), Underscore, @@ -87,7 +87,7 @@ pub fn symbols_from_pattern_help(pattern: &Pattern, symbols: &mut Vec) { NumLiteral(_, _) | IntLiteral(_) - | FloatLiteral(_) + | FloatLiteral(_, _) | StrLiteral(_) | Underscore | MalformedPattern(_, _) @@ -191,7 +191,7 @@ pub fn canonicalize_pattern<'a>( let problem = MalformedPatternProblem::MalformedFloat; malformed_pattern(env, problem, region) } - Ok(float) => Pattern::FloatLiteral(float), + Ok(float) => Pattern::FloatLiteral(var_store.fresh(), float), }, ptype => unsupported_pattern(env, ptype, region), }, @@ -464,7 +464,7 @@ fn add_bindings_from_patterns( } NumLiteral(_, _) | IntLiteral(_) - | FloatLiteral(_) + | FloatLiteral(_, _) | StrLiteral(_) | Underscore | Shadowed(_, _) diff --git a/compiler/constrain/src/builtins.rs b/compiler/constrain/src/builtins.rs index 1df15d5aef..ef8a497184 100644 --- a/compiler/constrain/src/builtins.rs +++ b/compiler/constrain/src/builtins.rs @@ -11,30 +11,58 @@ use roc_types::types::Reason; use roc_types::types::Type::{self, *}; #[inline(always)] -pub fn int_literal(num_var: Variable, expected: Expected, region: Region) -> Constraint { +pub fn int_literal( + num_var: Variable, + percision_var: Variable, + expected: Expected, + region: Region, +) -> Constraint { let num_type = Variable(num_var); let reason = Reason::IntLiteral; - let expected_literal = ForReason(reason, num_int(), region); exists( vec![num_var], And(vec![ - Eq(num_type.clone(), expected_literal, Category::Int, region), + Eq( + num_type.clone(), + ForReason( + reason, + // TODO: Put into seperate function? + num_num(num_integer(Type::Variable(percision_var))), + region, + ), + Category::Int, + region, + ), Eq(num_type, expected, Category::Int, region), ]), ) } #[inline(always)] -pub fn float_literal(num_var: Variable, expected: Expected, region: Region) -> Constraint { +pub fn float_literal( + num_var: Variable, + percision_var: Variable, + expected: Expected, + region: Region, +) -> Constraint { let num_type = Variable(num_var); let reason = Reason::FloatLiteral; - let expected_literal = ForReason(reason, num_float(), region); exists( vec![num_var], And(vec![ - Eq(num_type.clone(), expected_literal, Category::Float, region), + Eq( + num_type.clone(), + ForReason( + reason, + // TODO: Put into seperate function? + num_num(num_floatingpoint(Type::Variable(percision_var))), + region, + ), + Category::Float, + region, + ), Eq(num_type, expected, Category::Float, region), ]), ) @@ -71,15 +99,6 @@ pub fn str_type() -> Type { builtin_type(Symbol::STR_STR, Vec::new()) } -#[inline(always)] -pub fn num_float() -> Type { - Type::Alias( - Symbol::NUM_F64, - vec![], - Box::new(num_num(num_floatingpoint(num_binary64()))), - ) -} - #[inline(always)] pub fn num_floatingpoint(range: Type) -> Type { let alias_content = Type::TagUnion( @@ -108,7 +127,7 @@ pub fn num_binary64() -> Type { } #[inline(always)] -pub fn num_int() -> Type { +pub fn num_i64() -> Type { Type::Alias( Symbol::NUM_I64, vec![], diff --git a/compiler/constrain/src/expr.rs b/compiler/constrain/src/expr.rs index 000bbde915..2bde1b52da 100644 --- a/compiler/constrain/src/expr.rs +++ b/compiler/constrain/src/expr.rs @@ -96,7 +96,7 @@ pub fn constrain_expr( expected: Expected, ) -> Constraint { match expr { - Int(var, _) => int_literal(*var, expected, region), + Int(var, percision, _) => int_literal(*var, *percision, expected, region), Num(var, _) => exists( vec![*var], Eq( @@ -106,7 +106,7 @@ pub fn constrain_expr( region, ), ), - Float(var, _) => float_literal(*var, expected, region), + Float(var, percision, _) => float_literal(*var, *percision, expected, region), EmptyRecord => constrain_empty_record(region, expected), Expr::Record { record_var, fields } => { if fields.is_empty() { diff --git a/compiler/constrain/src/pattern.rs b/compiler/constrain/src/pattern.rs index 164df10b34..04cc1d0c7f 100644 --- a/compiler/constrain/src/pattern.rs +++ b/compiler/constrain/src/pattern.rs @@ -58,7 +58,7 @@ fn headers_from_annotation_help( | UnsupportedPattern(_) | NumLiteral(_, _) | IntLiteral(_) - | FloatLiteral(_) + | FloatLiteral(_, _) | StrLiteral(_) => true, RecordDestructure { destructs, .. } => match annotation.value.shallow_dealias() { @@ -158,16 +158,16 @@ pub fn constrain_pattern( state.constraints.push(Constraint::Pattern( region, PatternCategory::Int, - builtins::num_int(), + builtins::num_i64(), expected, )); } - FloatLiteral(_) => { + FloatLiteral(var, _) => { state.constraints.push(Constraint::Pattern( region, PatternCategory::Float, - builtins::num_float(), + builtins::num_floatingpoint(Type::Variable(*var)), expected, )); } diff --git a/compiler/constrain/src/uniq.rs b/compiler/constrain/src/uniq.rs index c3ce919dd3..a63d49ad3a 100644 --- a/compiler/constrain/src/uniq.rs +++ b/compiler/constrain/src/uniq.rs @@ -180,7 +180,7 @@ fn constrain_pattern( Constraint::Pattern(pattern.region, PatternCategory::Int, num_type, expected), )); } - FloatLiteral(_) => { + FloatLiteral(_, _) => { let (a, b, c, num_type) = unique_float(var_store); state.constraints.push(exists( @@ -423,10 +423,9 @@ fn unique_int(var_store: &mut VarStore) -> (Variable, Variable, Variable, Type) let num_uvar1 = var_store.fresh(); let num_uvar2 = var_store.fresh(); let num_uvar3 = var_store.fresh(); + let num_uvar4 = var_store.fresh(); - let signed_64 = num_signed64(); - let attr_signed_64 = attr_type(Bool::variable(num_uvar1), signed_64); - let integer = num_integer(attr_signed_64); + let integer = num_integer(Type::Variable(num_uvar4)); let attr_int = attr_type(Bool::variable(num_uvar2), integer); let num = num_num(attr_int); let attr_num = attr_type(Bool::variable(num_uvar3), num); @@ -438,10 +437,9 @@ fn unique_float(var_store: &mut VarStore) -> (Variable, Variable, Variable, Type let num_uvar1 = var_store.fresh(); let num_uvar2 = var_store.fresh(); let num_uvar3 = var_store.fresh(); + let num_uvar4 = var_store.fresh(); - let binary_64 = num_binary64(); - let attr_binary_64 = attr_type(Bool::variable(num_uvar1), binary_64); - let fp = num_floatingpoint(attr_binary_64); + let fp = num_floatingpoint(Type::Variable(num_uvar4)); let attr_fp = attr_type(Bool::variable(num_uvar2), fp); let num = num_num(attr_fp); let attr_num = attr_type(Bool::variable(num_uvar3), num); @@ -478,7 +476,7 @@ pub fn constrain_expr( ]), ) } - Int(var, _) => { + Int(var, _, _) => { let (a, b, c, num_type) = unique_int(var_store); exists( @@ -494,7 +492,7 @@ pub fn constrain_expr( ]), ) } - Float(var, _) => { + Float(var, _, _) => { let (a, b, c, num_type) = unique_float(var_store); exists( diff --git a/compiler/gen/tests/gen_num.rs b/compiler/gen/tests/gen_num.rs index 1b7be86555..5400502dcd 100644 --- a/compiler/gen/tests/gen_num.rs +++ b/compiler/gen/tests/gen_num.rs @@ -15,6 +15,22 @@ mod helpers; mod gen_num { use roc_std::RocOrder; + #[test] + fn i32_to_hex() { + assert_evals_to!( + indoc!( + r#" + f : I32 + f = 0x123 + + f + "# + ), + 0x123, + i32 + ); + } + #[test] fn i128_signed_int_alias() { assert_evals_to!("15 : I128", 15, i128); diff --git a/compiler/load/src/file.rs b/compiler/load/src/file.rs index 9a76a70eda..b181313d2c 100644 --- a/compiler/load/src/file.rs +++ b/compiler/load/src/file.rs @@ -3552,6 +3552,7 @@ fn add_def_to_module<'a>( // never gets called by Roc code, it will never // get specialized! if is_exposed { + dbg!("A"); let annotation = def.expr_var; let layout = match layout_cache.from_var( diff --git a/compiler/mono/src/decision_tree.rs b/compiler/mono/src/decision_tree.rs index ec9fff2c5f..2e3701faa2 100644 --- a/compiler/mono/src/decision_tree.rs +++ b/compiler/mono/src/decision_tree.rs @@ -451,7 +451,7 @@ fn test_at_path<'a>(selected_path: &Path, branch: &Branch<'a>, all_tests: &mut V IntLiteral(v) => { all_tests.push(guarded(IsInt(*v))); } - FloatLiteral(v) => { + FloatLiteral(_, v) => { all_tests.push(IsFloat(*v)); } StrLiteral(v) => { @@ -655,7 +655,7 @@ fn to_relevant_branch_help<'a>( _ => None, }, - FloatLiteral(float) => match test { + FloatLiteral(_, float) => match test { IsFloat(test_float) if float == *test_float => { start.extend(end); Some(Branch { @@ -749,7 +749,7 @@ fn needs_tests<'a>(pattern: &Pattern<'a>) -> bool { | BitLiteral { .. } | EnumLiteral { .. } | IntLiteral(_) - | FloatLiteral(_) + | FloatLiteral(_, _) | StrLiteral(_) => true, } } diff --git a/compiler/mono/src/exhaustive.rs b/compiler/mono/src/exhaustive.rs index 70077c2199..64847454d2 100644 --- a/compiler/mono/src/exhaustive.rs +++ b/compiler/mono/src/exhaustive.rs @@ -49,7 +49,7 @@ fn simplify<'a>(pattern: &crate::ir::Pattern<'a>) -> Pattern { match pattern { IntLiteral(v) => Literal(Literal::Int(*v)), - FloatLiteral(v) => Literal(Literal::Float(*v)), + FloatLiteral(_, v) => Literal(Literal::Float(*v)), StrLiteral(v) => Literal(Literal::Str(v.clone())), // To make sure these are exhaustive, we have to "fake" a union here diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index f8138d74d5..067ebaeceb 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -1380,7 +1380,7 @@ fn pattern_to_when<'a>( (symbol, Located::at_zero(wrapped_body)) } - IntLiteral(_) | NumLiteral(_, _) | FloatLiteral(_) | StrLiteral(_) => { + IntLiteral(_) | NumLiteral(_, _) | FloatLiteral(_, _) | StrLiteral(_) => { // These patters are refutable, and thus should never occur outside a `when` expression // They should have been replaced with `UnsupportedPattern` during canonicalization unreachable!("refutable pattern {:?} where irrefutable pattern is expected. This should never happen!", pattern.value) @@ -2245,14 +2245,14 @@ pub fn with_hole<'a>( let arena = env.arena; match can_expr { - Int(_, num) => Stmt::Let( + Int(_, _, num) => Stmt::Let( assigned, Expr::Literal(Literal::Int(num)), Layout::Builtin(Builtin::Int64), hole, ), - Float(_, num) => Stmt::Let( + Float(_, _, num) => Stmt::Let( assigned, Expr::Literal(Literal::Float(num)), Layout::Builtin(Builtin::Float64), @@ -4583,7 +4583,7 @@ fn store_pattern<'a>( // do nothing } IntLiteral(_) - | FloatLiteral(_) + | FloatLiteral(_, _) | EnumLiteral { .. } | BitLiteral { .. } | StrLiteral(_) => {} @@ -4623,7 +4623,7 @@ fn store_pattern<'a>( // ignore } IntLiteral(_) - | FloatLiteral(_) + | FloatLiteral(_, _) | EnumLiteral { .. } | BitLiteral { .. } | StrLiteral(_) => {} @@ -4737,7 +4737,7 @@ fn store_record_destruct<'a>( // internally. But `y` is never used, so we must make sure it't not stored/loaded. } IntLiteral(_) - | FloatLiteral(_) + | FloatLiteral(_, _) | EnumLiteral { .. } | BitLiteral { .. } | StrLiteral(_) => {} @@ -5408,7 +5408,7 @@ pub enum Pattern<'a> { Underscore, IntLiteral(i64), - FloatLiteral(u64), + FloatLiteral(Variable, u64), BitLiteral { value: bool, tag_name: TagName, @@ -5469,7 +5469,7 @@ pub fn from_can_pattern<'a>( Underscore => Pattern::Underscore, Identifier(symbol) => Pattern::Identifier(*symbol), IntLiteral(v) => Pattern::IntLiteral(*v), - FloatLiteral(v) => Pattern::FloatLiteral(f64::to_bits(*v)), + FloatLiteral(var, float) => Pattern::FloatLiteral(*var, f64::to_bits(*float)), StrLiteral(v) => Pattern::StrLiteral(v.clone()), Shadowed(region, ident) => Pattern::Shadowed(*region, ident.clone()), UnsupportedPattern(region) => Pattern::UnsupportedPattern(*region), @@ -5479,7 +5479,7 @@ pub fn from_can_pattern<'a>( } NumLiteral(var, num) => match num_argument_to_int_or_float(env.subs, *var) { IntOrFloat::IntType => Pattern::IntLiteral(*num), - IntOrFloat::FloatType => Pattern::FloatLiteral(*num as u64), + IntOrFloat::FloatType => Pattern::FloatLiteral(*var, *num as u64), }, AppliedTag { diff --git a/compiler/mono/src/layout.rs b/compiler/mono/src/layout.rs index 3cfd1c9c29..1d7dba7d23 100644 --- a/compiler/mono/src/layout.rs +++ b/compiler/mono/src/layout.rs @@ -652,7 +652,9 @@ impl<'a> LayoutCache<'a> { seen: MutSet::default(), }; + dbg!(&var); let result = Layout::from_var(&mut env, var); + dbg!(&result); // Don't actually cache. The layout cache is very hard to get right in the presence // of specialization, it's turned of for now so an invalid cache is never the cause diff --git a/compiler/uniq/src/sharing.rs b/compiler/uniq/src/sharing.rs index 736e45e6d2..b6761594ec 100644 --- a/compiler/uniq/src/sharing.rs +++ b/compiler/uniq/src/sharing.rs @@ -754,7 +754,7 @@ fn annotate_usage_pattern(pattern: &Pattern, usage: &mut VarUsage) { Identifier(_) | IntLiteral(_) | NumLiteral(_, _) - | FloatLiteral(_) + | FloatLiteral(_, _) | StrLiteral(_) | Underscore | Shadowed(_, _) @@ -785,8 +785,8 @@ pub fn annotate_usage(expr: &Expr, usage: &mut VarUsage) { match expr { RuntimeError(_) | Num(_, _) - | Int(_, _) - | Float(_, _) + | Int(_, _, _) + | Float(_, _, _) | Str { .. } | EmptyRecord | Accessor { .. } From 791a0e94047df573f2e757181f7715364cfaaa1a Mon Sep 17 00:00:00 2001 From: Jared Ramirez Date: Tue, 29 Dec 2020 09:33:55 -0600 Subject: [PATCH 4/4] Use precision in mono/ir to determine which number to generate --- compiler/constrain/src/builtins.rs | 4 +- compiler/constrain/src/uniq.rs | 2 +- compiler/gen/src/llvm/build.rs | 11 +- compiler/gen/tests/gen_num.rs | 14 +- compiler/gen/tests/helpers/eval.rs | 7 - compiler/load/src/file.rs | 1 - compiler/mono/src/ir.rs | 203 +++++++++++++++++++++++------ compiler/mono/src/layout.rs | 2 - 8 files changed, 183 insertions(+), 61 deletions(-) diff --git a/compiler/constrain/src/builtins.rs b/compiler/constrain/src/builtins.rs index ef8a497184..4457a1c80e 100644 --- a/compiler/constrain/src/builtins.rs +++ b/compiler/constrain/src/builtins.rs @@ -27,7 +27,6 @@ pub fn int_literal( num_type.clone(), ForReason( reason, - // TODO: Put into seperate function? num_num(num_integer(Type::Variable(percision_var))), region, ), @@ -49,6 +48,8 @@ pub fn float_literal( let num_type = Variable(num_var); let reason = Reason::FloatLiteral; + dbg!(&expected); + exists( vec![num_var], And(vec![ @@ -56,7 +57,6 @@ pub fn float_literal( num_type.clone(), ForReason( reason, - // TODO: Put into seperate function? num_num(num_floatingpoint(Type::Variable(percision_var))), region, ), diff --git a/compiler/constrain/src/uniq.rs b/compiler/constrain/src/uniq.rs index a63d49ad3a..f42cf95a88 100644 --- a/compiler/constrain/src/uniq.rs +++ b/compiler/constrain/src/uniq.rs @@ -1,4 +1,4 @@ -use crate::builtins::{num_binary64, num_floatingpoint, num_integer, num_num, num_signed64}; +use crate::builtins::{num_floatingpoint, num_integer, num_num}; use crate::expr::{exists, Info}; use roc_can::annotation::IntroducedVariables; use roc_can::constraint::Constraint::{self, *}; diff --git a/compiler/gen/src/llvm/build.rs b/compiler/gen/src/llvm/build.rs index 3fbba6c7de..4888657b40 100644 --- a/compiler/gen/src/llvm/build.rs +++ b/compiler/gen/src/llvm/build.rs @@ -495,7 +495,7 @@ pub fn build_exp_literal<'a, 'ctx, 'env>( Float(num) => (match layout { Layout::Builtin(Builtin::Float64) => env.context.f64_type(), - // Layout::Builtin(Builtin::Float32) => env.context.f32_type(), + Layout::Builtin(Builtin::Float32) => env.context.f32_type(), _ => panic!("Invalid layout for float literal = {:?}", layout), }).const_float(*num).into(), Bool(b) => env.context.bool_type().const_int(*b as u64, false).into(), @@ -1312,9 +1312,6 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>( Let(first_symbol, first_expr, first_layout, mut cont) => { let mut queue = Vec::new_in(env.arena); - dbg!(first_expr); - dbg!(first_layout); - queue.push((first_symbol, first_expr, first_layout)); @@ -2207,9 +2204,6 @@ pub fn build_proc_header<'a, 'ctx, 'env>( .get(symbol, layout) .to_symbol_string(symbol, &env.interns); - dbg!("build_proc_header"); - dbg!(&fn_name); - use roc_mono::ir::HostExposedLayouts; match &proc.host_exposed_layouts { HostExposedLayouts::NotHostExposed => {} @@ -2609,9 +2603,6 @@ pub fn build_proc<'a, 'ctx, 'env>( scope.insert(*arg_symbol, (layout.clone(), alloca)); } - dbg!("build_proc"); - dbg!(&proc.body); - let body = build_exp_stmt(env, layout_ids, &mut scope, fn_val, &proc.body); // only add a return if codegen did not already add one diff --git a/compiler/gen/tests/gen_num.rs b/compiler/gen/tests/gen_num.rs index 5400502dcd..b713072af5 100644 --- a/compiler/gen/tests/gen_num.rs +++ b/compiler/gen/tests/gen_num.rs @@ -33,8 +33,20 @@ mod gen_num { #[test] fn i128_signed_int_alias() { - assert_evals_to!("15 : I128", 15, i128); + assert_evals_to!( + indoc!( + r#" + i : I128 + i = 15 + + i + "# + ), + 15, + i128 + ); } + // TODO: Use indoc #[test] fn i64_signed_int_alias() { assert_evals_to!("15 : I64", 15, i64); diff --git a/compiler/gen/tests/helpers/eval.rs b/compiler/gen/tests/helpers/eval.rs index 63d3cd2ecc..fe22eebc85 100644 --- a/compiler/gen/tests/helpers/eval.rs +++ b/compiler/gen/tests/helpers/eval.rs @@ -201,10 +201,6 @@ pub fn helper<'a>( // because their bodies may reference each other. let mut scope = Scope::default(); for ((symbol, layout), proc) in procedures.drain() { - dbg!("helper: build_proc_header"); - dbg!(&proc); - dbg!(&layout); - let fn_val = build_proc_header(&env, &mut layout_ids, symbol, &layout, &proc); if proc.args.is_empty() { @@ -225,9 +221,6 @@ pub fn helper<'a>( let home = proc.name.module_id(); current_scope.retain_top_level_thunks_for_module(home); - dbg!("helper: build_proc"); - dbg!(&proc); - build_proc(&env, &mut layout_ids, scope.clone(), proc, fn_val); // call finalize() before any code generation/verification diff --git a/compiler/load/src/file.rs b/compiler/load/src/file.rs index b181313d2c..9a76a70eda 100644 --- a/compiler/load/src/file.rs +++ b/compiler/load/src/file.rs @@ -3552,7 +3552,6 @@ fn add_def_to_module<'a>( // never gets called by Roc code, it will never // get specialized! if is_exposed { - dbg!("A"); let annotation = def.expr_var; let layout = match layout_cache.from_var( diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index 067ebaeceb..338bbbc534 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -14,6 +14,26 @@ use roc_types::subs::{Content, FlatType, Subs, Variable}; use std::collections::HashMap; use ven_pretty::{BoxAllocator, DocAllocator, DocBuilder}; +// Function return type does not match operand type of return inst! +// ret i64 %f1, !dbg !521 +// i32define private fastcc i32 @"#UserApp_main_1"() !dbg !517 { +// entry: +// %f = alloca i64 +// store i64 291, i64* %f, !dbg !521 +// %f1 = load i64, i64* %f, !dbg !521 +// ret i64 %f1, !dbg !521 +// } + +// Function return type does not match operand type of return inst! +// ret i32 %f1, !dbg !521 +// i64define private fastcc i64 @"#UserApp_main_1"() !dbg !517 { +// entry: +// %f = alloca i32 +// store i32 291, i32* %f, !dbg !521 +// %f1 = load i32, i32* %f, !dbg !521 +// ret i32 %f1, !dbg !521 +// } + pub const PRETTY_PRINT_IR_SYMBOLS: bool = false; #[derive(Clone, Debug, PartialEq)] @@ -2245,19 +2265,37 @@ pub fn with_hole<'a>( let arena = env.arena; match can_expr { - Int(_, _, num) => Stmt::Let( - assigned, - Expr::Literal(Literal::Int(num)), - Layout::Builtin(Builtin::Int64), - hole, - ), + Int(_, precision, num) => match num_argument_to_int_or_float(env.subs, precision) { + IntOrFloat::SignedIntType(precision) => Stmt::Let( + assigned, + Expr::Literal(Literal::Int(num)), + Layout::Builtin(int_precision_to_builtin(precision)), + hole, + ), + IntOrFloat::UnsignedIntType(precision) => Stmt::Let( + assigned, + Expr::Literal(Literal::Int(num)), + Layout::Builtin(int_precision_to_builtin(precision)), + hole, + ), + _ => unreachable!("unexpected float precision for integer"), + }, - Float(_, _, num) => Stmt::Let( - assigned, - Expr::Literal(Literal::Float(num)), - Layout::Builtin(Builtin::Float64), - hole, - ), + Float(_, precision, num) => match num_argument_to_int_or_float(env.subs, precision) { + IntOrFloat::BinaryFloatType(precision) => Stmt::Let( + assigned, + Expr::Literal(Literal::Float(num as f64)), + Layout::Builtin(float_precision_to_builtin(precision)), + hole, + ), + IntOrFloat::DecimalFloatType(precision) => Stmt::Let( + assigned, + Expr::Literal(Literal::Float(num as f64)), + Layout::Builtin(float_precision_to_builtin(precision)), + hole, + ), + _ => unreachable!("unexpected float precision for integer"), + }, Str(string) => Stmt::Let( assigned, @@ -2267,16 +2305,28 @@ pub fn with_hole<'a>( ), Num(var, num) => match num_argument_to_int_or_float(env.subs, var) { - IntOrFloat::IntType => Stmt::Let( + IntOrFloat::SignedIntType(precision) => Stmt::Let( assigned, Expr::Literal(Literal::Int(num)), - Layout::Builtin(Builtin::Int64), + Layout::Builtin(int_precision_to_builtin(precision)), hole, ), - IntOrFloat::FloatType => Stmt::Let( + IntOrFloat::UnsignedIntType(precision) => Stmt::Let( + assigned, + Expr::Literal(Literal::Int(num)), + Layout::Builtin(int_precision_to_builtin(precision)), + hole, + ), + IntOrFloat::BinaryFloatType(precision) => Stmt::Let( assigned, Expr::Literal(Literal::Float(num as f64)), - Layout::Builtin(Builtin::Float64), + Layout::Builtin(float_precision_to_builtin(precision)), + hole, + ), + IntOrFloat::DecimalFloatType(precision) => Stmt::Let( + assigned, + Expr::Literal(Literal::Float(num as f64)), + Layout::Builtin(float_precision_to_builtin(precision)), hole, ), }, @@ -5478,8 +5528,10 @@ pub fn from_can_pattern<'a>( Pattern::UnsupportedPattern(*region) } NumLiteral(var, num) => match num_argument_to_int_or_float(env.subs, *var) { - IntOrFloat::IntType => Pattern::IntLiteral(*num), - IntOrFloat::FloatType => Pattern::FloatLiteral(*var, *num as u64), + IntOrFloat::SignedIntType(_) => Pattern::IntLiteral(*num), + IntOrFloat::UnsignedIntType(_) => Pattern::IntLiteral(*num), + IntOrFloat::BinaryFloatType(_) => Pattern::FloatLiteral(*var, *num as u64), + IntOrFloat::DecimalFloatType(_) => Pattern::FloatLiteral(*var, *num as u64), }, AppliedTag { @@ -5854,29 +5906,100 @@ fn optimize_low_level( } } +pub enum IntPrecision { + I128, + I64, + I32, + I16, + I8, +} + +pub enum FloatPrecision { + F64, + F32, +} + pub enum IntOrFloat { - IntType, - FloatType, + SignedIntType(IntPrecision), + UnsignedIntType(IntPrecision), + BinaryFloatType(FloatPrecision), + DecimalFloatType(FloatPrecision), +} + +fn float_precision_to_builtin(precision: FloatPrecision) -> Builtin<'static> { + use FloatPrecision::*; + match precision { + F64 => Builtin::Float64, + F32 => Builtin::Float32, + } +} + +fn int_precision_to_builtin(precision: IntPrecision) -> Builtin<'static> { + use IntPrecision::*; + match precision { + I128 => Builtin::Int128, + I64 => Builtin::Int64, + I32 => Builtin::Int32, + I16 => Builtin::Int16, + I8 => Builtin::Int8, + } } /// Given the `a` in `Num a`, determines whether it's an int or a float pub fn num_argument_to_int_or_float(subs: &Subs, var: Variable) -> IntOrFloat { match subs.get_without_compacting(var).content { - Content::Alias(Symbol::NUM_INTEGER, args, _) => { - debug_assert!(args.len() == 1); - - // TODO: we probably need to match on the type of the arg - IntOrFloat::IntType + Content::FlexVar(_) => IntOrFloat::SignedIntType(IntPrecision::I64), // We default (Num *) to I64 + Content::Alias(Symbol::NUM_I128, _, _) + | Content::Alias(Symbol::NUM_SIGNED128, _, _) + | Content::Alias(Symbol::NUM_AT_SIGNED128, _, _) => { + IntOrFloat::SignedIntType(IntPrecision::I128) } - Content::FlexVar(_) => { - // If this was still a (Num *), assume compiling it to an Int - IntOrFloat::IntType + Content::Alias(Symbol::NUM_INTEGER, _, _) // 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_FLOATINGPOINT, args, _) => { - debug_assert!(args.len() == 1); - - // TODO: we probably need to match on the type of the arg - IntOrFloat::FloatType + // TODO: Add ors for aall NUM_SIGNED, NUM_BINARY (maybe NUM_AT_*) + 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::Structure(FlatType::Apply(Symbol::ATTR_ATTR, attr_args)) => { debug_assert!(attr_args.len() == 2); @@ -5884,10 +6007,16 @@ pub fn num_argument_to_int_or_float(subs: &Subs, var: Variable) -> IntOrFloat { // Recurse on the second argument num_argument_to_int_or_float(subs, attr_args[1]) } - Content::Alias(Symbol::NUM_F64, args, _) | Content::Alias(Symbol::NUM_F32, args, _) => { - debug_assert!(args.is_empty()); - - IntOrFloat::FloatType + Content::Alias(Symbol::NUM_FLOATINGPOINT, _, _) // 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_F32, _, _) + | Content::Alias(Symbol::NUM_BINARY32, _, _) + | Content::Alias(Symbol::NUM_AT_BINARY32, _, _) => { + IntOrFloat::BinaryFloatType(FloatPrecision::F32) } other => { panic!( diff --git a/compiler/mono/src/layout.rs b/compiler/mono/src/layout.rs index 1d7dba7d23..3cfd1c9c29 100644 --- a/compiler/mono/src/layout.rs +++ b/compiler/mono/src/layout.rs @@ -652,9 +652,7 @@ impl<'a> LayoutCache<'a> { seen: MutSet::default(), }; - dbg!(&var); let result = Layout::from_var(&mut env, var); - dbg!(&result); // Don't actually cache. The layout cache is very hard to get right in the presence // of specialization, it's turned of for now so an invalid cache is never the cause