1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt -S -basic-aa -licm -use-dereferenceable-at-point-semantics=0 < %s | FileCheck %s
3; RUN: opt -S -basic-aa -licm -use-dereferenceable-at-point-semantics=1 < %s | FileCheck %s
4
5target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
6target triple = "x86_64-unknown-linux-gnu"
7
8declare void @unknown()
9declare void @init(i8* nocapture)
10declare void @use(i8)
11
12define i8 @test_sink_alloca() {
13; CHECK-LABEL: @test_sink_alloca(
14; CHECK-NEXT:  entry:
15; CHECK-NEXT:    [[A:%.*]] = alloca [32 x i8], align 1
16; CHECK-NEXT:    [[A_RAW:%.*]] = bitcast [32 x i8]* [[A]] to i8*
17; CHECK-NEXT:    call void @init(i8* [[A_RAW]])
18; CHECK-NEXT:    br label [[FOR_BODY:%.*]]
19; CHECK:       for.body:
20; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[FOR_BODY]] ], [ 0, [[ENTRY:%.*]] ]
21; CHECK-NEXT:    call void @unknown()
22; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
23; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp eq i64 [[IV_NEXT]], 200
24; CHECK-NEXT:    br i1 [[EXITCOND]], label [[FOR_END:%.*]], label [[FOR_BODY]]
25; CHECK:       for.end:
26; CHECK-NEXT:    [[ADDR_LE:%.*]] = getelementptr i8, i8* [[A_RAW]], i32 31
27; CHECK-NEXT:    [[RES_LE:%.*]] = load i8, i8* [[ADDR_LE]], align 1
28; CHECK-NEXT:    ret i8 [[RES_LE]]
29;
30entry:
31  %a = alloca [32 x i8]
32  %a.raw = bitcast [32 x i8]* %a to i8*
33  call void @init(i8* %a.raw)
34  br label %for.body
35
36for.body:
37  %iv = phi i64 [ %iv.next, %for.body ], [ 0, %entry ]
38  call void @unknown() ;; may throw
39  %addr = getelementptr i8, i8* %a.raw, i32 31
40  %res = load i8, i8* %addr
41  %iv.next = add nuw nsw i64 %iv, 1
42  %exitcond = icmp eq i64 %iv.next, 200
43  br i1 %exitcond, label %for.end, label %for.body
44
45for.end:
46  ret i8 %res
47}
48
49define i8 @test_hoist_alloca() {
50; CHECK-LABEL: @test_hoist_alloca(
51; CHECK-NEXT:  entry:
52; CHECK-NEXT:    [[A:%.*]] = alloca [32 x i8], align 1
53; CHECK-NEXT:    [[A_RAW:%.*]] = bitcast [32 x i8]* [[A]] to i8*
54; CHECK-NEXT:    call void @init(i8* [[A_RAW]])
55; CHECK-NEXT:    [[ADDR:%.*]] = getelementptr i8, i8* [[A_RAW]], i32 31
56; CHECK-NEXT:    [[RES:%.*]] = load i8, i8* [[ADDR]], align 1
57; CHECK-NEXT:    br label [[FOR_BODY:%.*]]
58; CHECK:       for.body:
59; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[FOR_BODY]] ], [ 0, [[ENTRY:%.*]] ]
60; CHECK-NEXT:    call void @unknown()
61; CHECK-NEXT:    call void @use(i8 [[RES]])
62; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
63; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp eq i64 [[IV_NEXT]], 200
64; CHECK-NEXT:    br i1 [[EXITCOND]], label [[FOR_END:%.*]], label [[FOR_BODY]]
65; CHECK:       for.end:
66; CHECK-NEXT:    [[RES_LCSSA:%.*]] = phi i8 [ [[RES]], [[FOR_BODY]] ]
67; CHECK-NEXT:    ret i8 [[RES_LCSSA]]
68;
69entry:
70  %a = alloca [32 x i8]
71  %a.raw = bitcast [32 x i8]* %a to i8*
72  call void @init(i8* %a.raw)
73  br label %for.body
74
75for.body:
76  %iv = phi i64 [ %iv.next, %for.body ], [ 0, %entry ]
77  call void @unknown() ;; may throw
78  %addr = getelementptr i8, i8* %a.raw, i32 31
79  %res = load i8, i8* %addr
80  call void @use(i8 %res)
81  %iv.next = add nuw nsw i64 %iv, 1
82  %exitcond = icmp eq i64 %iv.next, 200
83  br i1 %exitcond, label %for.end, label %for.body
84
85for.end:
86  ret i8 %res
87}
88
89; The attributes listed here are a) inferred by -O3 from the names
90; and b) required for a standalone test.  We're very inconsistent about
91; which decisions we drive from TLI vs assume attributes have been infered.
92declare void @free(i8* nocapture)
93declare noalias i8* @malloc(i64)
94
95define i8 @test_sink_malloc() {
96; CHECK-LABEL: @test_sink_malloc(
97; CHECK-NEXT:  entry:
98; CHECK-NEXT:    [[A_RAW:%.*]] = call nonnull i8* @malloc(i64 32)
99; CHECK-NEXT:    call void @init(i8* [[A_RAW]])
100; CHECK-NEXT:    br label [[FOR_BODY:%.*]]
101; CHECK:       for.body:
102; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[FOR_BODY]] ], [ 0, [[ENTRY:%.*]] ]
103; CHECK-NEXT:    call void @unknown()
104; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
105; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp eq i64 [[IV_NEXT]], 200
106; CHECK-NEXT:    br i1 [[EXITCOND]], label [[FOR_END:%.*]], label [[FOR_BODY]]
107; CHECK:       for.end:
108; CHECK-NEXT:    [[ADDR_LE:%.*]] = getelementptr i8, i8* [[A_RAW]], i32 31
109; CHECK-NEXT:    [[RES_LE:%.*]] = load i8, i8* [[ADDR_LE]], align 1
110; CHECK-NEXT:    call void @free(i8* [[A_RAW]])
111; CHECK-NEXT:    ret i8 [[RES_LE]]
112;
113entry:
114  ; Mark as nonnull to simplify test
115  %a.raw = call nonnull i8* @malloc(i64 32)
116  call void @init(i8* %a.raw)
117  br label %for.body
118
119for.body:
120  %iv = phi i64 [ %iv.next, %for.body ], [ 0, %entry ]
121  call void @unknown() ;; may throw
122  %addr = getelementptr i8, i8* %a.raw, i32 31
123  %res = load i8, i8* %addr
124  %iv.next = add nuw nsw i64 %iv, 1
125  %exitcond = icmp eq i64 %iv.next, 200
126  br i1 %exitcond, label %for.end, label %for.body
127
128for.end:
129  call void @free(i8* %a.raw)
130  ret i8 %res
131}
132
133; TODO: We can hoist the load in this case, but only once we have
134; some form of context sensitive free analysis.
135define i8 @test_hoist_malloc() {
136; CHECK-LABEL: @test_hoist_malloc(
137; CHECK-NEXT:  entry:
138; CHECK-NEXT:    [[A_RAW:%.*]] = call nonnull i8* @malloc(i64 32)
139; CHECK-NEXT:    call void @init(i8* [[A_RAW]])
140; CHECK-NEXT:    [[ADDR:%.*]] = getelementptr i8, i8* [[A_RAW]], i32 31
141; CHECK-NEXT:    br label [[FOR_BODY:%.*]]
142; CHECK:       for.body:
143; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[FOR_BODY]] ], [ 0, [[ENTRY:%.*]] ]
144; CHECK-NEXT:    call void @unknown()
145; CHECK-NEXT:    [[RES:%.*]] = load i8, i8* [[ADDR]], align 1
146; CHECK-NEXT:    call void @use(i8 [[RES]])
147; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
148; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp eq i64 [[IV_NEXT]], 200
149; CHECK-NEXT:    br i1 [[EXITCOND]], label [[FOR_END:%.*]], label [[FOR_BODY]]
150; CHECK:       for.end:
151; CHECK-NEXT:    [[RES_LCSSA:%.*]] = phi i8 [ [[RES]], [[FOR_BODY]] ]
152; CHECK-NEXT:    call void @free(i8* [[A_RAW]])
153; CHECK-NEXT:    ret i8 [[RES_LCSSA]]
154;
155entry:
156  %a.raw = call nonnull i8* @malloc(i64 32)
157  call void @init(i8* %a.raw)
158  br label %for.body
159
160for.body:
161  %iv = phi i64 [ %iv.next, %for.body ], [ 0, %entry ]
162  call void @unknown() ;; may throw
163  %addr = getelementptr i8, i8* %a.raw, i32 31
164  %res = load i8, i8* %addr
165  call void @use(i8 %res)
166  %iv.next = add nuw nsw i64 %iv, 1
167  %exitcond = icmp eq i64 %iv.next, 200
168  br i1 %exitcond, label %for.end, label %for.body
169
170for.end:
171  call void @free(i8* %a.raw)
172  ret i8 %res
173}
174
175define i8 @test_hoist_malloc_leak() nofree nosync {
176; CHECK-LABEL: @test_hoist_malloc_leak(
177; CHECK-NEXT:  entry:
178; CHECK-NEXT:    [[A_RAW:%.*]] = call nonnull i8* @malloc(i64 32)
179; CHECK-NEXT:    call void @init(i8* [[A_RAW]])
180; CHECK-NEXT:    [[ADDR:%.*]] = getelementptr i8, i8* [[A_RAW]], i32 31
181; CHECK-NEXT:    br label [[FOR_BODY:%.*]]
182; CHECK:       for.body:
183; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[FOR_BODY]] ], [ 0, [[ENTRY:%.*]] ]
184; CHECK-NEXT:    call void @unknown()
185; CHECK-NEXT:    [[RES:%.*]] = load i8, i8* [[ADDR]], align 1
186; CHECK-NEXT:    call void @use(i8 [[RES]])
187; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
188; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp eq i64 [[IV_NEXT]], 200
189; CHECK-NEXT:    br i1 [[EXITCOND]], label [[FOR_END:%.*]], label [[FOR_BODY]]
190; CHECK:       for.end:
191; CHECK-NEXT:    [[RES_LCSSA:%.*]] = phi i8 [ [[RES]], [[FOR_BODY]] ]
192; CHECK-NEXT:    ret i8 [[RES_LCSSA]]
193;
194entry:
195  %a.raw = call nonnull i8* @malloc(i64 32)
196  call void @init(i8* %a.raw)
197  br label %for.body
198
199for.body:
200  %iv = phi i64 [ %iv.next, %for.body ], [ 0, %entry ]
201  call void @unknown() ;; may throw
202  %addr = getelementptr i8, i8* %a.raw, i32 31
203  %res = load i8, i8* %addr
204  call void @use(i8 %res)
205  %iv.next = add nuw nsw i64 %iv, 1
206  %exitcond = icmp eq i64 %iv.next, 200
207  br i1 %exitcond, label %for.end, label %for.body
208
209for.end:
210  ret i8 %res
211}
212
213; In this case, we can't hoist the load out of the loop as the memory it
214; accesses may have been conditionally freed in a manner correlated with
215; whether the load is reached in the loop.
216define void @test_hoist_malloc_cond_free(i1 %c) {
217; CHECK-LABEL: @test_hoist_malloc_cond_free(
218; CHECK-NEXT:  entry:
219; CHECK-NEXT:    [[A_RAW:%.*]] = call nonnull i8* @malloc(i64 32)
220; CHECK-NEXT:    call void @init(i8* [[A_RAW]])
221; CHECK-NEXT:    br i1 [[C:%.*]], label [[COND_FREE:%.*]], label [[PREHEADER:%.*]]
222; CHECK:       cond.free:
223; CHECK-NEXT:    call void @free(i8* [[A_RAW]])
224; CHECK-NEXT:    br label [[PREHEADER]]
225; CHECK:       preheader:
226; CHECK-NEXT:    [[ADDR:%.*]] = getelementptr i8, i8* [[A_RAW]], i32 31
227; CHECK-NEXT:    br label [[FOR_BODY:%.*]]
228; CHECK:       for.body:
229; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ], [ 0, [[PREHEADER]] ]
230; CHECK-NEXT:    br i1 [[C]], label [[FOR_END:%.*]], label [[LOOP_LATCH]]
231; CHECK:       loop.latch:
232; CHECK-NEXT:    call void @unknown()
233; CHECK-NEXT:    [[RES:%.*]] = load i8, i8* [[ADDR]], align 1
234; CHECK-NEXT:    call void @use(i8 [[RES]])
235; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
236; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp eq i64 [[IV_NEXT]], 200
237; CHECK-NEXT:    br i1 [[EXITCOND]], label [[FOR_END]], label [[FOR_BODY]]
238; CHECK:       for.end:
239; CHECK-NEXT:    ret void
240;
241entry:
242  %a.raw = call nonnull i8* @malloc(i64 32)
243  call void @init(i8* %a.raw)
244  br i1 %c, label %cond.free, label %preheader
245cond.free:
246  call void @free(i8* %a.raw)
247  br label %preheader
248preheader:
249  br label %for.body
250
251for.body:
252  %iv = phi i64 [ %iv.next, %loop.latch ], [ 0, %preheader ]
253  br i1 %c, label %for.end, label %loop.latch
254
255loop.latch:
256  call void @unknown() ;; may throw
257  %addr = getelementptr i8, i8* %a.raw, i32 31
258  %res = load i8, i8* %addr
259  call void @use(i8 %res)
260  %iv.next = add nuw nsw i64 %iv, 1
261  %exitcond = icmp eq i64 %iv.next, 200
262  br i1 %exitcond, label %for.end, label %for.body
263
264for.end:
265  ret void
266}
267
268define i8 @test_sink_malloc_cond_free(i1 %c) {
269; CHECK-LABEL: @test_sink_malloc_cond_free(
270; CHECK-NEXT:  entry:
271; CHECK-NEXT:    [[A_RAW:%.*]] = call nonnull i8* @malloc(i64 32)
272; CHECK-NEXT:    call void @init(i8* [[A_RAW]])
273; CHECK-NEXT:    br i1 [[C:%.*]], label [[COND_FREE:%.*]], label [[PREHEADER:%.*]]
274; CHECK:       cond.free:
275; CHECK-NEXT:    call void @free(i8* [[A_RAW]])
276; CHECK-NEXT:    br label [[PREHEADER]]
277; CHECK:       preheader:
278; CHECK-NEXT:    br label [[FOR_BODY:%.*]]
279; CHECK:       for.body:
280; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ], [ 0, [[PREHEADER]] ]
281; CHECK-NEXT:    br i1 [[C]], label [[FOR_END_SPLIT_LOOP_EXIT1:%.*]], label [[LOOP_LATCH]]
282; CHECK:       loop.latch:
283; CHECK-NEXT:    call void @unknown()
284; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
285; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp eq i64 [[IV_NEXT]], 200
286; CHECK-NEXT:    br i1 [[EXITCOND]], label [[FOR_END_SPLIT_LOOP_EXIT:%.*]], label [[FOR_BODY]]
287; CHECK:       for.end.split.loop.exit:
288; CHECK-NEXT:    [[ADDR_LE:%.*]] = getelementptr i8, i8* [[A_RAW]], i32 31
289; CHECK-NEXT:    [[RES_LE:%.*]] = load i8, i8* [[ADDR_LE]], align 1
290; CHECK-NEXT:    br label [[FOR_END:%.*]]
291; CHECK:       for.end.split.loop.exit1:
292; CHECK-NEXT:    [[PHI_PH2:%.*]] = phi i8 [ 0, [[FOR_BODY]] ]
293; CHECK-NEXT:    br label [[FOR_END]]
294; CHECK:       for.end:
295; CHECK-NEXT:    [[PHI:%.*]] = phi i8 [ [[RES_LE]], [[FOR_END_SPLIT_LOOP_EXIT]] ], [ [[PHI_PH2]], [[FOR_END_SPLIT_LOOP_EXIT1]] ]
296; CHECK-NEXT:    ret i8 [[PHI]]
297;
298entry:
299  %a.raw = call nonnull i8* @malloc(i64 32)
300  call void @init(i8* %a.raw)
301  br i1 %c, label %cond.free, label %preheader
302cond.free:
303  call void @free(i8* %a.raw)
304  br label %preheader
305preheader:
306  br label %for.body
307
308for.body:
309  %iv = phi i64 [ %iv.next, %loop.latch ], [ 0, %preheader ]
310  br i1 %c, label %for.end, label %loop.latch
311
312loop.latch:
313  call void @unknown() ;; may throw
314  %addr = getelementptr i8, i8* %a.raw, i32 31
315  %res = load i8, i8* %addr
316  %iv.next = add nuw nsw i64 %iv, 1
317  %exitcond = icmp eq i64 %iv.next, 200
318  br i1 %exitcond, label %for.end, label %for.body
319
320for.end:
321  %phi = phi i8 [%res, %loop.latch], [0, %for.body]
322  ret i8 %phi
323}
324
325declare noalias i8* @my_alloc(i64) allocsize(0)
326
327; We would need context sensitive reasoning about frees (which we don't
328; don't currently have) to hoist the load in this example.
329define i8 @test_hoist_allocsize() {
330; CHECK-LABEL: @test_hoist_allocsize(
331; CHECK-NEXT:  entry:
332; CHECK-NEXT:    [[A_RAW:%.*]] = call nonnull i8* @my_alloc(i64 32)
333; CHECK-NEXT:    call void @init(i8* [[A_RAW]])
334; CHECK-NEXT:    [[ADDR:%.*]] = getelementptr i8, i8* [[A_RAW]], i32 31
335; CHECK-NEXT:    br label [[FOR_BODY:%.*]]
336; CHECK:       for.body:
337; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[FOR_BODY]] ], [ 0, [[ENTRY:%.*]] ]
338; CHECK-NEXT:    call void @unknown()
339; CHECK-NEXT:    [[RES:%.*]] = load i8, i8* [[ADDR]], align 1
340; CHECK-NEXT:    call void @use(i8 [[RES]])
341; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
342; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp eq i64 [[IV_NEXT]], 200
343; CHECK-NEXT:    br i1 [[EXITCOND]], label [[FOR_END:%.*]], label [[FOR_BODY]]
344; CHECK:       for.end:
345; CHECK-NEXT:    [[RES_LCSSA:%.*]] = phi i8 [ [[RES]], [[FOR_BODY]] ]
346; CHECK-NEXT:    call void @free(i8* [[A_RAW]])
347; CHECK-NEXT:    ret i8 [[RES_LCSSA]]
348;
349entry:
350  %a.raw = call nonnull i8* @my_alloc(i64 32)
351  call void @init(i8* %a.raw)
352  br label %for.body
353
354for.body:
355  %iv = phi i64 [ %iv.next, %for.body ], [ 0, %entry ]
356  call void @unknown() ;; may throw
357  %addr = getelementptr i8, i8* %a.raw, i32 31
358  %res = load i8, i8* %addr
359  call void @use(i8 %res)
360  %iv.next = add nuw nsw i64 %iv, 1
361  %exitcond = icmp eq i64 %iv.next, 200
362  br i1 %exitcond, label %for.end, label %for.body
363
364for.end:
365  call void @free(i8* %a.raw)
366  ret i8 %res
367}
368
369define i8 @test_hoist_allocsize_leak() nofree nosync {
370; CHECK-LABEL: @test_hoist_allocsize_leak(
371; CHECK-NEXT:  entry:
372; CHECK-NEXT:    [[A_RAW:%.*]] = call nonnull i8* @my_alloc(i64 32)
373; CHECK-NEXT:    call void @init(i8* [[A_RAW]])
374; CHECK-NEXT:    [[ADDR:%.*]] = getelementptr i8, i8* [[A_RAW]], i32 31
375; CHECK-NEXT:    br label [[FOR_BODY:%.*]]
376; CHECK:       for.body:
377; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[FOR_BODY]] ], [ 0, [[ENTRY:%.*]] ]
378; CHECK-NEXT:    call void @unknown()
379; CHECK-NEXT:    [[RES:%.*]] = load i8, i8* [[ADDR]], align 1
380; CHECK-NEXT:    call void @use(i8 [[RES]])
381; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
382; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp eq i64 [[IV_NEXT]], 200
383; CHECK-NEXT:    br i1 [[EXITCOND]], label [[FOR_END:%.*]], label [[FOR_BODY]]
384; CHECK:       for.end:
385; CHECK-NEXT:    [[RES_LCSSA:%.*]] = phi i8 [ [[RES]], [[FOR_BODY]] ]
386; CHECK-NEXT:    ret i8 [[RES_LCSSA]]
387;
388entry:
389  %a.raw = call nonnull i8* @my_alloc(i64 32)
390  call void @init(i8* %a.raw)
391  br label %for.body
392
393for.body:
394  %iv = phi i64 [ %iv.next, %for.body ], [ 0, %entry ]
395  call void @unknown() ;; may throw
396  %addr = getelementptr i8, i8* %a.raw, i32 31
397  %res = load i8, i8* %addr
398  call void @use(i8 %res)
399  %iv.next = add nuw nsw i64 %iv, 1
400  %exitcond = icmp eq i64 %iv.next, 200
401  br i1 %exitcond, label %for.end, label %for.body
402
403for.end:
404  ret i8 %res
405}
406