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