xref: /llvm-project/llvm/test/Transforms/ConstraintElimination/loops-bottom-tested-pointer-cmps.ll (revision 8a5d51b039c52c3e429390966670b0ab21cf257c)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt -passes=constraint-elimination -S %s | FileCheck %s
3
4declare void @use(i1)
5
6define void @checks_in_loops_removable(ptr %ptr, ptr %lower, ptr %upper, i8 %n) {
7; CHECK-LABEL: @checks_in_loops_removable(
8; CHECK-NEXT:  entry:
9; CHECK-NEXT:    [[CMP_PTR_LOWER:%.*]] = icmp ult ptr [[PTR:%.*]], [[LOWER:%.*]]
10; CHECK-NEXT:    br i1 [[CMP_PTR_LOWER]], label [[TRAP:%.*]], label [[PRE_1:%.*]]
11; CHECK:       pre.1:
12; CHECK-NEXT:    [[IDX_EXT:%.*]] = zext i8 [[N:%.*]] to i16
13; CHECK-NEXT:    [[PTR_N:%.*]] = getelementptr inbounds i8, ptr [[PTR]], i16 [[IDX_EXT]]
14; CHECK-NEXT:    [[CMP_PTR_N_UPPER:%.*]] = icmp ult ptr [[PTR_N]], [[UPPER:%.*]]
15; CHECK-NEXT:    br i1 [[CMP_PTR_N_UPPER]], label [[PRE_2:%.*]], label [[TRAP]]
16; CHECK:       pre.2:
17; CHECK-NEXT:    [[CMP_N_NOT_ZERO:%.*]] = icmp eq i8 [[N]], 0
18; CHECK-NEXT:    br i1 [[CMP_N_NOT_ZERO]], label [[EXIT:%.*]], label [[LOOP_HEADER:%.*]]
19; CHECK:       trap:
20; CHECK-NEXT:    ret void
21; CHECK:       loop.header:
22; CHECK-NEXT:    [[IV:%.*]] = phi i16 [ 0, [[PRE_2]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
23; CHECK-NEXT:    [[PTR_IV:%.*]] = getelementptr inbounds i8, ptr [[PTR]], i16 [[IV]]
24; CHECK-NEXT:    [[CMP_PTR_IV_LOWER:%.*]] = icmp ugt ptr [[LOWER]], [[PTR_IV]]
25; CHECK-NEXT:    [[CMP_PTR_IV_UPPER:%.*]] = icmp ule ptr [[UPPER]], [[PTR_IV]]
26; CHECK-NEXT:    [[OR:%.*]] = or i1 false, [[CMP_PTR_IV_UPPER]]
27; CHECK-NEXT:    br i1 [[OR]], label [[TRAP]], label [[LOOP_LATCH]]
28; CHECK:       loop.latch:
29; CHECK-NEXT:    store i8 0, ptr [[PTR_IV]], align 4
30; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i16 [[IV]], 1
31; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp ne i16 [[IV_NEXT]], [[IDX_EXT]]
32; CHECK-NEXT:    br i1 [[EXITCOND]], label [[LOOP_HEADER]], label [[EXIT]]
33; CHECK:       exit:
34; CHECK-NEXT:    ret void
35;
36entry:
37  %cmp.ptr.lower = icmp ult ptr %ptr, %lower
38  br i1 %cmp.ptr.lower, label %trap, label %pre.1
39
40pre.1:
41  %idx.ext = zext i8 %n to i16
42  %ptr.n = getelementptr inbounds i8, ptr %ptr, i16 %idx.ext
43  %cmp.ptr.n.upper = icmp ult ptr %ptr.n, %upper
44  br i1 %cmp.ptr.n.upper, label %pre.2, label %trap
45
46pre.2:
47  %cmp.n.not.zero = icmp eq i8 %n, 0
48  br i1 %cmp.n.not.zero, label %exit, label %loop.header
49
50trap:
51  ret void
52
53loop.header:
54  %iv = phi i16 [ 0, %pre.2 ], [ %iv.next, %loop.latch ]
55  %ptr.iv = getelementptr inbounds i8, ptr %ptr, i16 %iv
56  %cmp.ptr.iv.lower = icmp ugt ptr %lower, %ptr.iv
57  %cmp.ptr.iv.upper = icmp ule ptr %upper, %ptr.iv
58  %or = or i1 %cmp.ptr.iv.lower, %cmp.ptr.iv.upper
59  br i1 %or, label %trap, label %loop.latch
60
61loop.latch:
62  store i8 0, ptr %ptr.iv, align 4
63  %iv.next = add nuw nsw i16 %iv, 1
64  %exitcond = icmp ne i16 %iv.next, %idx.ext
65  br i1 %exitcond, label %loop.header, label %exit
66
67exit:
68  ret void
69}
70
71define void @some_checks_in_loops_removable(ptr %ptr, ptr %lower, ptr %upper, i8 %n) {
72; CHECK-LABEL: @some_checks_in_loops_removable(
73; CHECK-NEXT:  entry:
74; CHECK-NEXT:    [[CMP_PTR_LOWER:%.*]] = icmp ult ptr [[PTR:%.*]], [[LOWER:%.*]]
75; CHECK-NEXT:    br i1 [[CMP_PTR_LOWER]], label [[TRAP:%.*]], label [[PRE_1:%.*]]
76; CHECK:       pre.1:
77; CHECK-NEXT:    [[IDX_EXT:%.*]] = zext i8 [[N:%.*]] to i16
78; CHECK-NEXT:    [[PTR_N:%.*]] = getelementptr inbounds i8, ptr [[PTR]], i16 [[IDX_EXT]]
79; CHECK-NEXT:    [[CMP_PTR_N_UPPER:%.*]] = icmp ult ptr [[PTR_N]], [[UPPER:%.*]]
80; CHECK-NEXT:    br i1 [[CMP_PTR_N_UPPER]], label [[PRE_2:%.*]], label [[TRAP]]
81; CHECK:       pre.2:
82; CHECK-NEXT:    [[CMP_N_NOT_ZERO:%.*]] = icmp eq i8 [[N]], 0
83; CHECK-NEXT:    br i1 [[CMP_N_NOT_ZERO]], label [[EXIT:%.*]], label [[LOOP_HEADER:%.*]]
84; CHECK:       trap:
85; CHECK-NEXT:    ret void
86; CHECK:       loop.header:
87; CHECK-NEXT:    [[IV:%.*]] = phi i16 [ 0, [[PRE_2]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
88; CHECK-NEXT:    [[PTR_IV:%.*]] = getelementptr inbounds i8, ptr [[PTR]], i16 [[IV]]
89; CHECK-NEXT:    [[CMP_PTR_IV_LOWER:%.*]] = icmp ugt ptr [[LOWER]], [[PTR_IV]]
90; CHECK-NEXT:    [[CMP_PTR_IV_UPPER:%.*]] = icmp ule ptr [[UPPER]], [[PTR_IV]]
91; CHECK-NEXT:    [[OR:%.*]] = or i1 false, [[CMP_PTR_IV_UPPER]]
92; CHECK-NEXT:    br i1 [[OR]], label [[TRAP]], label [[LOOP_BODY:%.*]]
93; CHECK:       loop.body:
94; CHECK-NEXT:    [[IV_1:%.*]] = add nuw nsw i16 [[IV]], 1
95; CHECK-NEXT:    [[PTR_IV_1:%.*]] = getelementptr inbounds i8, ptr [[PTR]], i16 [[IV_1]]
96; CHECK-NEXT:    [[CMP_PTR_IV_1_UPPER:%.*]] = icmp ule ptr [[UPPER]], [[PTR_IV_1]]
97; CHECK-NEXT:    [[OR_1:%.*]] = or i1 false, [[CMP_PTR_IV_1_UPPER]]
98; CHECK-NEXT:    br i1 [[OR]], label [[TRAP]], label [[LOOP_LATCH]]
99; CHECK:       loop.latch:
100; CHECK-NEXT:    store i8 0, ptr [[PTR_IV]], align 4
101; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i16 [[IV]], 1
102; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp ne i16 [[IV_NEXT]], [[IDX_EXT]]
103; CHECK-NEXT:    br i1 [[EXITCOND]], label [[LOOP_HEADER]], label [[EXIT]]
104; CHECK:       exit:
105; CHECK-NEXT:    ret void
106;
107entry:
108  %cmp.ptr.lower = icmp ult ptr %ptr, %lower
109  br i1 %cmp.ptr.lower, label %trap, label %pre.1
110
111pre.1:
112  %idx.ext = zext i8 %n to i16
113  %ptr.n = getelementptr inbounds i8, ptr %ptr, i16 %idx.ext
114  %cmp.ptr.n.upper = icmp ult ptr %ptr.n, %upper
115  br i1 %cmp.ptr.n.upper, label %pre.2, label %trap
116
117pre.2:
118  %cmp.n.not.zero = icmp eq i8 %n, 0
119  br i1 %cmp.n.not.zero, label %exit, label %loop.header
120
121trap:
122  ret void
123
124loop.header:
125  %iv = phi i16 [ 0, %pre.2 ], [ %iv.next, %loop.latch ]
126  %ptr.iv = getelementptr inbounds i8, ptr %ptr, i16 %iv
127  %cmp.ptr.iv.lower = icmp ugt ptr %lower, %ptr.iv
128  %cmp.ptr.iv.upper = icmp ule ptr %upper, %ptr.iv
129  %or = or i1 %cmp.ptr.iv.lower, %cmp.ptr.iv.upper
130  br i1 %or, label %trap, label %loop.body
131
132loop.body:
133  %iv.1 = add nuw nsw i16 %iv, 1
134  %ptr.iv.1 = getelementptr inbounds i8, ptr %ptr, i16 %iv.1
135  %cmp.ptr.iv.1.lower = icmp ugt ptr %lower, %ptr.iv.1
136  %cmp.ptr.iv.1.upper = icmp ule ptr %upper, %ptr.iv.1
137  %or.1 = or i1 %cmp.ptr.iv.1.lower, %cmp.ptr.iv.1.upper
138  br i1 %or, label %trap, label %loop.latch
139
140loop.latch:
141  store i8 0, ptr %ptr.iv, align 4
142  %iv.next = add nuw nsw i16 %iv, 1
143  %exitcond = icmp ne i16 %iv.next, %idx.ext
144  br i1 %exitcond, label %loop.header, label %exit
145
146exit:
147  ret void
148}
149
150; N might be zero, cannot remove upper checks.
151define void @no_checks_in_loops_removable(ptr %ptr, ptr %lower, ptr %upper, i8 %n) {
152; CHECK-LABEL: @no_checks_in_loops_removable(
153; CHECK-NEXT:  entry:
154; CHECK-NEXT:    [[CMP_PTR_LOWER:%.*]] = icmp ult ptr [[PTR:%.*]], [[LOWER:%.*]]
155; CHECK-NEXT:    br i1 [[CMP_PTR_LOWER]], label [[TRAP:%.*]], label [[PRE_1:%.*]]
156; CHECK:       pre.1:
157; CHECK-NEXT:    [[IDX_EXT:%.*]] = zext i8 [[N:%.*]] to i16
158; CHECK-NEXT:    [[PTR_N:%.*]] = getelementptr inbounds i8, ptr [[PTR]], i16 [[IDX_EXT]]
159; CHECK-NEXT:    [[CMP_PTR_N_UPPER:%.*]] = icmp ult ptr [[PTR_N]], [[UPPER:%.*]]
160; CHECK-NEXT:    br i1 [[CMP_PTR_N_UPPER]], label [[LOOP_HEADER:%.*]], label [[TRAP]]
161; CHECK:       trap:
162; CHECK-NEXT:    ret void
163; CHECK:       loop.header:
164; CHECK-NEXT:    [[IV:%.*]] = phi i16 [ 0, [[PRE_1]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
165; CHECK-NEXT:    [[PTR_IV:%.*]] = getelementptr inbounds i8, ptr [[PTR]], i16 [[IV]]
166; CHECK-NEXT:    [[CMP_PTR_IV_LOWER:%.*]] = icmp ugt ptr [[LOWER]], [[PTR_IV]]
167; CHECK-NEXT:    [[CMP_PTR_IV_UPPER:%.*]] = icmp ule ptr [[UPPER]], [[PTR_IV]]
168; CHECK-NEXT:    [[OR:%.*]] = or i1 false, [[CMP_PTR_IV_UPPER]]
169; CHECK-NEXT:    br i1 [[OR]], label [[TRAP]], label [[LOOP_BODY:%.*]]
170; CHECK:       loop.body:
171; CHECK-NEXT:    [[IV_1:%.*]] = add nuw nsw i16 [[IV]], 1
172; CHECK-NEXT:    [[PTR_IV_1:%.*]] = getelementptr inbounds i8, ptr [[PTR]], i16 [[IV_1]]
173; CHECK-NEXT:    [[CMP_PTR_IV_1_UPPER:%.*]] = icmp ule ptr [[UPPER]], [[PTR_IV_1]]
174; CHECK-NEXT:    [[OR_1:%.*]] = or i1 false, [[CMP_PTR_IV_1_UPPER]]
175; CHECK-NEXT:    br i1 [[OR]], label [[TRAP]], label [[LOOP_LATCH]]
176; CHECK:       loop.latch:
177; CHECK-NEXT:    store i8 0, ptr [[PTR_IV]], align 4
178; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i16 [[IV]], 1
179; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp ne i16 [[IV_NEXT]], [[IDX_EXT]]
180; CHECK-NEXT:    br i1 [[EXITCOND]], label [[LOOP_HEADER]], label [[EXIT:%.*]]
181; CHECK:       exit:
182; CHECK-NEXT:    ret void
183;
184entry:
185  %cmp.ptr.lower = icmp ult ptr %ptr, %lower
186  br i1 %cmp.ptr.lower, label %trap, label %pre.1
187
188pre.1:
189  %idx.ext = zext i8 %n to i16
190  %ptr.n = getelementptr inbounds i8, ptr %ptr, i16 %idx.ext
191  %cmp.ptr.n.upper = icmp ult ptr %ptr.n, %upper
192  br i1 %cmp.ptr.n.upper, label %loop.header, label %trap
193
194trap:
195  ret void
196
197loop.header:
198  %iv = phi i16 [ 0, %pre.1 ], [ %iv.next, %loop.latch ]
199  %ptr.iv = getelementptr inbounds i8, ptr %ptr, i16 %iv
200  %cmp.ptr.iv.lower = icmp ugt ptr %lower, %ptr.iv
201  %cmp.ptr.iv.upper = icmp ule ptr %upper, %ptr.iv
202  %or = or i1 %cmp.ptr.iv.lower, %cmp.ptr.iv.upper
203  br i1 %or, label %trap, label %loop.body
204
205loop.body:
206  %iv.1 = add nuw nsw i16 %iv, 1
207  %ptr.iv.1 = getelementptr inbounds i8, ptr %ptr, i16 %iv.1
208  %cmp.ptr.iv.1.lower = icmp ugt ptr %lower, %ptr.iv.1
209  %cmp.ptr.iv.1.upper = icmp ule ptr %upper, %ptr.iv.1
210  %or.1 = or i1 %cmp.ptr.iv.1.lower, %cmp.ptr.iv.1.upper
211  br i1 %or, label %trap, label %loop.latch
212
213loop.latch:
214  store i8 0, ptr %ptr.iv, align 4
215  %iv.next = add nuw nsw i16 %iv, 1
216  %exitcond = icmp ne i16 %iv.next, %idx.ext
217  br i1 %exitcond, label %loop.header, label %exit
218
219exit:
220  ret void
221}
222