Skip to content

Commit 270ea8b

Browse files
committed
SILOptimizer: Fix mandatory switch dispatch elimination for unreachable cases.
#67920 introduced a mandatory SIL optimization that eliminates switch statement dispatch for enum elements that are provably unavailable at runtime. This optimization helps eliminate unreachable code, but it's also load bearing because it removes references to enum element symbols that may not preset at link time. The optimization was checking the wrong condition to determine whether an enum element is unavailable at runtime and so the optimization wasn't working for code using custom availability domains. Resolves rdar://161846311.
1 parent 9953b1e commit 270ea8b

File tree

2 files changed

+64
-3
lines changed

2 files changed

+64
-3
lines changed

lib/SILOptimizer/Mandatory/DiagnoseUnreachable.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -926,9 +926,7 @@ static bool eliminateSwitchDispatchOnUnavailableElements(
926926
SmallVector<std::pair<EnumElementDecl *, SILBasicBlock *>, 4> NewCaseBBs;
927927
for (unsigned i : range(SWI.getNumCases())) {
928928
auto CaseBB = SWI.getCase(i);
929-
auto availableAtr = CaseBB.first->getUnavailableAttr();
930-
931-
if (availableAtr && availableAtr->isUnconditionallyUnavailable()) {
929+
if (!CaseBB.first->isAvailableDuringLowering()) {
932930
// Mark the basic block as potentially unreachable.
933931
SILBasicBlock *UnreachableBlock = CaseBB.second;
934932
if (!State->PossiblyUnreachableBlocks.contains(UnreachableBlock)) {
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// RUN: %target-swift-emit-sil -module-name Test %s -verify -parse-as-library \
2+
// RUN: -enable-experimental-feature CustomAvailability \
3+
// RUN: -define-enabled-availability-domain EnabledDomain \
4+
// RUN: -define-always-enabled-availability-domain AlwaysEnabledDomain \
5+
// RUN: -define-disabled-availability-domain DisabledDomain \
6+
// RUN: -define-dynamic-availability-domain DynamicDomain \
7+
// RUN: -Onone \
8+
// RUN: | %FileCheck %s --check-prefixes=CHECK,CHECK-NOOPT
9+
10+
// REQUIRES: swift_feature_CustomAvailability
11+
12+
public enum Enum {
13+
case alwaysAvailable
14+
15+
@available(*, unavailable)
16+
case alwaysUnavailable
17+
18+
@available(EnabledDomain)
19+
case enabled
20+
21+
@available(EnabledDomain, unavailable)
22+
case enabledUnavailable
23+
24+
@available(AlwaysEnabledDomain)
25+
case alwaysEnabled
26+
27+
@available(AlwaysEnabledDomain, unavailable)
28+
case alwaysEnabledUnavailable
29+
30+
@available(DisabledDomain)
31+
case disabled
32+
33+
@available(DisabledDomain, unavailable)
34+
case disabledUnavailable
35+
36+
@available(DynamicDomain)
37+
case dynamic
38+
39+
@available(DynamicDomain, unavailable)
40+
case dynamicUnavailable
41+
}
42+
43+
// CHECK-LABEL: sil @$s4Test22testFullyCoveredSwitchyyAA4EnumOF : $@convention(thin) (Enum) -> () {
44+
// CHECK: switch_enum %0, case #Enum.alwaysAvailable!enumelt: {{bb[0-9]+}}, case #Enum.alwaysUnavailable!enumelt: {{bb[0-9]+}}, case #Enum.enabled!enumelt: {{bb[0-9]+}}, case #Enum.alwaysEnabled!enumelt: {{bb[0-9]+}}, case #Enum.disabledUnavailable!enumelt: {{bb[0-9]+}}, case #Enum.dynamic!enumelt: {{bb[0-9]+}}, case #Enum.dynamicUnavailable!enumelt: {{bb[0-9]+}}, default [[DEFAULTBB:bb[0-9]+]]
45+
// CHECK: [[DEFAULTBB]]:
46+
// CHECK-NEXT: integer_literal $Builtin.Int1, -1
47+
// CHECK-NEXT: cond_fail {{%.*}}, "unexpected enum value"
48+
// CHECK-NEXT: unreachable
49+
// CHECK: } // end sil function '$s4Test22testFullyCoveredSwitchyyAA4EnumOF'
50+
public func testFullyCoveredSwitch(_ e: Enum) {
51+
switch e {
52+
case .alwaysAvailable: ()
53+
case .alwaysUnavailable: ()
54+
case .enabled: ()
55+
case .enabledUnavailable: ()
56+
case .alwaysEnabled: ()
57+
case .alwaysEnabledUnavailable: ()
58+
case .disabled: ()
59+
case .disabledUnavailable: ()
60+
case .dynamic: ()
61+
case .dynamicUnavailable: ()
62+
}
63+
}

0 commit comments

Comments
 (0)