forked from OSchip/llvm-project
[GlobalDCE, Misc] Don't remove functions referenced by ifuncs
We forgot to consider the target of ifuncs when considering if a function was alive or dead. N.B. Also update a few auxiliary tools like bugpoint and verify-uselistorder. This fixes PR27593. llvm-svn: 268468
This commit is contained in:
parent
c44644d6e9
commit
95549497ec
|
@ -78,21 +78,6 @@ public:
|
|||
return getIndirectSymbol();
|
||||
}
|
||||
|
||||
const GlobalObject *getBaseObject() const {
|
||||
return const_cast<GlobalAlias *>(this)->getBaseObject();
|
||||
}
|
||||
GlobalObject *getBaseObject() {
|
||||
return dyn_cast<GlobalObject>(getAliasee()->stripInBoundsOffsets());
|
||||
}
|
||||
|
||||
const GlobalObject *getBaseObject(const DataLayout &DL, APInt &Offset) const {
|
||||
return const_cast<GlobalAlias *>(this)->getBaseObject(DL, Offset);
|
||||
}
|
||||
GlobalObject *getBaseObject(const DataLayout &DL, APInt &Offset) {
|
||||
return dyn_cast<GlobalObject>(
|
||||
getAliasee()->stripAndAccumulateInBoundsConstantOffsets(DL, Offset));
|
||||
}
|
||||
|
||||
static bool isValidLinkage(LinkageTypes L) {
|
||||
return isExternalLinkage(L) || isLocalLinkage(L) ||
|
||||
isWeakLinkage(L) || isLinkOnceLinkage(L);
|
||||
|
|
|
@ -49,6 +49,22 @@ public:
|
|||
return getOperand(0);
|
||||
}
|
||||
|
||||
const GlobalObject *getBaseObject() const {
|
||||
return const_cast<GlobalIndirectSymbol *>(this)->getBaseObject();
|
||||
}
|
||||
GlobalObject *getBaseObject() {
|
||||
return dyn_cast<GlobalObject>(getIndirectSymbol()->stripInBoundsOffsets());
|
||||
}
|
||||
|
||||
const GlobalObject *getBaseObject(const DataLayout &DL, APInt &Offset) const {
|
||||
return const_cast<GlobalIndirectSymbol *>(this)->getBaseObject(DL, Offset);
|
||||
}
|
||||
GlobalObject *getBaseObject(const DataLayout &DL, APInt &Offset) {
|
||||
return dyn_cast<GlobalObject>(
|
||||
getIndirectSymbol()->stripAndAccumulateInBoundsConstantOffsets(DL,
|
||||
Offset));
|
||||
}
|
||||
|
||||
// Methods for support type inquiry through isa, cast, and dyn_cast:
|
||||
static inline bool classof(const Value *V) {
|
||||
return V->getValueID() == Value::GlobalAliasVal ||
|
||||
|
|
|
@ -32,6 +32,7 @@ using namespace llvm;
|
|||
|
||||
STATISTIC(NumAliases , "Number of global aliases removed");
|
||||
STATISTIC(NumFunctions, "Number of functions removed");
|
||||
STATISTIC(NumIFuncs, "Number of indirect functions removed");
|
||||
STATISTIC(NumVariables, "Number of global variables removed");
|
||||
|
||||
namespace {
|
||||
|
@ -118,6 +119,13 @@ PreservedAnalyses GlobalDCEPass::run(Module &M) {
|
|||
GlobalIsNeeded(&GA);
|
||||
}
|
||||
|
||||
for (GlobalIFunc &GIF : M.ifuncs()) {
|
||||
Changed |= RemoveUnusedGlobalValue(GIF);
|
||||
// Externally visible ifuncs are needed.
|
||||
if (!GIF.isDiscardableIfUnused())
|
||||
GlobalIsNeeded(&GIF);
|
||||
}
|
||||
|
||||
// Now that all globals which are needed are in the AliveGlobals set, we loop
|
||||
// through the program, deleting those which are not alive.
|
||||
//
|
||||
|
@ -152,6 +160,14 @@ PreservedAnalyses GlobalDCEPass::run(Module &M) {
|
|||
GA.setAliasee(nullptr);
|
||||
}
|
||||
|
||||
// The third pass drops targets of ifuncs which are dead...
|
||||
std::vector<GlobalIFunc*> DeadIFuncs;
|
||||
for (GlobalIFunc &GIF : M.ifuncs())
|
||||
if (!AliveGlobals.count(&GIF)) {
|
||||
DeadIFuncs.push_back(&GIF);
|
||||
GIF.setResolver(nullptr);
|
||||
}
|
||||
|
||||
if (!DeadFunctions.empty()) {
|
||||
// Now that all interferences have been dropped, delete the actual objects
|
||||
// themselves.
|
||||
|
@ -182,6 +198,16 @@ PreservedAnalyses GlobalDCEPass::run(Module &M) {
|
|||
Changed = true;
|
||||
}
|
||||
|
||||
// Now delete any dead aliases.
|
||||
if (!DeadIFuncs.empty()) {
|
||||
for (GlobalIFunc *GIF : DeadIFuncs) {
|
||||
RemoveUnusedGlobalValue(*GIF);
|
||||
M.getIFuncList().erase(GIF);
|
||||
}
|
||||
NumIFuncs += DeadIFuncs.size();
|
||||
Changed = true;
|
||||
}
|
||||
|
||||
// Make sure that all memory is released
|
||||
AliveGlobals.clear();
|
||||
SeenConstants.clear();
|
||||
|
|
|
@ -47,7 +47,7 @@ static void addNonConstUser(ClusterMapType &GVtoClusterMap,
|
|||
if (const Instruction *I = dyn_cast<Instruction>(U)) {
|
||||
const GlobalValue *F = I->getParent()->getParent();
|
||||
GVtoClusterMap.unionSets(GV, F);
|
||||
} else if (isa<GlobalAlias>(U) || isa<Function>(U) ||
|
||||
} else if (isa<GlobalIndirectSymbol>(U) || isa<Function>(U) ||
|
||||
isa<GlobalVariable>(U)) {
|
||||
GVtoClusterMap.unionSets(GV, cast<GlobalValue>(U));
|
||||
} else {
|
||||
|
@ -107,8 +107,8 @@ static void findPartitions(Module *M, ClusterIDMapType &ClusterIDMap,
|
|||
|
||||
// For aliases we should not separate them from their aliasees regardless
|
||||
// of linkage.
|
||||
if (GlobalAlias *GA = dyn_cast<GlobalAlias>(&GV)) {
|
||||
if (const GlobalObject *Base = GA->getBaseObject())
|
||||
if (auto *GIS = dyn_cast<GlobalIndirectSymbol>(&GV)) {
|
||||
if (const GlobalObject *Base = GIS->getBaseObject())
|
||||
GVtoClusterMap.unionSets(&GV, Base);
|
||||
}
|
||||
|
||||
|
@ -205,8 +205,8 @@ static void externalize(GlobalValue *GV) {
|
|||
|
||||
// Returns whether GV should be in partition (0-based) I of N.
|
||||
static bool isInPartition(const GlobalValue *GV, unsigned I, unsigned N) {
|
||||
if (auto GA = dyn_cast<GlobalAlias>(GV))
|
||||
if (const GlobalObject *Base = GA->getBaseObject())
|
||||
if (auto *GIS = dyn_cast<GlobalIndirectSymbol>(GV))
|
||||
if (const GlobalObject *Base = GIS->getBaseObject())
|
||||
GV = Base;
|
||||
|
||||
StringRef Name;
|
||||
|
@ -236,6 +236,8 @@ void llvm::SplitModule(
|
|||
externalize(&GV);
|
||||
for (GlobalAlias &GA : M->aliases())
|
||||
externalize(&GA);
|
||||
for (GlobalIFunc &GIF : M->ifuncs())
|
||||
externalize(&GIF);
|
||||
}
|
||||
|
||||
// This performs splitting without a need for externalization, which might not
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
; RUN: opt -S -globaldce < %s | FileCheck %s
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
||||
@if = ifunc void (), void ()* @fn
|
||||
|
||||
define internal void @fn() {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK-DAG: @if = ifunc void (), void ()* @fn
|
||||
; CHECK-DAG: define internal void @fn(
|
|
@ -264,8 +264,8 @@ bool ReduceCrashingFunctions::TestFuncs(std::vector<Function*> &Funcs) {
|
|||
std::vector<GlobalValue*> ToRemove;
|
||||
// First, remove aliases to functions we're about to purge.
|
||||
for (GlobalAlias &Alias : M->aliases()) {
|
||||
Constant *Root = Alias.getAliasee()->stripPointerCasts();
|
||||
Function *F = dyn_cast<Function>(Root);
|
||||
GlobalObject *Root = Alias.getBaseObject();
|
||||
Function *F = dyn_cast_or_null<Function>(Root);
|
||||
if (F) {
|
||||
if (Functions.count(F))
|
||||
// We're keeping this function.
|
||||
|
|
|
@ -191,6 +191,8 @@ ValueMapping::ValueMapping(const Module &M) {
|
|||
map(&G);
|
||||
for (const GlobalAlias &A : M.aliases())
|
||||
map(&A);
|
||||
for (const GlobalIFunc &IF : M.ifuncs())
|
||||
map(&IF);
|
||||
for (const Function &F : M)
|
||||
map(&F);
|
||||
|
||||
|
@ -200,6 +202,8 @@ ValueMapping::ValueMapping(const Module &M) {
|
|||
map(G.getInitializer());
|
||||
for (const GlobalAlias &A : M.aliases())
|
||||
map(A.getAliasee());
|
||||
for (const GlobalIFunc &IF : M.ifuncs())
|
||||
map(IF.getResolver());
|
||||
for (const Function &F : M) {
|
||||
if (F.hasPrefixData())
|
||||
map(F.getPrefixData());
|
||||
|
@ -463,6 +467,8 @@ static void changeUseLists(Module &M, Changer changeValueUseList) {
|
|||
changeValueUseList(&G);
|
||||
for (GlobalAlias &A : M.aliases())
|
||||
changeValueUseList(&A);
|
||||
for (GlobalIFunc &IF : M.ifuncs())
|
||||
changeValueUseList(&IF);
|
||||
for (Function &F : M)
|
||||
changeValueUseList(&F);
|
||||
|
||||
|
@ -472,6 +478,8 @@ static void changeUseLists(Module &M, Changer changeValueUseList) {
|
|||
changeValueUseList(G.getInitializer());
|
||||
for (GlobalAlias &A : M.aliases())
|
||||
changeValueUseList(A.getAliasee());
|
||||
for (GlobalIFunc &IF : M.ifuncs())
|
||||
changeValueUseList(IF.getResolver());
|
||||
for (Function &F : M) {
|
||||
if (F.hasPrefixData())
|
||||
changeValueUseList(F.getPrefixData());
|
||||
|
|
Loading…
Reference in New Issue