Merge branch 'trunk' into singleton-to-single

This commit is contained in:
Chadtech 2021-03-14 21:58:08 -04:00 committed by GitHub
commit 1e9cf7ba89
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 74 additions and 6 deletions

View file

@ -384,6 +384,15 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
),
);
// isMultipleOf : Int a, Int a -> Bool
add_type(
Symbol::NUM_IS_MULTIPLE_OF,
top_level_function(
vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))],
Box::new(bool_type()),
),
);
// maxI128 : I128
add_type(Symbol::NUM_MAX_I128, i128_type());

View file

@ -136,6 +136,7 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option<Def>
NUM_ABS => num_abs,
NUM_NEG => num_neg,
NUM_REM => num_rem,
NUM_IS_MULTIPLE_OF => num_is_multiple_of,
NUM_SQRT => num_sqrt,
NUM_ROUND => num_round,
NUM_IS_ODD => num_is_odd,
@ -271,6 +272,7 @@ pub fn builtin_defs(var_store: &mut VarStore) -> MutMap<Symbol, Def> {
Symbol::NUM_ABS => num_abs,
Symbol::NUM_NEG => num_neg,
Symbol::NUM_REM => num_rem,
Symbol::NUM_IS_MULTIPLE_OF => num_is_multiple_of,
Symbol::NUM_SQRT => num_sqrt,
Symbol::NUM_ROUND => num_round,
Symbol::NUM_IS_ODD => num_is_odd,
@ -2611,6 +2613,11 @@ fn num_rem(symbol: Symbol, var_store: &mut VarStore) -> Def {
)
}
/// Num.isMultipleOf : Int, Int -> Bool
fn num_is_multiple_of(symbol: Symbol, var_store: &mut VarStore) -> Def {
lowlevel_2(symbol, LowLevel::NumIsMultipleOf, var_store)
}
/// Num.neg : Num a -> Num a
fn num_neg(symbol: Symbol, var_store: &mut VarStore) -> Def {
let num_var = var_store.fresh();

View file

@ -4075,8 +4075,8 @@ fn run_low_level<'a, 'ctx, 'env>(
}
NumAdd | NumSub | NumMul | NumLt | NumLte | NumGt | NumGte | NumRemUnchecked
| NumAddWrap | NumAddChecked | NumDivUnchecked | NumPow | NumPowInt | NumSubWrap
| NumSubChecked | NumMulWrap | NumMulChecked => {
| NumIsMultipleOf | NumAddWrap | NumAddChecked | NumDivUnchecked | NumPow | NumPowInt
| NumSubWrap | NumSubChecked | NumMulWrap | NumMulChecked => {
debug_assert_eq!(args.len(), 2);
let (lhs_arg, lhs_layout) = load_symbol_and_layout(scope, &args[0]);
@ -4778,6 +4778,44 @@ fn build_int_binop<'a, 'ctx, 'env>(
NumLt => bd.build_int_compare(SLT, lhs, rhs, "int_lt").into(),
NumLte => bd.build_int_compare(SLE, lhs, rhs, "int_lte").into(),
NumRemUnchecked => bd.build_int_signed_rem(lhs, rhs, "rem_int").into(),
NumIsMultipleOf => {
/* this builds the following construct
if rhs == 0 {
lhs == 0
} else {
let rem = lhs % rhs;
rem == 0
}
*/
let zero = rhs.get_type().const_zero();
let condition_rhs = bd.build_int_compare(IntPredicate::EQ, rhs, zero, "is_zero_rhs");
let condition_lhs = bd.build_int_compare(IntPredicate::EQ, lhs, zero, "is_zero_lhs");
let current_block = bd.get_insert_block().unwrap(); //block that we are in right now;
let else_block = env.context.append_basic_block(parent, "else"); //
let cont_block = env.context.append_basic_block(parent, "branchcont");
bd.build_conditional_branch(condition_rhs, cont_block, else_block);
bd.position_at_end(else_block);
let rem = bd.build_int_signed_rem(lhs, rhs, "int_rem");
let condition_rem = bd.build_int_compare(IntPredicate::EQ, rem, zero, "is_zero_rem");
bd.build_unconditional_branch(cont_block);
bd.position_at_end(cont_block);
let phi = bd.build_phi(env.context.bool_type(), "branch");
phi.add_incoming(&[
(&condition_lhs, current_block),
(&condition_rem, else_block),
]);
phi.as_basic_value()
}
NumDivUnchecked => bd.build_int_signed_div(lhs, rhs, "div_int").into(),
NumPowInt => call_bitcode_fn(env, &[lhs.into(), rhs.into()], &bitcode::NUM_POW_INT),
NumBitwiseAnd => bd.build_and(lhs, rhs, "int_bitwise_and").into(),

View file

@ -65,6 +65,7 @@ pub enum LowLevel {
NumCompare,
NumDivUnchecked,
NumRemUnchecked,
NumIsMultipleOf,
NumAbs,
NumNeg,
NumSin,

View file

@ -856,6 +856,7 @@ define_builtins! {
95 NUM_NAT: "Nat" imported
96 NUM_INT_CAST: "intCast"
97 NUM_MAX_I128: "maxI128"
98 NUM_IS_MULTIPLE_OF: "isMultipleOf"
}
2 BOOL: "Bool" => {

View file

@ -667,10 +667,9 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[bool] {
And | Or | NumAdd | NumAddWrap | NumAddChecked | NumSub | NumSubWrap | NumSubChecked
| NumMul | NumMulWrap | NumMulChecked | NumGt | NumGte | NumLt | NumLte | NumCompare
| NumDivUnchecked | NumRemUnchecked | NumPow | NumPowInt | NumBitwiseAnd
| NumBitwiseXor | NumBitwiseOr | NumShiftLeftBy | NumShiftRightBy | NumShiftRightZfBy => {
arena.alloc_slice_copy(&[irrelevant, irrelevant])
}
| NumDivUnchecked | NumRemUnchecked | NumIsMultipleOf | NumPow | NumPowInt
| 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 => {

View file

@ -1377,4 +1377,17 @@ mod gen_num {
i128
);
}
#[test]
fn is_multiple_of() {
// true
assert_evals_to!("Num.isMultipleOf 5 1", true, bool);
assert_evals_to!("Num.isMultipleOf 5 -1", true, bool);
assert_evals_to!("Num.isMultipleOf 0 0", true, bool);
assert_evals_to!("Num.isMultipleOf 0 1", true, bool);
assert_evals_to!("Num.isMultipleOf 0 -1", true, bool);
// false
assert_evals_to!("Num.isMultipleOf 5 2", false, bool);
assert_evals_to!("Num.isMultipleOf 5 0", false, bool);
}
}