Index: lib/CodeGen/AsmPrinter/DebugHandlerBase.h =================================================================== --- lib/CodeGen/AsmPrinter/DebugHandlerBase.h +++ lib/CodeGen/AsmPrinter/DebugHandlerBase.h @@ -49,6 +49,10 @@ extractFromMachineInstruction(const MachineInstr &Instruction); }; +using InlinedLabel = + std::pair; +using LabelInstrMap = MapVector; + /// Base class for debug information backends. Common functionality related to /// tracking which variables and scopes are alive at a given PC live here. class DebugHandlerBase : public AsmPrinterHandler { @@ -82,6 +86,9 @@ /// variable. Variables are listed in order of appearance. DbgValueHistoryMap DbgValues; + /// Mapping of inlined labels and DBG_LABEL machine instruction. + LabelInstrMap DbgLabels; + /// Maps instruction with label emitted before instruction. /// FIXME: Make this private from DwarfDebug, we have the necessary accessors /// for it. @@ -104,6 +111,8 @@ LabelsAfterInsn.insert(std::make_pair(MI, nullptr)); } + void collectDbgLabels(const MachineFunction *MF); + virtual void beginFunctionImpl(const MachineFunction *MF) = 0; virtual void endFunctionImpl(const MachineFunction *MF) = 0; virtual void skippedNonDebugFunction() {} Index: lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp +++ lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp @@ -167,6 +167,32 @@ return true; } +/// Collect labels in this machine function into DebugHandlerBase::DbgLabels. +/// +/// When we encounter a DBG_LABEL, we will get the inlined location of it and +/// create the mapping of this inlined label to the DBG_LABEL. +/// In addition, we will create a temp symbol before the inlined label to get +/// its address afterward. +void DebugHandlerBase::collectDbgLabels(const MachineFunction *MF) { + for (const auto &MBB : *MF) { + for (const auto &MI : MBB) { + 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"); + // Ensure there is a symbol before DBG_LABEL. + requestLabelBeforeInsn(&MI); + // 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[L] = &MI; + } + } + } +} + void DebugHandlerBase::beginFunction(const MachineFunction *MF) { PrevInstBB = nullptr; @@ -226,6 +252,9 @@ } } + // Collect label's information from DBG_LABEL in this machine function. + collectDbgLabels(MF); + PrevInstLoc = DebugLoc(); PrevLabel = Asm->getFunctionBegin(); beginFunctionImpl(MF); Index: lib/CodeGen/AsmPrinter/DwarfCompileUnit.h =================================================================== --- lib/CodeGen/AsmPrinter/DwarfCompileUnit.h +++ lib/CodeGen/AsmPrinter/DwarfCompileUnit.h @@ -82,6 +82,7 @@ DenseMap AbstractSPDies; DenseMap> AbstractVariables; + DenseMap> AbstractLabels; /// \brief Construct a DIE for the given DbgVariable without initializing the /// DbgVariable's DIE reference. @@ -101,6 +102,12 @@ return DU->getAbstractVariables(); } + DenseMap> &getAbstractLabels() { + if (isDwoUnit() && !DD->shareAcrossDWOCUs()) + return AbstractLabels; + return DU->getAbstractLabels(); + } + public: DwarfCompileUnit(unsigned UID, const DICompileUnit *Node, AsmPrinter *A, DwarfDebug *DW, DwarfFile *DWU); @@ -191,6 +198,9 @@ DIE *constructVariableDIE(DbgVariable &DV, const LexicalScope &Scope, DIE *&ObjectPointer); + /// constructLabelDIE - Construct a DIE for the given DwarfLabel. + DIE *constructLabelDIE(DwarfLabel &DL, const LexicalScope &Scope); + /// A helper function to create children of a Scope DIE. DIE *createScopeChildrenDIE(LexicalScope *Scope, SmallVectorImpl &Children, @@ -208,6 +218,7 @@ void finishSubprogramDefinition(const DISubprogram *SP); void finishVariableDefinition(const DbgVariable &Var); + void finishLabelDefinition(const DwarfLabel &Label); /// Find abstract variable associated with Var. using InlinedVariable = DbgValueHistoryMap::InlinedVariable; @@ -216,6 +227,12 @@ DbgVariable *getExistingAbstractVariable(InlinedVariable IV); void createAbstractVariable(const DILocalVariable *DV, LexicalScope *Scope); + /// Find abstract label associated with inlined label. + DwarfLabel *getExistingInlinedLabel(InlinedLabel IL, + const DILabel *&Label); + DwarfLabel *getExistingInlinedLabel(InlinedLabel IL); + void createInlinedLabel(const DILabel *DL, LexicalScope *Scope); + /// Set the skeleton unit associated with this unit. void setSkeleton(DwarfCompileUnit &Skel) { Skeleton = &Skel; } @@ -278,6 +295,8 @@ void applySubprogramAttributesToDefinition(const DISubprogram *SP, DIE &SPDie); + void applyLabelAttributes(const DwarfLabel &Label, DIE &LabelDie); + /// getRangeLists - Get the vector of range lists. const SmallVectorImpl &getRangeLists() const { return (Skeleton ? Skeleton : this)->CURangeLists; Index: lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -487,6 +487,19 @@ return D; } +/// constructLabelDIE - Construct a DIE for the given DwarfLabel. +DIE *DwarfCompileUnit::constructLabelDIE(DwarfLabel &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. @@ -677,6 +690,9 @@ if (HasNonScopeChildren) *HasNonScopeChildren = !Children.empty(); + for (DwarfLabel *DL : DU->getScopeLabels().lookup(Scope)) + Children.push_back(constructLabelDIE(*DL, *Scope)); + for (LexicalScope *LS : Scope->getChildren()) constructScopeDIE(LS, Children); @@ -813,6 +829,54 @@ applyVariableAttributes(Var, *VariableDie); } +void DwarfCompileUnit::applyLabelAttributes(const DwarfLabel &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); +} + +void DwarfCompileUnit::finishLabelDefinition(const DwarfLabel &Label) { + DwarfLabel *InlinedDwarfLabel = getExistingInlinedLabel( + InlinedLabel(Label.getLabel(), Label.getInlinedAt())); + auto *LabelDie = Label.getDIE(); + if (InlinedDwarfLabel && InlinedDwarfLabel->getDIE()) { + addDIEEntry(*LabelDie, dwarf::DW_AT_abstract_origin, + *InlinedDwarfLabel->getDIE()); + } else + applyLabelAttributes(Label, *LabelDie); + + const MCSymbol *Sym = Label.getSymbol(); + addLabelAddress(*LabelDie, dwarf::DW_AT_low_pc, Sym); +} + +DwarfLabel *DwarfCompileUnit::getExistingInlinedLabel(InlinedLabel IL) { + const DILabel *Label; + return getExistingInlinedLabel(IL, Label); +} + +DwarfLabel *DwarfCompileUnit::getExistingInlinedLabel( + InlinedLabel IL, const DILabel *&Label) { + Label = IL.first; + auto &InlinedLabels = getAbstractLabels(); + auto I = InlinedLabels.find(Label); + if (I != InlinedLabels.end()) + return I->second.get(); + return nullptr; +} + +void DwarfCompileUnit::createInlinedLabel(const DILabel *Label, + LexicalScope *Scope) { + assert(Scope && Scope->isAbstractScope()); + auto AbsDwarfLabel = llvm::make_unique(Label, + nullptr /* IA */, + nullptr /* Sym */); + DU->addScopeLabel(Scope, AbsDwarfLabel.get()); + getAbstractLabels()[Label] = std::move(AbsDwarfLabel); +} + DbgVariable *DwarfCompileUnit::getExistingAbstractVariable(InlinedVariable IV) { const DILocalVariable *Cleansed; return getExistingAbstractVariable(IV, Cleansed); Index: lib/CodeGen/AsmPrinter/DwarfDebug.h =================================================================== --- lib/CodeGen/AsmPrinter/DwarfDebug.h +++ lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -184,6 +184,40 @@ } }; +//===----------------------------------------------------------------------===// +/// This class is used to track label information. +/// +/// Labels are collected from \c DBG_LABEL instructions. +class DwarfLabel { + const DILabel *Label; /// Label Descriptor. + const DILocation *IA; /// Inlined at location. + const MCSymbol *Sym; /// Symbol before DBG_LABEL instruction. + DIE *TheDIE = nullptr; /// Label DIE. + +public: + // We need MCSymbol information to generate DW_AT_low_pc. + DwarfLabel(const DILabel *L, const DILocation *IA, const MCSymbol *Sym) + : Label(L), IA(IA), Sym(Sym) {} + + // Accessors. + const DILabel *getLabel() const { return Label; } + const DILocation *getInlinedAt() const { return IA; } + const MCSymbol *getSymbol() const { return Sym; } + void setDIE(DIE &D) { TheDIE = &D; } + DIE *getDIE() const { return TheDIE; } + StringRef getName() const { return Label->getName(); } + + // Translate tag to proper Dwarf tag. + dwarf::Tag getTag() const { + return dwarf::DW_TAG_label; + } + +private: + template T *resolve(TypedDINodeRef Ref) const { + return Ref.resolve(); + } +}; + /// Helper used to pair up a symbol and its DWARF compile unit. struct SymbolCU { SymbolCU(DwarfCompileUnit *CU, const MCSymbol *Sym) : Sym(Sym), CU(CU) {} @@ -212,6 +246,9 @@ /// Collection of abstract variables. SmallVector, 64> ConcreteVariables; + /// Collection of user labels. + SmallVector, 4> UserLabels; + /// Collection of DebugLocEntry. Stored in a linked list so that DIELocLists /// can refer to them in spite of insertions into this list. DebugLocStream DebugLocs; @@ -327,11 +364,21 @@ DbgVariable *createConcreteVariable(DwarfCompileUnit &TheCU, LexicalScope &Scope, InlinedVariable IV); + void ensureInlinedLabelIsCreated(DwarfCompileUnit &CU, InlinedLabel Label, + const MDNode *Scope); + void ensureInlinedLabelIsCreatedIfScoped(DwarfCompileUnit &CU, InlinedLabel Label, + const MDNode *Scope); + + void createConcreteLabel(DwarfCompileUnit &TheCU, + LexicalScope &Scope, InlinedLabel IL, MCSymbol *Sym); + /// Construct a DIE for this abstract scope. void constructAbstractSubprogramScopeDIE(DwarfCompileUnit &SrcCU, LexicalScope *Scope); void finishVariableDefinitions(); + void finishLabelDefinitions(); + void finishSubprogramDefinitions(); /// Finish off debug information after all functions have been @@ -439,6 +486,9 @@ void collectVariableInfo(DwarfCompileUnit &TheCU, const DISubprogram *SP, DenseSet &ProcessedVars); + /// Populate LexicalScope entries with labels' info. + void collectLabelInfo(DwarfCompileUnit &TheCU, const DISubprogram *SP); + /// Build the location list for all DBG_VALUEs in the /// function that describe the same variable. void buildLocationList(SmallVectorImpl &DebugLoc, Index: lib/CodeGen/AsmPrinter/DwarfDebug.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -694,6 +694,16 @@ } } +void DwarfDebug::finishLabelDefinitions() { + for (const auto &Label : UserLabels) { + DIE *LabelDie = Label->getDIE(); + assert(LabelDie); + DwarfCompileUnit *Unit = CUDieMap.lookup(LabelDie->getUnitDie()); + assert(Unit); + Unit->finishLabelDefinition(*Label); + } +} + void DwarfDebug::finishSubprogramDefinitions() { for (const DISubprogram *SP : ProcessedSPNodes) { assert(SP->getUnit()->getEmissionKind() != DICompileUnit::NoDebug); @@ -710,6 +720,8 @@ finishVariableDefinitions(); + finishLabelDefinitions(); + // 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 // duplicate with the same CU partially imported into another ThinLTO unit. @@ -873,6 +885,27 @@ CU.createAbstractVariable(Cleansed, Scope); } +void DwarfDebug::ensureInlinedLabelIsCreated(DwarfCompileUnit &CU, InlinedLabel IL, + const MDNode *ScopeNode) { + const DILabel *Label = nullptr; + if (CU.getExistingInlinedLabel(IL, Label)) + return; + + CU.createInlinedLabel(Label, LScopes.getOrCreateAbstractScope( + cast(ScopeNode))); +} + +void DwarfDebug::ensureInlinedLabelIsCreatedIfScoped(DwarfCompileUnit &CU, + InlinedLabel IL, const MDNode *ScopeNode) { + const DILabel *Label = nullptr; + if (CU.getExistingInlinedLabel(IL, Label)) + return; + + if (LexicalScope *Scope = + LScopes.findAbstractScope(cast_or_null(ScopeNode))) + CU.createInlinedLabel(Label, Scope); +} + // Collect variable information from side table maintained by MF. void DwarfDebug::collectVariableInfoFromMFTable( DwarfCompileUnit &TheCU, DenseSet &Processed) { @@ -1196,6 +1229,53 @@ } } +void DwarfDebug::createConcreteLabel(DwarfCompileUnit &TheCU, + LexicalScope &Scope, + InlinedLabel IL, + MCSymbol *Sym) { + ensureInlinedLabelIsCreatedIfScoped(TheCU, IL, Scope.getScopeNode()); + // Keep a list of DwarfLabel in DwarfDebug::UserLabels. + // We will use the list to go through all labels in this machine + // function and fill all detail information of DW_TAG_label in + // finishLabelDefinitions(). + UserLabels.push_back(make_unique(IL.first, IL.second, Sym)); + // Create 'scope to labels' mappings. When we construct DIE tree, we + // need to know which scope the label DIE is in. + InfoHolder.addScopeLabel(&Scope, UserLabels.back().get()); +} + +// Dwarf-specific handling of DebugHandlerBase::DbgLabels +void DwarfDebug::collectLabelInfo(DwarfCompileUnit &TheCU, + const DISubprogram *SP) { + // For each InlinedLabel collected from DBG_LABEL instructions, convert to + // DWARF-related DwarfLabel. + 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; + + MCSymbol *Sym = getLabelBeforeInsn(MI); + createConcreteLabel(TheCU, *Scope, IL, Sym); + } + + // Collect info for labels that were optimized out. + for (const DILabel *DL : SP->getLabels()) { + if (LexicalScope *Scope = LScopes.findLexicalScope(DL->getScope())) + createConcreteLabel(TheCU, *Scope, InlinedLabel(DL, nullptr), nullptr); + } +} + // Process beginning of an instruction. void DwarfDebug::beginInstruction(const MachineInstr *MI) { DebugHandlerBase::beginInstruction(MI); @@ -1352,6 +1432,8 @@ DenseSet ProcessedVars; collectVariableInfo(TheCU, SP, ProcessedVars); + collectLabelInfo(TheCU, SP); + // Add the range of this function to the list of ranges for the CU. TheCU.addRange(RangeSpan(Asm->getFunctionBegin(), Asm->getFunctionEnd())); @@ -1382,6 +1464,11 @@ assert(LScopes.getAbstractScopesList().size() == NumAbstractScopes && "ensureAbstractVariableIsCreated inserted abstract scopes"); } + // Collect info for labels that were optimized out. + for (const DILabel *DL : SP->getLabels()) { + ensureInlinedLabelIsCreated(TheCU, InlinedLabel(DL, nullptr), + DL->getScope()); + } constructAbstractSubprogramScopeDIE(TheCU, AScope); } @@ -1397,6 +1484,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: lib/CodeGen/AsmPrinter/DwarfFile.h =================================================================== --- lib/CodeGen/AsmPrinter/DwarfFile.h +++ lib/CodeGen/AsmPrinter/DwarfFile.h @@ -25,6 +25,7 @@ class AsmPrinter; class DbgVariable; +class DwarfLabel; class DwarfCompileUnit; class DwarfUnit; class LexicalScope; @@ -58,9 +59,14 @@ /// Collection of DbgVariables of each lexical scope. DenseMap ScopeVariables; + // Collection of dbg labels of a scope + using LabelList = SmallVector; + DenseMap ScopeLabels; + // Collection of abstract subprogram DIEs. DenseMap AbstractSPDies; DenseMap> AbstractVariables; + DenseMap> AbstractLabels; /// 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 @@ -117,10 +123,16 @@ /// \returns false if the variable was merged with a previous one. bool addScopeVariable(LexicalScope *LS, DbgVariable *Var); + void addScopeLabel(LexicalScope *LS, DwarfLabel *Label); + DenseMap &getScopeVariables() { return ScopeVariables; } + DenseMap &getScopeLabels() { + return ScopeLabels; + } + DenseMap &getAbstractSPDies() { return AbstractSPDies; } @@ -129,6 +141,10 @@ return AbstractVariables; } + DenseMap> &getAbstractLabels() { + return AbstractLabels; + } + void insertDIE(const MDNode *TypeMD, DIE *Die) { DITypeNodeToDieMap.insert(std::make_pair(TypeMD, Die)); } Index: lib/CodeGen/AsmPrinter/DwarfFile.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfFile.cpp +++ lib/CodeGen/AsmPrinter/DwarfFile.cpp @@ -118,3 +118,8 @@ } return true; } + +void DwarfFile::addScopeLabel(LexicalScope *LS, DwarfLabel *Label) { + SmallVectorImpl &Labels = ScopeLabels[LS]; + Labels.push_back(Label); +} Index: lib/CodeGen/AsmPrinter/DwarfUnit.h =================================================================== --- lib/CodeGen/AsmPrinter/DwarfUnit.h +++ lib/CodeGen/AsmPrinter/DwarfUnit.h @@ -211,6 +211,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: lib/CodeGen/AsmPrinter/DwarfUnit.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -404,6 +404,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: test/DebugInfo/Generic/debug-label-inline.ll =================================================================== --- /dev/null +++ test/DebugInfo/Generic/debug-label-inline.ll @@ -0,0 +1,65 @@ +; 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 !6 { +entry: + %0 = load i32, i32* @ga, align 4, !dbg !13 + %1 = load i32, i32* @gb, align 4, !dbg !13 + call void @llvm.dbg.value(metadata i32 %0, metadata !18, metadata !DIExpression()), !dbg !27 + call void @llvm.dbg.value(metadata i32 %1, metadata !23, metadata !DIExpression()), !dbg !27 + call void @llvm.dbg.label(metadata !26), !dbg !29 + %add.i = add nsw i32 %1, %0, !dbg !30 + call void @llvm.dbg.value(metadata i32 %add.i, metadata !24, metadata !DIExpression()), !dbg !31 + call void @llvm.dbg.value(metadata i32 %add.i, metadata !12, metadata !DIExpression()), !dbg !32 + ret i32 %add.i, !dbg !33 +} + +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, !4} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !7, isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) +!2 = !{} +!3 = !{i32 2, !"Debug Info Version", i32 3} +!4 = !{i32 1, !"wchar_size", i32 4} +!6 = distinct !DISubprogram(name: "f2", scope: !7, file: !7, line: 15, type: !8, isLocal: false, isDefinition: true, scopeLine: 15, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !11, labels: !2) +!7 = !DIFile(filename: "debug-label-inline.c", directory: "./") +!8 = !DISubroutineType(types: !9) +!9 = !{!10} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !{!12} +!12 = !DILocalVariable(name: "result", scope: !6, file: !7, line: 16, type: !10) +!13 = !DILocation(line: 18, scope: !6) +!18 = !DILocalVariable(name: "a", arg: 1, scope: !19, file: !7, line: 5, type: !10) +!19 = distinct !DISubprogram(name: "f1", scope: !7, file: !7, line: 5, type: !20, isLocal: false, isDefinition: true, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !22, labels: !25) +!20 = !DISubroutineType(types: !21) +!21 = !{!10, !10, !10} +!22 = !{!18, !23, !24} +!23 = !DILocalVariable(name: "b", arg: 2, scope: !19, file: !7, line: 5, type: !10) +!24 = !DILocalVariable(name: "sum", scope: !19, file: !7, line: 6, type: !10) +!25 = !{!26} +!26 = !DILabel(scope: !19, name: "top", file: !7, line: 8) +!27 = !DILocation(line: 5, scope: !19, inlinedAt: !28) +!28 = distinct !DILocation(line: 18, scope: !6) +!29 = !DILocation(line: 8, scope: !19, inlinedAt: !28) +!30 = !DILocation(line: 9, scope: !19, inlinedAt: !28) +!31 = !DILocation(line: 6, scope: !19, inlinedAt: !28) +!32 = !DILocation(line: 16, scope: !6) +!33 = !DILocation(line: 21, scope: !6) Index: test/DebugInfo/Generic/debug-label.ll =================================================================== --- /dev/null +++ test/DebugInfo/Generic/debug-label.ll @@ -0,0 +1,78 @@ +; RUN: llc -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 -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 = !{!3, !4, !5} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) +!1 = !DIFile(filename: "debug-label.c", directory: "./") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !7, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !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)