1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt < %s -aa-pipeline=basic-aa,globals-aa -S -passes='require<globals-aa>,function(loop-mssa(licm))' | FileCheck %s
8 ;static struct str obj;
9 ;extern void nocapture_nocallback_func(struct str *);
11 ; nocapture_nocallback_func(&obj);
12 ; for (int i = 0; i < 1000; ++i) {
13 ; unknown_call(); // optional
18 target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
20 %struct.str = type { ptr }
22 @obj0 = internal global %struct.str zeroinitializer, align 8
23 @obj1 = internal global %struct.str zeroinitializer, align 8
24 @obj2 = internal global %struct.str zeroinitializer, align 8
25 @obj3 = internal global %struct.str zeroinitializer, align 8
26 @obj4 = internal global %struct.str zeroinitializer, align 8
27 @obj5 = internal global %struct.str zeroinitializer, align 8
29 define dso_local void @test0(ptr %p) {
30 ; Check that load from @obj0 is hoisted from the loop, meaning
31 ; that it does not conflict with the store inside the loop:
32 ; CHECK-LABEL: @test0(
34 ; CHECK-NEXT: call void @nocapture_nocallback_func(ptr @obj0)
35 ; CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr @obj0, align 8
36 ; CHECK-NEXT: br label [[FOR_COND:%.*]]
38 ; CHECK-NEXT: [[I_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ]
39 ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I_0]], 1000
40 ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]]
42 ; CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[I_0]] to i64
43 ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds ptr, ptr [[TMP0]], i64 [[IDXPROM]]
44 ; CHECK-NEXT: store ptr [[P:%.*]], ptr [[ARRAYIDX]], align 8
45 ; CHECK-NEXT: br label [[FOR_INC]]
47 ; CHECK-NEXT: [[INC]] = add nsw i32 [[I_0]], 1
48 ; CHECK-NEXT: br label [[FOR_COND]]
50 ; CHECK-NEXT: ret void
54 call void @nocapture_nocallback_func(ptr @obj0)
57 for.cond: ; preds = %for.inc, %entry
58 %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
59 %cmp = icmp slt i32 %i.0, 1000
60 br i1 %cmp, label %for.body, label %for.end
62 for.body: ; preds = %for.cond
63 %0 = load ptr, ptr @obj0, align 8
64 %idxprom = sext i32 %i.0 to i64
65 %arrayidx = getelementptr inbounds ptr, ptr %0, i64 %idxprom
66 store ptr %p, ptr %arrayidx, align 8
69 for.inc: ; preds = %for.body
70 %inc = add nsw i32 %i.0, 1
73 for.end: ; preds = %for.cond
77 define dso_local void @test1(ptr %p) {
78 ; Check that load from @obj1 is not hoisted from the loop,
79 ; because 'nocallback' is missing:
80 ; CHECK-LABEL: @test1(
82 ; CHECK-NEXT: call void @nocapture_func(ptr @obj1)
83 ; CHECK-NEXT: br label [[FOR_COND:%.*]]
85 ; CHECK-NEXT: [[I_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ]
86 ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I_0]], 1000
87 ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]]
89 ; CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr @obj1, align 8
90 ; CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[I_0]] to i64
91 ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds ptr, ptr [[TMP0]], i64 [[IDXPROM]]
92 ; CHECK-NEXT: store ptr [[P:%.*]], ptr [[ARRAYIDX]], align 8
93 ; CHECK-NEXT: br label [[FOR_INC]]
95 ; CHECK-NEXT: [[INC]] = add nsw i32 [[I_0]], 1
96 ; CHECK-NEXT: br label [[FOR_COND]]
98 ; CHECK-NEXT: ret void
102 call void @nocapture_func(ptr @obj1)
105 for.cond: ; preds = %for.inc, %entry
106 %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
107 %cmp = icmp slt i32 %i.0, 1000
108 br i1 %cmp, label %for.body, label %for.end
110 for.body: ; preds = %for.cond
111 %0 = load ptr, ptr @obj1, align 8
112 %idxprom = sext i32 %i.0 to i64
113 %arrayidx = getelementptr inbounds ptr, ptr %0, i64 %idxprom
114 store ptr %p, ptr %arrayidx, align 8
117 for.inc: ; preds = %for.body
118 %inc = add nsw i32 %i.0, 1
121 for.end: ; preds = %for.cond
125 define dso_local void @test2(ptr %p) {
126 ; Check that load from @obj2 is not hoisted from the loop,
127 ; because 'nocapture' is missing:
128 ; CHECK-LABEL: @test2(
130 ; CHECK-NEXT: call void @nocallback_func(ptr @obj2)
131 ; CHECK-NEXT: br label [[FOR_COND:%.*]]
133 ; CHECK-NEXT: [[I_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ]
134 ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I_0]], 1000
135 ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]]
137 ; CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr @obj2, align 8
138 ; CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[I_0]] to i64
139 ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds ptr, ptr [[TMP0]], i64 [[IDXPROM]]
140 ; CHECK-NEXT: store ptr [[P:%.*]], ptr [[ARRAYIDX]], align 8
141 ; CHECK-NEXT: br label [[FOR_INC]]
143 ; CHECK-NEXT: [[INC]] = add nsw i32 [[I_0]], 1
144 ; CHECK-NEXT: br label [[FOR_COND]]
146 ; CHECK-NEXT: ret void
150 call void @nocallback_func(ptr @obj2)
153 for.cond: ; preds = %for.inc, %entry
154 %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
155 %cmp = icmp slt i32 %i.0, 1000
156 br i1 %cmp, label %for.body, label %for.end
158 for.body: ; preds = %for.cond
159 %0 = load ptr, ptr @obj2, align 8
160 %idxprom = sext i32 %i.0 to i64
161 %arrayidx = getelementptr inbounds ptr, ptr %0, i64 %idxprom
162 store ptr %p, ptr %arrayidx, align 8
165 for.inc: ; preds = %for.body
166 %inc = add nsw i32 %i.0, 1
169 for.end: ; preds = %for.cond
173 define dso_local void @test3(ptr %p) {
174 ; Check that load from @obj3 is hoisted from the loop, even though
175 ; there is unknown call in the loop.
176 ; CHECK-LABEL: @test3(
178 ; CHECK-NEXT: call void @nocapture_nocallback_func(ptr @obj3)
179 ; CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr @obj3, align 8
180 ; CHECK-NEXT: br label [[FOR_COND:%.*]]
182 ; CHECK-NEXT: [[I_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ]
183 ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I_0]], 1000
184 ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]]
186 ; CHECK-NEXT: call void @unknown_call()
187 ; CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[I_0]] to i64
188 ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds ptr, ptr [[TMP0]], i64 [[IDXPROM]]
189 ; CHECK-NEXT: store ptr [[P:%.*]], ptr [[ARRAYIDX]], align 8
190 ; CHECK-NEXT: br label [[FOR_INC]]
192 ; CHECK-NEXT: [[INC]] = add nsw i32 [[I_0]], 1
193 ; CHECK-NEXT: br label [[FOR_COND]]
195 ; CHECK-NEXT: ret void
199 call void @nocapture_nocallback_func(ptr @obj3)
202 for.cond: ; preds = %for.inc, %entry
203 %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
204 %cmp = icmp slt i32 %i.0, 1000
205 br i1 %cmp, label %for.body, label %for.end
207 for.body: ; preds = %for.cond
208 %0 = load ptr, ptr @obj3, align 8
209 call void @unknown_call()
210 %idxprom = sext i32 %i.0 to i64
211 %arrayidx = getelementptr inbounds ptr, ptr %0, i64 %idxprom
212 store ptr %p, ptr %arrayidx, align 8
215 for.inc: ; preds = %for.body
216 %inc = add nsw i32 %i.0, 1
219 for.end: ; preds = %for.cond
223 define dso_local void @test4(ptr %p) {
224 ; Check that load from @obj4 is not hoisted from the loop,
225 ; because 'nocallback' is missing:
226 ; CHECK-LABEL: @test4(
228 ; CHECK-NEXT: call void @nocapture_func(ptr @obj4)
229 ; CHECK-NEXT: br label [[FOR_COND:%.*]]
231 ; CHECK-NEXT: [[I_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ]
232 ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I_0]], 1000
233 ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]]
235 ; CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr @obj4, align 8
236 ; CHECK-NEXT: call void @unknown_call()
237 ; CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[I_0]] to i64
238 ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds ptr, ptr [[TMP0]], i64 [[IDXPROM]]
239 ; CHECK-NEXT: store ptr [[P:%.*]], ptr [[ARRAYIDX]], align 8
240 ; CHECK-NEXT: br label [[FOR_INC]]
242 ; CHECK-NEXT: [[INC]] = add nsw i32 [[I_0]], 1
243 ; CHECK-NEXT: br label [[FOR_COND]]
245 ; CHECK-NEXT: ret void
249 call void @nocapture_func(ptr @obj4)
252 for.cond: ; preds = %for.inc, %entry
253 %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
254 %cmp = icmp slt i32 %i.0, 1000
255 br i1 %cmp, label %for.body, label %for.end
257 for.body: ; preds = %for.cond
258 %0 = load ptr, ptr @obj4, align 8
259 call void @unknown_call()
260 %idxprom = sext i32 %i.0 to i64
261 %arrayidx = getelementptr inbounds ptr, ptr %0, i64 %idxprom
262 store ptr %p, ptr %arrayidx, align 8
265 for.inc: ; preds = %for.body
266 %inc = add nsw i32 %i.0, 1
269 for.end: ; preds = %for.cond
273 define dso_local void @test5(ptr %p) {
274 ; Check that load from @obj5 is not hoisted from the loop,
275 ; because 'nocapture' is missing:
276 ; CHECK-LABEL: @test5(
278 ; CHECK-NEXT: call void @nocallback_func(ptr @obj5)
279 ; CHECK-NEXT: br label [[FOR_COND:%.*]]
281 ; CHECK-NEXT: [[I_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ]
282 ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I_0]], 1000
283 ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]]
285 ; CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr @obj5, align 8
286 ; CHECK-NEXT: call void @unknown_call()
287 ; CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[I_0]] to i64
288 ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds ptr, ptr [[TMP0]], i64 [[IDXPROM]]
289 ; CHECK-NEXT: store ptr [[P:%.*]], ptr [[ARRAYIDX]], align 8
290 ; CHECK-NEXT: br label [[FOR_INC]]
292 ; CHECK-NEXT: [[INC]] = add nsw i32 [[I_0]], 1
293 ; CHECK-NEXT: br label [[FOR_COND]]
295 ; CHECK-NEXT: ret void
299 call void @nocallback_func(ptr @obj5)
302 for.cond: ; preds = %for.inc, %entry
303 %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
304 %cmp = icmp slt i32 %i.0, 1000
305 br i1 %cmp, label %for.body, label %for.end
307 for.body: ; preds = %for.cond
308 %0 = load ptr, ptr @obj5, align 8
309 call void @unknown_call()
310 %idxprom = sext i32 %i.0 to i64
311 %arrayidx = getelementptr inbounds ptr, ptr %0, i64 %idxprom
312 store ptr %p, ptr %arrayidx, align 8
315 for.inc: ; preds = %for.body
316 %inc = add nsw i32 %i.0, 1
319 for.end: ; preds = %for.cond
323 declare void @nocapture_nocallback_func(ptr nocapture) nocallback
324 declare void @nocapture_func(ptr nocapture)
325 declare void @nocallback_func(ptr) nocallback
326 ; nosync and nocallback are required, otherwise the call
327 ; will by ModRef for any global:
328 declare void @unknown_call() nosync nocallback