@@ -60,6 +60,7 @@ class SILGlobalOpt {
60
60
typedef SmallVector<ApplyInst *, 4 > GlobalInitCalls;
61
61
typedef SmallVector<LoadInst *, 4 > GlobalLoads;
62
62
typedef SmallVector<BeginAccessInst *, 4 > GlobalAccess;
63
+ typedef SmallVector<GlobalAddrInst *, 4 > GlobalAddrs;
63
64
64
65
// / A map from each visited global initializer call to a list of call sites.
65
66
llvm::MapVector<SILFunction *, GlobalInitCalls> GlobalInitCallMap;
@@ -74,6 +75,9 @@ class SILGlobalOpt {
74
75
// / A map from each visited global to its set of begin_access instructions.
75
76
llvm::MapVector<SILGlobalVariable *, GlobalAccess> GlobalAccessMap;
76
77
78
+ // / A map from each visited global to all of its global address instructions.
79
+ llvm::MapVector<SILGlobalVariable *, GlobalAddrs> GlobalAddrMap;
80
+
77
81
// / A map from each visited global let variable to the store instructions
78
82
// / which initialize it.
79
83
llvm::MapVector<SILGlobalVariable *, StoreInst *> GlobalVarStore;
@@ -152,8 +156,16 @@ class SILGlobalOpt {
152
156
// / can be statically initialized.
153
157
void optimizeInitializer (SILFunction *AddrF, GlobalInitCalls &Calls);
154
158
155
- // / Remove private global variables that are never used.
156
- void tryOptimizeUnusedGlobal (SILGlobalVariable *global, StoreInst *store);
159
+ // / If possible, remove global address instructions associated with the given
160
+ // / global.
161
+ bool tryRemoveGlobalAddr (SILGlobalVariable *global);
162
+
163
+ // / If possible, remove global alloc instructions associated with the given
164
+ // / global.
165
+ bool tryRemoveGlobalAlloc (SILGlobalVariable *global, AllocGlobalInst *alloc);
166
+
167
+ // / If a global has no uses, remove it.
168
+ bool tryRemoveUnusedGlobal (SILGlobalVariable *global);
157
169
158
170
// / Optimize access to the global variable, which is known to have a constant
159
171
// / value. Replace all loads from the global address by invocations of a
@@ -786,33 +798,41 @@ void SILGlobalOpt::optimizeInitializer(SILFunction *AddrF,
786
798
HasChanged = true ;
787
799
}
788
800
789
- // / Look through all the uses of the global variable. If the only use is a
790
- // / store, and the global is private, then we can remove the global, the store,
791
- // / and the alloc. Otherwise, return.
792
- void SILGlobalOpt::tryOptimizeUnusedGlobal (SILGlobalVariable *global,
793
- StoreInst *store) {
794
- if (global->getLinkage () != SILLinkage::Private)
795
- return ;
801
+ // / If there are no loads or accesses of a given global, then remove its
802
+ // / associated global addr and all asssociated instructions.
803
+ bool SILGlobalOpt::tryRemoveGlobalAddr (SILGlobalVariable *global) {
804
+ if (isPossiblyUsedExternally (global->getLinkage (), Module->isWholeModule ()))
805
+ return false ;
796
806
if (GlobalLoadMap.count (global) || GlobalAccessMap.count (global))
797
- return ;
807
+ return false ;
798
808
799
- auto globalAddr = cast<GlobalAddrInst>(store->getDest ());
800
- bool canRemove = true ;
801
- for (auto *use : globalAddr->getUses ()) {
802
- if (!isa<StoreInst>(use->getUser ())) {
803
- canRemove = false ;
804
- break ;
805
- }
809
+ for (auto *addr : GlobalAddrMap[global]) {
810
+ eraseUsesOfInstruction (addr, [](SILInstruction *) {});
811
+ addr->eraseFromParent ();
806
812
}
807
813
808
- if (canRemove) {
809
- store->eraseFromParent ();
810
- assert (globalAddr->getUses ().begin () == globalAddr->getUses ().end ());
811
- globalAddr->eraseFromParent ();
812
- if (AllocGlobalStore.count (global))
813
- AllocGlobalStore[global]->eraseFromParent ();
814
- global->getModule ().eraseGlobalVariable (global);
815
- }
814
+ GlobalAddrMap.erase (global);
815
+ return true ;
816
+ }
817
+
818
+ bool SILGlobalOpt::tryRemoveGlobalAlloc (SILGlobalVariable *global,
819
+ AllocGlobalInst *alloc) {
820
+ if (GlobalAddrMap.count (global))
821
+ return false ;
822
+
823
+ alloc->eraseFromParent ();
824
+ AllocGlobalStore.erase (global);
825
+ return true ;
826
+ }
827
+
828
+ bool SILGlobalOpt::tryRemoveUnusedGlobal (SILGlobalVariable *global) {
829
+ if (GlobalAddrMap.count (global) || GlobalAccessMap.count (global) ||
830
+ GlobalLoadMap.count (global) || AllocGlobalStore.count (global) ||
831
+ GlobalVarStore.count (global))
832
+ return false ;
833
+
834
+ global->getModule ().eraseGlobalVariable (global);
835
+ return true ;
816
836
}
817
837
818
838
static bool canBeChangedExternally (SILGlobalVariable *SILG) {
@@ -874,6 +894,8 @@ void SILGlobalOpt::collectGlobalAccess(GlobalAddrInst *GAI) {
874
894
if (!SILG)
875
895
return ;
876
896
897
+ GlobalAddrMap[SILG].push_back (GAI);
898
+
877
899
if (!SILG->isLet ()) {
878
900
// We cannot determine the value for global variables which could be
879
901
// changed externally at run-time.
@@ -1041,7 +1063,33 @@ bool SILGlobalOpt::run() {
1041
1063
1042
1064
// Optimize the access to globals if possible.
1043
1065
optimizeGlobalAccess (Init.first , Init.second );
1044
- tryOptimizeUnusedGlobal (Init.first , Init.second );
1066
+ }
1067
+
1068
+ for (auto &addrPair : GlobalAddrMap) {
1069
+ // Don't optimize functions that are marked with the opt.never attribute.
1070
+ bool shouldOptimize = true ;
1071
+ for (auto *addr : addrPair.second ) {
1072
+ if (!addr->getFunction ()->shouldOptimize ()) {
1073
+ shouldOptimize = false ;
1074
+ break ;
1075
+ }
1076
+ }
1077
+ if (!shouldOptimize)
1078
+ continue ;
1079
+
1080
+ HasChanged |= tryRemoveGlobalAddr (addrPair.first );
1081
+ }
1082
+
1083
+ for (auto &alloc : AllocGlobalStore) {
1084
+ if (!alloc.second ->getFunction ()->shouldOptimize ())
1085
+ continue ;
1086
+ HasChanged |= tryRemoveGlobalAlloc (alloc.first , alloc.second );
1087
+ }
1088
+
1089
+ for (auto &global : Module->getSILGlobals ()) {
1090
+ // TODO: For some reaons, if we keep iterating through `getSILGlobals`
1091
+ // after `tryRemoveUnusedGlobal` is called, we gen an error.
1092
+ HasChanged |= tryRemoveUnusedGlobal (&global);
1045
1093
}
1046
1094
1047
1095
return HasChanged;
0 commit comments