1 ; RUN: opt < %s -loop-interchange -loop-interchange-threshold=-100 -verify-loop-lcssa -S | FileCheck %s
3 ; Test case for PR41725. The induction variables in the latches escape the
4 ; loops and we must move some PHIs around.
6 @a = common dso_local global i64 0, align 4
7 @b = common dso_local global i64 0, align 4
8 @c = common dso_local global [10 x [1 x i32 ]] zeroinitializer, align 16
11 define void @test_lcssa_indvars1() {
12 ; CHECK-LABEL: @test_lcssa_indvars1()
13 ; CHECK-LABEL: inner.body:
14 ; CHECK-NEXT: %iv.inner = phi i64 [ %[[IVNEXT:[0-9]+]], %inner.body.split ], [ 5, %inner.body.preheader ]
16 ; CHECK-LABEL: inner.body.split:
17 ; CHECK-NEXT: %0 = phi i64 [ %iv.outer.next, %outer.latch ]
18 ; CHECK-NEXT: %[[IVNEXT]] = add nsw i64 %iv.inner, -1
19 ; CHECK-NEXT: %[[COND:[0-9]+]] = icmp eq i64 %iv.inner, 0
20 ; CHECK-NEXT: br i1 %[[COND]], label %exit, label %inner.body
23 ; CHECK-NEXT: %v4.lcssa = phi i64 [ %0, %inner.body.split ]
24 ; CHECK-NEXT: %v8.lcssa.lcssa = phi i64 [ %[[IVNEXT]], %inner.body.split ]
25 ; CHECK-NEXT: store i64 %v8.lcssa.lcssa, i64* @b, align 4
26 ; CHECK-NEXT: store i64 %v4.lcssa, i64* @a, align 4
29 br label %outer.header
31 outer.header: ; preds = %outer.latch, %entry
32 %iv.outer = phi i64 [ 0, %entry ], [ %iv.outer.next, %outer.latch ]
35 inner.body: ; preds = %inner.body, %outer.header
36 %iv.inner = phi i64 [ 5, %outer.header ], [ %iv.inner.next, %inner.body ]
37 %v7 = getelementptr inbounds [10 x [1 x i32]], [10 x [1 x i32]]* @c, i64 0, i64 %iv.inner, i64 %iv.outer
38 store i32 0, i32* %v7, align 4
39 %iv.inner.next = add nsw i64 %iv.inner, -1
40 %v9 = icmp eq i64 %iv.inner, 0
41 br i1 %v9, label %outer.latch, label %inner.body
43 outer.latch: ; preds = %inner.body
44 %v8.lcssa = phi i64 [ %iv.inner.next, %inner.body ]
45 %iv.outer.next = add nuw nsw i64 %iv.outer, 1
46 %v5 = icmp ult i64 %iv.outer, 2
47 br i1 %v5, label %outer.header, label %exit
49 exit: ; preds = %outer.latch
50 %v4.lcssa = phi i64 [ %iv.outer.next, %outer.latch ]
51 %v8.lcssa.lcssa = phi i64 [ %v8.lcssa, %outer.latch ]
52 store i64 %v8.lcssa.lcssa, i64* @b, align 4
53 store i64 %v4.lcssa, i64* @a, align 4
58 define void @test_lcssa_indvars2() {
59 ; CHECK-LABEL: @test_lcssa_indvars2()
60 ; CHECK-LABEL: inner.body:
61 ; CHECK-NEXT: %iv.inner = phi i64 [ %[[IVNEXT:[0-9]+]], %inner.body.split ], [ 5, %inner.body.preheader ]
63 ; CHECK-LABEL: inner.body.split:
64 ; CHECK-NEXT: %0 = phi i64 [ %iv.outer, %outer.latch ]
65 ; CHECK-NEXT: %[[IVNEXT]] = add nsw i64 %iv.inner, -1
66 ; CHECK-NEXT: %[[COND:[0-9]+]] = icmp eq i64 %[[IVNEXT]], 0
67 ; CHECK-NEXT: br i1 %[[COND]], label %exit, label %inner.body
70 ; CHECK-NEXT: %v4.lcssa = phi i64 [ %0, %inner.body.split ]
71 ; CHECK-NEXT: %v8.lcssa.lcssa = phi i64 [ %iv.inner, %inner.body.split ]
72 ; CHECK-NEXT: store i64 %v8.lcssa.lcssa, i64* @b, align 4
73 ; CHECK-NEXT: store i64 %v4.lcssa, i64* @a, align 4
76 br label %outer.header
78 outer.header: ; preds = %outer.latch, %entry
79 %iv.outer = phi i64 [ 0, %entry ], [ %iv.outer.next, %outer.latch ]
82 inner.body: ; preds = %inner.body, %outer.header
83 %iv.inner = phi i64 [ 5, %outer.header ], [ %iv.inner.next, %inner.body ]
84 %v7 = getelementptr inbounds [10 x [1 x i32]], [10 x [1 x i32]]* @c, i64 0, i64 %iv.inner, i64 %iv.outer
85 store i32 0, i32* %v7, align 4
86 %iv.inner.next = add nsw i64 %iv.inner, -1
87 %v9 = icmp eq i64 %iv.inner.next, 0
88 br i1 %v9, label %outer.latch, label %inner.body
90 outer.latch: ; preds = %inner.body
91 %v8.lcssa = phi i64 [ %iv.inner, %inner.body ]
92 %iv.outer.next = add nuw nsw i64 %iv.outer, 1
93 %v5 = icmp ult i64 %iv.outer.next, 2
94 br i1 %v5, label %outer.header, label %exit
96 exit: ; preds = %outer.latch
97 %v4.lcssa = phi i64 [ %iv.outer, %outer.latch ]
98 %v8.lcssa.lcssa = phi i64 [ %v8.lcssa, %outer.latch ]
99 store i64 %v8.lcssa.lcssa, i64* @b, align 4
100 store i64 %v4.lcssa, i64* @a, align 4
104 define void @test_lcssa_indvars3() {
105 ; CHECK-LABEL: @test_lcssa_indvars3()
106 ; CHECK-LABEL: inner.body:
107 ; CHECK-NEXT: %iv.inner = phi i64 [ %[[IVNEXT:[0-9]+]], %inner.body.split ], [ 5, %inner.body.preheader ]
109 ; CHECK-LABEL: inner.body.split:
110 ; CHECK-NEXT: %0 = phi i64 [ %iv.outer.next, %outer.latch ]
111 ; CHECK-NEXT: %[[IVNEXT]] = add nsw i64 %iv.inner, -1
112 ; CHECK-NEXT: %[[COND:[0-9]+]] = icmp eq i64 %iv.inner, 0
113 ; CHECK-NEXT: br i1 %[[COND]], label %exit, label %inner.body
116 ; CHECK-NEXT: %v4.lcssa = phi i64 [ %0, %inner.body.split ]
117 ; CHECK-NEXT: %v8.lcssa.lcssa = phi i64 [ %[[IVNEXT]], %inner.body.split ]
118 ; CHECK-NEXT: %v8.lcssa.lcssa.2 = phi i64 [ %[[IVNEXT]], %inner.body.split ]
119 ; CHECK-NEXT: %r1 = add i64 %v8.lcssa.lcssa, %v8.lcssa.lcssa.2
120 ; CHECK-NEXT: store i64 %r1, i64* @b, align 4
121 ; CHECK-NEXT: store i64 %v4.lcssa, i64* @a, align 4
125 br label %outer.header
127 outer.header: ; preds = %outer.latch, %entry
128 %iv.outer = phi i64 [ 0, %entry ], [ %iv.outer.next, %outer.latch ]
131 inner.body: ; preds = %inner.body, %outer.header
132 %iv.inner = phi i64 [ 5, %outer.header ], [ %iv.inner.next, %inner.body ]
133 %v7 = getelementptr inbounds [10 x [1 x i32]], [10 x [1 x i32]]* @c, i64 0, i64 %iv.inner, i64 %iv.outer
134 store i32 0, i32* %v7, align 4
135 %iv.inner.next = add nsw i64 %iv.inner, -1
136 %v9 = icmp eq i64 %iv.inner, 0
137 br i1 %v9, label %outer.latch, label %inner.body
139 outer.latch: ; preds = %inner.body
140 %v8.lcssa = phi i64 [ %iv.inner.next, %inner.body ]
141 ;%const.lcssa = phi i64 [ 111, %inner.body ]
142 %iv.outer.next = add nuw nsw i64 %iv.outer, 1
143 %v5 = icmp ult i64 %iv.outer, 2
144 br i1 %v5, label %outer.header, label %exit
146 exit: ; preds = %outer.latch
147 %v4.lcssa = phi i64 [ %iv.outer.next, %outer.latch ]
148 %v8.lcssa.lcssa = phi i64 [ %v8.lcssa, %outer.latch ]
149 %v8.lcssa.lcssa.2 = phi i64 [ %v8.lcssa, %outer.latch ]
150 %r1 = add i64 %v8.lcssa.lcssa, %v8.lcssa.lcssa.2
151 store i64 %r1, i64* @b, align 4
152 store i64 %v4.lcssa, i64* @a, align 4
157 ; Make sure we do not crash for loops without reachable exits.
158 define void @no_reachable_exits() {
159 ; Check we interchanged.
160 ; CHECK-LABEL: @no_reachable_exits() {
162 ; CHECK-NEXT: br label %inner.ph
163 ; CHECK-LABEL: outer.ph:
164 ; CHECK-NEXT: br label %outer.header
165 ; CHECK-LABEL: inner.ph:
166 ; CHECK-NEXT: br label %inner.body
167 ; CHECK-LABEL: inner.body:
168 ; CHECK-NEXT: %tmp31 = phi i32 [ 0, %inner.ph ], [ %[[IVNEXT:[0-9]]], %inner.body.split ]
169 ; CHECK-NEXT: br label %outer.ph
170 ; CHECK-LABEL: inner.body.split:
171 ; CHECK-NEXT: %[[IVNEXT]] = add nsw i32 %tmp31, 1
172 ; CHECK-NEXT: br i1 false, label %inner.body, label %exit
178 outer.ph: ; preds = %bb
179 br label %outer.header
181 outer.header: ; preds = %outer.ph, %outer.latch
182 %tmp2 = phi i32 [ 0, %outer.ph ], [ %tmp8, %outer.latch ]
183 br i1 undef, label %inner.ph, label %outer.latch
185 inner.ph: ; preds = %outer.header
188 inner.body: ; preds = %inner.ph, %inner.body
189 %tmp31 = phi i32 [ 0, %inner.ph ], [ %tmp6, %inner.body]
190 %tmp5 = load i32*, i32** undef, align 8
191 %tmp6 = add nsw i32 %tmp31, 1
192 br i1 undef, label %inner.body, label %outer.latch
194 outer.latch: ; preds = %inner.body, %outer.header
195 %tmp8 = add nsw i32 %tmp2, 1
196 br i1 undef, label %outer.header, label %exit
198 exit: ; preds = %outer.latch