18
18
19
19
#define DEBUG_TYPE " sil-temp-rvalue-opt"
20
20
#include " swift/SIL/DebugUtils.h"
21
+ #include " swift/SIL/MemAccessUtils.h"
21
22
#include " swift/SIL/SILArgument.h"
22
23
#include " swift/SIL/SILBuilder.h"
23
24
#include " swift/SIL/SILVisitor.h"
24
25
#include " swift/SILOptimizer/Analysis/AliasAnalysis.h"
25
26
#include " swift/SILOptimizer/Analysis/DominanceAnalysis.h"
26
27
#include " swift/SILOptimizer/Analysis/PostOrderAnalysis.h"
27
28
#include " swift/SILOptimizer/Analysis/RCIdentityAnalysis.h"
29
+ #include " swift/SILOptimizer/Analysis/SimplifyInstruction.h"
28
30
#include " swift/SILOptimizer/PassManager/Passes.h"
29
31
#include " swift/SILOptimizer/PassManager/Transforms.h"
30
32
#include " swift/SILOptimizer/Utils/CFGOptUtils.h"
@@ -50,7 +52,7 @@ namespace {
50
52
// /
51
53
// / %temp = alloc_stack $T
52
54
// / copy_addr %src to [initialization] %temp : $*T
53
- // / // no writes to %src and %temp
55
+ // / // no writes to %src or %temp
54
56
// / destroy_addr %temp : $*T
55
57
// / dealloc_stack %temp : $*T
56
58
// /
@@ -67,7 +69,7 @@ class TempRValueOptPass : public SILFunctionTransform {
67
69
SmallPtrSetImpl<SILInstruction *> &loadInsts);
68
70
69
71
bool
70
- checkNoSourceModification (CopyAddrInst *copyInst,
72
+ checkNoSourceModification (CopyAddrInst *copyInst, SILValue copySrc,
71
73
const SmallPtrSetImpl<SILInstruction *> &useInsts);
72
74
73
75
bool
@@ -118,6 +120,9 @@ bool TempRValueOptPass::collectLoads(
118
120
<< " Temp use may write/destroy its source" << *user);
119
121
return false ;
120
122
123
+ case SILInstructionKind::BeginAccessInst:
124
+ return cast<BeginAccessInst>(user)->getAccessKind () == SILAccessKind::Read;
125
+
121
126
case SILInstructionKind::ApplyInst:
122
127
case SILInstructionKind::TryApplyInst: {
123
128
ApplySite apply (user);
@@ -227,7 +232,8 @@ bool TempRValueOptPass::collectLoads(
227
232
// / of the temporary and look for the last use, which effectively ends the
228
233
// / lifetime.
229
234
bool TempRValueOptPass::checkNoSourceModification (
230
- CopyAddrInst *copyInst, const SmallPtrSetImpl<SILInstruction *> &useInsts) {
235
+ CopyAddrInst *copyInst, SILValue copySrc,
236
+ const SmallPtrSetImpl<SILInstruction *> &useInsts) {
231
237
unsigned numLoadsFound = 0 ;
232
238
auto iter = std::next (copyInst->getIterator ());
233
239
// We already checked that the useful lifetime of the temporary ends in
@@ -244,7 +250,7 @@ bool TempRValueOptPass::checkNoSourceModification(
244
250
if (numLoadsFound == useInsts.size ())
245
251
return true ;
246
252
247
- if (aa->mayWriteToMemory (inst, copyInst-> getSrc () )) {
253
+ if (aa->mayWriteToMemory (inst, copySrc )) {
248
254
LLVM_DEBUG (llvm::dbgs () << " Source modified by" << *iter);
249
255
return false ;
250
256
}
@@ -336,8 +342,15 @@ bool TempRValueOptPass::tryOptimizeCopyIntoTemp(CopyAddrInst *copyInst) {
336
342
if (!tempObj)
337
343
return false ;
338
344
339
- assert (tempObj != copyInst->getSrc () &&
340
- " can't initialize temporary with itself" );
345
+ // The copy's source address must not be a scoped instruction, like
346
+ // begin_borrow. When the temporary object is eliminated, it's uses are
347
+ // replaced with the copy's source. Therefore, the source address must be
348
+ // valid at least until the next instruction that may write to or destroy the
349
+ // source. End-of-scope markers, such as end_borrow, do not write to or
350
+ // destroy memory, so scoped addresses are not valid replacements.
351
+ SILValue copySrc = stripAccessMarkers (copyInst->getSrc ());
352
+
353
+ assert (tempObj != copySrc && " can't initialize temporary with itself" );
341
354
342
355
// Scan all uses of the temporary storage (tempObj) to verify they all refer
343
356
// to the value initialized by this copy. It is sufficient to check that the
@@ -363,12 +376,12 @@ bool TempRValueOptPass::tryOptimizeCopyIntoTemp(CopyAddrInst *copyInst) {
363
376
}
364
377
}
365
378
366
- if (!collectLoads (useOper, user, tempObj, copyInst-> getSrc () , loadInsts))
379
+ if (!collectLoads (useOper, user, tempObj, copySrc , loadInsts))
367
380
return false ;
368
381
}
369
382
370
383
// Check if the source is modified within the lifetime of the temporary.
371
- if (!checkNoSourceModification (copyInst, loadInsts))
384
+ if (!checkNoSourceModification (copyInst, copySrc, loadInsts))
372
385
return false ;
373
386
374
387
ValueLifetimeAnalysis::Frontier tempAddressFrontier;
@@ -391,7 +404,7 @@ bool TempRValueOptPass::tryOptimizeCopyIntoTemp(CopyAddrInst *copyInst) {
391
404
switch (user->getKind ()) {
392
405
case SILInstructionKind::DestroyAddrInst:
393
406
if (copyInst->isTakeOfSrc ()) {
394
- use->set (copyInst-> getSrc () );
407
+ use->set (copySrc );
395
408
} else {
396
409
user->dropAllReferences ();
397
410
toDelete.push_back (user);
@@ -408,7 +421,7 @@ bool TempRValueOptPass::tryOptimizeCopyIntoTemp(CopyAddrInst *copyInst) {
408
421
if (cai->isTakeOfSrc () && !copyInst->isTakeOfSrc ())
409
422
cai->setIsTakeOfSrc (IsNotTake);
410
423
}
411
- use->set (copyInst-> getSrc () );
424
+ use->set (copySrc );
412
425
break ;
413
426
}
414
427
case SILInstructionKind::LoadInst: {
@@ -447,9 +460,9 @@ bool TempRValueOptPass::tryOptimizeCopyIntoTemp(CopyAddrInst *copyInst) {
447
460
448
461
// ASSUMPTION: no operations that may be handled by this default clause can
449
462
// destroy tempObj. This includes operations that load the value from memory
450
- // and release it.
463
+ // and release it or cast the address before destroying it .
451
464
default :
452
- use->set (copyInst-> getSrc () );
465
+ use->set (copySrc );
453
466
break ;
454
467
}
455
468
}
@@ -474,33 +487,50 @@ void TempRValueOptPass::run() {
474
487
bool changed = false ;
475
488
476
489
// Find all copy_addr instructions.
490
+ llvm::SmallVector<CopyAddrInst *, 8 > deadCopies;
477
491
for (auto &block : *getFunction ()) {
478
- auto ii = block.begin ();
479
- while (ii != block.end ()) {
492
+ // Increment the instruction iterator only after calling
493
+ // tryOptimizeCopyIntoTemp because the instruction after CopyInst might be
494
+ // deleted, but copyInst itself won't be deleted until later.
495
+ for (auto ii = block.begin (); ii != block.end (); ++ii) {
480
496
auto *copyInst = dyn_cast<CopyAddrInst>(&*ii);
481
497
482
498
if (copyInst) {
483
499
// In case of success, this may delete instructions, but not the
484
500
// CopyInst itself.
485
501
changed |= tryOptimizeCopyIntoTemp (copyInst);
502
+ // Remove identity copies which either directly result from successfully
503
+ // calling tryOptimizeCopyIntoTemp or was created by an earlier
504
+ // iteration, where another copy_addr copied the temporary back to the
505
+ // source location.
506
+ if (stripAccessMarkers (copyInst->getSrc ()) == copyInst->getDest ()) {
507
+ changed = true ;
508
+ deadCopies.push_back (copyInst);
509
+ }
486
510
}
487
-
488
- // Increment the instruction iterator here. We can't do it at the begin of
489
- // the loop because the instruction after CopyInst might be deleted in
490
- // in tryOptimizeCopyIntoTemp. We can't do it at the end of the loop
491
- // because the CopyInst might be deleted in the following code.
492
- ++ii;
493
-
494
- // Remove identity copies which are a result of this optimization.
495
- if (copyInst && copyInst->getSrc () == copyInst->getDest ()) {
496
- // This is either the CopyInst which just got optimized or it is a
497
- // follow-up from an earlier iteration, where another copy_addr copied
498
- // the temporary back to the source location.
499
- copyInst->eraseFromParent ();
511
+ }
512
+ }
513
+ // Delete the copies and any unused address operands.
514
+ // The same copy may have been added multiple times.
515
+ sortUnique (deadCopies);
516
+ for (auto *deadCopy : deadCopies) {
517
+ assert (changed);
518
+ auto *srcInst = deadCopy->getSrc ()->getDefiningInstruction ();
519
+ deadCopy->eraseFromParent ();
520
+ // Simplify any access scope markers that were only used by the dead
521
+ // copy_addr and other potentially unused addresses.
522
+ if (srcInst) {
523
+ if (SILValue result = simplifyInstruction (srcInst)) {
524
+ replaceAllSimplifiedUsesAndErase (
525
+ srcInst, result, [](SILInstruction *instToKill) {
526
+ // SimplifyInstruction is not in the business of removing
527
+ // copy_addr. If it were, then we would need to update deadCopies.
528
+ assert (!isa<CopyAddrInst>(instToKill));
529
+ instToKill->eraseFromParent ();
530
+ });
500
531
}
501
532
}
502
533
}
503
-
504
534
if (changed) {
505
535
invalidateAnalysis (SILAnalysis::InvalidationKind::Instructions);
506
536
}
0 commit comments