• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt -enable-nontrivial-unswitch=true -simple-loop-unswitch -S < %s | FileCheck %s
3; RUN: opt -enable-nontrivial-unswitch=true -passes='loop(unswitch),verify<loops>' -S < %s | FileCheck %s
4
5declare void @may_exit()
6declare void @throw_npe()
7
8; It is illegal to preserve make_implicit notion of the condition being
9; unswitched because we may exit loop before we reach the condition, so
10; there is no guarantee that following implicit branch always means getting
11; to throw_npe block.
12define i32 @test_should_drop_make_implicit(i32* %p1, i32* %p2) {
13; CHECK-LABEL: @test_should_drop_make_implicit(
14; CHECK-NEXT:  entry:
15; CHECK-NEXT:    [[NULL_CHECK:%.*]] = icmp eq i32* [[P2:%.*]], null
16; CHECK-NOT:     !make.implicit
17; CHECK-NEXT:    br i1 [[NULL_CHECK]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]]
18; CHECK:       entry.split.us:
19; CHECK-NEXT:    br label [[LOOP_US:%.*]]
20; CHECK:       loop.us:
21; CHECK-NEXT:    [[IV_US:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT_US]] ]
22; CHECK-NEXT:    [[X_US:%.*]] = load i32, i32* [[P1:%.*]], align 4
23; CHECK-NEXT:    [[SIDE_EXIT_COND_US:%.*]] = icmp eq i32 [[X_US]], 0
24; CHECK-NEXT:    br i1 [[SIDE_EXIT_COND_US]], label [[SIDE_EXIT_SPLIT_US:%.*]], label [[NULL_CHECK_BLOCK_US:%.*]]
25; CHECK:       null_check_block.us:
26; CHECK-NEXT:    br label [[THROW_NPE_SPLIT_US:%.*]]
27; CHECK:       side_exit.split.us:
28; CHECK-NEXT:    br label [[SIDE_EXIT:%.*]]
29; CHECK:       throw_npe.split.us:
30; CHECK-NEXT:    br label [[THROW_NPE:%.*]]
31; CHECK:       entry.split:
32; CHECK-NEXT:    br label [[LOOP:%.*]]
33; CHECK:       loop:
34; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
35; CHECK-NEXT:    [[X:%.*]] = load i32, i32* [[P1]], align 4
36; CHECK-NEXT:    [[SIDE_EXIT_COND:%.*]] = icmp eq i32 [[X]], 0
37; CHECK-NEXT:    br i1 [[SIDE_EXIT_COND]], label [[SIDE_EXIT_SPLIT:%.*]], label [[NULL_CHECK_BLOCK:%.*]]
38; CHECK:       null_check_block:
39; CHECK-NEXT:    br label [[BACKEDGE]]
40; CHECK:       backedge:
41; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
42; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], 10000
43; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
44; CHECK:       side_exit.split:
45; CHECK-NEXT:    br label [[SIDE_EXIT]]
46; CHECK:       side_exit:
47; CHECK-NEXT:    ret i32 0
48; CHECK:       throw_npe:
49; CHECK-NEXT:    call void @throw_npe()
50; CHECK-NEXT:    unreachable
51; CHECK:       exit:
52; CHECK-NEXT:    [[X_LCSSA2:%.*]] = phi i32 [ [[X]], [[BACKEDGE]] ]
53; CHECK-NEXT:    ret i32 [[X_LCSSA2]]
54;
55entry:
56  %null_check = icmp eq i32* %p2, null
57  br label %loop
58loop:
59  %iv = phi i32 [0, %entry], [%iv.next, %backedge]
60  %x = load i32, i32* %p1
61  %side_exit_cond = icmp eq i32 %x, 0
62  br i1 %side_exit_cond, label %side_exit, label %null_check_block
63
64null_check_block:
65  br i1 %null_check, label %throw_npe, label %backedge, !make.implicit !0
66
67backedge:
68  %iv.next = add i32 %iv,1
69  %loop_cond = icmp slt i32 %iv.next, 10000
70  br i1 %loop_cond, label %loop, label %exit
71
72side_exit:
73  ret i32 0
74
75throw_npe:
76  call void @throw_npe()
77  unreachable
78
79exit:
80  ret i32 %x
81}
82
83; Here make.implicit notion may be preserved because we always get to throw_npe
84; after following true branch. This is a trivial unswitch.
85define i32 @test_may_keep_make_implicit_trivial(i32* %p1, i32* %p2) {
86; CHECK-LABEL: @test_may_keep_make_implicit_trivial(
87; CHECK-NEXT:  entry:
88; CHECK-NEXT:    [[NULL_CHECK:%.*]] = icmp eq i32* [[P2:%.*]], null
89; CHECK-NEXT:    br i1 [[NULL_CHECK]], label [[THROW_NPE:%.*]], label [[ENTRY_SPLIT:%.*]], !make.implicit !0
90; CHECK:       entry.split:
91; CHECK-NEXT:    br label [[LOOP:%.*]]
92; CHECK:       loop:
93; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
94; CHECK-NEXT:    [[X:%.*]] = load i32, i32* [[P1:%.*]], align 4
95; CHECK-NEXT:    [[SIDE_EXIT_COND:%.*]] = icmp eq i32 [[X]], 0
96; CHECK-NEXT:    br label [[SIDE_EXIT_BLOCK:%.*]]
97; CHECK:       side_exit_block:
98; CHECK-NEXT:    br i1 [[SIDE_EXIT_COND]], label [[SIDE_EXIT:%.*]], label [[BACKEDGE]]
99; CHECK:       backedge:
100; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
101; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], 10000
102; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
103; CHECK:       side_exit:
104; CHECK-NEXT:    ret i32 0
105; CHECK:       throw_npe:
106; CHECK-NEXT:    call void @throw_npe()
107; CHECK-NEXT:    unreachable
108; CHECK:       exit:
109; CHECK-NEXT:    [[X_LCSSA2:%.*]] = phi i32 [ [[X]], [[BACKEDGE]] ]
110; CHECK-NEXT:    ret i32 [[X_LCSSA2]]
111;
112entry:
113  %null_check = icmp eq i32* %p2, null
114  br label %loop
115loop:
116  %iv = phi i32 [0, %entry], [%iv.next, %backedge]
117  %x = load i32, i32* %p1
118  %side_exit_cond = icmp eq i32 %x, 0
119  br i1 %null_check, label %throw_npe, label %side_exit_block, !make.implicit !0
120
121side_exit_block:
122  br i1 %side_exit_cond, label %side_exit, label %backedge
123
124backedge:
125  %iv.next = add i32 %iv,1
126  %loop_cond = icmp slt i32 %iv.next, 10000
127  br i1 %loop_cond, label %loop, label %exit
128
129side_exit:
130  ret i32 0
131
132throw_npe:
133  call void @throw_npe()
134  unreachable
135
136exit:
137  ret i32 %x
138}
139
140define i32 @test_may_keep_make_implicit_non_trivial(i32* %p1, i32* %p2) {
141; CHECK-LABEL: @test_may_keep_make_implicit_non_trivial(
142; CHECK-NEXT:  entry:
143; CHECK-NEXT:    [[NULL_CHECK:%.*]] = icmp eq i32* [[P2:%.*]], null
144; CHECK-NEXT:    br i1 [[NULL_CHECK]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]], !make.implicit !0
145; CHECK:       entry.split.us:
146; CHECK-NEXT:    br label [[LOOP_US:%.*]]
147; CHECK:       loop.us:
148; CHECK-NEXT:    [[IV_US:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT_US]] ]
149; CHECK-NEXT:    [[X_US:%.*]] = load i32, i32* [[P1:%.*]], align 4
150; CHECK-NEXT:    [[INNER_BLOCK_COND_US:%.*]] = icmp eq i32 [[X_US]], 0
151; CHECK-NEXT:    br i1 [[INNER_BLOCK_COND_US]], label [[INNER_BLOCK_US:%.*]], label [[NULL_CHECK_BLOCK_US:%.*]]
152; CHECK:       inner_block.us:
153; CHECK-NEXT:    br label [[NULL_CHECK_BLOCK_US]]
154; CHECK:       null_check_block.us:
155; CHECK-NEXT:    br label [[THROW_NPE_SPLIT_US:%.*]]
156; CHECK:       throw_npe.split.us:
157; CHECK-NEXT:    br label [[THROW_NPE:%.*]]
158; CHECK:       entry.split:
159; CHECK-NEXT:    br label [[LOOP:%.*]]
160; CHECK:       loop:
161; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
162; CHECK-NEXT:    [[X:%.*]] = load i32, i32* [[P1]], align 4
163; CHECK-NEXT:    [[INNER_BLOCK_COND:%.*]] = icmp eq i32 [[X]], 0
164; CHECK-NEXT:    br i1 [[INNER_BLOCK_COND]], label [[INNER_BLOCK:%.*]], label [[NULL_CHECK_BLOCK:%.*]]
165; CHECK:       inner_block:
166; CHECK-NEXT:    br label [[NULL_CHECK_BLOCK]]
167; CHECK:       null_check_block:
168; CHECK-NEXT:    br label [[BACKEDGE]]
169; CHECK:       backedge:
170; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
171; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], 10000
172; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
173; CHECK:       throw_npe:
174; CHECK-NEXT:    call void @throw_npe()
175; CHECK-NEXT:    unreachable
176; CHECK:       exit:
177; CHECK-NEXT:    [[X_LCSSA1:%.*]] = phi i32 [ [[X]], [[BACKEDGE]] ]
178; CHECK-NEXT:    ret i32 [[X_LCSSA1]]
179;
180entry:
181  %null_check = icmp eq i32* %p2, null
182  br label %loop
183loop:
184  %iv = phi i32 [0, %entry], [%iv.next, %backedge]
185  %x = load i32, i32* %p1
186  %inner_block_cond = icmp eq i32 %x, 0
187  br i1 %inner_block_cond, label %inner_block, label %null_check_block
188
189inner_block:
190  br label %null_check_block
191
192null_check_block:
193  br i1 %null_check, label %throw_npe, label %backedge, !make.implicit !0
194
195backedge:
196  %iv.next = add i32 %iv,1
197  %loop_cond = icmp slt i32 %iv.next, 10000
198  br i1 %loop_cond, label %loop, label %exit
199
200throw_npe:
201  call void @throw_npe()
202  unreachable
203
204exit:
205  ret i32 %x
206}
207
208; Here make.implicit notion should be dropped because of exiting call.
209define i32 @test_should_drop_make_implicit_exiting_call(i32* %p1, i32* %p2) {
210; CHECK-LABEL: @test_should_drop_make_implicit_exiting_call(
211; CHECK-NEXT:  entry:
212; CHECK-NEXT:    [[NULL_CHECK:%.*]] = icmp eq i32* [[P2:%.*]], null
213; CHECK-NOT:     !make.implicit
214; CHECK-NEXT:    br i1 [[NULL_CHECK]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]]
215; CHECK:       entry.split.us:
216; CHECK-NEXT:    br label [[LOOP_US:%.*]]
217; CHECK:       loop.us:
218; CHECK-NEXT:    [[IV_US:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT_US]] ]
219; CHECK-NEXT:    call void @may_exit()
220; CHECK-NEXT:    [[X_US:%.*]] = load i32, i32* [[P1:%.*]], align 4
221; CHECK-NEXT:    [[SIDE_EXIT_COND_US:%.*]] = icmp eq i32 [[X_US]], 0
222; CHECK-NEXT:    br label [[THROW_NPE_SPLIT_US:%.*]]
223; CHECK:       throw_npe.split.us:
224; CHECK-NEXT:    br label [[THROW_NPE:%.*]]
225; CHECK:       entry.split:
226; CHECK-NEXT:    br label [[LOOP:%.*]]
227; CHECK:       loop:
228; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
229; CHECK-NEXT:    call void @may_exit()
230; CHECK-NEXT:    [[X:%.*]] = load i32, i32* [[P1]], align 4
231; CHECK-NEXT:    [[SIDE_EXIT_COND:%.*]] = icmp eq i32 [[X]], 0
232; CHECK-NEXT:    br label [[BACKEDGE]]
233; CHECK:       backedge:
234; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
235; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], 10000
236; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
237; CHECK:       throw_npe:
238; CHECK-NEXT:    call void @throw_npe()
239; CHECK-NEXT:    unreachable
240; CHECK:       exit:
241; CHECK-NEXT:    [[X_LCSSA1:%.*]] = phi i32 [ [[X]], [[BACKEDGE]] ]
242; CHECK-NEXT:    ret i32 [[X_LCSSA1]]
243;
244entry:
245  %null_check = icmp eq i32* %p2, null
246  br label %loop
247loop:
248  %iv = phi i32 [0, %entry], [%iv.next, %backedge]
249  call void @may_exit()
250  %x = load i32, i32* %p1
251  %side_exit_cond = icmp eq i32 %x, 0
252  br i1 %null_check, label %throw_npe, label %backedge, !make.implicit !0
253
254backedge:
255  %iv.next = add i32 %iv,1
256  %loop_cond = icmp slt i32 %iv.next, 10000
257  br i1 %loop_cond, label %loop, label %exit
258
259throw_npe:
260  call void @throw_npe()
261  unreachable
262
263exit:
264  ret i32 %x
265}
266
267; Here exiting call goes after the null check, so make.implicit may be preserved.
268define i32 @test_may_keep_make_implicit_exiting_call(i32* %p1, i32* %p2) {
269; CHECK-LABEL: @test_may_keep_make_implicit_exiting_call(
270; CHECK-NEXT:  entry:
271; CHECK-NEXT:    [[NULL_CHECK:%.*]] = icmp eq i32* [[P2:%.*]], null
272; CHECK-NEXT:    br i1 [[NULL_CHECK]], label [[THROW_NPE:%.*]], label [[ENTRY_SPLIT:%.*]], !make.implicit !0
273; CHECK:       entry.split:
274; CHECK-NEXT:    br label [[LOOP:%.*]]
275; CHECK:       loop:
276; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
277; CHECK-NEXT:    [[X:%.*]] = load i32, i32* [[P1:%.*]], align 4
278; CHECK-NEXT:    [[SIDE_EXIT_COND:%.*]] = icmp eq i32 [[X]], 0
279; CHECK-NEXT:    br label [[BACKEDGE]]
280; CHECK:       backedge:
281; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
282; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], 10000
283; CHECK-NEXT:    call void @may_exit()
284; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
285; CHECK:       throw_npe:
286; CHECK-NEXT:    call void @throw_npe()
287; CHECK-NEXT:    unreachable
288; CHECK:       exit:
289; CHECK-NEXT:    [[X_LCSSA1:%.*]] = phi i32 [ [[X]], [[BACKEDGE]] ]
290; CHECK-NEXT:    ret i32 [[X_LCSSA1]]
291;
292entry:
293  %null_check = icmp eq i32* %p2, null
294  br label %loop
295loop:
296  %iv = phi i32 [0, %entry], [%iv.next, %backedge]
297  %x = load i32, i32* %p1
298  %side_exit_cond = icmp eq i32 %x, 0
299  br i1 %null_check, label %throw_npe, label %backedge, !make.implicit !0
300
301backedge:
302  %iv.next = add i32 %iv,1
303  %loop_cond = icmp slt i32 %iv.next, 10000
304  call void @may_exit()
305  br i1 %loop_cond, label %loop, label %exit
306
307throw_npe:
308  call void @throw_npe()
309  unreachable
310
311exit:
312  ret i32 %x
313}
314
315!0 = !{}
316