@@ -271,122 +271,6 @@ bool SILCombiner::tryOptimizeKeypathApplication(ApplyInst *AI,
271271 return true ;
272272}
273273
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-
390274// / Try to optimize a keypath KVC string access on a literal key path.
391275// /
392276// / Replace:
@@ -395,8 +279,17 @@ bool SILCombiner::tryOptimizeKeypathOffsetOf(ApplyInst *AI,
395279// / With:
396280// / %string = string_literal "blah"
397281bool 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+
400293 if (!calleeFn->getAttrs ()
401294 .hasSemanticsAttr (semantics::KEYPATH_KVC_KEY_PATH_STRING))
402295 return false ;
@@ -407,6 +300,11 @@ bool SILCombiner::tryOptimizeKeypathKVCString(ApplyInst *AI,
407300 if (!objTy || objTy.getStructOrBoundGenericStruct () != C.getStringDecl ())
408301 return false ;
409302
303+ KeyPathInst *kp
304+ = KeyPathProjector::getLiteralKeyPath (AI->getArgument (0 ));
305+ if (!kp || !kp->hasPattern ())
306+ return false ;
307+
410308 auto objcString = kp->getPattern ()->getObjCString ();
411309
412310 SILValue literalValue;
@@ -459,33 +357,10 @@ bool SILCombiner::tryOptimizeKeypath(ApplyInst *AI) {
459357 return tryOptimizeKeypathApplication (AI, callee);
460358 }
461359
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 ());
474362 }
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 ;
482363
483- if (tryOptimizeKeypathOffsetOf (AI, calleeFn, kp))
484- return true ;
485-
486- if (tryOptimizeKeypathKVCString (AI, calleeFn, kp))
487- return true ;
488-
489364 return false ;
490365}
491366
0 commit comments