@@ -79,9 +79,8 @@ class TempRValueOptPass : public SILFunctionTransform {
7979 checkTempObjectDestroy (AllocStackInst *tempObj, CopyAddrInst *copyInst,
8080 ValueLifetimeAnalysis::Frontier &tempAddressFrontier);
8181
82- bool checkNoTempObjectModificationInApply (Operand *tempObjUser,
83- SILInstruction *inst,
84- SILValue srcAddr);
82+ bool canApplyBeTreatedAsLoad (Operand *tempObjUser, ApplySite apply,
83+ SILValue srcAddr);
8584
8685 bool tryOptimizeCopyIntoTemp (CopyAddrInst *copyInst);
8786 std::pair<SILBasicBlock::iterator, bool >
@@ -115,57 +114,39 @@ bool TempRValueOptPass::collectLoadsFromProjection(
115114 return true ;
116115}
117116
118- // / Check if 'tempObjUser' passed to the apply instruction can be modified by it
119- bool TempRValueOptPass::checkNoTempObjectModificationInApply (
120- Operand *tempObjUser, SILInstruction *applyInst, SILValue srcAddr) {
121- ApplySite apply (applyInst);
122-
117+ // / Check if \p tempObjUser, passed to the apply instruction, is only loaded,
118+ // / but not modified and if \p srcAddr is not modified as well.
119+ bool TempRValueOptPass::canApplyBeTreatedAsLoad (
120+ Operand *tempObjUser, ApplySite apply, SILValue srcAddr) {
123121 // Check if the function can just read from tempObjUser.
124122 auto convention = apply.getArgumentConvention (*tempObjUser);
125123 if (!convention.isGuaranteedConvention ()) {
126124 LLVM_DEBUG (llvm::dbgs () << " Temp consuming use may write/destroy "
127125 " its source"
128- << *applyInst);
129- return false ;
130- }
131-
132- // If we do not have an src address, but are indirect, bail. We would need
133- // to perform function signature specialization to change the functions
134- // signature to pass something direct.
135- if (!srcAddr && convention.isIndirectConvention ()) {
136- LLVM_DEBUG (
137- llvm::dbgs ()
138- << " Temp used to materialize value for indirect convention?! Can "
139- " not remove temporary without func sig opts"
140- << *applyInst);
126+ << *apply.getInstruction ());
141127 return false ;
142128 }
143129
144- // Check if there is another function argument, which is inout which might
145- // modify the source address if we have one.
146- //
147- // When a use of the temporary is an apply, then we need to prove that the
148- // function called by the apply cannot modify the temporary's source
149- // value. By design, this should be handled by
150- // `checkNoSourceModification`. However, this would be too conservative
151- // since it's common for the apply to have an @out argument, and alias
152- // analysis cannot prove that the @out does not alias with `src`. Instead,
153- // `checkNoSourceModification` always avoids analyzing the current use, so
154- // applies need to be handled here. We already know that an @out cannot
155- // alias with `src` because the `src` value must be initialized at the point
156- // of the call. Hence, it is sufficient to check specifically for another
157- // @inout that might alias with `src`.
158130 if (srcAddr) {
159- auto calleeConv = apply.getSubstCalleeConv ();
160- unsigned calleeArgIdx = apply.getCalleeArgIndexOfFirstAppliedArg ();
161- for (const auto &operand : apply.getArgumentOperands ()) {
162- auto argConv = calleeConv.getSILArgumentConvention (calleeArgIdx);
163- if (argConv.isInoutConvention ()) {
164- if (!aa->isNoAlias (operand.get (), srcAddr)) {
165- return false ;
166- }
167- }
168- ++calleeArgIdx;
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 ;
169150 }
170151 }
171152 return true ;
@@ -189,7 +170,8 @@ bool TempRValueOptPass::collectLoads(
189170 SILValue srcAddr, SmallPtrSetImpl<SILInstruction *> &loadInsts) {
190171 // All normal uses (loads) must be in the initialization block.
191172 // (The destroy and dealloc are commonly in a different block though.)
192- if (user->getParent () != address->getParent ())
173+ SILBasicBlock *block = address->getParent ();
174+ if (user->getParent () != block)
193175 return false ;
194176
195177 // Only allow uses that cannot destroy their operand. We need to be sure
@@ -232,22 +214,25 @@ bool TempRValueOptPass::collectLoads(
232214 LLVM_FALLTHROUGH;
233215 case SILInstructionKind::ApplyInst:
234216 case SILInstructionKind::TryApplyInst: {
235- if (!checkNoTempObjectModificationInApply (userOp, user, srcAddr))
217+ if (!canApplyBeTreatedAsLoad (userOp, ApplySite ( user) , srcAddr))
236218 return false ;
237219 // Everything is okay with the function call. Register it as a "load".
238220 loadInsts.insert (user);
239221 return true ;
240222 }
241223 case SILInstructionKind::BeginApplyInst: {
242- if (!checkNoTempObjectModificationInApply (userOp, user, srcAddr))
224+ if (!canApplyBeTreatedAsLoad (userOp, ApplySite ( user) , srcAddr))
243225 return false ;
244226
245227 auto beginApply = cast<BeginApplyInst>(user);
246228 // Register 'end_apply'/'abort_apply' as loads as well
247229 // 'checkNoSourceModification' should check instructions until
248230 // 'end_apply'/'abort_apply'.
249- for (auto tokenUses : beginApply->getTokenResult ()->getUses ()) {
250- loadInsts.insert (tokenUses->getUser ());
231+ for (auto tokenUse : beginApply->getTokenResult ()->getUses ()) {
232+ SILInstruction *user = tokenUse->getUser ();
233+ if (user->getParent () != block)
234+ return false ;
235+ loadInsts.insert (tokenUse->getUser ());
251236 }
252237 return true ;
253238 }
@@ -285,7 +270,8 @@ bool TempRValueOptPass::collectLoads(
285270 return collectLoadsFromProjection (utedai, srcAddr, loadInsts);
286271 }
287272 case SILInstructionKind::StructElementAddrInst:
288- case SILInstructionKind::TupleElementAddrInst: {
273+ case SILInstructionKind::TupleElementAddrInst:
274+ case SILInstructionKind::UncheckedAddrCastInst: {
289275 return collectLoadsFromProjection (cast<SingleValueInstruction>(user),
290276 srcAddr, loadInsts);
291277 }
0 commit comments