[LLVM][IR] Use splat syntax when printing ConstantExpr based splats. (#116856)
[llvm-project.git] / llvm / test / Transforms / ConstraintElimination / geps-inbounds-precondition-ub-in-use-blocks.ll
blob7bd2aca8160264b60c5b147778b5dd0e93636d03
1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt -passes=constraint-elimination -S %s | FileCheck %s
4 ; Tests for using inbounds information from GEPs where the GEP only causes UB in the use blocks.
6 declare void @noundef(ptr noundef) willreturn nounwind
7 declare void @noundef2(ptr noundef)
9 declare void @use(i1)
11 ; %start + %n.ext is guaranteed to not overflow (due to inbounds).
12 ; %start + %idx.ext does not overflow if %idx.ext <= %n.ext.
13 define i1 @inbounds_poison_is_ub_in_use_block_1(ptr %src, i32 %n, i32 %idx) {
14 ; CHECK-LABEL: @inbounds_poison_is_ub_in_use_block_1(
15 ; CHECK-NEXT:  entry:
16 ; CHECK-NEXT:    [[N_EXT:%.*]] = zext i32 [[N:%.*]] to i64
17 ; CHECK-NEXT:    [[UPPER:%.*]] = getelementptr inbounds i32, ptr [[SRC:%.*]], i64 [[N_EXT]]
18 ; CHECK-NEXT:    [[CMP_IDX:%.*]] = icmp ult i32 [[IDX:%.*]], [[N]]
19 ; CHECK-NEXT:    [[IDX_EXT:%.*]] = zext i32 [[IDX]] to i64
20 ; CHECK-NEXT:    [[SRC_IDX:%.*]] = getelementptr i32, ptr [[SRC]], i64 [[IDX_EXT]]
21 ; CHECK-NEXT:    br i1 [[CMP_IDX]], label [[THEN:%.*]], label [[ELSE:%.*]]
22 ; CHECK:       then:
23 ; CHECK-NEXT:    call void @noundef(ptr [[UPPER]])
24 ; CHECK-NEXT:    [[CMP_UPPER_1:%.*]] = icmp ule ptr [[SRC_IDX]], [[UPPER]]
25 ; CHECK-NEXT:    ret i1 [[CMP_UPPER_1]]
26 ; CHECK:       else:
27 ; CHECK-NEXT:    [[CMP_UPPER_2:%.*]] = icmp ule ptr [[SRC_IDX]], [[UPPER]]
28 ; CHECK-NEXT:    ret i1 [[CMP_UPPER_2]]
30 entry:
31   %n.ext = zext i32 %n to i64
32   %upper = getelementptr inbounds i32, ptr %src, i64 %n.ext
33   %cmp.idx = icmp ult i32 %idx, %n
34   %idx.ext = zext i32 %idx to i64
35   %src.idx = getelementptr i32, ptr %src, i64 %idx.ext
36   br i1 %cmp.idx, label %then, label %else
38 then:
39   call void @noundef(ptr %upper)
40   %cmp.upper.1 = icmp ule ptr %src.idx, %upper
41   ret i1 %cmp.upper.1
43 else:
44   %cmp.upper.2 = icmp ule ptr %src.idx, %upper
45   ret i1 %cmp.upper.2
48 define i1 @inbounds_poison_is_ub_in_use_block_2(ptr %src, i32 %n, i32 %idx, i1 %c) {
49 ; CHECK-LABEL: @inbounds_poison_is_ub_in_use_block_2(
50 ; CHECK-NEXT:  entry:
51 ; CHECK-NEXT:    [[N_EXT:%.*]] = zext i32 [[N:%.*]] to i64
52 ; CHECK-NEXT:    [[UPPER:%.*]] = getelementptr inbounds i32, ptr [[SRC:%.*]], i64 [[N_EXT]]
53 ; CHECK-NEXT:    [[CMP_IDX:%.*]] = icmp ult i32 [[IDX:%.*]], [[N]]
54 ; CHECK-NEXT:    [[IDX_EXT:%.*]] = zext i32 [[IDX]] to i64
55 ; CHECK-NEXT:    [[SRC_IDX:%.*]] = getelementptr i32, ptr [[SRC]], i64 [[IDX_EXT]]
56 ; CHECK-NEXT:    br i1 [[CMP_IDX]], label [[THEN:%.*]], label [[ELSE:%.*]]
57 ; CHECK:       then:
58 ; CHECK-NEXT:    [[CMP_UPPER_1:%.*]] = icmp ule ptr [[SRC_IDX]], [[UPPER]]
59 ; CHECK-NEXT:    call void @noundef(ptr [[UPPER]])
60 ; CHECK-NEXT:    ret i1 [[CMP_UPPER_1]]
61 ; CHECK:       else:
62 ; CHECK-NEXT:    [[CMP_UPPER_2:%.*]] = icmp ule ptr [[SRC_IDX]], [[UPPER]]
63 ; CHECK-NEXT:    ret i1 [[CMP_UPPER_2]]
65 entry:
66   %n.ext = zext i32 %n to i64
67   %upper = getelementptr inbounds i32, ptr %src, i64 %n.ext
68   %cmp.idx = icmp ult i32 %idx, %n
69   %idx.ext = zext i32 %idx to i64
70   %src.idx = getelementptr i32, ptr %src, i64 %idx.ext
71   br i1 %cmp.idx, label %then, label %else
73 then:
74   %cmp.upper.1 = icmp ule ptr %src.idx, %upper
75   call void @noundef(ptr %upper)
76   ret i1 %cmp.upper.1
78 else:
79   %cmp.upper.2 = icmp ule ptr %src.idx, %upper
80   ret i1 %cmp.upper.2
83 declare void @llvm.assume(i1)
85 ; %start + %n.ext is guaranteed to not overflow (due to inbounds).
86 ; %start + %idx.ext does not overflow if %idx.ext <= %n.ext.
87 define i1 @inbounds_poison_is_ub_in_use_block_by_assume(ptr %src, i32 %n, i32 %idx) {
88 ; CHECK-LABEL: @inbounds_poison_is_ub_in_use_block_by_assume(
89 ; CHECK-NEXT:  entry:
90 ; CHECK-NEXT:    [[N_EXT:%.*]] = zext i32 [[N:%.*]] to i64
91 ; CHECK-NEXT:    [[UPPER:%.*]] = getelementptr inbounds i32, ptr [[SRC:%.*]], i64 [[N_EXT]]
92 ; CHECK-NEXT:    [[CMP_IDX:%.*]] = icmp ult i32 [[IDX:%.*]], [[N]]
93 ; CHECK-NEXT:    [[IDX_EXT:%.*]] = zext i32 [[IDX]] to i64
94 ; CHECK-NEXT:    [[SRC_IDX:%.*]] = getelementptr i32, ptr [[SRC]], i64 [[IDX_EXT]]
95 ; CHECK-NEXT:    br i1 [[CMP_IDX]], label [[THEN:%.*]], label [[ELSE:%.*]]
96 ; CHECK:       then:
97 ; CHECK-NEXT:    [[CMP_NE:%.*]] = icmp ule ptr null, [[UPPER]]
98 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_NE]])
99 ; CHECK-NEXT:    [[CMP_UPPER_1:%.*]] = icmp ule ptr [[SRC_IDX]], [[UPPER]]
100 ; CHECK-NEXT:    ret i1 [[CMP_UPPER_1]]
101 ; CHECK:       else:
102 ; CHECK-NEXT:    [[CMP_UPPER_2:%.*]] = icmp ule ptr [[SRC_IDX]], [[UPPER]]
103 ; CHECK-NEXT:    ret i1 [[CMP_UPPER_2]]
105 entry:
106   %n.ext = zext i32 %n to i64
107   %upper = getelementptr inbounds i32, ptr %src, i64 %n.ext
108   %cmp.idx = icmp ult i32 %idx, %n
109   %idx.ext = zext i32 %idx to i64
110   %src.idx = getelementptr i32, ptr %src, i64 %idx.ext
111   br i1 %cmp.idx, label %then, label %else
113 then:
114   %cmp.ne = icmp ule ptr null, %upper
115   call void @llvm.assume(i1 %cmp.ne)
116   %cmp.upper.1 = icmp ule ptr %src.idx, %upper
117   ret i1 %cmp.upper.1
119 else:
120   %cmp.upper.2 = icmp ule ptr %src.idx, %upper
121   ret i1 %cmp.upper.2
125 ; %start + %n.ext is guaranteed to not overflow (due to inbounds).
126 ; %start + %idx.ext does not overflow if %idx.ext <= %n.ext.
127 define i1 @inbounds_poison_is_ub_in_in_multiple_use_blocks_1(ptr %src, i32 %n, i32 %idx, i1 %c) {
128 ; CHECK-LABEL: @inbounds_poison_is_ub_in_in_multiple_use_blocks_1(
129 ; CHECK-NEXT:  entry:
130 ; CHECK-NEXT:    [[N_EXT:%.*]] = zext i32 [[N:%.*]] to i64
131 ; CHECK-NEXT:    [[UPPER:%.*]] = getelementptr inbounds i32, ptr [[SRC:%.*]], i64 [[N_EXT]]
132 ; CHECK-NEXT:    br i1 [[C:%.*]], label [[CHECK_BB:%.*]], label [[EXIT:%.*]]
133 ; CHECK:       check.bb:
134 ; CHECK-NEXT:    call void @noundef(ptr [[UPPER]])
135 ; CHECK-NEXT:    [[CMP_IDX:%.*]] = icmp ult i32 [[IDX:%.*]], [[N]]
136 ; CHECK-NEXT:    [[IDX_EXT:%.*]] = zext i32 [[IDX]] to i64
137 ; CHECK-NEXT:    [[SRC_IDX:%.*]] = getelementptr i32, ptr [[SRC]], i64 [[IDX_EXT]]
138 ; CHECK-NEXT:    br i1 [[CMP_IDX]], label [[THEN:%.*]], label [[ELSE:%.*]]
139 ; CHECK:       then:
140 ; CHECK-NEXT:    call void @noundef(ptr [[UPPER]])
141 ; CHECK-NEXT:    [[CMP_UPPER_1:%.*]] = icmp ule ptr [[SRC_IDX]], [[UPPER]]
142 ; CHECK-NEXT:    ret i1 [[CMP_UPPER_1]]
143 ; CHECK:       else:
144 ; CHECK-NEXT:    [[CMP_UPPER_2:%.*]] = icmp ule ptr [[SRC_IDX]], [[UPPER]]
145 ; CHECK-NEXT:    ret i1 [[CMP_UPPER_2]]
146 ; CHECK:       exit:
147 ; CHECK-NEXT:    ret i1 false
149 entry:
150   %n.ext = zext i32 %n to i64
151   %upper = getelementptr inbounds i32, ptr %src, i64 %n.ext
152   br i1 %c, label %check.bb, label %exit
154 check.bb:
155   call void @noundef(ptr %upper)
156   %cmp.idx = icmp ult i32 %idx, %n
157   %idx.ext = zext i32 %idx to i64
158   %src.idx = getelementptr i32, ptr %src, i64 %idx.ext
159   br i1 %cmp.idx, label %then, label %else
161 then:
162   call void @noundef(ptr %upper)
163   %cmp.upper.1 = icmp ule ptr %src.idx, %upper
164   ret i1 %cmp.upper.1
166 else:
167   %cmp.upper.2 = icmp ule ptr %src.idx, %upper
168   ret i1 %cmp.upper.2
170 exit:
171   ret i1 false
174 define i1 @may_exit_before_ub_is_caused(ptr %src, i32 %n, i32 %idx) {
175 ; CHECK-LABEL: @may_exit_before_ub_is_caused(
176 ; CHECK-NEXT:  entry:
177 ; CHECK-NEXT:    [[N_EXT:%.*]] = zext i32 [[N:%.*]] to i64
178 ; CHECK-NEXT:    [[UPPER:%.*]] = getelementptr inbounds i32, ptr [[SRC:%.*]], i64 [[N_EXT]]
179 ; CHECK-NEXT:    [[CMP_IDX:%.*]] = icmp ult i32 [[IDX:%.*]], [[N]]
180 ; CHECK-NEXT:    [[IDX_EXT:%.*]] = zext i32 [[IDX]] to i64
181 ; CHECK-NEXT:    [[SRC_IDX:%.*]] = getelementptr i32, ptr [[SRC]], i64 [[IDX_EXT]]
182 ; CHECK-NEXT:    br i1 [[CMP_IDX]], label [[THEN:%.*]], label [[ELSE:%.*]]
183 ; CHECK:       then:
184 ; CHECK-NEXT:    [[CMP_UPPER_1:%.*]] = icmp ule ptr [[SRC_IDX]], [[UPPER]]
185 ; CHECK-NEXT:    call void @use(i1 [[CMP_UPPER_1]])
186 ; CHECK-NEXT:    call void @noundef(ptr [[UPPER]])
187 ; CHECK-NEXT:    ret i1 [[CMP_UPPER_1]]
188 ; CHECK:       else:
189 ; CHECK-NEXT:    [[CMP_UPPER_2:%.*]] = icmp ule ptr [[SRC_IDX]], [[UPPER]]
190 ; CHECK-NEXT:    ret i1 [[CMP_UPPER_2]]
192 entry:
193   %n.ext = zext i32 %n to i64
194   %upper = getelementptr inbounds i32, ptr %src, i64 %n.ext
195   %cmp.idx = icmp ult i32 %idx, %n
196   %idx.ext = zext i32 %idx to i64
197   %src.idx = getelementptr i32, ptr %src, i64 %idx.ext
198   br i1 %cmp.idx, label %then, label %else
200 then:
201   %cmp.upper.1 = icmp ule ptr %src.idx, %upper
202   call void @use(i1 %cmp.upper.1);
203   call void @noundef(ptr %upper)
204   ret i1 %cmp.upper.1
206 else:
207   %cmp.upper.2 = icmp ule ptr %src.idx, %upper
208   ret i1 %cmp.upper.2
211 define i1 @only_UB_in_false_block(ptr %src, i32 %n, i32 %idx) {
212 ; CHECK-LABEL: @only_UB_in_false_block(
213 ; CHECK-NEXT:  entry:
214 ; CHECK-NEXT:    [[N_EXT:%.*]] = zext i32 [[N:%.*]] to i64
215 ; CHECK-NEXT:    [[UPPER:%.*]] = getelementptr inbounds i32, ptr [[SRC:%.*]], i64 [[N_EXT]]
216 ; CHECK-NEXT:    [[CMP_IDX:%.*]] = icmp ult i32 [[IDX:%.*]], [[N]]
217 ; CHECK-NEXT:    [[IDX_EXT:%.*]] = zext i32 [[IDX]] to i64
218 ; CHECK-NEXT:    [[SRC_IDX:%.*]] = getelementptr i32, ptr [[SRC]], i64 [[IDX_EXT]]
219 ; CHECK-NEXT:    br i1 [[CMP_IDX]], label [[THEN:%.*]], label [[ELSE:%.*]]
220 ; CHECK:       then:
221 ; CHECK-NEXT:    [[CMP_UPPER_1:%.*]] = icmp ule ptr [[SRC_IDX]], [[UPPER]]
222 ; CHECK-NEXT:    ret i1 [[CMP_UPPER_1]]
223 ; CHECK:       else:
224 ; CHECK-NEXT:    call void @noundef(ptr [[UPPER]])
225 ; CHECK-NEXT:    [[CMP_UPPER_2:%.*]] = icmp ule ptr [[SRC_IDX]], [[UPPER]]
226 ; CHECK-NEXT:    ret i1 [[CMP_UPPER_2]]
228 entry:
229   %n.ext = zext i32 %n to i64
230   %upper = getelementptr inbounds i32, ptr %src, i64 %n.ext
231   %cmp.idx = icmp ult i32 %idx, %n
232   %idx.ext = zext i32 %idx to i64
233   %src.idx = getelementptr i32, ptr %src, i64 %idx.ext
234   br i1 %cmp.idx, label %then, label %else
236 then:
237   %cmp.upper.1 = icmp ule ptr %src.idx, %upper
238   ret i1 %cmp.upper.1
240 else:
241   call void @noundef(ptr %upper)
242   %cmp.upper.2 = icmp ule ptr %src.idx, %upper
243   ret i1 %cmp.upper.2
246 define i1 @only_ub_by_assume_in_false_block(ptr %src, i32 %n, i32 %idx) {
247 ; CHECK-LABEL: @only_ub_by_assume_in_false_block(
248 ; CHECK-NEXT:  entry:
249 ; CHECK-NEXT:    [[N_EXT:%.*]] = zext i32 [[N:%.*]] to i64
250 ; CHECK-NEXT:    [[UPPER:%.*]] = getelementptr inbounds i32, ptr [[SRC:%.*]], i64 [[N_EXT]]
251 ; CHECK-NEXT:    [[CMP_IDX:%.*]] = icmp ult i32 [[IDX:%.*]], [[N]]
252 ; CHECK-NEXT:    [[IDX_EXT:%.*]] = zext i32 [[IDX]] to i64
253 ; CHECK-NEXT:    [[SRC_IDX:%.*]] = getelementptr i32, ptr [[SRC]], i64 [[IDX_EXT]]
254 ; CHECK-NEXT:    br i1 [[CMP_IDX]], label [[THEN:%.*]], label [[ELSE:%.*]]
255 ; CHECK:       then:
256 ; CHECK-NEXT:    [[CMP_UPPER_1:%.*]] = icmp ule ptr [[SRC_IDX]], [[UPPER]]
257 ; CHECK-NEXT:    ret i1 [[CMP_UPPER_1]]
258 ; CHECK:       else:
259 ; CHECK-NEXT:    [[CMP_NE:%.*]] = icmp ule ptr null, [[UPPER]]
260 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_NE]])
261 ; CHECK-NEXT:    [[CMP_UPPER_2:%.*]] = icmp ule ptr [[SRC_IDX]], [[UPPER]]
262 ; CHECK-NEXT:    ret i1 [[CMP_UPPER_2]]
264 entry:
265   %n.ext = zext i32 %n to i64
266   %upper = getelementptr inbounds i32, ptr %src, i64 %n.ext
267   %cmp.idx = icmp ult i32 %idx, %n
268   %idx.ext = zext i32 %idx to i64
269   %src.idx = getelementptr i32, ptr %src, i64 %idx.ext
270   br i1 %cmp.idx, label %then, label %else
272 then:
273   %cmp.upper.1 = icmp ule ptr %src.idx, %upper
274   ret i1 %cmp.upper.1
276 else:
277   %cmp.ne = icmp ule ptr null, %upper
278   call void @llvm.assume(i1 %cmp.ne)
279   %cmp.upper.2 = icmp ule ptr %src.idx, %upper
280   ret i1 %cmp.upper.2