Index: llvm/include/llvm/IR/Function.h =================================================================== --- llvm/include/llvm/IR/Function.h +++ llvm/include/llvm/IR/Function.h @@ -876,7 +876,8 @@ /// ignores callback uses. /// 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 Index: llvm/lib/Analysis/CallGraph.cpp =================================================================== --- llvm/lib/Analysis/CallGraph.cpp +++ 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); Index: llvm/lib/IR/Function.cpp =================================================================== --- llvm/lib/IR/Function.cpp +++ 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" @@ -1580,7 +1581,8 @@ /// other than direct calls or invokes to it. Optionally ignores callback /// uses. 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; Index: llvm/test/Analysis/CallGraph/ignore-assumelike-calls.ll =================================================================== --- /dev/null +++ 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)