diff --git a/compiler/builtins/src/std.rs b/compiler/builtins/src/std.rs index 42eb034581..5156fadc0b 100644 --- a/compiler/builtins/src/std.rs +++ b/compiler/builtins/src/std.rs @@ -324,6 +324,24 @@ pub fn types() -> MutMap { ), ); + // bitwiseOr : Int a, Int a -> Int a + add_type( + Symbol::NUM_BITWISE_OR, + top_level_function( + vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))], + Box::new(int_type(flex(TVAR1))), + ), + ); + + // shiftLeftBy : Nat, Int a -> Int a + add_type( + Symbol::NUM_SHIFT_LEFT, + top_level_function( + vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))], + Box::new(int_type(flex(TVAR1))), + ), + ); + // rem : Int a, Int a -> Result (Int a) [ DivByZero ]* add_type( Symbol::NUM_REM, diff --git a/compiler/can/src/builtins.rs b/compiler/can/src/builtins.rs index fdff0a4e2c..f3e1ff4a32 100644 --- a/compiler/can/src/builtins.rs +++ b/compiler/can/src/builtins.rs @@ -151,6 +151,8 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option NUM_MIN_INT => num_min_int, NUM_BITWISE_AND => num_bitwise_and, NUM_BITWISE_XOR => num_bitwise_xor, + NUM_BITWISE_OR => num_bitwise_or, + NUM_SHIFT_LEFT=> num_shift_left_by, RESULT_MAP => result_map, RESULT_MAP_ERR => result_map_err, RESULT_WITH_DEFAULT => result_with_default, @@ -273,6 +275,10 @@ pub fn builtin_defs(var_store: &mut VarStore) -> MutMap { Symbol::NUM_ASIN => num_asin, Symbol::NUM_MAX_INT => num_max_int, Symbol::NUM_MIN_INT => num_min_int, + Symbol::NUM_BITWISE_AND => num_bitwise_and, + Symbol::NUM_BITWISE_XOR => num_bitwise_xor, + Symbol::NUM_BITWISE_OR => num_bitwise_or, + Symbol::NUM_SHIFT_LEFT=> num_shift_left_by, Symbol::RESULT_MAP => result_map, Symbol::RESULT_MAP_ERR => result_map_err, Symbol::RESULT_WITH_DEFAULT => result_with_default, @@ -1299,6 +1305,16 @@ fn num_bitwise_xor(symbol: Symbol, var_store: &mut VarStore) -> Def { num_binop(symbol, var_store, LowLevel::NumBitwiseXor) } +/// Num.bitwiseOr: Int, Int -> Int +fn num_bitwise_or(symbol: Symbol, var_store: &mut VarStore) -> Def { + num_binop(symbol, var_store, LowLevel::NumBitwiseOr) +} + +/// Num.shiftLeftBy: Nat, Int a -> Int a +fn num_shift_left_by(symbol: Symbol, var_store: &mut VarStore) -> Def { + lowlevel_2(symbol, LowLevel::NumShiftLeftBy, var_store) +} + /// List.isEmpty : List * -> Bool fn list_is_empty(symbol: Symbol, var_store: &mut VarStore) -> Def { let list_var = var_store.fresh(); diff --git a/compiler/gen/src/llvm/build.rs b/compiler/gen/src/llvm/build.rs index 5e65bc2cee..e77ae31500 100644 --- a/compiler/gen/src/llvm/build.rs +++ b/compiler/gen/src/llvm/build.rs @@ -3943,7 +3943,23 @@ fn run_low_level<'a, 'ctx, 'env>( build_num_binop(env, parent, lhs_arg, lhs_layout, rhs_arg, rhs_layout, op) } - NumBitwiseAnd | NumBitwiseXor => { + NumBitwiseAnd | NumBitwiseOr | NumBitwiseXor => { + debug_assert_eq!(args.len(), 2); + + let (lhs_arg, lhs_layout) = load_symbol_and_layout(scope, &args[0]); + let (rhs_arg, rhs_layout) = load_symbol_and_layout(scope, &args[1]); + + build_int_binop( + env, + parent, + lhs_arg.into_int_value(), + lhs_layout, + rhs_arg.into_int_value(), + rhs_layout, + op, + ) + } + NumShiftLeftBy => { debug_assert_eq!(args.len(), 2); let (lhs_arg, lhs_layout) = load_symbol_and_layout(scope, &args[0]); @@ -4585,6 +4601,14 @@ fn build_int_binop<'a, 'ctx, 'env>( NumPowInt => call_bitcode_fn(env, &[lhs.into(), rhs.into()], &bitcode::NUM_POW_INT), NumBitwiseAnd => bd.build_and(lhs, rhs, "int_bitwise_and").into(), NumBitwiseXor => bd.build_xor(lhs, rhs, "int_bitwise_xor").into(), + NumBitwiseOr => bd.build_or(lhs, rhs, "int_bitwise_or").into(), + NumShiftLeftBy => { + // NOTE arguments are flipped; + // we write `assert_eq!(0b0000_0001 << 0, 0b0000_0001);` + // as `Num.shiftLeftBy 0 0b0000_0001 + bd.build_left_shift(rhs, lhs, "int_bitwise_or").into() + } + _ => { unreachable!("Unrecognized int binary operation: {:?}", op); } diff --git a/compiler/module/src/low_level.rs b/compiler/module/src/low_level.rs index e69fa0dd02..05a20c72c5 100644 --- a/compiler/module/src/low_level.rs +++ b/compiler/module/src/low_level.rs @@ -78,6 +78,8 @@ pub enum LowLevel { NumAsin, NumBitwiseAnd, NumBitwiseXor, + NumBitwiseOr, + NumShiftLeftBy, Eq, NotEq, And, diff --git a/compiler/module/src/symbol.rs b/compiler/module/src/symbol.rs index 54700dd492..64717e405b 100644 --- a/compiler/module/src/symbol.rs +++ b/compiler/module/src/symbol.rs @@ -841,15 +841,17 @@ define_builtins! { 80 NUM_BINARY32: "Binary32" imported 81 NUM_BITWISE_AND: "bitwiseAnd" 82 NUM_BITWISE_XOR: "bitwiseXor" - 83 NUM_SUB_WRAP: "subWrap" - 84 NUM_SUB_CHECKED: "subChecked" - 85 NUM_MUL_WRAP: "mulWrap" - 86 NUM_MUL_CHECKED: "mulChecked" - 87 NUM_INT: "Int" imported - 88 NUM_FLOAT: "Float" imported - 89 NUM_AT_NATURAL: "@Natural" - 90 NUM_NATURAL: "Natural" imported - 91 NUM_NAT: "Nat" imported + 83 NUM_BITWISE_OR: "bitwiseOr" + 84 NUM_SHIFT_LEFT: "shiftLeftBy" + 85 NUM_SUB_WRAP: "subWrap" + 86 NUM_SUB_CHECKED: "subChecked" + 87 NUM_MUL_WRAP: "mulWrap" + 88 NUM_MUL_CHECKED: "mulChecked" + 89 NUM_INT: "Int" imported + 90 NUM_FLOAT: "Float" imported + 91 NUM_AT_NATURAL: "@Natural" + 92 NUM_NATURAL: "Natural" imported + 93 NUM_NAT: "Nat" imported } 2 BOOL: "Bool" => { 0 BOOL_BOOL: "Bool" imported // the Bool.Bool type alias diff --git a/compiler/mono/src/borrow.rs b/compiler/mono/src/borrow.rs index ba652c0c7b..2fa8893d4c 100644 --- a/compiler/mono/src/borrow.rs +++ b/compiler/mono/src/borrow.rs @@ -373,6 +373,14 @@ impl<'a> BorrowInfState<'a> { self.own_var(z); // if the function exects an owned argument (ps), the argument must be owned (args) + debug_assert_eq!( + arguments.len(), + ps.len(), + "{:?} has {} parameters, but was applied to {} arguments", + name, + ps.len(), + arguments.len() + ); self.own_args_using_params(arguments, ps); } None => { @@ -658,7 +666,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 => arena.alloc_slice_copy(&[irrelevant, irrelevant]), + | NumBitwiseXor | NumBitwiseOr | NumShiftLeftBy => { + arena.alloc_slice_copy(&[irrelevant, irrelevant]) + } NumAbs | NumNeg | NumSin | NumCos | NumSqrtUnchecked | NumRound | NumCeiling | NumFloor | NumToFloat | Not | NumIsFinite | NumAtan | NumAcos | NumAsin => {