aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Transforms/IPO/MergeFunctions.cpp
diff options
context:
space:
mode:
authorwhitequark <whitequark@whitequark.org>2018-11-08 03:58:01 +0000
committerwhitequark <whitequark@whitequark.org>2018-11-08 03:58:01 +0000
commit73cb9784957802156c0bae15fb5709da3e9bf3d3 (patch)
tree4adde10fddff10b9fa56414cf8fcccc3cbb01248 /llvm/lib/Transforms/IPO/MergeFunctions.cpp
parent3580ac6125dd6bc59b5e60134cf586687af01ec7 (diff)
downloadllvm-73cb9784957802156c0bae15fb5709da3e9bf3d3.zip
llvm-73cb9784957802156c0bae15fb5709da3e9bf3d3.tar.gz
llvm-73cb9784957802156c0bae15fb5709da3e9bf3d3.tar.bz2
[MergeFuncs] Improve ordering of equal functions
Summary: MergeFunctions currently tries to process strong functions before weak functions, because weak functions can simply call strong functions, while a strong/weak function cannot call a weak function (a backing strong function is needed). This patch additionally tries to process external functions before local functions, because we definitely have to keep the external function, but may be able to drop the local one (and definitely can if it is also unnamed_addr). Unfortunately, this exposes an existing bug in the implementation: The FnTree and FNodesInTree structures can currently go out of sync in the case where two weak functions are merged, because the function in FnTree/FNodesInTree is RAUWed. This leaves it behind in FnTree (this is intended, as it is the strong backing function which should be used for further merges), while it is replaced in FNodesInTree (this is not intended). This is fixed by switching FNodesInTree from using a ValueMap to using a DenseMap of AssertingVH. This exposes another minor issue: Currently FNodesInTree is not cleared after MergeFunctions finishes running. Currently, this is potentially dangerous (e.g. if something else wants to RAUW a function with a non-function), but at the very least it is unnecessary/inefficient. After the change to use AssertingVH it becomes more problematic, because there are certainly passes that remove functions. This issue is fixed by clearing FNodesInTree at the end of the pass. Reviewers: jfb, whitequark Reviewed By: whitequark Subscribers: rkruppe, llvm-commits Differential Revision: https://reviews.llvm.org/D53271 llvm-svn: 346386
Diffstat (limited to 'llvm/lib/Transforms/IPO/MergeFunctions.cpp')
-rw-r--r--llvm/lib/Transforms/IPO/MergeFunctions.cpp30
1 files changed, 21 insertions, 9 deletions
diff --git a/llvm/lib/Transforms/IPO/MergeFunctions.cpp b/llvm/lib/Transforms/IPO/MergeFunctions.cpp
index 49b3eac..4c51cd1 100644
--- a/llvm/lib/Transforms/IPO/MergeFunctions.cpp
+++ b/llvm/lib/Transforms/IPO/MergeFunctions.cpp
@@ -284,7 +284,7 @@ private:
// modified, i.e. in insert(), remove(), and replaceFunctionInTree(), to avoid
// dangling iterators into FnTree. The invariant that preserves this is that
// there is exactly one mapping F -> FN for each FunctionNode FN in FnTree.
- ValueMap<Function*, FnTreeType::iterator> FNodesInTree;
+ DenseMap<AssertingVH<Function>, FnTreeType::iterator> FNodesInTree;
};
} // end anonymous namespace
@@ -425,6 +425,7 @@ bool MergeFunctions::runOnModule(Module &M) {
} while (!Deferred.empty());
FnTree.clear();
+ FNodesInTree.clear();
GlobalNumbers.clear();
return Changed;
@@ -817,6 +818,24 @@ void MergeFunctions::replaceFunctionInTree(const FunctionNode &FN,
FN.replaceBy(G);
}
+// Ordering for functions that are equal under FunctionComparator
+static bool isFuncOrderCorrect(const Function *F, const Function *G) {
+ if (F->isInterposable() != G->isInterposable()) {
+ // Strong before weak, because the weak function may call the strong
+ // one, but not the other way around.
+ return !F->isInterposable();
+ }
+ if (F->hasLocalLinkage() != G->hasLocalLinkage()) {
+ // External before local, because we definitely have to keep the external
+ // function, but may be able to drop the local one.
+ return !F->hasLocalLinkage();
+ }
+ // Impose a total order (by name) on the replacement of functions. This is
+ // important when operating on more than one module independently to prevent
+ // cycles of thunks calling each other when the modules are linked together.
+ return F->getName() <= G->getName();
+}
+
// Insert a ComparableFunction into the FnTree, or merge it away if equal to one
// that was already inserted.
bool MergeFunctions::insert(Function *NewFunction) {
@@ -833,14 +852,7 @@ bool MergeFunctions::insert(Function *NewFunction) {
const FunctionNode &OldF = *Result.first;
- // Impose a total order (by name) on the replacement of functions. This is
- // important when operating on more than one module independently to prevent
- // cycles of thunks calling each other when the modules are linked together.
- //
- // First of all, we process strong functions before weak functions.
- if ((OldF.getFunc()->isInterposable() && !NewFunction->isInterposable()) ||
- (OldF.getFunc()->isInterposable() == NewFunction->isInterposable() &&
- OldF.getFunc()->getName() > NewFunction->getName())) {
+ if (!isFuncOrderCorrect(OldF.getFunc(), NewFunction)) {
// Swap the two functions.
Function *F = OldF.getFunc();
replaceFunctionInTree(*Result.first, NewFunction);