[llvm] Implement S_INLINEES debug symbol (#67490)

The `S_INLINEES` debug symbol is used to record all the functions that
are directly inlined within the current function (nested inlining is
ignored).

This change implements support for emitting the `S_INLINEES` debug
symbol in LLVM, and cleans up how the `S_INLINEES` and `S_CALLEES` debug
symbols are dumped.
This commit is contained in:
Daniel Paoliello 2023-09-27 14:06:22 -07:00 committed by GitHub
parent a82368ca7b
commit 050bb26174
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 138 additions and 4 deletions

View File

@ -226,6 +226,7 @@ public:
Error visitKnownRecord(CVSymbol &Record, UDTSym &UDT) override;
Error visitKnownRecord(CVSymbol &Record, UsingNamespaceSym &UN) override;
Error visitKnownRecord(CVSymbol &Record, JumpTableSym &JumpTable) override;
Error visitKnownRecord(CVSymbol &Record, CallerSym &Caller) override;
};
// Visitor for CodeView types and symbols to populate elements.

View File

@ -250,7 +250,10 @@ CodeViewDebug::getInlineSite(const DILocation *InlinedAt,
InlinedAt->getLine(), InlinedAt->getColumn(), SMLoc());
Site->Inlinee = Inlinee;
InlinedSubprograms.insert(Inlinee);
getFuncIdForSubprogram(Inlinee);
auto InlineeIdx = getFuncIdForSubprogram(Inlinee);
if (InlinedAt->getInlinedAt() == nullptr)
CurFn->Inlinees.insert(InlineeIdx);
}
return *Site;
}
@ -1194,6 +1197,7 @@ void CodeViewDebug::emitDebugInfoForFunction(const Function *GV,
OS.emitInt32(uint32_t(FI.FrameProcOpts));
endSymbolRecord(FrameProcEnd);
emitInlinees(FI.Inlinees);
emitLocalVariableList(FI, FI.Locals);
emitGlobalVariableList(FI.Globals);
emitLexicalBlockList(FI.ChildBlocks, FI);
@ -3588,3 +3592,31 @@ void CodeViewDebug::emitDebugInfoForJumpTables(const FunctionInfo &FI) {
endSymbolRecord(JumpTableEnd);
}
}
void CodeViewDebug::emitInlinees(
const SmallSet<codeview::TypeIndex, 1> &Inlinees) {
// Divide the list of inlinees into chunks such that each chunk fits within
// one record.
constexpr auto ChunkSize =
(MaxRecordLength - sizeof(SymbolKind) - sizeof(uint32_t)) /
sizeof(uint32_t);
SmallVector<TypeIndex> SortedInlinees{Inlinees.begin(), Inlinees.end()};
llvm::sort(SortedInlinees);
uint64_t CurrentIndex = 0;
while (CurrentIndex < SortedInlinees.size()) {
auto Symbol = beginSymbolRecord(SymbolKind::S_INLINEES);
auto CurrentChunkSize =
std::min(ChunkSize, SortedInlinees.size() - CurrentIndex);
OS.AddComment("Count");
OS.emitInt32(CurrentChunkSize);
const uint64_t CurrentChunkEnd = CurrentIndex + CurrentChunkSize;
for (; CurrentIndex < CurrentChunkEnd; ++CurrentIndex) {
OS.AddComment("Inlinee");
OS.emitInt32(SortedInlinees[CurrentIndex].getIndex());
}
endSymbolRecord(Symbol);
}
}

View File

@ -20,6 +20,7 @@
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/CodeGen/DbgEntityHistoryCalculator.h"
#include "llvm/CodeGen/DebugHandlerBase.h"
@ -158,6 +159,9 @@ private:
/// Ordered list of top-level inlined call sites.
SmallVector<const DILocation *, 1> ChildSites;
/// Set of all functions directly inlined into this one.
SmallSet<codeview::TypeIndex, 1> Inlinees;
SmallVector<LocalVariable, 1> Locals;
SmallVector<CVGlobalVariable, 1> Globals;
@ -371,6 +375,8 @@ private:
void emitInlinedCallSite(const FunctionInfo &FI, const DILocation *InlinedAt,
const InlineSite &Site);
void emitInlinees(const SmallSet<codeview::TypeIndex, 1> &Inlinees);
using InlinedEntity = DbgValueHistoryMap::InlinedEntity;
void collectGlobalVariableInfo();

View File

@ -589,7 +589,22 @@ Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
}
Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, CallerSym &Caller) {
ListScope S(W, CVR.kind() == S_CALLEES ? "Callees" : "Callers");
llvm::StringRef ScopeName;
switch (CVR.kind()) {
case S_CALLEES:
ScopeName = "Callees";
break;
case S_CALLERS:
ScopeName = "Callers";
break;
case S_INLINEES:
ScopeName = "Inlinees";
break;
default:
return llvm::make_error<CodeViewError>(
"Unknown CV Record type for a CallerSym object!");
}
ListScope S(W, ScopeName);
for (auto FuncID : Caller.Indices)
printTypeIndex("FuncID", FuncID);
return Error::success();

View File

@ -1705,6 +1705,31 @@ Error LVSymbolVisitor::visitKnownRecord(CVSymbol &CVR,
return Error::success();
}
// S_CALLERS, S_CALLEES, S_INLINEES
Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record, CallerSym &Caller) {
LLVM_DEBUG({
llvm::StringRef FieldName;
switch (Caller.getKind()) {
case SymbolRecordKind::CallerSym:
FieldName = "Callee";
break;
case SymbolRecordKind::CalleeSym:
FieldName = "Caller";
break;
case SymbolRecordKind::InlineesSym:
FieldName = "Inlinee";
break;
default:
return llvm::make_error<CodeViewError>(
"Unknown CV Record type for a CallerSym object!");
}
for (auto FuncID : Caller.Indices) {
printTypeIndex(FieldName, FuncID);
}
});
return Error::success();
}
#undef DEBUG_TYPE
#define DEBUG_TYPE "CodeViewLogicalVisitor"

View File

@ -21,6 +21,12 @@
; OBJ: {{.*}}Proc{{.*}}Sym {
; OBJ: DisplayName: f
; OBJ: }
; OBJ: InlineesSym {
; OBJ-NEXT: Kind: S_INLINEES (0x1168)
; OBJ-NEXT: Inlinees [
; OBJ-NEXT: FuncID: file_change (0x1002)
; OBJ-NEXT: ]
; OBJ-NEXT:}
; OBJ: InlineSiteSym {
; OBJ: PtrParent: 0x0
; OBJ: PtrEnd: 0x0

View File

@ -75,6 +75,13 @@
; OBJ: LinkageName: _main
; OBJ: }
; OBJ: InlineesSym {
; OBJ-NEXT: Kind: S_INLINEES (0x1168)
; OBJ-NEXT: Inlinees [
; OBJ-NEXT: FuncID: g (0x1002)
; OBJ-NEXT: ]
; OBJ-NEXT: }
; Previously, g's InlineSiteSym referenced t.h, which was wasteful.
; OBJ: InlineSiteSym {
; OBJ: Inlinee: g (0x1002)

View File

@ -19,6 +19,12 @@
; OBJ: Subsection [
; OBJ: SubSectionType: Symbols (0xF1)
; OBJ: {{.*}}Proc{{.*}}Sym {
; OBJ: InlineesSym {
; OBJ-NEXT: Kind: S_INLINEES (0x1168)
; OBJ-NEXT: Inlinees [
; OBJ-NEXT: FuncID: h (0x1002)
; OBJ-NEXT: ]
; OBJ-NEXT:}
; OBJ: InlineSiteSym {
; OBJ: Inlinee: h (0x1002)
; OBJ: }

View File

@ -33,6 +33,15 @@
; CHECK: )
; CHECK: }
; CHECK: InlineesSym {
; CHECK-NEXT: Kind: S_INLINEES (0x1168)
; CHECK-NEXT: Inlinees [
; CHECK-NEXT: FuncID: a (0x1002)
; CHECK-NEXT: FuncID: ab (0x1003)
; CHECK-NEXT: FuncID: abc (0x1004)
; CHECK-NEXT: FuncID: abcd (0x1005)
; CHECK-NEXT: ]
; C++ source used to generate the IR:
;
; extern volatile int x;

View File

@ -18,6 +18,12 @@
; CHECK: {{.*}}Proc{{.*}}Sym {
; CHECK: DisplayName: main
; CHECK: }
; CHECK: InlineesSym {
; CHECK-NEXT: Kind: S_INLINEES (0x1168)
; CHECK-NEXT: Inlinees [
; CHECK-NEXT: FuncID: same_name (0x1002)
; CHECK-NEXT: ]
; CHECK-NEXT:}
; CHECK: InlineSiteSym {
; CHECK: Inlinee: same_name (0x1002)
; CHECK: }

View File

@ -166,6 +166,12 @@
; OBJ: DisplayName: baz
; OBJ: LinkageName: ?baz@@YAXXZ
; OBJ: }
; OBJ: InlineesSym {
; OBJ-NEXT: Kind: S_INLINEES (0x1168)
; OBJ-NEXT: Inlinees [
; OBJ-NEXT: FuncID: bar (0x1002)
; OBJ-NEXT: ]
; OBJ-NEXT:}
; OBJ: InlineSiteSym {
; OBJ: PtrParent: 0x0
; OBJ: PtrEnd: 0x0

View File

@ -28,7 +28,7 @@ CHECK: Kind: S_INLINESITE (0x114D)
CHECK: Inlinee: f (0x1003)
CHECK: InlineesSym {
CHECK-NEXT: Kind: S_INLINEES (0x1168)
CHECK-NEXT: Callers [
CHECK-NEXT: Inlinees [
CHECK-NEXT: FuncID: f (0x1003)
CHECK-NEXT: FuncID: h (0x1004)
CHECK-NEXT: ]

View File

@ -875,9 +875,24 @@ Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
}
Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, CallerSym &Caller) {
const char *Format;
switch (CVR.kind()) {
case S_CALLEES:
Format = "callee: {0}";
break;
case S_CALLERS:
Format = "caller: {0}";
break;
case S_INLINEES:
Format = "inlinee: {0}";
break;
default:
return llvm::make_error<CodeViewError>(
"Unknown CV Record type for a CallerSym object!");
}
AutoIndent Indent(P, 7);
for (const auto &I : Caller.Indices) {
P.formatLine("callee: {0}", idIndex(I));
P.formatLine(Format, idIndex(I));
}
return Error::success();
}