| author | |
| committer | |
| log | e106e18d96595bdc4bc037e0b36900992a576160 |
| tree | 950e169ddf58e761fb7b90fa4580cc26ef045cbf |
| parent | 964dbeb82623515b8392c8c7cb9317246812174e |
15 files changed, 203 insertions(+), 57 deletions(-)
src/Air.zig+7| ... | ... | @@ -153,6 +153,12 @@ pub const Inst = struct { |
| 153 | 153 | /// of the operation. |
| 154 | 154 | /// Uses the `pl_op` field with payload `Bin`. |
| 155 | 155 | mul_with_overflow, |
| 156 | /// Integer left-shift with overflow. Both operands are guaranteed to be the same type, | |
| 157 | /// and the result is bool. The wrapped value is written to the pointer given by the in | |
| 158 | /// operand of the `pl_op` field. Payload is `Bin` with `lhs` and `rhs` the relevant types | |
| 159 | /// of the operation. | |
| 160 | /// Uses the `pl_op` field with payload `Bin`. | |
| 161 | shl_with_overflow, | |
| 156 | 162 | /// Allocates stack local memory. |
| 157 | 163 | /// Uses the `ty` field. |
| 158 | 164 | alloc, |
| ... | ... | @@ -830,6 +836,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 830 | 836 | .add_with_overflow, |
| 831 | 837 | .sub_with_overflow, |
| 832 | 838 | .mul_with_overflow, |
| 839 | .shl_with_overflow, | |
| 833 | 840 | => return Type.initTag(.bool), |
| 834 | 841 | } |
| 835 | 842 | } |
src/Liveness.zig+2-1| ... | ... | @@ -387,7 +387,8 @@ fn analyzeInst( |
| 387 | 387 | .add_with_overflow, |
| 388 | 388 | .sub_with_overflow, |
| 389 | 389 | .mul_with_overflow, |
| 390 | => { | |
| 390 | .shl_with_overflow, | |
| 391 | => { | |
| 391 | 392 | const pl_op = inst_datas[inst].pl_op; |
| 392 | 393 | const extra = a.air.extraData(Air.Bin, pl_op.payload).data; |
| 393 | 394 | return trackOperands(a, new_set, inst, main_tomb, .{ pl_op.operand, extra.lhs, extra.rhs }); |
src/Sema.zig+39-8| ... | ... | @@ -7425,8 +7425,32 @@ fn zirOverflowArithmetic( |
| 7425 | 7425 | } |
| 7426 | 7426 | } |
| 7427 | 7427 | }, |
| 7428 | .shl_with_overflow, | |
| 7429 | => return sema.fail(block, src, "TODO implement Sema.zirOverflowArithmetic for {}", .{zir_tag}), | |
| 7428 | .shl_with_overflow => { | |
| 7429 | // If lhs is zero, the result is zero and no overflow occurred. | |
| 7430 | // If rhs is zero, the result is lhs (even if undefined) and no overflow occurred. | |
| 7431 | // Oterhwise if either of the arguments is undefined, both results are undefined. | |
| 7432 | if (maybe_lhs_val) |lhs_val| { | |
| 7433 | if (!lhs_val.isUndef() and lhs_val.compareWithZero(.eq)) { | |
| 7434 | break :result .{ .overflowed = .no, .wrapped = lhs }; | |
| 7435 | } | |
| 7436 | } | |
| 7437 | if (maybe_rhs_val) |rhs_val| { | |
| 7438 | if (!rhs_val.isUndef() and rhs_val.compareWithZero(.eq)) { | |
| 7439 | break :result .{ .overflowed = .no, .wrapped = lhs }; | |
| 7440 | } | |
| 7441 | } | |
| 7442 | if (maybe_lhs_val) |lhs_val| { | |
| 7443 | if (maybe_rhs_val) |rhs_val| { | |
| 7444 | if (lhs_val.isUndef() or rhs_val.isUndef()) { | |
| 7445 | break :result .{ .overflowed = .undef, .wrapped = try sema.addConstUndef(dest_ty) }; | |
| 7446 | } | |
| 7447 | ||
| 7448 | const result = try lhs_val.shlWithOverflow(rhs_val, dest_ty, sema.arena, target); | |
| 7449 | const inst = try sema.addConstant(dest_ty, result.wrapped_result); | |
| 7450 | break :result .{ .overflowed = if (result.overflowed) .yes else .no, .wrapped = inst }; | |
| 7451 | } | |
| 7452 | } | |
| 7453 | }, | |
| 7430 | 7454 | else => unreachable, |
| 7431 | 7455 | } |
| 7432 | 7456 | |
| ... | ... | @@ -7434,7 +7458,8 @@ fn zirOverflowArithmetic( |
| 7434 | 7458 | .add_with_overflow => .add_with_overflow, |
| 7435 | 7459 | .mul_with_overflow => .mul_with_overflow, |
| 7436 | 7460 | .sub_with_overflow => .sub_with_overflow, |
| 7437 | else => return sema.fail(block, src, "TODO implement runtime Sema.zirOverflowArithmetic for {}", .{zir_tag}), | |
| 7461 | .shl_with_overflow => .shl_with_overflow, | |
| 7462 | else => unreachable, | |
| 7438 | 7463 | }; |
| 7439 | 7464 | |
| 7440 | 7465 | try sema.requireRuntimeBlock(block, src); |
| ... | ... | @@ -9041,11 +9066,17 @@ fn log2IntType(sema: *Sema, block: *Block, operand: Type, src: LazySrcLoc) Compi |
| 9041 | 9066 | switch (operand.zigTypeTag()) { |
| 9042 | 9067 | .ComptimeInt => return Air.Inst.Ref.comptime_int_type, |
| 9043 | 9068 | .Int => { |
| 9044 | var count: u16 = 0; | |
| 9045 | var s = operand.bitSize(sema.mod.getTarget()) - 1; | |
| 9046 | while (s != 0) : (s >>= 1) { | |
| 9047 | count += 1; | |
| 9048 | } | |
| 9069 | const bits = operand.bitSize(sema.mod.getTarget()); | |
| 9070 | const count = if (bits == 0) | |
| 9071 | 0 | |
| 9072 | else blk: { | |
| 9073 | var count: u16 = 0; | |
| 9074 | var s = bits - 1; | |
| 9075 | while (s != 0) : (s >>= 1) { | |
| 9076 | count += 1; | |
| 9077 | } | |
| 9078 | break :blk count; | |
| 9079 | }; | |
| 9049 | 9080 | const res = try Module.makeIntType(sema.arena, .unsigned, count); |
| 9050 | 9081 | return sema.addType(res); |
| 9051 | 9082 | }, |
src/arch/aarch64/CodeGen.zig+9-3| ... | ... | @@ -524,6 +524,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 524 | 524 | .add_with_overflow => try self.airAddWithOverflow(inst), |
| 525 | 525 | .sub_with_overflow => try self.airSubWithOverflow(inst), |
| 526 | 526 | .mul_with_overflow => try self.airMulWithOverflow(inst), |
| 527 | .shl_with_overflow => try self.airShlWithOverflow(inst), | |
| 527 | 528 | |
| 528 | 529 | .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst), |
| 529 | 530 | |
| ... | ... | @@ -975,17 +976,22 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { |
| 975 | 976 | |
| 976 | 977 | fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 977 | 978 | _ = inst; |
| 978 | return self.fail("TODO implement airAddResultWithOverflow for {}", .{self.target.cpu.arch}); | |
| 979 | return self.fail("TODO implement airAddWithOverflow for {}", .{self.target.cpu.arch}); | |
| 979 | 980 | } |
| 980 | 981 | |
| 981 | 982 | fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 982 | 983 | _ = inst; |
| 983 | return self.fail("TODO implement airSubResultWithOverflow for {}", .{self.target.cpu.arch}); | |
| 984 | return self.fail("TODO implement airSubWithOverflow for {}", .{self.target.cpu.arch}); | |
| 984 | 985 | } |
| 985 | 986 | |
| 986 | 987 | fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 987 | 988 | _ = inst; |
| 988 | return self.fail("TODO implement airMulResultWithOverflow for {}", .{self.target.cpu.arch}); | |
| 989 | return self.fail("TODO implement airMulWithOverflow for {}", .{self.target.cpu.arch}); | |
| 990 | } | |
| 991 | ||
| 992 | fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | |
| 993 | _ = inst; | |
| 994 | return self.fail("TODO implement airShlWithOverflow for {}", .{self.target.cpu.arch}); | |
| 989 | 995 | } |
| 990 | 996 | |
| 991 | 997 | fn airDiv(self: *Self, inst: Air.Inst.Index) !void { |
src/arch/arm/CodeGen.zig+9-3| ... | ... | @@ -522,6 +522,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 522 | 522 | .add_with_overflow => try self.airAddWithOverflow(inst), |
| 523 | 523 | .sub_with_overflow => try self.airSubWithOverflow(inst), |
| 524 | 524 | .mul_with_overflow => try self.airMulWithOverflow(inst), |
| 525 | .shl_with_overflow => try self.airShlWithOverflow(inst), | |
| 525 | 526 | |
| 526 | 527 | .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst), |
| 527 | 528 | |
| ... | ... | @@ -1005,17 +1006,22 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { |
| 1005 | 1006 | |
| 1006 | 1007 | fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1007 | 1008 | _ = inst; |
| 1008 | return self.fail("TODO implement airAddResultWithOverflow for {}", .{self.target.cpu.arch}); | |
| 1009 | return self.fail("TODO implement airAddWithOverflow for {}", .{self.target.cpu.arch}); | |
| 1009 | 1010 | } |
| 1010 | 1011 | |
| 1011 | 1012 | fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1012 | 1013 | _ = inst; |
| 1013 | return self.fail("TODO implement airSubResultWithOverflow for {}", .{self.target.cpu.arch}); | |
| 1014 | return self.fail("TODO implement airSubWithOverflow for {}", .{self.target.cpu.arch}); | |
| 1014 | 1015 | } |
| 1015 | 1016 | |
| 1016 | 1017 | fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1017 | 1018 | _ = inst; |
| 1018 | return self.fail("TODO implement airMulResultWithOverflow for {}", .{self.target.cpu.arch}); | |
| 1019 | return self.fail("TODO implement airMulWithOverflow for {}", .{self.target.cpu.arch}); | |
| 1020 | } | |
| 1021 | ||
| 1022 | fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | |
| 1023 | _ = inst; | |
| 1024 | return self.fail("TODO implement airShlWithOverflow for {}", .{self.target.cpu.arch}); | |
| 1019 | 1025 | } |
| 1020 | 1026 | |
| 1021 | 1027 | fn airDiv(self: *Self, inst: Air.Inst.Index) !void { |
src/arch/riscv64/CodeGen.zig+9-3| ... | ... | @@ -503,6 +503,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 503 | 503 | .add_with_overflow => try self.airAddWithOverflow(inst), |
| 504 | 504 | .sub_with_overflow => try self.airSubWithOverflow(inst), |
| 505 | 505 | .mul_with_overflow => try self.airMulWithOverflow(inst), |
| 506 | .shl_with_overflow => try self.airShlWithOverflow(inst), | |
| 506 | 507 | |
| 507 | 508 | .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst), |
| 508 | 509 | |
| ... | ... | @@ -920,17 +921,22 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { |
| 920 | 921 | |
| 921 | 922 | fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 922 | 923 | _ = inst; |
| 923 | return self.fail("TODO implement airAddResultWithOverflow for {}", .{self.target.cpu.arch}); | |
| 924 | return self.fail("TODO implement airAddWithOverflow for {}", .{self.target.cpu.arch}); | |
| 924 | 925 | } |
| 925 | 926 | |
| 926 | 927 | fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 927 | 928 | _ = inst; |
| 928 | return self.fail("TODO implement airSubResultWithOverflow for {}", .{self.target.cpu.arch}); | |
| 929 | return self.fail("TODO implement airSubWithOverflow for {}", .{self.target.cpu.arch}); | |
| 929 | 930 | } |
| 930 | 931 | |
| 931 | 932 | fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 932 | 933 | _ = inst; |
| 933 | return self.fail("TODO implement airMulResultWithOverflow for {}", .{self.target.cpu.arch}); | |
| 934 | return self.fail("TODO implement airMulWithOverflow for {}", .{self.target.cpu.arch}); | |
| 935 | } | |
| 936 | ||
| 937 | fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | |
| 938 | _ = inst; | |
| 939 | return self.fail("TODO implement airShlWithOverflow for {}", .{self.target.cpu.arch}); | |
| 934 | 940 | } |
| 935 | 941 | |
| 936 | 942 | fn airDiv(self: *Self, inst: Air.Inst.Index) !void { |
src/arch/x86_64/CodeGen.zig+9-3| ... | ... | @@ -556,6 +556,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 556 | 556 | .add_with_overflow => try self.airAddWithOverflow(inst), |
| 557 | 557 | .sub_with_overflow => try self.airSubWithOverflow(inst), |
| 558 | 558 | .mul_with_overflow => try self.airMulWithOverflow(inst), |
| 559 | .shl_with_overflow => try self.airShlWithOverflow(inst), | |
| 559 | 560 | |
| 560 | 561 | .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst), |
| 561 | 562 | |
| ... | ... | @@ -1034,17 +1035,22 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { |
| 1034 | 1035 | |
| 1035 | 1036 | fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1036 | 1037 | _ = inst; |
| 1037 | return self.fail("TODO implement airAddResultWithOverflow for {}", .{self.target.cpu.arch}); | |
| 1038 | return self.fail("TODO implement airAddWithOverflow for {}", .{self.target.cpu.arch}); | |
| 1038 | 1039 | } |
| 1039 | 1040 | |
| 1040 | 1041 | fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1041 | 1042 | _ = inst; |
| 1042 | return self.fail("TODO implement airSubResultWithOverflow for {}", .{self.target.cpu.arch}); | |
| 1043 | return self.fail("TODO implement airSubWithOverflow for {}", .{self.target.cpu.arch}); | |
| 1043 | 1044 | } |
| 1044 | 1045 | |
| 1045 | 1046 | fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1046 | 1047 | _ = inst; |
| 1047 | return self.fail("TODO implement airMulResultWithOverflow for {}", .{self.target.cpu.arch}); | |
| 1048 | return self.fail("TODO implement airMulWithOverflow for {}", .{self.target.cpu.arch}); | |
| 1049 | } | |
| 1050 | ||
| 1051 | fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | |
| 1052 | _ = inst; | |
| 1053 | return self.fail("TODO implement airShlWithOverflow for {}", .{self.target.cpu.arch}); | |
| 1048 | 1054 | } |
| 1049 | 1055 | |
| 1050 | 1056 | fn airDiv(self: *Self, inst: Air.Inst.Index) !void { |
src/codegen/c.zig+7| ... | ... | @@ -1159,6 +1159,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO |
| 1159 | 1159 | .add_with_overflow => try airAddWithOverflow(f, inst), |
| 1160 | 1160 | .sub_with_overflow => try airSubWithOverflow(f, inst), |
| 1161 | 1161 | .mul_with_overflow => try airMulWithOverflow(f, inst), |
| 1162 | .shl_with_overflow => try airShlWithOverflow(f, inst), | |
| 1162 | 1163 | |
| 1163 | 1164 | .min => try airMinMax(f, inst, "<"), |
| 1164 | 1165 | .max => try airMinMax(f, inst, ">"), |
| ... | ... | @@ -1887,6 +1888,12 @@ fn airMulWithOverflow(f: *Function, inst: Air.Inst.Index) !CValue { |
| 1887 | 1888 | return f.fail("TODO mul with overflow", .{}); |
| 1888 | 1889 | } |
| 1889 | 1890 | |
| 1891 | fn airShlWithOverflow(f: *Function, inst: Air.Inst.Index) !CValue { | |
| 1892 | _ = f; | |
| 1893 | _ = inst; | |
| 1894 | return f.fail("TODO shl with overflow", .{}); | |
| 1895 | } | |
| 1896 | ||
| 1890 | 1897 | fn airNot(f: *Function, inst: Air.Inst.Index) !CValue { |
| 1891 | 1898 | if (f.liveness.isUnused(inst)) |
| 1892 | 1899 | return CValue.none; |
src/codegen/llvm.zig+36| ... | ... | @@ -1721,6 +1721,7 @@ pub const FuncGen = struct { |
| 1721 | 1721 | .add_with_overflow => try self.airOverflow(inst, "llvm.sadd.with.overflow", "llvm.uadd.with.overflow"), |
| 1722 | 1722 | .sub_with_overflow => try self.airOverflow(inst, "llvm.ssub.with.overflow", "llvm.usub.with.overflow"), |
| 1723 | 1723 | .mul_with_overflow => try self.airOverflow(inst, "llvm.smul.with.overflow", "llvm.umul.with.overflow"), |
| 1724 | .shl_with_overflow => try self.airShlWithOverflow(inst), | |
| 1724 | 1725 | |
| 1725 | 1726 | .bit_and, .bool_and => try self.airAnd(inst), |
| 1726 | 1727 | .bit_or, .bool_or => try self.airOr(inst), |
| ... | ... | @@ -3176,6 +3177,41 @@ pub const FuncGen = struct { |
| 3176 | 3177 | return overflow_bit; |
| 3177 | 3178 | } |
| 3178 | 3179 | |
| 3180 | fn airShlWithOverflow(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { | |
| 3181 | if (self.liveness.isUnused(inst)) | |
| 3182 | return null; | |
| 3183 | ||
| 3184 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | |
| 3185 | const extra = self.air.extraData(Air.Bin, pl_op.payload).data; | |
| 3186 | ||
| 3187 | const ptr = try self.resolveInst(pl_op.operand); | |
| 3188 | const lhs = try self.resolveInst(extra.lhs); | |
| 3189 | const rhs = try self.resolveInst(extra.rhs); | |
| 3190 | ||
| 3191 | const ptr_ty = self.air.typeOf(pl_op.operand); | |
| 3192 | const lhs_ty = self.air.typeOf(extra.lhs); | |
| 3193 | const rhs_ty = self.air.typeOf(extra.rhs); | |
| 3194 | ||
| 3195 | const tg = self.dg.module.getTarget(); | |
| 3196 | ||
| 3197 | const casted_rhs = if (rhs_ty.bitSize(tg) < lhs_ty.bitSize(tg)) | |
| 3198 | self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_ty), "") | |
| 3199 | else | |
| 3200 | rhs; | |
| 3201 | ||
| 3202 | const result = self.builder.buildShl(lhs, casted_rhs, ""); | |
| 3203 | const reconstructed = if (lhs_ty.isSignedInt()) | |
| 3204 | self.builder.buildAShr(result, casted_rhs, "") | |
| 3205 | else | |
| 3206 | self.builder.buildLShr(result, casted_rhs, ""); | |
| 3207 | ||
| 3208 | const overflow_bit = self.builder.buildICmp(.NE, lhs, reconstructed, ""); | |
| 3209 | ||
| 3210 | self.store(ptr, ptr_ty, result, .NotAtomic); | |
| 3211 | ||
| 3212 | return overflow_bit; | |
| 3213 | } | |
| 3214 | ||
| 3179 | 3215 | fn airAnd(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { |
| 3180 | 3216 | if (self.liveness.isUnused(inst)) |
| 3181 | 3217 | return null; |
src/print_air.zig+1| ... | ... | @@ -233,6 +233,7 @@ const Writer = struct { |
| 233 | 233 | .add_with_overflow, |
| 234 | 234 | .sub_with_overflow, |
| 235 | 235 | .mul_with_overflow, |
| 236 | .shl_with_overflow, | |
| 236 | 237 | => try w.writeOverflow(s, inst), |
| 237 | 238 | } |
| 238 | 239 | } |
src/value.zig+31| ... | ... | @@ -2548,6 +2548,37 @@ pub const Value = extern union { |
| 2548 | 2548 | return fromBigInt(allocator, result_bigint.toConst()); |
| 2549 | 2549 | } |
| 2550 | 2550 | |
| 2551 | pub fn shlWithOverflow( | |
| 2552 | lhs: Value, | |
| 2553 | rhs: Value, | |
| 2554 | ty: Type, | |
| 2555 | allocator: Allocator, | |
| 2556 | target: Target, | |
| 2557 | ) !OverflowArithmeticResult { | |
| 2558 | const info = ty.intInfo(target); | |
| 2559 | var lhs_space: Value.BigIntSpace = undefined; | |
| 2560 | const lhs_bigint = lhs.toBigInt(&lhs_space); | |
| 2561 | const shift = @intCast(usize, rhs.toUnsignedInt()); | |
| 2562 | const limbs = try allocator.alloc( | |
| 2563 | std.math.big.Limb, | |
| 2564 | lhs_bigint.limbs.len + (shift / (@sizeOf(std.math.big.Limb) * 8)) + 1, | |
| 2565 | ); | |
| 2566 | var result_bigint = BigIntMutable{ | |
| 2567 | .limbs = limbs, | |
| 2568 | .positive = undefined, | |
| 2569 | .len = undefined, | |
| 2570 | }; | |
| 2571 | result_bigint.shiftLeft(lhs_bigint, shift); | |
| 2572 | const overflowed = !result_bigint.toConst().fitsInTwosComp(info.signedness, info.bits); | |
| 2573 | if (overflowed) { | |
| 2574 | result_bigint.truncate(result_bigint.toConst(), info.signedness, info.bits); | |
| 2575 | } | |
| 2576 | return OverflowArithmeticResult{ | |
| 2577 | .overflowed = overflowed, | |
| 2578 | .wrapped_result = try fromBigInt(allocator, result_bigint.toConst()), | |
| 2579 | }; | |
| 2580 | } | |
| 2581 | ||
| 2551 | 2582 | pub fn shlSat( |
| 2552 | 2583 | lhs: Value, |
| 2553 | 2584 | rhs: Value, |
test/behavior/eval.zig+16| ... | ... | @@ -451,3 +451,19 @@ test "comptime bitwise operators" { |
| 451 | 451 | try expect(~@as(u128, 0) == 0xffffffffffffffffffffffffffffffff); |
| 452 | 452 | } |
| 453 | 453 | } |
| 454 | ||
| 455 | test "comptime shlWithOverflow" { | |
| 456 | const ct_shifted: u64 = comptime amt: { | |
| 457 | var amt = @as(u64, 0); | |
| 458 | _ = @shlWithOverflow(u64, ~@as(u64, 0), 16, &amt); | |
| 459 | break :amt amt; | |
| 460 | }; | |
| 461 | ||
| 462 | const rt_shifted: u64 = amt: { | |
| 463 | var amt = @as(u64, 0); | |
| 464 | _ = @shlWithOverflow(u64, ~@as(u64, 0), 16, &amt); | |
| 465 | break :amt amt; | |
| 466 | }; | |
| 467 | ||
| 468 | try expect(ct_shifted == rt_shifted); | |
| 469 | } |
test/behavior/eval_stage1.zig-16| ... | ... | @@ -162,22 +162,6 @@ test "const ptr to comptime mutable data is not memoized" { |
| 162 | 162 | } |
| 163 | 163 | } |
| 164 | 164 | |
| 165 | test "comptime shlWithOverflow" { | |
| 166 | const ct_shifted: u64 = comptime amt: { | |
| 167 | var amt = @as(u64, 0); | |
| 168 | _ = @shlWithOverflow(u64, ~@as(u64, 0), 16, &amt); | |
| 169 | break :amt amt; | |
| 170 | }; | |
| 171 | ||
| 172 | const rt_shifted: u64 = amt: { | |
| 173 | var amt = @as(u64, 0); | |
| 174 | _ = @shlWithOverflow(u64, ~@as(u64, 0), 16, &amt); | |
| 175 | break :amt amt; | |
| 176 | }; | |
| 177 | ||
| 178 | try expect(ct_shifted == rt_shifted); | |
| 179 | } | |
| 180 | ||
| 181 | 165 | test "runtime 128 bit integer division" { |
| 182 | 166 | var a: u128 = 152313999999999991610955792383; |
| 183 | 167 | var b: u128 = 10000000000000000000; |
test/behavior/math.zig+28| ... | ... | @@ -511,3 +511,31 @@ test "@subWithOverflow" { |
| 511 | 511 | try expect(!@subWithOverflow(u8, a, b, &result)); |
| 512 | 512 | try expect(result == 0); |
| 513 | 513 | } |
| 514 | ||
| 515 | test "@shlWithOverflow" { | |
| 516 | var result: u16 = undefined; | |
| 517 | try expect(@shlWithOverflow(u16, 0b0010111111111111, 3, &result)); | |
| 518 | try expect(result == 0b0111111111111000); | |
| 519 | try expect(!@shlWithOverflow(u16, 0b0010111111111111, 2, &result)); | |
| 520 | try expect(result == 0b1011111111111100); | |
| 521 | ||
| 522 | var a: u16 = 0b0000_0000_0000_0011; | |
| 523 | var b: u4 = 15; | |
| 524 | try expect(@shlWithOverflow(u16, a, b, &result)); | |
| 525 | try expect(result == 0b1000_0000_0000_0000); | |
| 526 | b = 14; | |
| 527 | try expect(!@shlWithOverflow(u16, a, b, &result)); | |
| 528 | try expect(result == 0b1100_0000_0000_0000); | |
| 529 | } | |
| 530 | ||
| 531 | test "overflow arithmetic with u0 values" { | |
| 532 | var result: u0 = undefined; | |
| 533 | try expect(!@addWithOverflow(u0, 0, 0, &result)); | |
| 534 | try expect(result == 0); | |
| 535 | try expect(!@subWithOverflow(u0, 0, 0, &result)); | |
| 536 | try expect(result == 0); | |
| 537 | try expect(!@mulWithOverflow(u0, 0, 0, &result)); | |
| 538 | try expect(result == 0); | |
| 539 | try expect(!@shlWithOverflow(u0, 0, 0, &result)); | |
| 540 | try expect(result == 0); | |
| 541 | } |
test/behavior/math_stage1.zig-20| ... | ... | @@ -6,26 +6,6 @@ const maxInt = std.math.maxInt; |
| 6 | 6 | const minInt = std.math.minInt; |
| 7 | 7 | const mem = std.mem; |
| 8 | 8 | |
| 9 | test "@shlWithOverflow" { | |
| 10 | var result: u16 = undefined; | |
| 11 | try expect(@shlWithOverflow(u16, 0b0010111111111111, 3, &result)); | |
| 12 | try expect(result == 0b0111111111111000); | |
| 13 | try expect(!@shlWithOverflow(u16, 0b0010111111111111, 2, &result)); | |
| 14 | try expect(result == 0b1011111111111100); | |
| 15 | } | |
| 16 | ||
| 17 | test "overflow arithmetic with u0 values" { | |
| 18 | var result: u0 = undefined; | |
| 19 | try expect(!@addWithOverflow(u0, 0, 0, &result)); | |
| 20 | try expect(result == 0); | |
| 21 | try expect(!@subWithOverflow(u0, 0, 0, &result)); | |
| 22 | try expect(result == 0); | |
| 23 | try expect(!@mulWithOverflow(u0, 0, 0, &result)); | |
| 24 | try expect(result == 0); | |
| 25 | try expect(!@shlWithOverflow(u0, 0, 0, &result)); | |
| 26 | try expect(result == 0); | |
| 27 | } | |
| 28 | ||
| 29 | 9 | test "@clz vectors" { |
| 30 | 10 | try testClzVectors(); |
| 31 | 11 | comptime try testClzVectors(); |