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 @@ -872,11 +872,12 @@ /// hasAddressTaken - returns true if there are any uses of this function /// other than direct calls or invokes to it, or blockaddress expressions. - /// Optionally passes back an offending user for diagnostic purposes and - /// ignores callback uses. + /// Optionally passes back an offending user for diagnostic purposes, + /// ignores callback uses, and assume like pointer annotation calls. /// bool hasAddressTaken(const User ** = nullptr, - bool IgnoreCallbackUses = false) const; + bool IgnoreCallbackUses = false, + bool IgnoreAssumeLikeCalls = 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/Analysis/CallGraph.cpp b/llvm/lib/Analysis/CallGraph.cpp --- a/llvm/lib/Analysis/CallGraph.cpp +++ b/llvm/lib/Analysis/CallGraph.cpp @@ -80,7 +80,8 @@ // If this function has external linkage or has its address taken and // it is not a callback, then anything could call it. if (!F->hasLocalLinkage() || - F->hasAddressTaken(nullptr, /*IgnoreCallbackUses=*/true)) + F->hasAddressTaken(nullptr, /*IgnoreCallbackUses=*/true, + /* IgnoreAssumeLikeCalls */ true)) ExternalCallingNode->addCalledFunction(nullptr, Node); populateCallGraphNode(Node); 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 @@ -31,6 +31,7 @@ #include "llvm/IR/InstIterator.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" +#include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/IntrinsicsAArch64.h" #include "llvm/IR/IntrinsicsAMDGPU.h" @@ -1578,9 +1579,10 @@ /// hasAddressTaken - returns true if there are any uses of this function /// other than direct calls or invokes to it. Optionally ignores callback -/// uses. +/// uses and assume like pointer annotation calls. bool Function::hasAddressTaken(const User **PutOffender, - bool IgnoreCallbackUses) const { + bool IgnoreCallbackUses, + bool IgnoreAssumeLikeCalls) const { for (const Use &U : uses()) { const User *FU = U.getUser(); if (isa(FU)) @@ -1594,6 +1596,17 @@ const auto *Call = dyn_cast(FU); if (!Call) { + if (IgnoreAssumeLikeCalls) { + if (const auto *FI = dyn_cast(FU)) { + if (FI->isCast() && !FI->user_empty() && + llvm::all_of(FU->users(), [](const User *U) { + if (const auto *I = dyn_cast(U)) + return I->isAssumeLikeIntrinsic(); + return false; + })) + continue; + } + } if (PutOffender) *PutOffender = FU; return true; diff --git a/llvm/test/Analysis/CallGraph/ignore-assumelike-calls.ll b/llvm/test/Analysis/CallGraph/ignore-assumelike-calls.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Analysis/CallGraph/ignore-assumelike-calls.ll @@ -0,0 +1,26 @@ +; RUN: opt < %s -print-callgraph -disable-output 2>&1 | FileCheck %s +; CHECK: Call graph node <><<{{.*}}>> #uses=0 +; CHECK-NEXT: CS calls function 'cast_only' +; CHECK-NEXT: CS calls function 'llvm.lifetime.start.p0i8' +; CHECK-EMPTY: +; CHECK-NEXT: Call graph node for function: 'cast_only'<<{{.*}}>> #uses=1 +; CHECK-EMPTY: +; CHECK-NEXT: Call graph node for function: 'llvm.lifetime.start.p0i8'<<{{.*}}>> #uses=1 +; CHECK-EMPTY: +; CHECK-NEXT: Call graph node for function: 'used_by_lifetime'<<{{.*}}>> #uses=0 +; CHECK-EMPTY: + +define internal void @used_by_lifetime() { +entry: + %c = bitcast void()* @used_by_lifetime to i8* + call void @llvm.lifetime.start.p0i8(i64 4, i8* %c) + ret void +} + +define internal void @cast_only() { +entry: + %c = bitcast void()* @cast_only to i8* + ret void +} + +declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture)