1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt -S -basic-aa -dse < %s | FileCheck %s
3
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
6declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) nounwind
7declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) nounwind
8declare void @llvm.memset.p0i8.i8(i8* nocapture, i8, i8, i1) nounwind
9
10define void @test1() {
11; CHECK-LABEL: @test1(
12; CHECK-NEXT:    [[A:%.*]] = alloca i8, align 1
13; CHECK-NEXT:    call void @llvm.lifetime.end.p0i8(i64 1, i8* [[A]])
14; CHECK-NEXT:    ret void
15;
16  %A = alloca i8
17
18  store i8 0, i8* %A  ;; Written to by memset
19  call void @llvm.lifetime.end.p0i8(i64 1, i8* %A)
20
21  call void @llvm.memset.p0i8.i8(i8* %A, i8 0, i8 -1, i1 false)
22
23  ret void
24}
25
26define void @test2(i32* %P) {
27; CHECK-LABEL: @test2(
28; CHECK-NEXT:    [[Q:%.*]] = getelementptr i32, i32* [[P:%.*]], i32 1
29; CHECK-NEXT:    [[R:%.*]] = bitcast i32* [[Q]] to i8*
30; CHECK-NEXT:    call void @llvm.lifetime.start.p0i8(i64 4, i8* [[R]])
31; CHECK-NEXT:    call void @llvm.lifetime.end.p0i8(i64 4, i8* [[R]])
32; CHECK-NEXT:    ret void
33;
34  %Q = getelementptr i32, i32* %P, i32 1
35  %R = bitcast i32* %Q to i8*
36  call void @llvm.lifetime.start.p0i8(i64 4, i8* %R)
37  store i32 0, i32* %Q  ;; This store is dead.
38  call void @llvm.lifetime.end.p0i8(i64 4, i8* %R)
39  ret void
40}
41
42; lifetime.end only marks the first two bytes of %A as dead. Make sure
43; `store i8 20, i8* %A.2 is not removed.
44define void @test3_lifetime_end_partial() {
45; CHECK-LABEL: @test3_lifetime_end_partial(
46; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4
47; CHECK-NEXT:    [[A_0:%.*]] = bitcast i32* [[A]] to i8*
48; CHECK-NEXT:    call void @llvm.lifetime.start.p0i8(i64 2, i8* [[A_0]])
49; CHECK-NEXT:    [[A_1:%.*]] = getelementptr i8, i8* [[A_0]], i64 1
50; CHECK-NEXT:    [[A_2:%.*]] = getelementptr i8, i8* [[A_0]], i64 2
51; CHECK-NEXT:    store i8 20, i8* [[A_2]], align 1
52; CHECK-NEXT:    call void @llvm.lifetime.end.p0i8(i64 2, i8* [[A_0]])
53; CHECK-NEXT:    call void @use(i8* [[A_1]])
54; CHECK-NEXT:    ret void
55;
56  %A = alloca i32
57
58  %A.0 = bitcast i32 * %A to i8*
59  call void @llvm.lifetime.start.p0i8(i64 2, i8* %A.0)
60  %A.1 = getelementptr i8, i8* %A.0, i64 1
61  %A.2 = getelementptr i8, i8* %A.0, i64 2
62
63  store i8 0, i8* %A.0
64  store i8 10, i8* %A.1
65  store i8 20, i8* %A.2
66
67  call void @llvm.lifetime.end.p0i8(i64 2, i8* %A.0)
68  call void @use(i8* %A.1)
69  ret void
70}
71
72; lifetime.end only marks the first two bytes of %A as dead. Make sure
73; `store i8 20, i8* %A.2 is not removed.
74define void @test4_lifetime_end_partial_loop() {
75; CHECK-LABEL: @test4_lifetime_end_partial_loop(
76; CHECK-NEXT:  entry:
77; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4
78; CHECK-NEXT:    [[A_0:%.*]] = bitcast i32* [[A]] to i8*
79; CHECK-NEXT:    br label [[LOOP:%.*]]
80; CHECK:       loop:
81; CHECK-NEXT:    [[IV:%.*]] = phi i8 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
82; CHECK-NEXT:    call void @llvm.lifetime.start.p0i8(i64 2, i8* [[A_0]])
83; CHECK-NEXT:    [[A_1:%.*]] = getelementptr i8, i8* [[A_0]], i64 1
84; CHECK-NEXT:    [[A_2:%.*]] = getelementptr i8, i8* [[A_0]], i64 2
85; CHECK-NEXT:    call void @use(i8* [[A_1]])
86; CHECK-NEXT:    store i8 20, i8* [[A_2]], align 1
87; CHECK-NEXT:    call void @llvm.lifetime.end.p0i8(i64 2, i8* [[A_0]])
88; CHECK-NEXT:    [[IV_NEXT]] = add i8 [[IV]], 10
89; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp eq i8 [[IV_NEXT]], 10
90; CHECK-NEXT:    br i1 [[EXITCOND]], label [[EXIT:%.*]], label [[LOOP]]
91; CHECK:       exit:
92; CHECK-NEXT:    ret void
93;
94entry:
95  %A = alloca i32
96
97  %A.0 = bitcast i32 * %A to i8*
98  br label %loop
99
100loop:
101  %iv = phi i8 [ 0, %entry ], [ %iv.next, %loop ]
102  call void @llvm.lifetime.start.p0i8(i64 2, i8* %A.0)
103  %A.1 = getelementptr i8, i8* %A.0, i64 1
104  %A.2 = getelementptr i8, i8* %A.0, i64 2
105
106  call void @use(i8* %A.1)
107
108  store i8 20, i8* %A.2
109  store i8 10, i8* %A.1
110  store i8 0, i8* %A.0
111  call void @llvm.lifetime.end.p0i8(i64 2, i8* %A.0)
112
113  %iv.next = add i8 %iv, 10
114  %exitcond = icmp eq i8 %iv.next, 10
115  br i1 %exitcond, label %exit, label %loop
116
117exit:
118  ret void
119}
120
121; lifetime.end only marks the first two bytes of %A as dead. Make sure
122; `store i8 20, i8* %A.2 is not removed.
123define void @test5_lifetime_end_partial(i32* %A) {
124; CHECK-LABEL: @test5_lifetime_end_partial(
125; CHECK-NEXT:    [[A_0:%.*]] = bitcast i32* [[A:%.*]] to i8*
126; CHECK-NEXT:    call void @llvm.lifetime.start.p0i8(i64 2, i8* [[A_0]])
127; CHECK-NEXT:    [[A_1:%.*]] = getelementptr i8, i8* [[A_0]], i64 1
128; CHECK-NEXT:    [[A_2:%.*]] = getelementptr i8, i8* [[A_0]], i64 2
129; CHECK-NEXT:    store i8 20, i8* [[A_2]], align 1
130; CHECK-NEXT:    call void @llvm.lifetime.end.p0i8(i64 2, i8* [[A_0]])
131; CHECK-NEXT:    call void @use(i8* [[A_1]])
132; CHECK-NEXT:    store i8 30, i8* [[A_1]], align 1
133; CHECK-NEXT:    store i8 40, i8* [[A_2]], align 1
134; CHECK-NEXT:    ret void
135;
136
137  %A.0 = bitcast i32 * %A to i8*
138  call void @llvm.lifetime.start.p0i8(i64 2, i8* %A.0)
139  %A.1 = getelementptr i8, i8* %A.0, i64 1
140  %A.2 = getelementptr i8, i8* %A.0, i64 2
141
142  store i8 0, i8* %A.0
143  store i8 10, i8* %A.1
144  store i8 20, i8* %A.2
145
146  call void @llvm.lifetime.end.p0i8(i64 2, i8* %A.0)
147
148  call void @use(i8* %A.1)
149  store i8 30, i8* %A.1
150  store i8 40, i8* %A.2
151  ret void
152}
153
154declare void @use(i8*) readonly
155