1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt < %s -S -passes='early-cse' -earlycse-debug-hash | FileCheck %s --check-prefix=CHECK-NOMEMSSA
3 ; RUN: opt < %s -S -passes='early-cse<memssa>' | FileCheck %s
4 ; RUN: opt < %s -S -passes='early-cse' | FileCheck %s --check-prefix=CHECK-NOMEMSSA
5 ; RUN: opt < %s -S -aa-pipeline=basic-aa -passes='early-cse<memssa>' | FileCheck %s
7 @G1 = global i32 zeroinitializer
8 @G2 = global i32 zeroinitializer
9 @G3 = global i32 zeroinitializer
11 ;; Simple load value numbering across non-clobbering store.
13 ; CHECK-NOMEMSSA-LABEL: @test1(
14 ; CHECK-NOMEMSSA-NEXT: [[V1:%.*]] = load i32, ptr @G1, align 4
15 ; CHECK-NOMEMSSA-NEXT: store i32 0, ptr @G2, align 4
16 ; CHECK-NOMEMSSA-NEXT: [[V2:%.*]] = load i32, ptr @G1, align 4
17 ; CHECK-NOMEMSSA-NEXT: [[DIFF:%.*]] = sub i32 [[V1]], [[V2]]
18 ; CHECK-NOMEMSSA-NEXT: ret i32 [[DIFF]]
20 ; CHECK-LABEL: @test1(
21 ; CHECK-NEXT: [[V1:%.*]] = load i32, ptr @G1, align 4
22 ; CHECK-NEXT: store i32 0, ptr @G2, align 4
23 ; CHECK-NEXT: ret i32 0
25 %V1 = load i32, ptr @G1
27 %V2 = load i32, ptr @G1
28 %Diff = sub i32 %V1, %V2
32 ;; Simple dead store elimination across non-clobbering store.
33 define void @test2() {
34 ; CHECK-NOMEMSSA-LABEL: @test2(
35 ; CHECK-NOMEMSSA-NEXT: entry:
36 ; CHECK-NOMEMSSA-NEXT: [[V1:%.*]] = load i32, ptr @G1, align 4
37 ; CHECK-NOMEMSSA-NEXT: store i32 0, ptr @G2, align 4
38 ; CHECK-NOMEMSSA-NEXT: store i32 [[V1]], ptr @G1, align 4
39 ; CHECK-NOMEMSSA-NEXT: ret void
41 ; CHECK-LABEL: @test2(
43 ; CHECK-NEXT: [[V1:%.*]] = load i32, ptr @G1, align 4
44 ; CHECK-NEXT: store i32 0, ptr @G2, align 4
45 ; CHECK-NEXT: ret void
48 %V1 = load i32, ptr @G1
50 store i32 %V1, ptr @G1
54 ;; Check that memoryphi optimization happens during EarlyCSE, enabling
55 ;; more load CSE opportunities.
56 define void @test_memphiopt(i1 %c, ptr %p) {
57 ; CHECK-NOMEMSSA-LABEL: @test_memphiopt(
58 ; CHECK-NOMEMSSA-NEXT: entry:
59 ; CHECK-NOMEMSSA-NEXT: [[V1:%.*]] = load i32, ptr @G1, align 4
60 ; CHECK-NOMEMSSA-NEXT: br i1 [[C:%.*]], label [[THEN:%.*]], label [[END:%.*]]
61 ; CHECK-NOMEMSSA: then:
62 ; CHECK-NOMEMSSA-NEXT: [[PV:%.*]] = load i32, ptr [[P:%.*]], align 4
63 ; CHECK-NOMEMSSA-NEXT: br label [[END]]
64 ; CHECK-NOMEMSSA: end:
65 ; CHECK-NOMEMSSA-NEXT: [[V2:%.*]] = load i32, ptr @G1, align 4
66 ; CHECK-NOMEMSSA-NEXT: [[SUM:%.*]] = add i32 [[V1]], [[V2]]
67 ; CHECK-NOMEMSSA-NEXT: store i32 [[SUM]], ptr @G2, align 4
68 ; CHECK-NOMEMSSA-NEXT: ret void
70 ; CHECK-LABEL: @test_memphiopt(
72 ; CHECK-NEXT: [[V1:%.*]] = load i32, ptr @G1, align 4
73 ; CHECK-NEXT: br i1 [[C:%.*]], label [[THEN:%.*]], label [[END:%.*]]
75 ; CHECK-NEXT: [[PV:%.*]] = load i32, ptr [[P:%.*]], align 4
76 ; CHECK-NEXT: br label [[END]]
78 ; CHECK-NEXT: [[SUM:%.*]] = add i32 [[V1]], [[V1]]
79 ; CHECK-NEXT: store i32 [[SUM]], ptr @G2, align 4
80 ; CHECK-NEXT: ret void
83 %v1 = load i32, ptr @G1
84 br i1 %c, label %then, label %end
87 %pv = load i32, ptr %p
92 %v2 = load i32, ptr @G1
93 %sum = add i32 %v1, %v2
94 store i32 %sum, ptr @G2
99 ;; Check that MemoryPhi optimization and MemoryUse re-optimization
100 ;; happens during EarlyCSE, enabling more load CSE opportunities.
101 define void @test_memphiopt2(i1 %c, ptr %p) {
102 ; CHECK-NOMEMSSA-LABEL: @test_memphiopt2(
103 ; CHECK-NOMEMSSA-NEXT: entry:
104 ; CHECK-NOMEMSSA-NEXT: [[V1:%.*]] = load i32, ptr @G1, align 4
105 ; CHECK-NOMEMSSA-NEXT: store i32 [[V1]], ptr @G2, align 4
106 ; CHECK-NOMEMSSA-NEXT: br i1 [[C:%.*]], label [[THEN:%.*]], label [[END:%.*]]
107 ; CHECK-NOMEMSSA: then:
108 ; CHECK-NOMEMSSA-NEXT: [[PV:%.*]] = load i32, ptr [[P:%.*]], align 4
109 ; CHECK-NOMEMSSA-NEXT: br label [[END]]
110 ; CHECK-NOMEMSSA: end:
111 ; CHECK-NOMEMSSA-NEXT: [[V2:%.*]] = load i32, ptr @G1, align 4
112 ; CHECK-NOMEMSSA-NEXT: store i32 [[V2]], ptr @G3, align 4
113 ; CHECK-NOMEMSSA-NEXT: ret void
115 ; CHECK-LABEL: @test_memphiopt2(
117 ; CHECK-NEXT: [[V1:%.*]] = load i32, ptr @G1, align 4
118 ; CHECK-NEXT: store i32 [[V1]], ptr @G2, align 4
119 ; CHECK-NEXT: br i1 [[C:%.*]], label [[THEN:%.*]], label [[END:%.*]]
121 ; CHECK-NEXT: [[PV:%.*]] = load i32, ptr [[P:%.*]], align 4
122 ; CHECK-NEXT: br label [[END]]
124 ; CHECK-NEXT: store i32 [[V1]], ptr @G3, align 4
125 ; CHECK-NEXT: ret void
128 %v1 = load i32, ptr @G1
129 store i32 %v1, ptr @G2
130 br i1 %c, label %then, label %end
133 %pv = load i32, ptr %p
134 store i32 %pv, ptr %p
138 %v2 = load i32, ptr @G1
139 store i32 %v2, ptr @G3
143 ;; Check that we respect lifetime.start/lifetime.end intrinsics when deleting
144 ;; stores that, without the lifetime calls, would be writebacks.
145 define void @test_writeback_lifetimes(ptr %p) {
146 ; CHECK-NOMEMSSA-LABEL: @test_writeback_lifetimes(
147 ; CHECK-NOMEMSSA-NEXT: entry:
148 ; CHECK-NOMEMSSA-NEXT: [[Q:%.*]] = getelementptr i32, ptr [[P:%.*]], i64 1
149 ; CHECK-NOMEMSSA-NEXT: [[PV:%.*]] = load i32, ptr [[P]], align 4
150 ; CHECK-NOMEMSSA-NEXT: [[QV:%.*]] = load i32, ptr [[Q]], align 4
151 ; CHECK-NOMEMSSA-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[P]])
152 ; CHECK-NOMEMSSA-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr [[P]])
153 ; CHECK-NOMEMSSA-NEXT: store i32 [[PV]], ptr [[P]], align 4
154 ; CHECK-NOMEMSSA-NEXT: store i32 [[QV]], ptr [[Q]], align 4
155 ; CHECK-NOMEMSSA-NEXT: ret void
157 ; CHECK-LABEL: @test_writeback_lifetimes(
159 ; CHECK-NEXT: [[Q:%.*]] = getelementptr i32, ptr [[P:%.*]], i64 1
160 ; CHECK-NEXT: [[PV:%.*]] = load i32, ptr [[P]], align 4
161 ; CHECK-NEXT: [[QV:%.*]] = load i32, ptr [[Q]], align 4
162 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[P]])
163 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr [[P]])
164 ; CHECK-NEXT: store i32 [[PV]], ptr [[P]], align 4
165 ; CHECK-NEXT: store i32 [[QV]], ptr [[Q]], align 4
166 ; CHECK-NEXT: ret void
169 %q = getelementptr i32, ptr %p, i64 1
170 %pv = load i32, ptr %p
171 %qv = load i32, ptr %q
172 call void @llvm.lifetime.end.p0(i64 8, ptr %p)
173 call void @llvm.lifetime.start.p0(i64 8, ptr %p)
174 store i32 %pv, ptr %p
175 store i32 %qv, ptr %q
179 ;; Check that we respect lifetime.start/lifetime.end intrinsics when deleting
180 ;; stores that, without the lifetime calls, would be writebacks.
181 define void @test_writeback_lifetimes_multi_arg(ptr %p, ptr %q) {
182 ; CHECK-NOMEMSSA-LABEL: @test_writeback_lifetimes_multi_arg(
183 ; CHECK-NOMEMSSA-NEXT: entry:
184 ; CHECK-NOMEMSSA-NEXT: [[PV:%.*]] = load i32, ptr [[P:%.*]], align 4
185 ; CHECK-NOMEMSSA-NEXT: [[QV:%.*]] = load i32, ptr [[Q:%.*]], align 4
186 ; CHECK-NOMEMSSA-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[P]])
187 ; CHECK-NOMEMSSA-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr [[P]])
188 ; CHECK-NOMEMSSA-NEXT: store i32 [[PV]], ptr [[P]], align 4
189 ; CHECK-NOMEMSSA-NEXT: store i32 [[QV]], ptr [[Q]], align 4
190 ; CHECK-NOMEMSSA-NEXT: ret void
192 ; CHECK-LABEL: @test_writeback_lifetimes_multi_arg(
194 ; CHECK-NEXT: [[PV:%.*]] = load i32, ptr [[P:%.*]], align 4
195 ; CHECK-NEXT: [[QV:%.*]] = load i32, ptr [[Q:%.*]], align 4
196 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[P]])
197 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr [[P]])
198 ; CHECK-NEXT: store i32 [[PV]], ptr [[P]], align 4
199 ; CHECK-NEXT: store i32 [[QV]], ptr [[Q]], align 4
200 ; CHECK-NEXT: ret void
203 %pv = load i32, ptr %p
204 %qv = load i32, ptr %q
205 call void @llvm.lifetime.end.p0(i64 8, ptr %p)
206 call void @llvm.lifetime.start.p0(i64 8, ptr %p)
207 store i32 %pv, ptr %p
208 store i32 %qv, ptr %q
212 declare void @llvm.lifetime.end.p0(i64, ptr)
213 declare void @llvm.lifetime.start.p0(i64, ptr)