@@ -271,122 +271,6 @@ bool SILCombiner::tryOptimizeKeypathApplication(ApplyInst *AI,
271
271
return true ;
272
272
}
273
273
274
- // / Replaces a call of the getter of AnyKeyPath._storedInlineOffset with a
275
- // / "constant" offset, in case of a keypath literal.
276
- // /
277
- // / "Constant" offset means a series of struct_element_addr and
278
- // / tuple_element_addr instructions with a 0-pointer as base address.
279
- // / These instructions can then be lowered to "real" constants in IRGen for
280
- // / concrete types, or to metatype offset lookups for generic or resilient types.
281
- // /
282
- // / Replaces:
283
- // / %kp = keypath ...
284
- // / %offset = apply %_storedInlineOffset_method(%kp)
285
- // / with:
286
- // / %zero = integer_literal $Builtin.Word, 0
287
- // / %null_ptr = unchecked_trivial_bit_cast %zero to $Builtin.RawPointer
288
- // / %null_addr = pointer_to_address %null_ptr
289
- // / %projected_addr = struct_element_addr %null_addr
290
- // / ... // other address projections
291
- // / %offset_ptr = address_to_pointer %projected_addr
292
- // / %offset_builtin_int = unchecked_trivial_bit_cast %offset_ptr
293
- // / %offset_int = struct $Int (%offset_builtin_int)
294
- // / %offset = enum $Optional<Int>, #Optional.some!enumelt, %offset_int
295
- bool SILCombiner::tryOptimizeKeypathOffsetOf (ApplyInst *AI,
296
- FuncDecl *calleeFn,
297
- KeyPathInst *kp) {
298
- auto *accessor = dyn_cast<AccessorDecl>(calleeFn);
299
- if (!accessor || !accessor->isGetter ())
300
- return false ;
301
-
302
- AbstractStorageDecl *storage = accessor->getStorage ();
303
- DeclName name = storage->getName ();
304
- if (!name.isSimpleName () ||
305
- (name.getBaseIdentifier ().str () != " _storedInlineOffset" ))
306
- return false ;
307
-
308
- KeyPathPattern *pattern = kp->getPattern ();
309
- SubstitutionMap patternSubs = kp->getSubstitutions ();
310
- CanType rootTy = pattern->getRootType ().subst (patternSubs)->getCanonicalType ();
311
- CanType parentTy = rootTy;
312
-
313
- // First check if _storedInlineOffset would return an offset or nil. Basically
314
- // only stored struct and tuple elements produce an offset. Everything else
315
- // (e.g. computed properties, class properties) result in nil.
316
- bool hasOffset = true ;
317
- for (const KeyPathPatternComponent &component : pattern->getComponents ()) {
318
- switch (component.getKind ()) {
319
- case KeyPathPatternComponent::Kind::StoredProperty: {
320
- if (!parentTy.getStructOrBoundGenericStruct ())
321
- hasOffset = false ;
322
- break ;
323
- }
324
- case KeyPathPatternComponent::Kind::TupleElement:
325
- break ;
326
- case KeyPathPatternComponent::Kind::GettableProperty:
327
- case KeyPathPatternComponent::Kind::SettableProperty:
328
- // We cannot predict the offset of fields in resilient types, because it's
329
- // unknown if a resilient field is a computed or stored property.
330
- if (component.getExternalDecl ())
331
- return false ;
332
- hasOffset = false ;
333
- break ;
334
- case KeyPathPatternComponent::Kind::OptionalChain:
335
- case KeyPathPatternComponent::Kind::OptionalForce:
336
- case KeyPathPatternComponent::Kind::OptionalWrap:
337
- hasOffset = false ;
338
- break ;
339
- }
340
- parentTy = component.getComponentType ();
341
- }
342
-
343
- SILLocation loc = AI->getLoc ();
344
- SILValue result;
345
-
346
- if (hasOffset) {
347
- SILType rootAddrTy = SILType::getPrimitiveAddressType (rootTy);
348
- SILValue rootAddr = Builder.createBaseAddrForOffset (loc, rootAddrTy);
349
-
350
- auto projector = KeyPathProjector::create (kp, rootAddr, loc, Builder);
351
- if (!projector)
352
- return false ;
353
-
354
- // Create the address projections of the keypath.
355
- SILType ptrType = SILType::getRawPointerType (Builder.getASTContext ());
356
- SILValue offsetPtr;
357
- projector->project (KeyPathProjector::AccessType::Get, [&](SILValue addr) {
358
- offsetPtr = Builder.createAddressToPointer (loc, addr, ptrType);
359
- });
360
-
361
- // The result of the _storedInlineOffset call should be Optional<Int>. If
362
- // not, something is wrong with the stdlib. Anyway, if it's not like we
363
- // expect, bail.
364
- SILType intType = AI->getType ().getOptionalObjectType ();
365
- if (!intType)
366
- return false ;
367
- StructDecl *intDecl = intType.getStructOrBoundGenericStruct ();
368
- if (!intDecl || intDecl->getStoredProperties ().size () != 1 )
369
- return false ;
370
- VarDecl *member = intDecl->getStoredProperties ()[0 ];
371
- CanType builtinIntTy = member->getType ()->getCanonicalType ();
372
- if (!isa<BuiltinIntegerType>(builtinIntTy))
373
- return false ;
374
-
375
- // Convert the projected address back to an optional integer.
376
- SILValue offset = Builder.createUncheckedBitCast (loc, offsetPtr,
377
- SILType::getPrimitiveObjectType (builtinIntTy));
378
- SILValue offsetInt = Builder.createStruct (loc, intType, { offset });
379
- result = Builder.createOptionalSome (loc, offsetInt, AI->getType ());
380
- } else {
381
- // The keypath has no offset.
382
- result = Builder.createOptionalNone (loc, AI->getType ());
383
- }
384
- AI->replaceAllUsesWith (result);
385
- eraseInstFromFunction (*AI);
386
- ++NumOptimizedKeypaths;
387
- return true ;
388
- }
389
-
390
274
// / Try to optimize a keypath KVC string access on a literal key path.
391
275
// /
392
276
// / Replace:
@@ -395,8 +279,17 @@ bool SILCombiner::tryOptimizeKeypathOffsetOf(ApplyInst *AI,
395
279
// / With:
396
280
// / %string = string_literal "blah"
397
281
bool SILCombiner::tryOptimizeKeypathKVCString (ApplyInst *AI,
398
- FuncDecl *calleeFn,
399
- KeyPathInst *kp) {
282
+ SILDeclRef callee) {
283
+ if (AI->getNumArguments () != 1 ) {
284
+ return false ;
285
+ }
286
+ if (!callee.hasDecl ()) {
287
+ return false ;
288
+ }
289
+ auto calleeFn = dyn_cast<FuncDecl>(callee.getDecl ());
290
+ if (!calleeFn)
291
+ return false ;
292
+
400
293
if (!calleeFn->getAttrs ()
401
294
.hasSemanticsAttr (semantics::KEYPATH_KVC_KEY_PATH_STRING))
402
295
return false ;
@@ -407,6 +300,11 @@ bool SILCombiner::tryOptimizeKeypathKVCString(ApplyInst *AI,
407
300
if (!objTy || objTy.getStructOrBoundGenericStruct () != C.getStringDecl ())
408
301
return false ;
409
302
303
+ KeyPathInst *kp
304
+ = KeyPathProjector::getLiteralKeyPath (AI->getArgument (0 ));
305
+ if (!kp || !kp->hasPattern ())
306
+ return false ;
307
+
410
308
auto objcString = kp->getPattern ()->getObjCString ();
411
309
412
310
SILValue literalValue;
@@ -459,33 +357,10 @@ bool SILCombiner::tryOptimizeKeypath(ApplyInst *AI) {
459
357
return tryOptimizeKeypathApplication (AI, callee);
460
358
}
461
359
462
- // Try optimize keypath method calls.
463
- auto *methodInst = dyn_cast<ClassMethodInst>(AI->getCallee ());
464
- if (!methodInst)
465
- return false ;
466
-
467
- if (AI->getNumArguments () != 1 ) {
468
- return false ;
469
- }
470
-
471
- SILDeclRef callee = methodInst->getMember ();
472
- if (!callee.hasDecl ()) {
473
- return false ;
360
+ if (auto method = dyn_cast<ClassMethodInst>(AI->getCallee ())) {
361
+ return tryOptimizeKeypathKVCString (AI, method->getMember ());
474
362
}
475
- auto *calleeFn = dyn_cast<FuncDecl>(callee.getDecl ());
476
- if (!calleeFn)
477
- return false ;
478
-
479
- KeyPathInst *kp = KeyPathProjector::getLiteralKeyPath (AI->getArgument (0 ));
480
- if (!kp || !kp->hasPattern ())
481
- return false ;
482
363
483
- if (tryOptimizeKeypathOffsetOf (AI, calleeFn, kp))
484
- return true ;
485
-
486
- if (tryOptimizeKeypathKVCString (AI, calleeFn, kp))
487
- return true ;
488
-
489
364
return false ;
490
365
}
491
366
0 commit comments