| ... | ... | @@ -1085,6 +1085,17 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 1085 | 1085 | } |
| 1086 | 1086 | } |
| 1087 | 1087 | |
| 1088 | fn getValue(self: *Self, value: MCValue, inst: ?Air.Inst.Index) void { |
| 1089 | const reg = switch (value) { |
| 1090 | .register => |reg| reg, |
| 1091 | .register_overflow => |ro| ro.reg, |
| 1092 | else => return, |
| 1093 | }; |
| 1094 | if (self.register_manager.isRegFree(reg)) { |
| 1095 | self.register_manager.getRegAssumeFree(reg, inst); |
| 1096 | } |
| 1097 | } |
| 1098 | |
| 1088 | 1099 | fn freeValue(self: *Self, value: MCValue) void { |
| 1089 | 1100 | switch (value) { |
| 1090 | 1101 | .register => |reg| { |
| ... | ... | @@ -1136,25 +1147,10 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live |
| 1136 | 1147 | log.debug("%{d} => {}", .{ inst, result }); |
| 1137 | 1148 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| 1138 | 1149 | branch.inst_table.putAssumeCapacityNoClobber(inst, result); |
| 1139 | | |
| 1140 | | // In some cases (such as bitcast), an operand |
| 1141 | | // may be the same MCValue as the result. If |
| 1142 | | // that operand died and was a register, it |
| 1143 | | // was freed by processDeath. We have to |
| 1144 | | // "re-allocate" the register. |
| 1145 | | switch (result) { |
| 1146 | | .register => |reg| { |
| 1147 | | if (self.register_manager.isRegFree(reg)) { |
| 1148 | | self.register_manager.getRegAssumeFree(reg, inst); |
| 1149 | | } |
| 1150 | | }, |
| 1151 | | .register_overflow => |ro| { |
| 1152 | | if (self.register_manager.isRegFree(ro.reg)) { |
| 1153 | | self.register_manager.getRegAssumeFree(ro.reg, inst); |
| 1154 | | } |
| 1155 | | }, |
| 1156 | | else => {}, |
| 1157 | | } |
| 1150 | // In some cases, an operand may be reused as the result. |
| 1151 | // If that operand died and was a register, it was freed by |
| 1152 | // processDeath, so we have to "re-allocate" the register. |
| 1153 | self.getValue(result, inst); |
| 1158 | 1154 | } else switch (result) { |
| 1159 | 1155 | .none, .dead, .unreach => {}, |
| 1160 | 1156 | else => unreachable, // Why didn't the result die? |
| ... | ... | @@ -5609,14 +5605,14 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void { |
| 5609 | 5605 | }); |
| 5610 | 5606 | defer self.blocks.getPtr(inst).?.relocs.deinit(self.gpa); |
| 5611 | 5607 | |
| 5608 | const ty = self.air.typeOfIndex(inst); |
| 5609 | const unused = !ty.hasRuntimeBitsIgnoreComptime() or self.liveness.isUnused(inst); |
| 5612 | 5610 | { |
| 5613 | 5611 | // Here we use `.none` to represent a null value so that the first break |
| 5614 | 5612 | // instruction will choose a MCValue for the block result and overwrite |
| 5615 | 5613 | // this field. Following break instructions will use that MCValue to put |
| 5616 | 5614 | // their block results. |
| 5617 | | const ty = self.air.typeOfIndex(inst); |
| 5618 | | const result: MCValue = |
| 5619 | | if (!ty.hasRuntimeBitsIgnoreComptime() or self.liveness.isUnused(inst)) .dead else .none; |
| 5615 | const result: MCValue = if (unused) .dead else .none; |
| 5620 | 5616 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| 5621 | 5617 | branch.inst_table.putAssumeCapacityNoClobber(inst, result); |
| 5622 | 5618 | } |
| ... | ... | @@ -5627,6 +5623,9 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void { |
| 5627 | 5623 | try self.genBody(body); |
| 5628 | 5624 | |
| 5629 | 5625 | for (self.blocks.getPtr(inst).?.relocs.items) |reloc| try self.performReloc(reloc); |
| 5626 | |
| 5627 | const result = if (unused) .dead else self.getResolvedInstValue(inst).?.*; |
| 5628 | self.getValue(result, inst); |
| 5630 | 5629 | self.finishAirBookkeeping(); |
| 5631 | 5630 | } |
| 5632 | 5631 | |
| ... | ... | @@ -5837,25 +5836,14 @@ fn br(self: *Self, inst: Air.Inst.Index, block: Air.Inst.Index, operand: Air.Ins |
| 5837 | 5836 | switch (dst_mcv.*) { |
| 5838 | 5837 | .none => { |
| 5839 | 5838 | const result = result: { |
| 5840 | | if (!self.reuseOperand(inst, operand, 0, src_mcv)) { |
| 5841 | | const new_mcv = try self.allocRegOrMem(block, true); |
| 5842 | | try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, src_mcv); |
| 5843 | | break :result new_mcv; |
| 5844 | | } |
| 5839 | if (self.reuseOperand(inst, operand, 0, src_mcv)) break :result src_mcv; |
| 5845 | 5840 | |
| 5846 | | // the value is actually tracked with block, not inst |
| 5847 | | switch (src_mcv) { |
| 5848 | | .register => |reg| if (!self.register_manager.isRegFree(reg)) { |
| 5849 | | if (RegisterManager.indexOfRegIntoTracked(reg)) |index| { |
| 5850 | | self.register_manager.registers[index] = block; |
| 5851 | | } |
| 5852 | | }, |
| 5853 | | .stack_offset => {}, |
| 5854 | | else => unreachable, |
| 5855 | | } |
| 5856 | | break :result src_mcv; |
| 5841 | const new_mcv = try self.allocRegOrMem(block, true); |
| 5842 | try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, src_mcv); |
| 5843 | break :result new_mcv; |
| 5857 | 5844 | }; |
| 5858 | 5845 | dst_mcv.* = result; |
| 5846 | self.freeValue(result); |
| 5859 | 5847 | }, |
| 5860 | 5848 | else => try self.setRegOrMem(self.air.typeOfIndex(block), dst_mcv.*, src_mcv), |
| 5861 | 5849 | } |