diff --git a/llvm/lib/CodeGen/MachineSink.cpp b/llvm/lib/CodeGen/MachineSink.cpp --- a/llvm/lib/CodeGen/MachineSink.cpp +++ b/llvm/lib/CodeGen/MachineSink.cpp @@ -452,9 +452,10 @@ MI.getDebugLoc()->getInlinedAt()); bool SeenBefore = SeenDbgVars.count(Var) != 0; - MachineOperand &MO = MI.getDebugOperand(0); - if (MO.isReg() && MO.getReg().isVirtual()) - SeenDbgUsers[MO.getReg()].push_back(SeenDbgUser(&MI, SeenBefore)); + for (MachineOperand &MO : MI.debug_operands()) { + if (MO.isReg() && MO.getReg().isVirtual()) + SeenDbgUsers[MO.getReg()].push_back(SeenDbgUser(&MI, SeenBefore)); + } // Record the variable for any DBG_VALUE, to avoid re-ordering any of them. SeenDbgVars.insert(Var); @@ -915,14 +916,14 @@ /// leaving an 'undef' DBG_VALUE in the original location. Don't do this if /// there's any subregister weirdness involved. Returns true if copy /// propagation occurred. -static bool attemptDebugCopyProp(MachineInstr &SinkInst, MachineInstr &DbgMI) { +static bool attemptDebugCopyProp(MachineInstr &SinkInst, MachineInstr &DbgMI, + Register Reg) { const MachineRegisterInfo &MRI = SinkInst.getMF()->getRegInfo(); const TargetInstrInfo &TII = *SinkInst.getMF()->getSubtarget().getInstrInfo(); // Copy DBG_VALUE operand and set the original to undef. We then check to // see whether this is something that can be copy-forwarded. If it isn't, // continue around the loop. - MachineOperand &DbgMO = DbgMI.getDebugOperand(0); const MachineOperand *SrcMO = nullptr, *DstMO = nullptr; auto CopyOperands = TII.isCopyInstr(SinkInst); @@ -935,29 +936,33 @@ bool PostRA = MRI.getNumVirtRegs() == 0; // Trying to forward between physical and virtual registers is too hard. - if (DbgMO.getReg().isVirtual() != SrcMO->getReg().isVirtual()) + if (Reg.isVirtual() != SrcMO->getReg().isVirtual()) return false; // Only try virtual register copy-forwarding before regalloc, and physical // register copy-forwarding after regalloc. - bool arePhysRegs = !DbgMO.getReg().isVirtual(); + bool arePhysRegs = !Reg.isVirtual(); if (arePhysRegs != PostRA) return false; // Pre-regalloc, only forward if all subregisters agree (or there are no // subregs at all). More analysis might recover some forwardable copies. - if (!PostRA && (DbgMO.getSubReg() != SrcMO->getSubReg() || - DbgMO.getSubReg() != DstMO->getSubReg())) - return false; + if (!PostRA) + for (auto DbgMO : DbgMI.getDebugOperandsForReg(Reg)) + if (DbgMO->getSubReg() != SrcMO->getSubReg() || + DbgMO->getSubReg() != DstMO->getSubReg()) + return false; // Post-regalloc, we may be sinking a DBG_VALUE of a sub or super-register // of this copy. Only forward the copy if the DBG_VALUE operand exactly // matches the copy destination. - if (PostRA && DbgMO.getReg() != DstMO->getReg()) + if (PostRA && Reg != DstMO->getReg()) return false; - DbgMO.setReg(SrcMO->getReg()); - DbgMO.setSubReg(SrcMO->getSubReg()); + for (auto DbgMO : DbgMI.getDebugOperandsForReg(Reg)) { + DbgMO->setReg(SrcMO->getReg()); + DbgMO->setSubReg(SrcMO->getSubReg()); + } return true; } @@ -991,7 +996,21 @@ MachineInstr *NewDbgMI = DbgMI->getMF()->CloneMachineInstr(*DBI); SuccToSinkTo.insert(InsertPos, NewDbgMI); - if (!attemptDebugCopyProp(MI, *DbgMI)) + unsigned SalvagedRegs = 0; + for (const MachineOperand &MO : MI.operands()) { + if (!MO.isReg()) + continue; + if (DbgMI->hasDebugOperandForReg(MO.getReg())) { + if (!attemptDebugCopyProp(MI, *DbgMI, MO.getReg())) + break; + SalvagedRegs += DbgMI->getDebugOperandsForReg(MO.getReg()).size(); + } + } + unsigned DbgRegCount = + count_if(DbgMI->debug_operands(), [](const MachineOperand &MO) { + return MO.isReg() && MO.getReg() != 0; + }); + if (SalvagedRegs < DbgRegCount) DbgMI->setDebugValueUndef(); } } @@ -1193,7 +1212,7 @@ if (User.getInt()) { // This DBG_VALUE would re-order assignments. If we can't copy-propagate // it, it can't be recovered. Set it undef. - if (!attemptDebugCopyProp(MI, *DbgMI)) + if (!attemptDebugCopyProp(MI, *DbgMI, MO.getReg())) DbgMI->setDebugValueUndef(); } else { DbgUsersToSink.push_back(DbgMI); @@ -1231,10 +1250,12 @@ // be sunk. For the rest, if they are not dominated by the block we will sink // MI into, propagate the copy source to them. SmallVector DbgDefUsers; + SmallVector DbgUseRegs; const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo(); for (auto &MO : MI.operands()) { if (!MO.isReg() || !MO.isDef() || !MO.getReg().isVirtual()) continue; + DbgUseRegs.push_back(MO.getReg()); for (auto &User : MRI.use_instructions(MO.getReg())) { if (!User.isDebugValue() || DT->dominates(TargetBlock, User.getParent())) continue; @@ -1243,8 +1264,8 @@ if (User.getParent() == MI.getParent()) continue; - assert(User.getDebugOperand(0).isReg() && - "DBG_VALUE user of vreg, but non reg operand?"); + assert(User.hasDebugOperandForReg(MO.getReg()) && + "DBG_VALUE user of vreg, but has no operand for it?"); DbgDefUsers.push_back(&User); } } @@ -1252,8 +1273,12 @@ // Point the users of this copy that are no longer dominated, at the source // of the copy. for (auto *User : DbgDefUsers) { - User->getDebugOperand(0).setReg(MI.getOperand(1).getReg()); - User->getDebugOperand(0).setSubReg(MI.getOperand(1).getSubReg()); + for (auto &Reg : DbgUseRegs) { + for (auto *DbgOp : User->getDebugOperandsForReg(Reg)) { + DbgOp->setReg(MI.getOperand(1).getReg()); + DbgOp->setSubReg(MI.getOperand(1).getSubReg()); + } + } } } @@ -1499,17 +1524,26 @@ // We must sink this DBG_VALUE if its operand is sunk. To avoid searching // for DBG_VALUEs later, record them when they're encountered. if (MI->isDebugValue()) { - auto &MO = MI->getDebugOperand(0); - if (MO.isReg() && Register::isPhysicalRegister(MO.getReg())) { - // Bail if we can already tell the sink would be rejected, rather - // than needlessly accumulating lots of DBG_VALUEs. - if (hasRegisterDependency(MI, UsedOpsInCopy, DefedRegsInCopy, - ModifiedRegUnits, UsedRegUnits)) - continue; - - // Record debug use of each reg unit. - SmallSet Units = getRegUnits(MO.getReg(), TRI); - for (MCRegister Reg : Units) + SmallSet MIUnits; + bool IsValid = true; + for (MachineOperand &MO : MI->debug_operands()) { + if (MO.isReg() && Register::isPhysicalRegister(MO.getReg())) { + // Bail if we can already tell the sink would be rejected, rather + // than needlessly accumulating lots of DBG_VALUEs. + if (hasRegisterDependency(MI, UsedOpsInCopy, DefedRegsInCopy, + ModifiedRegUnits, UsedRegUnits)) { + IsValid = false; + break; + } + + // Record debug use of each reg unit. + SmallSet RegUnits = getRegUnits(MO.getReg(), TRI); + for (MCRegister Reg : RegUnits) + MIUnits.insert(Reg); + } + } + if (IsValid) { + for (MCRegister Reg : MIUnits) SeenDbgInstrs[Reg].push_back(MI); } continue; diff --git a/llvm/lib/CodeGen/PrologEpilogInserter.cpp b/llvm/lib/CodeGen/PrologEpilogInserter.cpp --- a/llvm/lib/CodeGen/PrologEpilogInserter.cpp +++ b/llvm/lib/CodeGen/PrologEpilogInserter.cpp @@ -185,7 +185,8 @@ break; if (!MI.isDebugValue() || !MI.getDebugVariable()->isParameter()) continue; - if (MI.getDebugOperand(0).isFI()) { + if (any_of(MI.debug_operands(), + [](const MachineOperand &MO) { return MO.isFI(); })) { // We can only emit valid locations for frame indices after the frame // setup, so do not stash away them. FrameIndexValues.push_back(&MI); @@ -1203,18 +1204,16 @@ // way with simply the frame index and offset rather than any // target-specific addressing mode. if (MI.isDebugValue()) { - assert(i == 0 && "Frame indices can only appear as the first " - "operand of a DBG_VALUE machine instruction"); Register Reg; - unsigned FrameIdx = MI.getOperand(0).getIndex(); + unsigned FrameIdx = MI.getOperand(i).getIndex(); unsigned Size = MF.getFrameInfo().getObjectSize(FrameIdx); StackOffset Offset = TFI->getFrameIndexReference(MF, FrameIdx, Reg); assert(!Offset.getScalable() && "Frame offsets with a scalable component are not supported"); - MI.getOperand(0).ChangeToRegister(Reg, false /*isDef*/); - MI.getOperand(0).setIsDebug(); + MI.getOperand(i).ChangeToRegister(Reg, false /*isDef*/); + MI.getOperand(i).setIsDebug(); const DIExpression *DIExpr = MI.getDebugExpression(); @@ -1247,7 +1246,7 @@ // register, we must add Offset with `register x, plus Offset, deref`. unsigned DebugOpIndex = MI.getDebugOperandIndex(&MI.getOperand(i)); SmallVector Ops; - DIExpression::appendOffset(Ops, Offset); + DIExpression::appendOffset(Ops, Offset.getFixed()); DIExpr = DIExpression::appendOpsToArg(DIExpr, Ops, DebugOpIndex); } MI.getDebugExpressionOp().setMetadata(DIExpr); diff --git a/llvm/lib/CodeGen/RegisterCoalescer.cpp b/llvm/lib/CodeGen/RegisterCoalescer.cpp --- a/llvm/lib/CodeGen/RegisterCoalescer.cpp +++ b/llvm/lib/CodeGen/RegisterCoalescer.cpp @@ -3491,8 +3491,12 @@ // After collecting a block of DBG_VALUEs into ToInsert, enter them into the // vreg => DbgValueLoc map. auto CloseNewDVRange = [this, &ToInsert](SlotIndex Slot) { - for (auto *X : ToInsert) - DbgVRegToValues[X->getDebugOperand(0).getReg()].push_back({Slot, X}); + for (auto *X : ToInsert) { + for (auto Op : X->debug_operands()) { + if (Op.isReg() && Op.getReg().isVirtual()) + DbgVRegToValues[Op.getReg()].push_back({Slot, X}); + } + } ToInsert.clear(); }; @@ -3504,9 +3508,11 @@ SlotIndex CurrentSlot = Slots.getMBBStartIdx(&MBB); for (auto &MI : MBB) { - if (MI.isDebugValue() && MI.getDebugOperand(0).isReg() && - MI.getDebugOperand(0).getReg().isVirtual()) { - ToInsert.push_back(&MI); + if (MI.isDebugValue()) { + if (any_of(MI.debug_operands(), [](const MachineOperand &MO) { + return MO.isReg() && MO.getReg().isVirtual(); + })) + ToInsert.push_back(&MI); } else if (!MI.isDebugInstr()) { CurrentSlot = Slots.getInstructionIndex(MI); CloseNewDVRange(CurrentSlot); @@ -3603,12 +3609,14 @@ if (DbgValueSetIt->first < SegmentIt->end) { // "Other" is live and there is a DBG_VALUE of Reg: test if we should // set it undef. - if (DbgValueSetIt->first >= SegmentIt->start && - DbgValueSetIt->second->getDebugOperand(0).getReg() != 0 && - ShouldUndef(DbgValueSetIt->first)) { - // Mark undef, erase record of this DBG_VALUE to avoid revisiting. - DbgValueSetIt->second->setDebugValueUndef(); - continue; + if (DbgValueSetIt->first >= SegmentIt->start) { + bool HasReg = DbgValueSetIt->second->hasDebugOperandForReg(Reg); + bool ShouldUndefReg = ShouldUndef(DbgValueSetIt->first); + if (HasReg && ShouldUndefReg) { + // Mark undef, erase record of this DBG_VALUE to avoid revisiting. + DbgValueSetIt->second->setDebugValueUndef(); + continue; + } } ++DbgValueSetIt; } else { diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp --- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp +++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp @@ -767,11 +767,15 @@ OS << MI->getDebugVariable()->getName(); OS << " <- "; // Frame address. Currently handles register +- offset only. - assert(MI->getDebugOperand(0).isReg() && MI->isDebugOffsetImm()); + assert(MI->isIndirectDebugValue()); OS << '['; - printOperand(MI, 0, OS); - OS << '+'; - printOperand(MI, 1, OS); + for (unsigned I = 0, E = std::distance(MI->debug_operands().begin(), + MI->debug_operands().end()); + I < E; ++I) { + if (I != 0) + OS << ", "; + printOperand(MI, I, OS); + } OS << ']'; OS << "+"; printOperand(MI, NOps - 2, OS); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyDebugValueManager.h b/llvm/lib/Target/WebAssembly/WebAssemblyDebugValueManager.h --- a/llvm/lib/Target/WebAssembly/WebAssemblyDebugValueManager.h +++ b/llvm/lib/Target/WebAssembly/WebAssemblyDebugValueManager.h @@ -23,6 +23,7 @@ class WebAssemblyDebugValueManager { SmallVector DbgValues; + unsigned CurrentReg; public: WebAssemblyDebugValueManager(MachineInstr *Instr); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyDebugValueManager.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyDebugValueManager.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyDebugValueManager.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyDebugValueManager.cpp @@ -20,6 +20,8 @@ WebAssemblyDebugValueManager::WebAssemblyDebugValueManager( MachineInstr *Instr) { + if (Instr->getOperand(0).isReg()) + CurrentReg = Instr->getOperand(0).getReg(); Instr->collectDebugValues(DbgValues); } @@ -31,7 +33,9 @@ void WebAssemblyDebugValueManager::updateReg(unsigned Reg) { for (auto *DBI : DbgValues) - DBI->getDebugOperand(0).setReg(Reg); + for (auto *MO : DBI->getDebugOperandsForReg(CurrentReg)) + MO->setReg(Reg); + CurrentReg = Reg; } void WebAssemblyDebugValueManager::clone(MachineInstr *Insert, @@ -40,14 +44,15 @@ MachineFunction *MF = MBB->getParent(); for (MachineInstr *DBI : reverse(DbgValues)) { MachineInstr *Clone = MF->CloneMachineInstr(DBI); - Clone->getDebugOperand(0).setReg(NewReg); + for (auto *MO : Clone->getDebugOperandsForReg(CurrentReg)) + MO->setReg(NewReg); MBB->insert(Insert, Clone); } } void WebAssemblyDebugValueManager::replaceWithLocal(unsigned LocalId) { for (auto *DBI : DbgValues) { - MachineOperand &Op = DBI->getDebugOperand(0); - Op.ChangeToTargetIndex(llvm::WebAssembly::TI_LOCAL, LocalId); + for (auto *MO : DBI->getDebugOperandsForReg(CurrentReg)) + MO->ChangeToTargetIndex(llvm::WebAssembly::TI_LOCAL, LocalId); } }