@@ -136,6 +136,7 @@ using namespace llvm;
136
136
137
137
STATISTIC (NumFunctionsMerged, " Number of functions merged" );
138
138
STATISTIC (NumThunksWritten, " Number of thunks generated" );
139
+ STATISTIC (NumAliasesWritten, " Number of aliases generated" );
139
140
STATISTIC (NumDoubleWeak, " Number of new functions created" );
140
141
141
142
static cl::opt<unsigned > NumFunctionsForSanityCheck (
@@ -165,6 +166,11 @@ static cl::opt<bool>
165
166
cl::desc(" Preserve debug info in thunk when mergefunc "
166
167
" transformations are made." ));
167
168
169
+ static cl::opt<bool >
170
+ MergeFunctionsAliases (" mergefunc-use-aliases" , cl::Hidden,
171
+ cl::init (false ),
172
+ cl::desc(" Allow mergefunc to create aliases" ));
173
+
168
174
namespace {
169
175
170
176
class FunctionNode {
@@ -272,6 +278,13 @@ class MergeFunctions : public ModulePass {
272
278
// / delete G.
273
279
void writeThunk (Function *F, Function *G);
274
280
281
+ // Replace G with an alias to F (deleting function G)
282
+ void writeAlias (Function *F, Function *G);
283
+
284
+ // Replace G with an alias to F if possible, or a thunk to F if
285
+ // profitable. Returns false if neither is the case.
286
+ bool writeThunkOrAlias (Function *F, Function *G);
287
+
275
288
// / Replace function F with function G in the function tree.
276
289
void replaceFunctionInTree (const FunctionNode &FN, Function *G);
277
290
@@ -735,27 +748,76 @@ void MergeFunctions::writeThunk(Function *F, Function *G) {
735
748
++NumThunksWritten;
736
749
}
737
750
751
+ // Whether this function may be replaced by an alias
752
+ static bool canCreateAliasFor (Function *F) {
753
+ if (!MergeFunctionsAliases || !F->hasGlobalUnnamedAddr ())
754
+ return false ;
755
+
756
+ // We should only see linkages supported by aliases here
757
+ assert (F->hasLocalLinkage () || F->hasExternalLinkage ()
758
+ || F->hasWeakLinkage () || F->hasLinkOnceLinkage ());
759
+ return true ;
760
+ }
761
+
762
+ // Replace G with an alias to F (deleting function G)
763
+ void MergeFunctions::writeAlias (Function *F, Function *G) {
764
+ Constant *BitcastF = ConstantExpr::getBitCast (F, G->getType ());
765
+ PointerType *PtrType = G->getType ();
766
+ auto *GA = GlobalAlias::create (
767
+ PtrType->getElementType (), PtrType->getAddressSpace (),
768
+ G->getLinkage (), " " , BitcastF, G->getParent ());
769
+
770
+ F->setAlignment (std::max (F->getAlignment (), G->getAlignment ()));
771
+ GA->takeName (G);
772
+ GA->setVisibility (G->getVisibility ());
773
+ GA->setUnnamedAddr (GlobalValue::UnnamedAddr::Global);
774
+
775
+ removeUsers (G);
776
+ G->replaceAllUsesWith (GA);
777
+ G->eraseFromParent ();
778
+
779
+ LLVM_DEBUG (dbgs () << " writeAlias: " << GA->getName () << ' \n ' );
780
+ ++NumAliasesWritten;
781
+ }
782
+
783
+ // Replace G with an alias to F if possible, or a thunk to F if
784
+ // profitable. Returns false if neither is the case.
785
+ bool MergeFunctions::writeThunkOrAlias (Function *F, Function *G) {
786
+ if (canCreateAliasFor (G)) {
787
+ writeAlias (F, G);
788
+ return true ;
789
+ }
790
+ if (isThunkProfitable (F)) {
791
+ writeThunk (F, G);
792
+ return true ;
793
+ }
794
+ return false ;
795
+ }
796
+
738
797
// Merge two equivalent functions. Upon completion, Function G is deleted.
739
798
void MergeFunctions::mergeTwoFunctions (Function *F, Function *G) {
740
799
if (F->isInterposable ()) {
741
800
assert (G->isInterposable ());
742
801
743
- if (!isThunkProfitable (F)) {
802
+ // Both writeThunkOrAlias() calls below must succeed, either because we can
803
+ // create aliases for G and NewF, or because a thunk for F is profitable.
804
+ // F here has the same signature as NewF below, so that's what we check.
805
+ if (!isThunkProfitable (F) && (!canCreateAliasFor (F) || !canCreateAliasFor (G))) {
744
806
return ;
745
807
}
746
808
747
809
// Make them both thunks to the same internal function.
748
- Function *H = Function::Create (F->getFunctionType (), F->getLinkage (), " " ,
749
- F->getParent ());
750
- H ->copyAttributesFrom (F);
751
- H ->takeName (F);
810
+ Function *NewF = Function::Create (F->getFunctionType (), F->getLinkage (), " " ,
811
+ F->getParent ());
812
+ NewF ->copyAttributesFrom (F);
813
+ NewF ->takeName (F);
752
814
removeUsers (F);
753
- F->replaceAllUsesWith (H );
815
+ F->replaceAllUsesWith (NewF );
754
816
755
- unsigned MaxAlignment = std::max (G->getAlignment (), H ->getAlignment ());
817
+ unsigned MaxAlignment = std::max (G->getAlignment (), NewF ->getAlignment ());
756
818
757
- writeThunk (F, G);
758
- writeThunk (F, H );
819
+ writeThunkOrAlias (F, G);
820
+ writeThunkOrAlias (F, NewF );
759
821
760
822
F->setAlignment (MaxAlignment);
761
823
F->setLinkage (GlobalValue::PrivateLinkage);
@@ -789,12 +851,9 @@ void MergeFunctions::mergeTwoFunctions(Function *F, Function *G) {
789
851
return ;
790
852
}
791
853
792
- if (! isThunkProfitable (F )) {
793
- return ;
854
+ if (writeThunkOrAlias (F, G )) {
855
+ ++NumFunctionsMerged ;
794
856
}
795
-
796
- writeThunk (F, G);
797
- ++NumFunctionsMerged;
798
857
}
799
858
}
800
859
0 commit comments