[embedded] Compile-time (literal) KeyPaths for Embedded Swift

Enable KeyPath/AnyKeyPath/PartialKeyPath/WritableKeyPath in Embedded Swift, but
for compile-time use only:

- Add keypath optimizations into the mandatory optimizations pipeline
- Allow keypath optimizations to look through begin_borrow, to make them work
  even in OSSA.
- If a use of a KeyPath doesn't optimize away, diagnose in PerformanceDiagnostics
- Make UnsafePointer.pointer(to:) transparent to allow the keypath optimization
  to happen in the callers of UnsafePointer.pointer(to:).
This commit is contained in:
Kuba Mracek
2024-03-20 15:35:43 -07:00
parent 4389ae2dc8
commit b642d771be
18 changed files with 272 additions and 119 deletions

View File

@@ -263,8 +263,8 @@ SILCombiner::optimizeApplyOfConvertFunctionInst(FullApplySite AI,
/// %addr = struct_element_addr/ref_element_addr %root_object
/// ...
/// load/store %addr
bool SILCombiner::tryOptimizeKeypathApplication(ApplyInst *AI,
SILFunction *callee) {
bool swift::tryOptimizeKeypathApplication(ApplyInst *AI,
SILFunction *callee, SILBuilder Builder) {
if (AI->getNumArguments() != 3)
return false;
@@ -303,7 +303,6 @@ bool SILCombiner::tryOptimizeKeypathApplication(ApplyInst *AI,
}
});
eraseInstFromFunction(*AI);
++NumOptimizedKeypaths;
return true;
}
@@ -329,9 +328,9 @@ bool SILCombiner::tryOptimizeKeypathApplication(ApplyInst *AI,
/// %offset_builtin_int = unchecked_trivial_bit_cast %offset_ptr
/// %offset_int = struct $Int (%offset_builtin_int)
/// %offset = enum $Optional<Int>, #Optional.some!enumelt, %offset_int
bool SILCombiner::tryOptimizeKeypathOffsetOf(ApplyInst *AI,
bool swift::tryOptimizeKeypathOffsetOf(ApplyInst *AI,
FuncDecl *calleeFn,
KeyPathInst *kp) {
KeyPathInst *kp, SILBuilder Builder) {
auto *accessor = dyn_cast<AccessorDecl>(calleeFn);
if (!accessor || !accessor->isGetter())
return false;
@@ -432,7 +431,6 @@ bool SILCombiner::tryOptimizeKeypathOffsetOf(ApplyInst *AI,
result = Builder.createOptionalNone(loc, AI->getType());
}
AI->replaceAllUsesWith(result);
eraseInstFromFunction(*AI);
++NumOptimizedKeypaths;
return true;
}
@@ -444,9 +442,9 @@ bool SILCombiner::tryOptimizeKeypathOffsetOf(ApplyInst *AI,
/// %string = apply %keypath_kvcString_method(%kp)
/// With:
/// %string = string_literal "blah"
bool SILCombiner::tryOptimizeKeypathKVCString(ApplyInst *AI,
bool swift::tryOptimizeKeypathKVCString(ApplyInst *AI,
FuncDecl *calleeFn,
KeyPathInst *kp) {
KeyPathInst *kp, SILBuilder Builder) {
if (!calleeFn->getAttrs()
.hasSemanticsAttr(semantics::KEYPATH_KVC_KEY_PATH_STRING))
return false;
@@ -499,14 +497,13 @@ bool SILCombiner::tryOptimizeKeypathKVCString(ApplyInst *AI,
}
AI->replaceAllUsesWith(literalValue);
eraseInstFromFunction(*AI);
++NumOptimizedKeypaths;
return true;
}
bool SILCombiner::tryOptimizeKeypath(ApplyInst *AI) {
bool swift::tryOptimizeKeypath(ApplyInst *AI, SILBuilder Builder) {
if (SILFunction *callee = AI->getReferencedFunctionOrNull()) {
return tryOptimizeKeypathApplication(AI, callee);
return tryOptimizeKeypathApplication(AI, callee, Builder);
}
// Try optimize keypath method calls.
@@ -530,10 +527,10 @@ bool SILCombiner::tryOptimizeKeypath(ApplyInst *AI) {
if (!kp || !kp->hasPattern())
return false;
if (tryOptimizeKeypathOffsetOf(AI, calleeFn, kp))
if (tryOptimizeKeypathOffsetOf(AI, calleeFn, kp, Builder))
return true;
if (tryOptimizeKeypathKVCString(AI, calleeFn, kp))
if (tryOptimizeKeypathKVCString(AI, calleeFn, kp, Builder))
return true;
return false;
@@ -1465,8 +1462,10 @@ SILInstruction *SILCombiner::visitApplyInst(ApplyInst *AI) {
if (auto *CFI = dyn_cast<ConvertFunctionInst>(callee))
return optimizeApplyOfConvertFunctionInst(AI, CFI);
if (tryOptimizeKeypath(AI))
if (tryOptimizeKeypath(AI, Builder)) {
eraseInstFromFunction(*AI);
return nullptr;
}
// Optimize readonly functions with no meaningful users.
SILFunction *SF = AI->getReferencedFunctionOrNull();