xref: /llvm-project/llvm/test/Transforms/SimpleLoopUnswitch/trivial-unswitch-logical-and-or.ll (revision 2f79f5438cd6f4fa0fdc32458911c2d163f917c0)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt -passes='loop-mssa(simple-loop-unswitch)' -S %s | FileCheck %s
3
4; Test cases for trivial unswitching with selects that matches both a logical and & or.
5
6declare void @some_func()
7
8define void @test_select_logical_and_or_with_and_1(i1 noundef %cond1, i1 noundef %cond2) {
9; CHECK-LABEL: @test_select_logical_and_or_with_and_1(
10; CHECK-NEXT:  entry:
11; CHECK-NEXT:    br label [[LOOP_HEADER:%.*]]
12; CHECK:       loop.header:
13; CHECK-NEXT:    [[COND_AND1:%.*]] = and i1 [[COND2:%.*]], [[COND1:%.*]]
14; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND_AND1]], i1 true, i1 false
15; CHECK-NEXT:    br i1 [[SEL]], label [[EXIT:%.*]], label [[LOOP_LATCH:%.*]]
16; CHECK:       loop.latch:
17; CHECK-NEXT:    call void @some_func()
18; CHECK-NEXT:    br label [[LOOP_HEADER]]
19; CHECK:       exit:
20; CHECK-NEXT:    ret void
21;
22entry:
23  br label %loop.header
24
25loop.header:
26  %cond_and1 = and i1 %cond2, %cond1
27  %sel = select i1 %cond_and1, i1 true, i1 false
28  br i1 %sel, label %exit, label %loop.latch
29
30loop.latch:
31  call void @some_func()
32  br label %loop.header
33
34exit:
35  ret void
36}
37
38define void @test_select_logical_and_or_with_and_2(i1 noundef %cond1, i1 noundef %cond2) {
39; CHECK-LABEL: @test_select_logical_and_or_with_and_2(
40; CHECK-NEXT:  entry:
41; CHECK-NEXT:    [[TMP0:%.*]] = and i1 [[COND2:%.*]], [[COND1:%.*]]
42; CHECK-NEXT:    br i1 [[TMP0]], label [[ENTRY_SPLIT:%.*]], label [[EXIT_SPLIT:%.*]]
43; CHECK:       entry.split:
44; CHECK-NEXT:    br label [[LOOP_HEADER:%.*]]
45; CHECK:       loop.header:
46; CHECK-NEXT:    [[COND_AND1:%.*]] = and i1 true, true
47; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND_AND1]], i1 true, i1 false
48; CHECK-NEXT:    br i1 [[SEL]], label [[LOOP_LATCH:%.*]], label [[EXIT:%.*]]
49; CHECK:       loop.latch:
50; CHECK-NEXT:    call void @some_func()
51; CHECK-NEXT:    br label [[LOOP_HEADER]]
52; CHECK:       exit:
53; CHECK-NEXT:    br label [[EXIT_SPLIT]]
54; CHECK:       exit.split:
55; CHECK-NEXT:    ret void
56;
57entry:
58  br label %loop.header
59
60loop.header:
61  %cond_and1 = and i1 %cond2, %cond1
62  %sel = select i1 %cond_and1, i1 true, i1 false
63  br i1 %sel, label %loop.latch, label %exit
64
65loop.latch:
66  call void @some_func()
67  br label %loop.header
68
69exit:
70  ret void
71}
72
73define void @test_select_logical_and_or_with_or_1(i1 noundef %cond1, i1 noundef %cond2) {
74; CHECK-LABEL: @test_select_logical_and_or_with_or_1(
75; CHECK-NEXT:  entry:
76; CHECK-NEXT:    [[TMP0:%.*]] = or i1 [[COND2:%.*]], [[COND1:%.*]]
77; CHECK-NEXT:    br i1 [[TMP0]], label [[EXIT_SPLIT:%.*]], label [[ENTRY_SPLIT:%.*]]
78; CHECK:       entry.split:
79; CHECK-NEXT:    br label [[LOOP_HEADER:%.*]]
80; CHECK:       loop.header:
81; CHECK-NEXT:    [[COND_AND1:%.*]] = or i1 false, false
82; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND_AND1]], i1 true, i1 false
83; CHECK-NEXT:    br i1 [[SEL]], label [[EXIT:%.*]], label [[LOOP_LATCH:%.*]]
84; CHECK:       loop.latch:
85; CHECK-NEXT:    call void @some_func()
86; CHECK-NEXT:    br label [[LOOP_HEADER]]
87; CHECK:       exit:
88; CHECK-NEXT:    br label [[EXIT_SPLIT]]
89; CHECK:       exit.split:
90; CHECK-NEXT:    ret void
91;
92entry:
93  br label %loop.header
94
95loop.header:
96  %cond_and1 = or i1 %cond2, %cond1
97  %sel = select i1 %cond_and1, i1 true, i1 false
98  br i1 %sel, label %exit, label %loop.latch
99
100loop.latch:
101  call void @some_func()
102  br label %loop.header
103
104exit:
105  ret void
106}
107
108
109define void @test_select_logical_and_or_with_or_2(i1 noundef %cond1, i1 noundef %cond2) {
110; CHECK-LABEL: @test_select_logical_and_or_with_or_2(
111; CHECK-NEXT:  entry:
112; CHECK-NEXT:    br label [[LOOP_HEADER:%.*]]
113; CHECK:       loop.header:
114; CHECK-NEXT:    [[COND_AND1:%.*]] = or i1 [[COND2:%.*]], [[COND1:%.*]]
115; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND_AND1]], i1 true, i1 false
116; CHECK-NEXT:    br i1 [[SEL]], label [[LOOP_LATCH:%.*]], label [[EXIT:%.*]]
117; CHECK:       loop.latch:
118; CHECK-NEXT:    call void @some_func()
119; CHECK-NEXT:    br label [[LOOP_HEADER]]
120; CHECK:       exit:
121; CHECK-NEXT:    ret void
122;
123entry:
124  br label %loop.header
125
126loop.header:
127  %cond_and1 = or i1 %cond2, %cond1
128  %sel = select i1 %cond_and1, i1 true, i1 false
129  br i1 %sel, label %loop.latch, label %exit
130
131loop.latch:
132  call void @some_func()
133  br label %loop.header
134
135exit:
136  ret void
137}
138
139; Check that loop unswitch looks through a combination of or and select instructions.
140define i32 @test_partial_condition_unswitch_or_select(ptr %var, i1 %cond1, i1 %cond2, i1 %cond3, i1 %cond4, i1 %cond5, i1 %cond6) {
141; CHECK-LABEL: @test_partial_condition_unswitch_or_select(
142; CHECK-NEXT:  entry:
143; CHECK-NEXT:    [[COND4_FR:%.*]] = freeze i1 [[COND4:%.*]]
144; CHECK-NEXT:    [[COND2_FR:%.*]] = freeze i1 [[COND2:%.*]]
145; CHECK-NEXT:    [[COND3_FR:%.*]] = freeze i1 [[COND3:%.*]]
146; CHECK-NEXT:    [[COND1_FR:%.*]] = freeze i1 [[COND1:%.*]]
147; CHECK-NEXT:    [[TMP0:%.*]] = or i1 [[COND4_FR]], [[COND2_FR]]
148; CHECK-NEXT:    [[TMP1:%.*]] = or i1 [[TMP0]], [[COND3_FR]]
149; CHECK-NEXT:    [[TMP2:%.*]] = or i1 [[TMP1]], [[COND1_FR]]
150; CHECK-NEXT:    br i1 [[TMP2]], label [[LOOP_EXIT_SPLIT:%.*]], label [[ENTRY_SPLIT:%.*]]
151; CHECK:       entry.split:
152; CHECK-NEXT:    br label [[LOOP_BEGIN:%.*]]
153; CHECK:       loop_begin:
154; CHECK-NEXT:    [[VAR_VAL:%.*]] = load i32, ptr [[VAR:%.*]], align 4
155; CHECK-NEXT:    [[VAR_COND:%.*]] = trunc i32 [[VAR_VAL]] to i1
156; CHECK-NEXT:    [[COND_OR1:%.*]] = or i1 [[VAR_COND]], false
157; CHECK-NEXT:    [[COND_OR2:%.*]] = or i1 false, false
158; CHECK-NEXT:    [[COND_OR3:%.*]] = or i1 [[COND_OR1]], [[COND_OR2]]
159; CHECK-NEXT:    [[COND_XOR1:%.*]] = xor i1 [[COND5:%.*]], [[VAR_COND]]
160; CHECK-NEXT:    [[COND_AND1:%.*]] = and i1 [[COND6:%.*]], [[VAR_COND]]
161; CHECK-NEXT:    [[COND_OR4:%.*]] = or i1 [[COND_XOR1]], [[COND_AND1]]
162; CHECK-NEXT:    [[COND_OR5:%.*]] = select i1 [[COND_OR3]], i1 true, i1 [[COND_OR4]]
163; CHECK-NEXT:    [[COND_OR6:%.*]] = select i1 [[COND_OR5]], i1 true, i1 false
164; CHECK-NEXT:    br i1 [[COND_OR6]], label [[LOOP_EXIT:%.*]], label [[DO_SOMETHING:%.*]]
165; CHECK:       do_something:
166; CHECK-NEXT:    call void @some_func() #[[ATTR0:[0-9]+]]
167; CHECK-NEXT:    br label [[LOOP_BEGIN]]
168; CHECK:       loop_exit:
169; CHECK-NEXT:    br label [[LOOP_EXIT_SPLIT]]
170; CHECK:       loop_exit.split:
171; CHECK-NEXT:    ret i32 0
172;
173entry:
174  br label %loop_begin
175
176loop_begin:
177  %var_val = load i32, ptr %var
178  %var_cond = trunc i32 %var_val to i1
179  %cond_or1 = or i1 %var_cond, %cond1
180  %cond_or2 = or i1 %cond2, %cond3
181  %cond_or3 = or i1 %cond_or1, %cond_or2
182  %cond_xor1 = xor i1 %cond5, %var_cond
183  %cond_and1 = and i1 %cond6, %var_cond
184  %cond_or4 = or i1 %cond_xor1, %cond_and1
185  %cond_or5 = select i1 %cond_or3, i1 true, i1 %cond_or4
186  %cond_or6 = select i1 %cond_or5, i1 true, i1 %cond4
187  br i1 %cond_or6, label %loop_exit, label %do_something
188
189do_something:
190  call void @some_func() noreturn nounwind
191  br label %loop_begin
192
193loop_exit:
194  ret i32 0
195}
196
197; Same as test_partial_condition_unswitch_or_select, but with arguments marked
198; as noundef.
199define i32 @test_partial_condition_unswitch_or_select_noundef(ptr noundef %var, i1 noundef %cond1, i1 noundef %cond2, i1 noundef %cond3, i1 noundef %cond4, i1 noundef %cond5, i1 noundef %cond6) {
200; CHECK-LABEL: @test_partial_condition_unswitch_or_select_noundef(
201; CHECK-NEXT:  entry:
202; CHECK-NEXT:    [[TMP0:%.*]] = or i1 [[COND4:%.*]], [[COND2:%.*]]
203; CHECK-NEXT:    [[TMP1:%.*]] = or i1 [[TMP0]], [[COND3:%.*]]
204; CHECK-NEXT:    [[TMP2:%.*]] = or i1 [[TMP1]], [[COND1:%.*]]
205; CHECK-NEXT:    br i1 [[TMP2]], label [[LOOP_EXIT_SPLIT:%.*]], label [[ENTRY_SPLIT:%.*]]
206; CHECK:       entry.split:
207; CHECK-NEXT:    br label [[LOOP_BEGIN:%.*]]
208; CHECK:       loop_begin:
209; CHECK-NEXT:    [[VAR_VAL:%.*]] = load i32, ptr [[VAR:%.*]], align 4
210; CHECK-NEXT:    [[VAR_COND:%.*]] = trunc i32 [[VAR_VAL]] to i1
211; CHECK-NEXT:    [[COND_OR1:%.*]] = or i1 [[VAR_COND]], false
212; CHECK-NEXT:    [[COND_OR2:%.*]] = or i1 false, false
213; CHECK-NEXT:    [[COND_OR3:%.*]] = or i1 [[COND_OR1]], [[COND_OR2]]
214; CHECK-NEXT:    [[COND_XOR1:%.*]] = xor i1 [[COND5:%.*]], [[VAR_COND]]
215; CHECK-NEXT:    [[COND_AND1:%.*]] = and i1 [[COND6:%.*]], [[VAR_COND]]
216; CHECK-NEXT:    [[COND_OR4:%.*]] = or i1 [[COND_XOR1]], [[COND_AND1]]
217; CHECK-NEXT:    [[COND_OR5:%.*]] = select i1 [[COND_OR3]], i1 true, i1 [[COND_OR4]]
218; CHECK-NEXT:    [[COND_OR6:%.*]] = select i1 [[COND_OR5]], i1 true, i1 false
219; CHECK-NEXT:    br i1 [[COND_OR6]], label [[LOOP_EXIT:%.*]], label [[DO_SOMETHING:%.*]]
220; CHECK:       do_something:
221; CHECK-NEXT:    call void @some_func() #[[ATTR0]]
222; CHECK-NEXT:    br label [[LOOP_BEGIN]]
223; CHECK:       loop_exit:
224; CHECK-NEXT:    br label [[LOOP_EXIT_SPLIT]]
225; CHECK:       loop_exit.split:
226; CHECK-NEXT:    ret i32 0
227;
228entry:
229  br label %loop_begin
230
231loop_begin:
232  %var_val = load i32, ptr %var
233  %var_cond = trunc i32 %var_val to i1
234  %cond_or1 = or i1 %var_cond, %cond1
235  %cond_or2 = or i1 %cond2, %cond3
236  %cond_or3 = or i1 %cond_or1, %cond_or2
237  %cond_xor1 = xor i1 %cond5, %var_cond
238  %cond_and1 = and i1 %cond6, %var_cond
239  %cond_or4 = or i1 %cond_xor1, %cond_and1
240  %cond_or5 = select i1 %cond_or3, i1 true, i1 %cond_or4
241  %cond_or6 = select i1 %cond_or5, i1 true, i1 %cond4
242  br i1 %cond_or6, label %loop_exit, label %do_something
243
244do_something:
245  call void @some_func() noreturn nounwind
246  br label %loop_begin
247
248loop_exit:
249  ret i32 0
250}
251
252; Test case for PR55526.
253define void @test_pr55526(i16 %a) {
254; CHECK-LABEL: @test_pr55526(
255; CHECK-NEXT:  entry:
256; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp ne i16 [[A:%.*]], 0
257; CHECK-NEXT:    br i1 [[TOBOOL]], label [[ENTRY_SPLIT:%.*]], label [[EXIT:%.*]]
258; CHECK:       entry.split:
259; CHECK-NEXT:    br label [[LOOP:%.*]]
260; CHECK:       loop:
261; CHECK-NEXT:    [[SEL:%.*]] = select i1 true, i1 true, i1 false
262; CHECK-NEXT:    br label [[LOOP]]
263; CHECK:       exit:
264; CHECK-NEXT:    ret void
265;
266entry:
267  %tobool = icmp ne i16 %a, 0
268  br label %loop
269
270loop:
271  %sel = select i1 %tobool, i1 true, i1 false
272  br i1 %sel, label %loop, label %exit
273
274exit:
275  ret void
276}
277