Commit 964dbeb826
Changed files (12)
src
arch
test
behavior
src/arch/aarch64/CodeGen.zig
@@ -522,6 +522,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.slice => try self.airSlice(inst),
.add_with_overflow => try self.airAddWithOverflow(inst),
+ .sub_with_overflow => try self.airSubWithOverflow(inst),
.mul_with_overflow => try self.airMulWithOverflow(inst),
.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 {
return self.fail("TODO implement airAddResultWithOverflow for {}", .{self.target.cpu.arch});
}
+fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
+ _ = inst;
+ return self.fail("TODO implement airSubResultWithOverflow for {}", .{self.target.cpu.arch});
+}
+
fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
_ = inst;
return self.fail("TODO implement airMulResultWithOverflow for {}", .{self.target.cpu.arch});
src/arch/arm/CodeGen.zig
@@ -520,6 +520,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.slice => try self.airSlice(inst),
.add_with_overflow => try self.airAddWithOverflow(inst),
+ .sub_with_overflow => try self.airSubWithOverflow(inst),
.mul_with_overflow => try self.airMulWithOverflow(inst),
.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 {
return self.fail("TODO implement airAddResultWithOverflow for {}", .{self.target.cpu.arch});
}
+fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
+ _ = inst;
+ return self.fail("TODO implement airSubResultWithOverflow for {}", .{self.target.cpu.arch});
+}
+
fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
_ = inst;
return self.fail("TODO implement airMulResultWithOverflow for {}", .{self.target.cpu.arch});
src/arch/riscv64/CodeGen.zig
@@ -501,6 +501,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.slice => try self.airSlice(inst),
.add_with_overflow => try self.airAddWithOverflow(inst),
+ .sub_with_overflow => try self.airSubWithOverflow(inst),
.mul_with_overflow => try self.airMulWithOverflow(inst),
.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 {
return self.fail("TODO implement airAddResultWithOverflow for {}", .{self.target.cpu.arch});
}
+fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
+ _ = inst;
+ return self.fail("TODO implement airSubResultWithOverflow for {}", .{self.target.cpu.arch});
+}
+
fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
_ = inst;
return self.fail("TODO implement airMulResultWithOverflow for {}", .{self.target.cpu.arch});
src/arch/x86_64/CodeGen.zig
@@ -554,6 +554,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.slice => try self.airSlice(inst),
.add_with_overflow => try self.airAddWithOverflow(inst),
+ .sub_with_overflow => try self.airSubWithOverflow(inst),
.mul_with_overflow => try self.airMulWithOverflow(inst),
.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 {
return self.fail("TODO implement airAddResultWithOverflow for {}", .{self.target.cpu.arch});
}
+fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
+ _ = inst;
+ return self.fail("TODO implement airSubResultWithOverflow for {}", .{self.target.cpu.arch});
+}
+
fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
_ = inst;
return self.fail("TODO implement airMulResultWithOverflow for {}", .{self.target.cpu.arch});
src/codegen/c.zig
@@ -1157,6 +1157,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
.shl_sat => try airSatOp(f, inst, "shls_"),
.add_with_overflow => try airAddWithOverflow(f, inst),
+ .sub_with_overflow => try airSubWithOverflow(f, inst),
.mul_with_overflow => try airMulWithOverflow(f, inst),
.min => try airMinMax(f, inst, "<"),
@@ -1874,6 +1875,12 @@ fn airAddWithOverflow(f: *Function, inst: Air.Inst.Index) !CValue {
return f.fail("TODO add with overflow", .{});
}
+fn airSubWithOverflow(f: *Function, inst: Air.Inst.Index) !CValue {
+ _ = f;
+ _ = inst;
+ return f.fail("TODO sub with overflow", .{});
+}
+
fn airMulWithOverflow(f: *Function, inst: Air.Inst.Index) !CValue {
_ = f;
_ = inst;
src/codegen/llvm.zig
@@ -1719,6 +1719,7 @@ pub const FuncGen = struct {
.slice => try self.airSlice(inst),
.add_with_overflow => try self.airOverflow(inst, "llvm.sadd.with.overflow", "llvm.uadd.with.overflow"),
+ .sub_with_overflow => try self.airOverflow(inst, "llvm.ssub.with.overflow", "llvm.usub.with.overflow"),
.mul_with_overflow => try self.airOverflow(inst, "llvm.smul.with.overflow", "llvm.umul.with.overflow"),
.bit_and, .bool_and => try self.airAnd(inst),
src/Air.zig
@@ -141,6 +141,12 @@ pub const Inst = struct {
/// of the operation.
/// Uses the `pl_op` field with payload `Bin`.
add_with_overflow,
+ /// Integer subtraction with overflow. Both operands are guaranteed to be the same type,
+ /// and the result is bool. The wrapped value is written to the pointer given by the in
+ /// operand of the `pl_op` field. Payload is `Bin` with `lhs` and `rhs` the relevant types
+ /// of the operation.
+ /// Uses the `pl_op` field with payload `Bin`.
+ sub_with_overflow,
/// Integer multiplication with overflow. Both operands are guaranteed to be the same type,
/// and the result is bool. The wrapped value is written to the pointer given by the in
/// 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 {
},
.add_with_overflow,
+ .sub_with_overflow,
.mul_with_overflow,
=> return Type.initTag(.bool),
}
src/Liveness.zig
@@ -382,7 +382,12 @@ fn analyzeInst(
const extra = a.air.extraData(Air.AtomicRmw, pl_op.payload).data;
return trackOperands(a, new_set, inst, main_tomb, .{ pl_op.operand, extra.operand, .none });
},
- .memset, .memcpy, .add_with_overflow, .mul_with_overflow => {
+ .memset,
+ .memcpy,
+ .add_with_overflow,
+ .sub_with_overflow,
+ .mul_with_overflow,
+ => {
const pl_op = inst_datas[inst].pl_op;
const extra = a.air.extraData(Air.Bin, pl_op.payload).data;
return trackOperands(a, new_set, inst, main_tomb, .{ pl_op.operand, extra.lhs, extra.rhs });
src/print_air.zig
@@ -231,6 +231,7 @@ const Writer = struct {
.memset => try w.writeMemset(s, inst),
.add_with_overflow,
+ .sub_with_overflow,
.mul_with_overflow,
=> try w.writeOverflow(s, inst),
}
src/Sema.zig
@@ -7365,16 +7365,27 @@ fn zirOverflowArithmetic(
}
const result = try lhs_val.intAddWithOverflow(rhs_val, dest_ty, sema.arena, target);
- const inst = try sema.addConstant(
- dest_ty,
- result.wrapped_result,
- );
-
- if (result.overflowed) {
- break :result .{ .overflowed = .yes, .wrapped = inst };
- } else {
- break :result .{ .overflowed = .no, .wrapped = inst };
+ const inst = try sema.addConstant(dest_ty, result.wrapped_result);
+ break :result .{ .overflowed = if (result.overflowed) .yes else .no, .wrapped = inst };
+ }
+ }
+ },
+ .sub_with_overflow => {
+ // If the rhs is zero, then the result is lhs and no overflow occured.
+ // Otherwise, if either result is undefined, both results are undefined.
+ if (maybe_rhs_val) |rhs_val| {
+ if (rhs_val.isUndef()) {
+ break :result .{ .overflowed = .undef, .wrapped = try sema.addConstUndef(dest_ty) };
+ } else if (rhs_val.compareWithZero(.eq)) {
+ break :result .{ .overflowed = .no, .wrapped = lhs };
+ } else if (maybe_lhs_val) |lhs_val| {
+ if (lhs_val.isUndef()) {
+ break :result .{ .overflowed = .undef, .wrapped = try sema.addConstUndef(dest_ty) };
}
+
+ const result = try lhs_val.intSubWithOverflow(rhs_val, dest_ty, sema.arena, target);
+ const inst = try sema.addConstant(dest_ty, result.wrapped_result);
+ break :result .{ .overflowed = if (result.overflowed) .yes else .no, .wrapped = inst };
}
}
},
@@ -7382,7 +7393,6 @@ fn zirOverflowArithmetic(
// If either of the arguments is zero, the result is zero and no overflow occured.
// If either of the arguments is one, the result is the other and no overflow occured.
// Otherwise, if either of the arguments is undefined, both results are undefined.
-
if (maybe_lhs_val) |lhs_val| {
if (!lhs_val.isUndef()) {
if (lhs_val.compareWithZero(.eq)) {
@@ -7410,20 +7420,11 @@ fn zirOverflowArithmetic(
}
const result = try lhs_val.intMulWithOverflow(rhs_val, dest_ty, sema.arena, target);
- const inst = try sema.addConstant(
- dest_ty,
- result.wrapped_result,
- );
-
- if (result.overflowed) {
- break :result .{ .overflowed = .yes, .wrapped = inst };
- } else {
- break :result .{ .overflowed = .no, .wrapped = inst };
- }
+ const inst = try sema.addConstant(dest_ty, result.wrapped_result);
+ break :result .{ .overflowed = if (result.overflowed) .yes else .no, .wrapped = inst };
}
}
},
- .sub_with_overflow,
.shl_with_overflow,
=> return sema.fail(block, src, "TODO implement Sema.zirOverflowArithmetic for {}", .{zir_tag}),
else => unreachable,
@@ -7432,6 +7433,7 @@ fn zirOverflowArithmetic(
const air_tag: Air.Inst.Tag = switch (zir_tag) {
.add_with_overflow => .add_with_overflow,
.mul_with_overflow => .mul_with_overflow,
+ .sub_with_overflow => .sub_with_overflow,
else => return sema.fail(block, src, "TODO implement runtime Sema.zirOverflowArithmetic for {}", .{zir_tag}),
};
test/behavior/math.zig
@@ -495,3 +495,19 @@ test "@mulWithOverflow" {
try expect(@mulWithOverflow(u8, a, b, &result));
try expect(result == 236);
}
+
+test "@subWithOverflow" {
+ var result: u8 = undefined;
+ try expect(@subWithOverflow(u8, 1, 2, &result));
+ try expect(result == 255);
+ try expect(!@subWithOverflow(u8, 1, 1, &result));
+ try expect(result == 0);
+
+ var a: u8 = 1;
+ var b: u8 = 2;
+ try expect(@subWithOverflow(u8, a, b, &result));
+ try expect(result == 255);
+ b = 1;
+ try expect(!@subWithOverflow(u8, a, b, &result));
+ try expect(result == 0);
+}
test/behavior/math_stage1.zig
@@ -6,14 +6,6 @@ const maxInt = std.math.maxInt;
const minInt = std.math.minInt;
const mem = std.mem;
-test "@subWithOverflow" {
- var result: u8 = undefined;
- try expect(@subWithOverflow(u8, 1, 2, &result));
- try expect(result == 255);
- try expect(!@subWithOverflow(u8, 1, 1, &result));
- try expect(result == 0);
-}
-
test "@shlWithOverflow" {
var result: u16 = undefined;
try expect(@shlWithOverflow(u16, 0b0010111111111111, 3, &result));