authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2021-12-20 21:53:40+01:00
committergravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2021-12-21 01:41:51+01:00
log964dbeb82623515b8392c8c7cb9317246812174e
tree8bedd9ddf607ce6b3ca983702934c3c950959185
parent58d67a6718d5d0673389fa19f5bb20812b4bb22a

stage2: @subWithOverflow


12 files changed, 85 insertions(+), 30 deletions(-)

src/Air.zig+7
...@@ -141,6 +141,12 @@ pub const Inst = struct {...@@ -141,6 +141,12 @@ pub const Inst = struct {
141 /// of the operation.141 /// of the operation.
142 /// Uses the `pl_op` field with payload `Bin`.142 /// Uses the `pl_op` field with payload `Bin`.
143 add_with_overflow,143 add_with_overflow,
144 /// Integer subtraction with overflow. Both operands are guaranteed to be the same type,
145 /// and the result is bool. The wrapped value is written to the pointer given by the in
146 /// operand of the `pl_op` field. Payload is `Bin` with `lhs` and `rhs` the relevant types
147 /// of the operation.
148 /// Uses the `pl_op` field with payload `Bin`.
149 sub_with_overflow,
144 /// Integer multiplication with overflow. Both operands are guaranteed to be the same type,150 /// Integer multiplication with overflow. Both operands are guaranteed to be the same type,
145 /// and the result is bool. The wrapped value is written to the pointer given by the in151 /// and the result is bool. The wrapped value is written to the pointer given by the in
146 /// operand of the `pl_op` field. Payload is `Bin` with `lhs` and `rhs` the relevant types152 /// operand of the `pl_op` field. Payload is `Bin` with `lhs` and `rhs` the relevant types
...@@ -822,6 +828,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -822,6 +828,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
822 },828 },
823829
824 .add_with_overflow,830 .add_with_overflow,
831 .sub_with_overflow,
825 .mul_with_overflow,832 .mul_with_overflow,
826 => return Type.initTag(.bool),833 => return Type.initTag(.bool),
827 }834 }
src/Liveness.zig+6-1
...@@ -382,7 +382,12 @@ fn analyzeInst(...@@ -382,7 +382,12 @@ fn analyzeInst(
382 const extra = a.air.extraData(Air.AtomicRmw, pl_op.payload).data;382 const extra = a.air.extraData(Air.AtomicRmw, pl_op.payload).data;
383 return trackOperands(a, new_set, inst, main_tomb, .{ pl_op.operand, extra.operand, .none });383 return trackOperands(a, new_set, inst, main_tomb, .{ pl_op.operand, extra.operand, .none });
384 },384 },
385 .memset, .memcpy, .add_with_overflow, .mul_with_overflow => {385 .memset,
386 .memcpy,
387 .add_with_overflow,
388 .sub_with_overflow,
389 .mul_with_overflow,
390 => {
386 const pl_op = inst_datas[inst].pl_op;391 const pl_op = inst_datas[inst].pl_op;
387 const extra = a.air.extraData(Air.Bin, pl_op.payload).data;392 const extra = a.air.extraData(Air.Bin, pl_op.payload).data;
388 return trackOperands(a, new_set, inst, main_tomb, .{ pl_op.operand, extra.lhs, extra.rhs });393 return trackOperands(a, new_set, inst, main_tomb, .{ pl_op.operand, extra.lhs, extra.rhs });
src/Sema.zig+23-21
...@@ -7365,16 +7365,27 @@ fn zirOverflowArithmetic(...@@ -7365,16 +7365,27 @@ fn zirOverflowArithmetic(
7365 }7365 }
73667366
7367 const result = try lhs_val.intAddWithOverflow(rhs_val, dest_ty, sema.arena, target);7367 const result = try lhs_val.intAddWithOverflow(rhs_val, dest_ty, sema.arena, target);
7368 const inst = try sema.addConstant(7368 const inst = try sema.addConstant(dest_ty, result.wrapped_result);
7369 dest_ty,7369 break :result .{ .overflowed = if (result.overflowed) .yes else .no, .wrapped = inst };
7370 result.wrapped_result,7370 }
7371 );7371 }
73727372 },
7373 if (result.overflowed) {7373 .sub_with_overflow => {
7374 break :result .{ .overflowed = .yes, .wrapped = inst };7374 // If the rhs is zero, then the result is lhs and no overflow occured.
7375 } else {7375 // Otherwise, if either result is undefined, both results are undefined.
7376 break :result .{ .overflowed = .no, .wrapped = inst };7376 if (maybe_rhs_val) |rhs_val| {
7377 if (rhs_val.isUndef()) {
7378 break :result .{ .overflowed = .undef, .wrapped = try sema.addConstUndef(dest_ty) };
7379 } else if (rhs_val.compareWithZero(.eq)) {
7380 break :result .{ .overflowed = .no, .wrapped = lhs };
7381 } else if (maybe_lhs_val) |lhs_val| {
7382 if (lhs_val.isUndef()) {
7383 break :result .{ .overflowed = .undef, .wrapped = try sema.addConstUndef(dest_ty) };
7377 }7384 }
7385
7386 const result = try lhs_val.intSubWithOverflow(rhs_val, dest_ty, sema.arena, target);
7387 const inst = try sema.addConstant(dest_ty, result.wrapped_result);
7388 break :result .{ .overflowed = if (result.overflowed) .yes else .no, .wrapped = inst };
7378 }7389 }
7379 }7390 }
7380 },7391 },
...@@ -7382,7 +7393,6 @@ fn zirOverflowArithmetic(...@@ -7382,7 +7393,6 @@ fn zirOverflowArithmetic(
7382 // If either of the arguments is zero, the result is zero and no overflow occured.7393 // If either of the arguments is zero, the result is zero and no overflow occured.
7383 // If either of the arguments is one, the result is the other and no overflow occured.7394 // If either of the arguments is one, the result is the other and no overflow occured.
7384 // Otherwise, if either of the arguments is undefined, both results are undefined.7395 // Otherwise, if either of the arguments is undefined, both results are undefined.
7385
7386 if (maybe_lhs_val) |lhs_val| {7396 if (maybe_lhs_val) |lhs_val| {
7387 if (!lhs_val.isUndef()) {7397 if (!lhs_val.isUndef()) {
7388 if (lhs_val.compareWithZero(.eq)) {7398 if (lhs_val.compareWithZero(.eq)) {
...@@ -7410,20 +7420,11 @@ fn zirOverflowArithmetic(...@@ -7410,20 +7420,11 @@ fn zirOverflowArithmetic(
7410 }7420 }
74117421
7412 const result = try lhs_val.intMulWithOverflow(rhs_val, dest_ty, sema.arena, target);7422 const result = try lhs_val.intMulWithOverflow(rhs_val, dest_ty, sema.arena, target);
7413 const inst = try sema.addConstant(7423 const inst = try sema.addConstant(dest_ty, result.wrapped_result);
7414 dest_ty,7424 break :result .{ .overflowed = if (result.overflowed) .yes else .no, .wrapped = inst };
7415 result.wrapped_result,
7416 );
7417
7418 if (result.overflowed) {
7419 break :result .{ .overflowed = .yes, .wrapped = inst };
7420 } else {
7421 break :result .{ .overflowed = .no, .wrapped = inst };
7422 }
7423 }7425 }
7424 }7426 }
7425 },7427 },
7426 .sub_with_overflow,
7427 .shl_with_overflow,7428 .shl_with_overflow,
7428 => return sema.fail(block, src, "TODO implement Sema.zirOverflowArithmetic for {}", .{zir_tag}),7429 => return sema.fail(block, src, "TODO implement Sema.zirOverflowArithmetic for {}", .{zir_tag}),
7429 else => unreachable,7430 else => unreachable,
...@@ -7432,6 +7433,7 @@ fn zirOverflowArithmetic(...@@ -7432,6 +7433,7 @@ fn zirOverflowArithmetic(
7432 const air_tag: Air.Inst.Tag = switch (zir_tag) {7433 const air_tag: Air.Inst.Tag = switch (zir_tag) {
7433 .add_with_overflow => .add_with_overflow,7434 .add_with_overflow => .add_with_overflow,
7434 .mul_with_overflow => .mul_with_overflow,7435 .mul_with_overflow => .mul_with_overflow,
7436 .sub_with_overflow => .sub_with_overflow,
7435 else => return sema.fail(block, src, "TODO implement runtime Sema.zirOverflowArithmetic for {}", .{zir_tag}),7437 else => return sema.fail(block, src, "TODO implement runtime Sema.zirOverflowArithmetic for {}", .{zir_tag}),
7436 };7438 };
74377439
src/arch/aarch64/CodeGen.zig+6
...@@ -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 .slice => try self.airSlice(inst),522 .slice => try self.airSlice(inst),
523523
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 .mul_with_overflow => try self.airMulWithOverflow(inst),526 .mul_with_overflow => try self.airMulWithOverflow(inst),
526527
527 .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),528 .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),
...@@ -977,6 +978,11 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -977,6 +978,11 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
977 return self.fail("TODO implement airAddResultWithOverflow for {}", .{self.target.cpu.arch});978 return self.fail("TODO implement airAddResultWithOverflow for {}", .{self.target.cpu.arch});
978}979}
979980
981fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
982 _ = inst;
983 return self.fail("TODO implement airSubResultWithOverflow for {}", .{self.target.cpu.arch});
984}
985
980fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {986fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
981 _ = inst;987 _ = inst;
982 return self.fail("TODO implement airMulResultWithOverflow for {}", .{self.target.cpu.arch});988 return self.fail("TODO implement airMulResultWithOverflow for {}", .{self.target.cpu.arch});
src/arch/arm/CodeGen.zig+6
...@@ -520,6 +520,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -520,6 +520,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
520 .slice => try self.airSlice(inst),520 .slice => try self.airSlice(inst),
521521
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 .mul_with_overflow => try self.airMulWithOverflow(inst),524 .mul_with_overflow => try self.airMulWithOverflow(inst),
524525
525 .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),526 .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),
...@@ -1007,6 +1008,11 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1007,6 +1008,11 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1007 return self.fail("TODO implement airAddResultWithOverflow for {}", .{self.target.cpu.arch});1008 return self.fail("TODO implement airAddResultWithOverflow for {}", .{self.target.cpu.arch});
1008}1009}
10091010
1011fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1012 _ = inst;
1013 return self.fail("TODO implement airSubResultWithOverflow for {}", .{self.target.cpu.arch});
1014}
1015
1010fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {1016fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1011 _ = inst;1017 _ = inst;
1012 return self.fail("TODO implement airMulResultWithOverflow for {}", .{self.target.cpu.arch});1018 return self.fail("TODO implement airMulResultWithOverflow for {}", .{self.target.cpu.arch});
src/arch/riscv64/CodeGen.zig+6
...@@ -501,6 +501,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -501,6 +501,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
501 .slice => try self.airSlice(inst),501 .slice => try self.airSlice(inst),
502502
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 .mul_with_overflow => try self.airMulWithOverflow(inst),505 .mul_with_overflow => try self.airMulWithOverflow(inst),
505506
506 .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),507 .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),
...@@ -922,6 +923,11 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -922,6 +923,11 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
922 return self.fail("TODO implement airAddResultWithOverflow for {}", .{self.target.cpu.arch});923 return self.fail("TODO implement airAddResultWithOverflow for {}", .{self.target.cpu.arch});
923}924}
924925
926fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
927 _ = inst;
928 return self.fail("TODO implement airSubResultWithOverflow for {}", .{self.target.cpu.arch});
929}
930
925fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {931fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
926 _ = inst;932 _ = inst;
927 return self.fail("TODO implement airMulResultWithOverflow for {}", .{self.target.cpu.arch});933 return self.fail("TODO implement airMulResultWithOverflow for {}", .{self.target.cpu.arch});
src/arch/x86_64/CodeGen.zig+6
...@@ -554,6 +554,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -554,6 +554,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
554 .slice => try self.airSlice(inst),554 .slice => try self.airSlice(inst),
555555
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 .mul_with_overflow => try self.airMulWithOverflow(inst),558 .mul_with_overflow => try self.airMulWithOverflow(inst),
558559
559 .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),560 .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),
...@@ -1036,6 +1037,11 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1036,6 +1037,11 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1036 return self.fail("TODO implement airAddResultWithOverflow for {}", .{self.target.cpu.arch});1037 return self.fail("TODO implement airAddResultWithOverflow for {}", .{self.target.cpu.arch});
1037}1038}
10381039
1040fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1041 _ = inst;
1042 return self.fail("TODO implement airSubResultWithOverflow for {}", .{self.target.cpu.arch});
1043}
1044
1039fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {1045fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1040 _ = inst;1046 _ = inst;
1041 return self.fail("TODO implement airMulResultWithOverflow for {}", .{self.target.cpu.arch});1047 return self.fail("TODO implement airMulResultWithOverflow for {}", .{self.target.cpu.arch});
src/codegen/c.zig+7
...@@ -1157,6 +1157,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO...@@ -1157,6 +1157,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
1157 .shl_sat => try airSatOp(f, inst, "shls_"),1157 .shl_sat => try airSatOp(f, inst, "shls_"),
11581158
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 .mul_with_overflow => try airMulWithOverflow(f, inst),1161 .mul_with_overflow => try airMulWithOverflow(f, inst),
11611162
1162 .min => try airMinMax(f, inst, "<"),1163 .min => try airMinMax(f, inst, "<"),
...@@ -1874,6 +1875,12 @@ fn airAddWithOverflow(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -1874,6 +1875,12 @@ fn airAddWithOverflow(f: *Function, inst: Air.Inst.Index) !CValue {
1874 return f.fail("TODO add with overflow", .{});1875 return f.fail("TODO add with overflow", .{});
1875}1876}
18761877
1878fn airSubWithOverflow(f: *Function, inst: Air.Inst.Index) !CValue {
1879 _ = f;
1880 _ = inst;
1881 return f.fail("TODO sub with overflow", .{});
1882}
1883
1877fn airMulWithOverflow(f: *Function, inst: Air.Inst.Index) !CValue {1884fn airMulWithOverflow(f: *Function, inst: Air.Inst.Index) !CValue {
1878 _ = f;1885 _ = f;
1879 _ = inst;1886 _ = inst;
src/codegen/llvm.zig+1
...@@ -1719,6 +1719,7 @@ pub const FuncGen = struct {...@@ -1719,6 +1719,7 @@ pub const FuncGen = struct {
1719 .slice => try self.airSlice(inst),1719 .slice => try self.airSlice(inst),
17201720
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 .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"),
17231724
1724 .bit_and, .bool_and => try self.airAnd(inst),1725 .bit_and, .bool_and => try self.airAnd(inst),
src/print_air.zig+1
...@@ -231,6 +231,7 @@ const Writer = struct {...@@ -231,6 +231,7 @@ const Writer = struct {
231 .memset => try w.writeMemset(s, inst),231 .memset => try w.writeMemset(s, inst),
232232
233 .add_with_overflow,233 .add_with_overflow,
234 .sub_with_overflow,
234 .mul_with_overflow,235 .mul_with_overflow,
235 => try w.writeOverflow(s, inst),236 => try w.writeOverflow(s, inst),
236 }237 }
test/behavior/math.zig+16
...@@ -495,3 +495,19 @@ test "@mulWithOverflow" {...@@ -495,3 +495,19 @@ test "@mulWithOverflow" {
495 try expect(@mulWithOverflow(u8, a, b, &result));495 try expect(@mulWithOverflow(u8, a, b, &result));
496 try expect(result == 236);496 try expect(result == 236);
497}497}
498
499test "@subWithOverflow" {
500 var result: u8 = undefined;
501 try expect(@subWithOverflow(u8, 1, 2, &result));
502 try expect(result == 255);
503 try expect(!@subWithOverflow(u8, 1, 1, &result));
504 try expect(result == 0);
505
506 var a: u8 = 1;
507 var b: u8 = 2;
508 try expect(@subWithOverflow(u8, a, b, &result));
509 try expect(result == 255);
510 b = 1;
511 try expect(!@subWithOverflow(u8, a, b, &result));
512 try expect(result == 0);
513}
test/behavior/math_stage1.zig-8
...@@ -6,14 +6,6 @@ const maxInt = std.math.maxInt;...@@ -6,14 +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 "@subWithOverflow" {
10 var result: u8 = undefined;
11 try expect(@subWithOverflow(u8, 1, 2, &result));
12 try expect(result == 255);
13 try expect(!@subWithOverflow(u8, 1, 1, &result));
14 try expect(result == 0);
15}
16
17test "@shlWithOverflow" {9test "@shlWithOverflow" {
18 var result: u16 = undefined;10 var result: u16 = undefined;
19 try expect(@shlWithOverflow(u16, 0b0010111111111111, 3, &result));11 try expect(@shlWithOverflow(u16, 0b0010111111111111, 3, &result));