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 @@ -873,11 +873,13 @@ /// 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, - /// ignores callback uses, and assume like pointer annotation calls. + /// 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 IgnoreAssumeLikeCalls = false) const; + bool IgnoreAssumeLikeCalls = false, + bool IngoreLLVMUsed = 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 @@ -81,7 +81,8 @@ // it is not a callback, then anything could call it. if (!F->hasLocalLinkage() || F->hasAddressTaken(nullptr, /*IgnoreCallbackUses=*/true, - /* IgnoreAssumeLikeCalls */ true)) + /* IgnoreAssumeLikeCalls */ true, + /* IgnoreLLVMUsed */ 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 @@ -52,6 +52,7 @@ #include "llvm/IR/MDBuilder.h" #include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" +#include "llvm/IR/Operator.h" #include "llvm/IR/SymbolTableListTraits.h" #include "llvm/IR/Type.h" #include "llvm/IR/Use.h" @@ -1579,10 +1580,12 @@ /// hasAddressTaken - returns true if there are any uses of this function /// other than direct calls or invokes to it. Optionally ignores callback -/// uses and assume like pointer annotation calls. +/// uses, assume like pointer annotation calls, and references in llvm.used +/// and llvm.compiler.used variables. bool Function::hasAddressTaken(const User **PutOffender, bool IgnoreCallbackUses, - bool IgnoreAssumeLikeCalls) const { + bool IgnoreAssumeLikeCalls, + bool IgnoreLLVMUsed) const { for (const Use &U : uses()) { const User *FU = U.getUser(); if (isa(FU)) @@ -1607,6 +1610,20 @@ continue; } } + if (IgnoreLLVMUsed && !FU->user_empty()) { + const User *FUU = FU; + if (isa(FU) && FU->hasOneUse() && + !FU->user_begin()->user_empty()) + FUU = *FU->user_begin(); + if (llvm::all_of(FUU->users(), [](const User *U) { + if (const auto *GV = dyn_cast(U)) + return GV->hasName() && + (GV->getName().equals("llvm.compiler.used") || + GV->getName().equals("llvm.used")); + return false; + })) + continue; + } if (PutOffender) *PutOffender = FU; return true; diff --git a/llvm/test/Analysis/CallGraph/ignore-llvm-used.ll b/llvm/test/Analysis/CallGraph/ignore-llvm-used.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Analysis/CallGraph/ignore-llvm-used.ll @@ -0,0 +1,29 @@ +; RUN: opt < %s -print-callgraph -disable-output 2>&1 | FileCheck %s +; CHECK: Call graph node <><<{{.*}}>> #uses=0 +; CHECK-NEXT: CS calls function 'unused' +; CHECK-EMPTY: +; CHECK-NEXT: Call graph node for function: 'unused'<<{{.*}}>> #uses=1 +; CHECK-EMPTY: +; CHECK-NEXT: Call graph node for function: 'used1'<<{{.*}}>> #uses=0 +; CHECK-EMPTY: +; CHECK-NEXT: Call graph node for function: 'used2'<<{{.*}}>> #uses=0 +; CHECK-EMPTY: + +@llvm.used = appending global [1 x i8*] [i8* bitcast (void ()* @used1 to i8*)] +@llvm.compiler.used = appending global [1 x void()*] [void ()* @used2] +@array = appending global [1 x i8*] [i8* bitcast (void ()* @unused to i8*)] + +define internal void @used1() { +entry: + ret void +} + +define internal void @used2() { +entry: + ret void +} + +define internal void @unused() { +entry: + ret void +}