| ... | @@ -546,8 +546,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -546,8 +546,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 546 | .trunc_float | 546 | .trunc_float |
| 547 | => try self.airUnaryMath(inst), | 547 | => try self.airUnaryMath(inst), |
| 548 | | 548 | |
| 549 | .add_with_overflow => try self.airAddWithOverflow(inst), | 549 | .add_with_overflow => try self.airOverflow(inst), |
| 550 | .sub_with_overflow => try self.airSubWithOverflow(inst), | 550 | .sub_with_overflow => try self.airOverflow(inst), |
| 551 | .mul_with_overflow => try self.airMulWithOverflow(inst), | 551 | .mul_with_overflow => try self.airMulWithOverflow(inst), |
| 552 | .shl_with_overflow => try self.airShlWithOverflow(inst), | 552 | .shl_with_overflow => try self.airShlWithOverflow(inst), |
| 553 | | 553 | |
| ... | @@ -1245,18 +1245,24 @@ fn binOpRegister( | ... | @@ -1245,18 +1245,24 @@ fn binOpRegister( |
| 1245 | }; | 1245 | }; |
| 1246 | defer self.register_manager.unfreezeRegs(&.{rhs_reg}); | 1246 | defer self.register_manager.unfreezeRegs(&.{rhs_reg}); |
| 1247 | | 1247 | |
| 1248 | const dest_reg = if (maybe_inst) |inst| blk: { | 1248 | const dest_reg = switch (mir_tag) { |
| 1249 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1249 | .cmp_shifted_register => undefined, // cmp has no destination register |
| | 1250 | else => if (maybe_inst) |inst| blk: { |
| | 1251 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1250 | | 1252 | |
| 1251 | if (lhs_is_register and self.reuseOperand(inst, bin_op.lhs, 0, lhs)) { | 1253 | if (lhs_is_register and self.reuseOperand(inst, bin_op.lhs, 0, lhs)) { |
| 1252 | break :blk lhs_reg; | 1254 | break :blk lhs_reg; |
| 1253 | } else if (rhs_is_register and self.reuseOperand(inst, bin_op.rhs, 1, rhs)) { | 1255 | } else if (rhs_is_register and self.reuseOperand(inst, bin_op.rhs, 1, rhs)) { |
| 1254 | break :blk rhs_reg; | 1256 | break :blk rhs_reg; |
| 1255 | } else { | 1257 | } else { |
| 1256 | const raw_reg = try self.register_manager.allocReg(inst); | 1258 | const raw_reg = try self.register_manager.allocReg(inst); |
| | 1259 | break :blk registerAlias(raw_reg, lhs_ty.abiSize(self.target.*)); |
| | 1260 | } |
| | 1261 | } else blk: { |
| | 1262 | const raw_reg = try self.register_manager.allocReg(null); |
| 1257 | break :blk registerAlias(raw_reg, lhs_ty.abiSize(self.target.*)); | 1263 | break :blk registerAlias(raw_reg, lhs_ty.abiSize(self.target.*)); |
| 1258 | } | 1264 | }, |
| 1259 | } else try self.register_manager.allocReg(null); | 1265 | }; |
| 1260 | | 1266 | |
| 1261 | if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs); | 1267 | if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs); |
| 1262 | if (!rhs_is_register) try self.genSetReg(rhs_ty, rhs_reg, rhs); | 1268 | if (!rhs_is_register) try self.genSetReg(rhs_ty, rhs_reg, rhs); |
| ... | @@ -1368,7 +1374,10 @@ fn binOpImmediate( | ... | @@ -1368,7 +1374,10 @@ fn binOpImmediate( |
| 1368 | const raw_reg = try self.register_manager.allocReg(inst); | 1374 | const raw_reg = try self.register_manager.allocReg(inst); |
| 1369 | break :blk registerAlias(raw_reg, lhs_ty.abiSize(self.target.*)); | 1375 | break :blk registerAlias(raw_reg, lhs_ty.abiSize(self.target.*)); |
| 1370 | } | 1376 | } |
| 1371 | } else try self.register_manager.allocReg(null), | 1377 | } else blk: { |
| | 1378 | const raw_reg = try self.register_manager.allocReg(null); |
| | 1379 | break :blk registerAlias(raw_reg, lhs_ty.abiSize(self.target.*)); |
| | 1380 | }, |
| 1372 | }; | 1381 | }; |
| 1373 | | 1382 | |
| 1374 | if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs); | 1383 | if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs); |
| ... | @@ -1711,14 +1720,68 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1711,14 +1720,68 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { |
| 1711 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1720 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1712 | } | 1721 | } |
| 1713 | | 1722 | |
| 1714 | fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | 1723 | fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1715 | _ = inst; | 1724 | const tag = self.air.instructions.items(.tag)[inst]; |
| 1716 | return self.fail("TODO implement airAddWithOverflow for {}", .{self.target.cpu.arch}); | 1725 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1717 | } | 1726 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| | 1727 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| | 1728 | const lhs = try self.resolveInst(extra.lhs); |
| | 1729 | const rhs = try self.resolveInst(extra.rhs); |
| | 1730 | const lhs_ty = self.air.typeOf(extra.lhs); |
| | 1731 | const rhs_ty = self.air.typeOf(extra.rhs); |
| | 1732 | |
| | 1733 | const tuple_ty = self.air.typeOfIndex(inst); |
| | 1734 | const tuple_size = @intCast(u32, tuple_ty.abiSize(self.target.*)); |
| | 1735 | const tuple_align = tuple_ty.abiAlignment(self.target.*); |
| | 1736 | const overflow_bit_offset = @intCast(u32, tuple_ty.structFieldOffset(1, self.target.*)); |
| | 1737 | |
| | 1738 | switch (lhs_ty.zigTypeTag()) { |
| | 1739 | .Vector => return self.fail("TODO implement add_with_overflow/sub_with_overflow for vectors", .{}), |
| | 1740 | .Int => { |
| | 1741 | const mod = self.bin_file.options.module.?; |
| | 1742 | assert(lhs_ty.eql(rhs_ty, mod)); |
| | 1743 | const int_info = lhs_ty.intInfo(self.target.*); |
| | 1744 | switch (int_info.bits) { |
| | 1745 | 1...31, 33...63 => { |
| | 1746 | const stack_offset = try self.allocMem(inst, tuple_size, tuple_align); |
| | 1747 | |
| | 1748 | try self.spillCompareFlagsIfOccupied(); |
| | 1749 | self.compare_flags_inst = null; |
| | 1750 | |
| | 1751 | const base_tag: Air.Inst.Tag = switch (tag) { |
| | 1752 | .add_with_overflow => .add, |
| | 1753 | .sub_with_overflow => .sub, |
| | 1754 | else => unreachable, |
| | 1755 | }; |
| | 1756 | const dest = try self.binOp(base_tag, null, lhs, rhs, lhs_ty, rhs_ty); |
| | 1757 | const dest_reg = dest.register; |
| | 1758 | self.register_manager.freezeRegs(&.{dest_reg}); |
| | 1759 | defer self.register_manager.unfreezeRegs(&.{dest_reg}); |
| 1718 | | 1760 | |
| 1719 | fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | 1761 | const raw_truncated_reg = try self.register_manager.allocReg(null); |
| 1720 | _ = inst; | 1762 | const truncated_reg = registerAlias(raw_truncated_reg, lhs_ty.abiSize(self.target.*)); |
| 1721 | return self.fail("TODO implement airSubWithOverflow for {}", .{self.target.cpu.arch}); | 1763 | self.register_manager.freezeRegs(&.{truncated_reg}); |
| | 1764 | defer self.register_manager.unfreezeRegs(&.{truncated_reg}); |
| | 1765 | |
| | 1766 | // sbfx/ubfx truncated, dest, #0, #bits |
| | 1767 | try self.truncRegister(dest_reg, truncated_reg, int_info.signedness, int_info.bits); |
| | 1768 | |
| | 1769 | // cmp dest, truncated |
| | 1770 | _ = try self.binOp(.cmp_eq, null, dest, .{ .register = truncated_reg }, Type.usize, Type.usize); |
| | 1771 | |
| | 1772 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg }); |
| | 1773 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .compare_flags_unsigned = .neq }); |
| | 1774 | |
| | 1775 | break :result MCValue{ .stack_offset = stack_offset }; |
| | 1776 | }, |
| | 1777 | 32, 64 => return self.fail("TODO overflow operations on integers u32/i32 and u64/i64", .{}), |
| | 1778 | else => return self.fail("TODO overflow operations on integers > u32/i32", .{}), |
| | 1779 | } |
| | 1780 | }, |
| | 1781 | else => unreachable, |
| | 1782 | } |
| | 1783 | }; |
| | 1784 | return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none }); |
| 1722 | } | 1785 | } |
| 1723 | | 1786 | |
| 1724 | fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | 1787 | fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| ... | @@ -1957,7 +2020,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1957,7 +2020,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1957 | switch (elem_size) { | 2020 | switch (elem_size) { |
| 1958 | else => { | 2021 | else => { |
| 1959 | const dest = try self.allocRegOrMem(inst, true); | 2022 | const dest = try self.allocRegOrMem(inst, true); |
| 1960 | const addr = try self.binOp(.ptr_add, null, base_mcv, index_mcv, slice_ty, Type.usize); | 2023 | const addr = try self.binOp(.ptr_add, null, base_mcv, index_mcv, slice_ptr_field_type, Type.usize); |
| 1961 | try self.load(dest, addr, slice_ptr_field_type); | 2024 | try self.load(dest, addr, slice_ptr_field_type); |
| 1962 | | 2025 | |
| 1963 | break :result dest; | 2026 | break :result dest; |
| ... | @@ -2409,9 +2472,26 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde | ... | @@ -2409,9 +2472,26 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde |
| 2409 | fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { | 2472 | fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2410 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 2473 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 2411 | const extra = self.air.extraData(Air.StructField, ty_pl.payload).data; | 2474 | const extra = self.air.extraData(Air.StructField, ty_pl.payload).data; |
| 2412 | _ = extra; | 2475 | const operand = extra.struct_operand; |
| 2413 | return self.fail("TODO implement codegen struct_field_val", .{}); | 2476 | const index = extra.field_index; |
| 2414 | //return self.finishAir(inst, result, .{ extra.struct_ptr, .none, .none }); | 2477 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| | 2478 | const mcv = try self.resolveInst(operand); |
| | 2479 | const struct_ty = self.air.typeOf(operand); |
| | 2480 | const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*)); |
| | 2481 | |
| | 2482 | switch (mcv) { |
| | 2483 | .dead, .unreach => unreachable, |
| | 2484 | .stack_offset => |off| { |
| | 2485 | break :result MCValue{ .stack_offset = off - struct_field_offset }; |
| | 2486 | }, |
| | 2487 | .memory => |addr| { |
| | 2488 | break :result MCValue{ .memory = addr + struct_field_offset }; |
| | 2489 | }, |
| | 2490 | else => return self.fail("TODO implement codegen struct_field_val for {}", .{mcv}), |
| | 2491 | } |
| | 2492 | }; |
| | 2493 | |
| | 2494 | return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none }); |
| 2415 | } | 2495 | } |
| 2416 | | 2496 | |
| 2417 | fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void { | 2497 | fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void { |