authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-03-23 02:03:43-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-03-24 17:57:58-04:00
log12c07fcf20aba9e986b5b2131515b33e3d27176a
tree1dceb6741c25a00f4742359acdaf4f5e9d4ef98a
parentdbe1b4a7e5731e4fb17d42b754faf1052aa78f32

x86_64: fix more value tracking bugs


5 files changed, 85 insertions(+), 95 deletions(-)

src/arch/x86_64/CodeGen.zig+81-89
...@@ -214,11 +214,6 @@ const StackAllocation = struct {...@@ -214,11 +214,6 @@ const StackAllocation = struct {
214214
215const BlockData = struct {215const BlockData = struct {
216 relocs: std.ArrayListUnmanaged(Mir.Inst.Index),216 relocs: std.ArrayListUnmanaged(Mir.Inst.Index),
217 /// The first break instruction encounters `null` here and chooses a
218 /// machine code value for the block result, populating this field.
219 /// Following break instructions encounter that value and use it for
220 /// the location to store their block results.
221 mcv: MCValue,
222};217};
223218
224const BigTomb = struct {219const BigTomb = struct {
...@@ -1078,16 +1073,12 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -1078,16 +1073,12 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
1078 var it = self.register_manager.free_registers.iterator(.{ .kind = .unset });1073 var it = self.register_manager.free_registers.iterator(.{ .kind = .unset });
1079 while (it.next()) |index| {1074 while (it.next()) |index| {
1080 const tracked_inst = self.register_manager.registers[index];1075 const tracked_inst = self.register_manager.registers[index];
1081 switch (air_tags[tracked_inst]) {1076 const tracked_mcv = self.getResolvedInstValue(tracked_inst).?.*;
1082 .block => {},1077 assert(RegisterManager.indexOfRegIntoTracked(switch (tracked_mcv) {
1083 else => assert(RegisterManager.indexOfRegIntoTracked(1078 .register => |reg| reg,
1084 switch (self.getResolvedInstValue(tracked_inst).?) {1079 .register_overflow => |ro| ro.reg,
1085 .register => |reg| reg,1080 else => unreachable,
1086 .register_overflow => |ro| ro.reg,1081 }).? == index);
1087 else => unreachable,
1088 },
1089 ).? == index),
1090 }
1091 }1082 }
1092 }1083 }
1093 }1084 }
...@@ -1114,7 +1105,7 @@ fn freeValue(self: *Self, value: MCValue) void {...@@ -1114,7 +1105,7 @@ fn freeValue(self: *Self, value: MCValue) void {
1114fn processDeath(self: *Self, inst: Air.Inst.Index) void {1105fn processDeath(self: *Self, inst: Air.Inst.Index) void {
1115 const air_tags = self.air.instructions.items(.tag);1106 const air_tags = self.air.instructions.items(.tag);
1116 if (air_tags[inst] == .constant) return; // Constants are immortal.1107 if (air_tags[inst] == .constant) return; // Constants are immortal.
1117 const prev_value = self.getResolvedInstValue(inst) orelse return;1108 const prev_value = (self.getResolvedInstValue(inst) orelse return).*;
1118 log.debug("%{d} => {}", .{ inst, MCValue.dead });1109 log.debug("%{d} => {}", .{ inst, MCValue.dead });
1119 // When editing this function, note that the logic must synchronize with `reuseOperand`.1110 // When editing this function, note that the logic must synchronize with `reuseOperand`.
1120 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];1111 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
...@@ -1259,45 +1250,29 @@ fn allocRegOrMemAdvanced(self: *Self, elem_ty: Type, inst: ?Air.Inst.Index, reg_...@@ -1259,45 +1250,29 @@ fn allocRegOrMemAdvanced(self: *Self, elem_ty: Type, inst: ?Air.Inst.Index, reg_
1259}1250}
12601251
1261const State = struct {1252const State = struct {
1262 next_stack_offset: u32,
1263 registers: abi.RegisterManager.TrackedRegisters,1253 registers: abi.RegisterManager.TrackedRegisters,
1264 free_registers: abi.RegisterManager.RegisterBitSet,1254 free_registers: abi.RegisterManager.RegisterBitSet,
1265 eflags_inst: ?Air.Inst.Index,1255 eflags_inst: ?Air.Inst.Index,
1266 stack: std.AutoHashMapUnmanaged(u32, StackAllocation),
1267
1268 fn deinit(state: *State, gpa: Allocator) void {
1269 state.stack.deinit(gpa);
1270 }
1271};1256};
12721257
1273fn captureState(self: *Self) !State {1258fn captureState(self: *Self) State {
1274 return State{1259 return State{
1275 .next_stack_offset = self.next_stack_offset,
1276 .registers = self.register_manager.registers,1260 .registers = self.register_manager.registers,
1277 .free_registers = self.register_manager.free_registers,1261 .free_registers = self.register_manager.free_registers,
1278 .eflags_inst = self.eflags_inst,1262 .eflags_inst = self.eflags_inst,
1279 .stack = try self.stack.clone(self.gpa),
1280 };1263 };
1281}1264}
12821265
1283fn revertState(self: *Self, state: State) !void {1266fn revertState(self: *Self, state: State) void {
1284 var stack = try state.stack.clone(self.gpa);
1285 errdefer stack.deinit(self.gpa);
1286
1287 self.register_manager.registers = state.registers;
1288 self.eflags_inst = state.eflags_inst;1267 self.eflags_inst = state.eflags_inst;
1289
1290 self.stack.deinit(self.gpa);
1291 self.stack = stack;
1292
1293 self.next_stack_offset = state.next_stack_offset;
1294 self.register_manager.free_registers = state.free_registers;1268 self.register_manager.free_registers = state.free_registers;
1269 self.register_manager.registers = state.registers;
1295}1270}
12961271
1297pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void {1272pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void {
1298 const stack_mcv = try self.allocRegOrMem(inst, false);1273 const stack_mcv = try self.allocRegOrMem(inst, false);
1299 log.debug("spilling %{d} to stack mcv {any}", .{ inst, stack_mcv });1274 log.debug("spilling %{d} to stack mcv {any}", .{ inst, stack_mcv });
1300 const reg_mcv = self.getResolvedInstValue(inst).?;1275 const reg_mcv = self.getResolvedInstValue(inst).?.*;
1301 switch (reg_mcv) {1276 switch (reg_mcv) {
1302 .register => |other| {1277 .register => |other| {
1303 assert(reg.to64() == other.to64());1278 assert(reg.to64() == other.to64());
...@@ -1314,7 +1289,7 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void...@@ -1314,7 +1289,7 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void
13141289
1315pub fn spillEflagsIfOccupied(self: *Self) !void {1290pub fn spillEflagsIfOccupied(self: *Self) !void {
1316 if (self.eflags_inst) |inst_to_save| {1291 if (self.eflags_inst) |inst_to_save| {
1317 const mcv = self.getResolvedInstValue(inst_to_save).?;1292 const mcv = self.getResolvedInstValue(inst_to_save).?.*;
1318 const new_mcv = switch (mcv) {1293 const new_mcv = switch (mcv) {
1319 .register_overflow => try self.allocRegOrMem(inst_to_save, false),1294 .register_overflow => try self.allocRegOrMem(inst_to_save, false),
1320 .eflags => try self.allocRegOrMem(inst_to_save, true),1295 .eflags => try self.allocRegOrMem(inst_to_save, true),
...@@ -2607,7 +2582,7 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -2607,7 +2582,7 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void {
2607 const index_ty = self.air.typeOf(bin_op.rhs);2582 const index_ty = self.air.typeOf(bin_op.rhs);
2608 const index = try self.resolveInst(bin_op.rhs);2583 const index = try self.resolveInst(bin_op.rhs);
2609 const index_lock: ?RegisterLock = switch (index) {2584 const index_lock: ?RegisterLock = switch (index) {
2610 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),2585 .register => |reg| self.register_manager.lockReg(reg),
2611 else => null,2586 else => null,
2612 };2587 };
2613 defer if (index_lock) |lock| self.register_manager.unlockReg(lock);2588 defer if (index_lock) |lock| self.register_manager.unlockReg(lock);
...@@ -2656,7 +2631,7 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -2656,7 +2631,7 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {
2656 const index_ty = self.air.typeOf(extra.rhs);2631 const index_ty = self.air.typeOf(extra.rhs);
2657 const index = try self.resolveInst(extra.rhs);2632 const index = try self.resolveInst(extra.rhs);
2658 const index_lock: ?RegisterLock = switch (index) {2633 const index_lock: ?RegisterLock = switch (index) {
2659 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),2634 .register => |reg| self.register_manager.lockReg(reg),
2660 else => null,2635 else => null,
2661 };2636 };
2662 defer if (index_lock) |lock| self.register_manager.unlockReg(lock);2637 defer if (index_lock) |lock| self.register_manager.unlockReg(lock);
...@@ -3202,8 +3177,8 @@ fn reuseOperand(...@@ -3202,8 +3177,8 @@ fn reuseOperand(
3202 .register => |reg| {3177 .register => |reg| {
3203 // If it's in the registers table, need to associate the register with the3178 // If it's in the registers table, need to associate the register with the
3204 // new instruction.3179 // new instruction.
3205 if (RegisterManager.indexOfRegIntoTracked(reg)) |index| {3180 if (!self.register_manager.isRegFree(reg)) {
3206 if (!self.register_manager.isRegFree(reg)) {3181 if (RegisterManager.indexOfRegIntoTracked(reg)) |index| {
3207 self.register_manager.registers[index] = inst;3182 self.register_manager.registers[index] = inst;
3208 }3183 }
3209 }3184 }
...@@ -3542,7 +3517,7 @@ fn airStore(self: *Self, inst: Air.Inst.Index) !void {...@@ -3542,7 +3517,7 @@ fn airStore(self: *Self, inst: Air.Inst.Index) !void {
3542 const value_ty = self.air.typeOf(bin_op.rhs);3517 const value_ty = self.air.typeOf(bin_op.rhs);
3543 log.debug("airStore(%{d}): {} <- {}", .{ inst, ptr, value });3518 log.debug("airStore(%{d}): {} <- {}", .{ inst, ptr, value });
3544 try self.store(ptr, value, ptr_ty, value_ty);3519 try self.store(ptr, value, ptr_ty, value_ty);
3545 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });3520 return self.finishAir(inst, .none, .{ bin_op.lhs, bin_op.rhs, .none });
3546}3521}
35473522
3548fn airStructFieldPtr(self: *Self, inst: Air.Inst.Index) !void {3523fn airStructFieldPtr(self: *Self, inst: Air.Inst.Index) !void {
...@@ -5270,8 +5245,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -5270,8 +5245,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
5270 }5245 }
52715246
5272 // Capture the state of register and stack allocation state so that we can revert to it.5247 // Capture the state of register and stack allocation state so that we can revert to it.
5273 var saved_state = try self.captureState();5248 const saved_state = self.captureState();
5274 defer saved_state.deinit(self.gpa);
52755249
5276 {5250 {
5277 try self.branch_stack.append(.{});5251 try self.branch_stack.append(.{});
...@@ -5289,7 +5263,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -5289,7 +5263,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
5289 var then_branch = self.branch_stack.pop();5263 var then_branch = self.branch_stack.pop();
5290 defer then_branch.deinit(self.gpa);5264 defer then_branch.deinit(self.gpa);
52915265
5292 try self.revertState(saved_state);5266 self.revertState(saved_state);
52935267
5294 try self.performReloc(reloc);5268 try self.performReloc(reloc);
52955269
...@@ -5632,24 +5606,28 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void {...@@ -5632,24 +5606,28 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void {
5632 try self.blocks.putNoClobber(self.gpa, inst, .{5606 try self.blocks.putNoClobber(self.gpa, inst, .{
5633 // A block is a setup to be able to jump to the end.5607 // A block is a setup to be able to jump to the end.
5634 .relocs = .{},5608 .relocs = .{},
5635 // It also acts as a receptacle for break operands.
5636 // Here we use `MCValue.none` to represent a null value so that the first
5637 // break instruction will choose a MCValue for the block result and overwrite
5638 // this field. Following break instructions will use that MCValue to put their
5639 // block results.
5640 .mcv = if (self.liveness.isUnused(inst)) .dead else .none,
5641 });5609 });
5642 defer self.blocks.getPtr(inst).?.relocs.deinit(self.gpa);5610 defer self.blocks.getPtr(inst).?.relocs.deinit(self.gpa);
56435611
5612 {
5613 // Here we use `.none` to represent a null value so that the first break
5614 // instruction will choose a MCValue for the block result and overwrite
5615 // this field. Following break instructions will use that MCValue to put
5616 // 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;
5620 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
5621 branch.inst_table.putAssumeCapacityNoClobber(inst, result);
5622 }
5623
5644 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;5624 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
5645 const extra = self.air.extraData(Air.Block, ty_pl.payload);5625 const extra = self.air.extraData(Air.Block, ty_pl.payload);
5646 const body = self.air.extra[extra.end..][0..extra.data.body_len];5626 const body = self.air.extra[extra.end..][0..extra.data.body_len];
5647 try self.genBody(body);5627 try self.genBody(body);
56485628
5649 for (self.blocks.getPtr(inst).?.relocs.items) |reloc| try self.performReloc(reloc);5629 for (self.blocks.getPtr(inst).?.relocs.items) |reloc| try self.performReloc(reloc);
56505630 self.finishAirBookkeeping();
5651 const result = self.blocks.getPtr(inst).?.mcv;
5652 return self.finishAir(inst, result, .{ .none, .none, .none });
5653}5631}
56545632
5655fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {5633fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
...@@ -5687,8 +5665,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {...@@ -5687,8 +5665,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
5687 defer if (prev_branch) |*branch| branch.deinit(self.gpa);5665 defer if (prev_branch) |*branch| branch.deinit(self.gpa);
56885666
5689 // Capture the state of register and stack allocation state so that we can revert to it.5667 // Capture the state of register and stack allocation state so that we can revert to it.
5690 var saved_state = try self.captureState();5668 const saved_state = self.captureState();
5691 defer saved_state.deinit(self.gpa);
56925669
5693 const cases_len = switch_br.data.cases_len + @boolToInt(switch_br.data.else_body_len > 0);5670 const cases_len = switch_br.data.cases_len + @boolToInt(switch_br.data.else_body_len > 0);
5694 while (case_i < switch_br.data.cases_len) : (case_i += 1) {5671 while (case_i < switch_br.data.cases_len) : (case_i += 1) {
...@@ -5698,7 +5675,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {...@@ -5698,7 +5675,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
5698 extra_index = case.end + items.len + case_body.len;5675 extra_index = case.end + items.len + case_body.len;
56995676
5700 // Revert to the previous register and stack allocation state.5677 // Revert to the previous register and stack allocation state.
5701 if (prev_branch) |_| try self.revertState(saved_state);5678 if (prev_branch) |_| self.revertState(saved_state);
57025679
5703 var relocs = try self.gpa.alloc(u32, items.len);5680 var relocs = try self.gpa.alloc(u32, items.len);
5704 defer self.gpa.free(relocs);5681 defer self.gpa.free(relocs);
...@@ -5742,7 +5719,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {...@@ -5742,7 +5719,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
5742 const else_body = self.air.extra[extra_index..][0..switch_br.data.else_body_len];5719 const else_body = self.air.extra[extra_index..][0..switch_br.data.else_body_len];
57435720
5744 // Revert to the previous register and stack allocation state.5721 // Revert to the previous register and stack allocation state.
5745 if (prev_branch) |_| try self.revertState(saved_state);5722 if (prev_branch) |_| self.revertState(saved_state);
57465723
5747 {5724 {
5748 if (cases_len > 1) try self.branch_stack.append(.{});5725 if (cases_len > 1) try self.branch_stack.append(.{});
...@@ -5801,7 +5778,7 @@ fn canonicaliseBranches(...@@ -5801,7 +5778,7 @@ fn canonicaliseBranches(
5801 if (target_value == .dead) continue;5778 if (target_value == .dead) continue;
5802 // The instruction is only overridden in the else branch.5779 // The instruction is only overridden in the else branch.
5803 // If integer overflows occurs, the question is: why wasn't the instruction marked dead?5780 // If integer overflows occurs, the question is: why wasn't the instruction marked dead?
5804 break :blk self.getResolvedInstValue(target_key).?;5781 break :blk self.getResolvedInstValue(target_key).?.*;
5805 };5782 };
5806 log.debug("consolidating target_entry {d} {}=>{}", .{ target_key, target_value, canon_mcv });5783 log.debug("consolidating target_entry {d} {}=>{}", .{ target_key, target_value, canon_mcv });
5807 // TODO make sure the destination stack offset / register does not already have something5784 // TODO make sure the destination stack offset / register does not already have something
...@@ -5816,17 +5793,18 @@ fn canonicaliseBranches(...@@ -5816,17 +5793,18 @@ fn canonicaliseBranches(
5816 // We already deleted the items from this table that matched the target_branch.5793 // We already deleted the items from this table that matched the target_branch.
5817 // So these are all instructions that are only overridden in the canon branch.5794 // So these are all instructions that are only overridden in the canon branch.
5818 const parent_mcv =5795 const parent_mcv =
5819 if (canon_value != .dead) self.getResolvedInstValue(canon_key).? else undefined;5796 if (canon_value != .dead) self.getResolvedInstValue(canon_key).?.* else undefined;
5797 if (canon_value != .dead) {
5798 log.debug("consolidating canon_entry {d} {}=>{}", .{ canon_key, parent_mcv, canon_value });
5799 // TODO make sure the destination stack offset / register does not already have something
5800 // going on there.
5801 try self.setRegOrMem(self.air.typeOfIndex(canon_key), canon_value, parent_mcv);
5802 self.freeValue(parent_mcv);
5803 // TODO track the new register / stack allocation
5804 }
5820 if (update_parent) {5805 if (update_parent) {
5821 parent_branch.inst_table.putAssumeCapacity(canon_key, canon_value);5806 parent_branch.inst_table.putAssumeCapacity(canon_key, canon_value);
5822 }5807 }
5823 if (canon_value == .dead) continue;
5824 log.debug("consolidating canon_entry {d} {}=>{}", .{ canon_key, parent_mcv, canon_value });
5825 // TODO make sure the destination stack offset / register does not already have something
5826 // going on there.
5827 try self.setRegOrMem(self.air.typeOfIndex(canon_key), canon_value, parent_mcv);
5828 self.freeValue(parent_mcv);
5829 // TODO track the new register / stack allocation
5830 }5808 }
5831}5809}
58325810
...@@ -5845,27 +5823,41 @@ fn performReloc(self: *Self, reloc: Mir.Inst.Index) !void {...@@ -5845,27 +5823,41 @@ fn performReloc(self: *Self, reloc: Mir.Inst.Index) !void {
58455823
5846fn airBr(self: *Self, inst: Air.Inst.Index) !void {5824fn airBr(self: *Self, inst: Air.Inst.Index) !void {
5847 const branch = self.air.instructions.items(.data)[inst].br;5825 const branch = self.air.instructions.items(.data)[inst].br;
5848 try self.br(branch.block_inst, branch.operand);5826 try self.br(inst, branch.block_inst, branch.operand);
5849 return self.finishAir(inst, .dead, .{ branch.operand, .none, .none });5827 return self.finishAir(inst, .dead, .{ branch.operand, .none, .none });
5850}5828}
58515829
5852fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {5830fn br(self: *Self, inst: Air.Inst.Index, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {
5853 const block_data = self.blocks.getPtr(block).?;5831 // The first break instruction encounters `.none` here and chooses a
5854 if (block_data.mcv != .dead and self.air.typeOf(operand).hasRuntimeBits()) {5832 // machine code value for the block result, populating this field.
5855 const operand_mcv = try self.resolveInst(operand);5833 // Following break instructions encounter that value and use it for
5856 if (block_data.mcv == .none) {5834 // the location to store their block results.
5857 block_data.mcv = switch (operand_mcv) {5835 if (self.getResolvedInstValue(block)) |dst_mcv| {
5858 .none, .dead, .unreach => unreachable,5836 const src_mcv = try self.resolveInst(operand);
5859 .register, .stack_offset, .memory => operand_mcv,5837 switch (dst_mcv.*) {
5860 .eflags, .immediate, .ptr_stack_offset => blk: {5838 .none => {
5861 const new_mcv = try self.allocRegOrMem(block, true);5839 const result = result: {
5862 try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv);5840 if (!self.reuseOperand(inst, operand, 0, src_mcv)) {
5863 break :blk new_mcv;5841 const new_mcv = try self.allocRegOrMem(block, true);
5864 },5842 try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, src_mcv);
5865 else => return self.fail("TODO implement block_data.mcv = operand_mcv for {}", .{operand_mcv}),5843 break :result new_mcv;
5866 };5844 }
5867 } else {5845
5868 try self.setRegOrMem(self.air.typeOfIndex(block), block_data.mcv, operand_mcv);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;
5857 };
5858 dst_mcv.* = result;
5859 },
5860 else => try self.setRegOrMem(self.air.typeOfIndex(block), dst_mcv.*, src_mcv),
5869 }5861 }
5870 }5862 }
5871 return self.brVoid(block);5863 return self.brVoid(block);
...@@ -7243,17 +7235,17 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {...@@ -7243,17 +7235,17 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
7243 return gop.value_ptr.*;7235 return gop.value_ptr.*;
7244 },7236 },
7245 .const_ty => unreachable,7237 .const_ty => unreachable,
7246 else => return self.getResolvedInstValue(inst_index).?,7238 else => return self.getResolvedInstValue(inst_index).?.*,
7247 }7239 }
7248}7240}
72497241
7250fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) ?MCValue {7242fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) ?*MCValue {
7251 // Treat each stack item as a "layer" on top of the previous one.7243 // Treat each stack item as a "layer" on top of the previous one.
7252 var i: usize = self.branch_stack.items.len;7244 var i: usize = self.branch_stack.items.len;
7253 while (true) {7245 while (true) {
7254 i -= 1;7246 i -= 1;
7255 if (self.branch_stack.items[i].inst_table.get(inst)) |mcv| {7247 if (self.branch_stack.items[i].inst_table.getPtr(inst)) |mcv| {
7256 return if (mcv != .dead) mcv else null;7248 return if (mcv.* != .dead) mcv else null;
7257 }7249 }
7258 }7250 }
7259}7251}
test/behavior/cast.zig+2-5
...@@ -38,6 +38,8 @@ fn peerTypeTAndOptionalT(c: bool, b: bool) ?usize {...@@ -38,6 +38,8 @@ fn peerTypeTAndOptionalT(c: bool, b: bool) ?usize {
38}38}
3939
40test "resolve undefined with integer" {40test "resolve undefined with integer" {
41 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
42
41 try testResolveUndefWithInt(true, 1234);43 try testResolveUndefWithInt(true, 1234);
42 comptime try testResolveUndefWithInt(true, 1234);44 comptime try testResolveUndefWithInt(true, 1234);
43}45}
...@@ -419,7 +421,6 @@ fn testCastIntToErr(err: anyerror) !void {...@@ -419,7 +421,6 @@ fn testCastIntToErr(err: anyerror) !void {
419test "peer resolve array and const slice" {421test "peer resolve array and const slice" {
420 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;422 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
421 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO423 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
422 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
423 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO424 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
424425
425 try testPeerResolveArrayConstSlice(true);426 try testPeerResolveArrayConstSlice(true);
...@@ -818,7 +819,6 @@ test "peer type resolution: error union after non-error" {...@@ -818,7 +819,6 @@ test "peer type resolution: error union after non-error" {
818test "peer cast *[0]T to E![]const T" {819test "peer cast *[0]T to E![]const T" {
819 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;820 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
820 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;821 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
821 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
822 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO822 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
823823
824 var buffer: [5]u8 = "abcde".*;824 var buffer: [5]u8 = "abcde".*;
...@@ -833,7 +833,6 @@ test "peer cast *[0]T to E![]const T" {...@@ -833,7 +833,6 @@ test "peer cast *[0]T to E![]const T" {
833test "peer cast *[0]T to []const T" {833test "peer cast *[0]T to []const T" {
834 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;834 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
835 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;835 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
836 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
837 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO836 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
838837
839 var buffer: [5]u8 = "abcde".*;838 var buffer: [5]u8 = "abcde".*;
...@@ -855,7 +854,6 @@ test "peer cast *[N]T to [*]T" {...@@ -855,7 +854,6 @@ test "peer cast *[N]T to [*]T" {
855test "peer resolution of string literals" {854test "peer resolution of string literals" {
856 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;855 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
857 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO856 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
858 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
859 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO857 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
860858
861 const S = struct {859 const S = struct {
...@@ -1360,7 +1358,6 @@ test "cast f128 to narrower types" {...@@ -1360,7 +1358,6 @@ test "cast f128 to narrower types" {
1360test "peer type resolution: unreachable, null, slice" {1358test "peer type resolution: unreachable, null, slice" {
1361 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;1359 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1362 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1360 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1363 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1364 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1361 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13651362
1366 const S = struct {1363 const S = struct {
test/behavior/enum.zig+1
...@@ -904,6 +904,7 @@ test "enum literal casting to tagged union" {...@@ -904,6 +904,7 @@ test "enum literal casting to tagged union" {
904 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;904 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
905 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;905 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
906 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO906 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
907 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
907908
908 const Arch = union(enum) {909 const Arch = union(enum) {
909 x86_64,910 x86_64,
test/behavior/if.zig+1
...@@ -115,6 +115,7 @@ test "if peer expressions inferred optional type" {...@@ -115,6 +115,7 @@ test "if peer expressions inferred optional type" {
115 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;115 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
116 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;116 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
117 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO117 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
118 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
118119
119 var self: []const u8 = "abcdef";120 var self: []const u8 = "abcdef";
120 var index: usize = 0;121 var index: usize = 0;
test/behavior/switch.zig-1
...@@ -509,7 +509,6 @@ test "return result loc and then switch with range implicit casted to error unio...@@ -509,7 +509,6 @@ test "return result loc and then switch with range implicit casted to error unio
509}509}
510510
511test "switch with null and T peer types and inferred result location type" {511test "switch with null and T peer types and inferred result location type" {
512 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
513 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO512 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
514 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO513 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
515 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO514 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO