| author | |
| committer | |
| log | 97a53bb8a1703dfd09bee1124ae893f0764a8c8e |
| tree | 996a97b69875acef02651cab3279fb6e62c03d18 |
| parent | 16e88b75ba3e2eb13dbbf0de9194c3bf1a01026e |
| parent | 9070ad77740477f7f3806bad884b4070d476a68c |
| signature |
stage2: Change semantics of AIR arithmetic overflow instructions5 files changed, 61 insertions(+), 53 deletions(-)
src/Air.zig+16-22| ... | ... | @@ -134,28 +134,24 @@ pub const Inst = struct { |
| 134 | 134 | /// Uses the `bin_op` field. |
| 135 | 135 | min, |
| 136 | 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 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`. | |
| 141 | 140 | add_with_overflow, |
| 142 | 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 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`. | |
| 147 | 145 | sub_with_overflow, |
| 148 | 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 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`. | |
| 153 | 150 | mul_with_overflow, |
| 154 | 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 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`. | |
| 159 | 155 | shl_with_overflow, |
| 160 | 156 | /// Allocates stack local memory. |
| 161 | 157 | /// Uses the `ty` field. |
| ... | ... | @@ -964,6 +960,10 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 964 | 960 | .union_init, |
| 965 | 961 | .field_parent_ptr, |
| 966 | 962 | .cmp_vector, |
| 963 | .add_with_overflow, | |
| 964 | .sub_with_overflow, | |
| 965 | .mul_with_overflow, | |
| 966 | .shl_with_overflow, | |
| 967 | 967 | => return air.getRefType(datas[inst].ty_pl.ty), |
| 968 | 968 | |
| 969 | 969 | .not, |
| ... | ... | @@ -1074,12 +1074,6 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 1074 | 1074 | const extra = air.extraData(Air.Bin, datas[inst].pl_op.payload).data; |
| 1075 | 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 | } |
| 1085 | 1079 |
src/Liveness.zig+8-3| ... | ... | @@ -508,14 +508,19 @@ fn analyzeInst( |
| 508 | 508 | }, |
| 509 | 509 | .memset, |
| 510 | 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 | 516 | .add_with_overflow, |
| 512 | 517 | .sub_with_overflow, |
| 513 | 518 | .mul_with_overflow, |
| 514 | 519 | .shl_with_overflow, |
| 515 | 520 | => { |
| 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 }); | |
| 519 | 524 | }, |
| 520 | 525 | .br => { |
| 521 | 526 | const br = inst_datas[inst].br; |
src/Sema.zig+24-4| ... | ... | @@ -9064,6 +9064,18 @@ fn zirOverflowArithmetic( |
| 9064 | 9064 | const maybe_lhs_val = try sema.resolveMaybeUndefVal(block, lhs_src, lhs); |
| 9065 | 9065 | const maybe_rhs_val = try sema.resolveMaybeUndefVal(block, rhs_src, rhs); |
| 9066 | 9066 | |
| 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 | 9079 | const result: struct { |
| 9068 | 9080 | overflowed: enum { yes, no, undef }, |
| 9069 | 9081 | wrapped: Air.Inst.Ref, |
| ... | ... | @@ -9188,16 +9200,24 @@ fn zirOverflowArithmetic( |
| 9188 | 9200 | }; |
| 9189 | 9201 | |
| 9190 | 9202 | try sema.requireRuntimeBlock(block, src); |
| 9191 | return block.addInst(.{ | |
| 9203 | ||
| 9204 | const tuple = try block.addInst(.{ | |
| 9192 | 9205 | .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{ | |
| 9196 | 9209 | .lhs = lhs, |
| 9197 | 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 | }; |
| 9202 | 9222 | |
| 9203 | 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 | 5189 | if (self.liveness.isUnused(inst)) |
| 5190 | 5190 | return null; |
| 5191 | 5191 | |
| 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; | |
| 5194 | 5194 | |
| 5195 | const ptr = try self.resolveInst(pl_op.operand); | |
| 5196 | 5195 | const lhs = try self.resolveInst(extra.lhs); |
| 5197 | 5196 | const rhs = try self.resolveInst(extra.rhs); |
| 5198 | 5197 | |
| 5199 | const ptr_ty = self.air.typeOf(pl_op.operand); | |
| 5200 | 5198 | const lhs_ty = self.air.typeOf(extra.lhs); |
| 5201 | 5199 | |
| 5202 | 5200 | const intrinsic_name = if (lhs_ty.isSignedInt()) signed_intrinsic else unsigned_intrinsic; |
| ... | ... | @@ -5205,13 +5203,7 @@ pub const FuncGen = struct { |
| 5205 | 5203 | |
| 5206 | 5204 | const llvm_fn = self.getIntrinsic(intrinsic_name, &.{llvm_lhs_ty}); |
| 5207 | 5205 | 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; | |
| 5215 | 5207 | } |
| 5216 | 5208 | |
| 5217 | 5209 | fn airMulAdd(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { |
| ... | ... | @@ -5293,16 +5285,16 @@ pub const FuncGen = struct { |
| 5293 | 5285 | if (self.liveness.isUnused(inst)) |
| 5294 | 5286 | return null; |
| 5295 | 5287 | |
| 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; | |
| 5298 | 5290 | |
| 5299 | const ptr = try self.resolveInst(pl_op.operand); | |
| 5300 | 5291 | const lhs = try self.resolveInst(extra.lhs); |
| 5301 | 5292 | const rhs = try self.resolveInst(extra.rhs); |
| 5302 | 5293 | |
| 5303 | const ptr_ty = self.air.typeOf(pl_op.operand); | |
| 5304 | 5294 | const lhs_ty = self.air.typeOf(extra.lhs); |
| 5305 | 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); | |
| 5306 | 5298 | |
| 5307 | 5299 | const tg = self.dg.module.getTarget(); |
| 5308 | 5300 | |
| ... | ... | @@ -5319,9 +5311,8 @@ pub const FuncGen = struct { |
| 5319 | 5311 | |
| 5320 | 5312 | const overflow_bit = self.builder.buildICmp(.NE, lhs, reconstructed, ""); |
| 5321 | 5313 | |
| 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, ""); | |
| 5325 | 5316 | } |
| 5326 | 5317 | |
| 5327 | 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 | 473 | } |
| 474 | 474 | |
| 475 | 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; | |
| 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; | |
| 478 | 478 | |
| 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); | |
| 482 | 480 | try s.writeAll(", "); |
| 483 | try w.writeOperand(s, inst, 2, extra.rhs); | |
| 481 | try w.writeOperand(s, inst, 1, extra.rhs); | |
| 484 | 482 | } |
| 485 | 483 | |
| 486 | 484 | fn writeMemset(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { |