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 {
141141 /// of the operation.
142142 /// Uses the `pl_op` field with payload `Bin`.
143143 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,
144150 /// Integer multiplication with overflow. Both operands are guaranteed to be the same type,
145151 /// and the result is bool. The wrapped value is written to the pointer given by the in
146152 /// 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 {
822828 },
823829
824830 .add_with_overflow,
831 .sub_with_overflow,
825832 .mul_with_overflow,
826833 => return Type.initTag(.bool),
827834 }
src/Liveness.zig+6-1
......@@ -382,7 +382,12 @@ fn analyzeInst(
382382 const extra = a.air.extraData(Air.AtomicRmw, pl_op.payload).data;
383383 return trackOperands(a, new_set, inst, main_tomb, .{ pl_op.operand, extra.operand, .none });
384384 },
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 => {
386391 const pl_op = inst_datas[inst].pl_op;
387392 const extra = a.air.extraData(Air.Bin, pl_op.payload).data;
388393 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(
73657365 }
73667366
73677367 const result = try lhs_val.intAddWithOverflow(rhs_val, dest_ty, sema.arena, target);
7368 const inst = try sema.addConstant(
7369 dest_ty,
7370 result.wrapped_result,
7371 );
7372
7373 if (result.overflowed) {
7374 break :result .{ .overflowed = .yes, .wrapped = inst };
7375 } else {
7376 break :result .{ .overflowed = .no, .wrapped = inst };
7368 const inst = try sema.addConstant(dest_ty, result.wrapped_result);
7369 break :result .{ .overflowed = if (result.overflowed) .yes else .no, .wrapped = inst };
7370 }
7371 }
7372 },
7373 .sub_with_overflow => {
7374 // If the rhs is zero, then the result is lhs and no overflow occured.
7375 // Otherwise, if either result is undefined, both results are undefined.
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) };
73777384 }
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 };
73787389 }
73797390 }
73807391 },
......@@ -7382,7 +7393,6 @@ fn zirOverflowArithmetic(
73827393 // If either of the arguments is zero, the result is zero and no overflow occured.
73837394 // If either of the arguments is one, the result is the other and no overflow occured.
73847395 // Otherwise, if either of the arguments is undefined, both results are undefined.
7385
73867396 if (maybe_lhs_val) |lhs_val| {
73877397 if (!lhs_val.isUndef()) {
73887398 if (lhs_val.compareWithZero(.eq)) {
......@@ -7410,20 +7420,11 @@ fn zirOverflowArithmetic(
74107420 }
74117421
74127422 const result = try lhs_val.intMulWithOverflow(rhs_val, dest_ty, sema.arena, target);
7413 const inst = try sema.addConstant(
7414 dest_ty,
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 const inst = try sema.addConstant(dest_ty, result.wrapped_result);
7424 break :result .{ .overflowed = if (result.overflowed) .yes else .no, .wrapped = inst };
74237425 }
74247426 }
74257427 },
7426 .sub_with_overflow,
74277428 .shl_with_overflow,
74287429 => return sema.fail(block, src, "TODO implement Sema.zirOverflowArithmetic for {}", .{zir_tag}),
74297430 else => unreachable,
......@@ -7432,6 +7433,7 @@ fn zirOverflowArithmetic(
74327433 const air_tag: Air.Inst.Tag = switch (zir_tag) {
74337434 .add_with_overflow => .add_with_overflow,
74347435 .mul_with_overflow => .mul_with_overflow,
7436 .sub_with_overflow => .sub_with_overflow,
74357437 else => return sema.fail(block, src, "TODO implement runtime Sema.zirOverflowArithmetic for {}", .{zir_tag}),
74367438 };
74377439
src/arch/aarch64/CodeGen.zig+6
......@@ -522,6 +522,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
522522 .slice => try self.airSlice(inst),
523523
524524 .add_with_overflow => try self.airAddWithOverflow(inst),
525 .sub_with_overflow => try self.airSubWithOverflow(inst),
525526 .mul_with_overflow => try self.airMulWithOverflow(inst),
526527
527528 .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 {
977978 return self.fail("TODO implement airAddResultWithOverflow for {}", .{self.target.cpu.arch});
978979}
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
980986fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
981987 _ = inst;
982988 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 {
520520 .slice => try self.airSlice(inst),
521521
522522 .add_with_overflow => try self.airAddWithOverflow(inst),
523 .sub_with_overflow => try self.airSubWithOverflow(inst),
523524 .mul_with_overflow => try self.airMulWithOverflow(inst),
524525
525526 .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 {
10071008 return self.fail("TODO implement airAddResultWithOverflow for {}", .{self.target.cpu.arch});
10081009}
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
10101016fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
10111017 _ = inst;
10121018 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 {
501501 .slice => try self.airSlice(inst),
502502
503503 .add_with_overflow => try self.airAddWithOverflow(inst),
504 .sub_with_overflow => try self.airSubWithOverflow(inst),
504505 .mul_with_overflow => try self.airMulWithOverflow(inst),
505506
506507 .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 {
922923 return self.fail("TODO implement airAddResultWithOverflow for {}", .{self.target.cpu.arch});
923924}
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
925931fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
926932 _ = inst;
927933 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 {
554554 .slice => try self.airSlice(inst),
555555
556556 .add_with_overflow => try self.airAddWithOverflow(inst),
557 .sub_with_overflow => try self.airSubWithOverflow(inst),
557558 .mul_with_overflow => try self.airMulWithOverflow(inst),
558559
559560 .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 {
10361037 return self.fail("TODO implement airAddResultWithOverflow for {}", .{self.target.cpu.arch});
10371038}
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
10391045fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
10401046 _ = inst;
10411047 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
11571157 .shl_sat => try airSatOp(f, inst, "shls_"),
11581158
11591159 .add_with_overflow => try airAddWithOverflow(f, inst),
1160 .sub_with_overflow => try airSubWithOverflow(f, inst),
11601161 .mul_with_overflow => try airMulWithOverflow(f, inst),
11611162
11621163 .min => try airMinMax(f, inst, "<"),
......@@ -1874,6 +1875,12 @@ fn airAddWithOverflow(f: *Function, inst: Air.Inst.Index) !CValue {
18741875 return f.fail("TODO add with overflow", .{});
18751876}
18761877
1878fn airSubWithOverflow(f: *Function, inst: Air.Inst.Index) !CValue {
1879 _ = f;
1880 _ = inst;
1881 return f.fail("TODO sub with overflow", .{});
1882}
1883
18771884fn airMulWithOverflow(f: *Function, inst: Air.Inst.Index) !CValue {
18781885 _ = f;
18791886 _ = inst;
src/codegen/llvm.zig+1
......@@ -1719,6 +1719,7 @@ pub const FuncGen = struct {
17191719 .slice => try self.airSlice(inst),
17201720
17211721 .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"),
17221723 .mul_with_overflow => try self.airOverflow(inst, "llvm.smul.with.overflow", "llvm.umul.with.overflow"),
17231724
17241725 .bit_and, .bool_and => try self.airAnd(inst),
src/print_air.zig+1
......@@ -231,6 +231,7 @@ const Writer = struct {
231231 .memset => try w.writeMemset(s, inst),
232232
233233 .add_with_overflow,
234 .sub_with_overflow,
234235 .mul_with_overflow,
235236 => try w.writeOverflow(s, inst),
236237 }
test/behavior/math.zig+16
......@@ -495,3 +495,19 @@ test "@mulWithOverflow" {
495495 try expect(@mulWithOverflow(u8, a, b, &result));
496496 try expect(result == 236);
497497}
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;
66const minInt = std.math.minInt;
77const 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
179test "@shlWithOverflow" {
1810 var result: u16 = undefined;
1911 try expect(@shlWithOverflow(u16, 0b0010111111111111, 3, &result));