| ... | ... | @@ -26596,6 +26596,9 @@ fn airLoopSwitchBr(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 26596 | 26596 | if (switch_br.operand.toIndex()) |op_inst| try self.processDeath(op_inst); |
| 26597 | 26597 | } |
| 26598 | 26598 | |
| 26599 | // Ensure a register is available for dispatch. |
| 26600 | if (!mat_cond.isRegister()) _ = try self.register_manager.allocReg(null, abi.RegisterClass.gp); |
| 26601 | |
| 26599 | 26602 | self.scope_generation += 1; |
| 26600 | 26603 | const state = try self.saveState(); |
| 26601 | 26604 | |
| ... | ... | @@ -26618,47 +26621,63 @@ fn airSwitchDispatch(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 26618 | 26621 | |
| 26619 | 26622 | const block_ty = self.typeOfIndex(br.block_inst); |
| 26620 | 26623 | const loop_data = self.loops.getPtr(br.block_inst).?; |
| 26621 | | if (self.loop_switches.getPtr(br.block_inst)) |table| { |
| 26622 | | // Process operand death so that it is properly accounted for in the State below. |
| 26623 | | const condition_dies = self.liveness.operandDies(inst, 0); |
| 26624 | | |
| 26625 | | try self.restoreState(loop_data.state, &.{}, .{ |
| 26626 | | .emit_instructions = true, |
| 26627 | | .update_tracking = false, |
| 26628 | | .resurrect = false, |
| 26629 | | .close_scope = false, |
| 26630 | | }); |
| 26624 | const block_tracking = self.inst_tracking.getPtr(br.block_inst).?; |
| 26625 | { |
| 26626 | try self.getValue(block_tracking.short, null); |
| 26627 | const src_mcv = try self.resolveInst(br.operand); |
| 26628 | |
| 26629 | if (self.reuseOperandAdvanced(inst, br.operand, 0, src_mcv, br.block_inst)) { |
| 26630 | try self.getValue(block_tracking.short, br.block_inst); |
| 26631 | // .long = .none to avoid merging operand and block result stack frames. |
| 26632 | const current_tracking: InstTracking = .{ .long = .none, .short = src_mcv }; |
| 26633 | try current_tracking.materializeUnsafe(self, br.block_inst, block_tracking.*); |
| 26634 | for (current_tracking.getRegs()) |src_reg| self.register_manager.freeReg(src_reg); |
| 26635 | } else { |
| 26636 | try self.getValue(block_tracking.short, br.block_inst); |
| 26637 | try self.genCopy(block_ty, block_tracking.short, try self.resolveInst(br.operand), .{}); |
| 26638 | } |
| 26639 | } |
| 26631 | 26640 | |
| 26641 | // Process operand death so that it is properly accounted for in the State below. |
| 26642 | if (self.liveness.operandDies(inst, 0)) { |
| 26643 | if (br.operand.toIndex()) |op_inst| try self.processDeath(op_inst); |
| 26644 | } |
| 26645 | |
| 26646 | try self.restoreState(loop_data.state, &.{}, .{ |
| 26647 | .emit_instructions = true, |
| 26648 | .update_tracking = false, |
| 26649 | .resurrect = false, |
| 26650 | .close_scope = false, |
| 26651 | }); |
| 26652 | |
| 26653 | if (self.loop_switches.getPtr(br.block_inst)) |table| { |
| 26632 | 26654 | const condition_ty = self.typeOf(br.operand); |
| 26633 | | const condition = try self.resolveInst(br.operand); |
| 26634 | | const condition_index = if (condition_dies and condition.isModifiable()) condition else condition_index: { |
| 26635 | | const condition_index = try self.allocTempRegOrMem(condition_ty, true); |
| 26636 | | try self.genCopy(condition_ty, condition_index, condition, .{}); |
| 26637 | | break :condition_index condition_index; |
| 26638 | | }; |
| 26655 | const condition_mcv = block_tracking.short; |
| 26639 | 26656 | try self.spillEflagsIfOccupied(); |
| 26640 | 26657 | if (table.min.orderAgainstZero(self.pt.zcu).compare(.neq)) try self.genBinOpMir( |
| 26641 | 26658 | .{ ._, .sub }, |
| 26642 | 26659 | condition_ty, |
| 26643 | | condition_index, |
| 26660 | condition_mcv, |
| 26644 | 26661 | .{ .air_ref = Air.internedToRef(table.min.toIntern()) }, |
| 26645 | 26662 | ); |
| 26646 | 26663 | switch (table.else_relocs) { |
| 26647 | 26664 | .@"unreachable" => {}, |
| 26648 | 26665 | .forward => |*else_relocs| { |
| 26649 | | try self.genBinOpMir(.{ ._, .cmp }, condition_ty, condition_index, .{ .immediate = table.len - 1 }); |
| 26666 | try self.genBinOpMir(.{ ._, .cmp }, condition_ty, condition_mcv, .{ .immediate = table.len - 1 }); |
| 26650 | 26667 | try else_relocs.append(self.gpa, try self.asmJccReloc(.a, undefined)); |
| 26651 | 26668 | }, |
| 26652 | 26669 | .backward => |else_reloc| { |
| 26653 | | try self.genBinOpMir(.{ ._, .cmp }, condition_ty, condition_index, .{ .immediate = table.len - 1 }); |
| 26670 | try self.genBinOpMir(.{ ._, .cmp }, condition_ty, condition_mcv, .{ .immediate = table.len - 1 }); |
| 26654 | 26671 | _ = try self.asmJccReloc(.a, else_reloc); |
| 26655 | 26672 | }, |
| 26656 | 26673 | } |
| 26657 | 26674 | { |
| 26658 | | const condition_index_reg = if (condition_index.isRegister()) |
| 26659 | | condition_index.getReg().? |
| 26660 | | else |
| 26661 | | try self.copyToTmpRegister(.usize, condition_index); |
| 26675 | const condition_index_reg = if (condition_mcv.isRegister()) condition_mcv.getReg().? else cond: { |
| 26676 | const condition_index_reg = |
| 26677 | RegisterManager.regAtTrackedIndex(@intCast(loop_data.state.free_registers.findFirstSet().?)); |
| 26678 | try self.genSetReg(condition_index_reg, condition_ty, condition_mcv, .{}); |
| 26679 | break :cond condition_index_reg; |
| 26680 | }; |
| 26662 | 26681 | const condition_index_lock = self.register_manager.lockReg(condition_index_reg); |
| 26663 | 26682 | defer if (condition_index_lock) |lock| self.register_manager.unlockReg(lock); |
| 26664 | 26683 | try self.truncateRegister(condition_ty, condition_index_reg); |
| ... | ... | @@ -26677,38 +26696,6 @@ fn airSwitchDispatch(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 26677 | 26696 | return self.finishAir(inst, .none, .{ br.operand, .none, .none }); |
| 26678 | 26697 | } |
| 26679 | 26698 | |
| 26680 | | const block_tracking = self.inst_tracking.getPtr(br.block_inst).?; |
| 26681 | | done: { |
| 26682 | | try self.getValue(block_tracking.short, null); |
| 26683 | | const src_mcv = try self.resolveInst(br.operand); |
| 26684 | | |
| 26685 | | if (self.reuseOperandAdvanced(inst, br.operand, 0, src_mcv, br.block_inst)) { |
| 26686 | | try self.getValue(block_tracking.short, br.block_inst); |
| 26687 | | // .long = .none to avoid merging operand and block result stack frames. |
| 26688 | | const current_tracking: InstTracking = .{ .long = .none, .short = src_mcv }; |
| 26689 | | try current_tracking.materializeUnsafe(self, br.block_inst, block_tracking.*); |
| 26690 | | for (current_tracking.getRegs()) |src_reg| self.register_manager.freeReg(src_reg); |
| 26691 | | break :done; |
| 26692 | | } |
| 26693 | | |
| 26694 | | try self.getValue(block_tracking.short, br.block_inst); |
| 26695 | | const dst_mcv = block_tracking.short; |
| 26696 | | try self.genCopy(block_ty, dst_mcv, try self.resolveInst(br.operand), .{}); |
| 26697 | | break :done; |
| 26698 | | } |
| 26699 | | |
| 26700 | | // Process operand death so that it is properly accounted for in the State below. |
| 26701 | | if (self.liveness.operandDies(inst, 0)) { |
| 26702 | | if (br.operand.toIndex()) |op_inst| try self.processDeath(op_inst); |
| 26703 | | } |
| 26704 | | |
| 26705 | | try self.restoreState(loop_data.state, &.{}, .{ |
| 26706 | | .emit_instructions = true, |
| 26707 | | .update_tracking = false, |
| 26708 | | .resurrect = false, |
| 26709 | | .close_scope = false, |
| 26710 | | }); |
| 26711 | | |
| 26712 | 26699 | // Emit a jump with a relocation. It will be patched up after the block ends. |
| 26713 | 26700 | // Leave the jump offset undefined |
| 26714 | 26701 | _ = try self.asmJmpReloc(loop_data.target); |