28
28
#include " swift/SILOptimizer/Analysis/ValueTracking.h"
29
29
#include " swift/SILOptimizer/Utils/CFGOptUtils.h"
30
30
#include " swift/SILOptimizer/Utils/Existential.h"
31
+ #include " swift/SILOptimizer/Utils/KeyPathProjector.h"
31
32
#include " swift/SILOptimizer/Utils/ValueLifetime.h"
32
33
#include " llvm/ADT/DenseMap.h"
33
34
#include " llvm/ADT/SmallPtrSet.h"
34
35
#include " llvm/ADT/SmallVector.h"
35
36
#include " llvm/ADT/Statistic.h"
37
+ #include < utility>
36
38
37
39
using namespace swift ;
38
40
using namespace swift ::PatternMatch;
@@ -207,92 +209,6 @@ SILCombiner::optimizeApplyOfConvertFunctionInst(FullApplySite AI,
207
209
return NAI;
208
210
}
209
211
210
- // / Ends the begin_access "scope" if a begin_access was inserted for optimizing
211
- // / a keypath pattern.
212
- static void insertEndAccess (BeginAccessInst *&beginAccess, bool isModify,
213
- SILBuilder &builder) {
214
- if (beginAccess) {
215
- builder.createEndAccess (beginAccess->getLoc (), beginAccess,
216
- /* aborted*/ false );
217
- if (isModify)
218
- beginAccess->setAccessKind (SILAccessKind::Modify);
219
- beginAccess = nullptr ;
220
- }
221
- }
222
-
223
- // / Creates the projection pattern for a keypath instruction.
224
- // /
225
- // / Currently only the StoredProperty pattern is handled.
226
- // / TODO: handle other patterns, like getters/setters, optional chaining, etc.
227
- // /
228
- // / Returns false if \p keyPath is not a keypath instruction or if there is any
229
- // / other reason why the optimization cannot be done.
230
- static SILValue createKeypathProjections (SILValue keyPath, SILValue root,
231
- SILLocation loc,
232
- BeginAccessInst *&beginAccess,
233
- SILBuilder &builder) {
234
- if (auto *upCast = dyn_cast<UpcastInst>(keyPath))
235
- keyPath = upCast->getOperand ();
236
-
237
- // Is it a keypath instruction at all?
238
- auto *kpInst = dyn_cast<KeyPathInst>(keyPath);
239
- if (!kpInst || !kpInst->hasPattern ())
240
- return SILValue ();
241
-
242
- auto components = kpInst->getPattern ()->getComponents ();
243
-
244
- // Check if the keypath only contains patterns which we support.
245
- for (const KeyPathPatternComponent &comp : components) {
246
- if (comp.getKind () != KeyPathPatternComponent::Kind::StoredProperty)
247
- return SILValue ();
248
- }
249
-
250
- SILValue addr = root;
251
- for (const KeyPathPatternComponent &comp : components) {
252
- assert (comp.getKind () == KeyPathPatternComponent::Kind::StoredProperty);
253
- VarDecl *storedProperty = comp.getStoredPropertyDecl ();
254
- SILValue elementAddr;
255
- if (addr->getType ().getStructOrBoundGenericStruct ()) {
256
- addr = builder.createStructElementAddr (loc, addr, storedProperty);
257
- } else if (addr->getType ().getClassOrBoundGenericClass ()) {
258
- SingleValueInstruction *Ref = builder.createLoad (loc, addr,
259
- LoadOwnershipQualifier::Unqualified);
260
- insertEndAccess (beginAccess, /* isModify*/ false , builder);
261
-
262
- // Handle the case where the storedProperty is in a super class.
263
- while (Ref->getType ().getClassOrBoundGenericClass () !=
264
- storedProperty->getDeclContext ()) {
265
- SILType superCl = Ref->getType ().getSuperclass ();
266
- if (!superCl) {
267
- // This should never happen, because the property should be in the
268
- // decl or in a superclass of it. Just handle this to be on the safe
269
- // side.
270
- return SILValue ();
271
- }
272
- Ref = builder.createUpcast (loc, Ref, superCl);
273
- }
274
-
275
- addr = builder.createRefElementAddr (loc, Ref, storedProperty);
276
-
277
- // Class members need access enforcement.
278
- if (builder.getModule ().getOptions ().EnforceExclusivityDynamic ) {
279
- beginAccess = builder.createBeginAccess (loc, addr, SILAccessKind::Read,
280
- SILAccessEnforcement::Dynamic,
281
- /* noNestedConflict*/ false ,
282
- /* fromBuiltin*/ false );
283
- addr = beginAccess;
284
- }
285
- } else {
286
- // This should never happen, as a stored-property pattern can only be
287
- // applied to classes and structs. But to be safe - and future prove -
288
- // let's handle this case and bail.
289
- insertEndAccess (beginAccess, /* isModify*/ false , builder);
290
- return SILValue ();
291
- }
292
- }
293
- return addr;
294
- }
295
-
296
212
// / Try to optimize a keypath application with an apply instruction.
297
213
// /
298
214
// / Replaces (simplified SIL):
@@ -311,36 +227,40 @@ bool SILCombiner::tryOptimizeKeypath(ApplyInst *AI) {
311
227
return false ;
312
228
313
229
SILValue keyPath, rootAddr, valueAddr;
314
- bool isModify = false ;
230
+ bool isSet = false ;
315
231
if (callee->getName () == " swift_setAtWritableKeyPath" ||
316
232
callee->getName () == " swift_setAtReferenceWritableKeyPath" ) {
317
233
keyPath = AI->getArgument (1 );
318
234
rootAddr = AI->getArgument (0 );
319
235
valueAddr = AI->getArgument (2 );
320
- isModify = true ;
236
+ isSet = true ;
321
237
} else if (callee->getName () == " swift_getAtKeyPath" ) {
322
238
keyPath = AI->getArgument (2 );
323
239
rootAddr = AI->getArgument (1 );
324
240
valueAddr = AI->getArgument (0 );
325
241
} else {
326
242
return false ;
327
243
}
328
-
329
- BeginAccessInst *beginAccess = nullptr ;
330
- SILValue projectedAddr = createKeypathProjections (keyPath, rootAddr,
331
- AI->getLoc (), beginAccess,
332
- Builder);
333
- if (!projectedAddr)
244
+
245
+ auto projector = KeyPathProjector::create (keyPath, rootAddr,
246
+ AI->getLoc (), Builder);
247
+ if (!projector)
334
248
return false ;
335
-
336
- if (isModify) {
337
- Builder.createCopyAddr (AI->getLoc (), valueAddr, projectedAddr,
338
- IsTake, IsNotInitialization);
339
- } else {
340
- Builder.createCopyAddr (AI->getLoc (), projectedAddr, valueAddr,
341
- IsNotTake, IsInitialization);
342
- }
343
- insertEndAccess (beginAccess, isModify, Builder);
249
+
250
+ KeyPathProjector::AccessType accessType;
251
+ if (isSet) accessType = KeyPathProjector::AccessType::Set;
252
+ else accessType = KeyPathProjector::AccessType::Get;
253
+
254
+ projector->project (accessType, [&](SILValue projectedAddr) {
255
+ if (isSet) {
256
+ Builder.createCopyAddr (AI->getLoc (), valueAddr, projectedAddr,
257
+ IsTake, IsInitialization);
258
+ } else {
259
+ Builder.createCopyAddr (AI->getLoc (), projectedAddr, valueAddr,
260
+ IsNotTake, IsInitialization);
261
+ }
262
+ });
263
+
344
264
eraseInstFromFunction (*AI);
345
265
++NumOptimizedKeypaths;
346
266
return true ;
@@ -385,19 +305,24 @@ bool SILCombiner::tryOptimizeInoutKeypath(BeginApplyInst *AI) {
385
305
EndApplyInst *endApply = dyn_cast<EndApplyInst>(AIUse->getUser ());
386
306
if (!endApply)
387
307
return false ;
388
-
389
- BeginAccessInst *beginAccess = nullptr ;
390
- SILValue projectedAddr = createKeypathProjections (keyPath, rootAddr,
391
- AI->getLoc (), beginAccess,
392
- Builder);
393
- if (!projectedAddr)
308
+
309
+ auto projector = KeyPathProjector::create (keyPath, rootAddr,
310
+ AI->getLoc (), Builder);
311
+ if (!projector)
394
312
return false ;
313
+
314
+ KeyPathProjector::AccessType accessType;
315
+ if (isModify) accessType = KeyPathProjector::AccessType::Modify;
316
+ else accessType = KeyPathProjector::AccessType::Get;
317
+
318
+ projector->project (accessType, [&](SILValue projectedAddr) {
319
+ // Replace the projected address.
320
+ valueAddr->replaceAllUsesWith (projectedAddr);
321
+
322
+ // Skip to the end of the key path application before cleaning up.
323
+ Builder.setInsertionPoint (endApply);
324
+ });
395
325
396
- // Replace the projected address.
397
- valueAddr->replaceAllUsesWith (projectedAddr);
398
-
399
- Builder.setInsertionPoint (endApply);
400
- insertEndAccess (beginAccess, isModify, Builder);
401
326
eraseInstFromFunction (*endApply);
402
327
eraseInstFromFunction (*AI);
403
328
++NumOptimizedKeypaths;
0 commit comments