xref: /llvm-project/llvm/test/CodeGen/SystemZ/fp-strict-alias.ll (revision a1710eb3cd5823c5d14899112ca3086acbdbe9cb)
1; Verify that strict FP operations are not rescheduled
2;
3; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z13 | FileCheck %s
4
5declare float @llvm.experimental.constrained.sqrt.f32(float, metadata, metadata)
6declare float @llvm.sqrt.f32(float)
7declare void @llvm.s390.sfpc(i32)
8declare void @bar()
9
10; The basic assumption of all following tests is that on z13, we never
11; want to see two square root instructions directly in a row, so the
12; post-RA scheduler will always schedule something else in between
13; whenever possible.
14
15; We can move any FP operation across a (normal) store.
16
17define void @f1(float %f1, float %f2, ptr %ptr1, ptr %ptr2) {
18; CHECK-LABEL: f1:
19; CHECK: sqebr
20; CHECK: ste
21; CHECK: sqebr
22; CHECK: ste
23; CHECK: br %r14
24
25  %sqrt1 = call float @llvm.sqrt.f32(float %f1)
26  %sqrt2 = call float @llvm.sqrt.f32(float %f2)
27
28  store float %sqrt1, ptr %ptr1
29  store float %sqrt2, ptr %ptr2
30
31  ret void
32}
33
34define void @f2(float %f1, float %f2, ptr %ptr1, ptr %ptr2) #0 {
35; CHECK-LABEL: f2:
36; CHECK: sqebr
37; CHECK: ste
38; CHECK: sqebr
39; CHECK: ste
40; CHECK: br %r14
41
42  %sqrt1 = call float @llvm.experimental.constrained.sqrt.f32(
43                        float %f1,
44                        metadata !"round.dynamic",
45                        metadata !"fpexcept.ignore") #0
46  %sqrt2 = call float @llvm.experimental.constrained.sqrt.f32(
47                        float %f2,
48                        metadata !"round.dynamic",
49                        metadata !"fpexcept.ignore") #0
50
51  store float %sqrt1, ptr %ptr1
52  store float %sqrt2, ptr %ptr2
53
54  ret void
55}
56
57define void @f3(float %f1, float %f2, ptr %ptr1, ptr %ptr2) #0 {
58; CHECK-LABEL: f3:
59; CHECK: sqebr
60; CHECK: ste
61; CHECK: sqebr
62; CHECK: ste
63; CHECK: br %r14
64
65  %sqrt1 = call float @llvm.experimental.constrained.sqrt.f32(
66                        float %f1,
67                        metadata !"round.dynamic",
68                        metadata !"fpexcept.maytrap") #0
69  %sqrt2 = call float @llvm.experimental.constrained.sqrt.f32(
70                        float %f2,
71                        metadata !"round.dynamic",
72                        metadata !"fpexcept.maytrap") #0
73
74  store float %sqrt1, ptr %ptr1
75  store float %sqrt2, ptr %ptr2
76
77  ret void
78}
79
80define void @f4(float %f1, float %f2, ptr %ptr1, ptr %ptr2) #0 {
81; CHECK-LABEL: f4:
82; CHECK: sqebr
83; CHECK: ste
84; CHECK: sqebr
85; CHECK: ste
86; CHECK: br %r14
87
88  %sqrt1 = call float @llvm.experimental.constrained.sqrt.f32(
89                        float %f1,
90                        metadata !"round.dynamic",
91                        metadata !"fpexcept.strict") #0
92  %sqrt2 = call float @llvm.experimental.constrained.sqrt.f32(
93                        float %f2,
94                        metadata !"round.dynamic",
95                        metadata !"fpexcept.strict") #0
96
97  store float %sqrt1, ptr %ptr1
98  store float %sqrt2, ptr %ptr2
99
100  ret void
101}
102
103
104; We can move a non-strict FP operation or a fpexcept.ignore
105; operation even across a volatile store, but not a fpexcept.maytrap
106; or fpexcept.strict operation.
107
108define void @f5(float %f1, float %f2, ptr %ptr1, ptr %ptr2) {
109; CHECK-LABEL: f5:
110; CHECK: sqebr
111; CHECK: ste
112; CHECK: sqebr
113; CHECK: ste
114; CHECK: br %r14
115
116  %sqrt1 = call float @llvm.sqrt.f32(float %f1)
117  %sqrt2 = call float @llvm.sqrt.f32(float %f2)
118
119  store volatile float %sqrt1, ptr %ptr1
120  store volatile float %sqrt2, ptr %ptr2
121
122  ret void
123}
124
125define void @f6(float %f1, float %f2, ptr %ptr1, ptr %ptr2) #0 {
126; CHECK-LABEL: f6:
127; CHECK: sqebr
128; CHECK: ste
129; CHECK: sqebr
130; CHECK: ste
131; CHECK: br %r14
132
133  %sqrt1 = call float @llvm.experimental.constrained.sqrt.f32(
134                        float %f1,
135                        metadata !"round.dynamic",
136                        metadata !"fpexcept.ignore") #0
137  %sqrt2 = call float @llvm.experimental.constrained.sqrt.f32(
138                        float %f2,
139                        metadata !"round.dynamic",
140                        metadata !"fpexcept.ignore") #0
141
142  store volatile float %sqrt1, ptr %ptr1
143  store volatile float %sqrt2, ptr %ptr2
144
145  ret void
146}
147
148define void @f7(float %f1, float %f2, ptr %ptr1, ptr %ptr2) #0 {
149; CHECK-LABEL: f7:
150; CHECK: sqebr
151; CHECK: sqebr
152; CHECK: ste
153; CHECK: ste
154; CHECK: br %r14
155
156  %sqrt1 = call float @llvm.experimental.constrained.sqrt.f32(
157                        float %f1,
158                        metadata !"round.dynamic",
159                        metadata !"fpexcept.maytrap") #0
160  %sqrt2 = call float @llvm.experimental.constrained.sqrt.f32(
161                        float %f2,
162                        metadata !"round.dynamic",
163                        metadata !"fpexcept.maytrap") #0
164
165  store volatile float %sqrt1, ptr %ptr1
166  store volatile float %sqrt2, ptr %ptr2
167
168  ret void
169}
170
171define void @f8(float %f1, float %f2, ptr %ptr1, ptr %ptr2) #0 {
172; CHECK-LABEL: f8:
173; CHECK: sqebr
174; CHECK: sqebr
175; CHECK: ste
176; CHECK: ste
177; CHECK: br %r14
178
179  %sqrt1 = call float @llvm.experimental.constrained.sqrt.f32(
180                        float %f1,
181                        metadata !"round.dynamic",
182                        metadata !"fpexcept.strict") #0
183  %sqrt2 = call float @llvm.experimental.constrained.sqrt.f32(
184                        float %f2,
185                        metadata !"round.dynamic",
186                        metadata !"fpexcept.strict") #0
187
188  store volatile float %sqrt1, ptr %ptr1
189  store volatile float %sqrt2, ptr %ptr2
190
191  ret void
192}
193
194
195; No variant of FP operations can be scheduled across a SPFC.
196
197define void @f9(float %f1, float %f2, ptr %ptr1, ptr %ptr2) {
198; CHECK-LABEL: f9:
199; CHECK: sqebr
200; CHECK: sqebr
201; CHECK: ste
202; CHECK: ste
203; CHECK: br %r14
204
205  %sqrt1 = call float @llvm.sqrt.f32(float %f1)
206  %sqrt2 = call float @llvm.sqrt.f32(float %f2)
207
208  call void @llvm.s390.sfpc(i32 0)
209
210  store float %sqrt1, ptr %ptr1
211  store float %sqrt2, ptr %ptr2
212
213  ret void
214}
215
216define void @f10(float %f1, float %f2, ptr %ptr1, ptr %ptr2) #0 {
217; CHECK-LABEL: f10:
218; CHECK: sqebr
219; CHECK: sqebr
220; CHECK: ste
221; CHECK: ste
222; CHECK: br %r14
223
224  %sqrt1 = call float @llvm.experimental.constrained.sqrt.f32(
225                        float %f1,
226                        metadata !"round.dynamic",
227                        metadata !"fpexcept.ignore") #0
228  %sqrt2 = call float @llvm.experimental.constrained.sqrt.f32(
229                        float %f2,
230                        metadata !"round.dynamic",
231                        metadata !"fpexcept.ignore") #0
232
233  call void @llvm.s390.sfpc(i32 0) #0
234
235  store float %sqrt1, ptr %ptr1
236  store float %sqrt2, ptr %ptr2
237
238  ret void
239}
240
241define void @f11(float %f1, float %f2, ptr %ptr1, ptr %ptr2) #0 {
242; CHECK-LABEL: f11:
243; CHECK: sqebr
244; CHECK: sqebr
245; CHECK: ste
246; CHECK: ste
247; CHECK: br %r14
248
249  %sqrt1 = call float @llvm.experimental.constrained.sqrt.f32(
250                        float %f1,
251                        metadata !"round.dynamic",
252                        metadata !"fpexcept.maytrap") #0
253  %sqrt2 = call float @llvm.experimental.constrained.sqrt.f32(
254                        float %f2,
255                        metadata !"round.dynamic",
256                        metadata !"fpexcept.maytrap") #0
257
258  call void @llvm.s390.sfpc(i32 0) #0
259
260  store float %sqrt1, ptr %ptr1
261  store float %sqrt2, ptr %ptr2
262
263  ret void
264}
265
266define void @f12(float %f1, float %f2, ptr %ptr1, ptr %ptr2) #0 {
267; CHECK-LABEL: f12:
268; CHECK: sqebr
269; CHECK: sqebr
270; CHECK: ste
271; CHECK: ste
272; CHECK: br %r14
273
274  %sqrt1 = call float @llvm.experimental.constrained.sqrt.f32(
275                        float %f1,
276                        metadata !"round.dynamic",
277                        metadata !"fpexcept.strict") #0
278  %sqrt2 = call float @llvm.experimental.constrained.sqrt.f32(
279                        float %f2,
280                        metadata !"round.dynamic",
281                        metadata !"fpexcept.strict") #0
282
283  call void @llvm.s390.sfpc(i32 0) #0
284
285  store float %sqrt1, ptr %ptr1
286  store float %sqrt2, ptr %ptr2
287
288  ret void
289}
290
291; If the result of any FP operation is unused, it can be removed
292; -- except for fpexcept.strict operations.
293
294define void @f13(float %f1) {
295; CHECK-LABEL: f13:
296; CHECK-NOT: sqeb
297; CHECK: br %r14
298
299  %sqrt = call float @llvm.sqrt.f32(float %f1)
300
301  ret void
302}
303
304define void @f14(float %f1) #0 {
305; CHECK-LABEL: f14:
306; CHECK-NOT: sqeb
307; CHECK: br %r14
308
309  %sqrt = call float @llvm.experimental.constrained.sqrt.f32(
310                        float %f1,
311                        metadata !"round.dynamic",
312                        metadata !"fpexcept.ignore") #0
313
314  ret void
315}
316
317define void @f15(float %f1) #0 {
318; CHECK-LABEL: f15:
319; CHECK-NOT: sqeb
320; CHECK: br %r14
321
322  %sqrt = call float @llvm.experimental.constrained.sqrt.f32(
323                        float %f1,
324                        metadata !"round.dynamic",
325                        metadata !"fpexcept.maytrap") #0
326
327  ret void
328}
329
330define void @f16(float %f1) #0 {
331; CHECK-LABEL: f16:
332; CHECK: sqebr
333; CHECK: br %r14
334
335  %sqrt = call float @llvm.experimental.constrained.sqrt.f32(
336                        float %f1,
337                        metadata !"round.dynamic",
338                        metadata !"fpexcept.strict") #0
339
340  ret void
341}
342
343
344; Verify that constrained intrinsics and memory operations get their
345; chains linked up properly.
346
347define void @f17(float %in, ptr %out) #0 {
348; CHECK-LABEL: f17:
349; CHECK: sqebr
350; CHECK: ste
351; CHECK: jg bar
352  %sqrt = call float @llvm.experimental.constrained.sqrt.f32(
353                        float %in,
354                        metadata !"round.dynamic",
355                        metadata !"fpexcept.ignore") #0
356  store float %sqrt, ptr %out, align 4
357  tail call void @bar() #0
358  ret void
359}
360
361define void @f18(float %in, ptr %out) #0 {
362; CHECK-LABEL: f18:
363; CHECK: sqebr
364; CHECK: ste
365; CHECK: jg bar
366  %sqrt = call float @llvm.experimental.constrained.sqrt.f32(
367                        float %in,
368                        metadata !"round.dynamic",
369                        metadata !"fpexcept.ignore") #0
370  store float %sqrt, ptr %out, align 4
371  tail call void @bar() #0
372  ret void
373}
374
375define void @f19(float %in, ptr %out) #0 {
376; CHECK-LABEL: f19:
377; CHECK: sqebr
378; CHECK: ste
379; CHECK: jg bar
380  %sqrt = call float @llvm.experimental.constrained.sqrt.f32(
381                        float %in,
382                        metadata !"round.dynamic",
383                        metadata !"fpexcept.maytrap") #0
384  store float %sqrt, ptr %out, align 4
385  tail call void @bar() #0
386  ret void
387}
388
389define void @f20(float %in, ptr %out) #0 {
390; CHECK-LABEL: f20:
391; CHECK: sqebr
392; CHECK: ste
393; CHECK: jg bar
394  %sqrt = call float @llvm.experimental.constrained.sqrt.f32(
395                        float %in,
396                        metadata !"round.dynamic",
397                        metadata !"fpexcept.strict") #0
398  store float %sqrt, ptr %out, align 4
399  tail call void @bar() #0
400  ret void
401}
402
403attributes #0 = { strictfp }
404