24
24
#include " swift/SIL/Projection.h"
25
25
#include " swift/SIL/SILBuilder.h"
26
26
#include " swift/SIL/SILFunction.h"
27
+ #include " swift/SIL/SILInstruction.h"
27
28
#include " swift/SILOptimizer/Analysis/SimplifyInstruction.h"
28
29
#include " llvm/ADT/Statistic.h"
29
30
#include " llvm/Support/Debug.h"
@@ -110,6 +111,54 @@ simplifyAndReplace(SILInstruction *inst, CanonicalizeInstruction &pass) {
110
111
// Canonicalize Memory Operations
111
112
// ===----------------------------------------------------------------------===//
112
113
114
+ namespace {
115
+
116
+ struct LoadOperation {
117
+ llvm::PointerUnion<LoadInst *, LoadBorrowInst *> value;
118
+
119
+ LoadOperation (SILInstruction *input) : value(nullptr ) {
120
+ if (auto *li = dyn_cast<LoadInst>(input)) {
121
+ value = li;
122
+ return ;
123
+ }
124
+
125
+ if (auto *lbi = dyn_cast<LoadBorrowInst>(input)) {
126
+ value = lbi;
127
+ return ;
128
+ }
129
+ }
130
+
131
+ operator bool () const { return !value.isNull (); }
132
+
133
+ SingleValueInstruction *operator *() const {
134
+ if (value.is <LoadInst *>())
135
+ return value.get <LoadInst *>();
136
+ return value.get <LoadBorrowInst *>();
137
+ }
138
+
139
+ const SingleValueInstruction *operator ->() const {
140
+ if (value.is <LoadInst *>())
141
+ return value.get <LoadInst *>();
142
+ return value.get <LoadBorrowInst *>();
143
+ }
144
+
145
+ SingleValueInstruction *operator ->() {
146
+ if (value.is <LoadInst *>())
147
+ return value.get <LoadInst *>();
148
+ return value.get <LoadBorrowInst *>();
149
+ }
150
+
151
+ Optional<LoadOwnershipQualifier> getOwnershipQualifier () const {
152
+ if (auto *lbi = value.dyn_cast <LoadBorrowInst *>()) {
153
+ return None;
154
+ }
155
+
156
+ return value.get <LoadInst *>()->getOwnershipQualifier ();
157
+ }
158
+ };
159
+
160
+ } // anonymous namespace
161
+
113
162
// Replace all uses of an original struct or tuple extract instruction with the
114
163
// given load instruction. The caller ensures that the load only loads the
115
164
// extracted field.
@@ -120,27 +169,29 @@ simplifyAndReplace(SILInstruction *inst, CanonicalizeInstruction &pass) {
120
169
// \p loadInst has the form:
121
170
// (load (struct_element_addr %base, #field)
122
171
static void replaceUsesOfExtract (SingleValueInstruction *extract,
123
- LoadInst * loadInst,
172
+ LoadOperation loadInst,
124
173
CanonicalizeInstruction &pass) {
125
174
assert (extract->getType () == loadInst->getType ());
126
175
127
- SingleValueInstruction *loadedVal = loadInst;
128
- if (loadInst->getOwnershipQualifier () == LoadOwnershipQualifier::Copy) {
129
- // Borrow the load-copied subelement, with precisely the same scope as
130
- // the aggregate borrow.
131
- assert (extract->getNumOperands () == 1 );
132
- auto *origBorrow = cast<BeginBorrowInst>(extract->getOperand (0 ));
133
- auto *newBorrow = SILBuilderWithScope (origBorrow)
134
- .createBeginBorrow (loadInst->getLoc (), loadInst);
135
- pass.notifyNewInstruction (newBorrow);
136
-
137
- assert (extract == origBorrow->getSingleNonEndingUse ()->getUser ());
138
- for (auto *origEnd : origBorrow->getEndBorrows ()) {
139
- auto *endBorrow = SILBuilderWithScope (origEnd).createEndBorrow (
140
- origEnd->getLoc (), newBorrow);
141
- pass.notifyNewInstruction (endBorrow);
176
+ SingleValueInstruction *loadedVal = *loadInst;
177
+ if (auto qual = loadInst.getOwnershipQualifier ()) {
178
+ if (*qual == LoadOwnershipQualifier::Copy) {
179
+ // Borrow the load-copied subelement, with precisely the same scope as
180
+ // the aggregate borrow.
181
+ assert (extract->getNumOperands () == 1 );
182
+ auto *origBorrow = cast<BeginBorrowInst>(extract->getOperand (0 ));
183
+ auto *newBorrow = SILBuilderWithScope (origBorrow)
184
+ .createBeginBorrow (loadInst->getLoc (), *loadInst);
185
+ pass.notifyNewInstruction (newBorrow);
186
+
187
+ assert (extract == origBorrow->getSingleNonEndingUse ()->getUser ());
188
+ for (auto *origEnd : origBorrow->getEndBorrows ()) {
189
+ auto *endBorrow = SILBuilderWithScope (origEnd).createEndBorrow (
190
+ origEnd->getLoc (), newBorrow);
191
+ pass.notifyNewInstruction (endBorrow);
192
+ }
193
+ loadedVal = newBorrow;
142
194
}
143
- loadedVal = newBorrow;
144
195
}
145
196
LLVM_DEBUG (llvm::dbgs () << " Replacing " << *extract << " with "
146
197
<< *loadedVal << " \n " );
@@ -156,28 +207,34 @@ static void replaceUsesOfExtract(SingleValueInstruction *extract,
156
207
//
157
208
// TODO: Consider handling LoadBorrowInst.
158
209
static SILBasicBlock::iterator
159
- splitAggregateLoad (LoadInst * loadInst, CanonicalizeInstruction &pass) {
210
+ splitAggregateLoad (LoadOperation loadInst, CanonicalizeInstruction &pass) {
160
211
// Keep track of the next iterator after any newly added or to-be-deleted
161
212
// instructions. This must be valid regardless of whether the pass immediately
162
213
// deletes the instructions or simply records them for later deletion.
163
214
auto nextII = std::next (loadInst->getIterator ());
164
215
165
216
bool needsBorrow;
166
- switch (loadInst->getOwnershipQualifier ()) {
167
- case LoadOwnershipQualifier::Unqualified:
168
- case LoadOwnershipQualifier::Trivial:
217
+ if (auto qual = loadInst.getOwnershipQualifier ()) {
218
+ switch (*qual) {
219
+ case LoadOwnershipQualifier::Unqualified:
220
+ case LoadOwnershipQualifier::Trivial:
221
+ needsBorrow = false ;
222
+ break ;
223
+ case LoadOwnershipQualifier::Copy:
224
+ needsBorrow = true ;
225
+ break ;
226
+ case LoadOwnershipQualifier::Take:
227
+ // TODO: To handle a "take", we would need to generate additional destroys
228
+ // for any fields that aren't already extracted. This would be
229
+ // out-of-place for this transform, and I'm not sure if this a case that
230
+ // needs to be handled in CanonicalizeInstruction.
231
+ return nextII;
232
+ }
233
+ } else {
234
+ // If we don't have a qual, we have a borrow.
169
235
needsBorrow = false ;
170
- break ;
171
- case LoadOwnershipQualifier::Copy:
172
- needsBorrow = true ;
173
- break ;
174
- case LoadOwnershipQualifier::Take:
175
- // TODO: To handle a "take", we would need to generate additional destroys
176
- // for any fields that aren't already extracted. This would be out-of-place
177
- // for this transform, and I'm not sure if this a case that needs to be
178
- // handled in SILGenCleanup.
179
- return nextII;
180
236
}
237
+
181
238
struct ProjInstPair {
182
239
Projection proj;
183
240
SingleValueInstruction *extract;
@@ -191,12 +248,12 @@ splitAggregateLoad(LoadInst *loadInst, CanonicalizeInstruction &pass) {
191
248
// Add load projections to a projection list.
192
249
llvm::SmallVector<ProjInstPair, 8 > projections;
193
250
llvm::SmallVector<BeginBorrowInst *, 8 > borrows;
194
- llvm::SmallVector<DestroyValueInst *, 8 > destroys ;
195
- for (auto *use : getNonDebugUses (loadInst)) {
251
+ llvm::SmallVector<SILInstruction *, 8 > lifetimeEndingInsts ;
252
+ for (auto *use : getNonDebugUses (* loadInst)) {
196
253
auto *user = use->getUser ();
197
254
if (needsBorrow) {
198
255
if (auto *destroy = dyn_cast<DestroyValueInst>(user)) {
199
- destroys .push_back (destroy);
256
+ lifetimeEndingInsts .push_back (destroy);
200
257
continue ;
201
258
}
202
259
auto *borrow = dyn_cast<BeginBorrowInst>(user);
@@ -210,7 +267,14 @@ splitAggregateLoad(LoadInst *loadInst, CanonicalizeInstruction &pass) {
210
267
211
268
borrows.push_back (borrow);
212
269
user = borrowedOper->getUser ();
270
+ } else {
271
+ if (isa<EndBorrowInst>(user) &&
272
+ !loadInst.getOwnershipQualifier ().hasValue ()) {
273
+ lifetimeEndingInsts.push_back (user);
274
+ continue ;
275
+ }
213
276
}
277
+
214
278
// If we have any non SEI, TEI instruction, don't do anything here.
215
279
if (!isa<StructExtractInst>(user) && !isa<TupleExtractInst>(user))
216
280
return nextII;
@@ -252,61 +316,80 @@ splitAggregateLoad(LoadInst *loadInst, CanonicalizeInstruction &pass) {
252
316
// Create a new address projection instruction and load instruction for each
253
317
// unique projection.
254
318
Projection *lastProj = nullptr ;
255
- LoadInst * lastNewLoad = nullptr ;
319
+ Optional<LoadOperation> lastNewLoad;
256
320
for (auto &pair : projections) {
257
321
auto &proj = pair.proj ;
258
322
auto *extract = pair.extract ;
259
323
260
324
// If this projection is the same as the last projection we processed, just
261
325
// replace all uses of the projection with the load we created previously.
262
326
if (lastProj && proj == *lastProj) {
263
- replaceUsesOfExtract (extract, lastNewLoad, pass);
327
+ replaceUsesOfExtract (extract, * lastNewLoad, pass);
264
328
nextII = killInstruction (extract, nextII, pass);
265
329
continue ;
266
330
}
267
331
268
332
// This is a unique projection. Create the new address projection and load.
269
333
lastProj = &proj;
270
334
// Insert new instructions before the original load.
271
- SILBuilderWithScope LoadBuilder (loadInst);
335
+ SILBuilderWithScope LoadBuilder (* loadInst);
272
336
auto *projInst =
273
337
proj.createAddressProjection (LoadBuilder, loadInst->getLoc (),
274
- loadInst->getOperand ())
338
+ loadInst->getOperand (0 ))
275
339
.get ();
276
340
pass.notifyNewInstruction (projInst);
277
341
278
342
// When loading a trivial subelement, convert ownership.
279
- LoadOwnershipQualifier loadOwnership = loadInst->getOwnershipQualifier ();
280
- if (loadOwnership != LoadOwnershipQualifier::Unqualified
281
- && projInst->getType ().isTrivial (*projInst->getFunction ())) {
282
- loadOwnership = LoadOwnershipQualifier::Trivial;
343
+ Optional<LoadOwnershipQualifier> loadOwnership =
344
+ loadInst.getOwnershipQualifier ();
345
+ if (loadOwnership.hasValue ()) {
346
+ if (*loadOwnership != LoadOwnershipQualifier::Unqualified &&
347
+ projInst->getType ().isTrivial (*projInst->getFunction ()))
348
+ loadOwnership = LoadOwnershipQualifier::Trivial;
349
+ } else {
350
+ if (projInst->getType ().isTrivial (*projInst->getFunction ()))
351
+ loadOwnership = LoadOwnershipQualifier::Trivial;
283
352
}
284
353
285
- lastNewLoad =
286
- LoadBuilder.createLoad (loadInst->getLoc (), projInst, loadOwnership);
287
- pass.notifyNewInstruction (lastNewLoad);
288
-
289
- if (loadOwnership == LoadOwnershipQualifier::Copy) {
290
- // Destroy the loaded value wherever the aggregate load was destroyed.
291
- assert (loadInst->getOwnershipQualifier () == LoadOwnershipQualifier::Copy);
292
- for (DestroyValueInst *destroy : destroys) {
293
- SILBuilderWithScope (destroy).createDestroyValue (destroy->getLoc (),
294
- lastNewLoad);
295
- pass.notifyNewInstruction (destroy);
354
+ if (loadOwnership) {
355
+ lastNewLoad =
356
+ LoadBuilder.createLoad (loadInst->getLoc (), projInst, *loadOwnership);
357
+ } else {
358
+ lastNewLoad = LoadBuilder.createLoadBorrow (loadInst->getLoc (), projInst);
359
+ }
360
+ pass.notifyNewInstruction (**lastNewLoad);
361
+
362
+ if (loadOwnership) {
363
+ if (*loadOwnership == LoadOwnershipQualifier::Copy) {
364
+ // Destroy the loaded value wherever the aggregate load was destroyed.
365
+ assert (loadInst.getOwnershipQualifier () ==
366
+ LoadOwnershipQualifier::Copy);
367
+ for (SILInstruction *destroy : lifetimeEndingInsts) {
368
+ auto *newInst = SILBuilderWithScope (destroy).createDestroyValue (
369
+ destroy->getLoc (), **lastNewLoad);
370
+ pass.notifyNewInstruction (newInst);
371
+ }
372
+ }
373
+ } else {
374
+ for (SILInstruction *destroy : lifetimeEndingInsts) {
375
+ auto *newInst = SILBuilderWithScope (destroy).createEndBorrow (
376
+ destroy->getLoc (), **lastNewLoad);
377
+ pass.notifyNewInstruction (newInst);
296
378
}
297
379
}
298
- replaceUsesOfExtract (extract, lastNewLoad, pass);
380
+ replaceUsesOfExtract (extract, * lastNewLoad, pass);
299
381
nextII = killInstruction (extract, nextII, pass);
300
382
}
383
+
301
384
// Remove the now unused borrows.
302
385
for (auto *borrow : borrows)
303
386
nextII = killInstAndIncidentalUses (borrow, nextII, pass);
304
387
305
388
// Erase the old load.
306
- for (auto *destroy : destroys )
389
+ for (auto *destroy : lifetimeEndingInsts )
307
390
nextII = killInstruction (destroy, nextII, pass);
308
391
309
- return killInstAndIncidentalUses (loadInst, nextII, pass);
392
+ return killInstAndIncidentalUses (* loadInst, nextII, pass);
310
393
}
311
394
312
395
// Given a store within a single property struct, recursively form the parent
@@ -451,11 +534,13 @@ CanonicalizeInstruction::canonicalize(SILInstruction *inst) {
451
534
if (auto nextII = simplifyAndReplace (inst, *this ))
452
535
return nextII.getValue ();
453
536
454
- if (auto *loadInst = dyn_cast<LoadInst>(inst))
455
- return splitAggregateLoad (loadInst, *this );
537
+ if (auto li = LoadOperation (inst)) {
538
+ return splitAggregateLoad (li, *this );
539
+ }
456
540
457
- if (auto *storeInst = dyn_cast<StoreInst>(inst))
541
+ if (auto *storeInst = dyn_cast<StoreInst>(inst)) {
458
542
return broadenSingleElementStores (storeInst, *this );
543
+ }
459
544
460
545
if (auto *cvi = dyn_cast<CopyValueInst>(inst))
461
546
return eliminateSimpleCopies (cvi, *this );
0 commit comments