Skip to content

Commit 94b6e51

Browse files
committed
Optimizer: add simplification for switch_enum
Replace ``` %1 = enum $E, #someCase, %payload switch_enum %1, case #someCase: bb1, ... bb1(%payloadArgument): ``` -> ``` br bb1(%payload) bb1(%payloadArgument): ```
1 parent 680c737 commit 94b6e51

File tree

3 files changed

+217
-0
lines changed

3 files changed

+217
-0
lines changed

SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ swift_compiler_sources(Optimizer
2828
SimplifyRetainReleaseValue.swift
2929
SimplifyStrongRetainRelease.swift
3030
SimplifyStructExtract.swift
31+
SimplifySwitchEnum.swift
3132
SimplifyTupleExtract.swift
3233
SimplifyUncheckedEnumData.swift
3334
SimplifyValueToBridgeObject.swift)
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
//===--- SimplifySwitchEnum.swift -----------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import SIL
14+
15+
// Removes an `enum` - `switch_enum` pair:
16+
// ```
17+
// %1 = enum $E, #someCase, %payload
18+
// switch_enum %1, case #someCase: bb1, ...
19+
// bb1(%payloadArgument):
20+
// ```
21+
// ->
22+
// ```
23+
// br bb1(%payload)
24+
// bb1(%payloadArgument):
25+
// ```
26+
//
27+
// Other case blocks of the switch_enum become dead.
28+
//
29+
extension SwitchEnumInst : OnoneSimplifyable {
30+
func simplify(_ context: SimplifyContext) {
31+
guard let enumInst = enumOp as? EnumInst,
32+
let caseBlock = getUniqueSuccessor(forCaseIndex: enumInst.caseIndex) else
33+
{
34+
return
35+
}
36+
37+
let singleUse = context.preserveDebugInfo ? enumInst.uses.singleUse : enumInst.uses.ignoreDebugUses.singleUse
38+
let canEraseEnumInst = singleUse?.instruction == self
39+
40+
if !canEraseEnumInst && parentFunction.hasOwnership && enumInst.ownership == .owned {
41+
// We cannot add more uses to the `enum` instruction without inserting a copy.
42+
return
43+
}
44+
45+
let builder = Builder(before: self, context)
46+
switch caseBlock.arguments.count {
47+
case 0:
48+
precondition(enumInst.payload == nil || !parentFunction.hasOwnership,
49+
"missing payload argument in switch_enum case block")
50+
builder.createBranch(to: caseBlock)
51+
case 1:
52+
builder.createBranch(to: caseBlock, arguments: [enumInst.payload!])
53+
default:
54+
fatalError("case block of switch_enum cannot have more than 1 argument")
55+
}
56+
context.erase(instruction: self)
57+
58+
if canEraseEnumInst {
59+
context.erase(instructionIncludingDebugUses: enumInst)
60+
}
61+
}
62+
}
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
// RUN: %target-sil-opt -enable-sil-verify-all %s -onone-simplification -simplify-instruction=switch_enum | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ONONE
2+
// RUN: %target-sil-opt -enable-sil-verify-all %s -simplification -simplify-instruction=switch_enum | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-O
3+
4+
// REQUIRES: swift_in_compiler
5+
6+
import Swift
7+
import Builtin
8+
9+
enum E {
10+
case A
11+
case B(String)
12+
case C(Int)
13+
}
14+
15+
// CHECK-LABEL: sil @test_simple :
16+
// CHECK: bb0(%0 : $String):
17+
// CHECK-NEXT: br bb1(%0 : $String)
18+
// CHECK: bb1(%2 : $String):
19+
// CHECK-NEXT: return %2 : $String
20+
// CHECK-NOT: bb2
21+
// CHECK: } // end sil function 'test_simple'
22+
sil @test_simple : $@convention(thin) (@owned String) -> @owned String {
23+
bb0(%0 : $String):
24+
%1 = enum $E, #E.B!enumelt, %0 : $String
25+
switch_enum %1 : $E, case #E.B!enumelt: bb1, default bb2
26+
27+
bb1(%2 : $String):
28+
return %2 : $String
29+
30+
bb2:
31+
unreachable
32+
}
33+
34+
// CHECK-LABEL: sil @no_payload_argument :
35+
// CHECK: bb0(%0 : $String):
36+
// CHECK-NEXT: br bb1
37+
// CHECK: bb1:
38+
// CHECK-NEXT: tuple
39+
// CHECK-NEXT: return
40+
// CHECK-NOT: bb2
41+
// CHECK: } // end sil function 'no_payload_argument'
42+
sil @no_payload_argument : $@convention(thin) (@guaranteed String) -> () {
43+
bb0(%0 : $String):
44+
%1 = enum $E, #E.B!enumelt, %0 : $String
45+
switch_enum %1 : $E, case #E.B!enumelt: bb1, default bb2
46+
47+
bb1:
48+
%2 = tuple ()
49+
return %2 : $()
50+
51+
bb2:
52+
unreachable
53+
}
54+
55+
// CHECK-LABEL: sil [ossa] @owned_ossa :
56+
// CHECK: bb0(%0 : @owned $String):
57+
// CHECK-NEXT: br bb1(%0 : $String)
58+
// CHECK: bb1(%2 : @owned $String):
59+
// CHECK-NEXT: return %2 : $String
60+
// CHECK-NOT: bb2
61+
// CHECK: } // end sil function 'owned_ossa'
62+
sil [ossa] @owned_ossa : $@convention(thin) (@owned String) -> @owned String {
63+
bb0(%0 : @owned $String):
64+
%1 = enum $E, #E.B!enumelt, %0 : $String
65+
switch_enum %1 : $E, case #E.B!enumelt: bb1, default bb2
66+
67+
bb1(%2 : @owned $String):
68+
return %2 : $String
69+
70+
bb2(%4 : @owned $E):
71+
unreachable
72+
}
73+
74+
// CHECK-LABEL: sil [ossa] @guaranteed_ossa :
75+
// CHECK: bb0(%0 : @guaranteed $String):
76+
// CHECK-NEXT: br bb1(%0 : $String)
77+
// CHECK: bb1(%2 : @guaranteed $String):
78+
// CHECK-NEXT: %3 = copy_value %2
79+
// CHECK-NEXT: return %3 : $String
80+
// CHECK-NOT: bb2
81+
// CHECK: } // end sil function 'guaranteed_ossa'
82+
sil [ossa] @guaranteed_ossa : $@convention(thin) (@guaranteed String) -> @owned String {
83+
bb0(%0 : @guaranteed $String):
84+
%1 = enum $E, #E.B!enumelt, %0 : $String
85+
switch_enum %1 : $E, case #E.B!enumelt: bb1, default bb2
86+
87+
bb1(%2 : @guaranteed $String):
88+
%3 = copy_value %2 : $String
89+
return %3 : $String
90+
91+
bb2(%4 : @guaranteed $E):
92+
unreachable
93+
}
94+
95+
// CHECK-LABEL: sil [ossa] @owned_with_additional_uses :
96+
// CHECK: switch_enum
97+
// CHECK: } // end sil function 'owned_with_additional_uses'
98+
sil [ossa] @owned_with_additional_uses : $@convention(thin) (@owned String) -> @owned String {
99+
bb0(%0 : @owned $String):
100+
%1 = enum $E, #E.B!enumelt, %0 : $String
101+
%2 = begin_borrow %1 : $E
102+
end_borrow %2 : $E
103+
switch_enum %1 : $E, case #E.B!enumelt: bb1, default bb2
104+
105+
bb1(%5 : @owned $String):
106+
return %5 : $String
107+
108+
bb2(%7 : @owned $E):
109+
unreachable
110+
}
111+
112+
// CHECK-LABEL: sil [ossa] @guaranteed_with_additional_uses :
113+
// CHECK: enum
114+
// CHECK-NEXT: begin_borrow
115+
// CHECK-NEXT: end_borrow
116+
// CHECK-NEXT: br bb1(%0 : $String)
117+
// CHECK: bb1([[A:%.*]] : @guaranteed $String):
118+
// CHECK-NEXT: [[C:%.*]] = copy_value [[A]]
119+
// CHECK-NEXT: return [[C]] : $String
120+
// CHECK-NOT: bb2
121+
// CHECK: } // end sil function 'guaranteed_with_additional_uses'
122+
sil [ossa] @guaranteed_with_additional_uses : $@convention(thin) (@guaranteed String) -> @owned String {
123+
bb0(%0 : @guaranteed $String):
124+
%1 = enum $E, #E.B!enumelt, %0 : $String
125+
%2 = begin_borrow %1 : $E
126+
end_borrow %2 : $E
127+
switch_enum %1 : $E, case #E.B!enumelt: bb1, default bb2
128+
129+
bb1(%5 : @guaranteed $String):
130+
%6 = copy_value %5 : $String
131+
return %6 : $String
132+
133+
bb2(%7 : @guaranteed $E):
134+
unreachable
135+
}
136+
137+
// CHECK-LABEL: sil [ossa] @owned_with_debug_uses :
138+
// CHECK: bb0(%0 : @owned $String):
139+
// CHECK-O: br bb1(%0 : $String)
140+
// CHECK-ONONE: switch_enum
141+
// CHECK: } // end sil function 'owned_with_debug_uses'
142+
sil [ossa] @owned_with_debug_uses : $@convention(thin) (@owned String) -> @owned String {
143+
bb0(%0 : @owned $String):
144+
%1 = enum $E, #E.B!enumelt, %0 : $String
145+
debug_value %1 : $E, let, name "e"
146+
switch_enum %1 : $E, case #E.B!enumelt: bb1, default bb2
147+
148+
bb1(%2 : @owned $String):
149+
return %2 : $String
150+
151+
bb2(%4 : @owned $E):
152+
unreachable
153+
}
154+

0 commit comments

Comments
 (0)