diff --git a/SwiftCompilerSources/Sources/Optimizer/ModulePasses/MandatoryPerformanceOptimizations.swift b/SwiftCompilerSources/Sources/Optimizer/ModulePasses/MandatoryPerformanceOptimizations.swift index 76b4eb5291306..0e397471e9528 100644 --- a/SwiftCompilerSources/Sources/Optimizer/ModulePasses/MandatoryPerformanceOptimizations.swift +++ b/SwiftCompilerSources/Sources/Optimizer/ModulePasses/MandatoryPerformanceOptimizations.swift @@ -80,6 +80,17 @@ fileprivate struct PathFunctionTuple: Hashable { private func optimize(function: Function, _ context: FunctionPassContext, _ moduleContext: ModulePassContext, _ worklist: inout FunctionWorklist) { var alreadyInlinedFunctions: Set = 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) + } + } var changed = true while changed { diff --git a/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp b/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp index 9ee5b7ee7b15f..e45dfe2c89285 100644 --- a/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp +++ b/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp @@ -90,6 +90,7 @@ class DeadFunctionAndGlobalElimination { llvm::SmallPtrSet AliveFunctionsAndTables; bool keepExternalWitnessTablesAlive; + bool keepStringSwitchIntrinsicAlive; /// Checks is a function is alive, e.g. because it is visible externally. bool isAnchorFunction(SILFunction *F) { @@ -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; } @@ -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) { @@ -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); } }; diff --git a/test/embedded/string-switch2.swift b/test/embedded/string-switch2.swift new file mode 100644 index 0000000000000..1d88535522fab --- /dev/null +++ b/test/embedded/string-switch2.swift @@ -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