diff --git a/llvm/include/llvm/IR/Function.h b/llvm/include/llvm/IR/Function.h --- a/llvm/include/llvm/IR/Function.h +++ b/llvm/include/llvm/IR/Function.h @@ -876,10 +876,10 @@ /// ignores callback uses, assume like pointer annotation calls, and /// references in llvm.used and llvm.compiler.used variables. /// - bool hasAddressTaken(const User ** = nullptr, - bool IgnoreCallbackUses = false, + bool hasAddressTaken(const User ** = nullptr, bool IgnoreCallbackUses = false, bool IgnoreAssumeLikeCalls = false, - bool IngoreLLVMUsed = false) const; + bool IngoreLLVMUsed = false, + bool IgnoreBitCastCallees = false) const; /// isDefTriviallyDead - Return true if it is trivially safe to remove /// this function definition from the module (because it isn't externally diff --git a/llvm/lib/IR/Function.cpp b/llvm/lib/IR/Function.cpp --- a/llvm/lib/IR/Function.cpp +++ b/llvm/lib/IR/Function.cpp @@ -1584,8 +1584,8 @@ /// and llvm.compiler.used variables. bool Function::hasAddressTaken(const User **PutOffender, bool IgnoreCallbackUses, - bool IgnoreAssumeLikeCalls, - bool IgnoreLLVMUsed) const { + bool IgnoreAssumeLikeCalls, bool IgnoreLLVMUsed, + bool IgnoreBitCastCallees) const { for (const Use &U : uses()) { const User *FU = U.getUser(); if (isa(FU)) @@ -1597,6 +1597,13 @@ continue; } + if (IgnoreBitCastCallees) { + if (isa(FU) && + llvm::all_of(FU->users(), + [](const User *U) { return isa(U); })) + continue; + } + const auto *Call = dyn_cast(FU); if (!Call) { if (IgnoreAssumeLikeCalls) { diff --git a/llvm/test/Analysis/CallGraph/ignore-bitcast-callees.ll b/llvm/test/Analysis/CallGraph/ignore-bitcast-callees.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Analysis/CallGraph/ignore-bitcast-callees.ll @@ -0,0 +1,24 @@ +; RUN: opt < %s -print-callgraph -disable-output 2>&1 | FileCheck %s +; CHECK: Call graph node <><<{{.*}}>> #uses=0 +; CHECK-NEXT: CS calls function 'foo' +; CHECK-EMPTY: +; CHECK-NEXT: Call graph node for function: 'foo'<<{{.*}}>> #uses=1 +; CHECK-EMPTY: +; CHECK-NEXT: Call graph node for function: 'test_bitcast_callees'<<{{.*}}>> #uses=0 +; CHECK-NEXT: CS<{{.*}}> calls external node +; CHECK-NEXT: CS<{{.*}}> calls external node + +define internal i32 @foo() #1 { +entry: + ret i32 5 +} + +define internal float @test_bitcast_callees() #1 { + %v1 = call float bitcast (i32()* @foo to float()*)() + %v2 = fadd float %v1, 1.0 + %v3 = call i8 bitcast (i32()* @foo to i8()*)() + %v4 = uitofp i8 %v3 to float + %v5 = fadd float %v2, %v4 + ret float %v5 +} +