Skip to content

Commit f52a6f3

Browse files
committed
Refactor and add tests
1 parent 9cd11a6 commit f52a6f3

File tree

2 files changed

+92
-26
lines changed

2 files changed

+92
-26
lines changed

lib/SILOptimizer/IPO/GlobalOpt.cpp

Lines changed: 64 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ class SILGlobalOpt {
5959

6060
typedef SmallVector<ApplyInst *, 4> GlobalInitCalls;
6161
typedef SmallVector<LoadInst *, 4> GlobalLoads;
62+
typedef SmallVector<BeginAccessInst *, 4> GlobalAccess;
6263

6364
/// A map from each visited global initializer call to a list of call sites.
6465
llvm::MapVector<SILFunction *, GlobalInitCalls> GlobalInitCallMap;
@@ -70,10 +71,15 @@ class SILGlobalOpt {
7071
/// A map from each visited global let variable to its set of loads.
7172
llvm::MapVector<SILGlobalVariable *, GlobalLoads> GlobalLoadMap;
7273

74+
/// A map from each visited global to its set of begin_access instructions.
75+
llvm::MapVector<SILGlobalVariable *, GlobalAccess> GlobalAccessMap;
76+
7377
/// A map from each visited global let variable to the store instructions
7478
/// which initialize it.
7579
llvm::MapVector<SILGlobalVariable *, StoreInst *> GlobalVarStore;
76-
80+
81+
/// A map for each visited global variable to the alloc instruction that
82+
/// allocated space for it.
7783
llvm::MapVector<SILGlobalVariable *, AllocGlobalInst *> AllocGlobalStore;
7884

7985
/// A set of visited global variables that for some reason we have decided is
@@ -119,7 +125,9 @@ class SILGlobalOpt {
119125

120126
/// This is the main entrypoint for collecting global accesses.
121127
void collectGlobalAccess(GlobalAddrInst *GAI);
122-
128+
129+
/// Simple function to collect globals and their corresponding alloc
130+
/// instructions.
123131
void collectAllocGlobal(SILGlobalVariable *global,
124132
AllocGlobalInst *allocGlobal);
125133

@@ -144,6 +152,9 @@ class SILGlobalOpt {
144152
/// can be statically initialized.
145153
void optimizeInitializer(SILFunction *AddrF, GlobalInitCalls &Calls);
146154

155+
/// Remove private global variables that are never used.
156+
void tryOptimizeUnusedGlobal(SILGlobalVariable *global, StoreInst *store);
157+
147158
/// Optimize access to the global variable, which is known to have a constant
148159
/// value. Replace all loads from the global address by invocations of a
149160
/// getter that returns the value of this variable.
@@ -775,6 +786,35 @@ void SILGlobalOpt::optimizeInitializer(SILFunction *AddrF,
775786
HasChanged = true;
776787
}
777788

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;
796+
if (GlobalLoadMap.count(global) || GlobalAccessMap.count(global))
797+
return;
798+
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+
}
806+
}
807+
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+
}
816+
}
817+
778818
static bool canBeChangedExternally(SILGlobalVariable *SILG) {
779819
// Don't assume anything about globals which are imported from other modules.
780820
if (isAvailableExternally(SILG->getLinkage()))
@@ -873,6 +913,10 @@ void SILGlobalOpt::collectGlobalAccess(GlobalAddrInst *GAI) {
873913
continue;
874914
}
875915

916+
if (auto *beginAccess = dyn_cast<BeginAccessInst>(Op->getUser())) {
917+
GlobalAccessMap[SILG].push_back(beginAccess);
918+
}
919+
876920
LLVM_DEBUG(llvm::dbgs() << "GlobalOpt: has non-store, non-load use: "
877921
<< SILG->getName() << '\n';
878922
Op->getUser()->dump());
@@ -883,7 +927,8 @@ void SILGlobalOpt::collectGlobalAccess(GlobalAddrInst *GAI) {
883927
}
884928
}
885929

886-
void SILGlobalOpt::collectAllocGlobal(SILGlobalVariable *global, AllocGlobalInst *allocGlobal) {
930+
void SILGlobalOpt::collectAllocGlobal(SILGlobalVariable *global,
931+
AllocGlobalInst *allocGlobal) {
887932
AllocGlobalStore[global] = allocGlobal;
888933
}
889934

@@ -937,11 +982,6 @@ void SILGlobalOpt::optimizeGlobalAccess(SILGlobalVariable *SILG,
937982

938983
bool SILGlobalOpt::run() {
939984
for (auto &F : *Module) {
940-
941-
// Don't optimize functions that are marked with the opt.never attribute.
942-
if (!F.shouldOptimize())
943-
continue;
944-
945985
// TODO: Add support for ownership.
946986
if (F.hasOwnership()) {
947987
continue;
@@ -978,32 +1018,30 @@ bool SILGlobalOpt::run() {
9781018
}
9791019

9801020
for (auto &InitCalls : GlobalInitCallMap) {
1021+
// Don't optimize functions that are marked with the opt.never attribute.
1022+
bool shouldOptimize = true;
1023+
for (auto *apply : InitCalls.second) {
1024+
if (!apply->getFunction()->shouldOptimize()) {
1025+
shouldOptimize = false;
1026+
break;
1027+
}
1028+
}
1029+
if (!shouldOptimize)
1030+
continue;
1031+
9811032
// Optimize the addressors if possible.
9821033
optimizeInitializer(InitCalls.first, InitCalls.second);
9831034
placeInitializers(InitCalls.first, InitCalls.second);
9841035
}
9851036

9861037
for (auto &Init : GlobalVarStore) {
1038+
// Don't optimize functions that are marked with the opt.never attribute.
1039+
if (!Init.second->getFunction()->shouldOptimize())
1040+
continue;
1041+
9871042
// Optimize the access to globals if possible.
9881043
optimizeGlobalAccess(Init.first, Init.second);
989-
990-
if (Init.first->getLinkage() != SILLinkage::Private) continue;
991-
bool canRemove = true;
992-
auto globalAddr = cast<GlobalAddrInst>(Init.second->getDest());
993-
for (auto *use : globalAddr->getUses()) {
994-
if (!isa<StoreInst>(use->getUser())) {
995-
canRemove = false;
996-
break;
997-
}
998-
}
999-
if (canRemove) {
1000-
Init.second->eraseFromParent();
1001-
assert(globalAddr->getUses().begin() == globalAddr->getUses().end());
1002-
globalAddr->eraseFromParent();
1003-
if (AllocGlobalStore.count(Init.first))
1004-
AllocGlobalStore[Init.first]->eraseFromParent();
1005-
Init.first->getModule().eraseGlobalVariable(Init.first);
1006-
}
1044+
tryOptimizeUnusedGlobal(Init.first, Init.second);
10071045
}
10081046

10091047
return HasChanged;
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// RUN: %target-swift-frontend -O -emit-sil %s | %FileCheck %s
2+
3+
// CHECK-NOT: sil_global private [let] {{.*}}unused1{{.*}}
4+
private let unused1 = 0
5+
// CHECK-NOT: sil_global private {{.*}}unused2{{.*}}
6+
private var unused2 = 42
7+
// CHECK: sil_global private [let] @${{.*}}used1{{.*}} : $Int
8+
private let used1 = 0
9+
// CHECK: sil_global private @${{.*}}used2{{.*}} : $Int
10+
private var used2 = 0
11+
12+
// CHECK: sil_global [let] @${{.*}}unused3{{.*}} : $Int
13+
public let unused3 = 0
14+
// CHECK: sil_global @${{.*}}unused4{{.*}} : $Int
15+
public var unused4 = 0
16+
17+
// These should only be optimized with -wmo.
18+
// CHECK: sil_global hidden [let] @${{.*}}unused5{{.*}} : $Int
19+
let unused5 = 0
20+
// CHECK: sil_global hidden @${{.*}}unused6{{.*}} : $Int
21+
var unused6 = 0
22+
23+
// CHECK-LABEL: sil [Onone] @${{.*}}test{{.*}}
24+
@_optimize(none) public func test(x: Int) -> Int {
25+
// CHECK: %{{[0-9]+}} = global_addr @${{.*}}used2{{.*}}
26+
// CHECK: %{{[0-9]+}} = global_addr @${{.*}}used1{{.*}}
27+
return used1 + used2 + x
28+
}

0 commit comments

Comments
 (0)