diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h --- a/llvm/include/llvm/IR/DebugInfoMetadata.h +++ b/llvm/include/llvm/IR/DebugInfoMetadata.h @@ -1298,6 +1298,12 @@ (Flags, CC, TypeArray)) TempDISubroutineType clone() const { return cloneImpl(); } + // Returns a new temporary DISubroutineType with updated CC + TempDISubroutineType cloneWithCC(uint8_t CC) const { + auto NewTy = clone(); + NewTy->CC = CC; + return NewTy; + } uint8_t getCC() const { return CC; } @@ -1996,6 +2002,10 @@ DIType *getContainingType() const { return cast_or_null(getRawContainingType()); } + void replaceType(DISubroutineType *Ty) { + assert(isDistinct() && "Only distinct nodes can mutate"); + replaceOperandWith(4, Ty); + } DICompileUnit *getUnit() const { return cast_or_null(getRawUnit()); diff --git a/llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp b/llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp --- a/llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp +++ b/llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp @@ -23,6 +23,7 @@ #include "llvm/IR/Attributes.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Constants.h" +#include "llvm/IR/DIBuilder.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" @@ -1073,6 +1074,16 @@ for (auto MD : MDs) NF->addMetadata(MD.first, *MD.second); + // If either the return value(s) or argument(s) are removed, then probably the + // function does not follow standard calling conventions anymore. Hence add + // DW_CC_nocall to DISubroutineType to inform debugger that it may not safe to + // call this function or try to interpret the return value. + if (NFTy != FTy && NF->getSubprogram()) { + DISubprogram *SP = NF->getSubprogram(); + auto Temp = SP->getType()->cloneWithCC(llvm::dwarf::DW_CC_nocall); + SP->replaceType(MDNode::replaceWithPermanent(std::move(Temp))); + } + // Now that the old function is dead, delete it. F->eraseFromParent(); diff --git a/llvm/test/Transforms/DeadArgElim/2010-04-30-DbgInfo.ll b/llvm/test/Transforms/DeadArgElim/2010-04-30-DbgInfo.ll --- a/llvm/test/Transforms/DeadArgElim/2010-04-30-DbgInfo.ll +++ b/llvm/test/Transforms/DeadArgElim/2010-04-30-DbgInfo.ll @@ -1,9 +1,12 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature ; RUN: opt -S -passes=deadargelim < %s | FileCheck %s +; Apart from checking if debug metadata is correctly propagated, this also tests whether DW_CC_nocall +; calling convention is added when either return values or arguments are removed. + @.str = private constant [1 x i8] zeroinitializer, align 1 ; <[1 x i8]*> [#uses=1] -define i8* @vfs_addname(i8* %name, i32 %len, i32 %hash, i32 %flags) nounwind ssp { +define i8* @vfs_addname(i8* %name, i32 %len, i32 %hash, i32 %flags) nounwind ssp !dbg !1 { ; entry: call void @llvm.dbg.value(metadata i8* %name, metadata !0, metadata !DIExpression()), !dbg !DILocation(scope: !1) @@ -17,7 +20,7 @@ declare void @llvm.dbg.declare(metadata, metadata, metadata) nounwind readnone -define internal fastcc i8* @add_name_internal(i8* %name, i32 %len, i32 %hash, i8 zeroext %extra, i32 %flags) noinline nounwind ssp { +define internal fastcc i8* @add_name_internal(i8* %name, i32 %len, i32 %hash, i8 zeroext %extra, i32 %flags) noinline nounwind ssp !dbg !16 { ; entry: call void @llvm.dbg.value(metadata i8* %name, metadata !15, metadata !DIExpression()), !dbg !DILocation(scope: !16) @@ -64,7 +67,10 @@ !13 = !DILocation(line: 13, scope: !14) !14 = distinct !DILexicalBlock(line: 12, column: 0, file: !28, scope: !1) !15 = !DILocalVariable(name: "name", line: 17, arg: 1, scope: !16, file: !2, type: !6) +; CHECK: !DISubprogram(name: "add_name_internal" +; CHECK-SAME: type: ![[MD:[0-9]+]] !16 = distinct !DISubprogram(name: "add_name_internal", linkageName: "add_name_internal", line: 22, isLocal: true, isDefinition: true, virtualIndex: 6, isOptimized: false, unit: !3, file: !28, scope: !2, type: !17) +; CHECK: ![[MD]] = !DISubroutineType(cc: DW_CC_nocall, types: !{{[0-9]+}}) !17 = !DISubroutineType(types: !18) !18 = !{!6, !6, !9, !9, !19, !9} !19 = !DIBasicType(tag: DW_TAG_base_type, name: "unsigned char", size: 8, align: 8, encoding: DW_ATE_unsigned_char)