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 // maxI128 : I128
add_type(Symbol::NUM_MAX_I128, i128_type()); 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_ABS => num_abs,
NUM_NEG => num_neg, NUM_NEG => num_neg,
NUM_REM => num_rem, NUM_REM => num_rem,
NUM_IS_MULTIPLE_OF => num_is_multiple_of,
NUM_SQRT => num_sqrt, NUM_SQRT => num_sqrt,
NUM_ROUND => num_round, NUM_ROUND => num_round,
NUM_IS_ODD => num_is_odd, 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_ABS => num_abs,
Symbol::NUM_NEG => num_neg, Symbol::NUM_NEG => num_neg,
Symbol::NUM_REM => num_rem, Symbol::NUM_REM => num_rem,
Symbol::NUM_IS_MULTIPLE_OF => num_is_multiple_of,
Symbol::NUM_SQRT => num_sqrt, Symbol::NUM_SQRT => num_sqrt,
Symbol::NUM_ROUND => num_round, Symbol::NUM_ROUND => num_round,
Symbol::NUM_IS_ODD => num_is_odd, 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 /// Num.neg : Num a -> Num a
fn num_neg(symbol: Symbol, var_store: &mut VarStore) -> Def { fn num_neg(symbol: Symbol, var_store: &mut VarStore) -> Def {
let num_var = var_store.fresh(); 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 NumAdd | NumSub | NumMul | NumLt | NumLte | NumGt | NumGte | NumRemUnchecked
| NumAddWrap | NumAddChecked | NumDivUnchecked | NumPow | NumPowInt | NumSubWrap | NumIsMultipleOf | NumAddWrap | NumAddChecked | NumDivUnchecked | NumPow | NumPowInt
| NumSubChecked | NumMulWrap | NumMulChecked => { | NumSubWrap | NumSubChecked | NumMulWrap | NumMulChecked => {
debug_assert_eq!(args.len(), 2); debug_assert_eq!(args.len(), 2);
let (lhs_arg, lhs_layout) = load_symbol_and_layout(scope, &args[0]); 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(), NumLt => bd.build_int_compare(SLT, lhs, rhs, "int_lt").into(),
NumLte => bd.build_int_compare(SLE, lhs, rhs, "int_lte").into(), NumLte => bd.build_int_compare(SLE, lhs, rhs, "int_lte").into(),
NumRemUnchecked => bd.build_int_signed_rem(lhs, rhs, "rem_int").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(), NumDivUnchecked => bd.build_int_signed_div(lhs, rhs, "div_int").into(),
NumPowInt => call_bitcode_fn(env, &[lhs.into(), rhs.into()], &bitcode::NUM_POW_INT), NumPowInt => call_bitcode_fn(env, &[lhs.into(), rhs.into()], &bitcode::NUM_POW_INT),
NumBitwiseAnd => bd.build_and(lhs, rhs, "int_bitwise_and").into(), NumBitwiseAnd => bd.build_and(lhs, rhs, "int_bitwise_and").into(),

View file

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

View file

@ -856,6 +856,7 @@ define_builtins! {
95 NUM_NAT: "Nat" imported 95 NUM_NAT: "Nat" imported
96 NUM_INT_CAST: "intCast" 96 NUM_INT_CAST: "intCast"
97 NUM_MAX_I128: "maxI128" 97 NUM_MAX_I128: "maxI128"
98 NUM_IS_MULTIPLE_OF: "isMultipleOf"
} }
2 BOOL: "Bool" => { 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 And | Or | NumAdd | NumAddWrap | NumAddChecked | NumSub | NumSubWrap | NumSubChecked
| NumMul | NumMulWrap | NumMulChecked | NumGt | NumGte | NumLt | NumLte | NumCompare | NumMul | NumMulWrap | NumMulChecked | NumGt | NumGte | NumLt | NumLte | NumCompare
| NumDivUnchecked | NumRemUnchecked | NumPow | NumPowInt | NumBitwiseAnd | NumDivUnchecked | NumRemUnchecked | NumIsMultipleOf | NumPow | NumPowInt
| NumBitwiseXor | NumBitwiseOr | NumShiftLeftBy | NumShiftRightBy | NumShiftRightZfBy => { | NumBitwiseAnd | NumBitwiseXor | NumBitwiseOr | NumShiftLeftBy | NumShiftRightBy
arena.alloc_slice_copy(&[irrelevant, irrelevant]) | NumShiftRightZfBy => arena.alloc_slice_copy(&[irrelevant, irrelevant]),
}
NumAbs | NumNeg | NumSin | NumCos | NumSqrtUnchecked | NumRound | NumCeiling | NumFloor NumAbs | NumNeg | NumSin | NumCos | NumSqrtUnchecked | NumRound | NumCeiling | NumFloor
| NumToFloat | Not | NumIsFinite | NumAtan | NumAcos | NumAsin | NumIntCast => { | NumToFloat | Not | NumIsFinite | NumAtan | NumAcos | NumAsin | NumIntCast => {

View file

@ -1377,4 +1377,17 @@ mod gen_num {
i128 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);
}
} }