Skip to content

[Dwarf][Transforms] Add dwarf support when func signature changed #127855

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions llvm/include/llvm/BinaryFormat/Dwarf.def
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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.

Expand Down
4 changes: 3 additions & 1 deletion llvm/include/llvm/IR/DebugInfoFlags.def
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
5 changes: 5 additions & 0 deletions llvm/include/llvm/IR/DebugInfoMetadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
12 changes: 12 additions & 0 deletions llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// TODO: Add specifics about what changed.
This will clarify that you expect to add more info later, and that's why it's a tag not an attribute. (Which was my first question when reading the code. It took a more careful reading of the commit message to understand the longer-term goal.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are correct. The tag intends for future extensibility.


void DwarfUnit::updateAcceleratorTables(const DIScope *Context,
const DIType *Ty, const DIE &TyDIE) {
if (Ty->getName().empty())
Expand Down Expand Up @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
8 changes: 8 additions & 0 deletions llvm/lib/Transforms/IPO/ArgumentPromotion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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)) {
Expand All @@ -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())
Expand All @@ -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())
Expand Down Expand Up @@ -433,6 +437,10 @@ doPromotion(Function *F, FunctionAnalysisManager &FAM,
PromoteMemToReg(Allocas, DT, &AC);
}

DISubprogram *SP = NF->getSubprogram();
if (SP && CurrFuncArgChanged)
SP->setArgChanged();

return NF;
}

Expand Down
10 changes: 10 additions & 0 deletions llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)));
}
Expand Down
95 changes: 95 additions & 0 deletions llvm/test/DebugInfo/X86/arg-prom.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
; RUN: opt -S -passes=argpromotion < %s | FileCheck %s
;
; Source code:
; __attribute__((noinline)) static int is_absolute_path(const char *path)
; {
; return path[0] == '/';
; }
;
; void quit(char *buf);
; const char *make_nonrelative_path(char *buf, const char *path)
; {
; if (is_absolute_path(path))
; quit(buf);
; return buf;
; }

define dso_local ptr @make_nonrelative_path(ptr noundef %buf, ptr noundef %path) local_unnamed_addr #0 !dbg !10 {
#dbg_value(ptr %buf, !18, !DIExpression(), !20)
#dbg_value(ptr %path, !19, !DIExpression(), !20)
%x = call fastcc i32 @is_absolute_path(ptr noundef %path), !dbg !21
%y = icmp eq i32 %x, 0, !dbg !21
br i1 %y, label %to_ret, label %to_quit, !dbg !21

to_quit:
call void @quit(ptr noundef %buf), !dbg !23
br label %to_ret, !dbg !23

to_ret:
ret ptr %buf, !dbg !24
}

; Function Attrs: noinline nounwind uwtable
define internal fastcc range(i32 0, 2) i32 @is_absolute_path(ptr noundef %path) unnamed_addr #1 !dbg !25 {
#dbg_value(ptr %path, !30, !DIExpression(), !31)
%x = load i8, ptr %path, align 1, !dbg !32, !tbaa !33
%y = icmp eq i8 %x, 47, !dbg !36
%z = zext i1 %y to i32, !dbg !36
ret i32 %z, !dbg !37
}

; CHECK: define internal fastcc range(i32 0, 2) i32 @is_absolute_path(i8 {{.*}})

declare !dbg !38 void @quit(ptr noundef) local_unnamed_addr

attributes #0 = { nounwind }
attributes #1 = { noinline nounwind }

!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8}
!llvm.ident = !{!9}

!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang version 21.0.0git ([email protected]:yonghong-song/llvm-project.git 25cfee009e78194d1f7ca70779d63ef1936cc7b9)", 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: "bcc8cf18726713f5d2ab6d82e8ff459d")
!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 = !{i32 7, !"debug-info-assignment-tracking", i1 true}
!9 = !{!"clang version 21.0.0git ([email protected]:yonghong-song/llvm-project.git 25cfee009e78194d1f7ca70779d63ef1936cc7b9)"}
!10 = distinct !DISubprogram(name: "make_nonrelative_path", scope: !1, file: !1, line: 7, type: !11, scopeLine: 8, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !17)
!11 = !DISubroutineType(types: !12)
!12 = !{!13, !16, !13}
!13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64)
!14 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !15)
!15 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
!16 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !15, size: 64)
!17 = !{!18, !19}
!18 = !DILocalVariable(name: "buf", arg: 1, scope: !10, file: !1, line: 7, type: !16)
!19 = !DILocalVariable(name: "path", arg: 2, scope: !10, file: !1, line: 7, type: !13)
!20 = !DILocation(line: 0, scope: !10)
!21 = !DILocation(line: 9, column: 7, scope: !22)
!22 = distinct !DILexicalBlock(scope: !10, file: !1, line: 9, column: 7)
!23 = !DILocation(line: 10, column: 5, scope: !22)
!24 = !DILocation(line: 11, column: 3, scope: !10)
!25 = distinct !DISubprogram(name: "is_absolute_path", scope: !1, file: !1, line: 1, type: !26, scopeLine: 2, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !29)

; CHECK: distinct !DISubprogram(name: "is_absolute_path", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[#]], scopeLine: [[#]], flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized | DISPFlagArgChanged, unit: ![[#]], retainedNodes: ![[#]])

!26 = !DISubroutineType(types: !27)
!27 = !{!28, !13}
!28 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
!29 = !{!30}
!30 = !DILocalVariable(name: "path", arg: 1, scope: !25, file: !1, line: 1, type: !13)
!31 = !DILocation(line: 0, scope: !25)
!32 = !DILocation(line: 3, column: 10, scope: !25)
!33 = !{!34, !34, i64 0}
!34 = !{!"omnipotent char", !35, i64 0}
!35 = !{!"Simple C/C++ TBAA"}
!36 = !DILocation(line: 3, column: 18, scope: !25)
!37 = !DILocation(line: 3, column: 3, scope: !25)
!38 = !DISubprogram(name: "quit", scope: !1, file: !1, line: 6, type: !39, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized)
!39 = !DISubroutineType(types: !40)
!40 = !{null, !16}
76 changes: 76 additions & 0 deletions llvm/test/DebugInfo/X86/arg-retval-elim.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
; RUN: opt -S -passes=deadargelim < %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;
; }

define dso_local noundef i32 @bar(i32 noundef %a) local_unnamed_addr #0 !dbg !10 {
#dbg_value(i32 %a, !15, !DIExpression(), !16)
%2 = tail call fastcc i32 @foo(i32 noundef %a, i32 noundef 1), !dbg !17
ret i32 0, !dbg !18
}

define internal fastcc i32 @foo(i32 noundef %a, i32 noundef %b) unnamed_addr #1 !dbg !19 {
#dbg_value(i32 %a, !23, !DIExpression(), !25)
#dbg_value(i32 %b, !24, !DIExpression(), !25)
%x = tail call i32 @tar(i32 noundef %a), !dbg !26
%t = add nsw i32 %a, 1, !dbg !27
%y = tail call i32 @tar(i32 noundef %t), !dbg !28
%z = add nsw i32 %y, %x, !dbg !29
ret i32 %z, !dbg !30
}

; CHECK: define internal fastcc void @foo(i32 noundef %a)

declare !dbg !31 i32 @tar(i32 noundef) local_unnamed_addr

attributes #0 = { nounwind }
attributes #1 = { noinline nounwind }

!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8}
!llvm.ident = !{!9}

!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang version 21.0.0git ([email protected]:yonghong-song/llvm-project.git 25cfee009e78194d1f7ca70779d63ef1936cc7b9)", 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 = !{i32 7, !"debug-info-assignment-tracking", i1 true}
!9 = !{!"clang version 21.0.0git ([email protected]:yonghong-song/llvm-project.git 25cfee009e78194d1f7ca70779d63ef1936cc7b9)"}
!10 = distinct !DISubprogram(name: "bar", scope: !1, file: !1, line: 6, type: !11, scopeLine: 7, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !14)
!11 = !DISubroutineType(types: !12)
!12 = !{!13, !13}
!13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
!14 = !{!15}
!15 = !DILocalVariable(name: "a", arg: 1, scope: !10, file: !1, line: 6, type: !13)
!16 = !DILocation(line: 0, scope: !10)
!17 = !DILocation(line: 8, column: 3, scope: !10)
!18 = !DILocation(line: 9, column: 3, scope: !10)
!19 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 2, type: !20, scopeLine: 3, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !22)

; CHECK: distinct !DISubprogram(name: "foo", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[#]], scopeLine: [[#]], flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized | DISPFlagArgChanged | DISPFlagRetvalRemoved, unit: !0, retainedNodes: ![[#]])

!20 = !DISubroutineType(types: !21)
!21 = !{!13, !13, !13}
!22 = !{!23, !24}
!23 = !DILocalVariable(name: "a", arg: 1, scope: !19, file: !1, line: 2, type: !13)
!24 = !DILocalVariable(name: "b", arg: 2, scope: !19, file: !1, line: 2, type: !13)
!25 = !DILocation(line: 0, scope: !19)
!26 = !DILocation(line: 4, column: 10, scope: !19)
!27 = !DILocation(line: 4, column: 25, scope: !19)
!28 = !DILocation(line: 4, column: 19, scope: !19)
!29 = !DILocation(line: 4, column: 17, scope: !19)
!30 = !DILocation(line: 4, column: 3, scope: !19)
!31 = !DISubprogram(name: "tar", scope: !1, file: !1, line: 1, type: !11, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized)