xref: /llvm-project/llvm/test/Transforms/LICM/scalar-promote.ll (revision e390c229a438ed1eb3396df8fbeeda89c49474e6)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-attributes
2; RUN: opt < %s -passes=licm -S | FileCheck %s
3; RUN: opt -aa-pipeline=tbaa,basic-aa -passes='require<aa>,require<target-ir>,require<scalar-evolution>,require<opt-remark-emit>,loop-mssa(licm)' -S %s | FileCheck %s
4target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128"
5
6@X = global i32 7   ; <ptr> [#uses=4]
7
8define void @test1(i32 %i) {
9; CHECK-LABEL: @test1(
10; CHECK-NEXT:  Entry:
11; CHECK-NEXT:    [[X_PROMOTED:%.*]] = load i32, ptr @X, align 4
12; CHECK-NEXT:    br label [[LOOP:%.*]]
13; CHECK:       Loop:
14; CHECK-NEXT:    [[X21:%.*]] = phi i32 [ [[X_PROMOTED]], [[ENTRY:%.*]] ], [ [[X2:%.*]], [[LOOP]] ]
15; CHECK-NEXT:    [[J:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[NEXT:%.*]], [[LOOP]] ]
16; CHECK-NEXT:    [[X2]] = add i32 [[X21]], 1
17; CHECK-NEXT:    [[NEXT]] = add i32 [[J]], 1
18; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[NEXT]], 0
19; CHECK-NEXT:    br i1 [[COND]], label [[OUT:%.*]], label [[LOOP]]
20; CHECK:       Out:
21; CHECK-NEXT:    [[X2_LCSSA:%.*]] = phi i32 [ [[X2]], [[LOOP]] ]
22; CHECK-NEXT:    store i32 [[X2_LCSSA]], ptr @X, align 4
23; CHECK-NEXT:    ret void
24;
25Entry:
26  br label %Loop
27
28Loop:   ; preds = %Loop, %0
29  %j = phi i32 [ 0, %Entry ], [ %Next, %Loop ]    ; <i32> [#uses=1]
30  %x = load i32, ptr @X   ; <i32> [#uses=1]
31  %x2 = add i32 %x, 1   ; <i32> [#uses=1]
32  store i32 %x2, ptr @X
33  %Next = add i32 %j, 1   ; <i32> [#uses=2]
34  %cond = icmp eq i32 %Next, 0    ; <i1> [#uses=1]
35  br i1 %cond, label %Out, label %Loop
36
37Out:
38  ret void
39}
40
41define void @test2(i32 %i) {
42; CHECK-LABEL: @test2(
43; CHECK-NEXT:  Entry:
44; CHECK-NEXT:    [[X1:%.*]] = getelementptr i32, ptr @X, i64 1
45; CHECK-NEXT:    [[X2:%.*]] = getelementptr i32, ptr @X, i64 1
46; CHECK-NEXT:    [[X1_PROMOTED:%.*]] = load i32, ptr [[X1]], align 4
47; CHECK-NEXT:    br label [[LOOP:%.*]]
48; CHECK:       Loop:
49; CHECK-NEXT:    [[A1:%.*]] = phi i32 [ [[V:%.*]], [[LOOP]] ], [ [[X1_PROMOTED]], [[ENTRY:%.*]] ]
50; CHECK-NEXT:    [[V]] = add i32 [[A1]], 1
51; CHECK-NEXT:    br i1 false, label [[LOOP]], label [[EXIT:%.*]]
52; CHECK:       Exit:
53; CHECK-NEXT:    [[V_LCSSA:%.*]] = phi i32 [ [[V]], [[LOOP]] ]
54; CHECK-NEXT:    store i32 [[V_LCSSA]], ptr [[X1]], align 4
55; CHECK-NEXT:    ret void
56;
57Entry:
58  br label %Loop
59
60Loop:   ; preds = %Loop, %0
61  %X1 = getelementptr i32, ptr @X, i64 1    ; <ptr> [#uses=1]
62  %A = load i32, ptr %X1    ; <i32> [#uses=1]
63  %V = add i32 %A, 1    ; <i32> [#uses=1]
64  %X2 = getelementptr i32, ptr @X, i64 1    ; <ptr> [#uses=1]
65  store i32 %V, ptr %X2
66  br i1 false, label %Loop, label %Exit
67
68Exit:   ; preds = %Loop
69  ret void
70}
71
72define void @test3(i32 %i) {
73; CHECK-LABEL: @test3(
74; CHECK-NEXT:    br label [[LOOP:%.*]]
75; CHECK:       Loop:
76; CHECK-NEXT:    [[X:%.*]] = load volatile i32, ptr @X, align 4
77; CHECK-NEXT:    [[X2:%.*]] = add i32 [[X]], 1
78; CHECK-NEXT:    store i32 [[X2]], ptr @X, align 4
79; CHECK-NEXT:    br i1 true, label [[OUT:%.*]], label [[LOOP]]
80; CHECK:       Out:
81; CHECK-NEXT:    ret void
82;
83  br label %Loop
84Loop:
85  ; Should not promote this to a register
86  %x = load volatile i32, ptr @X
87  %x2 = add i32 %x, 1
88  store i32 %x2, ptr @X
89  br i1 true, label %Out, label %Loop
90
91Out:    ; preds = %Loop
92  ret void
93}
94
95; Should not promote this to a register
96define void @test3b(i32 %i) {
97; CHECK-LABEL: @test3b(
98; CHECK-NEXT:    br label [[LOOP:%.*]]
99; CHECK:       Loop:
100; CHECK-NEXT:    [[X:%.*]] = load i32, ptr @X, align 4
101; CHECK-NEXT:    [[X2:%.*]] = add i32 [[X]], 1
102; CHECK-NEXT:    store volatile i32 [[X2]], ptr @X, align 4
103; CHECK-NEXT:    br i1 true, label [[OUT:%.*]], label [[LOOP]]
104; CHECK:       Out:
105; CHECK-NEXT:    ret void
106;
107  br label %Loop
108Loop:
109  %x = load i32, ptr @X
110  %x2 = add i32 %x, 1
111  store volatile i32 %x2, ptr @X
112  br i1 true, label %Out, label %Loop
113
114Out:    ; preds = %Loop
115  ret void
116}
117
118; PR8041
119; Should have promoted 'handle2' accesses.
120; Should not have promoted offsetx1 loads.
121define void @test4(ptr %x, i8 %n) {
122; CHECK-LABEL: @test4(
123; CHECK-NEXT:    [[HANDLE1:%.*]] = alloca ptr, align 8
124; CHECK-NEXT:    [[HANDLE2:%.*]] = alloca ptr, align 8
125; CHECK-NEXT:    store ptr [[X:%.*]], ptr [[HANDLE1]], align 8
126; CHECK-NEXT:    [[TMP:%.*]] = getelementptr i8, ptr [[X]], i64 8
127; CHECK-NEXT:    [[OFFSETX1:%.*]] = load ptr, ptr [[HANDLE1]], align 8
128; CHECK-NEXT:    br label [[LOOP:%.*]]
129; CHECK:       loop:
130; CHECK-NEXT:    br label [[SUBLOOP:%.*]]
131; CHECK:       subloop:
132; CHECK-NEXT:    [[NEWOFFSETX21:%.*]] = phi ptr [ [[TMP]], [[LOOP]] ], [ [[NEWOFFSETX2:%.*]], [[SUBLOOP]] ]
133; CHECK-NEXT:    [[COUNT:%.*]] = phi i8 [ 0, [[LOOP]] ], [ [[NEXTCOUNT:%.*]], [[SUBLOOP]] ]
134; CHECK-NEXT:    store i8 [[N:%.*]], ptr [[NEWOFFSETX21]], align 1
135; CHECK-NEXT:    [[NEWOFFSETX2]] = getelementptr i8, ptr [[NEWOFFSETX21]], i64 -1
136; CHECK-NEXT:    [[NEXTCOUNT]] = add i8 [[COUNT]], 1
137; CHECK-NEXT:    [[INNEREXITCOND:%.*]] = icmp sge i8 [[NEXTCOUNT]], 8
138; CHECK-NEXT:    br i1 [[INNEREXITCOND]], label [[INNEREXIT:%.*]], label [[SUBLOOP]]
139; CHECK:       innerexit:
140; CHECK-NEXT:    [[NEWOFFSETX2_LCSSA:%.*]] = phi ptr [ [[NEWOFFSETX2]], [[SUBLOOP]] ]
141; CHECK-NEXT:    [[VAL:%.*]] = load i8, ptr [[OFFSETX1]], align 1
142; CHECK-NEXT:    [[COND:%.*]] = icmp eq i8 [[VAL]], [[N]]
143; CHECK-NEXT:    br i1 [[COND]], label [[EXIT:%.*]], label [[LOOP]]
144; CHECK:       exit:
145; CHECK-NEXT:    [[NEWOFFSETX2_LCSSA_LCSSA:%.*]] = phi ptr [ [[NEWOFFSETX2_LCSSA]], [[INNEREXIT]] ]
146; CHECK-NEXT:    store ptr [[NEWOFFSETX2_LCSSA_LCSSA]], ptr [[HANDLE2]], align 8
147; CHECK-NEXT:    ret void
148;
149  %handle1 = alloca ptr
150  %handle2 = alloca ptr
151  store ptr %x, ptr %handle1
152  br label %loop
153
154loop:
155  %tmp = getelementptr i8, ptr %x, i64 8
156  store ptr %tmp, ptr %handle2
157  br label %subloop
158
159subloop:
160  %count = phi i8 [ 0, %loop ], [ %nextcount, %subloop ]
161  %offsetx2 = load ptr, ptr %handle2
162  store i8 %n, ptr %offsetx2
163  %newoffsetx2 = getelementptr i8, ptr %offsetx2, i64 -1
164  store ptr %newoffsetx2, ptr %handle2
165  %nextcount = add i8 %count, 1
166  %innerexitcond = icmp sge i8 %nextcount, 8
167  br i1 %innerexitcond, label %innerexit, label %subloop
168
169innerexit:
170  %offsetx1 = load ptr, ptr %handle1
171  %val = load i8, ptr %offsetx1
172  %cond = icmp eq i8 %val, %n
173  br i1 %cond, label %exit, label %loop
174
175exit:
176  ret void
177}
178
179define void @test5(i32 %i, ptr noalias %P2) {
180; CHECK-LABEL: @test5(
181; CHECK-NEXT:  Entry:
182; CHECK-NEXT:    [[X_PROMOTED:%.*]] = load i32, ptr @X, align 4
183; CHECK-NEXT:    br label [[LOOP:%.*]]
184; CHECK:       Loop:
185; CHECK-NEXT:    [[X21:%.*]] = phi i32 [ [[X_PROMOTED]], [[ENTRY:%.*]] ], [ [[X2:%.*]], [[LOOP]] ]
186; CHECK-NEXT:    [[J:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[NEXT:%.*]], [[LOOP]] ]
187; CHECK-NEXT:    [[X2]] = add i32 [[X21]], 1
188; CHECK-NEXT:    store atomic ptr @X, ptr [[P2:%.*]] monotonic, align 8
189; CHECK-NEXT:    [[NEXT]] = add i32 [[J]], 1
190; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[NEXT]], 0
191; CHECK-NEXT:    br i1 [[COND]], label [[OUT:%.*]], label [[LOOP]]
192; CHECK:       Out:
193; CHECK-NEXT:    [[X2_LCSSA:%.*]] = phi i32 [ [[X2]], [[LOOP]] ]
194; CHECK-NEXT:    store i32 [[X2_LCSSA]], ptr @X, align 4
195; CHECK-NEXT:    ret void
196;
197Entry:
198  br label %Loop
199
200Loop:   ; preds = %Loop, %0
201  %j = phi i32 [ 0, %Entry ], [ %Next, %Loop ]    ; <i32> [#uses=1]
202  %x = load i32, ptr @X   ; <i32> [#uses=1]
203  %x2 = add i32 %x, 1   ; <i32> [#uses=1]
204  store i32 %x2, ptr @X
205
206  store atomic ptr @X, ptr %P2 monotonic, align 8
207
208  %Next = add i32 %j, 1   ; <i32> [#uses=2]
209  %cond = icmp eq i32 %Next, 0    ; <i1> [#uses=1]
210  br i1 %cond, label %Out, label %Loop
211
212Out:
213  ret void
214
215}
216
217
218; PR14753 - Preserve TBAA tags when promoting values in a loop.
219define void @test6(i32 %n, ptr nocapture %a, ptr %gi) {
220; CHECK-LABEL: @test6(
221; CHECK-NEXT:  entry:
222; CHECK-NEXT:    store i32 0, ptr [[GI:%.*]], align 4, !tbaa [[TBAA0:![0-9]+]]
223; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i32 0, [[N:%.*]]
224; CHECK-NEXT:    br i1 [[CMP1]], label [[FOR_BODY_LR_PH:%.*]], label [[FOR_END:%.*]]
225; CHECK:       for.body.lr.ph:
226; CHECK-NEXT:    [[GI_PROMOTED:%.*]] = load i32, ptr [[GI]], align 4, !tbaa [[TBAA0]]
227; CHECK-NEXT:    br label [[FOR_BODY:%.*]]
228; CHECK:       for.body:
229; CHECK-NEXT:    [[INC1:%.*]] = phi i32 [ [[GI_PROMOTED]], [[FOR_BODY_LR_PH]] ], [ [[INC:%.*]], [[FOR_BODY]] ]
230; CHECK-NEXT:    [[STOREMERGE2:%.*]] = phi i32 [ 0, [[FOR_BODY_LR_PH]] ], [ [[INC]], [[FOR_BODY]] ]
231; CHECK-NEXT:    [[IDXPROM:%.*]] = sext i32 [[STOREMERGE2]] to i64
232; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds float, ptr [[A:%.*]], i64 [[IDXPROM]]
233; CHECK-NEXT:    store float 0.000000e+00, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA4:![0-9]+]]
234; CHECK-NEXT:    [[INC]] = add nsw i32 [[INC1]], 1
235; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[INC]], [[N]]
236; CHECK-NEXT:    br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_COND_FOR_END_CRIT_EDGE:%.*]]
237; CHECK:       for.cond.for.end_crit_edge:
238; CHECK-NEXT:    [[INC_LCSSA:%.*]] = phi i32 [ [[INC]], [[FOR_BODY]] ]
239; CHECK-NEXT:    store i32 [[INC_LCSSA]], ptr [[GI]], align 4, !tbaa [[TBAA0]]
240; CHECK-NEXT:    br label [[FOR_END]]
241; CHECK:       for.end:
242; CHECK-NEXT:    ret void
243;
244entry:
245  store i32 0, ptr %gi, align 4, !tbaa !0
246  %cmp1 = icmp slt i32 0, %n
247  br i1 %cmp1, label %for.body.lr.ph, label %for.end
248
249for.body.lr.ph:                                   ; preds = %entry
250  br label %for.body
251
252for.body:                                         ; preds = %for.body.lr.ph, %for.body
253  %storemerge2 = phi i32 [ 0, %for.body.lr.ph ], [ %inc, %for.body ]
254  %idxprom = sext i32 %storemerge2 to i64
255  %arrayidx = getelementptr inbounds float, ptr %a, i64 %idxprom
256  store float 0.000000e+00, ptr %arrayidx, align 4, !tbaa !3
257  %0 = load i32, ptr %gi, align 4, !tbaa !0
258  %inc = add nsw i32 %0, 1
259  store i32 %inc, ptr %gi, align 4, !tbaa !0
260  %cmp = icmp slt i32 %inc, %n
261  br i1 %cmp, label %for.body, label %for.cond.for.end_crit_edge
262
263for.cond.for.end_crit_edge:                       ; preds = %for.body
264  br label %for.end
265
266for.end:                                          ; preds = %for.cond.for.end_crit_edge, %entry
267  ret void
268
269}
270
271declare i32 @opaque(i32) argmemonly
272declare void @capture(ptr)
273
274; We can promote even if opaque may throw.
275define i32 @test7() {
276; CHECK-LABEL: @test7(
277; CHECK-NEXT:  entry:
278; CHECK-NEXT:    [[LOCAL:%.*]] = alloca i32, align 4
279; CHECK-NEXT:    call void @capture(ptr [[LOCAL]])
280; CHECK-NEXT:    [[LOCAL_PROMOTED:%.*]] = load i32, ptr [[LOCAL]], align 4
281; CHECK-NEXT:    br label [[LOOP:%.*]]
282; CHECK:       loop:
283; CHECK-NEXT:    [[X21:%.*]] = phi i32 [ [[LOCAL_PROMOTED]], [[ENTRY:%.*]] ], [ [[X2:%.*]], [[LOOP]] ]
284; CHECK-NEXT:    [[J:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[NEXT:%.*]], [[LOOP]] ]
285; CHECK-NEXT:    [[X2]] = call i32 @opaque(i32 [[X21]])
286; CHECK-NEXT:    [[NEXT]] = add i32 [[J]], 1
287; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[NEXT]], 0
288; CHECK-NEXT:    br i1 [[COND]], label [[EXIT:%.*]], label [[LOOP]]
289; CHECK:       exit:
290; CHECK-NEXT:    [[X2_LCSSA:%.*]] = phi i32 [ [[X2]], [[LOOP]] ]
291; CHECK-NEXT:    store i32 [[X2_LCSSA]], ptr [[LOCAL]], align 4
292; CHECK-NEXT:    [[RET:%.*]] = load i32, ptr [[LOCAL]], align 4
293; CHECK-NEXT:    ret i32 [[RET]]
294;
295entry:
296  %local = alloca i32
297  call void @capture(ptr %local)
298  br label %loop
299
300loop:
301  %j = phi i32 [ 0, %entry ], [ %next, %loop ]
302  %x = load i32, ptr %local
303  %x2 = call i32 @opaque(i32 %x) ; Note this does not capture %local
304  store i32 %x2, ptr %local
305  %next = add i32 %j, 1
306  %cond = icmp eq i32 %next, 0
307  br i1 %cond, label %exit, label %loop
308
309exit:
310  %ret = load i32, ptr %local
311  ret i32 %ret
312}
313
314; Hoist the load even if we cannot sink the store, since the store is really
315; control-flow dependent.
316define i32 @test7bad() {
317; CHECK-LABEL: @test7bad(
318; CHECK-NEXT:  entry:
319; CHECK-NEXT:    [[LOCAL:%.*]] = alloca i32, align 4
320; CHECK-NEXT:    call void @capture(ptr [[LOCAL]])
321; CHECK-NEXT:    [[LOCAL_PROMOTED:%.*]] = load i32, ptr [[LOCAL]], align 4
322; CHECK-NEXT:    br label [[LOOP:%.*]]
323; CHECK:       loop:
324; CHECK-NEXT:    [[X22:%.*]] = phi i32 [ [[LOCAL_PROMOTED]], [[ENTRY:%.*]] ], [ [[X21:%.*]], [[ELSE:%.*]] ]
325; CHECK-NEXT:    [[J:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[NEXT:%.*]], [[ELSE]] ]
326; CHECK-NEXT:    [[X2:%.*]] = call i32 @opaque(i32 [[X22]])
327; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[X2]], 0
328; CHECK-NEXT:    br i1 [[CMP]], label [[IF:%.*]], label [[ELSE]]
329; CHECK:       if:
330; CHECK-NEXT:    store i32 [[X2]], ptr [[LOCAL]], align 4
331; CHECK-NEXT:    br label [[ELSE]]
332; CHECK:       else:
333; CHECK-NEXT:    [[X21]] = phi i32 [ [[X2]], [[IF]] ], [ [[X22]], [[LOOP]] ]
334; CHECK-NEXT:    [[NEXT]] = add i32 [[J]], 1
335; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[NEXT]], 0
336; CHECK-NEXT:    br i1 [[COND]], label [[EXIT:%.*]], label [[LOOP]]
337; CHECK:       exit:
338; CHECK-NEXT:    [[RET:%.*]] = load i32, ptr [[LOCAL]], align 4
339; CHECK-NEXT:    ret i32 [[RET]]
340;
341entry:
342  %local = alloca i32
343  call void @capture(ptr %local)
344  br label %loop
345loop:
346  %j = phi i32 [ 0, %entry ], [ %next, %else ]
347  %x = load i32, ptr %local
348  %x2 = call i32 @opaque(i32 %x) ; Note this does not capture %local
349  %cmp = icmp eq i32 %x2, 0
350  br i1 %cmp, label %if, label %else
351
352if:
353  store i32 %x2, ptr %local
354  br label %else
355
356else:
357  %next = add i32 %j, 1
358  %cond = icmp eq i32 %next, 0
359  br i1 %cond, label %exit, label %loop
360
361exit:
362  %ret = load i32, ptr %local
363  ret i32 %ret
364}
365
366; Even if neither the load nor the store or guaranteed to execute because
367; opaque() may throw, we can still promote - the load not being guaranteed
368; doesn't block us, because %local is always dereferenceable.
369define i32 @test8() {
370; CHECK-LABEL: @test8(
371; CHECK-NEXT:  entry:
372; CHECK-NEXT:    [[LOCAL:%.*]] = alloca i32, align 4
373; CHECK-NEXT:    call void @capture(ptr [[LOCAL]])
374; CHECK-NEXT:    [[LOCAL_PROMOTED:%.*]] = load i32, ptr [[LOCAL]], align 4
375; CHECK-NEXT:    br label [[LOOP:%.*]]
376; CHECK:       loop:
377; CHECK-NEXT:    [[X21:%.*]] = phi i32 [ [[LOCAL_PROMOTED]], [[ENTRY:%.*]] ], [ [[X2:%.*]], [[LOOP]] ]
378; CHECK-NEXT:    [[J:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[NEXT:%.*]], [[LOOP]] ]
379; CHECK-NEXT:    [[THROWAWAY:%.*]] = call i32 @opaque(i32 [[J]])
380; CHECK-NEXT:    [[X2]] = call i32 @opaque(i32 [[X21]])
381; CHECK-NEXT:    [[NEXT]] = add i32 [[J]], 1
382; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[NEXT]], 0
383; CHECK-NEXT:    br i1 [[COND]], label [[EXIT:%.*]], label [[LOOP]]
384; CHECK:       exit:
385; CHECK-NEXT:    [[X2_LCSSA:%.*]] = phi i32 [ [[X2]], [[LOOP]] ]
386; CHECK-NEXT:    store i32 [[X2_LCSSA]], ptr [[LOCAL]], align 4
387; CHECK-NEXT:    [[RET:%.*]] = load i32, ptr [[LOCAL]], align 4
388; CHECK-NEXT:    ret i32 [[RET]]
389;
390entry:
391  %local = alloca i32
392  call void @capture(ptr %local)
393  br label %loop
394
395loop:
396  %j = phi i32 [ 0, %entry ], [ %next, %loop ]
397  %throwaway = call i32 @opaque(i32 %j)
398  %x = load i32, ptr %local
399  %x2 = call i32 @opaque(i32 %x)
400  store i32 %x2, ptr %local
401  %next = add i32 %j, 1
402  %cond = icmp eq i32 %next, 0
403  br i1 %cond, label %exit, label %loop
404
405exit:
406  %ret = load i32, ptr %local
407  ret i32 %ret
408}
409
410
411; If the store is "guaranteed modulo exceptions", and the load depends on
412; control flow, we can only promote if the pointer is otherwise known to be
413; dereferenceable
414define i32 @test9() {
415; CHECK-LABEL: @test9(
416; CHECK-NEXT:  entry:
417; CHECK-NEXT:    [[LOCAL:%.*]] = alloca i32, align 4
418; CHECK-NEXT:    call void @capture(ptr [[LOCAL]])
419; CHECK-NEXT:    [[LOCAL_PROMOTED:%.*]] = load i32, ptr [[LOCAL]], align 4
420; CHECK-NEXT:    br label [[LOOP:%.*]]
421; CHECK:       loop:
422; CHECK-NEXT:    [[X21:%.*]] = phi i32 [ [[LOCAL_PROMOTED]], [[ENTRY:%.*]] ], [ [[X2:%.*]], [[ELSE:%.*]] ]
423; CHECK-NEXT:    [[J:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[NEXT:%.*]], [[ELSE]] ]
424; CHECK-NEXT:    [[J2:%.*]] = call i32 @opaque(i32 [[J]])
425; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[J2]], 0
426; CHECK-NEXT:    br i1 [[CMP]], label [[IF:%.*]], label [[ELSE]]
427; CHECK:       if:
428; CHECK-NEXT:    br label [[ELSE]]
429; CHECK:       else:
430; CHECK-NEXT:    [[X2]] = phi i32 [ 0, [[LOOP]] ], [ [[X21]], [[IF]] ]
431; CHECK-NEXT:    [[NEXT]] = add i32 [[J]], 1
432; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[NEXT]], 0
433; CHECK-NEXT:    br i1 [[COND]], label [[EXIT:%.*]], label [[LOOP]]
434; CHECK:       exit:
435; CHECK-NEXT:    [[X2_LCSSA:%.*]] = phi i32 [ [[X2]], [[ELSE]] ]
436; CHECK-NEXT:    store i32 [[X2_LCSSA]], ptr [[LOCAL]], align 4
437; CHECK-NEXT:    [[RET:%.*]] = load i32, ptr [[LOCAL]], align 4
438; CHECK-NEXT:    ret i32 [[RET]]
439;
440entry:
441  %local = alloca i32
442  call void @capture(ptr %local)
443  br label %loop
444
445loop:
446  %j = phi i32 [ 0, %entry ], [ %next, %else ]
447  %j2 = call i32 @opaque(i32 %j)
448  %cmp = icmp eq i32 %j2, 0
449  br i1 %cmp, label %if, label %else
450
451if:
452  %x = load i32, ptr %local
453  br label %else
454
455else:
456  %x2 = phi i32 [ 0, %loop ], [ %x, %if]
457  store i32 %x2, ptr %local
458  %next = add i32 %j, 1
459  %cond = icmp eq i32 %next, 0
460  br i1 %cond, label %exit, label %loop
461
462exit:
463  %ret = load i32, ptr %local
464  ret i32 %ret
465}
466
467define i32 @test9bad(i32 %i) {
468; CHECK-LABEL: @test9bad(
469; CHECK-NEXT:  entry:
470; CHECK-NEXT:    [[LOCAL:%.*]] = alloca i32, align 4
471; CHECK-NEXT:    call void @capture(ptr [[LOCAL]])
472; CHECK-NEXT:    [[NOTDEREF:%.*]] = getelementptr i32, ptr [[LOCAL]], i32 [[I:%.*]]
473; CHECK-NEXT:    br label [[LOOP:%.*]]
474; CHECK:       loop:
475; CHECK-NEXT:    [[J:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[NEXT:%.*]], [[ELSE:%.*]] ]
476; CHECK-NEXT:    [[J2:%.*]] = call i32 @opaque(i32 [[J]])
477; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[J2]], 0
478; CHECK-NEXT:    br i1 [[CMP]], label [[IF:%.*]], label [[ELSE]]
479; CHECK:       if:
480; CHECK-NEXT:    [[X:%.*]] = load i32, ptr [[NOTDEREF]], align 4
481; CHECK-NEXT:    br label [[ELSE]]
482; CHECK:       else:
483; CHECK-NEXT:    [[X2:%.*]] = phi i32 [ 0, [[LOOP]] ], [ [[X]], [[IF]] ]
484; CHECK-NEXT:    store i32 [[X2]], ptr [[NOTDEREF]], align 4
485; CHECK-NEXT:    [[NEXT]] = add i32 [[J]], 1
486; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[NEXT]], 0
487; CHECK-NEXT:    br i1 [[COND]], label [[EXIT:%.*]], label [[LOOP]]
488; CHECK:       exit:
489; CHECK-NEXT:    [[RET:%.*]] = load i32, ptr [[NOTDEREF]], align 4
490; CHECK-NEXT:    ret i32 [[RET]]
491;
492entry:
493  %local = alloca i32
494  call void @capture(ptr %local)
495  %notderef = getelementptr i32, ptr %local, i32 %i
496  br label %loop
497
498loop:
499  %j = phi i32 [ 0, %entry ], [ %next, %else ]
500  %j2 = call i32 @opaque(i32 %j)
501  %cmp = icmp eq i32 %j2, 0
502  br i1 %cmp, label %if, label %else
503
504if:
505  %x = load i32, ptr %notderef
506  br label %else
507
508else:
509  %x2 = phi i32 [ 0, %loop ], [ %x, %if]
510  store i32 %x2, ptr %notderef
511  %next = add i32 %j, 1
512  %cond = icmp eq i32 %next, 0
513  br i1 %cond, label %exit, label %loop
514
515exit:
516  %ret = load i32, ptr %notderef
517  ret i32 %ret
518}
519
520define void @test10(i32 %i) {
521; CHECK-LABEL: @test10(
522; CHECK-NEXT:  Entry:
523; CHECK-NEXT:    [[X_PROMOTED:%.*]] = load atomic i32, ptr @X unordered, align 4
524; CHECK-NEXT:    br label [[LOOP:%.*]]
525; CHECK:       Loop:
526; CHECK-NEXT:    [[X21:%.*]] = phi i32 [ [[X_PROMOTED]], [[ENTRY:%.*]] ], [ [[X2:%.*]], [[LOOP]] ]
527; CHECK-NEXT:    [[J:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[NEXT:%.*]], [[LOOP]] ]
528; CHECK-NEXT:    [[X2]] = add i32 [[X21]], 1
529; CHECK-NEXT:    [[NEXT]] = add i32 [[J]], 1
530; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[NEXT]], 0
531; CHECK-NEXT:    br i1 [[COND]], label [[OUT:%.*]], label [[LOOP]]
532; CHECK:       Out:
533; CHECK-NEXT:    [[X2_LCSSA:%.*]] = phi i32 [ [[X2]], [[LOOP]] ]
534; CHECK-NEXT:    store atomic i32 [[X2_LCSSA]], ptr @X unordered, align 4
535; CHECK-NEXT:    ret void
536;
537Entry:
538  br label %Loop
539
540
541Loop:   ; preds = %Loop, %0
542  %j = phi i32 [ 0, %Entry ], [ %Next, %Loop ]    ; <i32> [#uses=1]
543  %x = load atomic i32, ptr @X unordered, align 4
544  %x2 = add i32 %x, 1
545  store atomic i32 %x2, ptr @X unordered, align 4
546  %Next = add i32 %j, 1
547  %cond = icmp eq i32 %Next, 0
548  br i1 %cond, label %Out, label %Loop
549
550Out:
551  ret void
552
553}
554
555; Early exit is known not to be taken on first iteration and thus doesn't
556; effect whether load is known to execute.
557define void @test11(i32 %i) {
558; CHECK-LABEL: @test11(
559; CHECK-NEXT:  Entry:
560; CHECK-NEXT:    [[X_PROMOTED:%.*]] = load i32, ptr @X, align 4
561; CHECK-NEXT:    br label [[LOOP:%.*]]
562; CHECK:       Loop:
563; CHECK-NEXT:    [[X21:%.*]] = phi i32 [ [[X_PROMOTED]], [[ENTRY:%.*]] ], [ [[X2:%.*]], [[BODY:%.*]] ]
564; CHECK-NEXT:    [[J:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[NEXT:%.*]], [[BODY]] ]
565; CHECK-NEXT:    [[EARLY_TEST:%.*]] = icmp ult i32 [[J]], 32
566; CHECK-NEXT:    br i1 [[EARLY_TEST]], label [[BODY]], label [[EARLY:%.*]]
567; CHECK:       body:
568; CHECK-NEXT:    [[X2]] = add i32 [[X21]], 1
569; CHECK-NEXT:    [[NEXT]] = add i32 [[J]], 1
570; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[NEXT]], 0
571; CHECK-NEXT:    br i1 [[COND]], label [[OUT:%.*]], label [[LOOP]]
572; CHECK:       Early:
573; CHECK-NEXT:    [[X21_LCSSA:%.*]] = phi i32 [ [[X21]], [[LOOP]] ]
574; CHECK-NEXT:    store i32 [[X21_LCSSA]], ptr @X, align 4
575; CHECK-NEXT:    ret void
576; CHECK:       Out:
577; CHECK-NEXT:    [[X2_LCSSA:%.*]] = phi i32 [ [[X2]], [[BODY]] ]
578; CHECK-NEXT:    store i32 [[X2_LCSSA]], ptr @X, align 4
579; CHECK-NEXT:    ret void
580;
581Entry:
582  br label %Loop
583
584
585Loop:   ; preds = %Loop, %0
586  %j = phi i32 [ 0, %Entry ], [ %Next, %body ]    ; <i32> [#uses=1]
587  %early.test = icmp ult i32 %j, 32
588  br i1 %early.test, label %body, label %Early
589body:
590  %x = load i32, ptr @X   ; <i32> [#uses=1]
591  %x2 = add i32 %x, 1   ; <i32> [#uses=1]
592  store i32 %x2, ptr @X
593  %Next = add i32 %j, 1   ; <i32> [#uses=2]
594  %cond = icmp eq i32 %Next, 0    ; <i1> [#uses=1]
595  br i1 %cond, label %Out, label %Loop
596
597Early:
598  ret void
599Out:
600  ret void
601
602}
603
604define i8 @test_hoistable_existing_load_sinkable_store_writeonly(ptr dereferenceable(8) %ptr, i8 %start) writeonly {
605; CHECK: Function Attrs: memory(write)
606; CHECK-LABEL: @test_hoistable_existing_load_sinkable_store_writeonly(
607; CHECK-NEXT:  entry:
608; CHECK-NEXT:    [[PTR_PROMOTED:%.*]] = load i8, ptr [[PTR:%.*]], align 1
609; CHECK-NEXT:    br label [[LOOP_HEADER:%.*]]
610; CHECK:       loop.header:
611; CHECK-NEXT:    [[INC1:%.*]] = phi i8 [ [[PTR_PROMOTED]], [[ENTRY:%.*]] ], [ [[INC1]], [[LOOP_LATCH:%.*]] ]
612; CHECK-NEXT:    [[I:%.*]] = phi i8 [ [[START:%.*]], [[ENTRY]] ], [ [[ADD:%.*]], [[LOOP_LATCH]] ]
613; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i8 [[I]], 4
614; CHECK-NEXT:    br i1 [[CMP]], label [[LOOP_LATCH]], label [[EXIT:%.*]]
615; CHECK:       loop.latch:
616; CHECK-NEXT:    store i8 [[INC1]], ptr [[PTR]], align 1
617; CHECK-NEXT:    [[ADD]] = add i8 [[I]], [[INC1]]
618; CHECK-NEXT:    br label [[LOOP_HEADER]]
619; CHECK:       exit:
620; CHECK-NEXT:    [[I_LCSSA:%.*]] = phi i8 [ [[I]], [[LOOP_HEADER]] ]
621; CHECK-NEXT:    ret i8 [[I_LCSSA]]
622;
623entry:
624  br label %loop.header
625
626loop.header:
627  %i = phi i8 [ %start, %entry ], [ %add, %loop.latch ]
628  %cmp = icmp ult i8 %i, 4
629  br i1 %cmp, label %loop.latch, label %exit
630
631loop.latch:
632  %div = sdiv i8 %i, 3
633  %inc = load i8, ptr %ptr
634  store i8 %inc, ptr %ptr
635  %add = add i8 %i, %inc
636  br label %loop.header
637
638exit:
639  ret i8 %i
640}
641
642@glb = external global i8, align 1
643
644; Test case for PR51248.
645define void @test_sink_store_only() writeonly {
646; CHECK: Function Attrs: memory(write)
647; CHECK-LABEL: @test_sink_store_only(
648; CHECK-NEXT:  entry:
649; CHECK-NEXT:    br label [[LOOP_HEADER:%.*]]
650; CHECK:       loop.header:
651; CHECK-NEXT:    [[DIV1:%.*]] = phi i8 [ poison, [[ENTRY:%.*]] ], [ [[DIV:%.*]], [[LOOP_LATCH:%.*]] ]
652; CHECK-NEXT:    [[I:%.*]] = phi i8 [ 0, [[ENTRY]] ], [ [[ADD:%.*]], [[LOOP_LATCH]] ]
653; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i8 [[I]], 4
654; CHECK-NEXT:    br i1 [[CMP]], label [[LOOP_LATCH]], label [[EXIT:%.*]]
655; CHECK:       loop.latch:
656; CHECK-NEXT:    [[DIV]] = sdiv i8 [[I]], 3
657; CHECK-NEXT:    [[ADD]] = add i8 [[I]], 4
658; CHECK-NEXT:    br label [[LOOP_HEADER]]
659; CHECK:       exit:
660; CHECK-NEXT:    [[DIV1_LCSSA:%.*]] = phi i8 [ [[DIV1]], [[LOOP_HEADER]] ]
661; CHECK-NEXT:    store i8 [[DIV1_LCSSA]], ptr @glb, align 1
662; CHECK-NEXT:    ret void
663;
664entry:
665  br label %loop.header
666
667loop.header:
668  %i = phi i8 [ 0, %entry ], [ %add, %loop.latch ]
669  %cmp = icmp ult i8 %i, 4
670  br i1 %cmp, label %loop.latch, label %exit
671
672loop.latch:
673  %div = sdiv i8 %i, 3
674  store i8 %div, ptr @glb, align 1
675  %add = add i8 %i, 4
676  br label %loop.header
677
678exit:
679  ret void
680}
681
682define void @test_sink_store_to_local_object_only_loop_must_execute() writeonly {
683; CHECK: Function Attrs: memory(write)
684; CHECK-LABEL: @test_sink_store_to_local_object_only_loop_must_execute(
685; CHECK-NEXT:  entry:
686; CHECK-NEXT:    [[A:%.*]] = alloca i8, align 1
687; CHECK-NEXT:    br label [[LOOP_HEADER:%.*]]
688; CHECK:       loop.header:
689; CHECK-NEXT:    [[DIV1:%.*]] = phi i8 [ poison, [[ENTRY:%.*]] ], [ [[DIV:%.*]], [[LOOP_LATCH:%.*]] ]
690; CHECK-NEXT:    [[I:%.*]] = phi i8 [ 0, [[ENTRY]] ], [ [[ADD:%.*]], [[LOOP_LATCH]] ]
691; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i8 [[I]], 4
692; CHECK-NEXT:    br i1 [[CMP]], label [[LOOP_LATCH]], label [[EXIT:%.*]]
693; CHECK:       loop.latch:
694; CHECK-NEXT:    [[DIV]] = sdiv i8 [[I]], 3
695; CHECK-NEXT:    [[ADD]] = add i8 [[I]], 4
696; CHECK-NEXT:    br label [[LOOP_HEADER]]
697; CHECK:       exit:
698; CHECK-NEXT:    [[DIV1_LCSSA:%.*]] = phi i8 [ [[DIV1]], [[LOOP_HEADER]] ]
699; CHECK-NEXT:    store i8 [[DIV1_LCSSA]], ptr [[A]], align 1
700; CHECK-NEXT:    ret void
701;
702entry:
703  %a = alloca i8
704  br label %loop.header
705
706loop.header:
707  %i = phi i8 [ 0, %entry ], [ %add, %loop.latch ]
708  %cmp = icmp ult i8 %i, 4
709  br i1 %cmp, label %loop.latch, label %exit
710
711loop.latch:
712  %div = sdiv i8 %i, 3
713  store i8 %div, ptr %a, align 1
714  %add = add i8 %i, 4
715  br label %loop.header
716
717exit:
718  ret void
719}
720
721; The store in the loop may not execute, so we need to introduce a load in the
722; pre-header. Make sure the writeonly attribute is dropped.
723define void @test_sink_store_to_local_object_only_loop_may_not_execute(i8 %n) writeonly {
724; CHECK: Function Attrs: memory(write)
725; CHECK-LABEL: @test_sink_store_to_local_object_only_loop_may_not_execute(
726; CHECK-NEXT:  entry:
727; CHECK-NEXT:    [[A:%.*]] = alloca i8, align 1
728; CHECK-NEXT:    [[A_PROMOTED:%.*]] = load i8, ptr [[A]], align 1
729; CHECK-NEXT:    br label [[LOOP_HEADER:%.*]]
730; CHECK:       loop.header:
731; CHECK-NEXT:    [[DIV1:%.*]] = phi i8 [ [[A_PROMOTED]], [[ENTRY:%.*]] ], [ [[DIV:%.*]], [[LOOP_LATCH:%.*]] ]
732; CHECK-NEXT:    [[I:%.*]] = phi i8 [ 0, [[ENTRY]] ], [ [[ADD:%.*]], [[LOOP_LATCH]] ]
733; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i8 [[I]], [[N:%.*]]
734; CHECK-NEXT:    br i1 [[CMP]], label [[LOOP_LATCH]], label [[EXIT:%.*]]
735; CHECK:       loop.latch:
736; CHECK-NEXT:    [[DIV]] = sdiv i8 [[I]], 3
737; CHECK-NEXT:    [[ADD]] = add i8 [[I]], 4
738; CHECK-NEXT:    br label [[LOOP_HEADER]]
739; CHECK:       exit:
740; CHECK-NEXT:    [[DIV1_LCSSA:%.*]] = phi i8 [ [[DIV1]], [[LOOP_HEADER]] ]
741; CHECK-NEXT:    store i8 [[DIV1_LCSSA]], ptr [[A]], align 1
742; CHECK-NEXT:    ret void
743;
744entry:
745  %a = alloca i8
746  br label %loop.header
747
748loop.header:
749  %i = phi i8 [ 0, %entry ], [ %add, %loop.latch ]
750  %cmp = icmp ult i8 %i, %n
751  br i1 %cmp, label %loop.latch, label %exit
752
753loop.latch:
754  %div = sdiv i8 %i, 3
755  store i8 %div, ptr %a, align 1
756  %add = add i8 %i, 4
757  br label %loop.header
758
759exit:
760  ret void
761}
762
763declare dereferenceable(8) noalias ptr @alloc_writeonly() writeonly
764
765define void @test_sink_store_to_noalias_call_object_only_loop_may_not_execute1(i8 %n) writeonly {
766; CHECK: Function Attrs: memory(write)
767; CHECK-LABEL: @test_sink_store_to_noalias_call_object_only_loop_may_not_execute1(
768; CHECK-NEXT:  entry:
769; CHECK-NEXT:    [[A:%.*]] = call noalias dereferenceable(8) ptr @alloc_writeonly()
770; CHECK-NEXT:    [[A_PROMOTED:%.*]] = load i8, ptr [[A]], align 1
771; CHECK-NEXT:    br label [[LOOP_HEADER:%.*]]
772; CHECK:       loop.header:
773; CHECK-NEXT:    [[DIV1:%.*]] = phi i8 [ [[A_PROMOTED]], [[ENTRY:%.*]] ], [ [[DIV:%.*]], [[LOOP_LATCH:%.*]] ]
774; CHECK-NEXT:    [[I:%.*]] = phi i8 [ 0, [[ENTRY]] ], [ [[ADD:%.*]], [[LOOP_LATCH]] ]
775; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i8 [[I]], [[N:%.*]]
776; CHECK-NEXT:    br i1 [[CMP]], label [[LOOP_LATCH]], label [[EXIT:%.*]]
777; CHECK:       loop.latch:
778; CHECK-NEXT:    [[DIV]] = sdiv i8 [[I]], 3
779; CHECK-NEXT:    [[ADD]] = add i8 [[I]], 4
780; CHECK-NEXT:    br label [[LOOP_HEADER]]
781; CHECK:       exit:
782; CHECK-NEXT:    [[DIV1_LCSSA:%.*]] = phi i8 [ [[DIV1]], [[LOOP_HEADER]] ]
783; CHECK-NEXT:    store i8 [[DIV1_LCSSA]], ptr [[A]], align 1
784; CHECK-NEXT:    ret void
785;
786entry:
787  %a = call dereferenceable(8) noalias ptr @alloc_writeonly()
788  br label %loop.header
789
790loop.header:
791  %i = phi i8 [ 0, %entry ], [ %add, %loop.latch ]
792  %cmp = icmp ult i8 %i, %n
793  br i1 %cmp, label %loop.latch, label %exit
794
795loop.latch:
796  %div = sdiv i8 %i, 3
797  store i8 %div, ptr %a, align 1
798  %add = add i8 %i, 4
799  br label %loop.header
800
801exit:
802  ret void
803}
804
805define void @test_sink_store_only_no_phi_needed() writeonly {
806; CHECK: Function Attrs: memory(write)
807; CHECK-LABEL: @test_sink_store_only_no_phi_needed(
808; CHECK-NEXT:  entry:
809; CHECK-NEXT:    br label [[LOOP:%.*]]
810; CHECK:       loop:
811; CHECK-NEXT:    [[I:%.*]] = phi i8 [ 0, [[ENTRY:%.*]] ], [ [[ADD:%.*]], [[LOOP]] ]
812; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i8 [[I]], 4
813; CHECK-NEXT:    [[DIV:%.*]] = sdiv i8 [[I]], 3
814; CHECK-NEXT:    [[ADD]] = add i8 [[I]], 4
815; CHECK-NEXT:    br i1 [[CMP]], label [[LOOP]], label [[EXIT:%.*]]
816; CHECK:       exit:
817; CHECK-NEXT:    [[DIV_LCSSA:%.*]] = phi i8 [ [[DIV]], [[LOOP]] ]
818; CHECK-NEXT:    store i8 [[DIV_LCSSA]], ptr @glb, align 1
819; CHECK-NEXT:    ret void
820;
821entry:
822  br label %loop
823
824loop:
825  %i = phi i8 [ 0, %entry ], [ %add, %loop ]
826  %cmp = icmp ult i8 %i, 4
827  %div = sdiv i8 %i, 3
828  store i8 %div, ptr @glb, align 1
829  %add = add i8 %i, 4
830  br i1 %cmp, label %loop, label %exit
831
832exit:
833  ret void
834}
835
836define void @sink_store_lcssa_phis(ptr %ptr, i1 %c) {
837; CHECK-LABEL: @sink_store_lcssa_phis(
838; CHECK-NEXT:  entry:
839; CHECK-NEXT:    br label [[LOOP_1_HEADER:%.*]]
840; CHECK:       loop.1.header:
841; CHECK-NEXT:    br label [[LOOP_2_HEADER:%.*]]
842; CHECK:       loop.2.header:
843; CHECK-NEXT:    br i1 false, label [[LOOP_3_HEADER_PREHEADER:%.*]], label [[LOOP_1_LATCH:%.*]]
844; CHECK:       loop.3.header.preheader:
845; CHECK-NEXT:    br label [[LOOP_3_HEADER:%.*]]
846; CHECK:       loop.3.header:
847; CHECK-NEXT:    [[I_11:%.*]] = phi i32 [ [[I_1:%.*]], [[LOOP_3_LATCH:%.*]] ], [ poison, [[LOOP_3_HEADER_PREHEADER]] ]
848; CHECK-NEXT:    [[I_1]] = phi i32 [ 1, [[LOOP_3_LATCH]] ], [ 0, [[LOOP_3_HEADER_PREHEADER]] ]
849; CHECK-NEXT:    br i1 true, label [[LOOP_3_LATCH]], label [[LOOP_2_LATCH:%.*]]
850; CHECK:       loop.3.latch:
851; CHECK-NEXT:    br label [[LOOP_3_HEADER]]
852; CHECK:       loop.2.latch:
853; CHECK-NEXT:    [[I_11_LCSSA:%.*]] = phi i32 [ [[I_11]], [[LOOP_3_HEADER]] ]
854; CHECK-NEXT:    store i32 [[I_11_LCSSA]], ptr [[PTR:%.*]], align 4
855; CHECK-NEXT:    br label [[LOOP_2_HEADER]]
856; CHECK:       loop.1.latch:
857; CHECK-NEXT:    br i1 [[C:%.*]], label [[LOOP_1_HEADER]], label [[EXIT:%.*]]
858; CHECK:       exit:
859; CHECK-NEXT:    ret void
860;
861entry:
862  br label %loop.1.header
863
864loop.1.header:
865  br label %loop.2.header
866
867loop.2.header:
868  br i1 false, label %loop.3.header, label %loop.1.latch
869
870loop.3.header:
871  %i.1 = phi i32 [ 1, %loop.3.latch ], [ 0, %loop.2.header ]
872  br i1 true, label %loop.3.latch, label %loop.2.latch
873
874loop.3.latch:
875  store i32 %i.1, ptr %ptr, align 4
876  br label %loop.3.header
877
878loop.2.latch:
879  br label %loop.2.header
880
881loop.1.latch:
882  br i1 %c, label %loop.1.header, label %exit
883
884exit:
885  ret void
886}
887
888define void @cond_store_writable_dereferenceable(ptr noalias writable dereferenceable(4) %ptr) {
889; CHECK-LABEL: @cond_store_writable_dereferenceable(
890; CHECK-NEXT:    [[PTR_PROMOTED:%.*]] = load i32, ptr [[PTR:%.*]], align 4
891; CHECK-NEXT:    br label [[LOOP:%.*]]
892; CHECK:       loop:
893; CHECK-NEXT:    [[V_INC1:%.*]] = phi i32 [ [[V_INC:%.*]], [[LOOP_LATCH:%.*]] ], [ [[PTR_PROMOTED]], [[TMP0:%.*]] ]
894; CHECK-NEXT:    [[C:%.*]] = icmp ult i32 [[V_INC1]], 10
895; CHECK-NEXT:    br i1 [[C]], label [[LOOP_LATCH]], label [[EXIT:%.*]]
896; CHECK:       loop.latch:
897; CHECK-NEXT:    [[V_INC]] = add i32 [[V_INC1]], 1
898; CHECK-NEXT:    br label [[LOOP]]
899; CHECK:       exit:
900; CHECK-NEXT:    [[V_INC1_LCSSA:%.*]] = phi i32 [ [[V_INC1]], [[LOOP]] ]
901; CHECK-NEXT:    store i32 [[V_INC1_LCSSA]], ptr [[PTR]], align 4
902; CHECK-NEXT:    ret void
903;
904  br label %loop
905
906loop:
907  %v = load i32, ptr %ptr
908  %c = icmp ult i32 %v, 10
909  br i1 %c, label %loop.latch, label %exit
910
911loop.latch:
912  %v.inc = add i32 %v, 1
913  store i32 %v.inc, ptr %ptr
914  br label %loop
915
916exit:
917  ret void
918}
919
920define void @cond_store_writable_not_sufficiently_dereferenceable(ptr noalias writable dereferenceable(2) %ptr) {
921; CHECK-LABEL: @cond_store_writable_not_sufficiently_dereferenceable(
922; CHECK-NEXT:    [[PTR_PROMOTED:%.*]] = load i32, ptr [[PTR:%.*]], align 4
923; CHECK-NEXT:    br label [[LOOP:%.*]]
924; CHECK:       loop:
925; CHECK-NEXT:    [[V_INC1:%.*]] = phi i32 [ [[V_INC:%.*]], [[LOOP_LATCH:%.*]] ], [ [[PTR_PROMOTED]], [[TMP0:%.*]] ]
926; CHECK-NEXT:    [[C:%.*]] = icmp ult i32 [[V_INC1]], 10
927; CHECK-NEXT:    br i1 [[C]], label [[LOOP_LATCH]], label [[EXIT:%.*]]
928; CHECK:       loop.latch:
929; CHECK-NEXT:    [[V_INC]] = add i32 [[V_INC1]], 1
930; CHECK-NEXT:    store i32 [[V_INC]], ptr [[PTR]], align 4
931; CHECK-NEXT:    br label [[LOOP]]
932; CHECK:       exit:
933; CHECK-NEXT:    ret void
934;
935  br label %loop
936
937loop:
938  %v = load i32, ptr %ptr
939  %c = icmp ult i32 %v, 10
940  br i1 %c, label %loop.latch, label %exit
941
942loop.latch:
943  %v.inc = add i32 %v, 1
944  store i32 %v.inc, ptr %ptr
945  br label %loop
946
947exit:
948  ret void
949}
950
951!0 = !{!4, !4, i64 0}
952!1 = !{!"omnipotent char", !2}
953!2 = !{!"Simple C/C++ TBAA"}
954!3 = !{!5, !5, i64 0}
955!4 = !{!"int", !1}
956!5 = !{!"float", !1}
957