mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-29 14:54:47 +00:00
feat: adds Num.mulWrap and Num.mulChecked
This commit is contained in:
parent
d3d3497b46
commit
f3bd5368f0
7 changed files with 162 additions and 4 deletions
|
@ -130,6 +130,21 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
|
|||
),
|
||||
);
|
||||
|
||||
// mulWrap : Int, Int -> Int
|
||||
add_type(
|
||||
Symbol::NUM_MUL_WRAP,
|
||||
top_level_function(vec![int_type(), int_type()], Box::new(int_type())),
|
||||
);
|
||||
|
||||
// mulChecked : Num a, Num a -> Result (Num a) [ Overflow ]*
|
||||
add_type(
|
||||
Symbol::NUM_MUL_CHECKED,
|
||||
top_level_function(
|
||||
vec![num_type(flex(TVAR1)), num_type(flex(TVAR1))],
|
||||
Box::new(result_type(num_type(flex(TVAR1)), overflow())),
|
||||
),
|
||||
);
|
||||
|
||||
// abs : Num a -> Num a
|
||||
add_type(
|
||||
Symbol::NUM_ABS,
|
||||
|
|
|
@ -197,6 +197,21 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
|
|||
unique_function(vec![num_type(u, num), num_type(v, num)], num_type(w, num))
|
||||
});
|
||||
|
||||
// mulWrap : Int, Int -> Int
|
||||
add_type(Symbol::NUM_MUL_WRAP, {
|
||||
let_tvars! { u, v, w };
|
||||
unique_function(vec![int_type(u), int_type(v)], int_type(w))
|
||||
});
|
||||
|
||||
// mulChecked : Num a, Num a -> Result (Num a) [ Overflow ]*
|
||||
add_type(Symbol::NUM_MUL_CHECKED, {
|
||||
let_tvars! { u, v, w, num, result, star };
|
||||
unique_function(
|
||||
vec![num_type(u, num), num_type(v, num)],
|
||||
result_type(result, num_type(w, num), lift(star, overflow())),
|
||||
)
|
||||
});
|
||||
|
||||
// abs : Num a -> Num a
|
||||
add_type(Symbol::NUM_ABS, {
|
||||
let_tvars! { u, v, num };
|
||||
|
|
|
@ -85,6 +85,8 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option<Def>
|
|||
NUM_SUB_WRAP => num_sub_wrap,
|
||||
NUM_SUB_CHECKED => num_sub_checked,
|
||||
NUM_MUL => num_mul,
|
||||
NUM_MUL_WRAP => num_mul_wrap,
|
||||
NUM_MUL_CHECKED => num_mul_checked,
|
||||
NUM_GT => num_gt,
|
||||
NUM_GTE => num_gte,
|
||||
NUM_LT => num_lt,
|
||||
|
@ -573,6 +575,100 @@ fn num_mul(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
|||
num_binop(symbol, var_store, LowLevel::NumMul)
|
||||
}
|
||||
|
||||
/// Num.mulWrap : Int, Int -> Int
|
||||
fn num_mul_wrap(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||
num_binop(symbol, var_store, LowLevel::NumMulWrap)
|
||||
}
|
||||
|
||||
/// Num.mulChecked : Num a, Num a -> Result (Num a) [ Overflow ]*
|
||||
fn num_mul_checked(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||
let bool_var = var_store.fresh();
|
||||
let num_var_1 = var_store.fresh();
|
||||
let num_var_2 = var_store.fresh();
|
||||
let num_var_3 = var_store.fresh();
|
||||
let ret_var = var_store.fresh();
|
||||
let record_var = var_store.fresh();
|
||||
|
||||
// let arg_3 = RunLowLevel NumMulChecked arg_1 arg_2
|
||||
//
|
||||
// if arg_3.b then
|
||||
// # overflow
|
||||
// Err Overflow
|
||||
// else
|
||||
// # all is well
|
||||
// Ok arg_3.a
|
||||
|
||||
let cont = If {
|
||||
branch_var: ret_var,
|
||||
cond_var: bool_var,
|
||||
branches: vec![(
|
||||
// if-condition
|
||||
no_region(
|
||||
// arg_3.b
|
||||
Access {
|
||||
record_var,
|
||||
ext_var: var_store.fresh(),
|
||||
field: "b".into(),
|
||||
field_var: var_store.fresh(),
|
||||
loc_expr: Box::new(no_region(Var(Symbol::ARG_3))),
|
||||
},
|
||||
),
|
||||
// overflow!
|
||||
no_region(tag(
|
||||
"Err",
|
||||
vec![tag("Overflow", Vec::new(), var_store)],
|
||||
var_store,
|
||||
)),
|
||||
)],
|
||||
final_else: Box::new(
|
||||
// all is well
|
||||
no_region(
|
||||
// Ok arg_3.a
|
||||
tag(
|
||||
"Ok",
|
||||
vec![
|
||||
// arg_3.a
|
||||
Access {
|
||||
record_var,
|
||||
ext_var: var_store.fresh(),
|
||||
field: "a".into(),
|
||||
field_var: num_var_3,
|
||||
loc_expr: Box::new(no_region(Var(Symbol::ARG_3))),
|
||||
},
|
||||
],
|
||||
var_store,
|
||||
),
|
||||
),
|
||||
),
|
||||
};
|
||||
|
||||
// arg_3 = RunLowLevel NumMulChecked arg_1 arg_2
|
||||
let def = crate::def::Def {
|
||||
loc_pattern: no_region(Pattern::Identifier(Symbol::ARG_3)),
|
||||
loc_expr: no_region(RunLowLevel {
|
||||
op: LowLevel::NumMulChecked,
|
||||
args: vec![
|
||||
(num_var_1, Var(Symbol::ARG_1)),
|
||||
(num_var_2, Var(Symbol::ARG_2)),
|
||||
],
|
||||
ret_var: record_var,
|
||||
}),
|
||||
expr_var: record_var,
|
||||
pattern_vars: SendMap::default(),
|
||||
annotation: None,
|
||||
};
|
||||
|
||||
let body = LetNonRec(Box::new(def), Box::new(no_region(cont)), ret_var);
|
||||
|
||||
defn(
|
||||
symbol,
|
||||
vec![(num_var_1, Symbol::ARG_1), (num_var_2, Symbol::ARG_2)],
|
||||
var_store,
|
||||
body,
|
||||
ret_var,
|
||||
)
|
||||
}
|
||||
|
||||
/// Num.isGt : Num a, Num a -> Bool
|
||||
fn num_gt(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||
num_num_other_binop(symbol, var_store, LowLevel::NumGt)
|
||||
|
|
|
@ -3010,7 +3010,7 @@ fn run_low_level<'a, 'ctx, 'env>(
|
|||
|
||||
NumAdd | NumSub | NumMul | NumLt | NumLte | NumGt | NumGte | NumRemUnchecked
|
||||
| NumAddWrap | NumAddChecked | NumDivUnchecked | NumPow | NumPowInt | NumSubWrap
|
||||
| NumSubChecked => {
|
||||
| NumSubChecked | NumMulWrap | NumMulChecked => {
|
||||
debug_assert_eq!(args.len(), 2);
|
||||
|
||||
let (lhs_arg, lhs_layout) = load_symbol_and_layout(env, scope, &args[0]);
|
||||
|
@ -3295,7 +3295,8 @@ fn build_int_binop<'a, 'ctx, 'env>(
|
|||
|
||||
mul_result
|
||||
}
|
||||
// NumMulWrap => bd.build_int_mul(lhs, rhs, "mul_int").into(),
|
||||
NumMulWrap => bd.build_int_mul(lhs, rhs, "mul_int").into(),
|
||||
NumMulChecked => env.call_intrinsic(LLVM_SMUL_WITH_OVERFLOW_I64, &[lhs.into(), rhs.into()]),
|
||||
NumGt => bd.build_int_compare(SGT, lhs, rhs, "int_gt").into(),
|
||||
NumGte => bd.build_int_compare(SGE, lhs, rhs, "int_gte").into(),
|
||||
NumLt => bd.build_int_compare(SLT, lhs, rhs, "int_lt").into(),
|
||||
|
@ -3533,6 +3534,33 @@ fn build_float_binop<'a, 'ctx, 'env>(
|
|||
|
||||
result.into()
|
||||
}
|
||||
NumMulChecked => {
|
||||
let context = env.context;
|
||||
|
||||
let result = bd.build_float_mul(lhs, rhs, "mul_float");
|
||||
|
||||
let is_finite =
|
||||
call_bitcode_fn(env, &[result.into()], &bitcode::NUM_IS_FINITE).into_int_value();
|
||||
let is_infinite = bd.build_not(is_finite, "negate");
|
||||
|
||||
let struct_type = context.struct_type(
|
||||
&[context.f64_type().into(), context.bool_type().into()],
|
||||
false,
|
||||
);
|
||||
|
||||
let struct_value = {
|
||||
let v1 = struct_type.const_zero();
|
||||
let v2 = bd.build_insert_value(v1, result, 0, "set_result").unwrap();
|
||||
let v3 = bd
|
||||
.build_insert_value(v2, is_infinite, 1, "set_is_infinite")
|
||||
.unwrap();
|
||||
|
||||
v3.into_struct_value()
|
||||
};
|
||||
|
||||
struct_value.into()
|
||||
}
|
||||
NumMulWrap => unreachable!("wrapping multiplication is not defined on floats"),
|
||||
NumGt => bd.build_float_compare(OGT, lhs, rhs, "float_gt").into(),
|
||||
NumGte => bd.build_float_compare(OGE, lhs, rhs, "float_gte").into(),
|
||||
NumLt => bd.build_float_compare(OLT, lhs, rhs, "float_lt").into(),
|
||||
|
|
|
@ -34,6 +34,8 @@ pub enum LowLevel {
|
|||
NumSubWrap,
|
||||
NumSubChecked,
|
||||
NumMul,
|
||||
NumMulWrap,
|
||||
NumMulChecked,
|
||||
NumGt,
|
||||
NumGte,
|
||||
NumLt,
|
||||
|
|
|
@ -800,6 +800,8 @@ define_builtins! {
|
|||
57 NUM_BITWISE_AND: "bitwiseAnd"
|
||||
58 NUM_SUB_WRAP: "subWrap"
|
||||
59 NUM_SUB_CHECKED: "subChecked"
|
||||
60 NUM_MUL_WRAP: "mulWrap"
|
||||
61 NUM_MUL_CHECKED: "mulChecked"
|
||||
}
|
||||
2 BOOL: "Bool" => {
|
||||
0 BOOL_BOOL: "Bool" imported // the Bool.Bool type alias
|
||||
|
|
|
@ -540,8 +540,8 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[bool] {
|
|||
ListSum => arena.alloc_slice_copy(&[borrowed]),
|
||||
|
||||
Eq | NotEq | And | Or | NumAdd | NumAddWrap | NumAddChecked | NumSub | NumSubWrap
|
||||
| NumSubChecked | NumMul | NumGt | NumGte | NumLt | NumLte | NumCompare
|
||||
| NumDivUnchecked | NumRemUnchecked | NumPow | NumPowInt | NumBitwiseAnd => {
|
||||
| NumSubChecked | NumMul | NumMulWrap | NumMulChecked | NumGt | NumGte | NumLt | NumLte
|
||||
| NumCompare | NumDivUnchecked | NumRemUnchecked | NumPow | NumPowInt | NumBitwiseAnd => {
|
||||
arena.alloc_slice_copy(&[irrelevant, irrelevant])
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue