xref: /llvm-project/llvm/test/Analysis/GlobalsModRef/noescape-nocapture-nocallback.ll (revision 5bd8175dd70416221c58c3c92f06886427680cb5)
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
3
4;Reference C code:
5;struct str {
6;  void **p;
7;};
8;static struct str obj;
9;extern void nocapture_nocallback_func(struct str *);
10;void test(void *p) {
11;  nocapture_nocallback_func(&obj);
12;  for (int i = 0; i < 1000; ++i) {
13;    unknown_call(); // optional
14;    obj.p[i] = p;
15;  }
16;}
17
18target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
19
20%struct.str = type { ptr }
21
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
28
29define 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(
33; CHECK-NEXT:  entry:
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:%.*]]
37; CHECK:       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:%.*]]
41; CHECK:       for.body:
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]]
46; CHECK:       for.inc:
47; CHECK-NEXT:    [[INC]] = add nsw i32 [[I_0]], 1
48; CHECK-NEXT:    br label [[FOR_COND]]
49; CHECK:       for.end:
50; CHECK-NEXT:    ret void
51;
52
53entry:
54  call void @nocapture_nocallback_func(ptr @obj0)
55  br label %for.cond
56
57for.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
61
62for.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
67  br label %for.inc
68
69for.inc:                                          ; preds = %for.body
70  %inc = add nsw i32 %i.0, 1
71  br label %for.cond
72
73for.end:                                          ; preds = %for.cond
74  ret void
75}
76
77define 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(
81; CHECK-NEXT:  entry:
82; CHECK-NEXT:    call void @nocapture_func(ptr @obj1)
83; CHECK-NEXT:    br label [[FOR_COND:%.*]]
84; CHECK:       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:%.*]]
88; CHECK:       for.body:
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]]
94; CHECK:       for.inc:
95; CHECK-NEXT:    [[INC]] = add nsw i32 [[I_0]], 1
96; CHECK-NEXT:    br label [[FOR_COND]]
97; CHECK:       for.end:
98; CHECK-NEXT:    ret void
99;
100
101entry:
102  call void @nocapture_func(ptr @obj1)
103  br label %for.cond
104
105for.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
109
110for.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
115  br label %for.inc
116
117for.inc:                                          ; preds = %for.body
118  %inc = add nsw i32 %i.0, 1
119  br label %for.cond
120
121for.end:                                          ; preds = %for.cond
122  ret void
123}
124
125define 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(
129; CHECK-NEXT:  entry:
130; CHECK-NEXT:    call void @nocallback_func(ptr @obj2)
131; CHECK-NEXT:    br label [[FOR_COND:%.*]]
132; CHECK:       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:%.*]]
136; CHECK:       for.body:
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]]
142; CHECK:       for.inc:
143; CHECK-NEXT:    [[INC]] = add nsw i32 [[I_0]], 1
144; CHECK-NEXT:    br label [[FOR_COND]]
145; CHECK:       for.end:
146; CHECK-NEXT:    ret void
147;
148
149entry:
150  call void @nocallback_func(ptr @obj2)
151  br label %for.cond
152
153for.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
157
158for.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
163  br label %for.inc
164
165for.inc:                                          ; preds = %for.body
166  %inc = add nsw i32 %i.0, 1
167  br label %for.cond
168
169for.end:                                          ; preds = %for.cond
170  ret void
171}
172
173define 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(
177; CHECK-NEXT:  entry:
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:%.*]]
181; CHECK:       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:%.*]]
185; CHECK:       for.body:
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]]
191; CHECK:       for.inc:
192; CHECK-NEXT:    [[INC]] = add nsw i32 [[I_0]], 1
193; CHECK-NEXT:    br label [[FOR_COND]]
194; CHECK:       for.end:
195; CHECK-NEXT:    ret void
196;
197
198entry:
199  call void @nocapture_nocallback_func(ptr @obj3)
200  br label %for.cond
201
202for.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
206
207for.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
213  br label %for.inc
214
215for.inc:                                          ; preds = %for.body
216  %inc = add nsw i32 %i.0, 1
217  br label %for.cond
218
219for.end:                                          ; preds = %for.cond
220  ret void
221}
222
223define 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(
227; CHECK-NEXT:  entry:
228; CHECK-NEXT:    call void @nocapture_func(ptr @obj4)
229; CHECK-NEXT:    br label [[FOR_COND:%.*]]
230; CHECK:       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:%.*]]
234; CHECK:       for.body:
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]]
241; CHECK:       for.inc:
242; CHECK-NEXT:    [[INC]] = add nsw i32 [[I_0]], 1
243; CHECK-NEXT:    br label [[FOR_COND]]
244; CHECK:       for.end:
245; CHECK-NEXT:    ret void
246;
247
248entry:
249  call void @nocapture_func(ptr @obj4)
250  br label %for.cond
251
252for.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
256
257for.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
263  br label %for.inc
264
265for.inc:                                          ; preds = %for.body
266  %inc = add nsw i32 %i.0, 1
267  br label %for.cond
268
269for.end:                                          ; preds = %for.cond
270  ret void
271}
272
273define 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(
277; CHECK-NEXT:  entry:
278; CHECK-NEXT:    call void @nocallback_func(ptr @obj5)
279; CHECK-NEXT:    br label [[FOR_COND:%.*]]
280; CHECK:       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:%.*]]
284; CHECK:       for.body:
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]]
291; CHECK:       for.inc:
292; CHECK-NEXT:    [[INC]] = add nsw i32 [[I_0]], 1
293; CHECK-NEXT:    br label [[FOR_COND]]
294; CHECK:       for.end:
295; CHECK-NEXT:    ret void
296;
297
298entry:
299  call void @nocallback_func(ptr @obj5)
300  br label %for.cond
301
302for.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
306
307for.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
313  br label %for.inc
314
315for.inc:                                          ; preds = %for.body
316  %inc = add nsw i32 %i.0, 1
317  br label %for.cond
318
319for.end:                                          ; preds = %for.cond
320  ret void
321}
322
323declare void @nocapture_nocallback_func(ptr nocapture) nocallback
324declare void @nocapture_func(ptr nocapture)
325declare void @nocallback_func(ptr) nocallback
326; nosync and nocallback are required, otherwise the call
327; will by ModRef for any global:
328declare void @unknown_call() nosync nocallback
329