mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 20:23:11 +01:00
[Inliner] Discard empty COMDAT groups
COMDAT groups which have become rendered unused because of inline are discardable if we can prove that we've made the group empty. This fixes PR22285. llvm-svn: 236539
This commit is contained in:
parent
cdb160f205
commit
06d0bf99d8
@ -625,6 +625,21 @@ bool Inliner::doFinalization(CallGraph &CG) {
|
|||||||
/// Remove dead functions that are not included in DNR (Do Not Remove) list.
|
/// Remove dead functions that are not included in DNR (Do Not Remove) list.
|
||||||
bool Inliner::removeDeadFunctions(CallGraph &CG, bool AlwaysInlineOnly) {
|
bool Inliner::removeDeadFunctions(CallGraph &CG, bool AlwaysInlineOnly) {
|
||||||
SmallVector<CallGraphNode*, 16> FunctionsToRemove;
|
SmallVector<CallGraphNode*, 16> FunctionsToRemove;
|
||||||
|
SmallVector<CallGraphNode *, 16> DeadFunctionsInComdats;
|
||||||
|
SmallDenseMap<const Comdat *, int, 16> ComdatEntriesAlive;
|
||||||
|
|
||||||
|
auto RemoveCGN = [&](CallGraphNode *CGN) {
|
||||||
|
// Remove any call graph edges from the function to its callees.
|
||||||
|
CGN->removeAllCalledFunctions();
|
||||||
|
|
||||||
|
// Remove any edges from the external node to the function's call graph
|
||||||
|
// node. These edges might have been made irrelegant due to
|
||||||
|
// optimization of the program.
|
||||||
|
CG.getExternalCallingNode()->removeAnyCallEdgeTo(CGN);
|
||||||
|
|
||||||
|
// Removing the node for callee from the call graph and delete it.
|
||||||
|
FunctionsToRemove.push_back(CGN);
|
||||||
|
};
|
||||||
|
|
||||||
// Scan for all of the functions, looking for ones that should now be removed
|
// Scan for all of the functions, looking for ones that should now be removed
|
||||||
// from the program. Insert the dead ones in the FunctionsToRemove set.
|
// from the program. Insert the dead ones in the FunctionsToRemove set.
|
||||||
@ -651,20 +666,45 @@ bool Inliner::removeDeadFunctions(CallGraph &CG, bool AlwaysInlineOnly) {
|
|||||||
// without also dropping the other members of the COMDAT.
|
// without also dropping the other members of the COMDAT.
|
||||||
// The inliner doesn't visit non-function entities which are in COMDAT
|
// The inliner doesn't visit non-function entities which are in COMDAT
|
||||||
// groups so it is unsafe to do so *unless* the linkage is local.
|
// groups so it is unsafe to do so *unless* the linkage is local.
|
||||||
if (!F->hasLocalLinkage() && F->hasComdat())
|
if (!F->hasLocalLinkage()) {
|
||||||
continue;
|
if (const Comdat *C = F->getComdat()) {
|
||||||
|
--ComdatEntriesAlive[C];
|
||||||
// Remove any call graph edges from the function to its callees.
|
DeadFunctionsInComdats.push_back(CGN);
|
||||||
CGN->removeAllCalledFunctions();
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Remove any edges from the external node to the function's call graph
|
RemoveCGN(CGN);
|
||||||
// node. These edges might have been made irrelegant due to
|
|
||||||
// optimization of the program.
|
|
||||||
CG.getExternalCallingNode()->removeAnyCallEdgeTo(CGN);
|
|
||||||
|
|
||||||
// Removing the node for callee from the call graph and delete it.
|
|
||||||
FunctionsToRemove.push_back(CGN);
|
|
||||||
}
|
}
|
||||||
|
if (!DeadFunctionsInComdats.empty()) {
|
||||||
|
// Count up all the entities in COMDAT groups
|
||||||
|
auto ComdatGroupReferenced = [&](const Comdat *C) {
|
||||||
|
auto I = ComdatEntriesAlive.find(C);
|
||||||
|
if (I != ComdatEntriesAlive.end())
|
||||||
|
++(I->getSecond());
|
||||||
|
};
|
||||||
|
for (const Function &F : CG.getModule())
|
||||||
|
if (const Comdat *C = F.getComdat())
|
||||||
|
ComdatGroupReferenced(C);
|
||||||
|
for (const GlobalVariable &GV : CG.getModule().globals())
|
||||||
|
if (const Comdat *C = GV.getComdat())
|
||||||
|
ComdatGroupReferenced(C);
|
||||||
|
for (const GlobalAlias &GA : CG.getModule().aliases())
|
||||||
|
if (const Comdat *C = GA.getComdat())
|
||||||
|
ComdatGroupReferenced(C);
|
||||||
|
for (CallGraphNode *CGN : DeadFunctionsInComdats) {
|
||||||
|
Function *F = CGN->getFunction();
|
||||||
|
const Comdat *C = F->getComdat();
|
||||||
|
int NumAlive = ComdatEntriesAlive[C];
|
||||||
|
// We can remove functions in a COMDAT group if the entire group is dead.
|
||||||
|
assert(NumAlive >= 0);
|
||||||
|
if (NumAlive > 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
RemoveCGN(CGN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (FunctionsToRemove.empty())
|
if (FunctionsToRemove.empty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
15
test/Transforms/Inline/pr22285.ll
Normal file
15
test/Transforms/Inline/pr22285.ll
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
; RUN: opt < %s -inline -S | FileCheck %s
|
||||||
|
|
||||||
|
$f1 = comdat any
|
||||||
|
; CHECK-NOT: $f1 = comdat any
|
||||||
|
|
||||||
|
define void @f2() {
|
||||||
|
call void @f1()
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
; CHECK-LABEL: define void @f2
|
||||||
|
|
||||||
|
define linkonce_odr void @f1() comdat {
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
; CHECK-NOT: define linkonce_odr void @f1() comdat
|
Loading…
Reference in New Issue
Block a user