1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt < %s -passes='instcombine<use-loop-info>' -S | FileCheck %s
4 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
5 target triple = "x86_64-unknown-linux-gnu"
7 define i32 @foo(ptr nocapture readnone %match, i32 %cur_match, i32 %best_len, i32 %scan_end, ptr nocapture readonly %prev, i32 %limit, i32 %chain_length, ptr nocapture readonly %win, i32 %wmask) {
10 ; CHECK-NEXT: [[IDX_EXT2:%.*]] = zext i32 [[CUR_MATCH:%.*]] to i64
11 ; CHECK-NEXT: [[ADD_PTR4:%.*]] = getelementptr inbounds i8, ptr [[WIN:%.*]], i64 [[IDX_EXT2]]
12 ; CHECK-NEXT: [[IDX_EXT1:%.*]] = zext i32 [[BEST_LEN:%.*]] to i64
13 ; CHECK-NEXT: [[ADD_PTR25:%.*]] = getelementptr inbounds i8, ptr [[ADD_PTR4]], i64 [[IDX_EXT1]]
14 ; CHECK-NEXT: [[ADD_PTR36:%.*]] = getelementptr inbounds i8, ptr [[ADD_PTR25]], i64 -1
15 ; CHECK-NEXT: [[I1:%.*]] = load i32, ptr [[ADD_PTR36]], align 4
16 ; CHECK-NEXT: [[CMP7:%.*]] = icmp eq i32 [[I1]], [[SCAN_END:%.*]]
17 ; CHECK-NEXT: br i1 [[CMP7]], label [[DO_END:%.*]], label [[IF_THEN_LR_PH:%.*]]
18 ; CHECK: if.then.lr.ph:
19 ; CHECK-NEXT: br label [[IF_THEN:%.*]]
21 ; CHECK-NEXT: [[IDX_EXT:%.*]] = zext i32 [[I4:%.*]] to i64
22 ; CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds i8, ptr [[WIN]], i64 [[IDX_EXT]]
23 ; CHECK-NEXT: [[ADD_PTR2:%.*]] = getelementptr inbounds i8, ptr [[ADD_PTR]], i64 [[IDX_EXT1]]
24 ; CHECK-NEXT: [[ADD_PTR3:%.*]] = getelementptr inbounds i8, ptr [[ADD_PTR2]], i64 -1
25 ; CHECK-NEXT: [[I3:%.*]] = load i32, ptr [[ADD_PTR3]], align 4
26 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[I3]], [[SCAN_END]]
27 ; CHECK-NEXT: br i1 [[CMP]], label [[DO_END]], label [[IF_THEN]]
29 ; CHECK-NEXT: [[CUR_MATCH_ADDR_09:%.*]] = phi i32 [ [[CUR_MATCH]], [[IF_THEN_LR_PH]] ], [ [[I4]], [[DO_BODY:%.*]] ]
30 ; CHECK-NEXT: [[CHAIN_LENGTH_ADDR_08:%.*]] = phi i32 [ [[CHAIN_LENGTH:%.*]], [[IF_THEN_LR_PH]] ], [ [[DEC:%.*]], [[DO_BODY]] ]
31 ; CHECK-NEXT: [[AND:%.*]] = and i32 [[CUR_MATCH_ADDR_09]], [[WMASK:%.*]]
32 ; CHECK-NEXT: [[IDXPROM:%.*]] = zext i32 [[AND]] to i64
33 ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[PREV:%.*]], i64 [[IDXPROM]]
34 ; CHECK-NEXT: [[I4]] = load i32, ptr [[ARRAYIDX]], align 4
35 ; CHECK-NEXT: [[CMP4:%.*]] = icmp ugt i32 [[I4]], [[LIMIT:%.*]]
36 ; CHECK-NEXT: br i1 [[CMP4]], label [[LAND_LHS_TRUE:%.*]], label [[DO_END]]
37 ; CHECK: land.lhs.true:
38 ; CHECK-NEXT: [[DEC]] = add i32 [[CHAIN_LENGTH_ADDR_08]], -1
39 ; CHECK-NEXT: [[CMP5:%.*]] = icmp eq i32 [[DEC]], 0
40 ; CHECK-NEXT: br i1 [[CMP5]], label [[DO_END]], label [[DO_BODY]]
42 ; CHECK-NEXT: [[CONT_0:%.*]] = phi i32 [ 1, [[ENTRY:%.*]] ], [ 0, [[IF_THEN]] ], [ 0, [[LAND_LHS_TRUE]] ], [ 1, [[DO_BODY]] ]
43 ; CHECK-NEXT: ret i32 [[CONT_0]]
46 %idx.ext2 = zext i32 %cur_match to i64
47 %add.ptr4 = getelementptr inbounds i8, ptr %win, i64 %idx.ext2
48 %idx.ext1 = zext i32 %best_len to i64
49 %add.ptr25 = getelementptr inbounds i8, ptr %add.ptr4, i64 %idx.ext1
50 %add.ptr36 = getelementptr inbounds i8, ptr %add.ptr25, i64 -1
51 %i1 = load i32, ptr %add.ptr36, align 4
52 %cmp7 = icmp eq i32 %i1, %scan_end
53 br i1 %cmp7, label %do.end, label %if.then.lr.ph
55 if.then.lr.ph: ; preds = %entry
58 do.body: ; preds = %land.lhs.true
59 %chain_length.addr.0 = phi i32 [ %dec, %land.lhs.true ]
60 %cur_match.addr.0 = phi i32 [ %i4, %land.lhs.true ]
61 %idx.ext = zext i32 %cur_match.addr.0 to i64
62 %add.ptr = getelementptr inbounds i8, ptr %win, i64 %idx.ext
63 %add.ptr2 = getelementptr inbounds i8, ptr %add.ptr, i64 %idx.ext1
64 %add.ptr3 = getelementptr inbounds i8, ptr %add.ptr2, i64 -1
65 %i3 = load i32, ptr %add.ptr3, align 4
66 %cmp = icmp eq i32 %i3, %scan_end
67 br i1 %cmp, label %do.end, label %if.then
69 if.then: ; preds = %do.body, %if.then.lr.ph
70 %cur_match.addr.09 = phi i32 [ %cur_match, %if.then.lr.ph ], [ %cur_match.addr.0, %do.body ]
71 %chain_length.addr.08 = phi i32 [ %chain_length, %if.then.lr.ph ], [ %chain_length.addr.0, %do.body ]
72 %and = and i32 %cur_match.addr.09, %wmask
73 %idxprom = zext i32 %and to i64
74 %arrayidx = getelementptr inbounds i32, ptr %prev, i64 %idxprom
75 %i4 = load i32, ptr %arrayidx, align 4
76 %cmp4 = icmp ugt i32 %i4, %limit
77 br i1 %cmp4, label %land.lhs.true, label %do.end
79 land.lhs.true: ; preds = %if.then
80 %dec = add i32 %chain_length.addr.08, -1
81 %cmp5 = icmp eq i32 %dec, 0
82 br i1 %cmp5, label %do.end, label %do.body
84 do.end: ; preds = %land.lhs.true, %if.then, %do.body, %entry
85 %cont.0 = phi i32 [ 1, %entry ], [ 0, %if.then ], [ 0, %land.lhs.true ], [ 1, %do.body ]
89 declare void @blackhole(<2 x ptr>)
91 define void @PR37005(ptr %base, ptr %in) {
92 ; CHECK-LABEL: @PR37005(
94 ; CHECK-NEXT: br label [[LOOP:%.*]]
96 ; CHECK-NEXT: [[E1:%.*]] = getelementptr inbounds ptr, ptr [[IN:%.*]], i64 undef
97 ; CHECK-NEXT: [[E2:%.*]] = getelementptr inbounds i8, ptr [[E1]], i64 48
98 ; CHECK-NEXT: [[E4:%.*]] = getelementptr inbounds ptr, ptr [[E2]], <2 x i64> <i64 0, i64 1>
99 ; CHECK-NEXT: [[PI1:%.*]] = ptrtoint <2 x ptr> [[E4]] to <2 x i64>
100 ; CHECK-NEXT: [[TMP0:%.*]] = lshr <2 x i64> [[PI1]], <i64 14, i64 14>
101 ; CHECK-NEXT: [[SL1:%.*]] = and <2 x i64> [[TMP0]], <i64 1125899906842496, i64 1125899906842496>
102 ; CHECK-NEXT: [[E5:%.*]] = getelementptr inbounds i8, ptr [[BASE:%.*]], <2 x i64> [[SL1]]
103 ; CHECK-NEXT: [[E6:%.*]] = getelementptr inbounds i8, <2 x ptr> [[E5]], i64 80
104 ; CHECK-NEXT: call void @blackhole(<2 x ptr> [[E6]])
105 ; CHECK-NEXT: br label [[LOOP]]
110 loop: ; preds = %loop, %entry
111 %e1 = getelementptr inbounds ptr, ptr %in, i64 undef
112 %e2 = getelementptr inbounds ptr, ptr %e1, i64 6
113 %e4 = getelementptr inbounds ptr, ptr %e2, <2 x i64> <i64 0, i64 1>
114 %pi1 = ptrtoint <2 x ptr> %e4 to <2 x i64>
115 %lr1 = lshr <2 x i64> %pi1, <i64 21, i64 21>
116 %sl1 = shl nuw nsw <2 x i64> %lr1, <i64 7, i64 7>
117 %e5 = getelementptr inbounds i8, ptr %base, <2 x i64> %sl1
118 %e6 = getelementptr inbounds i8, <2 x ptr> %e5, i64 80
119 call void @blackhole(<2 x ptr> %e6)
123 define void @PR37005_2(ptr %base, ptr %in) {
124 ; CHECK-LABEL: @PR37005_2(
126 ; CHECK-NEXT: br label [[LOOP:%.*]]
128 ; CHECK-NEXT: [[E1:%.*]] = getelementptr inbounds ptr, ptr [[IN:%.*]], i64 undef
129 ; CHECK-NEXT: [[E2:%.*]] = getelementptr inbounds i8, ptr [[E1]], i64 48
130 ; CHECK-NEXT: [[PI1:%.*]] = ptrtoint ptr [[E2]] to i64
131 ; CHECK-NEXT: [[TMP0:%.*]] = lshr i64 [[PI1]], 14
132 ; CHECK-NEXT: [[SL1:%.*]] = and i64 [[TMP0]], 1125899906842496
133 ; CHECK-NEXT: [[E5:%.*]] = getelementptr inbounds i8, ptr [[BASE:%.*]], i64 [[SL1]]
134 ; CHECK-NEXT: [[E6:%.*]] = getelementptr inbounds i8, ptr [[E5]], <2 x i64> <i64 80, i64 60>
135 ; CHECK-NEXT: call void @blackhole(<2 x ptr> [[E6]])
136 ; CHECK-NEXT: br label [[LOOP]]
141 loop: ; preds = %loop, %entry
142 %e1 = getelementptr inbounds ptr, ptr %in, i64 undef
143 %e2 = getelementptr inbounds ptr, ptr %e1, i64 6
144 %pi1 = ptrtoint ptr %e2 to i64
145 %lr1 = lshr i64 %pi1, 21
146 %sl1 = shl nuw nsw i64 %lr1, 7
147 %e5 = getelementptr inbounds i8, ptr %base, i64 %sl1
148 %e6 = getelementptr inbounds i8, ptr %e5, <2 x i64> <i64 80, i64 60>
149 call void @blackhole(<2 x ptr> %e6)
153 define void @PR37005_3(<2 x ptr> %base, ptr %in) {
154 ; CHECK-LABEL: @PR37005_3(
156 ; CHECK-NEXT: br label [[LOOP:%.*]]
158 ; CHECK-NEXT: [[E1:%.*]] = getelementptr inbounds ptr, ptr [[IN:%.*]], i64 undef
159 ; CHECK-NEXT: [[E2:%.*]] = getelementptr inbounds i8, ptr [[E1]], i64 48
160 ; CHECK-NEXT: [[E4:%.*]] = getelementptr inbounds ptr, ptr [[E2]], <2 x i64> <i64 0, i64 1>
161 ; CHECK-NEXT: [[PI1:%.*]] = ptrtoint <2 x ptr> [[E4]] to <2 x i64>
162 ; CHECK-NEXT: [[TMP0:%.*]] = lshr <2 x i64> [[PI1]], <i64 14, i64 14>
163 ; CHECK-NEXT: [[SL1:%.*]] = and <2 x i64> [[TMP0]], <i64 1125899906842496, i64 1125899906842496>
164 ; CHECK-NEXT: [[E5:%.*]] = getelementptr inbounds i8, <2 x ptr> [[BASE:%.*]], <2 x i64> [[SL1]]
165 ; CHECK-NEXT: [[E6:%.*]] = getelementptr inbounds i8, <2 x ptr> [[E5]], i64 80
166 ; CHECK-NEXT: call void @blackhole(<2 x ptr> [[E6]])
167 ; CHECK-NEXT: br label [[LOOP]]
172 loop: ; preds = %loop, %entry
173 %e1 = getelementptr inbounds ptr, ptr %in, i64 undef
174 %e2 = getelementptr inbounds ptr, ptr %e1, i64 6
175 %e4 = getelementptr inbounds ptr, ptr %e2, <2 x i64> <i64 0, i64 1>
176 %pi1 = ptrtoint <2 x ptr> %e4 to <2 x i64>
177 %lr1 = lshr <2 x i64> %pi1, <i64 21, i64 21>
178 %sl1 = shl nuw nsw <2 x i64> %lr1, <i64 7, i64 7>
179 %e5 = getelementptr inbounds i8, <2 x ptr> %base, <2 x i64> %sl1
180 %e6 = getelementptr inbounds i8, <2 x ptr> %e5, i64 80
181 call void @blackhole(<2 x ptr> %e6)
185 ; This would crash because we did not expect to be able to constant fold a GEP.
187 define void @PR51485(<2 x i64> %v) {
188 ; CHECK-LABEL: @PR51485(
190 ; CHECK-NEXT: br label [[LOOP:%.*]]
192 ; CHECK-NEXT: [[SL1:%.*]] = shl nuw nsw <2 x i64> [[V:%.*]], <i64 7, i64 7>
193 ; CHECK-NEXT: [[E5:%.*]] = getelementptr inbounds i8, ptr @PR51485, <2 x i64> [[SL1]]
194 ; CHECK-NEXT: [[E6:%.*]] = getelementptr inbounds i8, <2 x ptr> [[E5]], i64 80
195 ; CHECK-NEXT: call void @blackhole(<2 x ptr> [[E6]])
196 ; CHECK-NEXT: br label [[LOOP]]
201 loop: ; preds = %loop, %entry
202 %sl1 = shl nuw nsw <2 x i64> %v, <i64 7, i64 7>
203 %e5 = getelementptr inbounds i8, ptr @PR51485, <2 x i64> %sl1
204 %e6 = getelementptr inbounds i8, <2 x ptr> %e5, i64 80
205 call void @blackhole(<2 x ptr> %e6)
209 ; Avoid folding the GEP outside the loop to inside, and increasing loop
211 define float @gep_cross_loop(ptr %_arg_, ptr %_arg_3, float %_arg_8) {
212 ; CHECK-LABEL: @gep_cross_loop(
214 ; CHECK-NEXT: [[I:%.*]] = load i64, ptr [[_ARG_:%.*]], align 8
215 ; CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds float, ptr [[_ARG_3:%.*]], i64 [[I]]
216 ; CHECK-NEXT: br label [[FOR_COND_I:%.*]]
218 ; CHECK-NEXT: [[IDX:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[ADD11_I:%.*]], [[FOR_BODY_I:%.*]] ]
219 ; CHECK-NEXT: [[SUM:%.*]] = phi float [ 0.000000e+00, [[ENTRY]] ], [ [[ADD_I:%.*]], [[FOR_BODY_I]] ]
220 ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[IDX]], 17
221 ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY_I]], label [[FOR_COND_I_I_I_PREHEADER:%.*]]
222 ; CHECK: for.cond.i.i.i.preheader:
223 ; CHECK-NEXT: ret float [[SUM]]
225 ; CHECK-NEXT: [[ARRAYIDX_I84_I:%.*]] = getelementptr inbounds float, ptr [[ADD_PTR]], i64 [[IDX]]
226 ; CHECK-NEXT: [[I1:%.*]] = load float, ptr [[ARRAYIDX_I84_I]], align 4
227 ; CHECK-NEXT: [[ADD_I]] = fadd fast float [[SUM]], [[I1]]
228 ; CHECK-NEXT: [[ADD11_I]] = add nuw nsw i64 [[IDX]], 1
229 ; CHECK-NEXT: br label [[FOR_COND_I]]
232 %i = load i64, ptr %_arg_, align 8
233 %add.ptr = getelementptr inbounds float, ptr %_arg_3, i64 %i
236 for.cond.i: ; preds = %for.body.i, %entry
237 %idx = phi i64 [ 0, %entry ], [ %add11.i, %for.body.i ]
238 %sum = phi float [ 0.000000e+00, %entry ], [ %add.i, %for.body.i ]
239 %cmp = icmp ule i64 %idx, 16
240 br i1 %cmp, label %for.body.i, label %for.cond.i.i.i.preheader
242 for.cond.i.i.i.preheader: ; preds = %for.cond.i
245 for.body.i: ; preds = %for.cond.i
246 %arrayidx.i84.i = getelementptr inbounds float, ptr %add.ptr, i64 %idx
247 %i1 = load float, ptr %arrayidx.i84.i, align 4
248 %add.i = fadd fast float %sum, %i1
249 %add11.i = add nsw i64 %idx, 1
253 declare void @use(ptr)
255 define void @only_one_inbounds(ptr %ptr, i1 %c, i32 noundef %arg1, i32 noundef %arg2) {
256 ; CHECK-LABEL: @only_one_inbounds(
258 ; CHECK-NEXT: [[ARG2_EXT:%.*]] = zext i32 [[ARG2:%.*]] to i64
259 ; CHECK-NEXT: br label [[LOOP:%.*]]
261 ; CHECK-NEXT: [[ARG1_EXT:%.*]] = zext i32 [[ARG1:%.*]] to i64
262 ; CHECK-NEXT: [[PTR2:%.*]] = getelementptr inbounds i8, ptr [[PTR:%.*]], i64 [[ARG1_EXT]]
263 ; CHECK-NEXT: [[PTR3:%.*]] = getelementptr i8, ptr [[PTR2]], i64 [[ARG2_EXT]]
264 ; CHECK-NEXT: call void @use(ptr [[PTR3]])
265 ; CHECK-NEXT: br i1 [[C:%.*]], label [[LOOP]], label [[EXIT:%.*]]
267 ; CHECK-NEXT: ret void
270 %arg2.ext = zext i32 %arg2 to i64
273 loop: ; preds = %loop, %entry
274 %arg1.ext = zext i32 %arg1 to i64
275 %ptr2 = getelementptr inbounds i8, ptr %ptr, i64 %arg1.ext
276 %ptr3 = getelementptr i8, ptr %ptr2, i64 %arg2.ext
277 call void @use(ptr %ptr3)
278 br i1 %c, label %loop, label %exit
280 exit: ; preds = %loop
284 define void @both_inbounds_one_neg(ptr %ptr, i1 %c, i32 noundef %arg) {
285 ; CHECK-LABEL: @both_inbounds_one_neg(
287 ; CHECK-NEXT: br label [[LOOP:%.*]]
289 ; CHECK-NEXT: [[ARG_EXT:%.*]] = zext i32 [[ARG:%.*]] to i64
290 ; CHECK-NEXT: [[PTR2:%.*]] = getelementptr inbounds i8, ptr [[PTR:%.*]], i64 [[ARG_EXT]]
291 ; CHECK-NEXT: [[PTR3:%.*]] = getelementptr inbounds i8, ptr [[PTR2]], i64 -1
292 ; CHECK-NEXT: call void @use(ptr nonnull [[PTR3]])
293 ; CHECK-NEXT: br i1 [[C:%.*]], label [[LOOP]], label [[EXIT:%.*]]
295 ; CHECK-NEXT: ret void
300 loop: ; preds = %loop, %entry
301 %arg.ext = zext i32 %arg to i64
302 %ptr2 = getelementptr inbounds i8, ptr %ptr, i64 %arg.ext
303 %ptr3 = getelementptr inbounds i8, ptr %ptr2, i64 -1
304 call void @use(ptr %ptr3)
305 br i1 %c, label %loop, label %exit
307 exit: ; preds = %loop
311 define void @both_inbounds_pos(ptr %ptr, i1 %c, i32 noundef %arg) {
312 ; CHECK-LABEL: @both_inbounds_pos(
314 ; CHECK-NEXT: br label [[LOOP:%.*]]
316 ; CHECK-NEXT: [[ARG_EXT:%.*]] = zext i32 [[ARG:%.*]] to i64
317 ; CHECK-NEXT: [[PTR2:%.*]] = getelementptr inbounds i8, ptr [[PTR:%.*]], i64 [[ARG_EXT]]
318 ; CHECK-NEXT: [[PTR3:%.*]] = getelementptr inbounds i8, ptr [[PTR2]], i64 1
319 ; CHECK-NEXT: call void @use(ptr nonnull [[PTR3]])
320 ; CHECK-NEXT: br i1 [[C:%.*]], label [[LOOP]], label [[EXIT:%.*]]
322 ; CHECK-NEXT: ret void
327 loop: ; preds = %loop, %entry
328 %arg.ext = zext i32 %arg to i64
329 %ptr2 = getelementptr inbounds i8, ptr %ptr, i64 %arg.ext
330 %ptr3 = getelementptr inbounds i8, ptr %ptr2, i64 1
331 call void @use(ptr %ptr3)
332 br i1 %c, label %loop, label %exit
334 exit: ; preds = %loop