Skip to content

Commit 1d1069f

Browse files
author
Yonghong Song
committed
[LLVM] Emit dwarf data for changed-signature and new functions
Add a new pass EmitChangedFuncDebugInfo which will add dwarf for additional functions including functions with signature change and new functions. The previous approach in [1] tries to add debuginfo for those optimization passes which cause signature changes. Based on discussion in [1], it is preferred to have a specific pass to add debuginfo and later on dwarf generation can include those new debuginfo. The ultimate goal is to add new information to dwarf like below: DW_TAG_compile_unit ... // New functions with suffix DW_TAG_inlined_subroutine DW_AT_name ("foo.1") DW_AT_type (0x0000000000000091 "int") DW_AT_artificial (true) DW_AT_specificiation (original DW_TAG_subprogram) DW_TAG_formal_parameter DW_AT_name ("b") DW_AT_type (0x0000000000000091 "int") DW_TAG_formal_parameter DW_AT_name ("c") DW_AT_type (0x0000000000000095 "long") ... // Functions with changed signatures DW_TAG_inlined_subroutine DW_AT_name ("bar") DW_AT_type (0x0000000000000091 "int") DW_AT_artificial (true) DW_AT_specificiation (original DW_TAG_subprogram) DW_TAG_formal_parameter DW_AT_name ("c") DW_AT_type (0x0000000000000095 "unsigned int") ... // Functions not obtained function changed signatures yet // The DW_CC_nocall presence indicates such cases. DW_TAG_inlined_subroutine DW_AT_name ("bar" or "bar.1") DW_AT_calling_convention (DW_CC_nocall) DW_AT_artificial (true) DW_AT_specificiation (original DW_TAG_subprogram) The parent tag of above DW_TAG_inlined_subroutine is DW_TAG_compile_unit. This is a new feature for dwarf so it won't cause issues with existing dwarf related tools. Total three patterns are introduced as the above. . New functions with suffix, e.g., 'foo.1' or 'foo.llvm.<hash>'. . Functions with changed signature due to ArgumentPromotion or DeadArgumentElimination. . Functions the current implementation cannot get proper signature. For this case, DW_CC_nocall is set to indicate signature is lost. More details in the below. A special CompileUnit with file name "<artificial>" is created to hold special DISubprograms for the above three kinds of functions. During actual dwarf generation, these special DISubprograms will turn to above to proper DW_TAG_inlined_subroutine tags. The below are some discussions with not handled cases and some other alternative things: (1) Currently, there are three not handled signature changes. . During to ArgumentPromotion, we may have foo(..., struct foo *p, ...) => foo(..., int p.0.val, int p.4.val, ...) . Struct argument which expands to two actual arguments, foo(..., struct foo v, ...) => foo(..., v.coerce0, v.coerce1, ...) . Struct argument changed to struct pointer, foo(..., struct foo v, ...) => foo(..., struct foo *p, ...) I think by utilizing dbg_value/dbg_declare and instructions, we might be able to resolve the above and get proper signature. But any suggestions are welcome. (2) Currently, I am using a special CompileUnit "<artificial>" to hold newly created DISubprograms. But there is an alternative. For example, "llvm.dbg.cu" metadata is used to hold all CompileUnits. We could introduce "llvm.dbg.sp.extra" to hold all new DISubprograms instead of a new CompileUnit. I have tested this patch set by building latest bpf-next linux kernel. For no-lto case: 65288 original number of functions 910 new functions with this patch (including DW_CC_nocall case) 7 new functions without signatures (with DW_CC_nocall) For thin-lto case: 65541 original number of functions 2324 new functions with this patch (including DW_CC_nocall case) 14 new functions without signatures (with DW_CC_nocall) The following are some examples with thinlto with generated dwarf: ... 0x0001707f: DW_TAG_inlined_subroutine DW_AT_name ("msr_build_context") DW_AT_type (0x00004163 "int") DW_AT_artificial (true) DW_AT_specification (0x0000440b "msr_build_context") 0x0001708b: DW_TAG_formal_parameter DW_AT_name ("msr_id") DW_AT_type (0x0000e55c "const u32 *") 0x00017093: NULL ... 0x004225e5: DW_TAG_inlined_subroutine DW_AT_name ("__die_body.llvm.14794269134614576759") DW_AT_type (0x00418a14 "int") DW_AT_artificial (true) DW_AT_specification (0x00422348 "__die_body") 0x004225f1: DW_TAG_formal_parameter DW_AT_name ("") DW_AT_type (0x004181f3 "const char *") 0x004225f9: DW_TAG_formal_parameter DW_AT_name ("") DW_AT_type (0x00419118 "pt_regs *") 0x00422601: DW_TAG_formal_parameter DW_AT_name ("") DW_AT_type (0x0041af2f "long") 0x00422609: NULL ... 0x013f5dac: DW_TAG_inlined_subroutine DW_AT_name ("devkmsg_emit") DW_AT_calling_convention (DW_CC_nocall) DW_AT_artificial (true) DW_AT_specification (0x013ef75b "devkmsg_emit") [1] #127855
1 parent 0455f8d commit 1d1069f

12 files changed

+474
-3
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//===- EmitChangedFuncDebugInfo.h - Emit Additional Debug Info -*- C++ --*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
/// \file
10+
/// Emit debug info for changed or new funcs.
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef LLVM_TRANSFORMS_UTILS_EMITCHANGEDFUNCDEBUGINFO_H
14+
#define LLVM_TRANSFORMS_UTILS_EMITCHANGEDFUNCDEBUGINFO_H
15+
16+
#include "llvm/IR/PassManager.h"
17+
18+
namespace llvm {
19+
20+
class Module;
21+
22+
// Pass that emits late dwarf.
23+
class EmitChangedFuncDebugInfoPass
24+
: public PassInfoMixin<EmitChangedFuncDebugInfoPass> {
25+
public:
26+
EmitChangedFuncDebugInfoPass() = default;
27+
28+
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
29+
};
30+
31+
} // end namespace llvm
32+
33+
#endif // LLVM_TRANSFORMS_UTILS_EMITCHANGEDFUNCDEBUGINFO_H

llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1266,11 +1266,83 @@ void DwarfDebug::finishSubprogramDefinitions() {
12661266
}
12671267
}
12681268

1269+
void DwarfDebug::addChangedSubprograms() {
1270+
// Generate additional dwarf for functions with signature changed.
1271+
NamedMDNode *NMD = MMI->getModule()->getNamedMetadata("llvm.dbg.cu");
1272+
DICompileUnit *ExtraCU = nullptr;
1273+
for (MDNode *N : NMD->operands()) {
1274+
auto *CU = dyn_cast<DICompileUnit>(N);
1275+
if (CU && CU->getFile()->getFilename() == "<artificial>") {
1276+
ExtraCU = CU;
1277+
break;
1278+
}
1279+
}
1280+
if (!ExtraCU)
1281+
return;
1282+
1283+
llvm::DebugInfoFinder DIF;
1284+
DIF.processModule(*MMI->getModule());
1285+
for (auto *ExtraSP : DIF.subprograms()) {
1286+
if (ExtraSP->getUnit() != ExtraCU)
1287+
continue;
1288+
1289+
DISubprogram *SP = cast<DISubprogram>(ExtraSP->getScope());
1290+
DwarfCompileUnit &Cu = getOrCreateDwarfCompileUnit(SP->getUnit());
1291+
DIE *ScopeDIE =
1292+
DIE::get(DIEValueAllocator, dwarf::DW_TAG_inlined_subroutine);
1293+
Cu.getUnitDie().addChild(ScopeDIE);
1294+
1295+
Cu.addString(*ScopeDIE, dwarf::DW_AT_name, ExtraSP->getName());
1296+
1297+
DITypeRefArray Args = ExtraSP->getType()->getTypeArray();
1298+
1299+
if (Args[0])
1300+
Cu.addType(*ScopeDIE, Args[0]);
1301+
1302+
if (ExtraSP->getType()->getCC() == llvm::dwarf::DW_CC_nocall) {
1303+
Cu.addUInt(*ScopeDIE, dwarf::DW_AT_calling_convention,
1304+
dwarf::DW_FORM_data1, llvm::dwarf::DW_CC_nocall);
1305+
}
1306+
1307+
Cu.addFlag(*ScopeDIE, dwarf::DW_AT_artificial);
1308+
1309+
// dereference the DIE* for DIEEntry
1310+
DIE *OriginDIE = Cu.getOrCreateSubprogramDIE(SP);
1311+
Cu.addDIEEntry(*ScopeDIE, dwarf::DW_AT_specification, DIEEntry(*OriginDIE));
1312+
1313+
SmallVector<const DILocalVariable *> ArgVars(Args.size());
1314+
for (const DINode *DN : ExtraSP->getRetainedNodes()) {
1315+
if (const auto *DV = dyn_cast<DILocalVariable>(DN)) {
1316+
uint32_t Arg = DV->getArg();
1317+
if (Arg)
1318+
ArgVars[Arg - 1] = DV;
1319+
}
1320+
}
1321+
1322+
for (unsigned i = 1, N = Args.size(); i < N; ++i) {
1323+
const DIType *Ty = Args[i];
1324+
if (!Ty) {
1325+
assert(i == N - 1 && "Unspecified parameter must be the last argument");
1326+
Cu.createAndAddDIE(dwarf::DW_TAG_unspecified_parameters, *ScopeDIE);
1327+
} else {
1328+
DIE &Arg =
1329+
Cu.createAndAddDIE(dwarf::DW_TAG_formal_parameter, *ScopeDIE);
1330+
const DILocalVariable *DV = ArgVars[i - 1];
1331+
if (DV)
1332+
Cu.addString(Arg, dwarf::DW_AT_name, DV->getName());
1333+
Cu.addType(Arg, Ty);
1334+
}
1335+
}
1336+
}
1337+
}
1338+
12691339
void DwarfDebug::finalizeModuleInfo() {
12701340
const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering();
12711341

12721342
finishSubprogramDefinitions();
12731343

1344+
addChangedSubprograms();
1345+
12741346
finishEntityDefinitions();
12751347

12761348
bool HasEmittedSplitCU = false;

llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,8 @@ class DwarfDebug : public DebugHandlerBase {
565565

566566
void finishSubprogramDefinitions();
567567

568+
void addChangedSubprograms();
569+
568570
/// Finish off debug information after all functions have been
569571
/// processed.
570572
void finalizeModuleInfo();

llvm/lib/Passes/PassBuilder.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,7 @@
347347
#include "llvm/Transforms/Utils/DXILUpgrade.h"
348348
#include "llvm/Transforms/Utils/Debugify.h"
349349
#include "llvm/Transforms/Utils/DeclareRuntimeLibcalls.h"
350+
#include "llvm/Transforms/Utils/EmitChangedFuncDebugInfo.h"
350351
#include "llvm/Transforms/Utils/EntryExitInstrumenter.h"
351352
#include "llvm/Transforms/Utils/FixIrreducible.h"
352353
#include "llvm/Transforms/Utils/HelloWorld.h"

llvm/lib/Passes/PassBuilderPipelines.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@
133133
#include "llvm/Transforms/Utils/AssumeBundleBuilder.h"
134134
#include "llvm/Transforms/Utils/CanonicalizeAliases.h"
135135
#include "llvm/Transforms/Utils/CountVisits.h"
136+
#include "llvm/Transforms/Utils/EmitChangedFuncDebugInfo.h"
136137
#include "llvm/Transforms/Utils/EntryExitInstrumenter.h"
137138
#include "llvm/Transforms/Utils/ExtraPassManager.h"
138139
#include "llvm/Transforms/Utils/InjectTLIMappings.h"
@@ -1625,9 +1626,12 @@ PassBuilder::buildModuleOptimizationPipeline(OptimizationLevel Level,
16251626
if (PTO.CallGraphProfile && !LTOPreLink)
16261627
MPM.addPass(CGProfilePass(isLTOPostLink(LTOPhase)));
16271628

1628-
// RelLookupTableConverterPass runs later in LTO post-link pipeline.
1629-
if (!LTOPreLink)
1629+
// RelLookupTableConverterPass and EmitChangedFuncDebugInfoPass run later in
1630+
// LTO post-link pipeline.
1631+
if (!LTOPreLink) {
16301632
MPM.addPass(RelLookupTableConverterPass());
1633+
MPM.addPass(EmitChangedFuncDebugInfoPass());
1634+
}
16311635

16321636
return MPM;
16331637
}
@@ -2355,4 +2359,4 @@ AAManager PassBuilder::buildDefaultAAPipeline() {
23552359
bool PassBuilder::isInstrumentedPGOUse() const {
23562360
return (PGOOpt && PGOOpt->Action == PGOOptions::IRUse) ||
23572361
!UseCtxProfile.empty();
2358-
}
2362+
}

llvm/lib/Passes/PassRegistry.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ MODULE_PASS("debugify", NewPMDebugifyPass())
7373
MODULE_PASS("declare-runtime-libcalls", DeclareRuntimeLibcallsPass())
7474
MODULE_PASS("dfsan", DataFlowSanitizerPass())
7575
MODULE_PASS("dot-callgraph", CallGraphDOTPrinterPass())
76+
MODULE_PASS("dwarf-emit-late", EmitChangedFuncDebugInfoPass())
7677
MODULE_PASS("dxil-upgrade", DXILUpgradePass())
7778
MODULE_PASS("elim-avail-extern", EliminateAvailableExternallyPass())
7879
MODULE_PASS("extract-blocks", BlockExtractorPass({}, false))

llvm/lib/Transforms/Utils/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ add_llvm_component_library(LLVMTransformUtils
2222
Debugify.cpp
2323
DeclareRuntimeLibcalls.cpp
2424
DemoteRegToStack.cpp
25+
EmitChangedFuncDebugInfo.cpp
2526
DXILUpgrade.cpp
2627
EntryExitInstrumenter.cpp
2728
EscapeEnumerator.cpp

0 commit comments

Comments
 (0)