Skip to content

Commit b796108

Browse files
authored
Merge pull request #4747 from shajrawi/swift-3-enum-unique-values
[SILOptimizer] Ignore duplicate conditions when optimizing switch statement
2 parents efa6dd9 + c4e2310 commit b796108

File tree

2 files changed

+108
-1
lines changed

2 files changed

+108
-1
lines changed

lib/SILOptimizer/Transforms/SimplifyCFG.cpp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3190,6 +3190,7 @@ bool simplifyToSelectValue(SILBasicBlock *MergeBlock, unsigned ArgNum,
31903190
}
31913191

31923192
SmallVector<std::pair<SILValue, SILValue>, 8> Cases;
3193+
llvm::SmallDenseMap<SILValue, SILValue> CaseLiteralsToResultMap;
31933194
SILValue defaultResult;
31943195

31953196
// The block of the first input value compare. It dominates all other blocks
@@ -3202,7 +3203,23 @@ bool simplifyToSelectValue(SILBasicBlock *MergeBlock, unsigned ArgNum,
32023203
auto *BrInst = cast<CondBranchInst>(CaseInfo.CmpOrDefault->getTerminator());
32033204
if (FoundCmpBlocks.count(BrInst->getFalseBB()) != 1)
32043205
return false;
3205-
Cases.push_back({CaseInfo.Literal, CaseInfo.Result});
3206+
// Ignore duplicate cases
3207+
if (CaseLiteralsToResultMap.find(CaseInfo.Literal) ==
3208+
CaseLiteralsToResultMap.end()) {
3209+
CaseLiteralsToResultMap.insert({CaseInfo.Literal, CaseInfo.Result});
3210+
Cases.push_back({CaseInfo.Literal, CaseInfo.Result});
3211+
} else {
3212+
// Check if the result value matches
3213+
EnumInst *PrevResult =
3214+
dyn_cast<EnumInst>(CaseLiteralsToResultMap[CaseInfo.Literal]);
3215+
assert(PrevResult && "Prev. case result is not an EnumInst");
3216+
EnumInst *CurrResult = dyn_cast<EnumInst>(CaseInfo.Result);
3217+
assert(CurrResult && "Curr. case result is not an EnumInst");
3218+
if (PrevResult->getElement() != CurrResult->getElement()) {
3219+
// result value does not match - bail
3220+
return false;
3221+
}
3222+
}
32063223
SILBasicBlock *Pred = CaseInfo.CmpOrDefault->getSinglePredecessor();
32073224
if (!Pred || FoundCmpBlocks.count(Pred) == 0) {
32083225
// There may be only a single block whose predecessor we didn't see. And
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
// RUN: %target-sil-opt -enable-sil-verify-all %s -simplify-cfg | %FileCheck %s
2+
3+
sil_stage canonical
4+
5+
import Builtin
6+
import Swift
7+
8+
enum DupCaseEnum {
9+
case firstCase
10+
case secondCase
11+
}
12+
13+
// CHECK-LABEL: sil @performSwitch : $@convention(thin) (Int64, @thin DupCaseEnum.Type) -> DupCaseEnum {
14+
// CHECK: bb0(%0 : $Int64, %1 : $@thin DupCaseEnum.Type):
15+
// CHECK: select_value
16+
// CHECK: br bb1
17+
// CHECK: bb1:
18+
// CHECK: return
19+
sil @performSwitch : $@convention(thin) (Int64, @thin DupCaseEnum.Type) -> DupCaseEnum {
20+
// %0 // users: %9, %5, %3, %2
21+
bb0(%0 : $Int64, %1 : $@thin DupCaseEnum.Type):
22+
%4 = integer_literal $Builtin.Int64, 0 // user: %6
23+
%5 = struct_extract %0 : $Int64, #Int64._value // user: %6
24+
%6 = builtin "cmp_eq_Int64"(%4 : $Builtin.Int64, %5 : $Builtin.Int64) : $Builtin.Int1 // users: %10, %7
25+
cond_br %6, bb6, bb1 // id: %7
26+
27+
bb1: // Preds: bb0
28+
br bb2 // id: %8
29+
30+
bb2: // Preds: bb1
31+
cond_br %6, bb5, bb3 // id: %10
32+
33+
bb3: // Preds: bb2
34+
br bb4 // id: %11
35+
36+
bb4: // Preds: bb3
37+
%12 = enum $DupCaseEnum, #DupCaseEnum.secondCase!enumelt // user: %13
38+
br bb7(%12 : $DupCaseEnum) // id: %13
39+
40+
bb5: // Preds: bb2
41+
%14 = enum $DupCaseEnum, #DupCaseEnum.firstCase!enumelt // user: %15
42+
br bb7(%14 : $DupCaseEnum) // id: %15
43+
44+
bb6: // Preds: bb0
45+
%16 = enum $DupCaseEnum, #DupCaseEnum.firstCase!enumelt // user: %17
46+
br bb7(%16 : $DupCaseEnum) // id: %17
47+
48+
// %18 // user: %19
49+
bb7(%18 : $DupCaseEnum): // Preds: bb6 bb5 bb4
50+
return %18 : $DupCaseEnum // id: %19
51+
}
52+
53+
// CHECK-LABEL: sil @performSwitch_bail_out : $@convention(thin) (Int64, @thin DupCaseEnum.Type) -> DupCaseEnum {
54+
// CHECK: bb0(%0 : $Int64, %1 : $@thin DupCaseEnum.Type):
55+
// CHECK-NOT: select_value
56+
// CHECK-NOT: br bb1
57+
// CHECK: cond_br
58+
sil @performSwitch_bail_out : $@convention(thin) (Int64, @thin DupCaseEnum.Type) -> DupCaseEnum {
59+
// %0 // users: %9, %5, %3, %2
60+
bb0(%0 : $Int64, %1 : $@thin DupCaseEnum.Type):
61+
%4 = integer_literal $Builtin.Int64, 0 // user: %6
62+
%5 = struct_extract %0 : $Int64, #Int64._value // user: %6
63+
%6 = builtin "cmp_eq_Int64"(%4 : $Builtin.Int64, %5 : $Builtin.Int64) : $Builtin.Int1 // users: %10, %7
64+
cond_br %6, bb6, bb1 // id: %7
65+
66+
bb1: // Preds: bb0
67+
br bb2 // id: %8
68+
69+
bb2: // Preds: bb1
70+
cond_br %6, bb5, bb3 // id: %10
71+
72+
bb3: // Preds: bb2
73+
br bb4 // id: %11
74+
75+
bb4: // Preds: bb3
76+
%12 = enum $DupCaseEnum, #DupCaseEnum.secondCase!enumelt // user: %13
77+
br bb7(%12 : $DupCaseEnum) // id: %13
78+
79+
bb5: // Preds: bb2
80+
%14 = enum $DupCaseEnum, #DupCaseEnum.secondCase!enumelt // user: %15
81+
br bb7(%14 : $DupCaseEnum) // id: %15
82+
83+
bb6: // Preds: bb0
84+
%16 = enum $DupCaseEnum, #DupCaseEnum.firstCase!enumelt // user: %17
85+
br bb7(%16 : $DupCaseEnum) // id: %17
86+
87+
// %18 // user: %19
88+
bb7(%18 : $DupCaseEnum): // Preds: bb6 bb5 bb4
89+
return %18 : $DupCaseEnum // id: %19
90+
}

0 commit comments

Comments
 (0)