Index: llvm/include/llvm/IR/Function.h =================================================================== --- llvm/include/llvm/IR/Function.h +++ llvm/include/llvm/IR/Function.h @@ -877,7 +877,8 @@ /// 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 Index: llvm/lib/Analysis/CallGraph.cpp =================================================================== --- llvm/lib/Analysis/CallGraph.cpp +++ 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); Index: llvm/lib/IR/Function.cpp =================================================================== --- llvm/lib/IR/Function.cpp +++ 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" @@ -1582,7 +1583,8 @@ /// uses. bool Function::hasAddressTaken(const User **PutOffender, bool IgnoreCallbackUses, - bool IgnoreAssumeLikeCalls) const { + bool IgnoreAssumeLikeCalls, + bool IngoreLLVMUsed) const { for (const Use &U : uses()) { const User *FU = U.getUser(); if (isa(FU)) @@ -1607,6 +1609,20 @@ continue; } } + if (IngoreLLVMUsed && !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; Index: llvm/test/Analysis/CallGraph/ignore-llvm-used.ll =================================================================== --- /dev/null +++ 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 +}