xref: /llvm-project/llvm/test/Transforms/JumpTableToSwitch/basic.ll (revision d26b43ff4f7396f79de4b099160262c750d6aba7)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
2; RUN: opt < %s -passes=jump-table-to-switch -verify-dom-info -S | FileCheck %s
3; RUN: opt < %s -passes=jump-table-to-switch -jump-table-to-switch-size-threshold=0 -verify-dom-info -S | FileCheck %s --check-prefix=THRESHOLD-0
4
5@func_array = constant [2 x ptr] [ptr @func0, ptr @func1]
6
7define i32 @func0() {
8  ret i32 1
9}
10
11define i32 @func1() {
12  ret i32 2
13}
14
15define i32 @function_with_jump_table(i32 %index) {
16; CHECK-LABEL: define i32 @function_with_jump_table(
17; CHECK-SAME: i32 [[INDEX:%.*]]) {
18; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds [2 x ptr], ptr @func_array, i32 0, i32 [[INDEX]]
19; CHECK-NEXT:    [[FUNC_PTR:%.*]] = load ptr, ptr [[GEP]], align 8
20; CHECK-NEXT:    switch i32 [[INDEX]], label [[DEFAULT_SWITCH_CASE_UNREACHABLE:%.*]] [
21; CHECK-NEXT:      i32 0, label [[CALL_0:%.*]]
22; CHECK-NEXT:      i32 1, label [[CALL_1:%.*]]
23; CHECK-NEXT:    ]
24; CHECK:       default.switch.case.unreachable:
25; CHECK-NEXT:    unreachable
26; CHECK:       call.0:
27; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @func0()
28; CHECK-NEXT:    br label [[DOTTAIL:%.*]]
29; CHECK:       call.1:
30; CHECK-NEXT:    [[TMP2:%.*]] = call i32 @func1()
31; CHECK-NEXT:    br label [[DOTTAIL]]
32; CHECK:       .tail:
33; CHECK-NEXT:    [[TMP3:%.*]] = phi i32 [ [[TMP1]], [[CALL_0]] ], [ [[TMP2]], [[CALL_1]] ]
34; CHECK-NEXT:    ret i32 [[TMP3]]
35;
36; THRESHOLD-0-LABEL: define i32 @function_with_jump_table(
37; THRESHOLD-0-SAME: i32 [[INDEX:%.*]]) {
38; THRESHOLD-0-NEXT:    [[GEP:%.*]] = getelementptr inbounds [2 x ptr], ptr @func_array, i32 0, i32 [[INDEX]]
39; THRESHOLD-0-NEXT:    [[FUNC_PTR:%.*]] = load ptr, ptr [[GEP]], align 8
40; THRESHOLD-0-NEXT:    [[RESULT:%.*]] = call i32 [[FUNC_PTR]]()
41; THRESHOLD-0-NEXT:    ret i32 [[RESULT]]
42;
43  %gep = getelementptr inbounds [2 x ptr], ptr @func_array, i32 0, i32 %index
44  %func_ptr = load ptr, ptr %gep
45  %result = call i32 %func_ptr()
46  ret i32 %result
47}
48
49define i32 @basic_block_splitted_twice(i32 %index) {
50; CHECK-LABEL: define i32 @basic_block_splitted_twice(
51; CHECK-SAME: i32 [[INDEX:%.*]]) {
52; CHECK-NEXT:    [[GEP1:%.*]] = getelementptr inbounds [2 x ptr], ptr @func_array, i32 0, i32 [[INDEX]]
53; CHECK-NEXT:    [[FUNC_PTR1:%.*]] = load ptr, ptr [[GEP1]], align 8
54; CHECK-NEXT:    switch i32 [[INDEX]], label [[DEFAULT_SWITCH_CASE_UNREACHABLE:%.*]] [
55; CHECK-NEXT:      i32 0, label [[CALL_0:%.*]]
56; CHECK-NEXT:      i32 1, label [[CALL_1:%.*]]
57; CHECK-NEXT:    ]
58; CHECK:       default.switch.case.unreachable:
59; CHECK-NEXT:    unreachable
60; CHECK:       call.0:
61; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @func0()
62; CHECK-NEXT:    br label [[DOTTAIL:%.*]]
63; CHECK:       call.1:
64; CHECK-NEXT:    [[TMP2:%.*]] = call i32 @func1()
65; CHECK-NEXT:    br label [[DOTTAIL]]
66; CHECK:       .tail:
67; CHECK-NEXT:    [[TMP3:%.*]] = phi i32 [ [[TMP1]], [[CALL_0]] ], [ [[TMP2]], [[CALL_1]] ]
68; CHECK-NEXT:    [[GEP2:%.*]] = getelementptr inbounds [2 x ptr], ptr @func_array, i32 0, i32 [[INDEX]]
69; CHECK-NEXT:    [[FUNC_PTR2:%.*]] = load ptr, ptr [[GEP2]], align 8
70; CHECK-NEXT:    switch i32 [[INDEX]], label [[DEFAULT_SWITCH_CASE_UNREACHABLE1:%.*]] [
71; CHECK-NEXT:      i32 0, label [[CALL_02:%.*]]
72; CHECK-NEXT:      i32 1, label [[CALL_13:%.*]]
73; CHECK-NEXT:    ]
74; CHECK:       default.switch.case.unreachable1:
75; CHECK-NEXT:    unreachable
76; CHECK:       call.02:
77; CHECK-NEXT:    [[TMP4:%.*]] = call i32 @func0()
78; CHECK-NEXT:    br label [[DOTTAIL_TAIL:%.*]]
79; CHECK:       call.13:
80; CHECK-NEXT:    [[TMP5:%.*]] = call i32 @func1()
81; CHECK-NEXT:    br label [[DOTTAIL_TAIL]]
82; CHECK:       .tail.tail:
83; CHECK-NEXT:    [[TMP6:%.*]] = phi i32 [ [[TMP4]], [[CALL_02]] ], [ [[TMP5]], [[CALL_13]] ]
84; CHECK-NEXT:    [[RESULT:%.*]] = add i32 [[TMP3]], [[TMP6]]
85; CHECK-NEXT:    ret i32 [[RESULT]]
86;
87; THRESHOLD-0-LABEL: define i32 @basic_block_splitted_twice(
88; THRESHOLD-0-SAME: i32 [[INDEX:%.*]]) {
89; THRESHOLD-0-NEXT:    [[GEP1:%.*]] = getelementptr inbounds [2 x ptr], ptr @func_array, i32 0, i32 [[INDEX]]
90; THRESHOLD-0-NEXT:    [[FUNC_PTR1:%.*]] = load ptr, ptr [[GEP1]], align 8
91; THRESHOLD-0-NEXT:    [[RESULT1:%.*]] = call i32 [[FUNC_PTR1]]()
92; THRESHOLD-0-NEXT:    [[GEP2:%.*]] = getelementptr inbounds [2 x ptr], ptr @func_array, i32 0, i32 [[INDEX]]
93; THRESHOLD-0-NEXT:    [[FUNC_PTR2:%.*]] = load ptr, ptr [[GEP2]], align 8
94; THRESHOLD-0-NEXT:    [[RESULT2:%.*]] = call i32 [[FUNC_PTR2]]()
95; THRESHOLD-0-NEXT:    [[RESULT:%.*]] = add i32 [[RESULT1]], [[RESULT2]]
96; THRESHOLD-0-NEXT:    ret i32 [[RESULT]]
97;
98  %gep1 = getelementptr inbounds [2 x ptr], ptr @func_array, i32 0, i32 %index
99  %func_ptr1 = load ptr, ptr %gep1
100  %result1 = call i32 %func_ptr1()
101  %gep2 = getelementptr inbounds [2 x ptr], ptr @func_array, i32 0, i32 %index
102  %func_ptr2 = load ptr, ptr %gep2
103  %result2 = call i32 %func_ptr2()
104  %result = add i32 %result1, %result2
105  ret i32 %result
106}
107
108define void @void_func0() {
109  ret void
110}
111
112define void @void_func1() {
113  ret void
114}
115
116@void_func_array = constant [2 x ptr] [ptr @void_func0, ptr @void_func1]
117
118define void @void_function_with_jump_table(i32 %index) {
119; CHECK-LABEL: define void @void_function_with_jump_table(
120; CHECK-SAME: i32 [[INDEX:%.*]]) {
121; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds [2 x ptr], ptr @void_func_array, i32 0, i32 [[INDEX]]
122; CHECK-NEXT:    [[FUNC_PTR:%.*]] = load ptr, ptr [[GEP]], align 8
123; CHECK-NEXT:    switch i32 [[INDEX]], label [[DEFAULT_SWITCH_CASE_UNREACHABLE:%.*]] [
124; CHECK-NEXT:      i32 0, label [[CALL_0:%.*]]
125; CHECK-NEXT:      i32 1, label [[CALL_1:%.*]]
126; CHECK-NEXT:    ]
127; CHECK:       default.switch.case.unreachable:
128; CHECK-NEXT:    unreachable
129; CHECK:       call.0:
130; CHECK-NEXT:    call void @void_func0()
131; CHECK-NEXT:    br label [[DOTTAIL:%.*]]
132; CHECK:       call.1:
133; CHECK-NEXT:    call void @void_func1()
134; CHECK-NEXT:    br label [[DOTTAIL]]
135; CHECK:       .tail:
136; CHECK-NEXT:    ret void
137;
138; THRESHOLD-0-LABEL: define void @void_function_with_jump_table(
139; THRESHOLD-0-SAME: i32 [[INDEX:%.*]]) {
140; THRESHOLD-0-NEXT:    [[GEP:%.*]] = getelementptr inbounds [2 x ptr], ptr @void_func_array, i32 0, i32 [[INDEX]]
141; THRESHOLD-0-NEXT:    [[FUNC_PTR:%.*]] = load ptr, ptr [[GEP]], align 8
142; THRESHOLD-0-NEXT:    call void [[FUNC_PTR]]()
143; THRESHOLD-0-NEXT:    ret void
144;
145  %gep = getelementptr inbounds [2 x ptr], ptr @void_func_array, i32 0, i32 %index
146  %func_ptr = load ptr, ptr %gep
147  call void %func_ptr()
148  ret void
149}
150
151define void @void_function_with_jump_table_and_call_site_attr(i32 %index) {
152; CHECK-LABEL: define void @void_function_with_jump_table_and_call_site_attr(
153; CHECK-SAME: i32 [[INDEX:%.*]]) {
154; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds [2 x ptr], ptr @void_func_array, i32 0, i32 [[INDEX]]
155; CHECK-NEXT:    [[FUNC_PTR:%.*]] = load ptr, ptr [[GEP]], align 8
156; CHECK-NEXT:    switch i32 [[INDEX]], label [[DEFAULT_SWITCH_CASE_UNREACHABLE:%.*]] [
157; CHECK-NEXT:      i32 0, label [[CALL_0:%.*]]
158; CHECK-NEXT:      i32 1, label [[CALL_1:%.*]]
159; CHECK-NEXT:    ]
160; CHECK:       default.switch.case.unreachable:
161; CHECK-NEXT:    unreachable
162; CHECK:       call.0:
163; CHECK-NEXT:    call void @void_func0() #[[ATTR0:[0-9]+]]
164; CHECK-NEXT:    br label [[DOTTAIL:%.*]]
165; CHECK:       call.1:
166; CHECK-NEXT:    call void @void_func1() #[[ATTR0]]
167; CHECK-NEXT:    br label [[DOTTAIL]]
168; CHECK:       .tail:
169; CHECK-NEXT:    ret void
170;
171; THRESHOLD-0-LABEL: define void @void_function_with_jump_table_and_call_site_attr(
172; THRESHOLD-0-SAME: i32 [[INDEX:%.*]]) {
173; THRESHOLD-0-NEXT:    [[GEP:%.*]] = getelementptr inbounds [2 x ptr], ptr @void_func_array, i32 0, i32 [[INDEX]]
174; THRESHOLD-0-NEXT:    [[FUNC_PTR:%.*]] = load ptr, ptr [[GEP]], align 8
175; THRESHOLD-0-NEXT:    call void [[FUNC_PTR]]() #[[ATTR0:[0-9]+]]
176; THRESHOLD-0-NEXT:    ret void
177;
178  %gep = getelementptr inbounds [2 x ptr], ptr @void_func_array, i32 0, i32 %index
179  %func_ptr = load ptr, ptr %gep
180  call void %func_ptr() nounwind
181  ret void
182}
183
184
185define i32 @func0_addrspace_42() addrspace(42) {
186  ret i32 1
187}
188
189define i32 @func1_addrspace_42() addrspace(42) {
190  ret i32 2
191}
192
193@func_array_addrspace_42 = addrspace(42) constant [2 x ptr addrspace(42)] [ptr addrspace(42) @func0_addrspace_42, ptr addrspace(42) @func1_addrspace_42]
194
195define i32 @function_with_jump_table_addrspace_42(i32 %index) addrspace(42) {
196; CHECK-LABEL: define i32 @function_with_jump_table_addrspace_42(
197; CHECK-SAME: i32 [[INDEX:%.*]]) addrspace(42) {
198; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds [2 x ptr addrspace(42)], ptr addrspace(42) @func_array_addrspace_42, i32 0, i32 [[INDEX]]
199; CHECK-NEXT:    [[FUNC_PTR:%.*]] = load ptr addrspace(42), ptr addrspace(42) [[GEP]], align 8
200; CHECK-NEXT:    switch i32 [[INDEX]], label [[DEFAULT_SWITCH_CASE_UNREACHABLE:%.*]] [
201; CHECK-NEXT:      i32 0, label [[CALL_0:%.*]]
202; CHECK-NEXT:      i32 1, label [[CALL_1:%.*]]
203; CHECK-NEXT:    ]
204; CHECK:       default.switch.case.unreachable:
205; CHECK-NEXT:    unreachable
206; CHECK:       call.0:
207; CHECK-NEXT:    [[TMP1:%.*]] = call addrspace(42) i32 @func0_addrspace_42()
208; CHECK-NEXT:    br label [[DOTTAIL:%.*]]
209; CHECK:       call.1:
210; CHECK-NEXT:    [[TMP2:%.*]] = call addrspace(42) i32 @func1_addrspace_42()
211; CHECK-NEXT:    br label [[DOTTAIL]]
212; CHECK:       .tail:
213; CHECK-NEXT:    [[TMP3:%.*]] = phi i32 [ [[TMP1]], [[CALL_0]] ], [ [[TMP2]], [[CALL_1]] ]
214; CHECK-NEXT:    ret i32 [[TMP3]]
215;
216; THRESHOLD-0-LABEL: define i32 @function_with_jump_table_addrspace_42(
217; THRESHOLD-0-SAME: i32 [[INDEX:%.*]]) addrspace(42) {
218; THRESHOLD-0-NEXT:    [[GEP:%.*]] = getelementptr inbounds [2 x ptr addrspace(42)], ptr addrspace(42) @func_array_addrspace_42, i32 0, i32 [[INDEX]]
219; THRESHOLD-0-NEXT:    [[FUNC_PTR:%.*]] = load ptr addrspace(42), ptr addrspace(42) [[GEP]], align 8
220; THRESHOLD-0-NEXT:    [[RESULT:%.*]] = call addrspace(42) i32 [[FUNC_PTR]]()
221; THRESHOLD-0-NEXT:    ret i32 [[RESULT]]
222;
223  %gep = getelementptr inbounds [2 x ptr addrspace(42)], ptr addrspace(42) @func_array_addrspace_42, i32 0, i32 %index
224  %func_ptr = load ptr addrspace(42), ptr addrspace(42) %gep, align 8
225  %result = call addrspace(42) i32 %func_ptr()
226  ret i32 %result
227}
228
229