This patch adds basic debug info support with basic block sections.

This patch uses ranges for debug information when a function contains basic block sections rather than using [lowpc, highpc]. This is also the first in a series of patches for debug info and does not contain the support for linker relaxation. That will be done as a follow up patch.

Differential Revision: https://reviews.llvm.org/D78851
This commit is contained in:
Krzysztof Pszeniczny 2020-07-01 23:47:30 -07:00 committed by Sriraman Tallam
parent fdbd78333f
commit e4b3c138de
9 changed files with 179 additions and 6 deletions

View File

@ -126,6 +126,14 @@ public:
/// default, this is equal to CurrentFnSym.
MCSymbol *CurrentFnSymForSize = nullptr;
/// Map a basic block section ID to the begin and end symbols of that section
/// which determine the section's range.
struct MBBSectionRange {
MCSymbol *BeginLabel, *EndLabel;
};
MapVector<unsigned, MBBSectionRange> MBBSectionRanges;
/// Map global GOT equivalent MCSymbols to GlobalVariables and keep track of
/// its number of uses by other globals.
using GOTEquivUsePair = std::pair<const GlobalVariable *, unsigned>;

View File

@ -67,6 +67,12 @@ public:
/// Process end of an instruction.
virtual void endInstruction() = 0;
/// Process beginning of a basic block during basic block sections.
virtual void beginBasicBlock(const MachineBasicBlock &MBB) {}
/// Process end of a basic block during basic block sections.
virtual void endBasicBlock(const MachineBasicBlock &MBB) {}
};
} // End of namespace llvm

View File

@ -118,6 +118,9 @@ public:
void beginFunction(const MachineFunction *MF) override;
void endFunction(const MachineFunction *MF) override;
void beginBasicBlock(const MachineBasicBlock &MBB) override;
void endBasicBlock(const MachineBasicBlock &MBB) override;
/// Return Label preceding the instruction.
MCSymbol *getLabelBeforeInsn(const MachineInstr *MI);

View File

@ -465,6 +465,12 @@ public:
/// Returns the section ID of this basic block.
MBBSectionID getSectionID() const { return SectionID; }
/// Returns the unique section ID number of this basic block.
unsigned getSectionIDNum() const {
return ((unsigned)MBBSectionID::SectionType::Cold) -
((unsigned)SectionID.Type) + SectionID.Number;
}
/// Sets the section ID for this basic block.
void setSectionID(MBBSectionID V) { SectionID = V; }

View File

@ -1207,6 +1207,8 @@ void AsmPrinter::emitFunctionBody() {
if (!MBB.sameSection(&MF->front())) {
if (MAI->hasDotTypeDotSizeDirective())
emitELFSizeDirective(CurrentSectionBeginSym);
MBBSectionRanges[MBB.getSectionIDNum()] =
MBBSectionRange{CurrentSectionBeginSym, CurrentBBEnd};
}
}
emitBasicBlockEnd(MBB);
@ -1283,6 +1285,8 @@ void AsmPrinter::emitFunctionBody() {
HI.Handler->markFunctionEnd();
}
MBBSectionRanges[MF->front().getSectionIDNum()] =
MBBSectionRange{CurrentFnBegin, CurrentFnEnd};
// Print out jump tables referenced by the function.
emitJumpTableInfo();
@ -1782,6 +1786,7 @@ void AsmPrinter::SetupMachineFunction(MachineFunction &MF) {
CurrentFnSymForSize = CurrentFnSym;
CurrentFnBegin = nullptr;
CurrentSectionBeginSym = nullptr;
MBBSectionRanges.clear();
CurExceptionSym = nullptr;
bool NeedsLocalForSize = MAI->needsLocalForSize();
if (F.hasFnAttribute("patchable-function-entry") ||

View File

@ -327,3 +327,17 @@ void DebugHandlerBase::endFunction(const MachineFunction *MF) {
LabelsBeforeInsn.clear();
LabelsAfterInsn.clear();
}
void DebugHandlerBase::beginBasicBlock(const MachineBasicBlock &MBB) {
if (!MBB.isBeginSection())
return;
PrevLabel = MBB.getSymbol();
}
void DebugHandlerBase::endBasicBlock(const MachineBasicBlock &MBB) {
if (!MBB.isEndSection())
return;
PrevLabel = nullptr;
}

View File

@ -396,7 +396,14 @@ void DwarfCompileUnit::attachLowHighPC(DIE &D, const MCSymbol *Begin,
DIE &DwarfCompileUnit::updateSubprogramScopeDIE(const DISubprogram *SP) {
DIE *SPDie = getOrCreateSubprogramDIE(SP, includeMinimalInlineScopes());
attachLowHighPC(*SPDie, Asm->getFunctionBegin(), Asm->getFunctionEnd());
SmallVector<RangeSpan, 2> BB_List;
// If basic block sections are on, ranges for each basic block section has
// to be emitted separately.
for (const auto &R : Asm->MBBSectionRanges)
BB_List.push_back({R.second.BeginLabel, R.second.EndLabel});
attachRangesOrLowHighPC(*SPDie, BB_List);
if (DD->useAppleExtensionAttributes() &&
!DD->getCurrentFunction()->getTarget().Options.DisableFramePointerElim(
*DD->getCurrentFunction()))
@ -570,9 +577,33 @@ void DwarfCompileUnit::attachRangesOrLowHighPC(
DIE &Die, const SmallVectorImpl<InsnRange> &Ranges) {
SmallVector<RangeSpan, 2> List;
List.reserve(Ranges.size());
for (const InsnRange &R : Ranges)
List.push_back(
{DD->getLabelBeforeInsn(R.first), DD->getLabelAfterInsn(R.second)});
for (const InsnRange &R : Ranges) {
auto *BeginLabel = DD->getLabelBeforeInsn(R.first);
auto *EndLabel = DD->getLabelAfterInsn(R.second);
const auto *BeginMBB = R.first->getParent();
const auto *EndMBB = R.second->getParent();
const auto *MBB = BeginMBB;
// Basic block sections allows basic block subsets to be placed in unique
// sections. For each section, the begin and end label must be added to the
// list. If there is more than one range, debug ranges must be used.
// Otherwise, low/high PC can be used.
// FIXME: Debug Info Emission depends on block order and this assumes that
// the order of blocks will be frozen beyond this point.
do {
if (MBB->sameSection(EndMBB) || MBB->isEndSection()) {
auto MBBSectionRange = Asm->MBBSectionRanges[MBB->getSectionIDNum()];
List.push_back(
{MBB->sameSection(BeginMBB) ? BeginLabel
: MBBSectionRange.BeginLabel,
MBB->sameSection(EndMBB) ? EndLabel : MBBSectionRange.EndLabel});
}
if (MBB->sameSection(EndMBB))
break;
MBB = MBB->getNextNode();
} while (true);
}
attachRangesOrLowHighPC(Die, std::move(List));
}

View File

@ -1664,7 +1664,8 @@ bool DwarfDebug::buildLocationList(SmallVectorImpl<DebugLocEntry> &DebugLoc,
const MCSymbol *EndLabel;
if (std::next(EI) == Entries.end()) {
EndLabel = Asm->getFunctionEnd();
const MachineBasicBlock &EndMBB = Asm->MF->back();
EndLabel = Asm->MBBSectionRanges[EndMBB.getSectionIDNum()].EndLabel;
if (EI->isClobber())
EndMI = EI->getInstr();
}
@ -2115,7 +2116,9 @@ void DwarfDebug::endFunctionImpl(const MachineFunction *MF) {
collectEntityInfo(TheCU, SP, Processed);
// Add the range of this function to the list of ranges for the CU.
TheCU.addRange({Asm->getFunctionBegin(), Asm->getFunctionEnd()});
// With basic block sections, add ranges for all basic block sections.
for (const auto &R : Asm->MBBSectionRanges)
TheCU.addRange({R.second.BeginLabel, R.second.EndLabel});
// Under -gmlt, skip building the subprogram if there are no inlined
// subroutines inside it. But with -fdebug-info-for-profiling, the subprogram

View File

@ -0,0 +1,97 @@
; RUN: llc -O0 %s -mtriple=x86_64-* -filetype=obj -o %t && llvm-dwarfdump -debug-info -v %t | FileCheck --check-prefix=NO-SECTIONS %s
; RUN: llc -O0 %s --basicblock-sections=all --unique-bb-section-names -mtriple=x86_64-* -filetype=obj -o %t && llvm-dwarfdump -debug-info -v %t | FileCheck --check-prefix=BB-SECTIONS %s
; RUN: llc -O0 %s --basicblock-sections=all --unique-bb-section-names -mtriple=x86_64-* -filetype=obj -split-dwarf-file=%t.dwo -o %t && llvm-dwarfdump -debug-info -v %t | FileCheck --check-prefix=BB-SECTIONS %s
; RUN: llc -O0 %s --basicblock-sections=all -mtriple=x86_64-* -filetype=asm -o - | FileCheck --check-prefix=BB-SECTIONS-ASM %s
; From:
; int foo(int a) {
; if (a > 20)
; return 2;
; else
; return 0;
; }
; NO-SECTIONS: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000 ".text")
; NO-SECTIONS: DW_AT_high_pc [DW_FORM_data4] ({{.*}})
; BB-SECTIONS: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000)
; BB-SECTIONS-NEXT: DW_AT_ranges [DW_FORM_sec_offset]
; BB-SECTIONS-NEXT: [{{.*}}) ".text._Z3fooi.1"
; BB-SECTIONS-NEXT: [{{.*}}) ".text._Z3fooi.2"
; BB-SECTIONS-NEXT: [{{.*}}) ".text._Z3fooi.3"
; BB-SECTIONS-NEXT: [{{.*}}) ".text"
; BB-SECTIONS-ASM: _Z3fooi:
; BB-SECTIONS-ASM: .Ltmp{{[0-9]+}}:
; BB-SECTIONS-ASM-NEXT: .loc 1 2 9 prologue_end
; BB-SECTIONS-ASM: .Ltmp{{[0-9]+}}:
; BB-SECTIONS-ASM-NEXT: .loc 1 2 7 is_stmt
; BB-SECTIONS-ASM: _Z3fooi.1:
; BB-SECTIONS-ASM: .Ltmp{{[0-9]+}}:
; BB-SECTIONS-ASM: .size _Z3fooi.1, .Ltmp{{[0-9]+}}-_Z3fooi.1
; BB-SECTIONS-ASM: _Z3fooi.2:
; BB-SECTIONS-ASM: .Ltmp{{[0-9]+}}:
; BB-SECTIONS-ASM-NEXT: .Ltmp{{[0-9]+}}:
; BB-SECTIONS-ASM: .size _Z3fooi.2, .Ltmp{{[0-9]+}}-_Z3fooi.2
; BB-SECTIONS-ASM: _Z3fooi.3:
; BB-SECTIONS-ASM: .Ltmp{{[0-9]+}}:
; BB-SECTIONS-ASM-NEXT: .Ltmp{{[0-9]+}}:
; BB-SECTIONS-ASM: .size _Z3fooi.3, .Ltmp{{[0-9]+}}-_Z3fooi.3
; BB-SECTIONS-ASM: .Lfunc_end0:
; BB-SECTIONS-ASM: .Ldebug_ranges0:
; BB-SECTIONS-ASM-NEXT: .quad _Z3fooi.1
; BB-SECTIONS-ASM-NEXT: .quad .Ltmp{{[0-9]+}}
; BB-SECTIONS-ASM-NEXT: .quad _Z3fooi.2
; BB-SECTIONS-ASM-NEXT: .quad .Ltmp{{[0-9]+}}
; BB-SECTIONS-ASM-NEXT: .quad _Z3fooi.3
; BB-SECTIONS-ASM-NEXT: .quad .Ltmp{{[0-9]+}}
; BB-SECTIONS-ASM-NEXT: .quad .Lfunc_begin0
; BB-SECTIONS-ASM-NEXT: .quad .Lfunc_end0
; BB-SECTIONS-ASM-NEXT: .quad 0
; BB-SECTIONS-ASM-NEXT: .quad 0
; Function Attrs: noinline nounwind optnone uwtable
define dso_local i32 @_Z3fooi(i32 %0) !dbg !7 {
%2 = alloca i32, align 4
%3 = alloca i32, align 4
store i32 %0, i32* %3, align 4
call void @llvm.dbg.declare(metadata i32* %3, metadata !11, metadata !DIExpression()), !dbg !12
%4 = load i32, i32* %3, align 4, !dbg !13
%5 = icmp sgt i32 %4, 20, !dbg !15
br i1 %5, label %6, label %7, !dbg !16
6: ; preds = %1
store i32 2, i32* %2, align 4, !dbg !17
br label %8, !dbg !17
7: ; preds = %1
store i32 0, i32* %2, align 4, !dbg !18
br label %8, !dbg !18
8: ; preds = %7, %6
%9 = load i32, i32* %2, align 4, !dbg !19
ret i32 %9, !dbg !19
}
; Function Attrs: nounwind readnone speculatable willreturn
declare void @llvm.dbg.declare(metadata, metadata, metadata)
!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!3, !4}
!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 10.0.0 (git@github.com:google/llvm-propeller.git f9421ebf4b3d8b64678bf6c49d1607fdce3f50c5)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
!1 = !DIFile(filename: "debuginfo.cc", directory: "/")
!2 = !{}
!3 = !{i32 2, !"Dwarf Version", i32 4}
!4 = !{i32 2, !"Debug Info Version", i32 3}
!7 = distinct !DISubprogram(name: "foo", linkageName: "_Z3fooi", scope: !1, file: !1, line: 1, type: !8, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2)
!8 = !DISubroutineType(types: !9)
!9 = !{!10, !10}
!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
!11 = !DILocalVariable(name: "a", arg: 1, scope: !7, file: !1, line: 1, type: !10)
!12 = !DILocation(line: 1, column: 13, scope: !7)
!13 = !DILocation(line: 2, column: 7, scope: !14)
!14 = distinct !DILexicalBlock(scope: !7, file: !1, line: 2, column: 7)
!15 = !DILocation(line: 2, column: 9, scope: !14)
!16 = !DILocation(line: 2, column: 7, scope: !7)
!17 = !DILocation(line: 3, column: 5, scope: !14)
!18 = !DILocation(line: 5, column: 5, scope: !14)
!19 = !DILocation(line: 6, column: 1, scope: !7)