stage2: @subWithOverflow

This commit is contained in:
Robin Voetter 2021-12-20 21:53:40 +01:00
parent 58d67a6718
commit 964dbeb826
12 changed files with 85 additions and 30 deletions

View File

@ -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),
}

View File

@ -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 });

View File

@ -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}),
};

View File

@ -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});

View File

@ -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});

View File

@ -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});

View File

@ -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});

View File

@ -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;

View File

@ -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),

View File

@ -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),
}

View File

@ -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);
}

View File

@ -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));