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 @@ -1300,6 +1300,7 @@ TempDISubroutineType clone() const { return cloneImpl(); } uint8_t getCC() const { return CC; } + void setCC(uint8_t NewCC) { CC = NewCC; } DITypeRefArray getTypeArray() const { return cast_or_null(getRawTypeArray()); 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" @@ -1083,6 +1084,15 @@ for (auto MD : MDs) NF->addMetadata(MD.first, *MD.second); + // If all the return values are removed, add DW_CC_nocall to DISubroutineType + // so that debuggers will know it is not safe to call this function or try to + // interpret the return value. + // FIXME: Should we add DW_CC_nocall simply when NFTy != FTy i.e. whenever + // an unused return value or an argument is removed? + if (!RetTy->isVoidTy() && NRetTy->isVoidTy() && NF->getSubprogram()) + // Change CallingConvention to DW_CC_nocall + NF->getSubprogram()->getType()->setCC(llvm::dwarf::DW_CC_nocall); + // 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,23 +1,27 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature -; RUN: opt -S -passes=deadargelim < %s | FileCheck %s +; RUN: opt < %s -S -passes=deadargelim > %t +; RUN: cat %t | FileCheck %s +; Test whether DW_CC_nocall calling convention is added when return values are removed and return type changed to void. +; RUN: cat %t | grep "define internal fastcc void \@add_name_internal" +; RUN: cat %t | grep DW_CC_nocall @.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) call void @llvm.dbg.value(metadata i32 %len, metadata !10, metadata !DIExpression()), !dbg !DILocation(scope: !1) call void @llvm.dbg.value(metadata i32 %hash, metadata !11, metadata !DIExpression()), !dbg !DILocation(scope: !1) call void @llvm.dbg.value(metadata i32 %flags, metadata !12, metadata !DIExpression()), !dbg !DILocation(scope: !1) -; CHECK: call fastcc i8* @add_name_internal(i8* %name, i32 %hash) [[NUW:#[0-9]+]], !dbg !{{[0-9]+}} +; CHECK: call fastcc void @add_name_internal(i8* %name, i32 %hash) [[NUW:#[0-9]+]], !dbg !{{[0-9]+}} %0 = call fastcc i8* @add_name_internal(i8* %name, i32 %len, i32 %hash, i8 zeroext 0, i32 %flags) nounwind, !dbg !13 ; [#uses=1] - ret i8* %0, !dbg !13 + ret i8* %name, !dbg !13 } 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)