xref: /llvm-project/llvm/test/Transforms/LoopPredication/invariant_load.ll (revision 99da317331e37d530610695b0cf44ba2686b735e)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt -S -passes=loop-predication < %s 2>&1 | FileCheck %s
3; RUN: opt -S -aa-pipeline=basic-aa -passes='require<aa>,require<scalar-evolution>,loop-mssa(loop-predication)' -verify-memoryssa < %s 2>&1 | FileCheck %s
4
5declare void @llvm.experimental.guard(i1, ...)
6
7@UNKNOWN = external global i1
8
9define i32 @neg_length_variant(ptr %array, ptr %length, i32 %n) {
10; CHECK-LABEL: @neg_length_variant(
11; CHECK-NEXT:  entry:
12; CHECK-NEXT:    [[TMP5:%.*]] = icmp eq i32 [[N:%.*]], 0
13; CHECK-NEXT:    br i1 [[TMP5]], label [[EXIT:%.*]], label [[LOOP_PREHEADER:%.*]]
14; CHECK:       loop.preheader:
15; CHECK-NEXT:    br label [[LOOP:%.*]]
16; CHECK:       loop:
17; CHECK-NEXT:    [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
18; CHECK-NEXT:    [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
19; CHECK-NEXT:    [[UNKNOWN:%.*]] = load volatile i1, ptr @UNKNOWN, align 1
20; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[UNKNOWN]]) [ "deopt"() ]
21; CHECK-NEXT:    [[LEN:%.*]] = load i32, ptr [[LENGTH:%.*]], align 4
22; CHECK-NEXT:    [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I]], [[LEN]]
23; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WITHIN_BOUNDS]], i32 9) [ "deopt"() ]
24; CHECK-NEXT:    [[I_I64:%.*]] = zext i32 [[I]] to i64
25; CHECK-NEXT:    [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY:%.*]], i64 [[I_I64]]
26; CHECK-NEXT:    [[ARRAY_I:%.*]] = load i32, ptr [[ARRAY_I_PTR]], align 4
27; CHECK-NEXT:    [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
28; CHECK-NEXT:    [[I_NEXT]] = add nuw i32 [[I]], 1
29; CHECK-NEXT:    [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], [[N]]
30; CHECK-NEXT:    br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]]
31; CHECK:       exit.loopexit:
32; CHECK-NEXT:    [[LOOP_ACC_NEXT_LCSSA:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[LOOP]] ]
33; CHECK-NEXT:    br label [[EXIT]]
34; CHECK:       exit:
35; CHECK-NEXT:    [[RESULT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[LOOP_ACC_NEXT_LCSSA]], [[EXIT_LOOPEXIT]] ]
36; CHECK-NEXT:    ret i32 [[RESULT]]
37;
38entry:
39  %tmp5 = icmp eq i32 %n, 0
40  br i1 %tmp5, label %exit, label %loop.preheader
41
42loop.preheader:
43  br label %loop
44
45loop:
46  %loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ]
47  %i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
48  %unknown = load volatile i1, ptr @UNKNOWN
49  call void (i1, ...) @llvm.experimental.guard(i1 %unknown) [ "deopt"() ]
50  %len = load i32, ptr %length, align 4
51  %within.bounds = icmp ult i32 %i, %len
52  call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
53
54  %i.i64 = zext i32 %i to i64
55  %array.i.ptr = getelementptr inbounds i32, ptr %array, i64 %i.i64
56  %array.i = load i32, ptr %array.i.ptr, align 4
57  %loop.acc.next = add i32 %loop.acc, %array.i
58
59  %i.next = add nuw i32 %i, 1
60  %continue = icmp ult i32 %i.next, %n
61  br i1 %continue, label %loop, label %exit
62
63exit:
64  %result = phi i32 [ 0, %entry ], [ %loop.acc.next, %loop ]
65  ret i32 %result
66}
67
68define i32 @invariant_load_guard_limit(ptr %array, ptr %length, i32 %n) {
69; CHECK-LABEL: @invariant_load_guard_limit(
70; CHECK-NEXT:  entry:
71; CHECK-NEXT:    [[TMP5:%.*]] = icmp eq i32 [[N:%.*]], 0
72; CHECK-NEXT:    br i1 [[TMP5]], label [[EXIT:%.*]], label [[LOOP_PREHEADER:%.*]]
73; CHECK:       loop.preheader:
74; CHECK-NEXT:    br label [[LOOP:%.*]]
75; CHECK:       loop:
76; CHECK-NEXT:    [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
77; CHECK-NEXT:    [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
78; CHECK-NEXT:    [[UNKNOWN:%.*]] = load volatile i1, ptr @UNKNOWN, align 1
79; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[UNKNOWN]]) [ "deopt"() ]
80; CHECK-NEXT:    [[LEN:%.*]] = load i32, ptr [[LENGTH:%.*]], align 4, !invariant.load !0
81; CHECK-NEXT:    [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I]], [[LEN]]
82; CHECK-NEXT:    [[TMP0:%.*]] = icmp ule i32 [[N]], [[LEN]]
83; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult i32 0, [[LEN]]
84; CHECK-NEXT:    [[TMP2:%.*]] = and i1 [[TMP1]], [[TMP0]]
85; CHECK-NEXT:    [[TMP3:%.*]] = freeze i1 [[TMP2]]
86; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[TMP3]], i32 9) [ "deopt"() ]
87; CHECK-NEXT:    call void @llvm.assume(i1 [[WITHIN_BOUNDS]])
88; CHECK-NEXT:    [[I_I64:%.*]] = zext i32 [[I]] to i64
89; CHECK-NEXT:    [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY:%.*]], i64 [[I_I64]]
90; CHECK-NEXT:    [[ARRAY_I:%.*]] = load i32, ptr [[ARRAY_I_PTR]], align 4
91; CHECK-NEXT:    [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
92; CHECK-NEXT:    [[I_NEXT]] = add nuw i32 [[I]], 1
93; CHECK-NEXT:    [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], [[N]]
94; CHECK-NEXT:    br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]]
95; CHECK:       exit.loopexit:
96; CHECK-NEXT:    [[LOOP_ACC_NEXT_LCSSA:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[LOOP]] ]
97; CHECK-NEXT:    br label [[EXIT]]
98; CHECK:       exit:
99; CHECK-NEXT:    [[RESULT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[LOOP_ACC_NEXT_LCSSA]], [[EXIT_LOOPEXIT]] ]
100; CHECK-NEXT:    ret i32 [[RESULT]]
101;
102entry:
103  %tmp5 = icmp eq i32 %n, 0
104  br i1 %tmp5, label %exit, label %loop.preheader
105
106loop.preheader:
107  br label %loop
108
109loop:
110  %loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ]
111  %i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
112  %unknown = load volatile i1, ptr @UNKNOWN
113  call void (i1, ...) @llvm.experimental.guard(i1 %unknown) [ "deopt"() ]
114  %len = load i32, ptr %length, align 4, !invariant.load !{}
115  %within.bounds = icmp ult i32 %i, %len
116  call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
117
118  %i.i64 = zext i32 %i to i64
119  %array.i.ptr = getelementptr inbounds i32, ptr %array, i64 %i.i64
120  %array.i = load i32, ptr %array.i.ptr, align 4
121  %loop.acc.next = add i32 %loop.acc, %array.i
122
123  %i.next = add nuw i32 %i, 1
124  %continue = icmp ult i32 %i.next, %n
125  br i1 %continue, label %loop, label %exit
126
127exit:
128  %result = phi i32 [ 0, %entry ], [ %loop.acc.next, %loop ]
129  ret i32 %result
130}
131
132; Case where we have an invariant load, but it's not loading from a loop
133; invariant location.
134define i32 @neg_varying_invariant_load_op(ptr %array, ptr %lengths, i32 %n) {
135; CHECK-LABEL: @neg_varying_invariant_load_op(
136; CHECK-NEXT:  entry:
137; CHECK-NEXT:    [[TMP5:%.*]] = icmp eq i32 [[N:%.*]], 0
138; CHECK-NEXT:    br i1 [[TMP5]], label [[EXIT:%.*]], label [[LOOP_PREHEADER:%.*]]
139; CHECK:       loop.preheader:
140; CHECK-NEXT:    br label [[LOOP:%.*]]
141; CHECK:       loop:
142; CHECK-NEXT:    [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
143; CHECK-NEXT:    [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
144; CHECK-NEXT:    [[UNKNOWN:%.*]] = load volatile i1, ptr @UNKNOWN, align 1
145; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[UNKNOWN]]) [ "deopt"() ]
146; CHECK-NEXT:    [[LENGTH_ADDR:%.*]] = getelementptr i32, ptr [[LENGTHS:%.*]], i32 [[I]]
147; CHECK-NEXT:    [[LEN:%.*]] = load i32, ptr [[LENGTH_ADDR]], align 4, !invariant.load !0
148; CHECK-NEXT:    [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I]], [[LEN]]
149; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WITHIN_BOUNDS]], i32 9) [ "deopt"() ]
150; CHECK-NEXT:    [[I_I64:%.*]] = zext i32 [[I]] to i64
151; CHECK-NEXT:    [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY:%.*]], i64 [[I_I64]]
152; CHECK-NEXT:    [[ARRAY_I:%.*]] = load i32, ptr [[ARRAY_I_PTR]], align 4
153; CHECK-NEXT:    [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
154; CHECK-NEXT:    [[I_NEXT]] = add nuw i32 [[I]], 1
155; CHECK-NEXT:    [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], [[N]]
156; CHECK-NEXT:    br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]]
157; CHECK:       exit.loopexit:
158; CHECK-NEXT:    [[LOOP_ACC_NEXT_LCSSA:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[LOOP]] ]
159; CHECK-NEXT:    br label [[EXIT]]
160; CHECK:       exit:
161; CHECK-NEXT:    [[RESULT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[LOOP_ACC_NEXT_LCSSA]], [[EXIT_LOOPEXIT]] ]
162; CHECK-NEXT:    ret i32 [[RESULT]]
163;
164entry:
165  %tmp5 = icmp eq i32 %n, 0
166  br i1 %tmp5, label %exit, label %loop.preheader
167
168loop.preheader:
169  br label %loop
170
171loop:
172  %loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ]
173  %i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
174  %unknown = load volatile i1, ptr @UNKNOWN
175  call void (i1, ...) @llvm.experimental.guard(i1 %unknown) [ "deopt"() ]
176
177  %length.addr = getelementptr i32, ptr %lengths, i32 %i
178  %len = load i32, ptr %length.addr, align 4, !invariant.load !{}
179  %within.bounds = icmp ult i32 %i, %len
180  call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
181
182  %i.i64 = zext i32 %i to i64
183  %array.i.ptr = getelementptr inbounds i32, ptr %array, i64 %i.i64
184  %array.i = load i32, ptr %array.i.ptr, align 4
185  %loop.acc.next = add i32 %loop.acc, %array.i
186
187  %i.next = add nuw i32 %i, 1
188  %continue = icmp ult i32 %i.next, %n
189  br i1 %continue, label %loop, label %exit
190
191exit:
192  %result = phi i32 [ 0, %entry ], [ %loop.acc.next, %loop ]
193  ret i32 %result
194}
195
196; This is a case where moving the load which provides the limit for the latch
197; would be invalid, so we can't preform the tempting transform.  Loading the
198; latch limit may fault since we could always fail the guard.
199define i32 @neg_invariant_load_latch_limit(ptr %array, ptr %length, i32 %n) {
200; CHECK-LABEL: @neg_invariant_load_latch_limit(
201; CHECK-NEXT:  entry:
202; CHECK-NEXT:    [[TMP5:%.*]] = icmp eq i32 [[N:%.*]], 0
203; CHECK-NEXT:    br i1 [[TMP5]], label [[EXIT:%.*]], label [[LOOP_PREHEADER:%.*]]
204; CHECK:       loop.preheader:
205; CHECK-NEXT:    br label [[LOOP:%.*]]
206; CHECK:       loop:
207; CHECK-NEXT:    [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
208; CHECK-NEXT:    [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
209; CHECK-NEXT:    [[UNKNOWN:%.*]] = load volatile i1, ptr @UNKNOWN, align 1
210; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[UNKNOWN]]) [ "deopt"() ]
211; CHECK-NEXT:    [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I]], [[N]]
212; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WITHIN_BOUNDS]], i32 9) [ "deopt"() ]
213; CHECK-NEXT:    [[I_I64:%.*]] = zext i32 [[I]] to i64
214; CHECK-NEXT:    [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY:%.*]], i64 [[I_I64]]
215; CHECK-NEXT:    [[ARRAY_I:%.*]] = load i32, ptr [[ARRAY_I_PTR]], align 4
216; CHECK-NEXT:    [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
217; CHECK-NEXT:    [[I_NEXT]] = add nuw i32 [[I]], 1
218; CHECK-NEXT:    [[LEN:%.*]] = load i32, ptr [[LENGTH:%.*]], align 4, !invariant.load !0
219; CHECK-NEXT:    [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], [[LEN]]
220; CHECK-NEXT:    br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]]
221; CHECK:       exit.loopexit:
222; CHECK-NEXT:    [[LOOP_ACC_NEXT_LCSSA:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[LOOP]] ]
223; CHECK-NEXT:    br label [[EXIT]]
224; CHECK:       exit:
225; CHECK-NEXT:    [[RESULT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[LOOP_ACC_NEXT_LCSSA]], [[EXIT_LOOPEXIT]] ]
226; CHECK-NEXT:    ret i32 [[RESULT]]
227;
228entry:
229  %tmp5 = icmp eq i32 %n, 0
230  br i1 %tmp5, label %exit, label %loop.preheader
231
232loop.preheader:
233  br label %loop
234
235loop:
236  %loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ]
237  %i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
238  %unknown = load volatile i1, ptr @UNKNOWN
239  call void (i1, ...) @llvm.experimental.guard(i1 %unknown) [ "deopt"() ]
240  %within.bounds = icmp ult i32 %i, %n
241  call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
242
243  %i.i64 = zext i32 %i to i64
244  %array.i.ptr = getelementptr inbounds i32, ptr %array, i64 %i.i64
245  %array.i = load i32, ptr %array.i.ptr, align 4
246  %loop.acc.next = add i32 %loop.acc, %array.i
247
248  %i.next = add nuw i32 %i, 1
249  %len = load i32, ptr %length, align 4, !invariant.load !{}
250  %continue = icmp ult i32 %i.next, %len
251  br i1 %continue, label %loop, label %exit
252
253exit:
254  %result = phi i32 [ 0, %entry ], [ %loop.acc.next, %loop ]
255  ret i32 %result
256}
257
258define i32 @invariant_load_latch_limit(ptr %array,
259; CHECK-LABEL: @invariant_load_latch_limit(
260; CHECK-NEXT:  entry:
261; CHECK-NEXT:    [[TMP5:%.*]] = icmp eq i32 [[N:%.*]], 0
262; CHECK-NEXT:    br i1 [[TMP5]], label [[EXIT:%.*]], label [[LOOP_PREHEADER:%.*]]
263; CHECK:       loop.preheader:
264; CHECK-NEXT:    br label [[LOOP:%.*]]
265; CHECK:       loop:
266; CHECK-NEXT:    [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
267; CHECK-NEXT:    [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
268; CHECK-NEXT:    [[UNKNOWN:%.*]] = load volatile i1, ptr @UNKNOWN, align 1
269; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[UNKNOWN]]) [ "deopt"() ]
270; CHECK-NEXT:    [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I]], [[N]]
271; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WITHIN_BOUNDS]], i32 9) [ "deopt"() ]
272; CHECK-NEXT:    [[I_I64:%.*]] = zext i32 [[I]] to i64
273; CHECK-NEXT:    [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY:%.*]], i64 [[I_I64]]
274; CHECK-NEXT:    [[ARRAY_I:%.*]] = load i32, ptr [[ARRAY_I_PTR]], align 4
275; CHECK-NEXT:    [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
276; CHECK-NEXT:    [[I_NEXT]] = add nuw i32 [[I]], 1
277; CHECK-NEXT:    [[LEN:%.*]] = load i32, ptr [[LENGTH:%.*]], align 4, !invariant.load !0
278; CHECK-NEXT:    [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], [[LEN]]
279; CHECK-NEXT:    br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]]
280; CHECK:       exit.loopexit:
281; CHECK-NEXT:    [[LOOP_ACC_NEXT_LCSSA:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[LOOP]] ]
282; CHECK-NEXT:    br label [[EXIT]]
283; CHECK:       exit:
284; CHECK-NEXT:    [[RESULT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[LOOP_ACC_NEXT_LCSSA]], [[EXIT_LOOPEXIT]] ]
285; CHECK-NEXT:    ret i32 [[RESULT]]
286;
287  ptr dereferenceable(4) %length,
288  i32 %n) {
289entry:
290  %tmp5 = icmp eq i32 %n, 0
291  br i1 %tmp5, label %exit, label %loop.preheader
292
293loop.preheader:
294  br label %loop
295
296loop:
297  %loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ]
298  %i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
299  %unknown = load volatile i1, ptr @UNKNOWN
300  call void (i1, ...) @llvm.experimental.guard(i1 %unknown) [ "deopt"() ]
301  %within.bounds = icmp ult i32 %i, %n
302  call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
303
304  %i.i64 = zext i32 %i to i64
305  %array.i.ptr = getelementptr inbounds i32, ptr %array, i64 %i.i64
306  %array.i = load i32, ptr %array.i.ptr, align 4
307  %loop.acc.next = add i32 %loop.acc, %array.i
308
309  %i.next = add nuw i32 %i, 1
310  %len = load i32, ptr %length, align 4, !invariant.load !{}
311  %continue = icmp ult i32 %i.next, %len
312  br i1 %continue, label %loop, label %exit
313
314exit:
315  %result = phi i32 [ 0, %entry ], [ %loop.acc.next, %loop ]
316  ret i32 %result
317}
318
319
320
321@Length = external constant i32
322
323define i32 @constant_memory(ptr %array, i32 %n) {
324; CHECK-LABEL: @constant_memory(
325; CHECK-NEXT:  entry:
326; CHECK-NEXT:    [[TMP5:%.*]] = icmp eq i32 [[N:%.*]], 0
327; CHECK-NEXT:    br i1 [[TMP5]], label [[EXIT:%.*]], label [[LOOP_PREHEADER:%.*]]
328; CHECK:       loop.preheader:
329; CHECK-NEXT:    br label [[LOOP:%.*]]
330; CHECK:       loop:
331; CHECK-NEXT:    [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
332; CHECK-NEXT:    [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
333; CHECK-NEXT:    [[UNKNOWN:%.*]] = load volatile i1, ptr @UNKNOWN, align 1
334; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[UNKNOWN]]) [ "deopt"() ]
335; CHECK-NEXT:    [[LEN:%.*]] = load i32, ptr @Length, align 4
336; CHECK-NEXT:    [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I]], [[LEN]]
337; CHECK-NEXT:    [[TMP0:%.*]] = icmp ule i32 [[N]], [[LEN]]
338; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult i32 0, [[LEN]]
339; CHECK-NEXT:    [[TMP2:%.*]] = and i1 [[TMP1]], [[TMP0]]
340; CHECK-NEXT:    [[TMP3:%.*]] = freeze i1 [[TMP2]]
341; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[TMP3]], i32 9) [ "deopt"() ]
342; CHECK-NEXT:    call void @llvm.assume(i1 [[WITHIN_BOUNDS]])
343; CHECK-NEXT:    [[I_I64:%.*]] = zext i32 [[I]] to i64
344; CHECK-NEXT:    [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY:%.*]], i64 [[I_I64]]
345; CHECK-NEXT:    [[ARRAY_I:%.*]] = load i32, ptr [[ARRAY_I_PTR]], align 4
346; CHECK-NEXT:    [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
347; CHECK-NEXT:    [[I_NEXT]] = add nuw i32 [[I]], 1
348; CHECK-NEXT:    [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], [[N]]
349; CHECK-NEXT:    br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]]
350; CHECK:       exit.loopexit:
351; CHECK-NEXT:    [[LOOP_ACC_NEXT_LCSSA:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[LOOP]] ]
352; CHECK-NEXT:    br label [[EXIT]]
353; CHECK:       exit:
354; CHECK-NEXT:    [[RESULT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[LOOP_ACC_NEXT_LCSSA]], [[EXIT_LOOPEXIT]] ]
355; CHECK-NEXT:    ret i32 [[RESULT]]
356;
357entry:
358  %tmp5 = icmp eq i32 %n, 0
359  br i1 %tmp5, label %exit, label %loop.preheader
360
361loop.preheader:
362  br label %loop
363
364loop:
365  %loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ]
366  %i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
367  %unknown = load volatile i1, ptr @UNKNOWN
368  call void (i1, ...) @llvm.experimental.guard(i1 %unknown) [ "deopt"() ]
369  %len = load i32, ptr @Length, align 4
370  %within.bounds = icmp ult i32 %i, %len
371  call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
372
373  %i.i64 = zext i32 %i to i64
374  %array.i.ptr = getelementptr inbounds i32, ptr %array, i64 %i.i64
375  %array.i = load i32, ptr %array.i.ptr, align 4
376  %loop.acc.next = add i32 %loop.acc, %array.i
377
378  %i.next = add nuw i32 %i, 1
379  %continue = icmp ult i32 %i.next, %n
380  br i1 %continue, label %loop, label %exit
381
382exit:
383  %result = phi i32 [ 0, %entry ], [ %loop.acc.next, %loop ]
384  ret i32 %result
385}
386
387define i32 @constant_length(ptr %array, i32 %n) {
388; CHECK-LABEL: @constant_length(
389; CHECK-NEXT:  entry:
390; CHECK-NEXT:    [[TMP5:%.*]] = icmp eq i32 [[N:%.*]], 0
391; CHECK-NEXT:    br i1 [[TMP5]], label [[EXIT:%.*]], label [[LOOP_PREHEADER:%.*]]
392; CHECK:       loop.preheader:
393; CHECK-NEXT:    [[TMP0:%.*]] = icmp ule i32 [[N]], 20
394; CHECK-NEXT:    [[TMP1:%.*]] = and i1 true, [[TMP0]]
395; CHECK-NEXT:    [[TMP2:%.*]] = freeze i1 [[TMP1]]
396; CHECK-NEXT:    br label [[LOOP:%.*]]
397; CHECK:       loop:
398; CHECK-NEXT:    [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
399; CHECK-NEXT:    [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
400; CHECK-NEXT:    [[UNKNOWN:%.*]] = load volatile i1, ptr @UNKNOWN, align 1
401; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[UNKNOWN]]) [ "deopt"() ]
402; CHECK-NEXT:    [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I]], 20
403; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[TMP2]], i32 9) [ "deopt"() ]
404; CHECK-NEXT:    call void @llvm.assume(i1 [[WITHIN_BOUNDS]])
405; CHECK-NEXT:    [[I_I64:%.*]] = zext i32 [[I]] to i64
406; CHECK-NEXT:    [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY:%.*]], i64 [[I_I64]]
407; CHECK-NEXT:    [[ARRAY_I:%.*]] = load i32, ptr [[ARRAY_I_PTR]], align 4
408; CHECK-NEXT:    [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
409; CHECK-NEXT:    [[I_NEXT]] = add nuw i32 [[I]], 1
410; CHECK-NEXT:    [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], [[N]]
411; CHECK-NEXT:    br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]]
412; CHECK:       exit.loopexit:
413; CHECK-NEXT:    [[LOOP_ACC_NEXT_LCSSA:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[LOOP]] ]
414; CHECK-NEXT:    br label [[EXIT]]
415; CHECK:       exit:
416; CHECK-NEXT:    [[RESULT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[LOOP_ACC_NEXT_LCSSA]], [[EXIT_LOOPEXIT]] ]
417; CHECK-NEXT:    ret i32 [[RESULT]]
418;
419entry:
420  %tmp5 = icmp eq i32 %n, 0
421  br i1 %tmp5, label %exit, label %loop.preheader
422
423loop.preheader:
424  br label %loop
425
426loop:
427  %loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ]
428  %i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
429  %unknown = load volatile i1, ptr @UNKNOWN
430  call void (i1, ...) @llvm.experimental.guard(i1 %unknown) [ "deopt"() ]
431  %within.bounds = icmp ult i32 %i, 20
432  call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
433
434  %i.i64 = zext i32 %i to i64
435  %array.i.ptr = getelementptr inbounds i32, ptr %array, i64 %i.i64
436  %array.i = load i32, ptr %array.i.ptr, align 4
437  %loop.acc.next = add i32 %loop.acc, %array.i
438
439  %i.next = add nuw i32 %i, 1
440  %continue = icmp ult i32 %i.next, %n
441  br i1 %continue, label %loop, label %exit
442
443exit:
444  %result = phi i32 [ 0, %entry ], [ %loop.acc.next, %loop ]
445  ret i32 %result
446}
447
448
449