Skip to content

Commit 97a53bb

Browse files
Merge pull request #11311 from joachimschmidt557/builtin-with-overflow
stage2: Change semantics of AIR arithmetic overflow instructions
2 parents 16e88b7 + 9070ad7 commit 97a53bb

File tree

5 files changed

+61
-53
lines changed

5 files changed

+61
-53
lines changed

src/Air.zig

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -134,28 +134,24 @@ pub const Inst = struct {
134134
/// Uses the `bin_op` field.
135135
min,
136136
/// Integer addition with overflow. Both operands are guaranteed to be the same type,
137-
/// and the result is bool. The wrapped value is written to the pointer given by the in
138-
/// operand of the `pl_op` field. Payload is `Bin` with `lhs` and `rhs` the relevant types
139-
/// of the operation.
140-
/// Uses the `pl_op` field with payload `Bin`.
137+
/// and the result is a tuple with .{res, ov}. The wrapped value is written to res
138+
/// and if an overflow happens, ov is 1. Otherwise ov is 0.
139+
/// Uses the `ty_pl` field. Payload is `Bin`.
141140
add_with_overflow,
142141
/// Integer subtraction with overflow. Both operands are guaranteed to be the same type,
143-
/// and the result is bool. The wrapped value is written to the pointer given by the in
144-
/// operand of the `pl_op` field. Payload is `Bin` with `lhs` and `rhs` the relevant types
145-
/// of the operation.
146-
/// Uses the `pl_op` field with payload `Bin`.
142+
/// and the result is a tuple with .{res, ov}. The wrapped value is written to res
143+
/// and if an overflow happens, ov is 1. Otherwise ov is 0.
144+
/// Uses the `ty_pl` field. Payload is `Bin`.
147145
sub_with_overflow,
148146
/// Integer multiplication with overflow. Both operands are guaranteed to be the same type,
149-
/// and the result is bool. The wrapped value is written to the pointer given by the in
150-
/// operand of the `pl_op` field. Payload is `Bin` with `lhs` and `rhs` the relevant types
151-
/// of the operation.
152-
/// Uses the `pl_op` field with payload `Bin`.
147+
/// and the result is a tuple with .{res, ov}. The wrapped value is written to res
148+
/// and if an overflow happens, ov is 1. Otherwise ov is 0.
149+
/// Uses the `ty_pl` field. Payload is `Bin`.
153150
mul_with_overflow,
154151
/// Integer left-shift with overflow. Both operands are guaranteed to be the same type,
155-
/// and the result is bool. The wrapped value is written to the pointer given by the in
156-
/// operand of the `pl_op` field. Payload is `Bin` with `lhs` and `rhs` the relevant types
157-
/// of the operation.
158-
/// Uses the `pl_op` field with payload `Bin`.
152+
/// and the result is a tuple with .{res, ov}. The wrapped value is written to res
153+
/// and if an overflow happens, ov is 1. Otherwise ov is 0.
154+
/// Uses the `ty_pl` field. Payload is `Bin`.
159155
shl_with_overflow,
160156
/// Allocates stack local memory.
161157
/// Uses the `ty` field.
@@ -964,6 +960,10 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
964960
.union_init,
965961
.field_parent_ptr,
966962
.cmp_vector,
963+
.add_with_overflow,
964+
.sub_with_overflow,
965+
.mul_with_overflow,
966+
.shl_with_overflow,
967967
=> return air.getRefType(datas[inst].ty_pl.ty),
968968

969969
.not,
@@ -1074,12 +1074,6 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
10741074
const extra = air.extraData(Air.Bin, datas[inst].pl_op.payload).data;
10751075
return air.typeOf(extra.lhs);
10761076
},
1077-
1078-
.add_with_overflow,
1079-
.sub_with_overflow,
1080-
.mul_with_overflow,
1081-
.shl_with_overflow,
1082-
=> return Type.bool,
10831077
}
10841078
}
10851079

src/Liveness.zig

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -508,14 +508,19 @@ fn analyzeInst(
508508
},
509509
.memset,
510510
.memcpy,
511+
=> {
512+
const pl_op = inst_datas[inst].pl_op;
513+
const extra = a.air.extraData(Air.Bin, pl_op.payload).data;
514+
return trackOperands(a, new_set, inst, main_tomb, .{ pl_op.operand, extra.lhs, extra.rhs });
515+
},
511516
.add_with_overflow,
512517
.sub_with_overflow,
513518
.mul_with_overflow,
514519
.shl_with_overflow,
515520
=> {
516-
const pl_op = inst_datas[inst].pl_op;
517-
const extra = a.air.extraData(Air.Bin, pl_op.payload).data;
518-
return trackOperands(a, new_set, inst, main_tomb, .{ pl_op.operand, extra.lhs, extra.rhs });
521+
const ty_pl = inst_datas[inst].ty_pl;
522+
const extra = a.air.extraData(Air.Bin, ty_pl.payload).data;
523+
return trackOperands(a, new_set, inst, main_tomb, .{ extra.lhs, extra.rhs, .none });
519524
},
520525
.br => {
521526
const br = inst_datas[inst].br;

src/Sema.zig

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9064,6 +9064,18 @@ fn zirOverflowArithmetic(
90649064
const maybe_lhs_val = try sema.resolveMaybeUndefVal(block, lhs_src, lhs);
90659065
const maybe_rhs_val = try sema.resolveMaybeUndefVal(block, rhs_src, rhs);
90669066

9067+
const types = try sema.arena.alloc(Type, 2);
9068+
const values = try sema.arena.alloc(Value, 2);
9069+
const tuple_ty = try Type.Tag.tuple.create(sema.arena, .{
9070+
.types = types,
9071+
.values = values,
9072+
});
9073+
9074+
types[0] = dest_ty;
9075+
types[1] = Type.initTag(.u1);
9076+
values[0] = Value.initTag(.unreachable_value);
9077+
values[1] = Value.initTag(.unreachable_value);
9078+
90679079
const result: struct {
90689080
overflowed: enum { yes, no, undef },
90699081
wrapped: Air.Inst.Ref,
@@ -9188,16 +9200,24 @@ fn zirOverflowArithmetic(
91889200
};
91899201

91909202
try sema.requireRuntimeBlock(block, src);
9191-
return block.addInst(.{
9203+
9204+
const tuple = try block.addInst(.{
91929205
.tag = air_tag,
9193-
.data = .{ .pl_op = .{
9194-
.operand = ptr,
9195-
.payload = try sema.addExtra(Air.Bin{
9206+
.data = .{ .ty_pl = .{
9207+
.ty = try block.sema.addType(tuple_ty),
9208+
.payload = try block.sema.addExtra(Air.Bin{
91969209
.lhs = lhs,
91979210
.rhs = rhs,
91989211
}),
91999212
} },
92009213
});
9214+
9215+
const wrapped = try block.addStructFieldVal(tuple, 0, dest_ty);
9216+
try sema.storePtr2(block, src, ptr, ptr_src, wrapped, src, .store);
9217+
9218+
const overflow_bit = try block.addStructFieldVal(tuple, 1, Type.initTag(.u1));
9219+
const zero_u1 = try sema.addConstant(Type.initTag(.u1), Value.zero);
9220+
return try block.addBinOp(.cmp_neq, overflow_bit, zero_u1);
92019221
};
92029222

92039223
try sema.storePtr2(block, src, ptr, ptr_src, result.wrapped, src, .store);

src/codegen/llvm.zig

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5189,14 +5189,12 @@ pub const FuncGen = struct {
51895189
if (self.liveness.isUnused(inst))
51905190
return null;
51915191

5192-
const pl_op = self.air.instructions.items(.data)[inst].pl_op;
5193-
const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
5192+
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
5193+
const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
51945194

5195-
const ptr = try self.resolveInst(pl_op.operand);
51965195
const lhs = try self.resolveInst(extra.lhs);
51975196
const rhs = try self.resolveInst(extra.rhs);
51985197

5199-
const ptr_ty = self.air.typeOf(pl_op.operand);
52005198
const lhs_ty = self.air.typeOf(extra.lhs);
52015199

52025200
const intrinsic_name = if (lhs_ty.isSignedInt()) signed_intrinsic else unsigned_intrinsic;
@@ -5205,13 +5203,7 @@ pub const FuncGen = struct {
52055203

52065204
const llvm_fn = self.getIntrinsic(intrinsic_name, &.{llvm_lhs_ty});
52075205
const result_struct = self.builder.buildCall(llvm_fn, &[_]*const llvm.Value{ lhs, rhs }, 2, .Fast, .Auto, "");
5208-
5209-
const result = self.builder.buildExtractValue(result_struct, 0, "");
5210-
const overflow_bit = self.builder.buildExtractValue(result_struct, 1, "");
5211-
5212-
self.store(ptr, ptr_ty, result, .NotAtomic);
5213-
5214-
return overflow_bit;
5206+
return result_struct;
52155207
}
52165208

52175209
fn airMulAdd(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
@@ -5293,16 +5285,16 @@ pub const FuncGen = struct {
52935285
if (self.liveness.isUnused(inst))
52945286
return null;
52955287

5296-
const pl_op = self.air.instructions.items(.data)[inst].pl_op;
5297-
const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
5288+
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
5289+
const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
52985290

5299-
const ptr = try self.resolveInst(pl_op.operand);
53005291
const lhs = try self.resolveInst(extra.lhs);
53015292
const rhs = try self.resolveInst(extra.rhs);
53025293

5303-
const ptr_ty = self.air.typeOf(pl_op.operand);
53045294
const lhs_ty = self.air.typeOf(extra.lhs);
53055295
const rhs_ty = self.air.typeOf(extra.rhs);
5296+
const dest_ty = self.air.typeOfIndex(inst);
5297+
const llvm_dest_ty = try self.dg.llvmType(dest_ty);
53065298

53075299
const tg = self.dg.module.getTarget();
53085300

@@ -5319,9 +5311,8 @@ pub const FuncGen = struct {
53195311

53205312
const overflow_bit = self.builder.buildICmp(.NE, lhs, reconstructed, "");
53215313

5322-
self.store(ptr, ptr_ty, result, .NotAtomic);
5323-
5324-
return overflow_bit;
5314+
const partial = self.builder.buildInsertValue(llvm_dest_ty.getUndef(), result, 0, "");
5315+
return self.builder.buildInsertValue(partial, overflow_bit, 1, "");
53255316
}
53265317

53275318
fn airAnd(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {

src/print_air.zig

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -473,14 +473,12 @@ const Writer = struct {
473473
}
474474

475475
fn writeOverflow(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
476-
const pl_op = w.air.instructions.items(.data)[inst].pl_op;
477-
const extra = w.air.extraData(Air.Bin, pl_op.payload).data;
476+
const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
477+
const extra = w.air.extraData(Air.Bin, ty_pl.payload).data;
478478

479-
try w.writeOperand(s, inst, 0, pl_op.operand);
480-
try s.writeAll(", ");
481-
try w.writeOperand(s, inst, 1, extra.lhs);
479+
try w.writeOperand(s, inst, 0, extra.lhs);
482480
try s.writeAll(", ");
483-
try w.writeOperand(s, inst, 2, extra.rhs);
481+
try w.writeOperand(s, inst, 1, extra.rhs);
484482
}
485483

486484
fn writeMemset(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {

0 commit comments

Comments
 (0)