Skip to content

Commit 68db2e7

Browse files
committed
TempRValueOpt: don't use collectLoads in tryOptimizeStoreIntoTemp
This refactoring removes a lot of special-casing in collectLoads and also makes tryOptimizeStoreIntoTemp simpler. It's a NFC.
1 parent 0073512 commit 68db2e7

File tree

1 file changed

+36
-65
lines changed

1 file changed

+36
-65
lines changed

lib/SILOptimizer/Transforms/TempRValueElimination.cpp

Lines changed: 36 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
6475
class TempRValueOptPass : public SILFunctionTransform {
6576
AliasAnalysis *aa = nullptr;
6677

@@ -94,14 +105,6 @@ class TempRValueOptPass : public SILFunctionTransform {
94105
bool 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

Comments
 (0)