diff options
author | whitequark <whitequark@whitequark.org> | 2018-11-08 03:58:01 +0000 |
---|---|---|
committer | whitequark <whitequark@whitequark.org> | 2018-11-08 03:58:01 +0000 |
commit | 73cb9784957802156c0bae15fb5709da3e9bf3d3 (patch) | |
tree | 4adde10fddff10b9fa56414cf8fcccc3cbb01248 /llvm/lib/Transforms/IPO/MergeFunctions.cpp | |
parent | 3580ac6125dd6bc59b5e60134cf586687af01ec7 (diff) | |
download | llvm-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.cpp | 30 |
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); |