Skip to content

Commit d569031

Browse files
committed
TempRValueOpt: move the mayWrite-check for applies from collectLoads to checkNoSourceModification
... where it belongs. This is mostly refactoring, but it also fixes a bug: we don't recurse into a begin_access in collectLoads. If there is an apply in such a scope, the mayWrite-check wouldn't be done. In checkNoSourceModification all instructions are visited, so the check is always done.
1 parent 673b887 commit d569031

File tree

1 file changed

+24
-48
lines changed

1 file changed

+24
-48
lines changed

lib/SILOptimizer/Transforms/TempRValueElimination.cpp

Lines changed: 24 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,6 @@ class TempRValueOptPass : public SILFunctionTransform {
8989
checkTempObjectDestroy(AllocStackInst *tempObj, CopyAddrInst *copyInst,
9090
ValueLifetimeAnalysis::Frontier &tempAddressFrontier);
9191

92-
bool canApplyBeTreatedAsLoad(Operand *tempObjUser, ApplySite apply,
93-
SILValue srcAddr);
94-
9592
bool tryOptimizeCopyIntoTemp(CopyAddrInst *copyInst);
9693
std::pair<SILBasicBlock::iterator, bool>
9794
tryOptimizeStoreIntoTemp(StoreInst *si);
@@ -116,31 +113,6 @@ bool TempRValueOptPass::collectLoadsFromProjection(
116113
return true;
117114
}
118115

119-
/// Check if \p tempObjUser, passed to the apply instruction, is only loaded,
120-
/// but not modified and if \p srcAddr is not modified as well.
121-
bool TempRValueOptPass::canApplyBeTreatedAsLoad(
122-
Operand *tempObjUser, ApplySite apply, SILValue srcAddr) {
123-
// Check if the function can just read from tempObjUser.
124-
auto convention = apply.getArgumentConvention(*tempObjUser);
125-
if (!convention.isGuaranteedConvention()) {
126-
LLVM_DEBUG(llvm::dbgs() << " Temp consuming use may write/destroy "
127-
"its source"
128-
<< *apply.getInstruction());
129-
return false;
130-
}
131-
132-
// If the function may write to the source of the copy_addr, the apply
133-
// cannot be treated as a load: all (potential) writes of the source must
134-
// appear _after_ all loads of the temporary. But in case of a function call
135-
// we don't know in which order the writes and loads are executed inside the
136-
// called function. The source may be written before the temporary is
137-
// loaded, which would make the optization invalid.
138-
if (aa->mayWriteToMemory(apply.getInstruction(), srcAddr))
139-
return false;
140-
141-
return true;
142-
}
143-
144116
/// Transitively explore all data flow uses of the given \p address until
145117
/// reaching a load or returning false.
146118
///
@@ -204,28 +176,23 @@ collectLoads(Operand *addressUse, CopyAddrInst *originalCopy,
204176
return false;
205177
LLVM_FALLTHROUGH;
206178
case SILInstructionKind::ApplyInst:
207-
case SILInstructionKind::TryApplyInst: {
208-
if (!canApplyBeTreatedAsLoad(addressUse, ApplySite(user),
209-
originalCopy->getSrc()))
210-
return false;
211-
// Everything is okay with the function call. Register it as a "load".
212-
loadInsts.insert(user);
213-
return true;
214-
}
179+
case SILInstructionKind::TryApplyInst:
215180
case SILInstructionKind::BeginApplyInst: {
216-
if (!canApplyBeTreatedAsLoad(addressUse, ApplySite(user),
217-
originalCopy->getSrc()))
181+
auto convention = ApplySite(user).getArgumentConvention(*addressUse);
182+
if (!convention.isGuaranteedConvention())
218183
return false;
219184

220-
auto beginApply = cast<BeginApplyInst>(user);
221-
// Register 'end_apply'/'abort_apply' as loads as well
222-
// 'checkNoSourceModification' should check instructions until
223-
// 'end_apply'/'abort_apply'.
224-
for (auto tokenUse : beginApply->getTokenResult()->getUses()) {
225-
SILInstruction *user = tokenUse->getUser();
226-
if (user->getParent() != block)
227-
return false;
228-
loadInsts.insert(tokenUse->getUser());
185+
loadInsts.insert(user);
186+
if (auto *beginApply = dyn_cast<BeginApplyInst>(user)) {
187+
// Register 'end_apply'/'abort_apply' as loads as well
188+
// 'checkNoSourceModification' should check instructions until
189+
// 'end_apply'/'abort_apply'.
190+
for (auto tokenUse : beginApply->getTokenResult()->getUses()) {
191+
SILInstruction *tokenUser = tokenUse->getUser();
192+
if (tokenUser->getParent() != block)
193+
return false;
194+
loadInsts.insert(tokenUser);
195+
}
229196
}
230197
return true;
231198
}
@@ -321,8 +288,17 @@ bool TempRValueOptPass::checkNoSourceModification(
321288

322289
// If this is the last use of the temp we are ok. After this point,
323290
// modifications to the source don't matter anymore.
324-
if (numLoadsFound == useInsts.size())
291+
// Note that we are assuming here that if an instruction loads and writes
292+
// to copySrc at the same time (like a copy_addr could do), the write
293+
// takes effect after the load.
294+
if (numLoadsFound == useInsts.size()) {
295+
// Function calls are an exception: in a called function a potential
296+
// modification of copySrc could occur _before_ the read of the temporary.
297+
if (FullApplySite::isa(inst) && aa->mayWriteToMemory(inst, copySrc))
298+
return false;
299+
325300
return true;
301+
}
326302

327303
if (aa->mayWriteToMemory(inst, copySrc)) {
328304
LLVM_DEBUG(llvm::dbgs() << " Source modified by" << *iter);

0 commit comments

Comments
 (0)