Index: llvm/trunk/include/llvm/IR/InstVisitor.h =================================================================== --- llvm/trunk/include/llvm/IR/InstVisitor.h +++ llvm/trunk/include/llvm/IR/InstVisitor.h @@ -213,7 +213,7 @@ // Handle the special instrinsic instruction classes. RetTy visitDbgDeclareInst(DbgDeclareInst &I) { DELEGATE(DbgInfoIntrinsic);} RetTy visitDbgValueInst(DbgValueInst &I) { DELEGATE(DbgInfoIntrinsic);} - RetTy visitDbgLabelInst(DbgLabelInst &I) { DELEGATE(DbgInfoIntrinsic);} + RetTy visitDbgLabelInst(DbgLabelInst &I) { DELEGATE(IntrinsicInst);} RetTy visitDbgInfoIntrinsic(DbgInfoIntrinsic &I) { DELEGATE(IntrinsicInst); } RetTy visitMemSetInst(MemSetInst &I) { DELEGATE(MemIntrinsic); } RetTy visitMemCpyInst(MemCpyInst &I) { DELEGATE(MemTransferInst); } Index: llvm/trunk/include/llvm/IR/IntrinsicInst.h =================================================================== --- llvm/trunk/include/llvm/IR/IntrinsicInst.h +++ llvm/trunk/include/llvm/IR/IntrinsicInst.h @@ -104,7 +104,6 @@ case Intrinsic::dbg_declare: case Intrinsic::dbg_value: case Intrinsic::dbg_addr: - case Intrinsic::dbg_label: return true; default: return false; } @@ -165,7 +164,7 @@ }; /// This represents the llvm.dbg.label instruction. - class DbgLabelInst : public DbgInfoIntrinsic { + class DbgLabelInst : public IntrinsicInst { public: DILabel *getLabel() const { return cast(getRawVariable()); Index: llvm/trunk/lib/CodeGen/AsmPrinter/CMakeLists.txt =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/CMakeLists.txt +++ llvm/trunk/lib/CodeGen/AsmPrinter/CMakeLists.txt @@ -5,7 +5,7 @@ AsmPrinter.cpp AsmPrinterDwarf.cpp AsmPrinterInlineAsm.cpp - DbgValueHistoryCalculator.cpp + DbgEntityHistoryCalculator.cpp DebugHandlerBase.cpp DebugLocStream.cpp DIE.cpp Index: llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.h =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.h +++ llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.h @@ -14,7 +14,7 @@ #ifndef LLVM_LIB_CODEGEN_ASMPRINTER_CODEVIEWDEBUG_H #define LLVM_LIB_CODEGEN_ASMPRINTER_CODEVIEWDEBUG_H -#include "DbgValueHistoryCalculator.h" +#include "DbgEntityHistoryCalculator.h" #include "DebugHandlerBase.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" Index: llvm/trunk/lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.h =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.h +++ llvm/trunk/lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.h @@ -0,0 +1,88 @@ +//===- llvm/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.h -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_CODEGEN_ASMPRINTER_DBGVALUEHISTORYCALCULATOR_H +#define LLVM_LIB_CODEGEN_ASMPRINTER_DBGVALUEHISTORYCALCULATOR_H + +#include "llvm/ADT/MapVector.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/IR/DebugInfoMetadata.h" +#include + +namespace llvm { + +class DILocalVariable; +class MachineFunction; +class MachineInstr; +class TargetRegisterInfo; + +// For each user variable, keep a list of instruction ranges where this variable +// is accessible. The variables are listed in order of appearance. +class DbgValueHistoryMap { + // Each instruction range starts with a DBG_VALUE instruction, specifying the + // location of a variable, which is assumed to be valid until the end of the + // range. If end is not specified, location is valid until the start + // instruction of the next instruction range, or until the end of the + // function. +public: + using InstrRange = std::pair; + using InstrRanges = SmallVector; + using InlinedVariable = + std::pair; + using InstrRangesMap = MapVector; + +private: + InstrRangesMap VarInstrRanges; + +public: + void startInstrRange(InlinedVariable Var, const MachineInstr &MI); + void endInstrRange(InlinedVariable Var, const MachineInstr &MI); + + // Returns register currently describing @Var. If @Var is currently + // unaccessible or is not described by a register, returns 0. + unsigned getRegisterForVar(InlinedVariable Var) const; + + bool empty() const { return VarInstrRanges.empty(); } + void clear() { VarInstrRanges.clear(); } + InstrRangesMap::const_iterator begin() const { return VarInstrRanges.begin(); } + InstrRangesMap::const_iterator end() const { return VarInstrRanges.end(); } + +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) + LLVM_DUMP_METHOD void dump() const; +#endif +}; + +/// For each inlined instance of a source-level label, keep the corresponding +/// DBG_LABEL instruction. The DBG_LABEL instruction could be used to generate +/// a temporary (assembler) label before it. +class DbgLabelInstrMap { +public: + using InlinedLabel = std::pair; + using InstrMap = MapVector; + +private: + InstrMap LabelInstr; + +public: + void addInstr(InlinedLabel Label, const MachineInstr &MI); + + bool empty() const { return LabelInstr.empty(); } + void clear() { LabelInstr.clear(); } + InstrMap::const_iterator begin() const { return LabelInstr.begin(); } + InstrMap::const_iterator end() const { return LabelInstr.end(); } +}; + +void calculateDbgEntityHistory(const MachineFunction *MF, + const TargetRegisterInfo *TRI, + DbgValueHistoryMap &DbgValues, + DbgLabelInstrMap &DbgLabels); + +} // end namespace llvm + +#endif // LLVM_LIB_CODEGEN_ASMPRINTER_DBGVALUEHISTORYCALCULATOR_H Index: llvm/trunk/lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp +++ llvm/trunk/lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp @@ -0,0 +1,316 @@ +//===- llvm/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DbgEntityHistoryCalculator.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineOperand.h" +#include "llvm/CodeGen/TargetLowering.h" +#include "llvm/CodeGen/TargetRegisterInfo.h" +#include "llvm/CodeGen/TargetSubtargetInfo.h" +#include "llvm/IR/DebugInfoMetadata.h" +#include "llvm/IR/DebugLoc.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +#include +#include +#include + +using namespace llvm; + +#define DEBUG_TYPE "dwarfdebug" + +// If @MI is a DBG_VALUE with debug value described by a +// defined register, returns the number of this register. +// In the other case, returns 0. +static unsigned isDescribedByReg(const MachineInstr &MI) { + assert(MI.isDebugValue()); + assert(MI.getNumOperands() == 4); + // If location of variable is described using a register (directly or + // indirectly), this register is always a first operand. + return MI.getOperand(0).isReg() ? MI.getOperand(0).getReg() : 0; +} + +void DbgValueHistoryMap::startInstrRange(InlinedVariable Var, + const MachineInstr &MI) { + // Instruction range should start with a DBG_VALUE instruction for the + // variable. + assert(MI.isDebugValue() && "not a DBG_VALUE"); + auto &Ranges = VarInstrRanges[Var]; + if (!Ranges.empty() && Ranges.back().second == nullptr && + Ranges.back().first->isIdenticalTo(MI)) { + LLVM_DEBUG(dbgs() << "Coalescing identical DBG_VALUE entries:\n" + << "\t" << Ranges.back().first << "\t" << MI << "\n"); + return; + } + Ranges.push_back(std::make_pair(&MI, nullptr)); +} + +void DbgValueHistoryMap::endInstrRange(InlinedVariable Var, + const MachineInstr &MI) { + auto &Ranges = VarInstrRanges[Var]; + // Verify that the current instruction range is not yet closed. + assert(!Ranges.empty() && Ranges.back().second == nullptr); + // For now, instruction ranges are not allowed to cross basic block + // boundaries. + assert(Ranges.back().first->getParent() == MI.getParent()); + Ranges.back().second = &MI; +} + +unsigned DbgValueHistoryMap::getRegisterForVar(InlinedVariable Var) const { + const auto &I = VarInstrRanges.find(Var); + if (I == VarInstrRanges.end()) + return 0; + const auto &Ranges = I->second; + if (Ranges.empty() || Ranges.back().second != nullptr) + return 0; + return isDescribedByReg(*Ranges.back().first); +} + +void DbgLabelInstrMap::addInstr(InlinedLabel Label, const MachineInstr &MI) { + assert(MI.isDebugLabel() && "not a DBG_LABEL"); + LabelInstr[Label] = &MI; +} + +namespace { + +// Maps physreg numbers to the variables they describe. +using InlinedVariable = DbgValueHistoryMap::InlinedVariable; +using RegDescribedVarsMap = std::map>; +using InlinedLabel = DbgLabelInstrMap::InlinedLabel; + +} // end anonymous namespace + +// Claim that @Var is not described by @RegNo anymore. +static void dropRegDescribedVar(RegDescribedVarsMap &RegVars, unsigned RegNo, + InlinedVariable Var) { + const auto &I = RegVars.find(RegNo); + assert(RegNo != 0U && I != RegVars.end()); + auto &VarSet = I->second; + const auto &VarPos = llvm::find(VarSet, Var); + assert(VarPos != VarSet.end()); + VarSet.erase(VarPos); + // Don't keep empty sets in a map to keep it as small as possible. + if (VarSet.empty()) + RegVars.erase(I); +} + +// Claim that @Var is now described by @RegNo. +static void addRegDescribedVar(RegDescribedVarsMap &RegVars, unsigned RegNo, + InlinedVariable Var) { + assert(RegNo != 0U); + auto &VarSet = RegVars[RegNo]; + assert(!is_contained(VarSet, Var)); + VarSet.push_back(Var); +} + +// Terminate the location range for variables described by register at +// @I by inserting @ClobberingInstr to their history. +static void clobberRegisterUses(RegDescribedVarsMap &RegVars, + RegDescribedVarsMap::iterator I, + DbgValueHistoryMap &HistMap, + const MachineInstr &ClobberingInstr) { + // Iterate over all variables described by this register and add this + // instruction to their history, clobbering it. + for (const auto &Var : I->second) + HistMap.endInstrRange(Var, ClobberingInstr); + RegVars.erase(I); +} + +// Terminate the location range for variables described by register +// @RegNo by inserting @ClobberingInstr to their history. +static void clobberRegisterUses(RegDescribedVarsMap &RegVars, unsigned RegNo, + DbgValueHistoryMap &HistMap, + const MachineInstr &ClobberingInstr) { + const auto &I = RegVars.find(RegNo); + if (I == RegVars.end()) + return; + clobberRegisterUses(RegVars, I, HistMap, 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(); + RegDescribedVarsMap RegVars; + 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, 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, 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, MI); + } + } + } + } + continue; + } + + if (MI.isDebugValue()) { + assert(MI.getNumOperands() > 1 && "Invalid DBG_VALUE instruction!"); + // Use the base variable (without any DW_OP_piece expressions) + // as index into History. The full variables including the + // piece expressions are attached to the MI. + const DILocalVariable *RawVar = MI.getDebugVariable(); + assert(RawVar->isValidLocationForIntrinsic(MI.getDebugLoc()) && + "Expected inlined-at fields to agree"); + InlinedVariable Var(RawVar, MI.getDebugLoc()->getInlinedAt()); + + if (unsigned PrevReg = DbgValues.getRegisterForVar(Var)) + dropRegDescribedVar(RegVars, PrevReg, Var); + + DbgValues.startInstrRange(Var, MI); + + if (unsigned NewReg = isDescribedByReg(MI)) + addRegDescribedVar(RegVars, NewReg, Var); + } else if (MI.isDebugLabel()) { + assert(MI.getNumOperands() == 1 && "Invalid DBG_LABEL instruction!"); + const DILabel *RawLabel = MI.getDebugLabel(); + assert(RawLabel->isValidLocationForIntrinsic(MI.getDebugLoc()) && + "Expected inlined-at fields to agree"); + // When collecting debug information for labels, there is no MCSymbol + // generated for it. So, we keep MachineInstr in DbgLabels in order + // to query MCSymbol afterward. + InlinedLabel L(RawLabel, MI.getDebugLoc()->getInlinedAt()); + DbgLabels.addInstr(L, MI); + } + } + + // Make sure locations for register-described 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()) { + for (auto I = RegVars.begin(), E = RegVars.end(); I != E;) { + auto CurElem = I++; // CurElem can be erased below. + if (TRI->isVirtualRegister(CurElem->first) || + ChangingRegs.test(CurElem->first)) + clobberRegisterUses(RegVars, CurElem, DbgValues, MBB.back()); + } + } + } +} + +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) +LLVM_DUMP_METHOD void DbgValueHistoryMap::dump() const { + dbgs() << "DbgValueHistoryMap:\n"; + for (const auto &VarRangePair : *this) { + const InlinedVariable &Var = VarRangePair.first; + const InstrRanges &Ranges = VarRangePair.second; + + const DILocalVariable *LocalVar = Var.first; + const DILocation *Location = Var.second; + + dbgs() << " - " << LocalVar->getName() << " at "; + + if (Location) + dbgs() << Location->getFilename() << ":" << Location->getLine() << ":" + << Location->getColumn(); + else + dbgs() << ""; + + dbgs() << " --\n"; + + for (const InstrRange &Range : Ranges) { + dbgs() << " Begin: " << *Range.first; + if (Range.second) + dbgs() << " End : " << *Range.second; + dbgs() << "\n"; + } + } +} +#endif Index: llvm/trunk/lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.h =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.h +++ llvm/trunk/lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.h @@ -1,67 +0,0 @@ -//===- llvm/CodeGen/AsmPrinter/DbgValueHistoryCalculator.h ------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_LIB_CODEGEN_ASMPRINTER_DBGVALUEHISTORYCALCULATOR_H -#define LLVM_LIB_CODEGEN_ASMPRINTER_DBGVALUEHISTORYCALCULATOR_H - -#include "llvm/ADT/MapVector.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/IR/DebugInfoMetadata.h" -#include - -namespace llvm { - -class DILocalVariable; -class MachineFunction; -class MachineInstr; -class TargetRegisterInfo; - -// For each user variable, keep a list of instruction ranges where this variable -// is accessible. The variables are listed in order of appearance. -class DbgValueHistoryMap { - // Each instruction range starts with a DBG_VALUE instruction, specifying the - // location of a variable, which is assumed to be valid until the end of the - // range. If end is not specified, location is valid until the start - // instruction of the next instruction range, or until the end of the - // function. -public: - using InstrRange = std::pair; - using InstrRanges = SmallVector; - using InlinedVariable = - std::pair; - using InstrRangesMap = MapVector; - -private: - InstrRangesMap VarInstrRanges; - -public: - void startInstrRange(InlinedVariable Var, const MachineInstr &MI); - void endInstrRange(InlinedVariable Var, const MachineInstr &MI); - - // Returns register currently describing @Var. If @Var is currently - // unaccessible or is not described by a register, returns 0. - unsigned getRegisterForVar(InlinedVariable Var) const; - - bool empty() const { return VarInstrRanges.empty(); } - void clear() { VarInstrRanges.clear(); } - InstrRangesMap::const_iterator begin() const { return VarInstrRanges.begin(); } - InstrRangesMap::const_iterator end() const { return VarInstrRanges.end(); } - -#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) - LLVM_DUMP_METHOD void dump() const; -#endif -}; - -void calculateDbgValueHistory(const MachineFunction *MF, - const TargetRegisterInfo *TRI, - DbgValueHistoryMap &Result); - -} // end namespace llvm - -#endif // LLVM_LIB_CODEGEN_ASMPRINTER_DBGVALUEHISTORYCALCULATOR_H Index: llvm/trunk/lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.cpp =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.cpp +++ llvm/trunk/lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.cpp @@ -1,301 +0,0 @@ -//===- llvm/CodeGen/AsmPrinter/DbgValueHistoryCalculator.cpp --------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "DbgValueHistoryCalculator.h" -#include "llvm/ADT/BitVector.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/CodeGen/MachineBasicBlock.h" -#include "llvm/CodeGen/MachineFunction.h" -#include "llvm/CodeGen/MachineInstr.h" -#include "llvm/CodeGen/MachineOperand.h" -#include "llvm/CodeGen/TargetLowering.h" -#include "llvm/CodeGen/TargetRegisterInfo.h" -#include "llvm/CodeGen/TargetSubtargetInfo.h" -#include "llvm/IR/DebugInfoMetadata.h" -#include "llvm/IR/DebugLoc.h" -#include "llvm/MC/MCRegisterInfo.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/raw_ostream.h" -#include -#include -#include - -using namespace llvm; - -#define DEBUG_TYPE "dwarfdebug" - -// If @MI is a DBG_VALUE with debug value described by a -// defined register, returns the number of this register. -// In the other case, returns 0. -static unsigned isDescribedByReg(const MachineInstr &MI) { - assert(MI.isDebugValue()); - assert(MI.getNumOperands() == 4); - // If location of variable is described using a register (directly or - // indirectly), this register is always a first operand. - return MI.getOperand(0).isReg() ? MI.getOperand(0).getReg() : 0; -} - -void DbgValueHistoryMap::startInstrRange(InlinedVariable Var, - const MachineInstr &MI) { - // Instruction range should start with a DBG_VALUE instruction for the - // variable. - assert(MI.isDebugValue() && "not a DBG_VALUE"); - auto &Ranges = VarInstrRanges[Var]; - if (!Ranges.empty() && Ranges.back().second == nullptr && - Ranges.back().first->isIdenticalTo(MI)) { - LLVM_DEBUG(dbgs() << "Coalescing identical DBG_VALUE entries:\n" - << "\t" << Ranges.back().first << "\t" << MI << "\n"); - return; - } - Ranges.push_back(std::make_pair(&MI, nullptr)); -} - -void DbgValueHistoryMap::endInstrRange(InlinedVariable Var, - const MachineInstr &MI) { - auto &Ranges = VarInstrRanges[Var]; - // Verify that the current instruction range is not yet closed. - assert(!Ranges.empty() && Ranges.back().second == nullptr); - // For now, instruction ranges are not allowed to cross basic block - // boundaries. - assert(Ranges.back().first->getParent() == MI.getParent()); - Ranges.back().second = &MI; -} - -unsigned DbgValueHistoryMap::getRegisterForVar(InlinedVariable Var) const { - const auto &I = VarInstrRanges.find(Var); - if (I == VarInstrRanges.end()) - return 0; - const auto &Ranges = I->second; - if (Ranges.empty() || Ranges.back().second != nullptr) - return 0; - return isDescribedByReg(*Ranges.back().first); -} - -namespace { - -// Maps physreg numbers to the variables they describe. -using InlinedVariable = DbgValueHistoryMap::InlinedVariable; -using RegDescribedVarsMap = std::map>; - -} // end anonymous namespace - -// Claim that @Var is not described by @RegNo anymore. -static void dropRegDescribedVar(RegDescribedVarsMap &RegVars, unsigned RegNo, - InlinedVariable Var) { - const auto &I = RegVars.find(RegNo); - assert(RegNo != 0U && I != RegVars.end()); - auto &VarSet = I->second; - const auto &VarPos = llvm::find(VarSet, Var); - assert(VarPos != VarSet.end()); - VarSet.erase(VarPos); - // Don't keep empty sets in a map to keep it as small as possible. - if (VarSet.empty()) - RegVars.erase(I); -} - -// Claim that @Var is now described by @RegNo. -static void addRegDescribedVar(RegDescribedVarsMap &RegVars, unsigned RegNo, - InlinedVariable Var) { - assert(RegNo != 0U); - auto &VarSet = RegVars[RegNo]; - assert(!is_contained(VarSet, Var)); - VarSet.push_back(Var); -} - -// Terminate the location range for variables described by register at -// @I by inserting @ClobberingInstr to their history. -static void clobberRegisterUses(RegDescribedVarsMap &RegVars, - RegDescribedVarsMap::iterator I, - DbgValueHistoryMap &HistMap, - const MachineInstr &ClobberingInstr) { - // Iterate over all variables described by this register and add this - // instruction to their history, clobbering it. - for (const auto &Var : I->second) - HistMap.endInstrRange(Var, ClobberingInstr); - RegVars.erase(I); -} - -// Terminate the location range for variables described by register -// @RegNo by inserting @ClobberingInstr to their history. -static void clobberRegisterUses(RegDescribedVarsMap &RegVars, unsigned RegNo, - DbgValueHistoryMap &HistMap, - const MachineInstr &ClobberingInstr) { - const auto &I = RegVars.find(RegNo); - if (I == RegVars.end()) - return; - clobberRegisterUses(RegVars, I, HistMap, 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::calculateDbgValueHistory(const MachineFunction *MF, - const TargetRegisterInfo *TRI, - DbgValueHistoryMap &Result) { - BitVector ChangingRegs(TRI->getNumRegs()); - collectChangingRegs(MF, TRI, ChangingRegs); - - const TargetLowering *TLI = MF->getSubtarget().getTargetLowering(); - unsigned SP = TLI->getStackPointerRegisterToSaveRestore(); - RegDescribedVarsMap RegVars; - 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(), Result, 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, Result, 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, Result, MI); - } - } - } - } - continue; - } - - // Skip DBG_LABEL instructions. - if (MI.isDebugLabel()) - continue; - - assert(MI.getNumOperands() > 1 && "Invalid DBG_VALUE instruction!"); - // Use the base variable (without any DW_OP_piece expressions) - // as index into History. The full variables including the - // piece expressions are attached to the MI. - const DILocalVariable *RawVar = MI.getDebugVariable(); - assert(RawVar->isValidLocationForIntrinsic(MI.getDebugLoc()) && - "Expected inlined-at fields to agree"); - InlinedVariable Var(RawVar, MI.getDebugLoc()->getInlinedAt()); - - if (unsigned PrevReg = Result.getRegisterForVar(Var)) - dropRegDescribedVar(RegVars, PrevReg, Var); - - Result.startInstrRange(Var, MI); - - if (unsigned NewReg = isDescribedByReg(MI)) - addRegDescribedVar(RegVars, NewReg, Var); - } - - // Make sure locations for register-described 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()) { - for (auto I = RegVars.begin(), E = RegVars.end(); I != E;) { - auto CurElem = I++; // CurElem can be erased below. - if (TRI->isVirtualRegister(CurElem->first) || - ChangingRegs.test(CurElem->first)) - clobberRegisterUses(RegVars, CurElem, Result, MBB.back()); - } - } - } -} - -#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) -LLVM_DUMP_METHOD void DbgValueHistoryMap::dump() const { - dbgs() << "DbgValueHistoryMap:\n"; - for (const auto &VarRangePair : *this) { - const InlinedVariable &Var = VarRangePair.first; - const InstrRanges &Ranges = VarRangePair.second; - - const DILocalVariable *LocalVar = Var.first; - const DILocation *Location = Var.second; - - dbgs() << " - " << LocalVar->getName() << " at "; - - if (Location) - dbgs() << Location->getFilename() << ":" << Location->getLine() << ":" - << Location->getColumn(); - else - dbgs() << ""; - - dbgs() << " --\n"; - - for (const InstrRange &Range : Ranges) { - dbgs() << " Begin: " << *Range.first; - if (Range.second) - dbgs() << " End : " << *Range.second; - dbgs() << "\n"; - } - } -} -#endif Index: llvm/trunk/lib/CodeGen/AsmPrinter/DebugHandlerBase.h =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/DebugHandlerBase.h +++ llvm/trunk/lib/CodeGen/AsmPrinter/DebugHandlerBase.h @@ -16,7 +16,7 @@ #define LLVM_LIB_CODEGEN_ASMPRINTER_DEBUGHANDLERBASE_H #include "AsmPrinterHandler.h" -#include "DbgValueHistoryCalculator.h" +#include "DbgEntityHistoryCalculator.h" #include "llvm/ADT/Optional.h" #include "llvm/CodeGen/LexicalScopes.h" #include "llvm/CodeGen/MachineInstr.h" @@ -82,6 +82,9 @@ /// variable. Variables are listed in order of appearance. DbgValueHistoryMap DbgValues; + /// Mapping of inlined labels and DBG_LABEL machine instruction. + DbgLabelInstrMap DbgLabels; + /// Maps instruction with label emitted before instruction. /// FIXME: Make this private from DwarfDebug, we have the necessary accessors /// for it. Index: llvm/trunk/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp +++ llvm/trunk/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp @@ -190,8 +190,9 @@ // Calculate history for local variables. assert(DbgValues.empty() && "DbgValues map wasn't cleaned!"); - calculateDbgValueHistory(MF, Asm->MF->getSubtarget().getRegisterInfo(), - DbgValues); + assert(DbgLabels.empty() && "DbgLabels map wasn't cleaned!"); + calculateDbgEntityHistory(MF, Asm->MF->getSubtarget().getRegisterInfo(), + DbgValues, DbgLabels); LLVM_DEBUG(DbgValues.dump()); // Request labels for the full history. @@ -229,6 +230,12 @@ } } + // Ensure there is a symbol before DBG_LABEL. + for (const auto &I : DbgLabels) { + const MachineInstr *MI = I.second; + requestLabelBeforeInsn(MI); + } + PrevInstLoc = DebugLoc(); PrevLabel = Asm->getFunctionBegin(); beginFunctionImpl(MF); @@ -296,6 +303,7 @@ if (hasDebugInfo(MMI, MF)) endFunctionImpl(MF); DbgValues.clear(); + DbgLabels.clear(); LabelsBeforeInsn.clear(); LabelsAfterInsn.clear(); } Index: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h +++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h @@ -14,7 +14,7 @@ #ifndef LLVM_LIB_CODEGEN_ASMPRINTER_DWARFCOMPILEUNIT_H #define LLVM_LIB_CODEGEN_ASMPRINTER_DWARFCOMPILEUNIT_H -#include "DbgValueHistoryCalculator.h" +#include "DbgEntityHistoryCalculator.h" #include "DwarfDebug.h" #include "DwarfUnit.h" #include "llvm/ADT/ArrayRef.h" @@ -81,7 +81,7 @@ const MCSymbol *BaseAddress = nullptr; DenseMap AbstractSPDies; - DenseMap> AbstractVariables; + DenseMap> AbstractEntities; /// DWO ID for correlating skeleton and split units. uint64_t DWOId = 0; @@ -98,10 +98,10 @@ return DU->getAbstractSPDies(); } - DenseMap> &getAbstractVariables() { + DenseMap> &getAbstractEntities() { if (isDwoUnit() && !DD->shareAcrossDWOCUs()) - return AbstractVariables; - return DU->getAbstractVariables(); + return AbstractEntities; + return DU->getAbstractEntities(); } public: @@ -194,6 +194,9 @@ DIE *constructVariableDIE(DbgVariable &DV, const LexicalScope &Scope, DIE *&ObjectPointer); + /// Construct a DIE for the given DbgLabel. + DIE *constructLabelDIE(DbgLabel &DL, const LexicalScope &Scope); + /// A helper function to create children of a Scope DIE. DIE *createScopeChildrenDIE(LexicalScope *Scope, SmallVectorImpl &Children, @@ -210,14 +213,12 @@ DIE *constructImportedEntityDIE(const DIImportedEntity *Module); void finishSubprogramDefinition(const DISubprogram *SP); - void finishVariableDefinition(const DbgVariable &Var); + void finishEntityDefinition(const DbgEntity *Entity); /// Find abstract variable associated with Var. using InlinedVariable = DbgValueHistoryMap::InlinedVariable; - DbgVariable *getExistingAbstractVariable(InlinedVariable IV, - const DILocalVariable *&Cleansed); - DbgVariable *getExistingAbstractVariable(InlinedVariable IV); - void createAbstractVariable(const DILocalVariable *Var, LexicalScope *Scope); + DbgEntity *getExistingAbstractEntity(const DINode *Node); + void createAbstractEntity(const DINode *Node, LexicalScope *Scope); /// Set the skeleton unit associated with this unit. void setSkeleton(DwarfCompileUnit &Skel) { Skeleton = &Skel; } @@ -288,6 +289,8 @@ void applySubprogramAttributesToDefinition(const DISubprogram *SP, DIE &SPDie); + void applyLabelAttributes(const DbgLabel &Label, DIE &LabelDie); + /// getRangeLists - Get the vector of range lists. const SmallVectorImpl &getRangeLists() const { return (Skeleton ? Skeleton : this)->CURangeLists; Index: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -502,6 +502,18 @@ return D; } +DIE *DwarfCompileUnit::constructLabelDIE(DbgLabel &DL, + const LexicalScope &Scope) { + auto LabelDie = DIE::get(DIEValueAllocator, DL.getTag()); + insertDIE(DL.getLabel(), LabelDie); + DL.setDIE(*LabelDie); + + if (Scope.isAbstractScope()) + applyLabelAttributes(DL, *LabelDie); + + return LabelDie; +} + DIE *DwarfCompileUnit::constructVariableDIEImpl(const DbgVariable &DV, bool Abstract) { // Define variable debug information entry. @@ -692,6 +704,9 @@ if (HasNonScopeChildren) *HasNonScopeChildren = !Children.empty(); + for (DbgLabel *DL : DU->getScopeLabels().lookup(Scope)) + Children.push_back(constructLabelDIE(*DL, *Scope)); + for (LexicalScope *LS : Scope->getChildren()) constructScopeDIE(LS, Children); @@ -817,40 +832,52 @@ } } -void DwarfCompileUnit::finishVariableDefinition(const DbgVariable &Var) { - DbgVariable *AbsVar = getExistingAbstractVariable( - InlinedVariable(Var.getVariable(), Var.getInlinedAt())); - auto *VariableDie = Var.getDIE(); - if (AbsVar && AbsVar->getDIE()) { - addDIEEntry(*VariableDie, dwarf::DW_AT_abstract_origin, - *AbsVar->getDIE()); - } else - applyVariableAttributes(Var, *VariableDie); +void DwarfCompileUnit::finishEntityDefinition(const DbgEntity *Entity) { + DbgEntity *AbsEntity = getExistingAbstractEntity(Entity->getEntity()); + + auto *Die = Entity->getDIE(); + /// Label may be used to generate DW_AT_low_pc, so put it outside + /// if/else block. + const DbgLabel *Label = nullptr; + if (AbsEntity && AbsEntity->getDIE()) { + addDIEEntry(*Die, dwarf::DW_AT_abstract_origin, *AbsEntity->getDIE()); + Label = dyn_cast(Entity); + } else { + if (const DbgVariable *Var = dyn_cast(Entity)) + applyVariableAttributes(*Var, *Die); + else if ((Label = dyn_cast(Entity))) + applyLabelAttributes(*Label, *Die); + else + llvm_unreachable("DbgEntity must be DbgVariable or DbgLabel."); + } + + if (Label) { + const MCSymbol *Sym = Label->getSymbol(); + addLabelAddress(*Die, dwarf::DW_AT_low_pc, Sym); + } } -DbgVariable *DwarfCompileUnit::getExistingAbstractVariable(InlinedVariable IV) { - const DILocalVariable *Cleansed; - return getExistingAbstractVariable(IV, Cleansed); -} - -// Find abstract variable, if any, associated with Var. -DbgVariable *DwarfCompileUnit::getExistingAbstractVariable( - InlinedVariable IV, const DILocalVariable *&Cleansed) { - // More then one inlined variable corresponds to one abstract variable. - Cleansed = IV.first; - auto &AbstractVariables = getAbstractVariables(); - auto I = AbstractVariables.find(Cleansed); - if (I != AbstractVariables.end()) +DbgEntity *DwarfCompileUnit::getExistingAbstractEntity(const DINode *Node) { + auto &AbstractEntities = getAbstractEntities(); + auto I = AbstractEntities.find(Node); + if (I != AbstractEntities.end()) return I->second.get(); return nullptr; } -void DwarfCompileUnit::createAbstractVariable(const DILocalVariable *Var, - LexicalScope *Scope) { +void DwarfCompileUnit::createAbstractEntity(const DINode *Node, + LexicalScope *Scope) { assert(Scope && Scope->isAbstractScope()); - auto AbsDbgVariable = llvm::make_unique(Var, /* IA */ nullptr); - DU->addScopeVariable(Scope, AbsDbgVariable.get()); - getAbstractVariables()[Var] = std::move(AbsDbgVariable); + auto &Entity = getAbstractEntities()[Node]; + if (isa(Node)) { + Entity = llvm::make_unique( + cast(Node), nullptr /* IA */);; + DU->addScopeVariable(Scope, cast(Entity.get())); + } else if (isa(Node)) { + Entity = llvm::make_unique( + cast(Node), nullptr /* IA */); + DU->addScopeLabel(Scope, cast(Entity.get())); + } } void DwarfCompileUnit::emitHeader(bool UseOffsets) { @@ -1005,6 +1032,15 @@ addFlag(VariableDie, dwarf::DW_AT_artificial); } +void DwarfCompileUnit::applyLabelAttributes(const DbgLabel &Label, + DIE &LabelDie) { + StringRef Name = Label.getName(); + if (!Name.empty()) + addString(LabelDie, dwarf::DW_AT_name, Name); + const auto *DILabel = Label.getLabel(); + addSourceLine(LabelDie, DILabel); +} + /// Add a Dwarf expression attribute data and value. void DwarfCompileUnit::addExpr(DIELoc &Die, dwarf::Form Form, const MCExpr *Expr) { Index: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.h =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.h +++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -15,7 +15,7 @@ #define LLVM_LIB_CODEGEN_ASMPRINTER_DWARFDEBUG_H #include "AddressPool.h" -#include "DbgValueHistoryCalculator.h" +#include "DbgEntityHistoryCalculator.h" #include "DebugHandlerBase.h" #include "DebugLocStream.h" #include "DwarfFile.h" @@ -62,6 +62,46 @@ class Module; //===----------------------------------------------------------------------===// +/// This class is defined as the common parent of DbgVariable and DbgLabel +/// such that it could levarage polymorphism to extract common code for +/// DbgVariable and DbgLabel. +class DbgEntity { + const DINode *Entity; + const DILocation *InlinedAt; + DIE *TheDIE = nullptr; + unsigned SubclassID; + +public: + enum DbgEntityKind { + DbgVariableKind, + DbgLabelKind + }; + + DbgEntity(const DINode *N, const DILocation *IA, unsigned ID) + : Entity(N), InlinedAt(IA), SubclassID(ID) {} + + /// Accessors. + /// @{ + const DINode *getEntity() const { return Entity; } + const DILocation *getInlinedAt() const { return InlinedAt; } + DIE *getDIE() const { return TheDIE; } + unsigned getDbgEntityID() const { return SubclassID; } + /// @} + + void setDIE(DIE &D) { TheDIE = &D; } + + static bool classof(const DbgEntity *N) { + switch (N->getDbgEntityID()) { + default: + return false; + case DbgVariableKind: + case DbgLabelKind: + return true; + } + } +}; + +//===----------------------------------------------------------------------===// /// This class is used to track local variable information. /// /// Variables can be created from allocas, in which case they're generated from @@ -73,10 +113,7 @@ /// single instruction use \a MInsn and (optionally) a single entry of \a Expr. /// /// Variables that have been optimized out use none of these fields. -class DbgVariable { - const DILocalVariable *Var; /// Variable Descriptor. - const DILocation *IA; /// Inlined at location. - DIE *TheDIE = nullptr; /// Variable DIE. +class DbgVariable : public DbgEntity { unsigned DebugLocListIndex = ~0u; /// Offset in DebugLocs. const MachineInstr *MInsn = nullptr; /// DBG_VALUE instruction. @@ -93,7 +130,7 @@ /// Creates a variable without any DW_AT_location. Call \a initializeMMI() /// for MMI entries, or \a initializeDbgValue() for DBG_VALUE instructions. DbgVariable(const DILocalVariable *V, const DILocation *IA) - : Var(V), IA(IA) {} + : DbgEntity(V, IA, DbgVariableKind) {} /// Initialize from the MMI table. void initializeMMI(const DIExpression *E, int FI) { @@ -111,8 +148,9 @@ assert(FrameIndexExprs.empty() && "Already initialized?"); assert(!MInsn && "Already initialized?"); - assert(Var == DbgValue->getDebugVariable() && "Wrong variable"); - assert(IA == DbgValue->getDebugLoc()->getInlinedAt() && "Wrong inlined-at"); + assert(getVariable() == DbgValue->getDebugVariable() && "Wrong variable"); + assert(getInlinedAt() == DbgValue->getDebugLoc()->getInlinedAt() && + "Wrong inlined-at"); MInsn = DbgValue; if (auto *E = DbgValue->getDebugExpression()) @@ -121,19 +159,18 @@ } // Accessors. - const DILocalVariable *getVariable() const { return Var; } - const DILocation *getInlinedAt() const { return IA; } + const DILocalVariable *getVariable() const { + return cast(getEntity()); + } const DIExpression *getSingleExpression() const { assert(MInsn && FrameIndexExprs.size() <= 1); return FrameIndexExprs.size() ? FrameIndexExprs[0].Expr : nullptr; } - void setDIE(DIE &D) { TheDIE = &D; } - DIE *getDIE() const { return TheDIE; } void setDebugLocListIndex(unsigned O) { DebugLocListIndex = O; } unsigned getDebugLocListIndex() const { return DebugLocListIndex; } - StringRef getName() const { return Var->getName(); } + StringRef getName() const { return getVariable()->getName(); } const MachineInstr *getMInsn() const { return MInsn; } /// Get the FI entries, sorted by fragment offset. ArrayRef getFrameIndexExprs() const; @@ -143,7 +180,7 @@ // Translate tag to proper Dwarf tag. dwarf::Tag getTag() const { // FIXME: Why don't we just infer this tag and store it all along? - if (Var->isParameter()) + if (getVariable()->isParameter()) return dwarf::DW_TAG_formal_parameter; return dwarf::DW_TAG_variable; @@ -151,7 +188,7 @@ /// Return true if DbgVariable is artificial. bool isArtificial() const { - if (Var->isArtificial()) + if (getVariable()->isArtificial()) return true; if (getType()->isArtificial()) return true; @@ -159,7 +196,7 @@ } bool isObjectPointer() const { - if (Var->isObjectPointer()) + if (getVariable()->isObjectPointer()) return true; if (getType()->isObjectPointer()) return true; @@ -178,6 +215,45 @@ bool isBlockByrefVariable() const; const DIType *getType() const; + static bool classof(const DbgEntity *N) { + return N->getDbgEntityID() == DbgVariableKind; + } + +private: + template T *resolve(TypedDINodeRef Ref) const { + return Ref.resolve(); + } +}; + +//===----------------------------------------------------------------------===// +/// This class is used to track label information. +/// +/// Labels are collected from \c DBG_LABEL instructions. +class DbgLabel : public DbgEntity { + const MCSymbol *Sym; /// Symbol before DBG_LABEL instruction. + +public: + /// We need MCSymbol information to generate DW_AT_low_pc. + DbgLabel(const DILabel *L, const DILocation *IA, const MCSymbol *Sym = nullptr) + : DbgEntity(L, IA, DbgLabelKind), Sym(Sym) {} + + /// Accessors. + /// @{ + const DILabel *getLabel() const { return cast(getEntity()); } + const MCSymbol *getSymbol() const { return Sym; } + + StringRef getName() const { return getLabel()->getName(); } + /// @} + + /// Translate tag to proper Dwarf tag. + dwarf::Tag getTag() const { + return dwarf::DW_TAG_label; + } + + static bool classof(const DbgEntity *N) { + return N->getDbgEntityID() == DbgLabelKind; + } + private: template T *resolve(TypedDINodeRef Ref) const { return Ref.resolve(); @@ -217,8 +293,8 @@ /// Size of each symbol emitted (for those symbols that have a specific size). DenseMap SymSize; - /// Collection of abstract variables. - SmallVector, 64> ConcreteVariables; + /// Collection of abstract variables/labels. + SmallVector, 64> ConcreteEntities; /// Collection of DebugLocEntry. Stored in a linked list so that DIELocLists /// can refer to them in spite of insertions into this list. @@ -333,14 +409,20 @@ } using InlinedVariable = DbgValueHistoryMap::InlinedVariable; + using InlinedLabel = DbgLabelInstrMap::InlinedLabel; - void ensureAbstractVariableIsCreated(DwarfCompileUnit &CU, InlinedVariable IV, - const MDNode *Scope); - void ensureAbstractVariableIsCreatedIfScoped(DwarfCompileUnit &CU, InlinedVariable IV, - const MDNode *Scope); - - DbgVariable *createConcreteVariable(DwarfCompileUnit &TheCU, - LexicalScope &Scope, InlinedVariable IV); + void ensureAbstractEntityIsCreated(DwarfCompileUnit &CU, + const DINode *Node, + const MDNode *Scope); + void ensureAbstractEntityIsCreatedIfScoped(DwarfCompileUnit &CU, + const DINode *Node, + const MDNode *Scope); + + DbgEntity *createConcreteEntity(DwarfCompileUnit &TheCU, + LexicalScope &Scope, + const DINode *Node, + const DILocation *Location, + const MCSymbol *Sym = nullptr); /// Construct a DIE for this abstract scope. void constructAbstractSubprogramScopeDIE(DwarfCompileUnit &SrcCU, LexicalScope *Scope); @@ -349,7 +431,7 @@ void addAccelNameImpl(AccelTable &AppleAccel, StringRef Name, const DIE &Die); - void finishVariableDefinitions(); + void finishEntityDefinitions(); void finishSubprogramDefinitions(); @@ -461,8 +543,8 @@ unsigned Flags); /// Populate LexicalScope entries with variables' info. - void collectVariableInfo(DwarfCompileUnit &TheCU, const DISubprogram *SP, - DenseSet &ProcessedVars); + void collectEntityInfo(DwarfCompileUnit &TheCU, const DISubprogram *SP, + DenseSet &ProcessedVars); /// Build the location list for all DBG_VALUEs in the /// function that describe the same variable. Index: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -188,12 +188,12 @@ } bool DbgVariable::isBlockByrefVariable() const { - assert(Var && "Invalid complex DbgVariable!"); - return Var->getType().resolve()->isBlockByrefStruct(); + assert(getVariable() && "Invalid complex DbgVariable!"); + return getVariable()->getType().resolve()->isBlockByrefStruct(); } const DIType *DbgVariable::getType() const { - DIType *Ty = Var->getType().resolve(); + DIType *Ty = getVariable()->getType().resolve(); // FIXME: isBlockByrefVariable should be reformulated in terms of complex // addresses instead. if (Ty->isBlockByrefStruct()) { @@ -258,8 +258,8 @@ void DbgVariable::addMMIEntry(const DbgVariable &V) { assert(DebugLocListIndex == ~0U && !MInsn && "not an MMI entry"); assert(V.DebugLocListIndex == ~0U && !V.MInsn && "not an MMI entry"); - assert(V.Var == Var && "conflicting variable"); - assert(V.IA == IA && "conflicting inlined-at location"); + assert(V.getVariable() == getVariable() && "conflicting variable"); + assert(V.getInlinedAt() == getInlinedAt() && "conflicting inlined-at location"); assert(!FrameIndexExprs.empty() && "Expected an MMI entry"); assert(!V.FrameIndexExprs.empty() && "Expected an MMI entry"); @@ -726,16 +726,16 @@ } } -void DwarfDebug::finishVariableDefinitions() { - for (const auto &Var : ConcreteVariables) { - DIE *VariableDie = Var->getDIE(); - assert(VariableDie); +void DwarfDebug::finishEntityDefinitions() { + for (const auto &Entity : ConcreteEntities) { + DIE *Die = Entity->getDIE(); + assert(Die); // FIXME: Consider the time-space tradeoff of just storing the unit pointer - // in the ConcreteVariables list, rather than looking it up again here. + // in the ConcreteEntities list, rather than looking it up again here. // DIE::getUnit isn't simple - it walks parent pointers, etc. - DwarfCompileUnit *Unit = CUDieMap.lookup(VariableDie->getUnitDie()); + DwarfCompileUnit *Unit = CUDieMap.lookup(Die->getUnitDie()); assert(Unit); - Unit->finishVariableDefinition(*Var); + Unit->finishEntityDefinition(Entity.get()); } } @@ -753,7 +753,7 @@ finishSubprogramDefinitions(); - finishVariableDefinitions(); + finishEntityDefinitions(); // Include the DWO file name in the hash if there's more than one CU. // This handles ThinLTO's situation where imported CUs may very easily be @@ -910,25 +910,24 @@ // FIXME: AbstractVariables.clear(); } -void DwarfDebug::ensureAbstractVariableIsCreated(DwarfCompileUnit &CU, InlinedVariable IV, - const MDNode *ScopeNode) { - const DILocalVariable *Cleansed = nullptr; - if (CU.getExistingAbstractVariable(IV, Cleansed)) +void DwarfDebug::ensureAbstractEntityIsCreated(DwarfCompileUnit &CU, + const DINode *Node, + const MDNode *ScopeNode) { + if (CU.getExistingAbstractEntity(Node)) return; - CU.createAbstractVariable(Cleansed, LScopes.getOrCreateAbstractScope( + CU.createAbstractEntity(Node, LScopes.getOrCreateAbstractScope( cast(ScopeNode))); } -void DwarfDebug::ensureAbstractVariableIsCreatedIfScoped(DwarfCompileUnit &CU, - InlinedVariable IV, const MDNode *ScopeNode) { - const DILocalVariable *Cleansed = nullptr; - if (CU.getExistingAbstractVariable(IV, Cleansed)) +void DwarfDebug::ensureAbstractEntityIsCreatedIfScoped(DwarfCompileUnit &CU, + const DINode *Node, const MDNode *ScopeNode) { + if (CU.getExistingAbstractEntity(Node)) return; if (LexicalScope *Scope = LScopes.findAbstractScope(cast_or_null(ScopeNode))) - CU.createAbstractVariable(Cleansed, Scope); + CU.createAbstractEntity(Node, Scope); } // Collect variable information from side table maintained by MF. @@ -949,14 +948,14 @@ if (!Scope) continue; - ensureAbstractVariableIsCreatedIfScoped(TheCU, Var, Scope->getScopeNode()); + ensureAbstractEntityIsCreatedIfScoped(TheCU, Var.first, Scope->getScopeNode()); auto RegVar = llvm::make_unique(Var.first, Var.second); RegVar->initializeMMI(VI.Expr, VI.Slot); if (DbgVariable *DbgVar = MFVars.lookup(Var)) DbgVar->addMMIEntry(*RegVar); else if (InfoHolder.addScopeVariable(Scope, RegVar.get())) { MFVars.insert({Var, RegVar.get()}); - ConcreteVariables.push_back(std::move(RegVar)); + ConcreteEntities.push_back(std::move(RegVar)); } } } @@ -1121,14 +1120,26 @@ } } -DbgVariable *DwarfDebug::createConcreteVariable(DwarfCompileUnit &TheCU, - LexicalScope &Scope, - InlinedVariable IV) { - ensureAbstractVariableIsCreatedIfScoped(TheCU, IV, Scope.getScopeNode()); - ConcreteVariables.push_back( - llvm::make_unique(IV.first, IV.second)); - InfoHolder.addScopeVariable(&Scope, ConcreteVariables.back().get()); - return ConcreteVariables.back().get(); +DbgEntity *DwarfDebug::createConcreteEntity(DwarfCompileUnit &TheCU, + LexicalScope &Scope, + const DINode *Node, + const DILocation *Location, + const MCSymbol *Sym) { + ensureAbstractEntityIsCreatedIfScoped(TheCU, Node, Scope.getScopeNode()); + if (isa(Node)) { + ConcreteEntities.push_back( + llvm::make_unique(cast(Node), + Location)); + InfoHolder.addScopeVariable(&Scope, + cast(ConcreteEntities.back().get())); + } else if (isa(Node)) { + ConcreteEntities.push_back( + llvm::make_unique(cast(Node), + Location, Sym)); + InfoHolder.addScopeLabel(&Scope, + cast(ConcreteEntities.back().get())); + } + return ConcreteEntities.back().get(); } /// Determine whether a *singular* DBG_VALUE is valid for the entirety of its @@ -1190,9 +1201,9 @@ } // Find variables for each lexical scope. -void DwarfDebug::collectVariableInfo(DwarfCompileUnit &TheCU, - const DISubprogram *SP, - DenseSet &Processed) { +void DwarfDebug::collectEntityInfo(DwarfCompileUnit &TheCU, + const DISubprogram *SP, + DenseSet &Processed) { // Grab the variable info that was squirreled away in the MMI side-table. collectVariableInfoFromMFTable(TheCU, Processed); @@ -1216,7 +1227,8 @@ continue; Processed.insert(IV); - DbgVariable *RegVar = createConcreteVariable(TheCU, *Scope, IV); + DbgVariable *RegVar = cast(createConcreteEntity(TheCU, + *Scope, IV.first, IV.second)); const MachineInstr *MInsn = Ranges.front().first; assert(MInsn->isDebugValue() && "History must begin with debug value"); @@ -1249,13 +1261,44 @@ Entry.finalize(*Asm, List, BT); } - // Collect info for variables that were optimized out. + // For each InlinedLabel collected from DBG_LABEL instructions, convert to + // DWARF-related DbgLabel. + for (const auto &I : DbgLabels) { + InlinedLabel IL = I.first; + const MachineInstr *MI = I.second; + if (MI == nullptr) + continue; + + LexicalScope *Scope = nullptr; + // Get inlined DILocation if it is inlined label. + if (const DILocation *IA = IL.second) + Scope = LScopes.findInlinedScope(IL.first->getScope(), IA); + else + Scope = LScopes.findLexicalScope(IL.first->getScope()); + // If label scope is not found then skip this label. + if (!Scope) + continue; + + /// At this point, the temporary label is created. + /// Save the temporary label to DbgLabel entity to get the + /// actually address when generating Dwarf DIE. + MCSymbol *Sym = getLabelBeforeInsn(MI); + createConcreteEntity(TheCU, *Scope, IL.first, IL.second, Sym); + } + + // Collect info for variables/labels that were optimized out. for (const DINode *DN : SP->getRetainedNodes()) { + LexicalScope *Scope = nullptr; if (auto *DV = dyn_cast(DN)) { - if (Processed.insert(InlinedVariable(DV, nullptr)).second) - if (LexicalScope *Scope = LScopes.findLexicalScope(DV->getScope())) - createConcreteVariable(TheCU, *Scope, InlinedVariable(DV, nullptr)); + if (!Processed.insert(InlinedVariable(DV, nullptr)).second) + continue; + Scope = LScopes.findLexicalScope(DV->getScope()); + } else if (auto *DL = dyn_cast(DN)) { + Scope = LScopes.findLexicalScope(DL->getScope()); } + + if (Scope) + createConcreteEntity(TheCU, *Scope, DN, nullptr); } } @@ -1413,7 +1456,7 @@ DwarfCompileUnit &TheCU = *CUMap.lookup(SP->getUnit()); DenseSet ProcessedVars; - collectVariableInfo(TheCU, SP, ProcessedVars); + collectEntityInfo(TheCU, SP, ProcessedVars); // Add the range of this function to the list of ranges for the CU. TheCU.addRange(RangeSpan(Asm->getFunctionBegin(), Asm->getFunctionEnd())); @@ -1441,10 +1484,11 @@ // Collect info for variables that were optimized out. if (!ProcessedVars.insert(InlinedVariable(DV, nullptr)).second) continue; - ensureAbstractVariableIsCreated(TheCU, InlinedVariable(DV, nullptr), - DV->getScope()); + ensureAbstractEntityIsCreated(TheCU, DV, DV->getScope()); assert(LScopes.getAbstractScopesList().size() == NumAbstractScopes - && "ensureAbstractVariableIsCreated inserted abstract scopes"); + && "ensureAbstractEntityIsCreated inserted abstract scopes"); + } else if (auto *DL = dyn_cast(DN)) { + ensureAbstractEntityIsCreated(TheCU, DL, DL->getScope()); } } constructAbstractSubprogramScopeDIE(TheCU, AScope); @@ -1462,6 +1506,7 @@ // DbgVariables except those that are also in AbstractVariables (since they // can be used cross-function) InfoHolder.getScopeVariables().clear(); + InfoHolder.getScopeLabels().clear(); PrevLabel = nullptr; CurFn = nullptr; } Index: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfFile.h =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfFile.h +++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfFile.h @@ -24,7 +24,9 @@ namespace llvm { class AsmPrinter; +class DbgEntity; class DbgVariable; +class DbgLabel; class DwarfCompileUnit; class DwarfUnit; class LexicalScope; @@ -62,9 +64,13 @@ /// Collection of DbgVariables of each lexical scope. DenseMap ScopeVariables; + /// Collection of DbgLabels of each lexical scope. + using LabelList = SmallVector; + DenseMap ScopeLabels; + // Collection of abstract subprogram DIEs. DenseMap AbstractSPDies; - DenseMap> AbstractVariables; + DenseMap> AbstractEntities; /// Maps MDNodes for type system with the corresponding DIEs. These DIEs can /// be shared across CUs, that is why we keep the map here instead @@ -125,16 +131,22 @@ /// \returns false if the variable was merged with a previous one. bool addScopeVariable(LexicalScope *LS, DbgVariable *Var); + void addScopeLabel(LexicalScope *LS, DbgLabel *Label); + DenseMap &getScopeVariables() { return ScopeVariables; } + DenseMap &getScopeLabels() { + return ScopeLabels; + } + DenseMap &getAbstractSPDies() { return AbstractSPDies; } - DenseMap> &getAbstractVariables() { - return AbstractVariables; + DenseMap> &getAbstractEntities() { + return AbstractEntities; } void insertDIE(const MDNode *TypeMD, DIE *Die) { Index: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfFile.cpp =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfFile.cpp +++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfFile.cpp @@ -118,3 +118,8 @@ } return true; } + +void DwarfFile::addScopeLabel(LexicalScope *LS, DbgLabel *Label) { + SmallVectorImpl &Labels = ScopeLabels[LS]; + Labels.push_back(Label); +} Index: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfUnit.h =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfUnit.h +++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfUnit.h @@ -213,6 +213,7 @@ void addSourceLine(DIE &Die, const DILocalVariable *V); void addSourceLine(DIE &Die, const DIGlobalVariable *G); void addSourceLine(DIE &Die, const DISubprogram *SP); + void addSourceLine(DIE &Die, const DILabel *L); void addSourceLine(DIE &Die, const DIType *Ty); void addSourceLine(DIE &Die, const DIObjCProperty *Ty); Index: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfUnit.cpp =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -401,6 +401,12 @@ addSourceLine(Die, SP->getLine(), SP->getFile()); } +void DwarfUnit::addSourceLine(DIE &Die, const DILabel *L) { + assert(L); + + addSourceLine(Die, L->getLine(), L->getFile()); +} + void DwarfUnit::addSourceLine(DIE &Die, const DIType *Ty) { assert(Ty); Index: llvm/trunk/test/DebugInfo/Generic/debug-label-inline.ll =================================================================== --- llvm/trunk/test/DebugInfo/Generic/debug-label-inline.ll +++ llvm/trunk/test/DebugInfo/Generic/debug-label-inline.ll @@ -0,0 +1,50 @@ +; RUN: llc -O2 -filetype=obj -o - %s | llvm-dwarfdump -v - | FileCheck %s +; +; CHECK: .debug_info contents: +; CHECK: [[LABEL_ORIGIN:0x[0-9a-zA-Z]+]]:{{ *}}DW_TAG_label +; CHECK-NEXT: DW_AT_name [DW_FORM_strp] {{.*}}"top" +; CHECK-NEXT: DW_AT_decl_file [DW_FORM_data1] {{.*}}debug-label-inline.c +; CHECK-NEXT: DW_AT_decl_line [DW_FORM_data1] {{.*}}8 +; CHECK: DW_TAG_label +; CHECK-NEXT: DW_AT_abstract_origin [DW_FORM_ref4] {{.*}}{[[LABEL_ORIGIN]]} "top" +; CHECK-NEXT: DW_AT_low_pc [DW_FORM_addr] {{.*}}{{0x[0-9a-f]+}} + +source_filename = "debug-label-inline.c" + +@ga = external local_unnamed_addr global i32, align 4 +@gb = external local_unnamed_addr global i32, align 4 + +define i32 @f2() local_unnamed_addr #0 !dbg !4 { +entry: + %0 = load i32, i32* @ga, align 4, !dbg !1 + %1 = load i32, i32* @gb, align 4, !dbg !1 + call void @llvm.dbg.label(metadata !15), !dbg !17 + %add.i = add nsw i32 %1, %0, !dbg !18 + ret i32 %add.i, !dbg !1 +} + +declare void @llvm.dbg.label(metadata) +declare void @llvm.dbg.value(metadata, metadata, metadata) + +attributes #0 = { nounwind readonly } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !6, isOptimized: true, emissionKind: FullDebug, enums: !2) +!1 = !DILocation(line: 18, scope: !4) +!2 = !{} +!3 = !{i32 2, !"Debug Info Version", i32 3} +!4 = distinct !DISubprogram(name: "f2", scope: !6, file: !6, line: 15, type: !7, isLocal: false, isDefinition: true, scopeLine: 15, isOptimized: true, unit: !0, retainedNodes: !2) +!6 = !DIFile(filename: "debug-label-inline.c", directory: "./") +!7 = !DISubroutineType(types: !8) +!8 = !{!10} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = distinct !DISubprogram(name: "f1", scope: !6, file: !6, line: 5, type: !12, isLocal: false, isDefinition: true, scopeLine: 5, isOptimized: true, unit: !0, retainedNodes: !14) +!12 = !DISubroutineType(types: !13) +!13 = !{!10, !10, !10} +!14 = !{!15} +!15 = !DILabel(scope: !11, name: "top", file: !6, line: 8) +!16 = distinct !DILocation(line: 18, scope: !4) +!17 = !DILocation(line: 8, scope: !11, inlinedAt: !16) +!18 = !DILocation(line: 9, scope: !11, inlinedAt: !16) Index: llvm/trunk/test/DebugInfo/Generic/debug-label.ll =================================================================== --- llvm/trunk/test/DebugInfo/Generic/debug-label.ll +++ llvm/trunk/test/DebugInfo/Generic/debug-label.ll @@ -0,0 +1,76 @@ +; RUN: llc -fast-isel=false -O0 -filetype=obj -o - %s | llvm-dwarfdump -v - | FileCheck %s +; +; CHECK: .debug_info contents: +; CHECK: DW_TAG_label +; CHECK-NEXT: DW_AT_name [DW_FORM_strp] {{.*}}"top" +; CHECK-NEXT: DW_AT_decl_file [DW_FORM_data1] {{.*}}debug-label.c +; CHECK-NEXT: DW_AT_decl_line [DW_FORM_data1] {{.*}}4 +; CHECK-NEXT: DW_AT_low_pc [DW_FORM_addr] {{.*}}{{0x[0-9a-f]+}} +; CHECK: DW_TAG_label +; CHECK-NEXT: DW_AT_name [DW_FORM_strp] {{.*}}"done" +; CHECK-NEXT: DW_AT_decl_file [DW_FORM_data1] {{.*}}debug-label.c +; CHECK-NEXT: DW_AT_decl_line [DW_FORM_data1] {{.*}}7 +; CHECK-NEXT: DW_AT_low_pc [DW_FORM_addr] {{.*}}{{0x[0-9a-f]+}} +; +; RUN: llc -fast-isel=false -O0 -o - %s | FileCheck %s -check-prefix=ASM +; +; ASM: [[TOP_LOW_PC:[.0-9a-zA-Z]+]]:{{[[:space:]].*}}DEBUG_LABEL: foo:top +; ASM: [[DONE_LOW_PC:[.0-9a-zA-Z]+]]:{{[[:space:]].*}}DEBUG_LABEL: foo:done +; ASM-LABEL: .debug_str +; ASM: [[TOP_LABEL:[.0-9a-zA-Z]+]]:{{[[:space:]].*}}"top" +; ASM: [[DONE_LABEL:[.0-9a-zA-Z]+]]:{{[[:space:]].*}}"done" +; ASM-LABEL: .debug_info +; ASM: DW_TAG_label +; ASM-NEXT: [[TOP_LABEL]] # DW_AT_name +; ASM-NEXT: 1 # DW_AT_decl_file +; ASM-NEXT: 4 # DW_AT_decl_line +; ASM-NEXT: [[TOP_LOW_PC]] # DW_AT_low_pc +; ASM: DW_TAG_label +; ASM-NEXT: [[DONE_LABEL]] # DW_AT_name +; ASM-NEXT: 1 # DW_AT_decl_file +; ASM-NEXT: 7 # DW_AT_decl_line +; ASM-NEXT: [[DONE_LOW_PC]] # DW_AT_low_pc + +source_filename = "debug-label.c" + +define dso_local i32 @foo(i32 %a, i32 %b) !dbg !6 { +entry: + %a.addr = alloca i32, align 4 + %b.addr = alloca i32, align 4 + %sum = alloca i32, align 4 + store i32 %a, i32* %a.addr, align 4 + store i32 %b, i32* %b.addr, align 4 + br label %top + +top: + call void @llvm.dbg.label(metadata !10), !dbg !11 + %0 = load i32, i32* %a.addr, align 4 + %1 = load i32, i32* %b.addr, align 4 + %add = add nsw i32 %0, %1 + store i32 %add, i32* %sum, align 4 + br label %done + +done: + call void @llvm.dbg.label(metadata !12), !dbg !13 + %2 = load i32, i32* %sum, align 4 + ret i32 %2, !dbg !14 +} + +declare void @llvm.dbg.label(metadata) + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!4} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, isOptimized: false, emissionKind: FullDebug, enums: !2) +!1 = !DIFile(filename: "debug-label.c", directory: "./") +!2 = !{} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!6 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !7, isLocal: false, isDefinition: true, scopeLine: 2, isOptimized: false, unit: !0, retainedNodes: !2) +!7 = !DISubroutineType(types: !8) +!8 = !{!9, !9, !9} +!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!10 = !DILabel(scope: !6, name: "top", file: !1, line: 4) +!11 = !DILocation(line: 4, column: 1, scope: !6) +!12 = !DILabel(scope: !6, name: "done", file: !1, line: 7) +!13 = !DILocation(line: 7, column: 1, scope: !6) +!14 = !DILocation(line: 8, column: 3, scope: !6)