Skip to content

[embedded] Support _findStringSwitchCaseWithCache in Embedded Swift #78915

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,17 @@ fileprivate struct PathFunctionTuple: Hashable {

private func optimize(function: Function, _ context: FunctionPassContext, _ moduleContext: ModulePassContext, _ worklist: inout FunctionWorklist) {
var alreadyInlinedFunctions: Set<PathFunctionTuple> = Set()

// ObjectOutliner replaces calls to findStringSwitchCase with _findStringSwitchCaseWithCache, but this happens as a late SIL optimization,
// which is a problem for Embedded Swift, because _findStringSwitchCaseWithCache will then reference non-specialized code. Solve this by
// eagerly linking and specializing _findStringSwitchCaseWithCache whenever findStringSwitchCase is found in the module.
if context.options.enableEmbeddedSwift {
if function.hasSemanticsAttribute("findStringSwitchCase"),
let f = context.lookupStdlibFunction(name: "_findStringSwitchCaseWithCache"),
context.loadFunction(function: f, loadCalleesRecursively: true) {
worklist.pushIfNotVisited(f)
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a reasonable approach


var changed = true
while changed {
Expand Down
22 changes: 18 additions & 4 deletions lib/SILOptimizer/IPO/DeadFunctionElimination.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ class DeadFunctionAndGlobalElimination {
llvm::SmallPtrSet<void *, 32> AliveFunctionsAndTables;

bool keepExternalWitnessTablesAlive;
bool keepStringSwitchIntrinsicAlive;

/// Checks is a function is alive, e.g. because it is visible externally.
bool isAnchorFunction(SILFunction *F) {
Expand Down Expand Up @@ -124,6 +125,15 @@ class DeadFunctionAndGlobalElimination {
if (F->getRepresentation() == SILFunctionTypeRepresentation::ObjCMethod)
return true;

// To support ObjectOutliner's replacing of calls to findStringSwitchCase
// with _findStringSwitchCaseWithCache. In Embedded Swift, we have to load
// the body of this function early and specialize it, so that ObjectOutliner
// can reference it later. To make this work we have to avoid DFE'ing it in
// the early DFE pass. Late DFE will take care of it if actually unused.
if (keepStringSwitchIntrinsicAlive &&
F->hasSemanticsAttr("findStringSwitchCaseWithCache"))
return true;

return false;
}

Expand Down Expand Up @@ -713,9 +723,11 @@ class DeadFunctionAndGlobalElimination {

public:
DeadFunctionAndGlobalElimination(SILModule *module,
bool keepExternalWitnessTablesAlive) :
bool keepExternalWitnessTablesAlive,
bool keepStringSwitchIntrinsicAlive) :
Module(module),
keepExternalWitnessTablesAlive(keepExternalWitnessTablesAlive) {}
keepExternalWitnessTablesAlive(keepExternalWitnessTablesAlive),
keepStringSwitchIntrinsicAlive(keepStringSwitchIntrinsicAlive) {}

/// The main entry point of the optimization.
void eliminateFunctionsAndGlobals(SILModuleTransform *DFEPass) {
Expand Down Expand Up @@ -799,8 +811,10 @@ class DeadFunctionAndGlobalEliminationPass : public SILModuleTransform {
// can eliminate such functions.
getModule()->invalidateSILLoaderCaches();

DeadFunctionAndGlobalElimination deadFunctionElimination(getModule(),
/*keepExternalWitnessTablesAlive*/ !isLateDFE);
DeadFunctionAndGlobalElimination deadFunctionElimination(
getModule(),
/*keepExternalWitnessTablesAlive*/ !isLateDFE,
/*keepStringSwitchIntrinsicAlive*/ !isLateDFE);
deadFunctionElimination.eliminateFunctionsAndGlobals(this);
}
};
Expand Down
37 changes: 37 additions & 0 deletions test/embedded/string-switch2.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// RUN: %target-run-simple-swift(-enable-experimental-feature Embedded -wmo -O -Xlinker %swift_obj_root/lib/swift/embedded/%target-cpu-apple-macos/libswiftUnicodeDataTables.a) | %FileCheck %s

// REQUIRES: swift_in_compiler
// REQUIRES: executable_test
// REQUIRES: optimized_stdlib
// REQUIRES: swift_stdlib_no_asserts
// REQUIRES: OS=macosx
// REQUIRES: swift_feature_Embedded

enum MyEnum: String {
case case1
case case2
case case3
case case4
case case5
case case6
case case7
case case8
case case9
case case10
case case11
case case12
case case13
case case14
case case15
case case16
case case17
case case18
case case19
}

var e = MyEnum.case1
print(e.rawValue)
e = MyEnum.case2
print(e.rawValue)
// CHECK: case1
// CHECK: case2