Skip to content

Commit 51be092

Browse files
committed
[SimpleLoopUnswitch] Add trivial unswitching tests with selects.
Add tests with selects that match both logical AND and logical OR. Note that some of the tests get miscompiled at the moment. Also moves a related test to the newly added test file.
1 parent 4059770 commit 51be092

File tree

2 files changed

+264
-57
lines changed

2 files changed

+264
-57
lines changed
Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
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+
6+
declare void @some_func()
7+
8+
define 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+
;
27+
entry:
28+
br label %loop.header
29+
30+
loop.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+
35+
loop.latch:
36+
call void @some_func()
37+
br label %loop.header
38+
39+
exit:
40+
ret void
41+
}
42+
43+
define 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+
;
62+
entry:
63+
br label %loop.header
64+
65+
loop.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+
70+
loop.latch:
71+
call void @some_func()
72+
br label %loop.header
73+
74+
exit:
75+
ret void
76+
}
77+
78+
define 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+
;
97+
entry:
98+
br label %loop.header
99+
100+
loop.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+
105+
loop.latch:
106+
call void @some_func()
107+
br label %loop.header
108+
109+
exit:
110+
ret void
111+
}
112+
113+
114+
define 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+
;
133+
entry:
134+
br label %loop.header
135+
136+
loop.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+
141+
loop.latch:
142+
call void @some_func()
143+
br label %loop.header
144+
145+
exit:
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.
152+
define 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: [[TMP0:%.*]] = or i1 [[COND4:%.*]], [[COND2:%.*]]
156+
; CHECK-NEXT: [[TMP1:%.*]] = or i1 [[TMP0]], [[COND3:%.*]]
157+
; CHECK-NEXT: [[TMP2:%.*]] = or i1 [[TMP1]], [[COND1:%.*]]
158+
; CHECK-NEXT: br i1 [[TMP2]], label [[LOOP_EXIT_SPLIT:%.*]], label [[ENTRY_SPLIT:%.*]]
159+
; CHECK: entry.split:
160+
; CHECK-NEXT: br i1 [[COND6:%.*]], label [[LOOP_EXIT_SPLIT1:%.*]], label [[ENTRY_SPLIT_SPLIT:%.*]]
161+
; CHECK: entry.split.split:
162+
; CHECK-NEXT: br label [[LOOP_BEGIN:%.*]]
163+
; CHECK: loop_begin:
164+
; CHECK-NEXT: [[VAR_VAL:%.*]] = load i32, i32* [[VAR:%.*]], align 4
165+
; CHECK-NEXT: [[VAR_COND:%.*]] = trunc i32 [[VAR_VAL]] to i1
166+
; CHECK-NEXT: [[COND_OR1:%.*]] = or i1 [[VAR_COND]], false
167+
; CHECK-NEXT: [[COND_OR2:%.*]] = or i1 false, false
168+
; CHECK-NEXT: [[COND_OR3:%.*]] = or i1 [[COND_OR1]], [[COND_OR2]]
169+
; CHECK-NEXT: [[COND_XOR1:%.*]] = xor i1 [[COND5:%.*]], [[VAR_COND]]
170+
; CHECK-NEXT: [[COND_AND1:%.*]] = and i1 false, [[VAR_COND]]
171+
; CHECK-NEXT: [[COND_OR4:%.*]] = or i1 [[COND_XOR1]], [[COND_AND1]]
172+
; CHECK-NEXT: [[COND_OR5:%.*]] = select i1 [[COND_OR3]], i1 true, i1 [[COND_OR4]]
173+
; CHECK-NEXT: [[COND_OR6:%.*]] = select i1 [[COND_OR5]], i1 true, i1 false
174+
; CHECK-NEXT: br i1 [[COND_OR6]], label [[LOOP_EXIT:%.*]], label [[DO_SOMETHING:%.*]]
175+
; CHECK: do_something:
176+
; CHECK-NEXT: call void @some_func() #[[ATTR0:[0-9]+]]
177+
; CHECK-NEXT: br label [[LOOP_BEGIN]]
178+
; CHECK: loop_exit:
179+
; CHECK-NEXT: br label [[LOOP_EXIT_SPLIT1]]
180+
; CHECK: loop_exit.split1:
181+
; CHECK-NEXT: br label [[LOOP_EXIT_SPLIT]]
182+
; CHECK: loop_exit.split:
183+
; CHECK-NEXT: ret i32 0
184+
;
185+
entry:
186+
br label %loop_begin
187+
188+
loop_begin:
189+
%var_val = load i32, i32* %var
190+
%var_cond = trunc i32 %var_val to i1
191+
%cond_or1 = or i1 %var_cond, %cond1
192+
%cond_or2 = or i1 %cond2, %cond3
193+
%cond_or3 = or i1 %cond_or1, %cond_or2
194+
%cond_xor1 = xor i1 %cond5, %var_cond
195+
%cond_and1 = and i1 %cond6, %var_cond
196+
%cond_or4 = or i1 %cond_xor1, %cond_and1
197+
%cond_or5 = select i1 %cond_or3, i1 true, i1 %cond_or4
198+
%cond_or6 = select i1 %cond_or5, i1 true, i1 %cond4
199+
br i1 %cond_or6, label %loop_exit, label %do_something
200+
201+
do_something:
202+
call void @some_func() noreturn nounwind
203+
br label %loop_begin
204+
205+
loop_exit:
206+
ret i32 0
207+
}
208+
209+
define 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) {
210+
; CHECK-LABEL: @test_partial_condition_unswitch_or_select_noundef(
211+
; CHECK-NEXT: entry:
212+
; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[COND4:%.*]], [[COND2:%.*]]
213+
; CHECK-NEXT: [[TMP1:%.*]] = or i1 [[TMP0]], [[COND3:%.*]]
214+
; CHECK-NEXT: [[TMP2:%.*]] = or i1 [[TMP1]], [[COND1:%.*]]
215+
; CHECK-NEXT: br i1 [[TMP2]], label [[LOOP_EXIT_SPLIT:%.*]], label [[ENTRY_SPLIT:%.*]]
216+
; CHECK: entry.split:
217+
; CHECK-NEXT: br i1 [[COND6:%.*]], label [[LOOP_EXIT_SPLIT1:%.*]], label [[ENTRY_SPLIT_SPLIT:%.*]]
218+
; CHECK: entry.split.split:
219+
; CHECK-NEXT: br label [[LOOP_BEGIN:%.*]]
220+
; CHECK: loop_begin:
221+
; CHECK-NEXT: [[VAR_VAL:%.*]] = load i32, i32* [[VAR:%.*]], align 4
222+
; CHECK-NEXT: [[VAR_COND:%.*]] = trunc i32 [[VAR_VAL]] to i1
223+
; CHECK-NEXT: [[COND_OR1:%.*]] = or i1 [[VAR_COND]], false
224+
; CHECK-NEXT: [[COND_OR2:%.*]] = or i1 false, false
225+
; CHECK-NEXT: [[COND_OR3:%.*]] = or i1 [[COND_OR1]], [[COND_OR2]]
226+
; CHECK-NEXT: [[COND_XOR1:%.*]] = xor i1 [[COND5:%.*]], [[VAR_COND]]
227+
; CHECK-NEXT: [[COND_AND1:%.*]] = and i1 false, [[VAR_COND]]
228+
; CHECK-NEXT: [[COND_OR4:%.*]] = or i1 [[COND_XOR1]], [[COND_AND1]]
229+
; CHECK-NEXT: [[COND_OR5:%.*]] = select i1 [[COND_OR3]], i1 true, i1 [[COND_OR4]]
230+
; CHECK-NEXT: [[COND_OR6:%.*]] = select i1 [[COND_OR5]], i1 true, i1 false
231+
; CHECK-NEXT: br i1 [[COND_OR6]], label [[LOOP_EXIT:%.*]], label [[DO_SOMETHING:%.*]]
232+
; CHECK: do_something:
233+
; CHECK-NEXT: call void @some_func() #[[ATTR0]]
234+
; CHECK-NEXT: br label [[LOOP_BEGIN]]
235+
; CHECK: loop_exit:
236+
; CHECK-NEXT: br label [[LOOP_EXIT_SPLIT1]]
237+
; CHECK: loop_exit.split1:
238+
; CHECK-NEXT: br label [[LOOP_EXIT_SPLIT]]
239+
; CHECK: loop_exit.split:
240+
; CHECK-NEXT: ret i32 0
241+
;
242+
entry:
243+
br label %loop_begin
244+
245+
loop_begin:
246+
%var_val = load i32, i32* %var
247+
%var_cond = trunc i32 %var_val to i1
248+
%cond_or1 = or i1 %var_cond, %cond1
249+
%cond_or2 = or i1 %cond2, %cond3
250+
%cond_or3 = or i1 %cond_or1, %cond_or2
251+
%cond_xor1 = xor i1 %cond5, %var_cond
252+
%cond_and1 = and i1 %cond6, %var_cond
253+
%cond_or4 = or i1 %cond_xor1, %cond_and1
254+
%cond_or5 = select i1 %cond_or3, i1 true, i1 %cond_or4
255+
%cond_or6 = select i1 %cond_or5, i1 true, i1 %cond4
256+
br i1 %cond_or6, label %loop_exit, label %do_something
257+
258+
do_something:
259+
call void @some_func() noreturn nounwind
260+
br label %loop_begin
261+
262+
loop_exit:
263+
ret i32 0
264+
}

llvm/test/Transforms/SimpleLoopUnswitch/trivial-unswitch.ll

Lines changed: 0 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -634,63 +634,6 @@ loop_exit:
634634
; CHECK-NEXT: ret
635635
}
636636

637-
; Check that loop unswitch looks through a combination of or and select instructions.
638-
; Note that cond6 can be unswitched because `select i1 %cond_or5, i1 true, i1 false` is
639-
; both logical-or and logical-and.
640-
define i32 @test_partial_condition_unswitch_or_select(i32* %var, i1 %cond1, i1 %cond2, i1 %cond3, i1 %cond4, i1 %cond5, i1 %cond6) {
641-
; CHECK-LABEL: @test_partial_condition_unswitch_or_select(
642-
entry:
643-
br label %loop_begin
644-
; CHECK-NEXT: entry:
645-
; CHECK-NEXT: %[[INV_OR1:.*]] = or i1 %cond4, %cond2
646-
; CHECK-NEXT: %[[INV_OR2:.*]] = or i1 %[[INV_OR1]], %cond3
647-
; CHECK-NEXT: %[[INV_OR3:.*]] = or i1 %[[INV_OR2]], %cond1
648-
; CHECK-NEXT: br i1 %[[INV_OR3]], label %loop_exit.split, label %entry.split
649-
;
650-
; CHECK: entry.split:
651-
; CHECK-NEXT: br i1 %cond6, label %loop_exit.split1, label %entry.split.split
652-
;
653-
; CHECK: entry.split.split:
654-
; CHECK-NEXT: br label %loop_begin
655-
656-
loop_begin:
657-
%var_val = load i32, i32* %var
658-
%var_cond = trunc i32 %var_val to i1
659-
%cond_or1 = or i1 %var_cond, %cond1
660-
%cond_or2 = or i1 %cond2, %cond3
661-
%cond_or3 = or i1 %cond_or1, %cond_or2
662-
%cond_xor1 = xor i1 %cond5, %var_cond
663-
%cond_and1 = and i1 %cond6, %var_cond
664-
%cond_or4 = or i1 %cond_xor1, %cond_and1
665-
%cond_or5 = select i1 %cond_or3, i1 true, i1 %cond_or4
666-
%cond_or6 = select i1 %cond_or5, i1 true, i1 %cond4
667-
br i1 %cond_or6, label %loop_exit, label %do_something
668-
; CHECK: loop_begin:
669-
; CHECK-NEXT: %[[VAR:.*]] = load i32
670-
; CHECK-NEXT: %[[VAR_COND:.*]] = trunc i32 %[[VAR]] to i1
671-
; CHECK-NEXT: %[[COND_OR1:.*]] = or i1 %[[VAR_COND]], false
672-
; CHECK-NEXT: %[[COND_OR2:.*]] = or i1 false, false
673-
; CHECK-NEXT: %[[COND_OR3:.*]] = or i1 %[[COND_OR1]], %[[COND_OR2]]
674-
; CHECK-NEXT: %[[COND_XOR:.*]] = xor i1 %cond5, %[[VAR_COND]]
675-
; CHECK-NEXT: %[[COND_AND:.*]] = and i1 false, %[[VAR_COND]]
676-
; CHECK-NEXT: %[[COND_OR4:.*]] = or i1 %[[COND_XOR]], %[[COND_AND]]
677-
; CHECK-NEXT: %[[COND_OR5:.*]] = select i1 %[[COND_OR3]], i1 true, i1 %[[COND_OR4]]
678-
; CHECK-NEXT: %[[COND_OR6:.*]] = select i1 %[[COND_OR5]], i1 true, i1 false
679-
; CHECK-NEXT: br i1 %[[COND_OR6]], label %loop_exit, label %do_something
680-
681-
do_something:
682-
call void @some_func() noreturn nounwind
683-
br label %loop_begin
684-
; CHECK: do_something:
685-
; CHECK-NEXT: call
686-
; CHECK-NEXT: br label %loop_begin
687-
688-
loop_exit:
689-
ret i32 0
690-
; CHECK: loop_exit.split:
691-
; CHECK-NEXT: ret
692-
}
693-
694637
define i32 @test_partial_condition_unswitch_with_lcssa_phi1(i32* %var, i1 %cond, i32 %x) {
695638
; CHECK-LABEL: @test_partial_condition_unswitch_with_lcssa_phi1(
696639
entry:

0 commit comments

Comments
 (0)