authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2021-12-21 01:38:46+01:00
committergravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2021-12-21 01:47:27+01:00
loge106e18d96595bdc4bc037e0b36900992a576160
tree950e169ddf58e761fb7b90fa4580cc26ef045cbf
parent964dbeb82623515b8392c8c7cb9317246812174e

stage2: @shlWithOverflow


15 files changed, 203 insertions(+), 57 deletions(-)

src/Air.zig+7
...@@ -153,6 +153,12 @@ pub const Inst = struct {...@@ -153,6 +153,12 @@ pub const Inst = struct {
153 /// of the operation.153 /// of the operation.
154 /// Uses the `pl_op` field with payload `Bin`.154 /// Uses the `pl_op` field with payload `Bin`.
155 mul_with_overflow,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 /// Allocates stack local memory.162 /// Allocates stack local memory.
157 /// Uses the `ty` field.163 /// Uses the `ty` field.
158 alloc,164 alloc,
...@@ -830,6 +836,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -830,6 +836,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
830 .add_with_overflow,836 .add_with_overflow,
831 .sub_with_overflow,837 .sub_with_overflow,
832 .mul_with_overflow,838 .mul_with_overflow,
839 .shl_with_overflow,
833 => return Type.initTag(.bool),840 => return Type.initTag(.bool),
834 }841 }
835}842}
src/Liveness.zig+2-1
...@@ -387,7 +387,8 @@ fn analyzeInst(...@@ -387,7 +387,8 @@ fn analyzeInst(
387 .add_with_overflow,387 .add_with_overflow,
388 .sub_with_overflow,388 .sub_with_overflow,
389 .mul_with_overflow,389 .mul_with_overflow,
390 => {390 .shl_with_overflow,
391 => {
391 const pl_op = inst_datas[inst].pl_op;392 const pl_op = inst_datas[inst].pl_op;
392 const extra = a.air.extraData(Air.Bin, pl_op.payload).data;393 const extra = a.air.extraData(Air.Bin, pl_op.payload).data;
393 return trackOperands(a, new_set, inst, main_tomb, .{ pl_op.operand, extra.lhs, extra.rhs });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,8 +7425,32 @@ fn zirOverflowArithmetic(
7425 }7425 }
7426 }7426 }
7427 },7427 },
7428 .shl_with_overflow,7428 .shl_with_overflow => {
7429 => return sema.fail(block, src, "TODO implement Sema.zirOverflowArithmetic for {}", .{zir_tag}),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 else => unreachable,7454 else => unreachable,
7431 }7455 }
74327456
...@@ -7434,7 +7458,8 @@ fn zirOverflowArithmetic(...@@ -7434,7 +7458,8 @@ fn zirOverflowArithmetic(
7434 .add_with_overflow => .add_with_overflow,7458 .add_with_overflow => .add_with_overflow,
7435 .mul_with_overflow => .mul_with_overflow,7459 .mul_with_overflow => .mul_with_overflow,
7436 .sub_with_overflow => .sub_with_overflow,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 };
74397464
7440 try sema.requireRuntimeBlock(block, src);7465 try sema.requireRuntimeBlock(block, src);
...@@ -9041,11 +9066,17 @@ fn log2IntType(sema: *Sema, block: *Block, operand: Type, src: LazySrcLoc) Compi...@@ -9041,11 +9066,17 @@ fn log2IntType(sema: *Sema, block: *Block, operand: Type, src: LazySrcLoc) Compi
9041 switch (operand.zigTypeTag()) {9066 switch (operand.zigTypeTag()) {
9042 .ComptimeInt => return Air.Inst.Ref.comptime_int_type,9067 .ComptimeInt => return Air.Inst.Ref.comptime_int_type,
9043 .Int => {9068 .Int => {
9044 var count: u16 = 0;9069 const bits = operand.bitSize(sema.mod.getTarget());
9045 var s = operand.bitSize(sema.mod.getTarget()) - 1;9070 const count = if (bits == 0)
9046 while (s != 0) : (s >>= 1) {9071 0
9047 count += 1;9072 else blk: {
9048 }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 const res = try Module.makeIntType(sema.arena, .unsigned, count);9080 const res = try Module.makeIntType(sema.arena, .unsigned, count);
9050 return sema.addType(res);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,6 +524,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
524 .add_with_overflow => try self.airAddWithOverflow(inst),524 .add_with_overflow => try self.airAddWithOverflow(inst),
525 .sub_with_overflow => try self.airSubWithOverflow(inst),525 .sub_with_overflow => try self.airSubWithOverflow(inst),
526 .mul_with_overflow => try self.airMulWithOverflow(inst),526 .mul_with_overflow => try self.airMulWithOverflow(inst),
527 .shl_with_overflow => try self.airShlWithOverflow(inst),
527528
528 .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),529 .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),
529530
...@@ -975,17 +976,22 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {...@@ -975,17 +976,22 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {
975976
976fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {977fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
977 _ = inst;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}
980981
981fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {982fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
982 _ = inst;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}
985986
986fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {987fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
987 _ = inst;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
992fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
993 _ = inst;
994 return self.fail("TODO implement airShlWithOverflow for {}", .{self.target.cpu.arch});
989}995}
990996
991fn airDiv(self: *Self, inst: Air.Inst.Index) !void {997fn 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,6 +522,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
522 .add_with_overflow => try self.airAddWithOverflow(inst),522 .add_with_overflow => try self.airAddWithOverflow(inst),
523 .sub_with_overflow => try self.airSubWithOverflow(inst),523 .sub_with_overflow => try self.airSubWithOverflow(inst),
524 .mul_with_overflow => try self.airMulWithOverflow(inst),524 .mul_with_overflow => try self.airMulWithOverflow(inst),
525 .shl_with_overflow => try self.airShlWithOverflow(inst),
525526
526 .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),527 .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),
527528
...@@ -1005,17 +1006,22 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {...@@ -1005,17 +1006,22 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {
10051006
1006fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {1007fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1007 _ = inst;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}
10101011
1011fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {1012fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1012 _ = inst;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}
10151016
1016fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {1017fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1017 _ = inst;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
1022fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1023 _ = inst;
1024 return self.fail("TODO implement airShlWithOverflow for {}", .{self.target.cpu.arch});
1019}1025}
10201026
1021fn airDiv(self: *Self, inst: Air.Inst.Index) !void {1027fn 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,6 +503,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
503 .add_with_overflow => try self.airAddWithOverflow(inst),503 .add_with_overflow => try self.airAddWithOverflow(inst),
504 .sub_with_overflow => try self.airSubWithOverflow(inst),504 .sub_with_overflow => try self.airSubWithOverflow(inst),
505 .mul_with_overflow => try self.airMulWithOverflow(inst),505 .mul_with_overflow => try self.airMulWithOverflow(inst),
506 .shl_with_overflow => try self.airShlWithOverflow(inst),
506507
507 .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),508 .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),
508509
...@@ -920,17 +921,22 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {...@@ -920,17 +921,22 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {
920921
921fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {922fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
922 _ = inst;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}
925926
926fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {927fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
927 _ = inst;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}
930931
931fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {932fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
932 _ = inst;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
937fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
938 _ = inst;
939 return self.fail("TODO implement airShlWithOverflow for {}", .{self.target.cpu.arch});
934}940}
935941
936fn airDiv(self: *Self, inst: Air.Inst.Index) !void {942fn 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,6 +556,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
556 .add_with_overflow => try self.airAddWithOverflow(inst),556 .add_with_overflow => try self.airAddWithOverflow(inst),
557 .sub_with_overflow => try self.airSubWithOverflow(inst),557 .sub_with_overflow => try self.airSubWithOverflow(inst),
558 .mul_with_overflow => try self.airMulWithOverflow(inst),558 .mul_with_overflow => try self.airMulWithOverflow(inst),
559 .shl_with_overflow => try self.airShlWithOverflow(inst),
559560
560 .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),561 .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),
561562
...@@ -1034,17 +1035,22 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {...@@ -1034,17 +1035,22 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {
10341035
1035fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {1036fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1036 _ = inst;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}
10391040
1040fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {1041fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1041 _ = inst;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}
10441045
1045fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {1046fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1046 _ = inst;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
1051fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1052 _ = inst;
1053 return self.fail("TODO implement airShlWithOverflow for {}", .{self.target.cpu.arch});
1048}1054}
10491055
1050fn airDiv(self: *Self, inst: Air.Inst.Index) !void {1056fn 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,6 +1159,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
1159 .add_with_overflow => try airAddWithOverflow(f, inst),1159 .add_with_overflow => try airAddWithOverflow(f, inst),
1160 .sub_with_overflow => try airSubWithOverflow(f, inst),1160 .sub_with_overflow => try airSubWithOverflow(f, inst),
1161 .mul_with_overflow => try airMulWithOverflow(f, inst),1161 .mul_with_overflow => try airMulWithOverflow(f, inst),
1162 .shl_with_overflow => try airShlWithOverflow(f, inst),
11621163
1163 .min => try airMinMax(f, inst, "<"),1164 .min => try airMinMax(f, inst, "<"),
1164 .max => try airMinMax(f, inst, ">"),1165 .max => try airMinMax(f, inst, ">"),
...@@ -1887,6 +1888,12 @@ fn airMulWithOverflow(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -1887,6 +1888,12 @@ fn airMulWithOverflow(f: *Function, inst: Air.Inst.Index) !CValue {
1887 return f.fail("TODO mul with overflow", .{});1888 return f.fail("TODO mul with overflow", .{});
1888}1889}
18891890
1891fn airShlWithOverflow(f: *Function, inst: Air.Inst.Index) !CValue {
1892 _ = f;
1893 _ = inst;
1894 return f.fail("TODO shl with overflow", .{});
1895}
1896
1890fn airNot(f: *Function, inst: Air.Inst.Index) !CValue {1897fn airNot(f: *Function, inst: Air.Inst.Index) !CValue {
1891 if (f.liveness.isUnused(inst))1898 if (f.liveness.isUnused(inst))
1892 return CValue.none;1899 return CValue.none;
src/codegen/llvm.zig+36
...@@ -1721,6 +1721,7 @@ pub const FuncGen = struct {...@@ -1721,6 +1721,7 @@ pub const FuncGen = struct {
1721 .add_with_overflow => try self.airOverflow(inst, "llvm.sadd.with.overflow", "llvm.uadd.with.overflow"),1721 .add_with_overflow => try self.airOverflow(inst, "llvm.sadd.with.overflow", "llvm.uadd.with.overflow"),
1722 .sub_with_overflow => try self.airOverflow(inst, "llvm.ssub.with.overflow", "llvm.usub.with.overflow"),1722 .sub_with_overflow => try self.airOverflow(inst, "llvm.ssub.with.overflow", "llvm.usub.with.overflow"),
1723 .mul_with_overflow => try self.airOverflow(inst, "llvm.smul.with.overflow", "llvm.umul.with.overflow"),1723 .mul_with_overflow => try self.airOverflow(inst, "llvm.smul.with.overflow", "llvm.umul.with.overflow"),
1724 .shl_with_overflow => try self.airShlWithOverflow(inst),
17241725
1725 .bit_and, .bool_and => try self.airAnd(inst),1726 .bit_and, .bool_and => try self.airAnd(inst),
1726 .bit_or, .bool_or => try self.airOr(inst),1727 .bit_or, .bool_or => try self.airOr(inst),
...@@ -3176,6 +3177,41 @@ pub const FuncGen = struct {...@@ -3176,6 +3177,41 @@ pub const FuncGen = struct {
3176 return overflow_bit;3177 return overflow_bit;
3177 }3178 }
31783179
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 fn airAnd(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {3215 fn airAnd(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
3180 if (self.liveness.isUnused(inst))3216 if (self.liveness.isUnused(inst))
3181 return null;3217 return null;
src/print_air.zig+1
...@@ -233,6 +233,7 @@ const Writer = struct {...@@ -233,6 +233,7 @@ const Writer = struct {
233 .add_with_overflow,233 .add_with_overflow,
234 .sub_with_overflow,234 .sub_with_overflow,
235 .mul_with_overflow,235 .mul_with_overflow,
236 .shl_with_overflow,
236 => try w.writeOverflow(s, inst),237 => try w.writeOverflow(s, inst),
237 }238 }
238 }239 }
src/value.zig+31
...@@ -2548,6 +2548,37 @@ pub const Value = extern union {...@@ -2548,6 +2548,37 @@ pub const Value = extern union {
2548 return fromBigInt(allocator, result_bigint.toConst());2548 return fromBigInt(allocator, result_bigint.toConst());
2549 }2549 }
25502550
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 pub fn shlSat(2582 pub fn shlSat(
2552 lhs: Value,2583 lhs: Value,
2553 rhs: Value,2584 rhs: Value,
test/behavior/eval.zig+16
...@@ -451,3 +451,19 @@ test "comptime bitwise operators" {...@@ -451,3 +451,19 @@ test "comptime bitwise operators" {
451 try expect(~@as(u128, 0) == 0xffffffffffffffffffffffffffffffff);451 try expect(~@as(u128, 0) == 0xffffffffffffffffffffffffffffffff);
452 }452 }
453}453}
454
455test "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,22 +162,6 @@ test "const ptr to comptime mutable data is not memoized" {
162 }162 }
163}163}
164164
165test "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
181test "runtime 128 bit integer division" {165test "runtime 128 bit integer division" {
182 var a: u128 = 152313999999999991610955792383;166 var a: u128 = 152313999999999991610955792383;
183 var b: u128 = 10000000000000000000;167 var b: u128 = 10000000000000000000;
test/behavior/math.zig+28
...@@ -511,3 +511,31 @@ test "@subWithOverflow" {...@@ -511,3 +511,31 @@ test "@subWithOverflow" {
511 try expect(!@subWithOverflow(u8, a, b, &result));511 try expect(!@subWithOverflow(u8, a, b, &result));
512 try expect(result == 0);512 try expect(result == 0);
513}513}
514
515test "@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
531test "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,26 +6,6 @@ const maxInt = std.math.maxInt;
6const minInt = std.math.minInt;6const minInt = std.math.minInt;
7const mem = std.mem;7const mem = std.mem;
88
9test "@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
17test "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
29test "@clz vectors" {9test "@clz vectors" {
30 try testClzVectors();10 try testClzVectors();
31 comptime try testClzVectors();11 comptime try testClzVectors();