1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt -passes=dse -S %s | FileCheck %s
4 ; Both the stores in %then and %else can be eliminated by translating %p
6 define void @memoryphi_translate_1(i1 %c) {
7 ; CHECK-LABEL: @memoryphi_translate_1(
9 ; CHECK-NEXT: [[A_1:%.*]] = alloca i8, align 1
10 ; CHECK-NEXT: [[A_2:%.*]] = alloca i8, align 1
11 ; CHECK-NEXT: br i1 [[C:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]]
13 ; CHECK-NEXT: br label [[END:%.*]]
15 ; CHECK-NEXT: br label [[END]]
17 ; CHECK-NEXT: [[P:%.*]] = phi ptr [ [[A_1]], [[THEN]] ], [ [[A_2]], [[ELSE]] ]
18 ; CHECK-NEXT: store i8 10, ptr [[P]], align 1
19 ; CHECK-NEXT: ret void
24 br i1 %c, label %then, label %else
35 %p = phi ptr [ %a.1, %then ], [ %a.2, %else ]
40 ; The store in %else can be eliminated by translating %p through the phi.
41 ; The store in %then cannot be eliminated, because %a.1 is read before the final
43 define i8 @memoryphi_translate_2(i1 %c) {
44 ; CHECK-LABEL: @memoryphi_translate_2(
46 ; CHECK-NEXT: [[A_1:%.*]] = alloca i8, align 1
47 ; CHECK-NEXT: [[A_2:%.*]] = alloca i8, align 1
48 ; CHECK-NEXT: br i1 [[C:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]]
50 ; CHECK-NEXT: store i8 0, ptr [[A_1]], align 1
51 ; CHECK-NEXT: br label [[END:%.*]]
53 ; CHECK-NEXT: br label [[END]]
55 ; CHECK-NEXT: [[P:%.*]] = phi ptr [ [[A_1]], [[THEN]] ], [ [[A_2]], [[ELSE]] ]
56 ; CHECK-NEXT: [[L:%.*]] = load i8, ptr [[A_1]], align 1
57 ; CHECK-NEXT: store i8 10, ptr [[P]], align 1
58 ; CHECK-NEXT: ret i8 [[L]]
63 br i1 %c, label %then, label %else
74 %p = phi ptr [ %a.1, %then ], [ %a.2, %else ]
75 %l = load i8, ptr %a.1
80 ; The store in %then can be eliminated by translating %p through the phi.
81 ; The store in %else cannot be eliminated, because %a.2 is read before the final
83 define i8 @memoryphi_translate_3(i1 %c) {
84 ; CHECK-LABEL: @memoryphi_translate_3(
86 ; CHECK-NEXT: [[A_1:%.*]] = alloca i8, align 1
87 ; CHECK-NEXT: [[A_2:%.*]] = alloca i8, align 1
88 ; CHECK-NEXT: br i1 [[C:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]]
90 ; CHECK-NEXT: br label [[END:%.*]]
92 ; CHECK-NEXT: store i8 9, ptr [[A_2]], align 1
93 ; CHECK-NEXT: br label [[END]]
95 ; CHECK-NEXT: [[P:%.*]] = phi ptr [ [[A_1]], [[THEN]] ], [ [[A_2]], [[ELSE]] ]
96 ; CHECK-NEXT: [[L:%.*]] = load i8, ptr [[A_2]], align 1
97 ; CHECK-NEXT: store i8 10, ptr [[P]], align 1
98 ; CHECK-NEXT: ret i8 [[L]]
103 br i1 %c, label %then, label %else
114 %p = phi ptr [ %a.1, %then ], [ %a.2, %else ]
115 %l = load i8, ptr %a.2
120 ; No stores can be eliminated, because there's a load from the phi.
121 define i8 @memoryphi_translate_4(i1 %c) {
122 ; CHECK-LABEL: @memoryphi_translate_4(
124 ; CHECK-NEXT: [[A_1:%.*]] = alloca i8, align 1
125 ; CHECK-NEXT: [[A_2:%.*]] = alloca i8, align 1
126 ; CHECK-NEXT: br i1 [[C:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]]
128 ; CHECK-NEXT: store i8 0, ptr [[A_1]], align 1
129 ; CHECK-NEXT: br label [[END:%.*]]
131 ; CHECK-NEXT: store i8 9, ptr [[A_2]], align 1
132 ; CHECK-NEXT: br label [[END]]
134 ; CHECK-NEXT: [[P:%.*]] = phi ptr [ [[A_1]], [[THEN]] ], [ [[A_2]], [[ELSE]] ]
135 ; CHECK-NEXT: [[L:%.*]] = load i8, ptr [[P]], align 1
136 ; CHECK-NEXT: store i8 10, ptr [[P]], align 1
137 ; CHECK-NEXT: ret i8 [[L]]
142 br i1 %c, label %then, label %else
153 %p = phi ptr [ %a.1, %then ], [ %a.2, %else ]
159 ; TODO: The store in %entry can be removed by translating %p through the phi.
160 define void @memoryphi_translate_5(i1 %cond) {
161 ; CHECK-LABEL: @memoryphi_translate_5(
163 ; CHECK-NEXT: [[A:%.*]] = alloca i8, align 1
164 ; CHECK-NEXT: [[B:%.*]] = alloca i8, align 1
165 ; CHECK-NEXT: store i8 0, ptr [[A]], align 1
166 ; CHECK-NEXT: br i1 [[COND:%.*]], label [[COND_TRUE:%.*]], label [[COND_END:%.*]]
168 ; CHECK-NEXT: br label [[COND_END]]
170 ; CHECK-NEXT: [[P:%.*]] = phi ptr [ [[B]], [[COND_TRUE]] ], [ [[A]], [[ENTRY:%.*]] ]
171 ; CHECK-NEXT: store i8 0, ptr [[P]], align 1
172 ; CHECK-NEXT: call void @use(ptr [[P]])
173 ; CHECK-NEXT: ret void
180 br i1 %cond, label %cond.true, label %cond.end
187 %p = phi ptr [ %b, %cond.true ], [ %a, %entry ]
189 call void @use(ptr %p)
193 ; TODO: The store in %entry can be removed by translating %p through the phi.
194 ; Same as @memoryphi_translate_5, but without stores in %cond.true, so there
196 define void @translate_without_memoryphi_1(i1 %cond) {
197 ; CHECK-LABEL: @translate_without_memoryphi_1(
199 ; CHECK-NEXT: [[A:%.*]] = alloca i8, align 1
200 ; CHECK-NEXT: [[B:%.*]] = alloca i8, align 1
201 ; CHECK-NEXT: store i8 0, ptr [[A]], align 1
202 ; CHECK-NEXT: br i1 [[COND:%.*]], label [[COND_TRUE:%.*]], label [[COND_END:%.*]]
204 ; CHECK-NEXT: br label [[COND_END]]
206 ; CHECK-NEXT: [[P:%.*]] = phi ptr [ [[B]], [[COND_TRUE]] ], [ [[A]], [[ENTRY:%.*]] ]
207 ; CHECK-NEXT: store i8 0, ptr [[P]], align 1
208 ; CHECK-NEXT: call void @use(ptr [[P]])
209 ; CHECK-NEXT: ret void
215 br i1 %cond, label %cond.true, label %cond.end
221 %p = phi ptr [ %b, %cond.true ], [ %a, %entry ]
223 call void @use(ptr %p)
227 ; In the test, translating through the phi results in a null address. Make sure
228 ; this does not cause a crash.
229 define void @test_trans_null(i1 %c, ptr %ptr) {
230 ; CHECK-LABEL: @test_trans_null(
232 ; CHECK-NEXT: br i1 [[C:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]]
234 ; CHECK-NEXT: br label [[EXIT:%.*]]
236 ; CHECK-NEXT: call void @fn()
237 ; CHECK-NEXT: [[GEP_1:%.*]] = getelementptr inbounds i16, ptr undef, i64 2
238 ; CHECK-NEXT: store i16 8, ptr [[GEP_1]], align 2
239 ; CHECK-NEXT: br label [[EXIT]]
241 ; CHECK-NEXT: [[P:%.*]] = phi ptr [ [[PTR:%.*]], [[THEN]] ], [ undef, [[ELSE]] ]
242 ; CHECK-NEXT: [[GEP_2:%.*]] = getelementptr inbounds i16, ptr [[P]], i64 2
243 ; CHECK-NEXT: store i16 8, ptr [[GEP_2]], align 2
244 ; CHECK-NEXT: ret void
247 br i1 %c, label %then, label %else
254 %gep.1 = getelementptr inbounds i16, ptr undef, i64 2
255 store i16 8, ptr %gep.1, align 2
259 %p = phi ptr [ %ptr, %then ], [ undef, %else ]
260 %gep.2 = getelementptr inbounds i16, ptr %p, i64 2
261 store i16 8, ptr %gep.2, align 2
266 declare void @use(ptr)