xref: /llvm-project/llvm/test/Transforms/DeadStoreElimination/phi-translation.ll (revision f497a00da968b0ff90d8c98caa184d14b9a92495)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt -passes=dse -S %s | FileCheck %s
3
4; Both the stores in %then and %else can be eliminated by translating %p
5; through the phi.
6define void @memoryphi_translate_1(i1 %c) {
7; CHECK-LABEL: @memoryphi_translate_1(
8; CHECK-NEXT:  entry:
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:%.*]]
12; CHECK:       then:
13; CHECK-NEXT:    br label [[END:%.*]]
14; CHECK:       else:
15; CHECK-NEXT:    br label [[END]]
16; CHECK:       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
20;
21entry:
22  %a.1 = alloca i8
23  %a.2 = alloca i8
24  br i1 %c, label %then, label %else
25
26then:
27  store i8 0, ptr %a.1
28  br label %end
29
30else:
31  store i8 9, ptr %a.2
32  br label %end
33
34end:
35  %p = phi ptr [ %a.1, %then ], [ %a.2, %else ]
36  store i8 10, ptr %p
37  ret void
38}
39
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
42; store.
43define i8 @memoryphi_translate_2(i1 %c) {
44; CHECK-LABEL: @memoryphi_translate_2(
45; CHECK-NEXT:  entry:
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:%.*]]
49; CHECK:       then:
50; CHECK-NEXT:    store i8 0, ptr [[A_1]], align 1
51; CHECK-NEXT:    br label [[END:%.*]]
52; CHECK:       else:
53; CHECK-NEXT:    br label [[END]]
54; CHECK:       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]]
59;
60entry:
61  %a.1 = alloca i8
62  %a.2 = alloca i8
63  br i1 %c, label %then, label %else
64
65then:
66  store i8 0, ptr %a.1
67  br label %end
68
69else:
70  store i8 9, ptr %a.2
71  br label %end
72
73end:
74  %p = phi ptr [ %a.1, %then ], [ %a.2, %else ]
75  %l = load i8, ptr %a.1
76  store i8 10, ptr %p
77  ret i8 %l
78}
79
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
82; store.
83define i8 @memoryphi_translate_3(i1 %c) {
84; CHECK-LABEL: @memoryphi_translate_3(
85; CHECK-NEXT:  entry:
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:%.*]]
89; CHECK:       then:
90; CHECK-NEXT:    br label [[END:%.*]]
91; CHECK:       else:
92; CHECK-NEXT:    store i8 9, ptr [[A_2]], align 1
93; CHECK-NEXT:    br label [[END]]
94; CHECK:       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]]
99;
100entry:
101  %a.1 = alloca i8
102  %a.2 = alloca i8
103  br i1 %c, label %then, label %else
104
105then:
106  store i8 0, ptr %a.1
107  br label %end
108
109else:
110  store i8 9, ptr %a.2
111  br label %end
112
113end:
114  %p = phi ptr [ %a.1, %then ], [ %a.2, %else ]
115  %l = load i8, ptr %a.2
116  store i8 10, ptr %p
117  ret i8 %l
118}
119
120; No stores can be eliminated, because there's a load from the phi.
121define i8 @memoryphi_translate_4(i1 %c) {
122; CHECK-LABEL: @memoryphi_translate_4(
123; CHECK-NEXT:  entry:
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:%.*]]
127; CHECK:       then:
128; CHECK-NEXT:    store i8 0, ptr [[A_1]], align 1
129; CHECK-NEXT:    br label [[END:%.*]]
130; CHECK:       else:
131; CHECK-NEXT:    store i8 9, ptr [[A_2]], align 1
132; CHECK-NEXT:    br label [[END]]
133; CHECK:       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]]
138;
139entry:
140  %a.1 = alloca i8
141  %a.2 = alloca i8
142  br i1 %c, label %then, label %else
143
144then:
145  store i8 0, ptr %a.1
146  br label %end
147
148else:
149  store i8 9, ptr %a.2
150  br label %end
151
152end:
153  %p = phi ptr [ %a.1, %then ], [ %a.2, %else ]
154  %l = load i8, ptr %p
155  store i8 10, ptr %p
156  ret i8 %l
157}
158
159; TODO: The store in %entry can be removed by translating %p through the phi.
160define void @memoryphi_translate_5(i1 %cond) {
161; CHECK-LABEL: @memoryphi_translate_5(
162; CHECK-NEXT:  entry:
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:%.*]]
167; CHECK:       cond.true:
168; CHECK-NEXT:    br label [[COND_END]]
169; CHECK:       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
174;
175entry:
176  %a = alloca i8
177  %b = alloca i8
178  %c = alloca i8
179  store i8 0, ptr %a
180  br i1 %cond, label %cond.true, label %cond.end
181
182cond.true:
183  store i8 0, ptr %c
184  br label %cond.end
185
186cond.end:
187  %p = phi ptr [ %b, %cond.true ], [ %a, %entry ]
188  store i8 0, ptr %p
189  call void @use(ptr %p)
190  ret void
191}
192
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
195; is no MemoryPhi.
196define void @translate_without_memoryphi_1(i1 %cond) {
197; CHECK-LABEL: @translate_without_memoryphi_1(
198; CHECK-NEXT:  entry:
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:%.*]]
203; CHECK:       cond.true:
204; CHECK-NEXT:    br label [[COND_END]]
205; CHECK:       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
210;
211entry:
212  %a = alloca i8
213  %b = alloca i8
214  store i8 0, ptr %a
215  br i1 %cond, label %cond.true, label %cond.end
216
217cond.true:
218  br label %cond.end
219
220cond.end:
221  %p = phi ptr [ %b, %cond.true ], [ %a, %entry ]
222  store i8 0, ptr %p
223  call void @use(ptr %p)
224  ret void
225}
226
227; In the test, translating through the phi results in a null address. Make sure
228; this does not cause a crash.
229define void @test_trans_null(i1 %c, ptr %ptr) {
230; CHECK-LABEL: @test_trans_null(
231; CHECK-NEXT:  entry:
232; CHECK-NEXT:    br i1 [[C:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]]
233; CHECK:       then:
234; CHECK-NEXT:    br label [[EXIT:%.*]]
235; CHECK:       else:
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]]
240; CHECK:       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
245;
246entry:
247  br i1 %c, label %then, label %else
248
249then:
250  br label %exit
251
252else:
253  call void @fn()
254  %gep.1 = getelementptr inbounds i16, ptr undef, i64 2
255  store i16 8, ptr %gep.1, align 2
256  br label %exit
257
258exit:
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
262  ret void
263}
264
265
266declare void @use(ptr)
267declare void @fn()
268