@@ -39,23 +39,9 @@ using namespace swift;
39
39
// Utility
40
40
// ===----------------------------------------------------------------------===//
41
41
42
- // / Attempts to perform several small optimizations to setup both the address
43
- // / and object checkers. Returns true if we made a change to the IR.
44
- static bool tryConvertSimpleMoveFromAllocStackTemporary (
45
- MarkUnresolvedMoveAddrInst *markMoveAddr, AliasAnalysis *aa) {
46
- LLVM_DEBUG (llvm::dbgs () << " Trying to fix up: " << *markMoveAddr);
47
-
48
- // We need a non-lexical alloc_stack as our source.
49
- auto *asi = dyn_cast<AllocStackInst>(markMoveAddr->getSrc ());
50
- if (!asi || asi->isLexical ()) {
51
- LLVM_DEBUG (llvm::dbgs ()
52
- << " Source isnt an alloc_stack or is lexical... Bailing!\n " );
53
- return false ;
54
- }
55
-
56
- DestroyAddrInst *dai = nullptr ;
57
- CopyAddrInst *cai = nullptr ;
58
- StoreInst *si = nullptr ;
42
+ static bool findInitAndDestroyForAllocation (
43
+ AllocStackInst *asi, MarkUnresolvedMoveAddrInst *markMoveAddr,
44
+ CopyAddrInst *&cai, DestroyAddrInst *&dai, StoreInst *&si) {
59
45
for (auto *use : asi->getUses ()) {
60
46
auto *user = use->getUser ();
61
47
LLVM_DEBUG (llvm::dbgs () << " Visiting User: " << *user);
@@ -113,6 +99,86 @@ static bool tryConvertSimpleMoveFromAllocStackTemporary(
113
99
return false ;
114
100
}
115
101
102
+ return true ;
103
+ }
104
+
105
+ static bool
106
+ tryHandlingLoadableVarMovePattern (MarkUnresolvedMoveAddrInst *markMoveAddr,
107
+ StoreInst *si, AliasAnalysis *aa) {
108
+ auto *li = dyn_cast<LoadInst>(si->getSrc ());
109
+ if (!li || li->getOwnershipQualifier () != LoadOwnershipQualifier::Copy ||
110
+ li->getParent () != si->getParent ())
111
+ return false ;
112
+
113
+ LLVM_DEBUG (llvm::dbgs () << " Found LI: " << *li);
114
+ SILValue operand = stripAccessMarkers (li->getOperand ());
115
+ auto *originalASI = dyn_cast<AllocStackInst>(operand);
116
+ if (!originalASI || !originalASI->isLexical () || !originalASI->isVar ())
117
+ return false ;
118
+
119
+ LLVM_DEBUG (llvm::dbgs () << " Found OriginalASI: " << *originalASI);
120
+ // Make sure that there aren't any side-effect having instructions in
121
+ // between our load/store.
122
+ LLVM_DEBUG (llvm::dbgs () << " Checking for uses in between LI and SI.\n " );
123
+ auto range =
124
+ llvm::make_range (std::next (li->getIterator ()), si->getIterator ());
125
+ if (!llvm::none_of (range, [&](SILInstruction &iter) {
126
+ if (!iter.mayHaveSideEffects ()) {
127
+ LLVM_DEBUG (llvm::dbgs () << " Found no side effect inst: " << iter);
128
+ return false ;
129
+ }
130
+
131
+ if (auto *dvi = dyn_cast<DestroyAddrInst>(&iter)) {
132
+ if (aa->isNoAlias (dvi->getOperand (), originalASI)) {
133
+ // We are going to be extending the lifetime of our
134
+ // underlying value, not shrinking it so we can ignore
135
+ // destroy_addr on other non-aliasing values.
136
+ LLVM_DEBUG (llvm::dbgs () << " Found no alias destroy_addr: " << iter);
137
+ return false ;
138
+ }
139
+ }
140
+
141
+ // Ignore end of scope markers with side-effects.
142
+ if (isEndOfScopeMarker (&iter)) {
143
+ LLVM_DEBUG (llvm::dbgs () << " Found end of scope marker: " << iter);
144
+ return false ;
145
+ }
146
+
147
+ LLVM_DEBUG (llvm::dbgs ()
148
+ << " Found side-effect inst... Bailing!: " << iter);
149
+ return true ;
150
+ })) {
151
+ return false ;
152
+ }
153
+
154
+ // Ok, we know our original lexical alloc_stack is not written to in between
155
+ // the load/store. Move the mark_move_addr onto the lexical alloc_stack.
156
+ LLVM_DEBUG (llvm::dbgs () << " Doing loadable var!\n " );
157
+ markMoveAddr->setSrc (originalASI);
158
+ return true ;
159
+ }
160
+
161
+ // / Attempts to perform several small optimizations to setup both the address
162
+ // / and object checkers. Returns true if we made a change to the IR.
163
+ static bool tryConvertSimpleMoveFromAllocStackTemporary (
164
+ MarkUnresolvedMoveAddrInst *markMoveAddr, AliasAnalysis *aa,
165
+ InstructionDeleter &deleter) {
166
+ LLVM_DEBUG (llvm::dbgs () << " Trying to fix up: " << *markMoveAddr);
167
+
168
+ // We need a non-lexical alloc_stack as our source.
169
+ auto *asi = dyn_cast<AllocStackInst>(markMoveAddr->getSrc ());
170
+ if (!asi || asi->isLexical ()) {
171
+ LLVM_DEBUG (llvm::dbgs ()
172
+ << " Source isnt an alloc_stack or is lexical... Bailing!\n " );
173
+ return false ;
174
+ }
175
+
176
+ DestroyAddrInst *dai = nullptr ;
177
+ CopyAddrInst *cai = nullptr ;
178
+ StoreInst *si = nullptr ;
179
+ if (!findInitAndDestroyForAllocation (asi, markMoveAddr, cai, dai, si))
180
+ return false ;
181
+
116
182
// If we did not find an (init | store) or destroy_addr, just bail.
117
183
if (!(cai || si) || !dai) {
118
184
LLVM_DEBUG (llvm::dbgs ()
@@ -122,7 +188,7 @@ static bool tryConvertSimpleMoveFromAllocStackTemporary(
122
188
123
189
assert (bool (cai) != bool (si));
124
190
125
- // Otherwise, lets walk from cai to markMoveAddr and make sure there aren't
191
+ // Otherwise, lets walk from cai/si to markMoveAddr and make sure there aren't
126
192
// any side-effect having instructions in between them.
127
193
//
128
194
// NOTE: We know that cai must be before the markMoveAddr in the block since
@@ -160,11 +226,11 @@ static bool tryConvertSimpleMoveFromAllocStackTemporary(
160
226
}))
161
227
return false ;
162
228
163
- LLVM_DEBUG (llvm::dbgs () << " Success! Performing optimization!\n " );
164
229
// Ok, we can perform our optimization! Change move_addr's source to be the
165
230
// original copy_addr's src and add add uses of the stack location to an
166
231
// instruction deleter. We will eliminate them later.
167
232
if (cai) {
233
+ LLVM_DEBUG (llvm::dbgs () << " Success! Performing optimization!\n " );
168
234
markMoveAddr->setSrc (cai->getSrc ());
169
235
return true ;
170
236
}
@@ -177,8 +243,8 @@ static bool tryConvertSimpleMoveFromAllocStackTemporary(
177
243
// re-materialized into an alloc_stack. In this example remembering that
178
244
// mark_unresolved_move_addr is a copy_addr [init], we try to move the MUMA
179
245
// onto the original lexical alloc_stack.
180
- //
181
- // TODO: Implement.
246
+ if ( tryHandlingLoadableVarMovePattern (markMoveAddr, si, aa))
247
+ return true ;
182
248
183
249
// If we do not have a load [copy], transform this mark_resolved_move_addr
184
250
// into a move_value [diagnostic] + store [init]. Predictable mem opts is
@@ -188,7 +254,11 @@ static bool tryConvertSimpleMoveFromAllocStackTemporary(
188
254
auto *newValue = builder.createMoveValue (si->getLoc (), si->getSrc ());
189
255
newValue->setAllowsDiagnostics (true );
190
256
si->setSrc (newValue);
191
- markMoveAddr->eraseFromParent ();
257
+ si->setDest (markMoveAddr->getDest ());
258
+ deleter.forceTrackAsDead (markMoveAddr);
259
+ deleter.forceTrackAsDead (dai);
260
+
261
+ LLVM_DEBUG (llvm::dbgs () << " Success! Performing optimization!\n " );
192
262
return true ;
193
263
}
194
264
@@ -217,6 +287,7 @@ class MoveFunctionCanonicalization : public SILFunctionTransform {
217
287
" Should only run on Raw SIL" );
218
288
219
289
auto *aa = getAnalysis<AliasAnalysis>(fn);
290
+ InstructionDeleter deleter;
220
291
221
292
for (auto &block : *fn) {
222
293
for (auto ii = block.begin (), ie = block.end (); ii != ie;) {
@@ -228,13 +299,15 @@ class MoveFunctionCanonicalization : public SILFunctionTransform {
228
299
// the mark_unresolved_move_addr is always on the operand regardless if
229
300
// in the caller we materalized the address into a temporary.
230
301
if (auto *markMoveAddr = dyn_cast<MarkUnresolvedMoveAddrInst>(inst)) {
231
- madeChange |=
232
- tryConvertSimpleMoveFromAllocStackTemporary ( markMoveAddr, aa);
302
+ madeChange |= tryConvertSimpleMoveFromAllocStackTemporary (
303
+ markMoveAddr, aa, deleter );
233
304
continue ;
234
305
}
235
306
}
236
307
}
237
308
309
+ deleter.cleanupDeadInstructions ();
310
+
238
311
if (madeChange) {
239
312
invalidateAnalysis (SILAnalysis::InvalidationKind::Instructions);
240
313
}
0 commit comments