[llvm] [RFC] Emit dwarf data for signature-changed or new functions (PR #157349)
via llvm-commits
llvm-commits at lists.llvm.org
Sun Sep 7 09:47:26 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-debuginfo
Author: None (yonghong-song)
<details>
<summary>Changes</summary>
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] https://github.com/llvm/llvm-project/pull/127855
---
Patch is 25.17 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/157349.diff
14 Files Affected:
- (added) llvm/include/llvm/Transforms/Utils/EmitChangedFuncDebugInfo.h (+33)
- (modified) llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp (+72)
- (modified) llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h (+2)
- (modified) llvm/lib/Passes/PassBuilder.cpp (+1)
- (modified) llvm/lib/Passes/PassBuilderPipelines.cpp (+7-3)
- (modified) llvm/lib/Passes/PassRegistry.def (+1)
- (modified) llvm/lib/Transforms/IPO/ArgumentPromotion.cpp (+9)
- (modified) llvm/lib/Transforms/Utils/CMakeLists.txt (+1)
- (added) llvm/lib/Transforms/Utils/EmitChangedFuncDebugInfo.cpp (+337)
- (modified) llvm/test/Other/new-pm-defaults.ll (+2)
- (modified) llvm/test/Other/new-pm-thinlto-postlink-defaults.ll (+1)
- (modified) llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll (+1)
- (modified) llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll (+1)
- (modified) llvm/test/Transforms/ArgumentPromotion/dbg.ll (+5-1)
``````````diff
diff --git a/llvm/include/llvm/Transforms/Utils/EmitChangedFuncDebugInfo.h b/llvm/include/llvm/Transforms/Utils/EmitChangedFuncDebugInfo.h
new file mode 100644
index 0000000000000..8d569cd95d7f7
--- /dev/null
+++ b/llvm/include/llvm/Transforms/Utils/EmitChangedFuncDebugInfo.h
@@ -0,0 +1,33 @@
+//===- EmitChangedFuncDebugInfo.h - Emit Additional Debug Info -*- C++ --*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file
+/// Emit debug info for changed or new funcs.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TRANSFORMS_UTILS_EMITCHANGEDFUNCDEBUGINFO_H
+#define LLVM_TRANSFORMS_UTILS_EMITCHANGEDFUNCDEBUGINFO_H
+
+#include "llvm/IR/PassManager.h"
+
+namespace llvm {
+
+class Module;
+
+// Pass that emits late dwarf.
+class EmitChangedFuncDebugInfoPass
+ : public PassInfoMixin<EmitChangedFuncDebugInfoPass> {
+public:
+ EmitChangedFuncDebugInfoPass() = default;
+
+ PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
+};
+
+} // end namespace llvm
+
+#endif // LLVM_TRANSFORMS_UTILS_EMITCHANGEDFUNCDEBUGINFO_H
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
index c27f100775625..3245d486feb77 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
@@ -1266,11 +1266,83 @@ void DwarfDebug::finishSubprogramDefinitions() {
}
}
+void DwarfDebug::addChangedSubprograms() {
+ // Generate additional dwarf for functions with signature changed.
+ NamedMDNode *NMD = MMI->getModule()->getNamedMetadata("llvm.dbg.cu");
+ DICompileUnit *ExtraCU = nullptr;
+ for (MDNode *N : NMD->operands()) {
+ auto *CU = cast<DICompileUnit>(N);
+ if (CU->getFile()->getFilename() == "<artificial>") {
+ ExtraCU = CU;
+ break;
+ }
+ }
+ if (!ExtraCU)
+ return;
+
+ llvm::DebugInfoFinder DIF;
+ DIF.processModule(*MMI->getModule());
+ for (auto *ExtraSP : DIF.subprograms()) {
+ if (ExtraSP->getUnit() != ExtraCU)
+ continue;
+
+ DISubprogram *SP = cast<DISubprogram>(ExtraSP->getScope());
+ DwarfCompileUnit &Cu = getOrCreateDwarfCompileUnit(SP->getUnit());
+ DIE *ScopeDIE =
+ DIE::get(DIEValueAllocator, dwarf::DW_TAG_inlined_subroutine);
+ Cu.getUnitDie().addChild(ScopeDIE);
+
+ Cu.addString(*ScopeDIE, dwarf::DW_AT_name, ExtraSP->getName());
+
+ DITypeRefArray Args = ExtraSP->getType()->getTypeArray();
+
+ if (Args[0])
+ Cu.addType(*ScopeDIE, Args[0]);
+
+ if (ExtraSP->getType()->getCC() == llvm::dwarf::DW_CC_nocall) {
+ Cu.addUInt(*ScopeDIE, dwarf::DW_AT_calling_convention,
+ dwarf::DW_FORM_data1, llvm::dwarf::DW_CC_nocall);
+ }
+
+ Cu.addFlag(*ScopeDIE, dwarf::DW_AT_artificial);
+
+ // dereference the DIE* for DIEEntry
+ DIE *OriginDIE = Cu.getOrCreateSubprogramDIE(SP);
+ Cu.addDIEEntry(*ScopeDIE, dwarf::DW_AT_specification, DIEEntry(*OriginDIE));
+
+ SmallVector<const DILocalVariable *> ArgVars(Args.size());
+ for (const DINode *DN : ExtraSP->getRetainedNodes()) {
+ if (const auto *DV = dyn_cast<DILocalVariable>(DN)) {
+ uint32_t Arg = DV->getArg();
+ if (Arg)
+ ArgVars[Arg - 1] = DV;
+ }
+ }
+
+ for (unsigned i = 1, N = Args.size(); i < N; ++i) {
+ const DIType *Ty = Args[i];
+ if (!Ty) {
+ assert(i == N-1 && "Unspecified parameter must be the last argument");
+ Cu.createAndAddDIE(dwarf::DW_TAG_unspecified_parameters, *ScopeDIE);
+ } else {
+ DIE &Arg =
+ Cu.createAndAddDIE(dwarf::DW_TAG_formal_parameter, *ScopeDIE);
+ const DILocalVariable *DV = ArgVars[i - 1];
+ if (DV)
+ Cu.addString(Arg, dwarf::DW_AT_name, DV->getName());
+ Cu.addType(Arg, Ty);
+ }
+ }
+ }
+}
+
void DwarfDebug::finalizeModuleInfo() {
const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering();
finishSubprogramDefinitions();
+ addChangedSubprograms();
+
finishEntityDefinitions();
bool HasEmittedSplitCU = false;
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
index 89813dcf0fdab..417ffb19633c3 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
@@ -565,6 +565,8 @@ class DwarfDebug : public DebugHandlerBase {
void finishSubprogramDefinitions();
+ void addChangedSubprograms();
+
/// Finish off debug information after all functions have been
/// processed.
void finalizeModuleInfo();
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index 587f0ece0859b..fa937a9a317be 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -344,6 +344,7 @@
#include "llvm/Transforms/Utils/CanonicalizeAliases.h"
#include "llvm/Transforms/Utils/CanonicalizeFreezeInLoops.h"
#include "llvm/Transforms/Utils/CountVisits.h"
+#include "llvm/Transforms/Utils/EmitChangedFuncDebugInfo.h"
#include "llvm/Transforms/Utils/DXILUpgrade.h"
#include "llvm/Transforms/Utils/Debugify.h"
#include "llvm/Transforms/Utils/DeclareRuntimeLibcalls.h"
diff --git a/llvm/lib/Passes/PassBuilderPipelines.cpp b/llvm/lib/Passes/PassBuilderPipelines.cpp
index 98821bb1408a7..123041ea8cad8 100644
--- a/llvm/lib/Passes/PassBuilderPipelines.cpp
+++ b/llvm/lib/Passes/PassBuilderPipelines.cpp
@@ -133,6 +133,7 @@
#include "llvm/Transforms/Utils/AssumeBundleBuilder.h"
#include "llvm/Transforms/Utils/CanonicalizeAliases.h"
#include "llvm/Transforms/Utils/CountVisits.h"
+#include "llvm/Transforms/Utils/EmitChangedFuncDebugInfo.h"
#include "llvm/Transforms/Utils/EntryExitInstrumenter.h"
#include "llvm/Transforms/Utils/ExtraPassManager.h"
#include "llvm/Transforms/Utils/InjectTLIMappings.h"
@@ -1625,9 +1626,12 @@ PassBuilder::buildModuleOptimizationPipeline(OptimizationLevel Level,
if (PTO.CallGraphProfile && !LTOPreLink)
MPM.addPass(CGProfilePass(isLTOPostLink(LTOPhase)));
- // RelLookupTableConverterPass runs later in LTO post-link pipeline.
- if (!LTOPreLink)
+ // RelLookupTableConverterPass and EmitChangedFuncDebugInfoPass run later in
+ // LTO post-link pipeline.
+ if (!LTOPreLink) {
MPM.addPass(RelLookupTableConverterPass());
+ MPM.addPass(EmitChangedFuncDebugInfoPass());
+ }
return MPM;
}
@@ -2355,4 +2359,4 @@ AAManager PassBuilder::buildDefaultAAPipeline() {
bool PassBuilder::isInstrumentedPGOUse() const {
return (PGOOpt && PGOOpt->Action == PGOOptions::IRUse) ||
!UseCtxProfile.empty();
-}
\ No newline at end of file
+}
diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def
index 299aaa801439b..78ee4ca6f96a1 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -73,6 +73,7 @@ MODULE_PASS("debugify", NewPMDebugifyPass())
MODULE_PASS("declare-runtime-libcalls", DeclareRuntimeLibcallsPass())
MODULE_PASS("dfsan", DataFlowSanitizerPass())
MODULE_PASS("dot-callgraph", CallGraphDOTPrinterPass())
+MODULE_PASS("dwarf-emit-late", EmitChangedFuncDebugInfoPass())
MODULE_PASS("dxil-upgrade", DXILUpgradePass())
MODULE_PASS("elim-avail-extern", EliminateAvailableExternallyPass())
MODULE_PASS("extract-blocks", BlockExtractorPass({}, false))
diff --git a/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp b/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp
index 262c902d40d2d..609e4f8e4d23a 100644
--- a/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp
+++ b/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp
@@ -50,6 +50,7 @@
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/Constants.h"
+#include "llvm/IR/DIBuilder.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Dominators.h"
@@ -432,6 +433,14 @@ doPromotion(Function *F, FunctionAnalysisManager &FAM,
PromoteMemToReg(Allocas, DT, &AC);
}
+ // DW_CC_nocall to DISubroutineType to inform debugger that it may not be safe
+ // to call this function.
+ DISubprogram *SP = NF->getSubprogram();
+ if (SP) {
+ auto Temp = SP->getType()->cloneWithCC(llvm::dwarf::DW_CC_nocall);
+ SP->replaceType(MDNode::replaceWithPermanent(std::move(Temp)));
+ }
+
return NF;
}
diff --git a/llvm/lib/Transforms/Utils/CMakeLists.txt b/llvm/lib/Transforms/Utils/CMakeLists.txt
index e411d68570096..0b36693ce7975 100644
--- a/llvm/lib/Transforms/Utils/CMakeLists.txt
+++ b/llvm/lib/Transforms/Utils/CMakeLists.txt
@@ -22,6 +22,7 @@ add_llvm_component_library(LLVMTransformUtils
Debugify.cpp
DeclareRuntimeLibcalls.cpp
DemoteRegToStack.cpp
+ EmitChangedFuncDebugInfo.cpp
DXILUpgrade.cpp
EntryExitInstrumenter.cpp
EscapeEnumerator.cpp
diff --git a/llvm/lib/Transforms/Utils/EmitChangedFuncDebugInfo.cpp b/llvm/lib/Transforms/Utils/EmitChangedFuncDebugInfo.cpp
new file mode 100644
index 0000000000000..82acae3f0efeb
--- /dev/null
+++ b/llvm/lib/Transforms/Utils/EmitChangedFuncDebugInfo.cpp
@@ -0,0 +1,337 @@
+//==- EmitChangedFuncDebugInfoPass - Emit Additional Debug Info -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements emitting debug info for functions with changed
+// signatures or new functions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Transforms/Utils/EmitChangedFuncDebugInfo.h"
+#include "llvm/IR/DIBuilder.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/Module.h"
+
+using namespace llvm;
+
+static bool getArg(BasicBlock &FirstBB, unsigned Idx, DIBuilder &DIB,
+ DIFile *NewFile, Function *F, DISubprogram *OldSP,
+ SmallVector<Metadata *, 5> &TypeList,
+ SmallVector<Metadata *, 5> &ArgList) {
+ for (Instruction &I : FirstBB) {
+ for (const DbgRecord &DR : I.getDbgRecordRange()) {
+ auto *DVR = dyn_cast<DbgVariableRecord>(&DR);
+ if (!DVR)
+ continue;
+ // All of DbgVariableRecord::LocationType::{Value,Assign,Declare}
+ // are covered.
+ Metadata *Loc = DVR->getRawLocation();
+ auto *ValueMDN = dyn_cast<ValueAsMetadata>(Loc);
+ if (!ValueMDN)
+ continue;
+
+ // A poison value may correspond to a unused argument.
+ if (isa<PoisonValue>(ValueMDN->getValue())) {
+ Type *Ty = ValueMDN->getType();
+ auto *Var = cast<DILocalVariable>(DVR->getRawVariable());
+ if (!Var || Var->getArg() != (Idx + 1))
+ continue;
+
+ // Check for cases like below due to ArgumentPromotion
+ // define internal ... i32 @add42_byref(i32 %p.0.val) ... {
+ // #dbg_value(ptr poison, !17, !DIExpression(), !18)
+ // ...
+ // }
+ // TODO: one pointer expands to more than one argument is not
+ // supported yet. For example,
+ // define internal ... i32 @add42_byref(i32 %p.0.val, i32 %p.4.val)
+ // ...
+ if (Ty->isPointerTy() && F->getArg(Idx)->getType()->isIntegerTy()) {
+ // For such cases, a new argument is created.
+ auto *IntTy = cast<IntegerType>(F->getArg(Idx)->getType());
+ unsigned IntBitWidth = IntTy->getBitWidth();
+
+ DIType *IntDIType =
+ DIB.createBasicType("int" + std::to_string(IntBitWidth),
+ IntBitWidth, dwarf::DW_ATE_signed);
+ Var = DIB.createParameterVariable(OldSP, F->getArg(Idx)->getName(),
+ Idx + 1, NewFile, OldSP->getLine(),
+ IntDIType);
+ }
+
+ TypeList.push_back(Var->getType());
+ ArgList.push_back(Var);
+ return true;
+ }
+
+ // Handle the following pattern:
+ // ... @vgacon_do_font_op(..., i32 noundef, i1 noundef zeroext %ch512)
+ // ... {
+ // ...
+ // #dbg_value(i32 %set, !8568, !DIExpression(), !8589)
+ // %storedv = zext i1 %ch512 to i8
+ // #dbg_value(i8 %storedv, !8569, !DIExpression(), !8589)
+ // ...
+ // }
+ if (ValueMDN->getValue() != F->getArg(Idx)) {
+ Instruction *PrevI = I.getPrevNode();
+ if (!PrevI)
+ continue;
+ if (ValueMDN->getValue() != PrevI)
+ continue;
+ auto *ZExt = dyn_cast<ZExtInst>(PrevI);
+ if (!ZExt)
+ continue;
+ if (ZExt->getOperand(0) != F->getArg(Idx))
+ continue;
+ }
+
+ auto *Var = cast<DILocalVariable>(DVR->getRawVariable());
+
+ // Even we get dbg_*(...) for arguments, we still need to ensure
+ // compatible types between IR func argument types and debugInfo argument
+ // types.
+ Type *Ty = ValueMDN->getType();
+ DIType *DITy = Var->getType();
+ while (auto *DTy = dyn_cast<DIDerivedType>(DITy)) {
+ if (DTy->getTag() == dwarf::DW_TAG_pointer_type) {
+ DITy = DTy;
+ break;
+ }
+ DITy = DTy->getBaseType();
+ }
+
+ if (Ty->isIntegerTy()) {
+ if (auto *DTy = dyn_cast<DICompositeType>(DITy)) {
+ if (!Ty->isIntegerTy(DTy->getSizeInBits())) {
+ // TODO: A struct param breaks into two actual arguments like
+ // static int count(struct user_arg_ptr argv, int max)
+ // and the actual func signature:
+ // i32 @count(i8 range(i8 0, 2) %argv.coerce0, ptr %argv.coerce1)
+ // {
+ // #dbg_value(i8 %argv.coerce0, !14759,
+ // !DIExpression(DW_OP_LLVM_fragment, 0, 8), !14768)
+ // #dbg_value(ptr %argv.coerce1, !14759,
+ // !DIExpression(DW_OP_LLVM_fragment, 64, 64), !14768)
+ // ...
+ // }
+ return false;
+ }
+ }
+ } else if (Ty->isPointerTy()) {
+ // TODO: A struct turned into a pointer to struct.
+ // @rhashtable_lookup_fast(ptr noundef %key,
+ // ptr noundef readonly byval(%struct.rhashtable_params)
+ // align 8 captures(none) %params) {
+ // ...
+ // %MyAlloca = alloca [160 x i8], align 32
+ // %0 = ptrtoint ptr %MyAlloca to i64
+ // %1 = add i64 %0, 32
+ // %2 = inttoptr i64 %1 to ptr
+ // ...
+ // call void @llvm.memcpy.p0.p0.i64(ptr align 8 %2, ptr align 8
+ // %params, i64 40, i1 false)
+ // #dbg_value(ptr @offdevs, !15308, !DIExpression(), !15312)
+ // #dbg_value(ptr %key, !15309, !DIExpression(), !15312)
+ // #dbg_declare(ptr %MyAlloca, !15310,
+ // !DIExpression(DW_OP_plus_uconst, 32), !15313)
+ // tail call void @__rcu_read_lock() #14, !dbg !15314
+ // }
+ if (dyn_cast<DICompositeType>(DITy))
+ return false;
+
+ auto *DTy = dyn_cast<DIDerivedType>(DITy);
+ if (!DTy)
+ continue;
+ if (DTy->getTag() != dwarf::DW_TAG_pointer_type)
+ continue;
+ }
+
+ TypeList.push_back(Var->getType());
+ if (Var->getArg() != (Idx + 1) ||
+ Var->getName() != F->getArg(Idx)->getName()) {
+ Var = DIB.createParameterVariable(OldSP, F->getArg(Idx)->getName(),
+ Idx + 1, OldSP->getUnit()->getFile(),
+ OldSP->getLine(), Var->getType());
+ }
+ ArgList.push_back(Var);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool getTypeArgList(DIBuilder &DIB, DIFile *NewFile, Function *F,
+ FunctionType *FTy, DISubprogram *OldSP,
+ SmallVector<Metadata *, 5> &TypeList,
+ SmallVector<Metadata *, 5> &ArgList) {
+ Type *RetTy = FTy->getReturnType();
+ if (RetTy->isVoidTy()) {
+ // Void return type may be due to optimization.
+ TypeList.push_back(nullptr);
+ } else {
+ // Optimization does not change return type from one
+ // non-void type to another non-void type.
+ DITypeRefArray TyArray = OldSP->getType()->getTypeArray();
+ TypeList.push_back(TyArray[0]);
+ }
+
+ unsigned NumArgs = FTy->getNumParams();
+ BasicBlock &FirstBB = F->getEntryBlock();
+ for (unsigned i = 0; i < NumArgs; ++i) {
+ if (!getArg(FirstBB, i, DIB, NewFile, F, OldSP, TypeList, ArgList))
+ return false;
+ }
+
+ return true;
+}
+
+static void generateDebugInfo(Module &M, Function *F) {
+ // For this CU, we want generate the following three dwarf units:
+ // 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)
+ // ...
+
+ // A new ComputeUnit is created with file name "<artificial>"
+ // to host newly-created DISubprogram's.
+ DICompileUnit *NewCU = nullptr;
+ NamedMDNode *CUs = M.getNamedMetadata("llvm.dbg.cu");
+ // Check whether the expected CU already there or not.
+ for (MDNode *Node : CUs->operands()) {
+ auto *CU = cast<DICompileUnit>(Node);
+ if (CU->getFile()->getFilename() == "<artificial>") {
+ NewCU = CU;
+ break;
+ }
+ }
+
+ DISubprogram *OldSP = F->getSubprogram();
+ DIBuilder DIB(M, /*AllowUnresolved=*/false, NewCU);
+ DIFile *NewFile;
+
+ if (NewCU) {
+ NewFile = NewCU->getFile();
+ } else {
+ DICompileUnit *OldCU = OldSP->getUnit();
+ DIFile *OldFile = OldCU->getFile();
+ NewFile = DIB.createFile("<artificial>", OldFile->getDirectory());
+ NewCU = DIB.createCompileUnit(
+ OldCU->getSourceLanguage(), NewFile, OldCU->getProducer(),
+ OldCU->isOptimized(), OldCU->getFlags(), OldCU->getRuntimeVersion());
+ }
+
+ SmallVector<Metadata *, 5> TypeList;
+ SmallVector<Metadata *, 5> ArgList;
+
+ FunctionType *FTy = F->getFunctionType();
+ bool Success = getTypeArgList(DIB, NewFile, F, FTy, OldSP, TypeList, ArgList);
+ if (!Success) {
+ TypeList.clear();
+ TypeList.push_back(nullptr);
+ ArgList.clear();
+ }
+
+ DITypeRefArray DITypeArray = DIB.getOrCreateTypeArray(TypeList);
+ auto *SubroutineType = DIB.createSubroutineType(DITypeArray);
+ DINodeArray ArgArray = DIB.getOrCreateArray(ArgList);
+
+ Function *DummyF =
+ Function::Create(FTy, GlobalValue::AvailableExternallyLinkage,
+ F->getName() + ".newsig", &M);
+
+ DISubprogram *NewSP =
+ DIB.createFunction(OldSP, // Scope
+ F->getName(), // Name
+ OldSP->getLinkageName(), // Linkage name
+ NewFile, // File
+ OldSP->getLine(), // Line
+ SubroutineType, // DISubroutineType
+ OldSP->getScopeLine(), // ScopeLine
+ ...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/157349
More information about the llvm-commits
mailing list