Merge pull request #1121 from rtfeldman/add-num-log

Add Num.log
This commit is contained in:
Richard Feldman 2021-03-28 21:44:07 -04:00 committed by GitHub
commit 4ce520fed6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 189 additions and 60 deletions

View File

@ -430,6 +430,20 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
),
);
// log : Float a -> Float a
let log_needs_positive = SolvedType::TagUnion(
vec![(TagName::Global("LogNeedsPositive".into()), vec![])],
Box::new(SolvedType::Wildcard),
);
add_type(
Symbol::NUM_LOG,
top_level_function(
vec![float_type(flex(TVAR1))],
Box::new(result_type(float_type(flex(TVAR1)), log_needs_positive)),
),
);
// round : Float a -> Int b
add_type(
Symbol::NUM_ROUND,

View File

@ -139,6 +139,7 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option<Def>
NUM_REM => num_rem,
NUM_IS_MULTIPLE_OF => num_is_multiple_of,
NUM_SQRT => num_sqrt,
NUM_LOG => num_log,
NUM_ROUND => num_round,
NUM_IS_ODD => num_is_odd,
NUM_IS_EVEN => num_is_even,
@ -276,6 +277,7 @@ pub fn builtin_defs(var_store: &mut VarStore) -> MutMap<Symbol, Def> {
Symbol::NUM_REM => num_rem,
Symbol::NUM_IS_MULTIPLE_OF => num_is_multiple_of,
Symbol::NUM_SQRT => num_sqrt,
Symbol::NUM_LOG => num_log,
Symbol::NUM_ROUND => num_round,
Symbol::NUM_IS_ODD => num_is_odd,
Symbol::NUM_IS_EVEN => num_is_even,
@ -1174,6 +1176,52 @@ fn num_sqrt(symbol: Symbol, var_store: &mut VarStore) -> Def {
)
}
/// Num.log : Float -> Result Float [ LogNeedsPositive ]*
fn num_log(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 precision_var = var_store.fresh();
let ret_var = var_store.fresh();
let body = If {
branch_var: ret_var,
cond_var: bool_var,
branches: vec![(
no_region(RunLowLevel {
op: LowLevel::NumGt,
args: vec![
(float_var, Var(Symbol::ARG_1)),
(float_var, Float(unbound_zero_var, precision_var, 0.0)),
],
ret_var: bool_var,
}),
no_region(tag(
"Ok",
vec![RunLowLevel {
op: LowLevel::NumLogUnchecked,
args: vec![(float_var, Var(Symbol::ARG_1))],
ret_var: float_var,
}],
var_store,
)),
)],
final_else: Box::new(no_region(tag(
"Err",
vec![tag("LogNeedsPositive", Vec::new(), var_store)],
var_store,
))),
};
defn(
symbol,
vec![(float_var, Symbol::ARG_1)],
var_store,
body,
ret_var,
)
}
/// Num.round : Float -> Int
fn num_round(symbol: Symbol, var_store: &mut VarStore) -> Def {
let float_var = var_store.fresh();

View File

@ -337,6 +337,12 @@ fn add_intrinsics<'ctx>(ctx: &'ctx Context, module: &Module<'ctx>) {
f64_type.fn_type(&[f64_type.into()], false),
);
add_intrinsic(
module,
LLVM_LOG_F64,
f64_type.fn_type(&[f64_type.into()], false),
);
add_intrinsic(
module,
LLVM_LROUND_I64_F64,
@ -455,6 +461,7 @@ fn add_intrinsics<'ctx>(ctx: &'ctx Context, module: &Module<'ctx>) {
static LLVM_MEMSET_I64: &str = "llvm.memset.p0i8.i64";
static LLVM_MEMSET_I32: &str = "llvm.memset.p0i8.i32";
static LLVM_SQRT_F64: &str = "llvm.sqrt.f64";
static LLVM_LOG_F64: &str = "llvm.log.f64";
static LLVM_LROUND_I64_F64: &str = "llvm.lround.i64.f64";
static LLVM_FABS_F64: &str = "llvm.fabs.f64";
static LLVM_SIN_F64: &str = "llvm.sin.f64";
@ -3969,8 +3976,8 @@ fn run_low_level<'a, 'ctx, 'env>(
list_join(env, inplace, parent, list, outer_list_layout)
}
NumAbs | NumNeg | NumRound | NumSqrtUnchecked | NumSin | NumCos | NumCeiling | NumFloor
| NumToFloat | NumIsFinite | NumAtan | NumAcos | NumAsin => {
NumAbs | NumNeg | NumRound | NumSqrtUnchecked | NumLogUnchecked | NumSin | NumCos
| NumCeiling | NumFloor | NumToFloat | NumIsFinite | NumAtan | NumAcos | NumAsin => {
debug_assert_eq!(args.len(), 1);
let (arg, arg_layout) = load_symbol_and_layout(scope, &args[0]);
@ -5279,6 +5286,7 @@ fn build_float_unary_op<'a, 'ctx, 'env>(
NumNeg => bd.build_float_neg(arg, "negate_float").into(),
NumAbs => env.call_intrinsic(LLVM_FABS_F64, &[arg.into()]),
NumSqrtUnchecked => env.call_intrinsic(LLVM_SQRT_F64, &[arg.into()]),
NumLogUnchecked => env.call_intrinsic(LLVM_LOG_F64, &[arg.into()]),
NumRound => env.call_intrinsic(LLVM_LROUND_I64_F64, &[arg.into()]),
NumSin => env.call_intrinsic(LLVM_SIN_F64, &[arg.into()]),
NumCos => env.call_intrinsic(LLVM_COS_F64, &[arg.into()]),

View File

@ -72,6 +72,7 @@ pub enum LowLevel {
NumSin,
NumCos,
NumSqrtUnchecked,
NumLogUnchecked,
NumRound,
NumToFloat,
NumPow,

View File

@ -804,59 +804,60 @@ define_builtins! {
43 NUM_MOD_INT: "modInt"
44 NUM_MOD_FLOAT: "modFloat"
45 NUM_SQRT: "sqrt"
46 NUM_ROUND: "round"
47 NUM_COMPARE: "compare"
48 NUM_POW: "pow"
49 NUM_CEILING: "ceiling"
50 NUM_POW_INT: "powInt"
51 NUM_FLOOR: "floor"
52 NUM_ADD_WRAP: "addWrap"
53 NUM_ADD_CHECKED: "addChecked"
54 NUM_ATAN: "atan"
55 NUM_ACOS: "acos"
56 NUM_ASIN: "asin"
57 NUM_AT_SIGNED128: "@Signed128"
58 NUM_SIGNED128: "Signed128" imported
59 NUM_AT_SIGNED64: "@Signed64"
60 NUM_SIGNED64: "Signed64" imported
61 NUM_AT_SIGNED32: "@Signed32"
62 NUM_SIGNED32: "Signed32" imported
63 NUM_AT_SIGNED16: "@Signed16"
64 NUM_SIGNED16: "Signed16" imported
65 NUM_AT_SIGNED8: "@Signed8"
66 NUM_SIGNED8: "Signed8" imported
67 NUM_AT_UNSIGNED128: "@Unsigned128"
68 NUM_UNSIGNED128: "Unsigned128" imported
69 NUM_AT_UNSIGNED64: "@Unsigned64"
70 NUM_UNSIGNED64: "Unsigned64" imported
71 NUM_AT_UNSIGNED32: "@Unsigned32"
72 NUM_UNSIGNED32: "Unsigned32" imported
73 NUM_AT_UNSIGNED16: "@Unsigned16"
74 NUM_UNSIGNED16: "Unsigned16" imported
75 NUM_AT_UNSIGNED8: "@Unsigned8"
76 NUM_UNSIGNED8: "Unsigned8" imported
77 NUM_AT_BINARY64: "@Binary64"
78 NUM_BINARY64: "Binary64" imported
79 NUM_AT_BINARY32: "@Binary32"
80 NUM_BINARY32: "Binary32" imported
81 NUM_BITWISE_AND: "bitwiseAnd"
82 NUM_BITWISE_XOR: "bitwiseXor"
83 NUM_BITWISE_OR: "bitwiseOr"
84 NUM_SHIFT_LEFT: "shiftLeftBy"
85 NUM_SHIFT_RIGHT: "shiftRightBy"
86 NUM_SHIFT_RIGHT_ZERO_FILL: "shiftRightZfBy"
87 NUM_SUB_WRAP: "subWrap"
88 NUM_SUB_CHECKED: "subChecked"
89 NUM_MUL_WRAP: "mulWrap"
90 NUM_MUL_CHECKED: "mulChecked"
91 NUM_INT: "Int" imported
92 NUM_FLOAT: "Float" imported
93 NUM_AT_NATURAL: "@Natural"
94 NUM_NATURAL: "Natural" imported
95 NUM_NAT: "Nat" imported
96 NUM_INT_CAST: "intCast"
97 NUM_MAX_I128: "maxI128"
98 NUM_IS_MULTIPLE_OF: "isMultipleOf"
46 NUM_LOG: "log"
47 NUM_ROUND: "round"
48 NUM_COMPARE: "compare"
49 NUM_POW: "pow"
50 NUM_CEILING: "ceiling"
51 NUM_POW_INT: "powInt"
52 NUM_FLOOR: "floor"
53 NUM_ADD_WRAP: "addWrap"
54 NUM_ADD_CHECKED: "addChecked"
55 NUM_ATAN: "atan"
56 NUM_ACOS: "acos"
57 NUM_ASIN: "asin"
58 NUM_AT_SIGNED128: "@Signed128"
59 NUM_SIGNED128: "Signed128" imported
60 NUM_AT_SIGNED64: "@Signed64"
61 NUM_SIGNED64: "Signed64" imported
62 NUM_AT_SIGNED32: "@Signed32"
63 NUM_SIGNED32: "Signed32" imported
64 NUM_AT_SIGNED16: "@Signed16"
65 NUM_SIGNED16: "Signed16" imported
66 NUM_AT_SIGNED8: "@Signed8"
67 NUM_SIGNED8: "Signed8" imported
68 NUM_AT_UNSIGNED128: "@Unsigned128"
69 NUM_UNSIGNED128: "Unsigned128" imported
70 NUM_AT_UNSIGNED64: "@Unsigned64"
71 NUM_UNSIGNED64: "Unsigned64" imported
72 NUM_AT_UNSIGNED32: "@Unsigned32"
73 NUM_UNSIGNED32: "Unsigned32" imported
74 NUM_AT_UNSIGNED16: "@Unsigned16"
75 NUM_UNSIGNED16: "Unsigned16" imported
76 NUM_AT_UNSIGNED8: "@Unsigned8"
77 NUM_UNSIGNED8: "Unsigned8" imported
78 NUM_AT_BINARY64: "@Binary64"
79 NUM_BINARY64: "Binary64" imported
80 NUM_AT_BINARY32: "@Binary32"
81 NUM_BINARY32: "Binary32" imported
82 NUM_BITWISE_AND: "bitwiseAnd"
83 NUM_BITWISE_XOR: "bitwiseXor"
84 NUM_BITWISE_OR: "bitwiseOr"
85 NUM_SHIFT_LEFT: "shiftLeftBy"
86 NUM_SHIFT_RIGHT: "shiftRightBy"
87 NUM_SHIFT_RIGHT_ZERO_FILL: "shiftRightZfBy"
88 NUM_SUB_WRAP: "subWrap"
89 NUM_SUB_CHECKED: "subChecked"
90 NUM_MUL_WRAP: "mulWrap"
91 NUM_MUL_CHECKED: "mulChecked"
92 NUM_INT: "Int" imported
93 NUM_FLOAT: "Float" imported
94 NUM_AT_NATURAL: "@Natural"
95 NUM_NATURAL: "Natural" imported
96 NUM_NAT: "Nat" imported
97 NUM_INT_CAST: "intCast"
98 NUM_MAX_I128: "maxI128"
99 NUM_IS_MULTIPLE_OF: "isMultipleOf"
}
2 BOOL: "Bool" => {

View File

@ -671,10 +671,9 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[bool] {
| NumBitwiseAnd | NumBitwiseXor | NumBitwiseOr | NumShiftLeftBy | NumShiftRightBy
| NumShiftRightZfBy => arena.alloc_slice_copy(&[irrelevant, irrelevant]),
NumAbs | NumNeg | NumSin | NumCos | NumSqrtUnchecked | NumRound | NumCeiling | NumFloor
| NumToFloat | Not | NumIsFinite | NumAtan | NumAcos | NumAsin | NumIntCast => {
arena.alloc_slice_copy(&[irrelevant])
}
NumAbs | NumNeg | NumSin | NumCos | NumSqrtUnchecked | NumLogUnchecked | NumRound
| NumCeiling | NumFloor | NumToFloat | Not | NumIsFinite | NumAtan | NumAcos | NumAsin
| NumIntCast => arena.alloc_slice_copy(&[irrelevant]),
StrStartsWith | StrEndsWith => arena.alloc_slice_copy(&[owned, borrowed]),
StrFromUtf8 => arena.alloc_slice_copy(&[owned]),
StrToBytes => arena.alloc_slice_copy(&[owned]),

View File

@ -361,7 +361,6 @@ mod gen_num {
#[test]
fn f64_sqrt() {
// FIXME this works with normal types, but fails when checking uniqueness types
assert_evals_to!(
indoc!(
r#"
@ -376,6 +375,35 @@ mod gen_num {
}
#[test]
fn f64_log() {
assert_evals_to!(
indoc!(
r#"
when Num.log 7.38905609893 is
Ok val -> val
Err _ -> -1
"#
),
1.999999999999912,
f64
);
}
#[test]
fn f64_log_one() {
assert_evals_to!(
indoc!(
r#"
when Num.log 1 is
Ok val -> val
Err _ -> -1
"#
),
0.0,
f64
);
}
fn f64_sqrt_zero() {
assert_evals_to!(
indoc!(
@ -405,6 +433,36 @@ mod gen_num {
);
}
#[test]
fn f64_log_zero() {
assert_evals_to!(
indoc!(
r#"
when Num.log 0 is
Err _ -> 42
Ok val -> val
"#
),
42.0,
f64
);
}
#[test]
fn f64_log_negative() {
assert_evals_to!(
indoc!(
r#"
when Num.log -1 is
Err _ -> 42
Ok val -> val
"#
),
42.0,
f64
);
}
#[test]
fn f64_round_old() {
assert_evals_to!("Num.round 3.6", 4, i64);