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 @@ -884,8 +884,7 @@ /// 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; 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 @@ -1624,6 +1624,14 @@ continue; } + if (isa(FU) && isa(FU) && + llvm::all_of(FU->uses(), [](const Use &U) { + if (const CallBase *CB = dyn_cast(U.getUser())) + return CB->isCallee(&U); + return false; + })) + continue; + const auto *Call = dyn_cast(FU); if (!Call) { if (IgnoreAssumeLikeCalls) { diff --git a/llvm/test/Analysis/CallGraph/ignore-bitcast-call-argument-callee.ll b/llvm/test/Analysis/CallGraph/ignore-bitcast-call-argument-callee.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Analysis/CallGraph/ignore-bitcast-call-argument-callee.ll @@ -0,0 +1,30 @@ +; 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: 'bar'<<{{.*}}>> #uses=1 +; CHECK-EMPTY: +; CHECK-NEXT: Call graph node for function: 'foo'<<{{.*}}>> #uses=1 +; CHECK-EMPTY: +; CHECK-NEXT: Call graph node for function: 'test'<<{{.*}}>> #uses=0 +; CHECK-NEXT: CS<{{.*}}> calls function 'bar' +; CHECK-NEXT: CS<{{.*}}> calls external node + +define internal i32 @foo() { +entry: + ret i32 5 +} + +define internal i32 @bar(float()* %arg) { + ret i32 5 +} + +define internal i32 @test() { + %v1 = call i32 @bar(float()* bitcast (i32()* @foo to float()*)) + %v2 = call float bitcast (i32()* @foo to float()*)() + %v3 = fptoui float %v2 to i32 + %v4 = add i32 %v1, %v3 + ret i32 %v4 +} + diff --git a/llvm/test/Analysis/CallGraph/ignore-bitcast-call-argument.ll b/llvm/test/Analysis/CallGraph/ignore-bitcast-call-argument.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Analysis/CallGraph/ignore-bitcast-call-argument.ll @@ -0,0 +1,27 @@ +; 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: 'bar'<<{{.*}}>> #uses=1 +; CHECK-EMPTY: +; CHECK-NEXT: Call graph node for function: 'foo'<<{{.*}}>> #uses=1 +; CHECK-EMPTY: +; CHECK-NEXT: Call graph node for function: 'test'<<{{.*}}>> #uses=0 +; CHECK-NEXT: CS<{{.*}}> calls function 'bar' + +define internal i32 @foo() { +entry: + ret i32 5 +} + +define internal i32 @bar(float()* %arg) { + ret i32 5 +} + +define internal i32 @test() { + %v1 = call i32 @bar(float()* bitcast (i32()* @foo to float()*)) + %v2 = add i32 %v1, 6 + ret i32 %v2 +} + 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,23 @@ +; RUN: opt < %s -print-callgraph -disable-output 2>&1 | FileCheck %s +; CHECK: Call graph node <><<{{.*}}>> #uses=0 +; CHECK-EMPTY: +; CHECK-NEXT: Call graph node for function: 'foo'<<{{.*}}>> #uses=0 +; 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() { +entry: + ret i32 5 +} + +define internal float @test_bitcast_callees() { + %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 +} +