[llvm] 43faefd - [ArgPromotion] Add DW_CC_nocall to DISubprogram (#178973)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Feb 3 13:55:34 PST 2026
Author: yonghong-song
Date: 2026-02-03T13:55:29-08:00
New Revision: 43faefdb12337216957b2fac34ca6bd1bed371b7
URL: https://github.com/llvm/llvm-project/commit/43faefdb12337216957b2fac34ca6bd1bed371b7
DIFF: https://github.com/llvm/llvm-project/commit/43faefdb12337216957b2fac34ca6bd1bed371b7.diff
LOG: [ArgPromotion] Add DW_CC_nocall to DISubprogram (#178973)
ArgumentPromotion pass may change function signatures. If this happens
and debuginfo is enabled, adding DW_CC_nocall allows dwarf to generate
DW_AT_calling_convention (DW_CC_nocall)
for DW_TAG_subprogram.
DeadArgumentElimination ([1]) already has similar implementation.
The pahole tool ([2]) is used in linux kernel build to generate vmlinux
BTF. One of its input is linux kernel dwarf. Currently, pahole
checks *all* DW_TAG_subprogram functions and find whether the source
signature matches the architecture ABI or not. If mismatch, pahole will
try to do some adjustment for those parameters. See [3]
and function parameter__new().
The linux kernel typically has ~65K functions and roughly 1100 functions
may have signature changed due to compile optimization. Without
DW_CC_nocall,
signatures of all of 64K functions will be checked in parameter__new().
But with DW_CC_nocall, the number of functions to checked is only 1100,
much smaller.
If DW_CC_nocall is not available, pahole may needs to parse complicated
locations. Even if the signature is not changed, pahole may not be able to
decide that the location matches function signature, and will incorrectly
exclude this function for vmlinux BTF.
So overall, adding DW_CC_nocall in ArgumentPromotion can help pahole
with less build time and more correct function encoding in vmlinux BTF.
With change in ArgumentPromotion.cpp, the test dbg.ll will fail since
the subroutine type is null. The non-null subroutine type is added so
the test can pass.
Without change in ArgumentPromotion.cpp, the dbg.ll will have
...
!3 = distinct !DISubprogram(name: "test", scope: null, file: !2, line: 3, type: !4,
scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !1)
!4 = !DISubroutineType(types: !5)
!5 = !{null, !6}
...
With change in Argumentpromotion.cpp, the dbg.ll will have
...
!3 = distinct !DISubprogram(name: "test", scope: null, file: !2, line: 3, type: !4,
scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !1)
!4 = !DISubroutineType(cc: DW_CC_nocall, types: !5)
!5 = !{null, !6}
Eventually, DW_CC_nocall will be encoded in dwarf.
[1] https://github.com/llvm/llvm-project/commit/340b0ca90095d838f095271aaa1098fa1bd5ecbe
[2] https://git.kernel.org/pub/scm/devel/pahole/pahole.git
[3] https://git.kernel.org/pub/scm/devel/pahole/pahole.git/tree/dwarf_loader.c
Added:
Modified:
llvm/lib/Transforms/IPO/ArgumentPromotion.cpp
llvm/test/Transforms/ArgumentPromotion/dbg.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp b/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp
index 675a5af368e7f..cfbf9dec01619 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,16 @@ doPromotion(Function *F, FunctionAnalysisManager &FAM,
PromoteMemToReg(Allocas, DT, &AC);
}
+ // If argument(s) are dead (hence removed) or promoted, the function probably
+ // does not follow the standard calling convention anymore. Add 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/test/Transforms/ArgumentPromotion/dbg.ll b/llvm/test/Transforms/ArgumentPromotion/dbg.ll
index 6a14facfb36a2..4f680f030b8be 100644
--- a/llvm/test/Transforms/ArgumentPromotion/dbg.ll
+++ b/llvm/test/Transforms/ArgumentPromotion/dbg.ll
@@ -53,7 +53,22 @@ define void @caller(ptr %Y, ptr %P) {
!0 = !{i32 2, !"Debug Info Version", i32 3}
!1 = !DILocation(line: 8, scope: !2)
-!2 = distinct !DISubprogram(name: "test", file: !5, line: 3, isLocal: true, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !3, scopeLine: 3, scope: null)
+!2 = distinct !DISubprogram(name: "test", file: !5, line: 3, type: !7, isLocal: true, isDefinition: true, flags: DIFlagPrototyped, isOptimized: false, unit: !3, scopeLine: 3, scope: null)
!3 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, producer: "clang version 3.5.0 ", isOptimized: false, emissionKind: LineTablesOnly, file: !5)
!5 = !DIFile(filename: "test.c", directory: "")
!6 = !DILocation(line: 9, scope: !2)
+!7 = !DISubroutineType(types: !8)
+!8 = !{null, !9}
+!9 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !10)
+!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+
+; CHECK: !0 = !{i32 2, !"Debug Info Version", i32 3}
+; CHECK-NEXT: !1 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !2, producer: "clang version 3.5.0 ", isOptimized: false, runtimeVersion: 0, emissionKind: LineTablesOnly)
+; CHECK-NEXT: !2 = !DIFile(filename: "test.c", directory: "")
+; CHECK-NEXT: !3 = distinct !DISubprogram(name: "test", scope: null, file: !2, line: 3, type: !4, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !1)
+; CHECK-NEXT: !4 = !DISubroutineType(cc: DW_CC_nocall, types: !5)
+; CHECK-NEXT: !5 = !{null, !6}
+; CHECK-NEXT: !6 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7)
+; CHECK-NEXT: !7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+; CHECK-NEXT: !8 = !DILocation(line: 8, scope: !3)
+; CHECK-NEXT: !9 = !DILocation(line: 9, scope: !3)
More information about the llvm-commits
mailing list