Index: lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp +++ lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp @@ -224,67 +224,10 @@ clobberRegisterUses(RegVars, I, HistMap, LiveEntries, ClobberingInstr); } -// Returns the first instruction in @MBB which corresponds to -// the function epilogue, or nullptr if @MBB doesn't contain an epilogue. -static const MachineInstr *getFirstEpilogueInst(const MachineBasicBlock &MBB) { - auto LastMI = MBB.getLastNonDebugInstr(); - if (LastMI == MBB.end() || !LastMI->isReturn()) - return nullptr; - // Assume that epilogue starts with instruction having the same debug location - // as the return instruction. - DebugLoc LastLoc = LastMI->getDebugLoc(); - auto Res = LastMI; - for (MachineBasicBlock::const_reverse_iterator I = LastMI.getReverse(), - E = MBB.rend(); - I != E; ++I) { - if (I->getDebugLoc() != LastLoc) - return &*Res; - Res = &*I; - } - // If all instructions have the same debug location, assume whole MBB is - // an epilogue. - return &*MBB.begin(); -} - -// Collect registers that are modified in the function body (their -// contents is changed outside of the prologue and epilogue). -static void collectChangingRegs(const MachineFunction *MF, - const TargetRegisterInfo *TRI, - BitVector &Regs) { - for (const auto &MBB : *MF) { - auto FirstEpilogueInst = getFirstEpilogueInst(MBB); - - for (const auto &MI : MBB) { - // Avoid looking at prologue or epilogue instructions. - if (&MI == FirstEpilogueInst) - break; - if (MI.getFlag(MachineInstr::FrameSetup)) - continue; - - // Look for register defs and register masks. Register masks are - // typically on calls and they clobber everything not in the mask. - for (const MachineOperand &MO : MI.operands()) { - // Skip virtual registers since they are handled by the parent. - if (MO.isReg() && MO.isDef() && MO.getReg() && - !TRI->isVirtualRegister(MO.getReg())) { - for (MCRegAliasIterator AI(MO.getReg(), TRI, true); AI.isValid(); - ++AI) - Regs.set(*AI); - } else if (MO.isRegMask()) { - Regs.setBitsNotInMask(MO.getRegMask()); - } - } - } - } -} - void llvm::calculateDbgEntityHistory(const MachineFunction *MF, const TargetRegisterInfo *TRI, DbgValueHistoryMap &DbgValues, DbgLabelInstrMap &DbgLabels) { - BitVector ChangingRegs(TRI->getNumRegs()); - collectChangingRegs(MF, TRI, ChangingRegs); - const TargetLowering *TLI = MF->getSubtarget().getTargetLowering(); unsigned SP = TLI->getStackPointerRegisterToSaveRestore(); unsigned FrameReg = TRI->getFrameRegister(*MF); @@ -292,43 +235,6 @@ DbgValueEntriesMap LiveEntries; for (const auto &MBB : *MF) { for (const auto &MI : MBB) { - if (!MI.isDebugInstr()) { - // Not a DBG_VALUE instruction. It may clobber registers which describe - // some variables. - for (const MachineOperand &MO : MI.operands()) { - if (MO.isReg() && MO.isDef() && MO.getReg()) { - // Ignore call instructions that claim to clobber SP. The AArch64 - // backend does this for aggregate function arguments. - if (MI.isCall() && MO.getReg() == SP) - continue; - // If this is a virtual register, only clobber it since it doesn't - // have aliases. - if (TRI->isVirtualRegister(MO.getReg())) - clobberRegisterUses(RegVars, MO.getReg(), DbgValues, LiveEntries, - MI); - // If this is a register def operand, it may end a debug value - // range. - else { - for (MCRegAliasIterator AI(MO.getReg(), TRI, true); AI.isValid(); - ++AI) - if (ChangingRegs.test(*AI)) - clobberRegisterUses(RegVars, *AI, DbgValues, LiveEntries, MI); - } - } else if (MO.isRegMask()) { - // If this is a register mask operand, clobber all debug values in - // non-CSRs. - for (unsigned I : ChangingRegs.set_bits()) { - // Don't consider SP to be clobbered by register masks. - if (unsigned(I) != SP && TRI->isPhysicalRegister(I) && - MO.clobbersPhysReg(I)) { - clobberRegisterUses(RegVars, I, DbgValues, LiveEntries, MI); - } - } - } - } - continue; - } - if (MI.isDebugValue()) { assert(MI.getNumOperands() > 1 && "Invalid DBG_VALUE instruction!"); // Use the base variable (without any DW_OP_piece expressions) @@ -351,46 +257,72 @@ InlinedEntity L(RawLabel, MI.getDebugLoc()->getInlinedAt()); DbgLabels.addInstr(L, MI); } - } + + if (MI.isDebugInstr()) + continue; + + // Not a DBG_VALUE instruction. It may clobber registers which describe + // some variables. + for (const MachineOperand &MO : MI.operands()) { + if (MO.isReg() && MO.isDef() && MO.getReg()) { + // Ignore call instructions that claim to clobber SP. The AArch64 + // backend does this for aggregate function arguments. + if (MI.isCall() && MO.getReg() == SP) + continue; + // If this is a virtual register, only clobber it since it doesn't + // have aliases. + if (TRI->isVirtualRegister(MO.getReg())) + clobberRegisterUses(RegVars, MO.getReg(), DbgValues, LiveEntries, + MI); + // If this is a register def operand, it may end a debug value + // range. Ignore defs of the frame register in the prologue. + else if (MO.getReg() != FrameReg || + !MI.getFlag(MachineInstr::FrameSetup)) { + for (MCRegAliasIterator AI(MO.getReg(), TRI, true); AI.isValid(); + ++AI) + clobberRegisterUses(RegVars, *AI, DbgValues, LiveEntries, MI); + } + } else if (MO.isRegMask()) { + // If this is a register mask operand, clobber all debug values in + // non-CSRs. + SmallVector RegsToClobber; + // Don't consider SP to be clobbered by register masks. + for (auto It : RegVars) { + unsigned int Reg = It.first; + if (Reg != SP && TRI->isPhysicalRegister(Reg) && + MO.clobbersPhysReg(Reg)) + RegsToClobber.push_back(Reg); + } + + for (unsigned Reg : RegsToClobber) { + clobberRegisterUses(RegVars, Reg, DbgValues, LiveEntries, MI); + } + } + } // End MO loop. + } // End instr loop. // Make sure locations for all variables are valid only until the end of // the basic block (unless it's the last basic block, in which case let // their liveness run off to the end of the function). if (!MBB.empty() && &MBB != &MF->back()) { // Iterate over all variables that have open debug values. - SmallSet RegsToClobber; for (auto &Pair : LiveEntries) { - // Iterate over history entries for all open fragments. - SmallVector IdxesToRemove; + if (Pair.second.empty()) + continue; + + // Create a clobbering entry. + EntryIndex ClobIdx = DbgValues.startClobber(Pair.first, MBB.back()); + + // End all entries. for (EntryIndex Idx : Pair.second) { DbgValueHistoryMap::Entry &Ent = DbgValues.getEntry(Pair.first, Idx); assert(Ent.isDbgValue() && !Ent.isClosed()); - const MachineInstr *DbgValue = Ent.getInstr(); - - // If this is a register or indirect DBG_VALUE, apply some futher - // tests to see if we should clobber it. Perform the clobbering - // later though, to keep LiveEntries iteration stable. - if (DbgValue->getOperand(0).isReg()) { - unsigned RegNo = DbgValue->getOperand(0).getReg(); - if (TRI->isVirtualRegister(RegNo) || ChangingRegs.test(RegNo) || - FrameReg == RegNo) - RegsToClobber.insert(RegNo); - } else { - // This is a constant, terminate it at end of the block. Store - // eliminated EntryIdx and delete later, for iteration stability. - EntryIndex ClobIdx = DbgValues.startClobber(Pair.first, MBB.back()); - DbgValues.getEntry(Pair.first, Idx).endEntry(ClobIdx); - IdxesToRemove.push_back(Idx); - } + Ent.endEntry(ClobIdx); } - - for (EntryIndex Idx : IdxesToRemove) - Pair.second.erase(Idx); } - // Implement clobbering of registers at the end of BB. - for (unsigned Reg : RegsToClobber) - clobberRegisterUses(RegVars, Reg, DbgValues, LiveEntries, MBB.back()); + LiveEntries.clear(); + RegVars.clear(); } } } Index: test/DebugInfo/AArch64/inlined-argument.ll =================================================================== --- test/DebugInfo/AArch64/inlined-argument.ll +++ test/DebugInfo/AArch64/inlined-argument.ll @@ -4,6 +4,15 @@ ; CHECK-NEXT: DW_AT_location (DW_OP_reg1 W1) ; CHECK-NEXT: DW_AT_abstract_origin {{.*}}"resource" ; +; XFAIL: * +; This test now fails as it requires the single-location variable recognizer +; to spot that the inlined function goes out of scope before the 'find.exit' +; exit block. Previously, unchanging variable locations could be extended to +; the end of the function, often erronously, and that's why this test used to +; pass. +; A future algorithm _should_ be able to recognize that "resource"/!37 covers +; all blocks in its lexical scope. +; ; Generated from: ; typedef struct t *t_t; ; extern unsigned int enable; Index: test/DebugInfo/AArch64/struct_by_value.ll =================================================================== --- test/DebugInfo/AArch64/struct_by_value.ll +++ test/DebugInfo/AArch64/struct_by_value.ll @@ -1,10 +1,12 @@ ; A by-value struct is a register-indirect value (breg). -; RUN: llc %s -filetype=asm -o - | FileCheck %s +; RUN: llc %s -filetype=obj -o - | llvm-dwarfdump - | FileCheck %s +; REQUIRES: object-emission -; CHECK: Lsection_info: -; CHECK: DW_AT_location -; CHECK-NEXT: .byte 112 -; 112 = 0x70 = DW_OP_breg0 +; Test that the 'f' parameter is present, with a location, and that the +; expression for the location contains a DW_OP_breg +; CHECK: DW_TAG_formal_parameter +; CHECK-NEXT: DW_AT_location +; CHECK-NEXT: DW_OP_breg ; rdar://problem/13658587 ; Index: test/DebugInfo/COFF/fpo-shrink-wrap.ll =================================================================== --- test/DebugInfo/COFF/fpo-shrink-wrap.ll +++ test/DebugInfo/COFF/fpo-shrink-wrap.ll @@ -33,7 +33,7 @@ ; ASM: popl %ebx ; ASM: [[EPILOGUE]]: # %return ; ASM: retl $8 -; ASM: Ltmp11: +; ASM: Ltmp10: ; ASM: .cv_fpo_endproc ; Note how RvaStart advances 7 bytes to skip the shrink-wrapped portion. Index: test/DebugInfo/X86/debug-loc-offset.mir =================================================================== --- test/DebugInfo/X86/debug-loc-offset.mir +++ test/DebugInfo/X86/debug-loc-offset.mir @@ -1,5 +1,11 @@ # RUN: llc -o - %s -start-after=patchable-function -filetype=obj -O0 -mtriple=i386-unknown-linux-gnu -dwarf-version=4 | llvm-dwarfdump -v - | FileCheck %s +# XFAIL: * +# Marked XFail due to the removal of "ChangingRegs" from +# DbgEntityHistoryCalculator, shortening the checked range to not reach the +# end of the function. Fixed by an about-to-land patch using the FrameDestroy +# flag to identify the end of functions. + # From the code: # # debug-loc-offset1.cc Index: test/DebugInfo/X86/pr19307.mir =================================================================== --- test/DebugInfo/X86/pr19307.mir +++ test/DebugInfo/X86/pr19307.mir @@ -1,5 +1,11 @@ # RUN: llc -o - %s -start-after=patchable-function -O0 | FileCheck %s +# XFAIL: * +# Marked XFail due to the removal of "ChangingRegs" from +# DbgEntityHistoryCalculator, shortening the checked range to not reach the +# end of the function. Fixed by an about-to-land patch using the FrameDestroy +# flag to identify the end of functions. + # Generated from the source file pr19307.cc: # #include # void parse_range(unsigned long long &offset, unsigned long long &limit, Index: test/DebugInfo/X86/reference-argument.ll =================================================================== --- test/DebugInfo/X86/reference-argument.ll +++ test/DebugInfo/X86/reference-argument.ll @@ -12,7 +12,8 @@ ; CHECK: DW_AT_name {{.*}} "this" ; CHECK-NOT: DW_TAG_subprogram ; CHECK: DW_TAG_formal_parameter -; CHECK-NEXT: DW_AT_location {{.*}}(DW_OP_breg4 RSI+0) +; CHECK-NEXT: DW_AT_location +; CHECK-NEXT: DW_OP_breg4 RSI+0 ; CHECK-NEXT: DW_AT_name {{.*}} "v" target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" Index: test/DebugInfo/X86/stack-value-piece.ll =================================================================== --- test/DebugInfo/X86/stack-value-piece.ll +++ test/DebugInfo/X86/stack-value-piece.ll @@ -26,7 +26,8 @@ ; CHECK: DW_AT_name {{.*}} "f" ; CHECK: DW_TAG_variable ; CHECK-NEXT: DW_AT_location {{.*}} ([[F:.*]] -; CHECK-NEXT: [{{.*}}, {{.*}}): DW_OP_reg17 XMM0, DW_OP_piece 0x4, DW_OP_lit0, DW_OP_stack_value, DW_OP_piece 0x4) +; CHECK-NEXT: [{{.*}}, {{.*}}): DW_OP_reg17 XMM0, DW_OP_piece 0x4, DW_OP_lit0, DW_OP_stack_value, DW_OP_piece 0x4 +; CHECK-NEXT: [{{.*}}, {{.*}}): DW_OP_piece 0x4, DW_OP_lit0, DW_OP_stack_value, DW_OP_piece 0x4) ; CHECK-NEXT: DW_AT_name {{.*}} "r" ; ; CHECK: .debug_loc contents: