xref: /llvm-project/llvm/test/Transforms/SimpleLoopUnswitch/implicit-null-checks.ll (revision d889e17eca8e8c43c6e4a2439fae5a1a40823623)
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 @throw_npe()
6
7; It is illegal to preserve make_implicit notion of the condition being
8; unswitched because we may exit loop before we reach the condition, so
9; there is no guarantee that following implicit branch always means getting
10; to throw_npe block.
11define i32 @test_should_drop_make_implicit(i32* %p1, i32* %p2) {
12; CHECK-LABEL: @test_should_drop_make_implicit(
13; CHECK-NEXT:  entry:
14; CHECK-NEXT:    [[NULL_CHECK:%.*]] = icmp eq i32* [[P2:%.*]], null
15; CHECK-NOT:     !make.implicit
16; CHECK-NEXT:    br i1 [[NULL_CHECK]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]]
17; CHECK:       entry.split.us:
18; CHECK-NEXT:    br label [[LOOP_US:%.*]]
19; CHECK:       loop.us:
20; CHECK-NEXT:    [[IV_US:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT_US]] ]
21; CHECK-NEXT:    [[X_US:%.*]] = load i32, i32* [[P1:%.*]], align 4
22; CHECK-NEXT:    [[SIDE_EXIT_COND_US:%.*]] = icmp eq i32 [[X_US]], 0
23; CHECK-NEXT:    br i1 [[SIDE_EXIT_COND_US]], label [[SIDE_EXIT_SPLIT_US:%.*]], label [[NULL_CHECK_BLOCK_US:%.*]]
24; CHECK:       null_check_block.us:
25; CHECK-NEXT:    br label [[THROW_NPE_SPLIT_US:%.*]]
26; CHECK:       side_exit.split.us:
27; CHECK-NEXT:    br label [[SIDE_EXIT:%.*]]
28; CHECK:       throw_npe.split.us:
29; CHECK-NEXT:    br label [[THROW_NPE:%.*]]
30; CHECK:       entry.split:
31; CHECK-NEXT:    br label [[LOOP:%.*]]
32; CHECK:       loop:
33; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
34; CHECK-NEXT:    [[X:%.*]] = load i32, i32* [[P1]], align 4
35; CHECK-NEXT:    [[SIDE_EXIT_COND:%.*]] = icmp eq i32 [[X]], 0
36; CHECK-NEXT:    br i1 [[SIDE_EXIT_COND]], label [[SIDE_EXIT_SPLIT:%.*]], label [[NULL_CHECK_BLOCK:%.*]]
37; CHECK:       null_check_block:
38; CHECK-NEXT:    br label [[BACKEDGE]]
39; CHECK:       backedge:
40; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
41; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], 10000
42; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
43; CHECK:       side_exit.split:
44; CHECK-NEXT:    br label [[SIDE_EXIT]]
45; CHECK:       side_exit:
46; CHECK-NEXT:    ret i32 0
47; CHECK:       throw_npe:
48; CHECK-NEXT:    call void @throw_npe()
49; CHECK-NEXT:    unreachable
50; CHECK:       exit:
51; CHECK-NEXT:    [[X_LCSSA2:%.*]] = phi i32 [ [[X]], [[BACKEDGE]] ]
52; CHECK-NEXT:    ret i32 [[X_LCSSA2]]
53;
54entry:
55  %null_check = icmp eq i32* %p2, null
56  br label %loop
57loop:
58  %iv = phi i32 [0, %entry], [%iv.next, %backedge]
59  %x = load i32, i32* %p1
60  %side_exit_cond = icmp eq i32 %x, 0
61  br i1 %side_exit_cond, label %side_exit, label %null_check_block
62
63null_check_block:
64  br i1 %null_check, label %throw_npe, label %backedge, !make.implicit !0
65
66backedge:
67  %iv.next = add i32 %iv,1
68  %loop_cond = icmp slt i32 %iv.next, 10000
69  br i1 %loop_cond, label %loop, label %exit
70
71side_exit:
72  ret i32 0
73
74throw_npe:
75  call void @throw_npe()
76  unreachable
77
78exit:
79  ret i32 %x
80}
81
82; Here make.implicit notion may be preserved because we always get to throw_npe
83; after following true branch. This is a trivial unswitch.
84define i32 @test_may_keep_make_implicit_trivial(i32* %p1, i32* %p2) {
85; CHECK-LABEL: @test_may_keep_make_implicit_trivial(
86; CHECK-NEXT:  entry:
87; CHECK-NEXT:    [[NULL_CHECK:%.*]] = icmp eq i32* [[P2:%.*]], null
88; CHECK-NEXT:    br i1 [[NULL_CHECK]], label [[THROW_NPE:%.*]], label [[ENTRY_SPLIT:%.*]], !make.implicit !0
89; CHECK:       entry.split:
90; CHECK-NEXT:    br label [[LOOP:%.*]]
91; CHECK:       loop:
92; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
93; CHECK-NEXT:    [[X:%.*]] = load i32, i32* [[P1:%.*]], align 4
94; CHECK-NEXT:    [[SIDE_EXIT_COND:%.*]] = icmp eq i32 [[X]], 0
95; CHECK-NEXT:    br label [[SIDE_EXIT_BLOCK:%.*]]
96; CHECK:       side_exit_block:
97; CHECK-NEXT:    br i1 [[SIDE_EXIT_COND]], label [[SIDE_EXIT:%.*]], label [[BACKEDGE]]
98; CHECK:       backedge:
99; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
100; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], 10000
101; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
102; CHECK:       side_exit:
103; CHECK-NEXT:    ret i32 0
104; CHECK:       throw_npe:
105; CHECK-NEXT:    call void @throw_npe()
106; CHECK-NEXT:    unreachable
107; CHECK:       exit:
108; CHECK-NEXT:    [[X_LCSSA2:%.*]] = phi i32 [ [[X]], [[BACKEDGE]] ]
109; CHECK-NEXT:    ret i32 [[X_LCSSA2]]
110;
111entry:
112  %null_check = icmp eq i32* %p2, null
113  br label %loop
114loop:
115  %iv = phi i32 [0, %entry], [%iv.next, %backedge]
116  %x = load i32, i32* %p1
117  %side_exit_cond = icmp eq i32 %x, 0
118  br i1 %null_check, label %throw_npe, label %side_exit_block, !make.implicit !0
119
120side_exit_block:
121  br i1 %side_exit_cond, label %side_exit, label %backedge
122
123backedge:
124  %iv.next = add i32 %iv,1
125  %loop_cond = icmp slt i32 %iv.next, 10000
126  br i1 %loop_cond, label %loop, label %exit
127
128side_exit:
129  ret i32 0
130
131throw_npe:
132  call void @throw_npe()
133  unreachable
134
135exit:
136  ret i32 %x
137}
138
139; TODO: This is a non-trivial unswitch, but it would still be legal to keep
140; !make.implicit in entry block. Currently we do not have enough analysis to
141; prove it.
142define i32 @test_may_keep_make_implicit_non_trivial(i32* %p1, i32* %p2) {
143; CHECK-LABEL: @test_may_keep_make_implicit_non_trivial(
144; CHECK-NEXT:  entry:
145; CHECK-NEXT:    [[NULL_CHECK:%.*]] = icmp eq i32* [[P2:%.*]], null
146; CHECK-NOT:     !make.implicit
147; CHECK-NEXT:    br i1 [[NULL_CHECK]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]]
148; CHECK:       entry.split.us:
149; CHECK-NEXT:    br label [[LOOP_US:%.*]]
150; CHECK:       loop.us:
151; CHECK-NEXT:    [[IV_US:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT_US]] ]
152; CHECK-NEXT:    [[X_US:%.*]] = load i32, i32* [[P1:%.*]], align 4
153; CHECK-NEXT:    [[INNER_BLOCK_COND_US:%.*]] = icmp eq i32 [[X_US]], 0
154; CHECK-NEXT:    br i1 [[INNER_BLOCK_COND_US]], label [[INNER_BLOCK_US:%.*]], label [[NULL_CHECK_BLOCK_US:%.*]]
155; CHECK:       inner_block.us:
156; CHECK-NEXT:    br label [[NULL_CHECK_BLOCK_US]]
157; CHECK:       null_check_block.us:
158; CHECK-NEXT:    br label [[THROW_NPE_SPLIT_US:%.*]]
159; CHECK:       throw_npe.split.us:
160; CHECK-NEXT:    br label [[THROW_NPE:%.*]]
161; CHECK:       entry.split:
162; CHECK-NEXT:    br label [[LOOP:%.*]]
163; CHECK:       loop:
164; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
165; CHECK-NEXT:    [[X:%.*]] = load i32, i32* [[P1]], align 4
166; CHECK-NEXT:    [[INNER_BLOCK_COND:%.*]] = icmp eq i32 [[X]], 0
167; CHECK-NEXT:    br i1 [[INNER_BLOCK_COND]], label [[INNER_BLOCK:%.*]], label [[NULL_CHECK_BLOCK:%.*]]
168; CHECK:       inner_block:
169; CHECK-NEXT:    br label [[NULL_CHECK_BLOCK]]
170; CHECK:       null_check_block:
171; CHECK-NEXT:    br label [[BACKEDGE]]
172; CHECK:       backedge:
173; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
174; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], 10000
175; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
176; CHECK:       throw_npe:
177; CHECK-NEXT:    call void @throw_npe()
178; CHECK-NEXT:    unreachable
179; CHECK:       exit:
180; CHECK-NEXT:    [[X_LCSSA1:%.*]] = phi i32 [ [[X]], [[BACKEDGE]] ]
181; CHECK-NEXT:    ret i32 [[X_LCSSA1]]
182;
183entry:
184  %null_check = icmp eq i32* %p2, null
185  br label %loop
186loop:
187  %iv = phi i32 [0, %entry], [%iv.next, %backedge]
188  %x = load i32, i32* %p1
189  %inner_block_cond = icmp eq i32 %x, 0
190  br i1 %inner_block_cond, label %inner_block, label %null_check_block
191
192inner_block:
193  br label %null_check_block
194
195null_check_block:
196  br i1 %null_check, label %throw_npe, label %backedge, !make.implicit !0
197
198backedge:
199  %iv.next = add i32 %iv,1
200  %loop_cond = icmp slt i32 %iv.next, 10000
201  br i1 %loop_cond, label %loop, label %exit
202
203throw_npe:
204  call void @throw_npe()
205  unreachable
206
207exit:
208  ret i32 %x
209}
210
211!0 = !{}
212