From 30a95e90d1e93c58eb63dec7ed8e81628f3db7a0 Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Tue, 23 Jun 2020 19:27:03 -0400 Subject: [PATCH] Fix Num.toFloat --- compiler/can/src/builtins.rs | 28 +++++++++++++----- compiler/gen/src/llvm/build.rs | 47 +++++++++++++----------------- compiler/gen/tests/gen_builtins.rs | 20 +++++++------ compiler/module/src/low_level.rs | 1 + compiler/uniq/src/sharing.rs | 2 +- 5 files changed, 55 insertions(+), 43 deletions(-) diff --git a/compiler/can/src/builtins.rs b/compiler/can/src/builtins.rs index 1b3eb2d04b..a41454fc15 100644 --- a/compiler/can/src/builtins.rs +++ b/compiler/can/src/builtins.rs @@ -77,6 +77,7 @@ pub fn builtin_defs(var_store: &mut VarStore) -> MutMap { Symbol::NUM_IS_ZERO => num_is_zero, Symbol::NUM_IS_POSITIVE => num_is_positive, Symbol::NUM_IS_NEGATIVE => num_is_negative, + Symbol::NUM_TO_FLOAT => num_to_float, } } @@ -272,12 +273,12 @@ fn num_tan(symbol: Symbol, var_store: &mut VarStore) -> Def { /// Num.isZero : Float -> Bool fn num_is_zero(symbol: Symbol, var_store: &mut VarStore) -> Def { - let bool_var = var_store.fresh(); + let arg_var = var_store.fresh(); let body = RunLowLevel { op: LowLevel::Eq, args: vec![ - (bool_var, Var(Symbol::ARG_1)), - (bool_var, Num(var_store.fresh(), 0)), + (arg_var, Var(Symbol::ARG_1)), + (arg_var, Num(var_store.fresh(), 0)), ], ret_var: var_store.fresh(), }; @@ -287,11 +288,12 @@ fn num_is_zero(symbol: Symbol, var_store: &mut VarStore) -> Def { /// Num.isNegative : Float -> Bool fn num_is_negative(symbol: Symbol, var_store: &mut VarStore) -> Def { + let arg_var = var_store.fresh(); let body = RunLowLevel { op: LowLevel::NumGt, args: vec![ - (var_store.fresh(), Num(var_store.fresh(), 0)), - (var_store.fresh(), Var(Symbol::ARG_1)), + (arg_var, Num(var_store.fresh(), 0)), + (arg_var, Var(Symbol::ARG_1)), ], ret_var: var_store.fresh(), }; @@ -301,11 +303,12 @@ fn num_is_negative(symbol: Symbol, var_store: &mut VarStore) -> Def { /// Num.isPositive : Float -> Bool fn num_is_positive(symbol: Symbol, var_store: &mut VarStore) -> Def { + let arg_var = var_store.fresh(); let body = RunLowLevel { op: LowLevel::NumGt, args: vec![ - (var_store.fresh(), Var(Symbol::ARG_1)), - (var_store.fresh(), Num(var_store.fresh(), 0)), + (arg_var, Var(Symbol::ARG_1)), + (arg_var, Num(var_store.fresh(), 0)), ], ret_var: var_store.fresh(), }; @@ -364,6 +367,17 @@ fn num_is_even(symbol: Symbol, var_store: &mut VarStore) -> Def { defn(symbol, vec![Symbol::ARG_1], var_store, body) } +/// Num.toFloat : Num * -> Float +fn num_to_float(symbol: Symbol, var_store: &mut VarStore) -> Def { + let body = RunLowLevel { + op: LowLevel::NumToFloat, + args: vec![(var_store.fresh(), Var(Symbol::ARG_1))], + ret_var: var_store.fresh(), + }; + + defn(symbol, vec![Symbol::ARG_1], var_store, body) +} + /// Num.sqrt : Float -> Result Float [ SqrtOfNegative ]* fn num_sqrt(symbol: Symbol, var_store: &mut VarStore) -> Def { let body = RunLowLevel { diff --git a/compiler/gen/src/llvm/build.rs b/compiler/gen/src/llvm/build.rs index b7eef57baa..dfd6ae168c 100644 --- a/compiler/gen/src/llvm/build.rs +++ b/compiler/gen/src/llvm/build.rs @@ -1021,31 +1021,6 @@ fn call_with_args<'a, 'ctx, 'env>( args: &[(BasicValueEnum<'ctx>, &'a Layout<'a>)], ) -> BasicValueEnum<'ctx> { match symbol { - Symbol::NUM_TO_FLOAT => { - // TODO specialize this to be not just for i64! - let builtin_fn_name = "i64_to_f64_"; - - let fn_val = env - .module - .get_function(builtin_fn_name) - .unwrap_or_else(|| panic!("Unrecognized builtin function: {:?} - if you're working on the Roc compiler, do you need to rebuild the bitcode? See compiler/builtins/bitcode/README.md", builtin_fn_name)); - - let mut arg_vals: Vec = Vec::with_capacity_in(args.len(), env.arena); - - for (arg, _layout) in args.iter() { - arg_vals.push(*arg); - } - - let call = env - .builder - .build_call(fn_val, arg_vals.into_bump_slice(), "call_builtin"); - - call.set_call_convention(fn_val.get_call_conventions()); - - call.try_as_basic_value() - .left() - .unwrap_or_else(|| panic!("LLVM error: Invalid call for builtin {:?}", symbol)) - } Symbol::LIST_SINGLE => { // List.single : a -> List a debug_assert!(args.len() == 1); @@ -1399,7 +1374,7 @@ fn run_low_level<'a, 'ctx, 'env>( BasicValueEnum::IntValue(answer) } - NumAbs | NumNeg | NumRound | NumSqrt | NumSin | NumCos => { + NumAbs | NumNeg | NumRound | NumSqrt | NumSin | NumCos | NumToFloat => { debug_assert_eq!(args.len(), 1); let arg = build_expr(env, layout_ids, scope, parent, &args[0].0); @@ -1675,6 +1650,25 @@ fn build_int_unary_op<'a, 'ctx, 'env>( NumAbs => { todo!("build_int_unary_op for integer absolute value. (possibly bitwise AND with 0b0111_1111_...)"); } + NumToFloat => { + // TODO specialize this to be not just for i64! + let builtin_fn_name = "i64_to_f64_"; + + let fn_val = env + .module + .get_function(builtin_fn_name) + .unwrap_or_else(|| panic!("Unrecognized builtin function: {:?} - if you're working on the Roc compiler, do you need to rebuild the bitcode? See compiler/builtins/bitcode/README.md", builtin_fn_name)); + + let call = env + .builder + .build_call(fn_val, &[arg.into()], "call_builtin"); + + call.set_call_convention(fn_val.get_call_conventions()); + + call.try_as_basic_value() + .left() + .unwrap_or_else(|| panic!("LLVM error: Invalid call for low-level op {:?}", op)) + } _ => { unreachable!("Unrecognized int unary operation: {:?}", op); } @@ -1698,6 +1692,7 @@ fn build_float_unary_op<'a, 'ctx, 'env>( NumRound => call_intrinsic(LLVM_LROUND_I64_F64, env, &[(arg.into(), arg_layout)]), NumSin => call_intrinsic(LLVM_SIN_F64, env, &[(arg.into(), arg_layout)]), NumCos => call_intrinsic(LLVM_COS_F64, env, &[(arg.into(), arg_layout)]), + NumToFloat => arg.into(), /* Converting from Float to Float is a no-op */ _ => { unreachable!("Unrecognized int unary operation: {:?}", op); } diff --git a/compiler/gen/tests/gen_builtins.rs b/compiler/gen/tests/gen_builtins.rs index d81af9ab2d..0718d57298 100644 --- a/compiler/gen/tests/gen_builtins.rs +++ b/compiler/gen/tests/gen_builtins.rs @@ -682,15 +682,17 @@ mod gen_builtins { #[test] fn int_to_float() { - assert_evals_to!( - indoc!( - r#" - Num.toFloat 0x9 - "# - ), - 9.0, - f64 - ); + assert_evals_to!("Num.toFloat 0x9", 9.0, f64); + } + + #[test] + fn num_to_float() { + assert_evals_to!("Num.toFloat 9", 9.0, f64); + } + + #[test] + fn float_to_float() { + assert_evals_to!("Num.toFloat 0.5", 0.5, f64); } #[test] diff --git a/compiler/module/src/low_level.rs b/compiler/module/src/low_level.rs index 14b4678366..5750db3931 100644 --- a/compiler/module/src/low_level.rs +++ b/compiler/module/src/low_level.rs @@ -23,6 +23,7 @@ pub enum LowLevel { NumCos, NumSqrt, NumRound, + NumToFloat, Eq, NotEq, And, diff --git a/compiler/uniq/src/sharing.rs b/compiler/uniq/src/sharing.rs index e15427ccc2..5b6ae00da7 100644 --- a/compiler/uniq/src/sharing.rs +++ b/compiler/uniq/src/sharing.rs @@ -757,7 +757,7 @@ fn annotate_low_level_usage( NumAdd | NumSub | NumMul | NumGt | NumGte | NumLt | NumLte | NumAbs | NumNeg | NumDivUnchecked | NumRemUnchecked | NumSqrt | NumRound | NumSin | NumCos | Eq | NotEq - | And | Or | Not => { + | And | Or | Not | NumToFloat => { for (_, arg) in args { annotate_usage(&arg, usage); }