authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-03-26 22:29:48+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-03-26 22:29:48+01:00
log97a53bb8a1703dfd09bee1124ae893f0764a8c8e
tree996a97b69875acef02651cab3279fb6e62c03d18
parent16e88b75ba3e2eb13dbbf0de9194c3bf1a01026e
parent9070ad77740477f7f3806bad884b4070d476a68c
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11311 from joachimschmidt557/builtin-with-overflow

stage2: Change semantics of AIR arithmetic overflow instructions

5 files changed, 61 insertions(+), 53 deletions(-)

src/Air.zig+16-22
...@@ -134,28 +134,24 @@ pub const Inst = struct {...@@ -134,28 +134,24 @@ pub const Inst = struct {
134 /// Uses the `bin_op` field.134 /// Uses the `bin_op` field.
135 min,135 min,
136 /// Integer addition with overflow. Both operands are guaranteed to be the same type,136 /// 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 in137 /// and the result is a tuple with .{res, ov}. The wrapped value is written to res
138 /// operand of the `pl_op` field. Payload is `Bin` with `lhs` and `rhs` the relevant types138 /// and if an overflow happens, ov is 1. Otherwise ov is 0.
139 /// of the operation.139 /// Uses the `ty_pl` field. Payload is `Bin`.
140 /// Uses the `pl_op` field with payload `Bin`.
141 add_with_overflow,140 add_with_overflow,
142 /// Integer subtraction with overflow. Both operands are guaranteed to be the same type,141 /// 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 in142 /// and the result is a tuple with .{res, ov}. The wrapped value is written to res
144 /// operand of the `pl_op` field. Payload is `Bin` with `lhs` and `rhs` the relevant types143 /// and if an overflow happens, ov is 1. Otherwise ov is 0.
145 /// of the operation.144 /// Uses the `ty_pl` field. Payload is `Bin`.
146 /// Uses the `pl_op` field with payload `Bin`.
147 sub_with_overflow,145 sub_with_overflow,
148 /// Integer multiplication with overflow. Both operands are guaranteed to be the same type,146 /// 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 in147 /// and the result is a tuple with .{res, ov}. The wrapped value is written to res
150 /// operand of the `pl_op` field. Payload is `Bin` with `lhs` and `rhs` the relevant types148 /// and if an overflow happens, ov is 1. Otherwise ov is 0.
151 /// of the operation.149 /// Uses the `ty_pl` field. Payload is `Bin`.
152 /// Uses the `pl_op` field with payload `Bin`.
153 mul_with_overflow,150 mul_with_overflow,
154 /// Integer left-shift with overflow. Both operands are guaranteed to be the same type,151 /// 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 in152 /// and the result is a tuple with .{res, ov}. The wrapped value is written to res
156 /// operand of the `pl_op` field. Payload is `Bin` with `lhs` and `rhs` the relevant types153 /// and if an overflow happens, ov is 1. Otherwise ov is 0.
157 /// of the operation.154 /// Uses the `ty_pl` field. Payload is `Bin`.
158 /// Uses the `pl_op` field with payload `Bin`.
159 shl_with_overflow,155 shl_with_overflow,
160 /// Allocates stack local memory.156 /// Allocates stack local memory.
161 /// Uses the `ty` field.157 /// Uses the `ty` field.
...@@ -964,6 +960,10 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -964,6 +960,10 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
964 .union_init,960 .union_init,
965 .field_parent_ptr,961 .field_parent_ptr,
966 .cmp_vector,962 .cmp_vector,
963 .add_with_overflow,
964 .sub_with_overflow,
965 .mul_with_overflow,
966 .shl_with_overflow,
967 => return air.getRefType(datas[inst].ty_pl.ty),967 => return air.getRefType(datas[inst].ty_pl.ty),
968968
969 .not,969 .not,
...@@ -1074,12 +1074,6 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -1074,12 +1074,6 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
1074 const extra = air.extraData(Air.Bin, datas[inst].pl_op.payload).data;1074 const extra = air.extraData(Air.Bin, datas[inst].pl_op.payload).data;
1075 return air.typeOf(extra.lhs);1075 return air.typeOf(extra.lhs);
1076 },1076 },
1077
1078 .add_with_overflow,
1079 .sub_with_overflow,
1080 .mul_with_overflow,
1081 .shl_with_overflow,
1082 => return Type.bool,
1083 }1077 }
1084}1078}
10851079
src/Liveness.zig+8-3
...@@ -508,14 +508,19 @@ fn analyzeInst(...@@ -508,14 +508,19 @@ fn analyzeInst(
508 },508 },
509 .memset,509 .memset,
510 .memcpy,510 .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 },
511 .add_with_overflow,516 .add_with_overflow,
512 .sub_with_overflow,517 .sub_with_overflow,
513 .mul_with_overflow,518 .mul_with_overflow,
514 .shl_with_overflow,519 .shl_with_overflow,
515 => {520 => {
516 const pl_op = inst_datas[inst].pl_op;521 const ty_pl = inst_datas[inst].ty_pl;
517 const extra = a.air.extraData(Air.Bin, pl_op.payload).data;522 const extra = a.air.extraData(Air.Bin, ty_pl.payload).data;
518 return trackOperands(a, new_set, inst, main_tomb, .{ pl_op.operand, extra.lhs, extra.rhs });523 return trackOperands(a, new_set, inst, main_tomb, .{ extra.lhs, extra.rhs, .none });
519 },524 },
520 .br => {525 .br => {
521 const br = inst_datas[inst].br;526 const br = inst_datas[inst].br;
src/Sema.zig+24-4
...@@ -9064,6 +9064,18 @@ fn zirOverflowArithmetic(...@@ -9064,6 +9064,18 @@ fn zirOverflowArithmetic(
9064 const maybe_lhs_val = try sema.resolveMaybeUndefVal(block, lhs_src, lhs);9064 const maybe_lhs_val = try sema.resolveMaybeUndefVal(block, lhs_src, lhs);
9065 const maybe_rhs_val = try sema.resolveMaybeUndefVal(block, rhs_src, rhs);9065 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
9067 const result: struct {9079 const result: struct {
9068 overflowed: enum { yes, no, undef },9080 overflowed: enum { yes, no, undef },
9069 wrapped: Air.Inst.Ref,9081 wrapped: Air.Inst.Ref,
...@@ -9188,16 +9200,24 @@ fn zirOverflowArithmetic(...@@ -9188,16 +9200,24 @@ fn zirOverflowArithmetic(
9188 };9200 };
91899201
9190 try sema.requireRuntimeBlock(block, src);9202 try sema.requireRuntimeBlock(block, src);
9191 return block.addInst(.{9203
9204 const tuple = try block.addInst(.{
9192 .tag = air_tag,9205 .tag = air_tag,
9193 .data = .{ .pl_op = .{9206 .data = .{ .ty_pl = .{
9194 .operand = ptr,9207 .ty = try block.sema.addType(tuple_ty),
9195 .payload = try sema.addExtra(Air.Bin{9208 .payload = try block.sema.addExtra(Air.Bin{
9196 .lhs = lhs,9209 .lhs = lhs,
9197 .rhs = rhs,9210 .rhs = rhs,
9198 }),9211 }),
9199 } },9212 } },
9200 });9213 });
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);
9201 };9221 };
92029222
9203 try sema.storePtr2(block, src, ptr, ptr_src, result.wrapped, src, .store);9223 try sema.storePtr2(block, src, ptr, ptr_src, result.wrapped, src, .store);
src/codegen/llvm.zig+9-18
...@@ -5189,14 +5189,12 @@ pub const FuncGen = struct {...@@ -5189,14 +5189,12 @@ pub const FuncGen = struct {
5189 if (self.liveness.isUnused(inst))5189 if (self.liveness.isUnused(inst))
5190 return null;5190 return null;
51915191
5192 const pl_op = self.air.instructions.items(.data)[inst].pl_op;5192 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
5193 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;5193 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
51945194
5195 const ptr = try self.resolveInst(pl_op.operand);
5196 const lhs = try self.resolveInst(extra.lhs);5195 const lhs = try self.resolveInst(extra.lhs);
5197 const rhs = try self.resolveInst(extra.rhs);5196 const rhs = try self.resolveInst(extra.rhs);
51985197
5199 const ptr_ty = self.air.typeOf(pl_op.operand);
5200 const lhs_ty = self.air.typeOf(extra.lhs);5198 const lhs_ty = self.air.typeOf(extra.lhs);
52015199
5202 const intrinsic_name = if (lhs_ty.isSignedInt()) signed_intrinsic else unsigned_intrinsic;5200 const intrinsic_name = if (lhs_ty.isSignedInt()) signed_intrinsic else unsigned_intrinsic;
...@@ -5205,13 +5203,7 @@ pub const FuncGen = struct {...@@ -5205,13 +5203,7 @@ pub const FuncGen = struct {
52055203
5206 const llvm_fn = self.getIntrinsic(intrinsic_name, &.{llvm_lhs_ty});5204 const llvm_fn = self.getIntrinsic(intrinsic_name, &.{llvm_lhs_ty});
5207 const result_struct = self.builder.buildCall(llvm_fn, &[_]*const llvm.Value{ lhs, rhs }, 2, .Fast, .Auto, "");5205 const result_struct = self.builder.buildCall(llvm_fn, &[_]*const llvm.Value{ lhs, rhs }, 2, .Fast, .Auto, "");
52085206 return result_struct;
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;
5215 }5207 }
52165208
5217 fn airMulAdd(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {5209 fn airMulAdd(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
...@@ -5293,16 +5285,16 @@ pub const FuncGen = struct {...@@ -5293,16 +5285,16 @@ pub const FuncGen = struct {
5293 if (self.liveness.isUnused(inst))5285 if (self.liveness.isUnused(inst))
5294 return null;5286 return null;
52955287
5296 const pl_op = self.air.instructions.items(.data)[inst].pl_op;5288 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
5297 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;5289 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
52985290
5299 const ptr = try self.resolveInst(pl_op.operand);
5300 const lhs = try self.resolveInst(extra.lhs);5291 const lhs = try self.resolveInst(extra.lhs);
5301 const rhs = try self.resolveInst(extra.rhs);5292 const rhs = try self.resolveInst(extra.rhs);
53025293
5303 const ptr_ty = self.air.typeOf(pl_op.operand);
5304 const lhs_ty = self.air.typeOf(extra.lhs);5294 const lhs_ty = self.air.typeOf(extra.lhs);
5305 const rhs_ty = self.air.typeOf(extra.rhs);5295 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
5307 const tg = self.dg.module.getTarget();5299 const tg = self.dg.module.getTarget();
53085300
...@@ -5319,9 +5311,8 @@ pub const FuncGen = struct {...@@ -5319,9 +5311,8 @@ pub const FuncGen = struct {
53195311
5320 const overflow_bit = self.builder.buildICmp(.NE, lhs, reconstructed, "");5312 const overflow_bit = self.builder.buildICmp(.NE, lhs, reconstructed, "");
53215313
5322 self.store(ptr, ptr_ty, result, .NotAtomic);5314 const partial = self.builder.buildInsertValue(llvm_dest_ty.getUndef(), result, 0, "");
53235315 return self.builder.buildInsertValue(partial, overflow_bit, 1, "");
5324 return overflow_bit;
5325 }5316 }
53265317
5327 fn airAnd(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {5318 fn airAnd(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
src/print_air.zig+4-6
...@@ -473,14 +473,12 @@ const Writer = struct {...@@ -473,14 +473,12 @@ const Writer = struct {
473 }473 }
474474
475 fn writeOverflow(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {475 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;476 const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
477 const extra = w.air.extraData(Air.Bin, pl_op.payload).data;477 const extra = w.air.extraData(Air.Bin, ty_pl.payload).data;
478478
479 try w.writeOperand(s, inst, 0, pl_op.operand);479 try w.writeOperand(s, inst, 0, extra.lhs);
480 try s.writeAll(", ");
481 try w.writeOperand(s, inst, 1, extra.lhs);
482 try s.writeAll(", ");480 try s.writeAll(", ");
483 try w.writeOperand(s, inst, 2, extra.rhs);481 try w.writeOperand(s, inst, 1, extra.rhs);
484 }482 }
485483
486 fn writeMemset(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {484 fn writeMemset(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {