[llvm] [Dwarf][Transforms] Add dwarf support when func signature changed (PR #127855)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Feb 19 12:26:34 PST 2025
https://github.com/yonghong-song updated https://github.com/llvm/llvm-project/pull/127855
>From 9070f6f058df5408ce3e6d7408d9a1b252901fcd Mon Sep 17 00:00:00 2001
From: Yonghong Song <yonghong.song at linux.dev>
Date: Tue, 18 Feb 2025 09:54:08 -0800
Subject: [PATCH] [Dwarf][Transforms] Add dwarf support when func signature
changed
The goal is to add additional tag/attribute to dwarf so users will know
that function signatures get changed. See [1] for motivation. Otherwise,
users may assume function signature remaining the same as its source,
and bpf tracing may get wrong results. With explicit tag/attribute in
dwarf to indicate a func signature change, for bpf tracing, users will
either go into the asm code to find the exact signature or go to find
another non-signature-change function for tracing, instead of debugging
the otherwise rong results.
Earlier I have a pull request [2] attempts to add suffix to indicate
signature change as gcc did this already. But later upstream suggested
to use dwarf to encode such suffix change info ([1]).
This patch introduced a new tag LLVM_func_args_changed and a new
attr LLVM_func_retval_removed. In DeadArgumentElimination pass, if
a function return value is removed, LLVM_func_retval_removed attr will
be added to that func in the dwarf. In DeadArgumentElimination and
ArgumentPromotion passes, if the function signature is changed,
LLVM_func_args_changed tag is added to dwarf. Here, LLVM_func_args_changed
tag is used so later on, we could add more debug info about what changes.
Regarding to potential more info under LLVM_func_args_changed, we might need
the following info.
1. Trying to have a new set of formal argument types. The existing types
should be available in related Transforms passes, but will need DIBuilder
to build DIType's and looks like there is not easy DIBuilder API to do this.
2. Trying to relate old func signature (from source) to new func signature.
For example, original arg index 2 becomes new arg index 1, etc.
More complexity will come from argument promotion and struct arguments
where struct argument has size greater than an arch register size.
[1] https://discourse.llvm.org/t/rfc-identify-func-signature-change-in-llvm-compiled-kernel-image/82609
[2] https://github.com/llvm/llvm-project/pull/109899
---
llvm/include/llvm/BinaryFormat/Dwarf.def | 2 +
llvm/include/llvm/IR/DebugInfoFlags.def | 4 +-
llvm/include/llvm/IR/DebugInfoMetadata.h | 5 +
.../CodeGen/AsmPrinter/DwarfCompileUnit.cpp | 2 +
llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp | 12 ++
llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h | 3 +
llvm/lib/Transforms/IPO/ArgumentPromotion.cpp | 8 +
.../IPO/DeadArgumentElimination.cpp | 10 ++
llvm/test/DebugInfo/arg-prom.ll | 157 ++++++++++++++++++
llvm/test/DebugInfo/arg-retval-elim.ll | 103 ++++++++++++
10 files changed, 305 insertions(+), 1 deletion(-)
create mode 100644 llvm/test/DebugInfo/arg-prom.ll
create mode 100644 llvm/test/DebugInfo/arg-retval-elim.ll
diff --git a/llvm/include/llvm/BinaryFormat/Dwarf.def b/llvm/include/llvm/BinaryFormat/Dwarf.def
index 724a14ccc7aea..de4215e088dd5 100644
--- a/llvm/include/llvm/BinaryFormat/Dwarf.def
+++ b/llvm/include/llvm/BinaryFormat/Dwarf.def
@@ -268,6 +268,7 @@ HANDLE_DW_TAG(0x5111, ALTIUM_rom, 0, ALTIUM, DW_KIND_NONE)
// LLVM
HANDLE_DW_TAG(0x6000, LLVM_annotation, 0, LLVM, DW_KIND_NONE)
+HANDLE_DW_TAG(0x6001, LLVM_func_args_changed, 0, LLVM, DW_KIND_NONE)
// Green Hills.
HANDLE_DW_TAG(0x8004, GHS_namespace, 0, GHS, DW_KIND_NONE)
@@ -624,6 +625,7 @@ HANDLE_DW_AT(0x3e09, LLVM_ptrauth_authenticates_null_values, 0, LLVM)
HANDLE_DW_AT(0x3e0a, LLVM_ptrauth_authentication_mode, 0, LLVM)
HANDLE_DW_AT(0x3e0b, LLVM_num_extra_inhabitants, 0, LLVM)
HANDLE_DW_AT(0x3e0c, LLVM_stmt_sequence, 0, LLVM)
+HANDLE_DW_AT(0x3e0d, LLVM_func_retval_removed, 0, LLVM)
// Apple extensions.
diff --git a/llvm/include/llvm/IR/DebugInfoFlags.def b/llvm/include/llvm/IR/DebugInfoFlags.def
index df375b6c68e81..e693addab7879 100644
--- a/llvm/include/llvm/IR/DebugInfoFlags.def
+++ b/llvm/include/llvm/IR/DebugInfoFlags.def
@@ -91,11 +91,13 @@ HANDLE_DISP_FLAG((1u << 8), MainSubprogram)
// for defaulted functions
HANDLE_DISP_FLAG((1u << 9), Deleted)
HANDLE_DISP_FLAG((1u << 11), ObjCDirect)
+HANDLE_DISP_FLAG((1u << 12), ArgChanged)
+HANDLE_DISP_FLAG((1u << 13), RetvalRemoved)
#ifdef DISP_FLAG_LARGEST_NEEDED
// Intended to be used with ADT/BitmaskEnum.h.
// NOTE: Always must be equal to largest flag, check this when adding new flags.
-HANDLE_DISP_FLAG((1 << 11), Largest)
+HANDLE_DISP_FLAG((1 << 13), Largest)
#undef DISP_FLAG_LARGEST_NEEDED
#endif
diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h
index 8515d8eda8568..73d568b5576b4 100644
--- a/llvm/include/llvm/IR/DebugInfoMetadata.h
+++ b/llvm/include/llvm/IR/DebugInfoMetadata.h
@@ -1907,6 +1907,11 @@ class DISubprogram : public DILocalScope {
DIScope *getScope() const { return cast_or_null<DIScope>(getRawScope()); }
+ void setArgChanged() { SPFlags |= SPFlagArgChanged; }
+ bool getArgChanged() const { return SPFlags & SPFlagArgChanged; }
+ void setRetvalRemoved() { SPFlags |= SPFlagRetvalRemoved; }
+ bool getRetvalRemoved() const { return SPFlags & SPFlagRetvalRemoved; }
+
StringRef getName() const { return getStringOperand(2); }
StringRef getLinkageName() const { return getStringOperand(3); }
/// Only used by clients of CloneFunction, and only right after the cloning.
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
index ddf0275ddfe6a..a80d764683db7 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
@@ -1123,6 +1123,8 @@ DIE &DwarfCompileUnit::constructSubprogramScopeDIE(const DISubprogram *Sub,
MCSymbol *LineTableSym) {
DIE &ScopeDIE = updateSubprogramScopeDIE(Sub, LineTableSym);
+ DwarfUnit::addLLVMChangedArgs(ScopeDIE, Sub);
+
if (Scope) {
assert(!Scope->getInlinedAt());
assert(!Scope->isAbstractScope());
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
index 5347c8a049ba6..7dcc10eccab20 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
@@ -654,6 +654,15 @@ DIE *DwarfUnit::getOrCreateTypeDIE(const MDNode *TyNode) {
->createTypeDIE(Context, *ContextDIE, Ty);
}
+void DwarfUnit::addLLVMChangedArgs(DIE &ScopeDIE, const DISubprogram *SP) {
+ if (!SP->getArgChanged())
+ return;
+
+ auto *LocalDie =
+ DIE::get(DIEValueAllocator, dwarf::DW_TAG_LLVM_func_args_changed);
+ ScopeDIE.addChild(LocalDie);
+}
+
void DwarfUnit::updateAcceleratorTables(const DIScope *Context,
const DIType *Ty, const DIE &TyDIE) {
if (Ty->getName().empty())
@@ -1328,6 +1337,9 @@ void DwarfUnit::applySubprogramAttributes(const DISubprogram *SP, DIE &SPDie,
if (!SkipSPSourceLocation)
addSourceLine(SPDie, SP);
+ if (SP->getRetvalRemoved())
+ addFlag(SPDie, dwarf::DW_AT_LLVM_func_retval_removed);
+
// Skip the rest of the attributes under -gmlt to save space.
if (SkipSPAttributes)
return;
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h
index 9ddd6f8c14175..49724bcfc87ff 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h
@@ -324,6 +324,9 @@ class DwarfUnit : public DIEUnit {
void updateAcceleratorTables(const DIScope *Context, const DIType *Ty,
const DIE &TyDIE);
+ /// Add DW_TAG_LLVM_func_args_changed.
+ void addLLVMChangedArgs(DIE &ScopeDIE, const DISubprogram *SP);
+
protected:
~DwarfUnit();
diff --git a/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp b/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp
index c440638884322..e81adb830a86b 100644
--- a/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp
+++ b/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp
@@ -51,6 +51,7 @@
#include "llvm/IR/CFG.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Function.h"
@@ -132,6 +133,7 @@ doPromotion(Function *F, FunctionAnalysisManager &FAM,
// First, determine the new argument list
unsigned ArgNo = 0, NewArgNo = 0;
+ bool CurrFuncArgChanged = false;
for (Function::arg_iterator I = F->arg_begin(), E = F->arg_end(); I != E;
++I, ++ArgNo) {
if (!ArgsToPromote.count(&*I)) {
@@ -142,6 +144,7 @@ doPromotion(Function *F, FunctionAnalysisManager &FAM,
} else if (I->use_empty()) {
// Dead argument (which are always marked as promotable)
++NumArgumentsDead;
+ CurrFuncArgChanged = true;
ORE.emit([&]() {
return OptimizationRemark(DEBUG_TYPE, "ArgumentRemoved", F)
<< "eliminating argument " << ore::NV("ArgName", I->getName())
@@ -156,6 +159,7 @@ doPromotion(Function *F, FunctionAnalysisManager &FAM,
ArgAttrVec.push_back(AttributeSet());
}
++NumArgumentsPromoted;
+ CurrFuncArgChanged = true;
ORE.emit([&]() {
return OptimizationRemark(DEBUG_TYPE, "ArgumentPromoted", F)
<< "promoting argument " << ore::NV("ArgName", I->getName())
@@ -433,6 +437,10 @@ doPromotion(Function *F, FunctionAnalysisManager &FAM,
PromoteMemToReg(Allocas, DT, &AC);
}
+ DISubprogram *SP = NF->getSubprogram();
+ if (SP && CurrFuncArgChanged)
+ SP->setArgChanged();
+
return NF;
}
diff --git a/llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp b/llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp
index ed93b4491c50e..5df3d47daa8dd 100644
--- a/llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp
+++ b/llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp
@@ -757,6 +757,8 @@ bool DeadArgumentEliminationPass::removeDeadStuffFromFunction(Function *F) {
// a new set of parameter attributes to correspond. Skip the first parameter
// attribute, since that belongs to the return value.
unsigned ArgI = 0;
+ bool CurrFuncArgEliminated = false;
+ bool CurrFuncRetEliminated = false;
for (Function::arg_iterator I = F->arg_begin(), E = F->arg_end(); I != E;
++I, ++ArgI) {
RetOrArg Arg = createArg(F, ArgI);
@@ -767,6 +769,7 @@ bool DeadArgumentEliminationPass::removeDeadStuffFromFunction(Function *F) {
HasLiveReturnedArg |= PAL.hasParamAttr(ArgI, Attribute::Returned);
} else {
++NumArgumentsEliminated;
+ CurrFuncArgEliminated = true;
ORE.emit([&]() {
return OptimizationRemark(DEBUG_TYPE, "ArgumentRemoved", F)
@@ -818,6 +821,7 @@ bool DeadArgumentEliminationPass::removeDeadStuffFromFunction(Function *F) {
NewRetIdxs[Ri] = RetTypes.size() - 1;
} else {
++NumRetValsEliminated;
+ CurrFuncRetEliminated = true;
ORE.emit([&]() {
return OptimizationRemark(DEBUG_TYPE, "ReturnValueRemoved", F)
@@ -1099,6 +1103,12 @@ bool DeadArgumentEliminationPass::removeDeadStuffFromFunction(Function *F) {
// to call this function or try to interpret the return value.
if (NFTy != FTy && NF->getSubprogram()) {
DISubprogram *SP = NF->getSubprogram();
+
+ if (CurrFuncArgEliminated)
+ SP->setArgChanged();
+ if (CurrFuncRetEliminated)
+ SP->setRetvalRemoved();
+
auto Temp = SP->getType()->cloneWithCC(llvm::dwarf::DW_CC_nocall);
SP->replaceType(MDNode::replaceWithPermanent(std::move(Temp)));
}
diff --git a/llvm/test/DebugInfo/arg-prom.ll b/llvm/test/DebugInfo/arg-prom.ll
new file mode 100644
index 0000000000000..dd8c91ec2438e
--- /dev/null
+++ b/llvm/test/DebugInfo/arg-prom.ll
@@ -0,0 +1,157 @@
+; REQUIRES: x86-registered-target
+; RUN: opt -O3 -S < %s | FileCheck %s
+;
+; Source code:
+; __attribute__((noinline)) static int is_absolute_path(const char *path)
+; {
+; return path[0] == '/';
+; }
+;
+; int scpy(char *, const char *, int);
+; int quit(void);
+; const char *make_nonrelative_path(char *buf, int sz, const char *path)
+; {
+; if (is_absolute_path(path)) {
+; if (scpy(buf, path, sz) >= sz)
+; quit();
+; }
+; return buf;
+; }
+; Compilation flag:
+; clang -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c
+
+; ModuleID = 'test.c'
+source_filename = "test.c"
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Function Attrs: nounwind uwtable
+define dso_local ptr @make_nonrelative_path(ptr noundef %0, i32 noundef %1, ptr noundef %2) #0 !dbg !9 {
+ %4 = alloca ptr, align 8
+ %5 = alloca i32, align 4
+ %6 = alloca ptr, align 8
+ store ptr %0, ptr %4, align 8, !tbaa !21
+ #dbg_declare(ptr %4, !18, !DIExpression(), !26)
+ store i32 %1, ptr %5, align 4, !tbaa !27
+ #dbg_declare(ptr %5, !19, !DIExpression(), !29)
+ store ptr %2, ptr %6, align 8, !tbaa !21
+ #dbg_declare(ptr %6, !20, !DIExpression(), !30)
+ %7 = load ptr, ptr %6, align 8, !dbg !31, !tbaa !21
+ %8 = call i32 @is_absolute_path(ptr noundef %7), !dbg !33
+ %9 = icmp ne i32 %8, 0, !dbg !33
+ br i1 %9, label %10, label %20, !dbg !33
+
+10: ; preds = %3
+ %11 = load ptr, ptr %4, align 8, !dbg !34, !tbaa !21
+ %12 = load ptr, ptr %6, align 8, !dbg !37, !tbaa !21
+ %13 = load i32, ptr %5, align 4, !dbg !38, !tbaa !27
+ %14 = call i32 @scpy(ptr noundef %11, ptr noundef %12, i32 noundef %13), !dbg !39
+ %15 = load i32, ptr %5, align 4, !dbg !40, !tbaa !27
+ %16 = icmp sge i32 %14, %15, !dbg !41
+ br i1 %16, label %17, label %19, !dbg !41
+
+17: ; preds = %10
+ %18 = call i32 @quit(), !dbg !42
+ br label %19, !dbg !42
+
+19: ; preds = %17, %10
+ br label %20, !dbg !43
+
+20: ; preds = %19, %3
+ %21 = load ptr, ptr %4, align 8, !dbg !44, !tbaa !21
+ ret ptr %21, !dbg !45
+}
+
+; Function Attrs: noinline nounwind uwtable
+define internal i32 @is_absolute_path(ptr noundef %0) #1 !dbg !46 {
+ %2 = alloca ptr, align 8
+ store ptr %0, ptr %2, align 8, !tbaa !21
+ #dbg_declare(ptr %2, !50, !DIExpression(), !51)
+ %3 = load ptr, ptr %2, align 8, !dbg !52, !tbaa !21
+ %4 = getelementptr inbounds i8, ptr %3, i64 0, !dbg !52
+ %5 = load i8, ptr %4, align 1, !dbg !52, !tbaa !53
+ %6 = sext i8 %5 to i32, !dbg !52
+ %7 = icmp eq i32 %6, 47, !dbg !54
+ %8 = zext i1 %7 to i32, !dbg !54
+ ret i32 %8, !dbg !55
+}
+
+; CHECK: define internal fastcc range(i32 0, 2) i32 @is_absolute_path(i8 {{.*}})
+
+declare !dbg !56 i32 @scpy(ptr noundef, ptr noundef, i32 noundef) #2
+
+declare !dbg !59 i32 @quit() #2
+
+attributes #0 = { nounwind uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+attributes #1 = { noinline nounwind uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+attributes #2 = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!2, !3, !4, !5, !6, !7}
+!llvm.ident = !{!8}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang version 21.0.0git (git at github.com:yonghong-song/llvm-project.git bbfd0a15ade80596f6d6dde8add7d50f4875dde1)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/tmp/tests/sig-change/prom", checksumkind: CSK_MD5, checksum: "1befb35eb4507489630adb56cb20fe09")
+!2 = !{i32 7, !"Dwarf Version", i32 5}
+!3 = !{i32 2, !"Debug Info Version", i32 3}
+!4 = !{i32 1, !"wchar_size", i32 4}
+!5 = !{i32 8, !"PIC Level", i32 2}
+!6 = !{i32 7, !"PIE Level", i32 2}
+!7 = !{i32 7, !"uwtable", i32 2}
+!8 = !{!"clang version 21.0.0git (git at github.com:yonghong-song/llvm-project.git bbfd0a15ade80596f6d6dde8add7d50f4875dde1)"}
+!9 = distinct !DISubprogram(name: "make_nonrelative_path", scope: !1, file: !1, line: 8, type: !10, scopeLine: 9, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !17)
+!10 = !DISubroutineType(types: !11)
+!11 = !{!12, !15, !16, !12}
+!12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64)
+!13 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !14)
+!14 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
+!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64)
+!16 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!17 = !{!18, !19, !20}
+!18 = !DILocalVariable(name: "buf", arg: 1, scope: !9, file: !1, line: 8, type: !15)
+!19 = !DILocalVariable(name: "sz", arg: 2, scope: !9, file: !1, line: 8, type: !16)
+!20 = !DILocalVariable(name: "path", arg: 3, scope: !9, file: !1, line: 8, type: !12)
+!21 = !{!22, !22, i64 0}
+!22 = !{!"p1 omnipotent char", !23, i64 0}
+!23 = !{!"any pointer", !24, i64 0}
+!24 = !{!"omnipotent char", !25, i64 0}
+!25 = !{!"Simple C/C++ TBAA"}
+!26 = !DILocation(line: 8, column: 41, scope: !9)
+!27 = !{!28, !28, i64 0}
+!28 = !{!"int", !24, i64 0}
+!29 = !DILocation(line: 8, column: 50, scope: !9)
+!30 = !DILocation(line: 8, column: 66, scope: !9)
+!31 = !DILocation(line: 10, column: 30, scope: !32)
+!32 = distinct !DILexicalBlock(scope: !9, file: !1, line: 10, column: 13)
+!33 = !DILocation(line: 10, column: 13, scope: !32)
+!34 = !DILocation(line: 11, column: 26, scope: !35)
+!35 = distinct !DILexicalBlock(scope: !36, file: !1, line: 11, column: 21)
+!36 = distinct !DILexicalBlock(scope: !32, file: !1, line: 10, column: 37)
+!37 = !DILocation(line: 11, column: 31, scope: !35)
+!38 = !DILocation(line: 11, column: 37, scope: !35)
+!39 = !DILocation(line: 11, column: 21, scope: !35)
+!40 = !DILocation(line: 11, column: 44, scope: !35)
+!41 = !DILocation(line: 11, column: 41, scope: !35)
+!42 = !DILocation(line: 12, column: 4, scope: !35)
+!43 = !DILocation(line: 13, column: 9, scope: !36)
+!44 = !DILocation(line: 14, column: 16, scope: !9)
+!45 = !DILocation(line: 14, column: 9, scope: !9)
+!46 = distinct !DISubprogram(name: "is_absolute_path", scope: !1, file: !1, line: 1, type: !47, scopeLine: 2, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !49)
+
+; CHECK: distinct !DISubprogram(name: "is_absolute_path", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[#]], scopeLine: [[#]], flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized | DISPFlagArgChanged, unit: ![[#]], retainedNodes: ![[#]])
+
+!47 = !DISubroutineType(types: !48)
+!48 = !{!16, !12}
+!49 = !{!50}
+!50 = !DILocalVariable(name: "path", arg: 1, scope: !46, file: !1, line: 1, type: !12)
+!51 = !DILocation(line: 1, column: 67, scope: !46)
+!52 = !DILocation(line: 3, column: 16, scope: !46)
+!53 = !{!24, !24, i64 0}
+!54 = !DILocation(line: 3, column: 24, scope: !46)
+!55 = !DILocation(line: 3, column: 9, scope: !46)
+!56 = !DISubprogram(name: "scpy", scope: !1, file: !1, line: 6, type: !57, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized)
+!57 = !DISubroutineType(types: !58)
+!58 = !{!16, !15, !12, !16}
+!59 = !DISubprogram(name: "quit", scope: !1, file: !1, line: 7, type: !60, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized)
+!60 = !DISubroutineType(types: !61)
+!61 = !{!16}
diff --git a/llvm/test/DebugInfo/arg-retval-elim.ll b/llvm/test/DebugInfo/arg-retval-elim.ll
new file mode 100644
index 0000000000000..abb1ea5e06563
--- /dev/null
+++ b/llvm/test/DebugInfo/arg-retval-elim.ll
@@ -0,0 +1,103 @@
+; REQUIRES: x86-registered-target
+; RUN: opt -O2 -S < %s | FileCheck %s
+;
+; Source code:
+; int tar(int a);
+; __attribute__((noinline)) static int foo(int a, int b)
+; {
+; return tar(a) + tar(a + 1);
+; }
+; int bar(int a)
+; {
+; foo(a, 1);
+; return 0;
+; }
+; Compilation flag:
+; clang -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c
+
+; ModuleID = 'test.c'
+source_filename = "test.c"
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Function Attrs: nounwind uwtable
+define dso_local i32 @bar(i32 noundef %0) #0 !dbg !9 {
+ %2 = alloca i32, align 4
+ store i32 %0, ptr %2, align 4, !tbaa !15
+ #dbg_declare(ptr %2, !14, !DIExpression(), !19)
+ %3 = load i32, ptr %2, align 4, !dbg !20, !tbaa !15
+ %4 = call i32 @foo(i32 noundef %3, i32 noundef 1), !dbg !21
+ ret i32 0, !dbg !22
+}
+
+; Function Attrs: noinline nounwind uwtable
+define internal i32 @foo(i32 noundef %0, i32 noundef %1) #1 !dbg !23 {
+ %3 = alloca i32, align 4
+ %4 = alloca i32, align 4
+ store i32 %0, ptr %3, align 4, !tbaa !15
+ #dbg_declare(ptr %3, !27, !DIExpression(), !29)
+ store i32 %1, ptr %4, align 4, !tbaa !15
+ #dbg_declare(ptr %4, !28, !DIExpression(), !30)
+ %5 = load i32, ptr %3, align 4, !dbg !31, !tbaa !15
+ %6 = call i32 @tar(i32 noundef %5), !dbg !32
+ %7 = load i32, ptr %3, align 4, !dbg !33, !tbaa !15
+ %8 = add nsw i32 %7, 1, !dbg !34
+ %9 = call i32 @tar(i32 noundef %8), !dbg !35
+ %10 = add nsw i32 %6, %9, !dbg !36
+ ret i32 %10, !dbg !37
+}
+
+; CHECK: define internal fastcc void @foo(i32 noundef %0)
+
+declare !dbg !38 i32 @tar(i32 noundef) #2
+
+attributes #0 = { nounwind uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+attributes #1 = { noinline nounwind uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+attributes #2 = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!2, !3, !4, !5, !6, !7}
+!llvm.ident = !{!8}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang version 21.0.0git (git at github.com:yonghong-song/llvm-project.git 95c942ca729f6f240c408ceeb39d2d5f10a3b0d5)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/tmp/tests/sig-change/deadret", checksumkind: CSK_MD5, checksum: "728d225e6425c104712ae21cee1db99b")
+!2 = !{i32 7, !"Dwarf Version", i32 5}
+!3 = !{i32 2, !"Debug Info Version", i32 3}
+!4 = !{i32 1, !"wchar_size", i32 4}
+!5 = !{i32 8, !"PIC Level", i32 2}
+!6 = !{i32 7, !"PIE Level", i32 2}
+!7 = !{i32 7, !"uwtable", i32 2}
+!8 = !{!"clang version 21.0.0git (git at github.com:yonghong-song/llvm-project.git 95c942ca729f6f240c408ceeb39d2d5f10a3b0d5)"}
+!9 = distinct !DISubprogram(name: "bar", scope: !1, file: !1, line: 6, type: !10, scopeLine: 7, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !13)
+!10 = !DISubroutineType(types: !11)
+!11 = !{!12, !12}
+!12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!13 = !{!14}
+!14 = !DILocalVariable(name: "a", arg: 1, scope: !9, file: !1, line: 6, type: !12)
+!15 = !{!16, !16, i64 0}
+!16 = !{!"int", !17, i64 0}
+!17 = !{!"omnipotent char", !18, i64 0}
+!18 = !{!"Simple C/C++ TBAA"}
+!19 = !DILocation(line: 6, column: 13, scope: !9)
+!20 = !DILocation(line: 8, column: 7, scope: !9)
+!21 = !DILocation(line: 8, column: 3, scope: !9)
+!22 = !DILocation(line: 9, column: 3, scope: !9)
+!23 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 2, type: !24, scopeLine: 3, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !26)
+
+; CHECK: distinct !DISubprogram(name: "foo", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[#]], scopeLine: [[#]], flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized | DISPFlagArgChanged | DISPFlagRetvalRemoved, unit: !0, retainedNodes: ![[#]])
+
+!24 = !DISubroutineType(types: !25)
+!25 = !{!12, !12, !12}
+!26 = !{!27, !28}
+!27 = !DILocalVariable(name: "a", arg: 1, scope: !23, file: !1, line: 2, type: !12)
+!28 = !DILocalVariable(name: "b", arg: 2, scope: !23, file: !1, line: 2, type: !12)
+!29 = !DILocation(line: 2, column: 46, scope: !23)
+!30 = !DILocation(line: 2, column: 53, scope: !23)
+!31 = !DILocation(line: 4, column: 14, scope: !23)
+!32 = !DILocation(line: 4, column: 10, scope: !23)
+!33 = !DILocation(line: 4, column: 23, scope: !23)
+!34 = !DILocation(line: 4, column: 25, scope: !23)
+!35 = !DILocation(line: 4, column: 19, scope: !23)
+!36 = !DILocation(line: 4, column: 17, scope: !23)
+!37 = !DILocation(line: 4, column: 3, scope: !23)
+!38 = !DISubprogram(name: "tar", scope: !1, file: !1, line: 1, type: !10, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized)
More information about the llvm-commits
mailing list