@@ -61,6 +61,17 @@ namespace {
6161// / it finds cases in which it is easy to determine that the source is
6262// / unmodified during the copy destination's lifetime. Thus, the destination can
6363// / be viewed as a short-lived "rvalue".
64+ // /
65+ // / As a second optimization, also stores into temporaries are handled. This is
66+ // / a simple form of redundant-load-elimination (RLE).
67+ // /
68+ // / %temp = alloc_stack $T
69+ // / store %src to [initialization] %temp : $*T
70+ // / // no writes to %temp
71+ // / %v = load [take] %temp : $*T
72+ // / dealloc_stack %temp : $*T
73+ // /
74+ // / TODO: Check if we still need to handle stores when RLE supports OSSA.
6475class TempRValueOptPass : public SILFunctionTransform {
6576 AliasAnalysis *aa = nullptr ;
6677
@@ -94,14 +105,6 @@ class TempRValueOptPass : public SILFunctionTransform {
94105bool TempRValueOptPass::collectLoadsFromProjection (
95106 SingleValueInstruction *projection, SILValue srcAddr,
96107 SmallPtrSetImpl<SILInstruction *> &loadInsts) {
97- if (!srcAddr) {
98- LLVM_DEBUG (
99- llvm::dbgs ()
100- << " Temp has addr_projection use?! Can not yet promote to value"
101- << *projection);
102- return false ;
103- }
104-
105108 // Transitively look through projections on stack addresses.
106109 for (auto *projUseOper : projection->getUses ()) {
107110 auto *user = projUseOper->getUser ();
@@ -127,28 +130,15 @@ bool TempRValueOptPass::canApplyBeTreatedAsLoad(
127130 return false ;
128131 }
129132
130- if (srcAddr) {
131- // If the function may write to the source of the copy_addr, the apply
132- // cannot be treated as a load: all (potential) writes of the source must
133- // appear _after_ all loads of the temporary. But in case of a function call
134- // we don't know in which order the writes and loads are executed inside the
135- // called function. The source may be written before the temporary is
136- // loaded, which would make the optization invalid.
137- if (aa->mayWriteToMemory (apply.getInstruction (), srcAddr))
138- return false ;
139- } else {
140- // If we do not have an src address, but are indirect, bail. We would need
141- // to perform function signature specialization to change the functions
142- // signature to pass something direct.
143- if (convention.isIndirectConvention ()) {
144- LLVM_DEBUG (
145- llvm::dbgs ()
146- << " Temp used to materialize value for indirect convention?! Can "
147- " not remove temporary without func sig opts"
148- << *apply.getInstruction ());
149- return false ;
150- }
151- }
133+ // If the function may write to the source of the copy_addr, the apply
134+ // cannot be treated as a load: all (potential) writes of the source must
135+ // appear _after_ all loads of the temporary. But in case of a function call
136+ // we don't know in which order the writes and loads are executed inside the
137+ // called function. The source may be written before the temporary is
138+ // loaded, which would make the optization invalid.
139+ if (aa->mayWriteToMemory (apply.getInstruction (), srcAddr))
140+ return false ;
141+
152142 return true ;
153143}
154144
@@ -237,14 +227,6 @@ bool TempRValueOptPass::collectLoads(
237227 return true ;
238228 }
239229 case SILInstructionKind::OpenExistentialAddrInst: {
240- // If we do not have an srcAddr, bail. We do not support promoting this yet.
241- if (!srcAddr) {
242- LLVM_DEBUG (llvm::dbgs () << " Temp has open_existential_addr use?! Can "
243- " not yet promote to value"
244- << *user);
245- return false ;
246- }
247-
248230 // We only support open existential addr if the access is immutable.
249231 auto *oeai = cast<OpenExistentialAddrInst>(user);
250232 if (oeai->getAccessKind () != OpenedExistentialAccess::Immutable) {
@@ -294,11 +276,6 @@ bool TempRValueOptPass::collectLoads(
294276 return true ;
295277
296278 case SILInstructionKind::LoadBorrowInst:
297- // If we do not have a source addr, we must be trying to eliminate a
298- // store. Until we check that the source object is not destroyed within the
299- // given range, we need bail.
300- if (!srcAddr)
301- return false ;
302279 loadInsts.insert (user);
303280 return true ;
304281 case SILInstructionKind::FixLifetimeInst:
@@ -598,29 +575,21 @@ TempRValueOptPass::tryOptimizeStoreIntoTemp(StoreInst *si) {
598575 if (user == si)
599576 continue ;
600577
601- // Destroys and deallocations are allowed to be in a different block.
602- if (isa<DestroyAddrInst>(user) || isa<DeallocStackInst>(user))
603- continue ;
604-
605- // Same for load [take] on the top level temp object. SILGen always takes
606- // whole values from temporaries. If we have load [take] on projections from
607- // our base, we fail since those would be re-initializations.
608- if (auto *li = dyn_cast<LoadInst>(user)) {
609- if (li->getOwnershipQualifier () == LoadOwnershipQualifier::Take) {
610- continue ;
611- }
612- }
613-
614- // We pass in SILValue() since we do not have a source address.
615- if (!collectLoads (useOper, user, tempObj, SILValue (), loadInsts))
616- return {std::next (si->getIterator ()), false };
617-
618578 // Bail if there is any kind of user which is not handled in the code below.
619579 switch (user->getKind ()) {
620- case SILInstructionKind::CopyAddrInst:
580+ case SILInstructionKind::DestroyAddrInst:
581+ case SILInstructionKind::DeallocStackInst:
582+ case SILInstructionKind::LoadInst:
621583 case SILInstructionKind::FixLifetimeInst:
584+ break ;
585+ case SILInstructionKind::CopyAddrInst:
586+ if (cast<CopyAddrInst>(user)->getDest () == tempObj)
587+ return {std::next (si->getIterator ()), false };
588+ break ;
622589 case SILInstructionKind::MarkDependenceInst:
623- continue ;
590+ if (cast<MarkDependenceInst>(user)->getValue () == tempObj)
591+ return {std::next (si->getIterator ()), false };
592+ break ;
624593 default :
625594 return {std::next (si->getIterator ()), false };
626595 }
@@ -690,11 +659,13 @@ TempRValueOptPass::tryOptimizeStoreIntoTemp(StoreInst *si) {
690659 break ;
691660 }
692661 case SILInstructionKind::MarkDependenceInst: {
693- SILBuilderWithScope builder (user);
694662 auto mdi = cast<MarkDependenceInst>(user);
695- auto newInst = builder.createMarkDependence (user->getLoc (), mdi->getValue (), si->getSrc ());
663+ assert (mdi->getBase () == tempObj);
664+ SILBuilderWithScope builder (user);
665+ auto newInst = builder.createMarkDependence (user->getLoc (),
666+ mdi->getValue (), si->getSrc ());
696667 mdi->replaceAllUsesWith (newInst);
697- toDelete.push_back (user );
668+ toDelete.push_back (mdi );
698669 break ;
699670 }
700671 // ASSUMPTION: no operations that may be handled by this default clause can
0 commit comments