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