@@ -226,11 +226,8 @@ SILCombiner::optimizeApplyOfConvertFunctionInst(FullApplySite AI,
226
226
// / %addr = struct_element_addr/ref_element_addr %root_object
227
227
// / ...
228
228
// / load/store %addr
229
- bool SILCombiner::tryOptimizeKeypath (ApplyInst *AI) {
230
- SILFunction *callee = AI->getReferencedFunctionOrNull ();
231
- if (!callee)
232
- return false ;
233
-
229
+ bool SILCombiner::tryOptimizeKeypathApplication (ApplyInst *AI,
230
+ SILFunction *callee) {
234
231
if (AI->getNumArguments () != 3 )
235
232
return false ;
236
233
@@ -274,6 +271,99 @@ bool SILCombiner::tryOptimizeKeypath(ApplyInst *AI) {
274
271
return true ;
275
272
}
276
273
274
+ // / Try to optimize a keypath KVC string access on a literal key path.
275
+ // /
276
+ // / Replace:
277
+ // / %kp = keypath (objc "blah", ...)
278
+ // / %string = apply %keypath_kvcString_method(%kp)
279
+ // / With:
280
+ // / %string = string_literal "blah"
281
+ bool SILCombiner::tryOptimizeKeypathKVCString (ApplyInst *AI,
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
+
293
+ if (!calleeFn->getAttrs ()
294
+ .hasSemanticsAttr (semantics::KEYPATH_KVC_KEY_PATH_STRING))
295
+ return false ;
296
+
297
+ // Method should return `String?`
298
+ auto &C = calleeFn->getASTContext ();
299
+ auto objTy = AI->getType ().getOptionalObjectType ();
300
+ if (!objTy || objTy.getStructOrBoundGenericStruct () != C.getStringDecl ())
301
+ return false ;
302
+
303
+ KeyPathInst *kp
304
+ = KeyPathProjector::getLiteralKeyPath (AI->getArgument (0 ));
305
+ if (!kp || !kp->hasPattern ())
306
+ return false ;
307
+
308
+ auto objcString = kp->getPattern ()->getObjCString ();
309
+
310
+ SILValue literalValue;
311
+ if (objcString.empty ()) {
312
+ // Replace with a nil String value.
313
+ literalValue = Builder.createEnum (AI->getLoc (), SILValue (),
314
+ C.getOptionalNoneDecl (),
315
+ AI->getType ());
316
+ } else {
317
+ // Construct a literal String from the ObjC string.
318
+ auto init = C.getStringBuiltinInitDecl (C.getStringDecl ());
319
+ if (!init)
320
+ return false ;
321
+ auto initRef = SILDeclRef (init.getDecl (), SILDeclRef::Kind::Allocator);
322
+ auto initFn = AI->getModule ().findFunction (initRef.mangle (),
323
+ SILLinkage::PublicExternal);
324
+ if (!initFn)
325
+ return false ;
326
+
327
+ auto stringValue = Builder.createStringLiteral (AI->getLoc (), objcString,
328
+ StringLiteralInst::Encoding::UTF8);
329
+ auto stringLen = Builder.createIntegerLiteral (AI->getLoc (),
330
+ SILType::getBuiltinWordType (C),
331
+ objcString.size ());
332
+ auto isAscii = Builder.createIntegerLiteral (AI->getLoc (),
333
+ SILType::getBuiltinIntegerType (1 , C),
334
+ C.isASCIIString (objcString));
335
+ auto metaTy =
336
+ CanMetatypeType::get (objTy.getASTType (), MetatypeRepresentation::Thin);
337
+ auto self = Builder.createMetatype (AI->getLoc (),
338
+ SILType::getPrimitiveObjectType (metaTy));
339
+
340
+ auto initFnRef = Builder.createFunctionRef (AI->getLoc (), initFn);
341
+ auto string = Builder.createApply (AI->getLoc (),
342
+ initFnRef, {},
343
+ {stringValue, stringLen, isAscii, self});
344
+
345
+ literalValue = Builder.createEnum (AI->getLoc (), string,
346
+ C.getOptionalSomeDecl (), AI->getType ());
347
+ }
348
+
349
+ AI->replaceAllUsesWith (literalValue);
350
+ eraseInstFromFunction (*AI);
351
+ ++NumOptimizedKeypaths;
352
+ return true ;
353
+ }
354
+
355
+ bool SILCombiner::tryOptimizeKeypath (ApplyInst *AI) {
356
+ if (SILFunction *callee = AI->getReferencedFunctionOrNull ()) {
357
+ return tryOptimizeKeypathApplication (AI, callee);
358
+ }
359
+
360
+ if (auto method = dyn_cast<ClassMethodInst>(AI->getCallee ())) {
361
+ return tryOptimizeKeypathKVCString (AI, method->getMember ());
362
+ }
363
+
364
+ return false ;
365
+ }
366
+
277
367
// / Try to optimize a keypath application with an apply instruction.
278
368
// /
279
369
// / Replaces (simplified SIL):
0 commit comments