aboutsummaryrefslogtreecommitdiff
path: root/lib/Transforms/IPO/MergeFunctions.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2019-08-20 20:50:12 +0000
committerDimitry Andric <dim@FreeBSD.org>2019-08-20 20:50:12 +0000
commite6d1592492a3a379186bfb02bd0f4eda0669c0d5 (patch)
tree599ab169a01f1c86eda9adc774edaedde2f2db5b /lib/Transforms/IPO/MergeFunctions.cpp
parent1a56a5ead7a2e84bee8240f5f6b033b5f1707154 (diff)
Diffstat (limited to 'lib/Transforms/IPO/MergeFunctions.cpp')
-rw-r--r--lib/Transforms/IPO/MergeFunctions.cpp70
1 files changed, 27 insertions, 43 deletions
diff --git a/lib/Transforms/IPO/MergeFunctions.cpp b/lib/Transforms/IPO/MergeFunctions.cpp
index 11efe95b10d4..3a08069dcd4a 100644
--- a/lib/Transforms/IPO/MergeFunctions.cpp
+++ b/lib/Transforms/IPO/MergeFunctions.cpp
@@ -1,9 +1,8 @@
//===- MergeFunctions.cpp - Merge identical functions ---------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -190,8 +189,6 @@ public:
void replaceBy(Function *G) const {
F = G;
}
-
- void release() { F = nullptr; }
};
/// MergeFunctions finds functions which will generate identical machine code,
@@ -281,8 +278,8 @@ private:
// Replace G with an alias to F (deleting function G)
void writeAlias(Function *F, Function *G);
- // Replace G with an alias to F if possible, or a thunk to F if
- // profitable. Returns false if neither is the case.
+ // Replace G with an alias to F if possible, or a thunk to F if possible.
+ // Returns false if neither is the case.
bool writeThunkOrAlias(Function *F, Function *G);
/// Replace function F with function G in the function tree.
@@ -383,6 +380,11 @@ bool MergeFunctions::doSanityCheck(std::vector<WeakTrackingVH> &Worklist) {
}
#endif
+/// Check whether \p F is eligible for function merging.
+static bool isEligibleForMerging(Function &F) {
+ return !F.isDeclaration() && !F.hasAvailableExternallyLinkage();
+}
+
bool MergeFunctions::runOnModule(Module &M) {
if (skipModule(M))
return false;
@@ -394,17 +396,12 @@ bool MergeFunctions::runOnModule(Module &M) {
std::vector<std::pair<FunctionComparator::FunctionHash, Function *>>
HashedFuncs;
for (Function &Func : M) {
- if (!Func.isDeclaration() && !Func.hasAvailableExternallyLinkage()) {
+ if (isEligibleForMerging(Func)) {
HashedFuncs.push_back({FunctionComparator::functionHash(Func), &Func});
}
}
- std::stable_sort(
- HashedFuncs.begin(), HashedFuncs.end(),
- [](const std::pair<FunctionComparator::FunctionHash, Function *> &a,
- const std::pair<FunctionComparator::FunctionHash, Function *> &b) {
- return a.first < b.first;
- });
+ llvm::stable_sort(HashedFuncs, less_first());
auto S = HashedFuncs.begin();
for (auto I = HashedFuncs.begin(), IE = HashedFuncs.end(); I != IE; ++I) {
@@ -654,12 +651,16 @@ void MergeFunctions::filterInstsUnrelatedToPDI(
LLVM_DEBUG(dbgs() << " }\n");
}
-// Don't merge tiny functions using a thunk, since it can just end up
-// making the function larger.
-static bool isThunkProfitable(Function * F) {
+/// Whether this function may be replaced by a forwarding thunk.
+static bool canCreateThunkFor(Function *F) {
+ if (F->isVarArg())
+ return false;
+
+ // Don't merge tiny functions using a thunk, since it can just end up
+ // making the function larger.
if (F->size() == 1) {
if (F->front().size() <= 2) {
- LLVM_DEBUG(dbgs() << "isThunkProfitable: " << F->getName()
+ LLVM_DEBUG(dbgs() << "canCreateThunkFor: " << F->getName()
<< " is too small to bother creating a thunk for\n");
return false;
}
@@ -695,6 +696,7 @@ void MergeFunctions::writeThunk(Function *F, Function *G) {
} else {
NewG = Function::Create(G->getFunctionType(), G->getLinkage(),
G->getAddressSpace(), "", G->getParent());
+ NewG->setComdat(G->getComdat());
BB = BasicBlock::Create(F->getContext(), "", NewG);
}
@@ -787,7 +789,7 @@ bool MergeFunctions::writeThunkOrAlias(Function *F, Function *G) {
writeAlias(F, G);
return true;
}
- if (isThunkProfitable(F)) {
+ if (canCreateThunkFor(F)) {
writeThunk(F, G);
return true;
}
@@ -802,9 +804,9 @@ void MergeFunctions::mergeTwoFunctions(Function *F, Function *G) {
// Both writeThunkOrAlias() calls below must succeed, either because we can
// create aliases for G and NewF, or because a thunk for F is profitable.
// F here has the same signature as NewF below, so that's what we check.
- if (!isThunkProfitable(F) && (!canCreateAliasFor(F) || !canCreateAliasFor(G))) {
+ if (!canCreateThunkFor(F) &&
+ (!canCreateAliasFor(F) || !canCreateAliasFor(G)))
return;
- }
// Make them both thunks to the same internal function.
Function *NewF = Function::Create(F->getFunctionType(), F->getLinkage(),
@@ -944,25 +946,7 @@ void MergeFunctions::remove(Function *F) {
// For each instruction used by the value, remove() the function that contains
// the instruction. This should happen right before a call to RAUW.
void MergeFunctions::removeUsers(Value *V) {
- std::vector<Value *> Worklist;
- Worklist.push_back(V);
- SmallPtrSet<Value*, 8> Visited;
- Visited.insert(V);
- while (!Worklist.empty()) {
- Value *V = Worklist.back();
- Worklist.pop_back();
-
- for (User *U : V->users()) {
- if (Instruction *I = dyn_cast<Instruction>(U)) {
- remove(I->getFunction());
- } else if (isa<GlobalValue>(U)) {
- // do nothing
- } else if (Constant *C = dyn_cast<Constant>(U)) {
- for (User *UU : C->users()) {
- if (!Visited.insert(UU).second)
- Worklist.push_back(UU);
- }
- }
- }
- }
+ for (User *U : V->users())
+ if (auto *I = dyn_cast<Instruction>(U))
+ remove(I->getFunction());
}