@@ -79,6 +79,10 @@ class TempRValueOptPass : public SILFunctionTransform {
79
79
checkTempObjectDestroy (AllocStackInst *tempObj, CopyAddrInst *copyInst,
80
80
ValueLifetimeAnalysis::Frontier &tempAddressFrontier);
81
81
82
+ bool checkNoTempObjectModificationInApply (Operand *tempObjUser,
83
+ SILInstruction *inst,
84
+ SILValue srcAddr);
85
+
82
86
bool tryOptimizeCopyIntoTemp (CopyAddrInst *copyInst);
83
87
std::pair<SILBasicBlock::iterator, bool >
84
88
tryOptimizeStoreIntoTemp (StoreInst *si);
@@ -111,6 +115,61 @@ bool TempRValueOptPass::collectLoadsFromProjection(
111
115
return true ;
112
116
}
113
117
118
+ bool TempRValueOptPass::checkNoTempObjectModificationInApply (
119
+ Operand *tempObjUser, SILInstruction *applyInst, SILValue srcAddr) {
120
+ ApplySite apply (applyInst);
121
+
122
+ // Check if the function can just read from tempObjUser.
123
+ auto convention = apply.getArgumentConvention (*tempObjUser);
124
+ if (!convention.isGuaranteedConvention ()) {
125
+ LLVM_DEBUG (llvm::dbgs () << " Temp consuming use may write/destroy "
126
+ " its source"
127
+ << *applyInst);
128
+ return false ;
129
+ }
130
+
131
+ // If we do not have an src address, but are indirect, bail. We would need
132
+ // to perform function signature specialization to change the functions
133
+ // signature to pass something direct.
134
+ if (!srcAddr && convention.isIndirectConvention ()) {
135
+ LLVM_DEBUG (
136
+ llvm::dbgs ()
137
+ << " Temp used to materialize value for indirect convention?! Can "
138
+ " not remove temporary without func sig opts"
139
+ << *applyInst);
140
+ return false ;
141
+ }
142
+
143
+ // Check if there is another function argument, which is inout which might
144
+ // modify the source address if we have one.
145
+ //
146
+ // When a use of the temporary is an apply, then we need to prove that the
147
+ // function called by the apply cannot modify the temporary's source
148
+ // value. By design, this should be handled by
149
+ // `checkNoSourceModification`. However, this would be too conservative
150
+ // since it's common for the apply to have an @out argument, and alias
151
+ // analysis cannot prove that the @out does not alias with `src`. Instead,
152
+ // `checkNoSourceModification` always avoids analyzing the current use, so
153
+ // applies need to be handled here. We already know that an @out cannot
154
+ // alias with `src` because the `src` value must be initialized at the point
155
+ // of the call. Hence, it is sufficient to check specifically for another
156
+ // @inout that might alias with `src`.
157
+ if (srcAddr) {
158
+ auto calleeConv = apply.getSubstCalleeConv ();
159
+ unsigned calleeArgIdx = apply.getCalleeArgIndexOfFirstAppliedArg ();
160
+ for (const auto &operand : apply.getArgumentOperands ()) {
161
+ auto argConv = calleeConv.getSILArgumentConvention (calleeArgIdx);
162
+ if (argConv.isInoutConvention ()) {
163
+ if (!aa->isNoAlias (operand.get (), srcAddr)) {
164
+ return false ;
165
+ }
166
+ }
167
+ ++calleeArgIdx;
168
+ }
169
+ }
170
+ return true ;
171
+ }
172
+
114
173
// / Transitively explore all data flow uses of the given \p address until
115
174
// / reaching a load or returning false.
116
175
// /
@@ -171,61 +230,21 @@ bool TempRValueOptPass::collectLoads(
171
230
return false ;
172
231
LLVM_FALLTHROUGH;
173
232
case SILInstructionKind::ApplyInst:
174
- case SILInstructionKind::BeginApplyInst:
175
233
case SILInstructionKind::TryApplyInst: {
176
- ApplySite apply (user);
177
-
178
- // Check if the function can just read from userOp.
179
- auto convention = apply.getArgumentConvention (*userOp);
180
- if (!convention.isGuaranteedConvention ()) {
181
- LLVM_DEBUG (llvm::dbgs () << " Temp consuming use may write/destroy "
182
- " its source"
183
- << *user);
234
+ if (!checkNoTempObjectModificationInApply (userOp, user, srcAddr))
184
235
return false ;
185
- }
186
-
187
- // If we do not have an src address, but are indirect, bail. We would need
188
- // to perform function signature specialization to change the functions
189
- // signature to pass something direct.
190
- if (!srcAddr && convention.isIndirectConvention ()) {
191
- LLVM_DEBUG (
192
- llvm::dbgs ()
193
- << " Temp used to materialize value for indirect convention?! Can "
194
- " not remove temporary without func sig opts"
195
- << *user);
236
+ // Everything is okay with the function call. Register it as a "load".
237
+ loadInsts.insert (user);
238
+ return true ;
239
+ }
240
+ case SILInstructionKind::BeginApplyInst: {
241
+ if (!checkNoTempObjectModificationInApply (userOp, user, srcAddr))
196
242
return false ;
197
- }
198
243
199
- // Check if there is another function argument, which is inout which might
200
- // modify the source address if we have one.
201
- //
202
- // When a use of the temporary is an apply, then we need to prove that the
203
- // function called by the apply cannot modify the temporary's source
204
- // value. By design, this should be handled by
205
- // `checkNoSourceModification`. However, this would be too conservative
206
- // since it's common for the apply to have an @out argument, and alias
207
- // analysis cannot prove that the @out does not alias with `src`. Instead,
208
- // `checkNoSourceModification` always avoids analyzing the current use, so
209
- // applies need to be handled here. We already know that an @out cannot
210
- // alias with `src` because the `src` value must be initialized at the point
211
- // of the call. Hence, it is sufficient to check specifically for another
212
- // @inout that might alias with `src`.
213
- if (srcAddr) {
214
- auto calleeConv = apply.getSubstCalleeConv ();
215
- unsigned calleeArgIdx = apply.getCalleeArgIndexOfFirstAppliedArg ();
216
- for (const auto &operand : apply.getArgumentOperands ()) {
217
- auto argConv = calleeConv.getSILArgumentConvention (calleeArgIdx);
218
- if (argConv.isInoutConvention ()) {
219
- if (!aa->isNoAlias (operand.get (), srcAddr)) {
220
- return false ;
221
- }
222
- }
223
- ++calleeArgIdx;
224
- }
244
+ auto beginApply = cast<BeginApplyInst>(user);
245
+ for (auto tokenUses : beginApply->getTokenResult ()->getUses ()) {
246
+ loadInsts.insert (tokenUses->getUser ());
225
247
}
226
-
227
- // Everything is okay with the function call. Register it as a "load".
228
- loadInsts.insert (user);
229
248
return true ;
230
249
}
231
250
case SILInstructionKind::OpenExistentialAddrInst: {
0 commit comments