mirror of
https://github.com/ziglang/zig.git
synced 2026-02-21 16:54:52 +00:00
stage2: @subWithOverflow
This commit is contained in:
parent
58d67a6718
commit
964dbeb826
@ -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),
|
||||
}
|
||||
|
||||
@ -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 });
|
||||
|
||||
44
src/Sema.zig
44
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}),
|
||||
};
|
||||
|
||||
|
||||
@ -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});
|
||||
|
||||
@ -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});
|
||||
|
||||
@ -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});
|
||||
|
||||
@ -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});
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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),
|
||||
|
||||
@ -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),
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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));
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user