1; Test strict multiplication of two f32s, producing an f64 result.
2;
3; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
4
5declare float @foo()
6declare double @llvm.experimental.constrained.fmul.f64(double, double, metadata, metadata)
7declare float @llvm.experimental.constrained.fadd.f32(float, float, metadata, metadata)
8declare float @llvm.experimental.constrained.fptrunc.f32.f64(double, metadata, metadata)
9declare double @llvm.experimental.constrained.fpext.f64.f32(float, metadata)
10
11; Check register multiplication.
12define double @f1(float %f1, float %f2) #0 {
13; CHECK-LABEL: f1:
14; CHECK: mdebr %f0, %f2
15; CHECK: br %r14
16  %f1x = call double @llvm.experimental.constrained.fpext.f64.f32(
17                        float %f1,
18                        metadata !"fpexcept.strict") #0
19  %f2x = call double @llvm.experimental.constrained.fpext.f64.f32(
20                        float %f2,
21                        metadata !"fpexcept.strict") #0
22  %res = call double @llvm.experimental.constrained.fmul.f64(
23                        double %f1x, double %f2x,
24                        metadata !"round.dynamic",
25                        metadata !"fpexcept.strict") #0
26  ret double %res
27}
28
29; Check the low end of the MDEB range.
30define double @f2(float %f1, float *%ptr) #0 {
31; CHECK-LABEL: f2:
32; CHECK: mdeb %f0, 0(%r2)
33; CHECK: br %r14
34  %f2 = load float, float *%ptr
35  %f1x = call double @llvm.experimental.constrained.fpext.f64.f32(
36                        float %f1,
37                        metadata !"fpexcept.strict") #0
38  %f2x = call double @llvm.experimental.constrained.fpext.f64.f32(
39                        float %f2,
40                        metadata !"fpexcept.strict") #0
41  %res = call double @llvm.experimental.constrained.fmul.f64(
42                        double %f1x, double %f2x,
43                        metadata !"round.dynamic",
44                        metadata !"fpexcept.strict") #0
45  ret double %res
46}
47
48; Check the high end of the aligned MDEB range.
49define double @f3(float %f1, float *%base) #0 {
50; CHECK-LABEL: f3:
51; CHECK: mdeb %f0, 4092(%r2)
52; CHECK: br %r14
53  %ptr = getelementptr float, float *%base, i64 1023
54  %f2 = load float, float *%ptr
55  %f1x = call double @llvm.experimental.constrained.fpext.f64.f32(
56                        float %f1,
57                        metadata !"fpexcept.strict") #0
58  %f2x = call double @llvm.experimental.constrained.fpext.f64.f32(
59                        float %f2,
60                        metadata !"fpexcept.strict") #0
61  %res = call double @llvm.experimental.constrained.fmul.f64(
62                        double %f1x, double %f2x,
63                        metadata !"round.dynamic",
64                        metadata !"fpexcept.strict") #0
65  ret double %res
66}
67
68; Check the next word up, which needs separate address logic.
69; Other sequences besides this one would be OK.
70define double @f4(float %f1, float *%base) #0 {
71; CHECK-LABEL: f4:
72; CHECK: aghi %r2, 4096
73; CHECK: mdeb %f0, 0(%r2)
74; CHECK: br %r14
75  %ptr = getelementptr float, float *%base, i64 1024
76  %f2 = load float, float *%ptr
77  %f1x = call double @llvm.experimental.constrained.fpext.f64.f32(
78                        float %f1,
79                        metadata !"fpexcept.strict") #0
80  %f2x = call double @llvm.experimental.constrained.fpext.f64.f32(
81                        float %f2,
82                        metadata !"fpexcept.strict") #0
83  %res = call double @llvm.experimental.constrained.fmul.f64(
84                        double %f1x, double %f2x,
85                        metadata !"round.dynamic",
86                        metadata !"fpexcept.strict") #0
87  ret double %res
88}
89
90; Check negative displacements, which also need separate address logic.
91define double @f5(float %f1, float *%base) #0 {
92; CHECK-LABEL: f5:
93; CHECK: aghi %r2, -4
94; CHECK: mdeb %f0, 0(%r2)
95; CHECK: br %r14
96  %ptr = getelementptr float, float *%base, i64 -1
97  %f2 = load float, float *%ptr
98  %f1x = call double @llvm.experimental.constrained.fpext.f64.f32(
99                        float %f1,
100                        metadata !"fpexcept.strict") #0
101  %f2x = call double @llvm.experimental.constrained.fpext.f64.f32(
102                        float %f2,
103                        metadata !"fpexcept.strict") #0
104  %res = call double @llvm.experimental.constrained.fmul.f64(
105                        double %f1x, double %f2x,
106                        metadata !"round.dynamic",
107                        metadata !"fpexcept.strict") #0
108  ret double %res
109}
110
111; Check that MDEB allows indices.
112define double @f6(float %f1, float *%base, i64 %index) #0 {
113; CHECK-LABEL: f6:
114; CHECK: sllg %r1, %r3, 2
115; CHECK: mdeb %f0, 400(%r1,%r2)
116; CHECK: br %r14
117  %ptr1 = getelementptr float, float *%base, i64 %index
118  %ptr2 = getelementptr float, float *%ptr1, i64 100
119  %f2 = load float, float *%ptr2
120  %f1x = call double @llvm.experimental.constrained.fpext.f64.f32(
121                        float %f1,
122                        metadata !"fpexcept.strict") #0
123  %f2x = call double @llvm.experimental.constrained.fpext.f64.f32(
124                        float %f2,
125                        metadata !"fpexcept.strict") #0
126  %res = call double @llvm.experimental.constrained.fmul.f64(
127                        double %f1x, double %f2x,
128                        metadata !"round.dynamic",
129                        metadata !"fpexcept.strict") #0
130  ret double %res
131}
132
133; Check that multiplications of spilled values can use MDEB rather than MDEBR.
134define float @f7(float *%ptr0) #0 {
135; CHECK-LABEL: f7:
136; CHECK: brasl %r14, foo@PLT
137; CHECK: mdeb %f0, 16{{[04]}}(%r15)
138; CHECK: br %r14
139  %ptr1 = getelementptr float, float *%ptr0, i64 2
140  %ptr2 = getelementptr float, float *%ptr0, i64 4
141  %ptr3 = getelementptr float, float *%ptr0, i64 6
142  %ptr4 = getelementptr float, float *%ptr0, i64 8
143  %ptr5 = getelementptr float, float *%ptr0, i64 10
144  %ptr6 = getelementptr float, float *%ptr0, i64 12
145  %ptr7 = getelementptr float, float *%ptr0, i64 14
146  %ptr8 = getelementptr float, float *%ptr0, i64 16
147  %ptr9 = getelementptr float, float *%ptr0, i64 18
148  %ptr10 = getelementptr float, float *%ptr0, i64 20
149
150  %val0 = load float, float *%ptr0
151  %val1 = load float, float *%ptr1
152  %val2 = load float, float *%ptr2
153  %val3 = load float, float *%ptr3
154  %val4 = load float, float *%ptr4
155  %val5 = load float, float *%ptr5
156  %val6 = load float, float *%ptr6
157  %val7 = load float, float *%ptr7
158  %val8 = load float, float *%ptr8
159  %val9 = load float, float *%ptr9
160  %val10 = load float, float *%ptr10
161
162  %frob0 = call float @llvm.experimental.constrained.fadd.f32(
163                        float %val0, float %val0,
164                        metadata !"round.dynamic",
165                        metadata !"fpexcept.strict") #0
166  %frob1 = call float @llvm.experimental.constrained.fadd.f32(
167                        float %val1, float %val1,
168                        metadata !"round.dynamic",
169                        metadata !"fpexcept.strict") #0
170  %frob2 = call float @llvm.experimental.constrained.fadd.f32(
171                        float %val2, float %val2,
172                        metadata !"round.dynamic",
173                        metadata !"fpexcept.strict") #0
174  %frob3 = call float @llvm.experimental.constrained.fadd.f32(
175                        float %val3, float %val3,
176                        metadata !"round.dynamic",
177                        metadata !"fpexcept.strict") #0
178  %frob4 = call float @llvm.experimental.constrained.fadd.f32(
179                        float %val4, float %val4,
180                        metadata !"round.dynamic",
181                        metadata !"fpexcept.strict") #0
182  %frob5 = call float @llvm.experimental.constrained.fadd.f32(
183                        float %val5, float %val5,
184                        metadata !"round.dynamic",
185                        metadata !"fpexcept.strict") #0
186  %frob6 = call float @llvm.experimental.constrained.fadd.f32(
187                        float %val6, float %val6,
188                        metadata !"round.dynamic",
189                        metadata !"fpexcept.strict") #0
190  %frob7 = call float @llvm.experimental.constrained.fadd.f32(
191                        float %val7, float %val7,
192                        metadata !"round.dynamic",
193                        metadata !"fpexcept.strict") #0
194  %frob8 = call float @llvm.experimental.constrained.fadd.f32(
195                        float %val8, float %val8,
196                        metadata !"round.dynamic",
197                        metadata !"fpexcept.strict") #0
198  %frob9 = call float @llvm.experimental.constrained.fadd.f32(
199                        float %val9, float %val9,
200                        metadata !"round.dynamic",
201                        metadata !"fpexcept.strict") #0
202  %frob10 = call float @llvm.experimental.constrained.fadd.f32(
203                        float %val10, float %val10,
204                        metadata !"round.dynamic",
205                        metadata !"fpexcept.strict") #0
206
207  store float %frob0, float *%ptr0
208  store float %frob1, float *%ptr1
209  store float %frob2, float *%ptr2
210  store float %frob3, float *%ptr3
211  store float %frob4, float *%ptr4
212  store float %frob5, float *%ptr5
213  store float %frob6, float *%ptr6
214  store float %frob7, float *%ptr7
215  store float %frob8, float *%ptr8
216  store float %frob9, float *%ptr9
217  store float %frob10, float *%ptr10
218
219  %ret = call float @foo() #0
220
221  %accext0 = call double @llvm.experimental.constrained.fpext.f64.f32(
222                        float %ret,
223                        metadata !"fpexcept.strict") #0
224  %ext0 = call double @llvm.experimental.constrained.fpext.f64.f32(
225                        float %frob0,
226                        metadata !"fpexcept.strict") #0
227  %mul0 = call double @llvm.experimental.constrained.fmul.f64(
228                        double %accext0, double %ext0,
229                        metadata !"round.dynamic",
230                        metadata !"fpexcept.strict") #0
231  %extra0 = call double @llvm.experimental.constrained.fmul.f64(
232                        double %mul0, double 1.01,
233                        metadata !"round.dynamic",
234                        metadata !"fpexcept.strict") #0
235  %trunc0 = call float @llvm.experimental.constrained.fptrunc.f32.f64(
236                        double %extra0,
237                        metadata !"round.dynamic",
238                        metadata !"fpexcept.strict") #0
239
240  %accext1 = call double @llvm.experimental.constrained.fpext.f64.f32(
241                        float %trunc0,
242                        metadata !"fpexcept.strict") #0
243  %ext1 = call double @llvm.experimental.constrained.fpext.f64.f32(
244                        float %frob1,
245                        metadata !"fpexcept.strict") #0
246  %mul1 = call double @llvm.experimental.constrained.fmul.f64(
247                        double %accext1, double %ext1,
248                        metadata !"round.dynamic",
249                        metadata !"fpexcept.strict") #0
250  %extra1 = call double @llvm.experimental.constrained.fmul.f64(
251                        double %mul1, double 1.11,
252                        metadata !"round.dynamic",
253                        metadata !"fpexcept.strict") #0
254  %trunc1 = call float @llvm.experimental.constrained.fptrunc.f32.f64(
255                        double %extra1,
256                        metadata !"round.dynamic",
257                        metadata !"fpexcept.strict") #0
258
259  %accext2 = call double @llvm.experimental.constrained.fpext.f64.f32(
260                        float %trunc1,
261                        metadata !"fpexcept.strict") #0
262  %ext2 = call double @llvm.experimental.constrained.fpext.f64.f32(
263                        float %frob2,
264                        metadata !"fpexcept.strict") #0
265  %mul2 = call double @llvm.experimental.constrained.fmul.f64(
266                        double %accext2, double %ext2,
267                        metadata !"round.dynamic",
268                        metadata !"fpexcept.strict") #0
269  %extra2 = call double @llvm.experimental.constrained.fmul.f64(
270                        double %mul2, double 1.21,
271                        metadata !"round.dynamic",
272                        metadata !"fpexcept.strict") #0
273  %trunc2 = call float @llvm.experimental.constrained.fptrunc.f32.f64(
274                        double %extra2,
275                        metadata !"round.dynamic",
276                        metadata !"fpexcept.strict") #0
277
278  %accext3 = call double @llvm.experimental.constrained.fpext.f64.f32(
279                        float %trunc2,
280                        metadata !"fpexcept.strict") #0
281  %ext3 = call double @llvm.experimental.constrained.fpext.f64.f32(
282                        float %frob3,
283                        metadata !"fpexcept.strict") #0
284  %mul3 = call double @llvm.experimental.constrained.fmul.f64(
285                        double %accext3, double %ext3,
286                        metadata !"round.dynamic",
287                        metadata !"fpexcept.strict") #0
288  %extra3 = call double @llvm.experimental.constrained.fmul.f64(
289                        double %mul3, double 1.31,
290                        metadata !"round.dynamic",
291                        metadata !"fpexcept.strict") #0
292  %trunc3 = call float @llvm.experimental.constrained.fptrunc.f32.f64(
293                        double %extra3,
294                        metadata !"round.dynamic",
295                        metadata !"fpexcept.strict") #0
296
297  %accext4 = call double @llvm.experimental.constrained.fpext.f64.f32(
298                        float %trunc3,
299                        metadata !"fpexcept.strict") #0
300  %ext4 = call double @llvm.experimental.constrained.fpext.f64.f32(
301                        float %frob4,
302                        metadata !"fpexcept.strict") #0
303  %mul4 = call double @llvm.experimental.constrained.fmul.f64(
304                        double %accext4, double %ext4,
305                        metadata !"round.dynamic",
306                        metadata !"fpexcept.strict") #0
307  %extra4 = call double @llvm.experimental.constrained.fmul.f64(
308                        double %mul4, double 1.41,
309                        metadata !"round.dynamic",
310                        metadata !"fpexcept.strict") #0
311  %trunc4 = call float @llvm.experimental.constrained.fptrunc.f32.f64(
312                        double %extra4,
313                        metadata !"round.dynamic",
314                        metadata !"fpexcept.strict") #0
315
316  %accext5 = call double @llvm.experimental.constrained.fpext.f64.f32(
317                        float %trunc4,
318                        metadata !"fpexcept.strict") #0
319  %ext5 = call double @llvm.experimental.constrained.fpext.f64.f32(
320                        float %frob5,
321                        metadata !"fpexcept.strict") #0
322  %mul5 = call double @llvm.experimental.constrained.fmul.f64(
323                        double %accext5, double %ext5,
324                        metadata !"round.dynamic",
325                        metadata !"fpexcept.strict") #0
326  %extra5 = call double @llvm.experimental.constrained.fmul.f64(
327                        double %mul5, double 1.51,
328                        metadata !"round.dynamic",
329                        metadata !"fpexcept.strict") #0
330  %trunc5 = call float @llvm.experimental.constrained.fptrunc.f32.f64(
331                        double %extra5,
332                        metadata !"round.dynamic",
333                        metadata !"fpexcept.strict") #0
334
335  %accext6 = call double @llvm.experimental.constrained.fpext.f64.f32(
336                        float %trunc5,
337                        metadata !"fpexcept.strict") #0
338  %ext6 = call double @llvm.experimental.constrained.fpext.f64.f32(
339                        float %frob6,
340                        metadata !"fpexcept.strict") #0
341  %mul6 = call double @llvm.experimental.constrained.fmul.f64(
342                        double %accext6, double %ext6,
343                        metadata !"round.dynamic",
344                        metadata !"fpexcept.strict") #0
345  %extra6 = call double @llvm.experimental.constrained.fmul.f64(
346                        double %mul6, double 1.61,
347                        metadata !"round.dynamic",
348                        metadata !"fpexcept.strict") #0
349  %trunc6 = call float @llvm.experimental.constrained.fptrunc.f32.f64(
350                        double %extra6,
351                        metadata !"round.dynamic",
352                        metadata !"fpexcept.strict") #0
353
354  %accext7 = call double @llvm.experimental.constrained.fpext.f64.f32(
355                        float %trunc6,
356                        metadata !"fpexcept.strict") #0
357  %ext7 = call double @llvm.experimental.constrained.fpext.f64.f32(
358                        float %frob7,
359                        metadata !"fpexcept.strict") #0
360  %mul7 = call double @llvm.experimental.constrained.fmul.f64(
361                        double %accext7, double %ext7,
362                        metadata !"round.dynamic",
363                        metadata !"fpexcept.strict") #0
364  %extra7 = call double @llvm.experimental.constrained.fmul.f64(
365                        double %mul7, double 1.71,
366                        metadata !"round.dynamic",
367                        metadata !"fpexcept.strict") #0
368  %trunc7 = call float @llvm.experimental.constrained.fptrunc.f32.f64(
369                        double %extra7,
370                        metadata !"round.dynamic",
371                        metadata !"fpexcept.strict") #0
372
373  %accext8 = call double @llvm.experimental.constrained.fpext.f64.f32(
374                        float %trunc7,
375                        metadata !"fpexcept.strict") #0
376  %ext8 = call double @llvm.experimental.constrained.fpext.f64.f32(
377                        float %frob8,
378                        metadata !"fpexcept.strict") #0
379  %mul8 = call double @llvm.experimental.constrained.fmul.f64(
380                        double %accext8, double %ext8,
381                        metadata !"round.dynamic",
382                        metadata !"fpexcept.strict") #0
383  %extra8 = call double @llvm.experimental.constrained.fmul.f64(
384                        double %mul8, double 1.81,
385                        metadata !"round.dynamic",
386                        metadata !"fpexcept.strict") #0
387  %trunc8 = call float @llvm.experimental.constrained.fptrunc.f32.f64(
388                        double %extra8,
389                        metadata !"round.dynamic",
390                        metadata !"fpexcept.strict") #0
391
392  %accext9 = call double @llvm.experimental.constrained.fpext.f64.f32(
393                        float %trunc8,
394                        metadata !"fpexcept.strict") #0
395  %ext9 = call double @llvm.experimental.constrained.fpext.f64.f32(
396                        float %frob9,
397                        metadata !"fpexcept.strict") #0
398  %mul9 = call double @llvm.experimental.constrained.fmul.f64(
399                        double %accext9, double %ext9,
400                        metadata !"round.dynamic",
401                        metadata !"fpexcept.strict") #0
402  %extra9 = call double @llvm.experimental.constrained.fmul.f64(
403                        double %mul9, double 1.91,
404                        metadata !"round.dynamic",
405                        metadata !"fpexcept.strict") #0
406  %trunc9 = call float @llvm.experimental.constrained.fptrunc.f32.f64(
407                        double %extra9,
408                        metadata !"round.dynamic",
409                        metadata !"fpexcept.strict") #0
410
411  ret float %trunc9
412}
413
414attributes #0 = { strictfp }
415