20
20
#include " swift/SIL/SILCloner.h"
21
21
#include " swift/SIL/SILGlobalVariable.h"
22
22
#include " swift/SIL/SILInstruction.h"
23
+ #include " swift/SIL/SILInstructionWorklist.h"
23
24
#include " swift/SILOptimizer/Analysis/ColdBlockInfo.h"
24
25
#include " swift/SILOptimizer/Analysis/DominanceAnalysis.h"
25
26
#include " swift/SILOptimizer/PassManager/Passes.h"
@@ -59,6 +60,8 @@ class SILGlobalOpt {
59
60
60
61
typedef SmallVector<ApplyInst *, 4 > GlobalInitCalls;
61
62
typedef SmallVector<LoadInst *, 4 > GlobalLoads;
63
+ typedef SmallVector<BeginAccessInst *, 4 > GlobalAccesses;
64
+ typedef SmallVector<GlobalAddrInst *, 4 > GlobalAddrs;
62
65
63
66
// / A map from each visited global initializer call to a list of call sites.
64
67
llvm::MapVector<SILFunction *, GlobalInitCalls> GlobalInitCallMap;
@@ -70,10 +73,20 @@ class SILGlobalOpt {
70
73
// / A map from each visited global let variable to its set of loads.
71
74
llvm::MapVector<SILGlobalVariable *, GlobalLoads> GlobalLoadMap;
72
75
76
+ // / A map from each visited global to its set of begin_access instructions.
77
+ llvm::MapVector<SILGlobalVariable *, GlobalAccesses> GlobalAccessMap;
78
+
79
+ // / A map from each visited global to all of its global address instructions.
80
+ llvm::MapVector<SILGlobalVariable *, GlobalAddrs> GlobalAddrMap;
81
+
73
82
// / A map from each visited global let variable to the store instructions
74
83
// / which initialize it.
75
84
llvm::MapVector<SILGlobalVariable *, StoreInst *> GlobalVarStore;
76
85
86
+ // / A map for each visited global variable to the alloc instruction that
87
+ // / allocated space for it.
88
+ llvm::MapVector<SILGlobalVariable *, AllocGlobalInst *> AllocGlobalStore;
89
+
77
90
// / A set of visited global variables that for some reason we have decided is
78
91
// / not able to be optimized safely or for which we do not know how to
79
92
// / optimize safely.
@@ -97,13 +110,25 @@ class SILGlobalOpt {
97
110
// / A map from a globalinit_func to the number of times "once" has called the
98
111
// / function.
99
112
llvm::DenseMap<SILFunction *, unsigned > InitializerCount;
113
+
114
+ llvm::SmallVector<SILInstruction *, 4 > InstToRemove;
115
+ llvm::SmallVector<SILGlobalVariable *, 4 > GlobalsToRemove;
116
+
100
117
public:
101
118
SILGlobalOpt (SILOptFunctionBuilder &FunctionBuilder, SILModule *M, DominanceAnalysis *DA)
102
119
: FunctionBuilder(FunctionBuilder), Module(M), DA(DA) {}
103
120
104
121
bool run ();
105
122
106
123
protected:
124
+ // / Reset all the maps of global variables.
125
+ void reset ();
126
+
127
+ // / Collect all global variables.
128
+ void collect ();
129
+
130
+ void collectUsesOfInstructionForDeletion (SILInstruction *inst);
131
+
107
132
// / If this is a call to a global initializer, map it.
108
133
void collectGlobalInitCall (ApplyInst *AI);
109
134
@@ -118,6 +143,11 @@ class SILGlobalOpt {
118
143
// / This is the main entrypoint for collecting global accesses.
119
144
void collectGlobalAccess (GlobalAddrInst *GAI);
120
145
146
+ // / Simple function to collect globals and their corresponding alloc
147
+ // / instructions.
148
+ void collectAllocGlobal (SILGlobalVariable *global,
149
+ AllocGlobalInst *allocGlobal);
150
+
121
151
// / Returns true if we think that \p CurBB is inside a loop.
122
152
bool isInLoop (SILBasicBlock *CurBB);
123
153
@@ -139,6 +169,17 @@ class SILGlobalOpt {
139
169
// / can be statically initialized.
140
170
void optimizeInitializer (SILFunction *AddrF, GlobalInitCalls &Calls);
141
171
172
+ // / If possible, remove global address instructions associated with the given
173
+ // / global.
174
+ bool tryRemoveGlobalAddr (SILGlobalVariable *global);
175
+
176
+ // / If possible, remove global alloc instructions associated with the given
177
+ // / global.
178
+ bool tryRemoveGlobalAlloc (SILGlobalVariable *global, AllocGlobalInst *alloc);
179
+
180
+ // / If a global has no uses, remove it.
181
+ bool tryRemoveUnusedGlobal (SILGlobalVariable *global);
182
+
142
183
// / Optimize access to the global variable, which is known to have a constant
143
184
// / value. Replace all loads from the global address by invocations of a
144
185
// / getter that returns the value of this variable.
@@ -809,6 +850,110 @@ static bool canBeChangedExternally(SILGlobalVariable *SILG) {
809
850
return true ;
810
851
}
811
852
853
+ static bool canBeUsedOrChangedExternally (SILGlobalVariable *global) {
854
+ if (global->isLet ())
855
+ return isPossiblyUsedExternally (global->getLinkage (),
856
+ global->getModule ().isWholeModule ());
857
+ return canBeChangedExternally (global);
858
+ }
859
+
860
+ static bool isSafeToRemove (SILGlobalVariable *global) {
861
+ return global->getDecl () && !canBeUsedOrChangedExternally (global);
862
+ }
863
+
864
+ bool SILGlobalOpt::tryRemoveGlobalAlloc (SILGlobalVariable *global,
865
+ AllocGlobalInst *alloc) {
866
+ if (!isSafeToRemove (global))
867
+ return false ;
868
+
869
+ // Make sure the global's address is never taken and we shouldn't skip this
870
+ // global.
871
+ if (GlobalVarSkipProcessing.count (global) ||
872
+ (GlobalAddrMap[global].size () &&
873
+ std::any_of (GlobalAddrMap[global].begin (), GlobalAddrMap[global].end (),
874
+ [=](GlobalAddrInst *addr) {
875
+ return std::find (InstToRemove.begin (), InstToRemove.end (),
876
+ addr) == InstToRemove.end ();
877
+ })))
878
+ return false ;
879
+
880
+ InstToRemove.push_back (alloc);
881
+ return true ;
882
+ }
883
+
884
+ // / If there are no loads or accesses of a given global, then remove its
885
+ // / associated global addr and all asssociated instructions.
886
+ bool SILGlobalOpt::tryRemoveGlobalAddr (SILGlobalVariable *global) {
887
+ if (!isSafeToRemove (global))
888
+ return false ;
889
+
890
+ if (GlobalVarSkipProcessing.count (global) || GlobalLoadMap[global].size () ||
891
+ GlobalAccessMap[global].size ())
892
+ return false ;
893
+
894
+ // Check if the address is used in anything but a store. If any global_addr
895
+ // instruction associated with a global is used in anything but a store, we
896
+ // can't remove ANY global_addr instruction associated with that global.
897
+ for (auto *addr : GlobalAddrMap[global]) {
898
+ for (auto *use : addr->getUses ()) {
899
+ if (!isa<StoreInst>(use->getUser ()))
900
+ return false ;
901
+ }
902
+ }
903
+
904
+ // Now that it's safe, remove all global addresses associated with this global
905
+ for (auto *addr : GlobalAddrMap[global]) {
906
+ InstToRemove.push_back (addr);
907
+ }
908
+
909
+ return true ;
910
+ }
911
+
912
+ bool SILGlobalOpt::tryRemoveUnusedGlobal (SILGlobalVariable *global) {
913
+ if (!isSafeToRemove (global))
914
+ return false ;
915
+
916
+ if (GlobalVarSkipProcessing.count (global))
917
+ return false ;
918
+
919
+ // If this global is used, check if the user is going to be removed.
920
+ // Make sure none of the removed instructions are the same as this global's
921
+ // alloc instruction
922
+ if (AllocGlobalStore.count (global) &&
923
+ std::none_of (InstToRemove.begin (), InstToRemove.end (),
924
+ [=](SILInstruction *inst) {
925
+ return AllocGlobalStore[global] == inst;
926
+ }))
927
+ return false ;
928
+
929
+ if (GlobalVarStore.count (global) &&
930
+ std::none_of (
931
+ InstToRemove.begin (), InstToRemove.end (),
932
+ [=](SILInstruction *inst) { return GlobalVarStore[global] == inst; }))
933
+ return false ;
934
+
935
+ // Check if any of the global_addr instructions associated with this global
936
+ // aren't going to be removed. In that case, we need to keep the global.
937
+ if (GlobalAddrMap[global].size () &&
938
+ std::any_of (GlobalAddrMap[global].begin (), GlobalAddrMap[global].end (),
939
+ [=](GlobalAddrInst *addr) {
940
+ return std::find (InstToRemove.begin (), InstToRemove.end (),
941
+ addr) == InstToRemove.end ();
942
+ }))
943
+ return false ;
944
+
945
+ if (GlobalAccessMap[global].size () &&
946
+ std::any_of (GlobalAccessMap[global].begin (),
947
+ GlobalAccessMap[global].end (), [=](BeginAccessInst *access) {
948
+ return std::find (InstToRemove.begin (), InstToRemove.end (),
949
+ access) == InstToRemove.end ();
950
+ }))
951
+ return false ;
952
+
953
+ GlobalsToRemove.push_back (global);
954
+ return true ;
955
+ }
956
+
812
957
// / Check if instruction I is a load from instruction V or
813
958
// / or a struct_element_addr from instruction V.
814
959
// / returns instruction I if this condition holds, or nullptr otherwise.
@@ -837,6 +982,11 @@ void SILGlobalOpt::collectGlobalAccess(GlobalAddrInst *GAI) {
837
982
if (!SILG)
838
983
return ;
839
984
985
+ if (!SILG->getDecl ())
986
+ return ;
987
+
988
+ GlobalAddrMap[SILG].push_back (GAI);
989
+
840
990
if (!SILG->isLet ()) {
841
991
// We cannot determine the value for global variables which could be
842
992
// changed externally at run-time.
@@ -861,9 +1011,6 @@ void SILGlobalOpt::collectGlobalAccess(GlobalAddrInst *GAI) {
861
1011
if (GlobalVar == SILG)
862
1012
return ;
863
1013
864
- if (!SILG->getDecl ())
865
- return ;
866
-
867
1014
for (auto *Op : getNonDebugUses (GAI)) {
868
1015
if (auto *SI = dyn_cast<StoreInst>(Op->getUser ())) {
869
1016
if (SI->getDest () == GAI)
@@ -876,6 +1023,10 @@ void SILGlobalOpt::collectGlobalAccess(GlobalAddrInst *GAI) {
876
1023
continue ;
877
1024
}
878
1025
1026
+ if (auto *beginAccess = dyn_cast<BeginAccessInst>(Op->getUser ())) {
1027
+ GlobalAccessMap[SILG].push_back (beginAccess);
1028
+ }
1029
+
879
1030
LLVM_DEBUG (llvm::dbgs () << " GlobalOpt: has non-store, non-load use: "
880
1031
<< SILG->getName () << ' \n ' ;
881
1032
Op->getUser ()->dump ());
@@ -886,6 +1037,11 @@ void SILGlobalOpt::collectGlobalAccess(GlobalAddrInst *GAI) {
886
1037
}
887
1038
}
888
1039
1040
+ void SILGlobalOpt::collectAllocGlobal (SILGlobalVariable *global,
1041
+ AllocGlobalInst *allocGlobal) {
1042
+ AllocGlobalStore[global] = allocGlobal;
1043
+ }
1044
+
889
1045
// Optimize access to the global variable, which is known to have a constant
890
1046
// value. Replace all loads from the global address by invocations of a getter
891
1047
// that returns the value of this variable.
@@ -906,7 +1062,7 @@ void SILGlobalOpt::optimizeGlobalAccess(SILGlobalVariable *SILG,
906
1062
return ;
907
1063
}
908
1064
909
- if (! GlobalLoadMap. count (SILG )) {
1065
+ if (GlobalLoadMap[SILG]. empty ( )) {
910
1066
LLVM_DEBUG (llvm::dbgs () << " GlobalOpt: not in load map: "
911
1067
<< SILG->getName () << ' \n ' );
912
1068
return ;
@@ -938,13 +1094,17 @@ void SILGlobalOpt::optimizeGlobalAccess(SILGlobalVariable *SILG,
938
1094
939
1095
}
940
1096
941
- bool SILGlobalOpt::run () {
942
- for (auto &F : *Module) {
943
-
944
- // Don't optimize functions that are marked with the opt.never attribute.
945
- if (!F.shouldOptimize ())
946
- continue ;
1097
+ void SILGlobalOpt::reset () {
1098
+ AllocGlobalStore.clear ();
1099
+ GlobalVarStore.clear ();
1100
+ GlobalAddrMap.clear ();
1101
+ GlobalAccessMap.clear ();
1102
+ GlobalLoadMap.clear ();
1103
+ GlobalInitCallMap.clear ();
1104
+ }
947
1105
1106
+ void SILGlobalOpt::collect () {
1107
+ for (auto &F : *Module) {
948
1108
// TODO: Add support for ownership.
949
1109
if (F.hasOwnership ()) {
950
1110
continue ;
@@ -967,27 +1127,92 @@ bool SILGlobalOpt::run() {
967
1127
continue ;
968
1128
}
969
1129
970
- auto *GAI = dyn_cast<GlobalAddrInst>(&I);
971
- if (! GAI) {
1130
+ if ( auto *GAI = dyn_cast<GlobalAddrInst>(&I)) {
1131
+ collectGlobalAccess ( GAI);
972
1132
continue ;
973
1133
}
974
1134
975
- collectGlobalAccess (GAI);
1135
+ if (auto *allocGlobal = dyn_cast<AllocGlobalInst>(&I)) {
1136
+ collectAllocGlobal (allocGlobal->getReferencedGlobal (), allocGlobal);
1137
+ continue ;
1138
+ }
976
1139
}
977
1140
}
978
1141
}
1142
+ }
1143
+
1144
+ bool SILGlobalOpt::run () {
1145
+ // Collect all the global variables and associated instructions.
1146
+ collect ();
979
1147
1148
+ // Optimize based on what we just collected.
980
1149
for (auto &InitCalls : GlobalInitCallMap) {
1150
+ // Don't optimize functions that are marked with the opt.never attribute.
1151
+ if (!InitCalls.first ->shouldOptimize ())
1152
+ continue ;
1153
+
981
1154
// Optimize the addressors if possible.
982
1155
optimizeInitializer (InitCalls.first , InitCalls.second );
983
1156
placeInitializers (InitCalls.first , InitCalls.second );
984
1157
}
985
1158
986
1159
for (auto &Init : GlobalVarStore) {
1160
+ // Don't optimize functions that are marked with the opt.never attribute.
1161
+ if (!Init.second ->getFunction ()->shouldOptimize ())
1162
+ continue ;
1163
+
987
1164
// Optimize the access to globals if possible.
988
1165
optimizeGlobalAccess (Init.first , Init.second );
989
1166
}
990
1167
1168
+ SmallVector<SILGlobalVariable *, 8 > addrGlobals;
1169
+ for (auto &addrPair : GlobalAddrMap) {
1170
+ // Don't optimize functions that are marked with the opt.never attribute.
1171
+ bool shouldOptimize = true ;
1172
+ for (auto *addr : addrPair.second ) {
1173
+ if (!addr->getFunction ()->shouldOptimize ()) {
1174
+ shouldOptimize = false ;
1175
+ break ;
1176
+ }
1177
+ }
1178
+ if (!shouldOptimize)
1179
+ continue ;
1180
+
1181
+ addrGlobals.push_back (addrPair.first );
1182
+ }
1183
+
1184
+ for (auto *global : addrGlobals) {
1185
+ HasChanged |= tryRemoveGlobalAddr (global);
1186
+ }
1187
+
1188
+ SmallVector<std::pair<SILGlobalVariable *, AllocGlobalInst *>, 12 >
1189
+ globalAllocPairs;
1190
+ for (auto &alloc : AllocGlobalStore) {
1191
+ if (!alloc.second ->getFunction ()->shouldOptimize ())
1192
+ continue ;
1193
+ globalAllocPairs.push_back (std::make_pair (alloc.first , alloc.second ));
1194
+ }
1195
+
1196
+ for (auto &allocPair : globalAllocPairs) {
1197
+ HasChanged |= tryRemoveGlobalAlloc (allocPair.first , allocPair.second );
1198
+ }
1199
+
1200
+ // Erase the instructions that we have marked for deletion.
1201
+ for (auto *inst : InstToRemove) {
1202
+ eraseUsesOfInstruction (inst);
1203
+ inst->eraseFromParent ();
1204
+ }
1205
+
1206
+ for (auto &global : Module->getSILGlobals ()) {
1207
+ HasChanged |= tryRemoveUnusedGlobal (&global);
1208
+ }
1209
+
1210
+ for (auto *global : GlobalsToRemove) {
1211
+ Module->eraseGlobalVariable (global);
1212
+ }
1213
+
1214
+ // Reset in case we re-run this function (when HasChanged is true).
1215
+ reset ();
991
1216
return HasChanged;
992
1217
}
993
1218
0 commit comments