1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt -passes='instcombine<no-verify-fixpoint>' -S < %s | FileCheck %s
4 ; In many of these tests nuw can be inferred on the sunk GEP in the exit
5 ; block. However, the condition is only converted into the necessary form
6 ; after it has been sunk and revisited already.
8 target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:32-f32:32:32-f64:32:32-v64:64:64-v128:128:128-a0:0:64"
10 define ptr@test1(ptr %A, i32 %Offset) {
11 ; CHECK-LABEL: @test1(
13 ; CHECK-NEXT: [[TMP_IDX:%.*]] = shl nsw i32 [[OFFSET:%.*]], 2
14 ; CHECK-NEXT: br label [[BB:%.*]]
16 ; CHECK-NEXT: [[RHS_IDX:%.*]] = phi i32 [ [[RHS_ADD:%.*]], [[BB]] ], [ [[TMP_IDX]], [[ENTRY:%.*]] ]
17 ; CHECK-NEXT: [[RHS_ADD]] = add nsw i32 [[RHS_IDX]], 4
18 ; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 [[RHS_IDX]], 400
19 ; CHECK-NEXT: br i1 [[COND]], label [[BB2:%.*]], label [[BB]]
21 ; CHECK-NEXT: [[RHS_PTR:%.*]] = getelementptr inbounds i8, ptr [[A:%.*]], i32 [[RHS_IDX]]
22 ; CHECK-NEXT: ret ptr [[RHS_PTR]]
25 %tmp = getelementptr inbounds i32, ptr %A, i32 %Offset
29 %RHS = phi ptr [ %RHS.next, %bb ], [ %tmp, %entry ]
30 %LHS = getelementptr inbounds i32, ptr %A, i32 100
31 %RHS.next = getelementptr inbounds i32, ptr %RHS, i64 1
32 %cond = icmp ult ptr %LHS, %RHS
33 br i1 %cond, label %bb2, label %bb
39 define ptr @test1_nuw(ptr %A, i32 %Offset) {
40 ; CHECK-LABEL: @test1_nuw(
42 ; CHECK-NEXT: [[TMP_IDX:%.*]] = shl nuw nsw i32 [[OFFSET:%.*]], 2
43 ; CHECK-NEXT: br label [[BB:%.*]]
45 ; CHECK-NEXT: [[RHS_IDX:%.*]] = phi i32 [ [[RHS_ADD:%.*]], [[BB]] ], [ [[TMP_IDX]], [[ENTRY:%.*]] ]
46 ; CHECK-NEXT: [[RHS_ADD]] = add nuw nsw i32 [[RHS_IDX]], 4
47 ; CHECK-NEXT: [[COND:%.*]] = icmp samesign ugt i32 [[RHS_IDX]], 400
48 ; CHECK-NEXT: br i1 [[COND]], label [[BB2:%.*]], label [[BB]]
50 ; CHECK-NEXT: [[RHS_PTR:%.*]] = getelementptr inbounds nuw i8, ptr [[A:%.*]], i32 [[RHS_IDX]]
51 ; CHECK-NEXT: ret ptr [[RHS_PTR]]
54 %tmp = getelementptr inbounds nuw i32, ptr %A, i32 %Offset
58 %RHS = phi ptr [ %RHS.next, %bb ], [ %tmp, %entry ]
59 %LHS = getelementptr inbounds nuw i32, ptr %A, i32 100
60 %RHS.next = getelementptr inbounds nuw i32, ptr %RHS, i64 1
61 %cond = icmp ult ptr %LHS, %RHS
62 br i1 %cond, label %bb2, label %bb
68 define ptr @test1_not_all_nuw(ptr %A, i32 %Offset) {
69 ; CHECK-LABEL: @test1_not_all_nuw(
71 ; CHECK-NEXT: [[TMP_IDX:%.*]] = shl nsw i32 [[OFFSET:%.*]], 2
72 ; CHECK-NEXT: br label [[BB:%.*]]
74 ; CHECK-NEXT: [[RHS_IDX:%.*]] = phi i32 [ [[RHS_ADD:%.*]], [[BB]] ], [ [[TMP_IDX]], [[ENTRY:%.*]] ]
75 ; CHECK-NEXT: [[RHS_ADD]] = add nsw i32 [[RHS_IDX]], 4
76 ; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 [[RHS_IDX]], 400
77 ; CHECK-NEXT: br i1 [[COND]], label [[BB2:%.*]], label [[BB]]
79 ; CHECK-NEXT: [[RHS_PTR:%.*]] = getelementptr inbounds i8, ptr [[A:%.*]], i32 [[RHS_IDX]]
80 ; CHECK-NEXT: ret ptr [[RHS_PTR]]
83 %tmp = getelementptr inbounds i32, ptr %A, i32 %Offset
87 %RHS = phi ptr [ %RHS.next, %bb ], [ %tmp, %entry ]
88 %LHS = getelementptr inbounds nuw i32, ptr %A, i32 100
89 %RHS.next = getelementptr inbounds nuw i32, ptr %RHS, i64 1
90 %cond = icmp ult ptr %LHS, %RHS
91 br i1 %cond, label %bb2, label %bb
97 define ptr@test2(i32 %A, i32 %Offset) {
98 ; CHECK-LABEL: @test2(
100 ; CHECK-NEXT: [[TMP_IDX:%.*]] = shl nsw i32 [[OFFSET:%.*]], 2
101 ; CHECK-NEXT: br label [[BB:%.*]]
103 ; CHECK-NEXT: [[RHS_IDX:%.*]] = phi i32 [ [[RHS_ADD:%.*]], [[BB]] ], [ [[TMP_IDX]], [[ENTRY:%.*]] ]
104 ; CHECK-NEXT: [[RHS_ADD]] = add nsw i32 [[RHS_IDX]], 4
105 ; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 [[RHS_IDX]], 400
106 ; CHECK-NEXT: br i1 [[COND]], label [[BB2:%.*]], label [[BB]]
108 ; CHECK-NEXT: [[A_PTR:%.*]] = inttoptr i32 [[A:%.*]] to ptr
109 ; CHECK-NEXT: [[RHS_PTR:%.*]] = getelementptr inbounds i8, ptr [[A_PTR]], i32 [[RHS_IDX]]
110 ; CHECK-NEXT: ret ptr [[RHS_PTR]]
113 %A.ptr = inttoptr i32 %A to ptr
114 %tmp = getelementptr inbounds i32, ptr %A.ptr, i32 %Offset
118 %RHS = phi ptr [ %RHS.next, %bb ], [ %tmp, %entry ]
119 %LHS = getelementptr inbounds i32, ptr %A.ptr, i32 100
120 %RHS.next = getelementptr inbounds i32, ptr %RHS, i64 1
121 %cmp0 = ptrtoint ptr %LHS to i32
122 %cmp1 = ptrtoint ptr %RHS to i32
123 %cond = icmp ult i32 %cmp0, %cmp1
124 br i1 %cond, label %bb2, label %bb
130 ; Perform the transformation only if we know that the GEPs used are inbounds.
131 define ptr @test3_no_inbounds1(ptr %A, i32 %Offset) {
132 ; CHECK-LABEL: @test3_no_inbounds1(
134 ; CHECK-NEXT: [[TMP:%.*]] = getelementptr i32, ptr [[A:%.*]], i32 [[OFFSET:%.*]]
135 ; CHECK-NEXT: br label [[BB:%.*]]
137 ; CHECK-NEXT: [[RHS:%.*]] = phi ptr [ [[RHS_NEXT:%.*]], [[BB]] ], [ [[TMP]], [[ENTRY:%.*]] ]
138 ; CHECK-NEXT: [[LHS:%.*]] = getelementptr inbounds nuw i8, ptr [[A]], i32 400
139 ; CHECK-NEXT: [[RHS_NEXT]] = getelementptr inbounds nuw i8, ptr [[RHS]], i32 4
140 ; CHECK-NEXT: [[COND:%.*]] = icmp ult ptr [[LHS]], [[RHS]]
141 ; CHECK-NEXT: br i1 [[COND]], label [[BB2:%.*]], label [[BB]]
143 ; CHECK-NEXT: ret ptr [[RHS]]
146 %tmp = getelementptr i32, ptr %A, i32 %Offset
150 %RHS = phi ptr [ %RHS.next, %bb ], [ %tmp, %entry ]
151 %LHS = getelementptr inbounds i32, ptr %A, i32 100
152 %RHS.next = getelementptr inbounds i32, ptr %RHS, i64 1
153 %cond = icmp ult ptr %LHS, %RHS
154 br i1 %cond, label %bb2, label %bb
160 define ptr @test3_no_inbounds2(ptr %A, i32 %Offset) {
161 ; CHECK-LABEL: @test3_no_inbounds2(
163 ; CHECK-NEXT: [[TMP:%.*]] = getelementptr inbounds i32, ptr [[A:%.*]], i32 [[OFFSET:%.*]]
164 ; CHECK-NEXT: br label [[BB:%.*]]
166 ; CHECK-NEXT: [[RHS:%.*]] = phi ptr [ [[RHS_NEXT:%.*]], [[BB]] ], [ [[TMP]], [[ENTRY:%.*]] ]
167 ; CHECK-NEXT: [[LHS:%.*]] = getelementptr inbounds nuw i8, ptr [[A]], i32 400
168 ; CHECK-NEXT: [[RHS_NEXT]] = getelementptr i8, ptr [[RHS]], i32 4
169 ; CHECK-NEXT: [[COND:%.*]] = icmp ult ptr [[LHS]], [[RHS]]
170 ; CHECK-NEXT: br i1 [[COND]], label [[BB2:%.*]], label [[BB]]
172 ; CHECK-NEXT: ret ptr [[RHS]]
175 %tmp = getelementptr inbounds i32, ptr %A, i32 %Offset
179 %RHS = phi ptr [ %RHS.next, %bb ], [ %tmp, %entry ]
180 %LHS = getelementptr inbounds i32, ptr %A, i32 100
181 %RHS.next = getelementptr i32, ptr %RHS, i64 1
182 %cond = icmp ult ptr %LHS, %RHS
183 br i1 %cond, label %bb2, label %bb
189 define ptr @test3_no_inbounds3(ptr %A, i32 %Offset) {
190 ; CHECK-LABEL: @test3_no_inbounds3(
192 ; CHECK-NEXT: [[TMP:%.*]] = getelementptr inbounds i32, ptr [[A:%.*]], i32 [[OFFSET:%.*]]
193 ; CHECK-NEXT: br label [[BB:%.*]]
195 ; CHECK-NEXT: [[RHS:%.*]] = phi ptr [ [[RHS_NEXT:%.*]], [[BB]] ], [ [[TMP]], [[ENTRY:%.*]] ]
196 ; CHECK-NEXT: [[LHS:%.*]] = getelementptr i8, ptr [[A]], i32 400
197 ; CHECK-NEXT: [[RHS_NEXT]] = getelementptr inbounds nuw i8, ptr [[RHS]], i32 4
198 ; CHECK-NEXT: [[COND:%.*]] = icmp ult ptr [[LHS]], [[RHS]]
199 ; CHECK-NEXT: br i1 [[COND]], label [[BB2:%.*]], label [[BB]]
201 ; CHECK-NEXT: ret ptr [[RHS]]
204 %tmp = getelementptr inbounds i32, ptr %A, i32 %Offset
208 %RHS = phi ptr [ %RHS.next, %bb ], [ %tmp, %entry ]
209 %LHS = getelementptr i32, ptr %A, i32 100
210 %RHS.next = getelementptr inbounds i32, ptr %RHS, i64 1
211 %cond = icmp ult ptr %LHS, %RHS
212 br i1 %cond, label %bb2, label %bb
218 ; An inttoptr that requires an extension or truncation will be opaque when determining
219 ; the base pointer. In this case we can still perform the transformation by considering
220 ; A.ptr as being the base pointer.
221 define ptr@test4(i16 %A, i32 %Offset) {
222 ; CHECK-LABEL: @test4(
224 ; CHECK-NEXT: [[TMP_IDX:%.*]] = shl nsw i32 [[OFFSET:%.*]], 2
225 ; CHECK-NEXT: br label [[BB:%.*]]
227 ; CHECK-NEXT: [[RHS_IDX:%.*]] = phi i32 [ [[RHS_ADD:%.*]], [[BB]] ], [ [[TMP_IDX]], [[ENTRY:%.*]] ]
228 ; CHECK-NEXT: [[RHS_ADD]] = add nsw i32 [[RHS_IDX]], 4
229 ; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 [[RHS_IDX]], 400
230 ; CHECK-NEXT: br i1 [[COND]], label [[BB2:%.*]], label [[BB]]
232 ; CHECK-NEXT: [[TMP0:%.*]] = zext i16 [[A:%.*]] to i32
233 ; CHECK-NEXT: [[A_PTR:%.*]] = inttoptr i32 [[TMP0]] to ptr
234 ; CHECK-NEXT: [[RHS_PTR:%.*]] = getelementptr inbounds i8, ptr [[A_PTR]], i32 [[RHS_IDX]]
235 ; CHECK-NEXT: ret ptr [[RHS_PTR]]
238 %A.ptr = inttoptr i16 %A to ptr
239 %tmp = getelementptr inbounds i32, ptr %A.ptr, i32 %Offset
243 %RHS = phi ptr [ %RHS.next, %bb ], [ %tmp, %entry ]
244 %LHS = getelementptr inbounds i32, ptr %A.ptr, i32 100
245 %RHS.next = getelementptr inbounds i32, ptr %RHS, i64 1
246 %cmp0 = ptrtoint ptr %LHS to i32
247 %cmp1 = ptrtoint ptr %RHS to i32
248 %cond = icmp ult i32 %cmp0, %cmp1
249 br i1 %cond, label %bb2, label %bb
255 declare ptr @fun_ptr()
257 define ptr@test5(i32 %Offset) personality ptr @__gxx_personality_v0 {
258 ; CHECK-LABEL: @test5(
260 ; CHECK-NEXT: [[A:%.*]] = invoke ptr @fun_ptr()
261 ; CHECK-NEXT: to label [[CONT:%.*]] unwind label [[LPAD:%.*]]
263 ; CHECK-NEXT: [[TMP_IDX:%.*]] = shl nsw i32 [[OFFSET:%.*]], 2
264 ; CHECK-NEXT: br label [[BB:%.*]]
266 ; CHECK-NEXT: [[RHS_IDX:%.*]] = phi i32 [ [[RHS_ADD:%.*]], [[BB]] ], [ [[TMP_IDX]], [[CONT]] ]
267 ; CHECK-NEXT: [[RHS_ADD]] = add nsw i32 [[RHS_IDX]], 4
268 ; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 [[RHS_IDX]], 400
269 ; CHECK-NEXT: br i1 [[COND]], label [[BB2:%.*]], label [[BB]]
271 ; CHECK-NEXT: [[RHS_PTR:%.*]] = getelementptr inbounds i8, ptr [[A]], i32 [[RHS_IDX]]
272 ; CHECK-NEXT: ret ptr [[RHS_PTR]]
274 ; CHECK-NEXT: [[L:%.*]] = landingpad { ptr, i32 }
275 ; CHECK-NEXT: cleanup
276 ; CHECK-NEXT: ret ptr null
279 %A = invoke ptr@fun_ptr() to label %cont unwind label %lpad
282 %tmp = getelementptr inbounds i32, ptr %A, i32 %Offset
286 %RHS = phi ptr [ %RHS.next, %bb ], [ %tmp, %cont ]
287 %LHS = getelementptr inbounds i32, ptr %A, i32 100
288 %RHS.next = getelementptr inbounds i32, ptr %RHS, i64 1
289 %cond = icmp ult ptr %LHS, %RHS
290 br i1 %cond, label %bb2, label %bb
296 %l = landingpad { ptr, i32 } cleanup
300 declare i32 @fun_i32()
302 define ptr@test6(i32 %Offset) personality ptr @__gxx_personality_v0 {
303 ; CHECK-LABEL: @test6(
305 ; CHECK-NEXT: [[A:%.*]] = invoke i32 @fun_i32()
306 ; CHECK-NEXT: to label [[CONT:%.*]] unwind label [[LPAD:%.*]]
308 ; CHECK-NEXT: [[TMP_IDX:%.*]] = shl nsw i32 [[OFFSET:%.*]], 2
309 ; CHECK-NEXT: br label [[BB:%.*]]
311 ; CHECK-NEXT: [[RHS_IDX:%.*]] = phi i32 [ [[RHS_ADD:%.*]], [[BB]] ], [ [[TMP_IDX]], [[CONT]] ]
312 ; CHECK-NEXT: [[RHS_ADD]] = add nsw i32 [[RHS_IDX]], 4
313 ; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 [[RHS_IDX]], 400
314 ; CHECK-NEXT: br i1 [[COND]], label [[BB2:%.*]], label [[BB]]
316 ; CHECK-NEXT: [[A_PTR:%.*]] = inttoptr i32 [[A]] to ptr
317 ; CHECK-NEXT: [[RHS_PTR:%.*]] = getelementptr inbounds i8, ptr [[A_PTR]], i32 [[RHS_IDX]]
318 ; CHECK-NEXT: ret ptr [[RHS_PTR]]
320 ; CHECK-NEXT: [[L:%.*]] = landingpad { ptr, i32 }
321 ; CHECK-NEXT: cleanup
322 ; CHECK-NEXT: ret ptr null
325 %A = invoke i32 @fun_i32() to label %cont unwind label %lpad
328 %A.ptr = inttoptr i32 %A to ptr
329 %tmp = getelementptr inbounds i32, ptr %A.ptr, i32 %Offset
333 %RHS = phi ptr [ %RHS.next, %bb ], [ %tmp, %cont ]
334 %LHS = getelementptr inbounds i32, ptr %A.ptr, i32 100
335 %RHS.next = getelementptr inbounds i32, ptr %RHS, i64 1
336 %cond = icmp ult ptr %LHS, %RHS
337 br i1 %cond, label %bb2, label %bb
343 %l = landingpad { ptr, i32 } cleanup
348 @pr30402 = constant i64 3
350 ; CHECK-LABEL: @test7(
352 ; CHECK-NEXT: br label [[BB7:%.*]]
354 ; CHECK-NEXT: [[CMP:%.*]] = phi i1 [ false, [[ENTRY:%.*]] ], [ true, [[BB7]] ]
355 ; CHECK-NEXT: br i1 [[CMP]], label [[BB10:%.*]], label [[BB7]]
357 ; CHECK-NEXT: ret i1 true
362 bb7: ; preds = %bb10, %entry-block
363 %phi = phi ptr [ @pr30402, %entry ], [ getelementptr inbounds (i64, ptr @pr30402, i32 1), %bb7 ]
364 %cmp = icmp eq ptr %phi, getelementptr inbounds (i64, ptr @pr30402, i32 1)
365 br i1 %cmp, label %bb10, label %bb7
371 declare i32 @__gxx_personality_v0(...)
373 define i1 @test8(ptr %in, i64 %offset) {
374 ; CHECK-LABEL: @test8(
376 ; CHECK-NEXT: [[LD:%.*]] = load i64, ptr [[IN:%.*]], align 8
377 ; CHECK-NEXT: [[TMP0:%.*]] = trunc i64 [[LD]] to i32
378 ; CHECK-NEXT: [[CASTI8:%.*]] = inttoptr i32 [[TMP0]] to ptr
379 ; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[OFFSET:%.*]] to i32
380 ; CHECK-NEXT: [[GEPI8:%.*]] = getelementptr inbounds i8, ptr [[CASTI8]], i32 [[TMP1]]
381 ; CHECK-NEXT: [[TMP2:%.*]] = trunc i64 [[LD]] to i32
382 ; CHECK-NEXT: [[PTRCAST:%.*]] = inttoptr i32 [[TMP2]] to ptr
383 ; CHECK-NEXT: [[GEPI32:%.*]] = getelementptr inbounds nuw i8, ptr [[PTRCAST]], i32 4
384 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[GEPI32]], [[GEPI8]]
385 ; CHECK-NEXT: ret i1 [[CMP]]
388 %ld = load i64, ptr %in, align 8
389 %casti8 = inttoptr i64 %ld to ptr
390 %gepi8 = getelementptr inbounds i8, ptr %casti8, i64 %offset
391 %ptrcast = inttoptr i64 %ld to ptr
392 %gepi32 = getelementptr inbounds ptr, ptr %ptrcast, i64 1
393 %cmp = icmp eq ptr %gepi32, %gepi8
397 define void @test_zero_offset_cycle(ptr %arg) {
398 ; CHECK-LABEL: @test_zero_offset_cycle(
400 ; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds nuw i8, ptr [[ARG:%.*]], i32 8
401 ; CHECK-NEXT: [[GEP_INT:%.*]] = ptrtoint ptr [[GEP]] to i32
402 ; CHECK-NEXT: br label [[LOOP:%.*]]
404 ; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ [[GEP_INT]], [[ENTRY:%.*]] ], [ [[GEP_INT2:%.*]], [[LOOP_CONT:%.*]] ], [ [[PHI]], [[LOOP]] ]
405 ; CHECK-NEXT: [[PHI_PTR:%.*]] = inttoptr i32 [[PHI]] to ptr
406 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[GEP]], [[PHI_PTR]]
407 ; CHECK-NEXT: br i1 [[CMP]], label [[LOOP]], label [[LOOP_CONT]]
409 ; CHECK-NEXT: [[GEP_INT2]] = ptrtoint ptr [[GEP]] to i32
410 ; CHECK-NEXT: br label [[LOOP]]
413 %gep = getelementptr inbounds { i64, i64 }, ptr %arg, i32 0, i32 1
414 %gep.int = ptrtoint ptr %gep to i32
418 %phi = phi i32 [ %gep.int, %entry ], [ %gep.int2, %loop.cont ], [ %phi, %loop ]
419 %phi.ptr = inttoptr i32 %phi to ptr
420 %cmp = icmp eq ptr %gep, %phi.ptr
421 br i1 %cmp, label %loop, label %loop.cont
424 %gep.int2 = ptrtoint ptr %gep to i32