1; RUN: llc -march=amdgcn -mcpu=gfx900 -denormal-fp-math-f32=preserve-sign -verify-machineinstrs < %s | FileCheck -enable-var-scope -check-prefixes=GCN,GFX89,GFX9,GFX9-F32FLUSH %s
2; RUN: llc -march=amdgcn -mcpu=gfx900 -denormal-fp-math-f32=ieee -verify-machineinstrs < %s | FileCheck -enable-var-scope -check-prefixes=GCN,GFX89,GFX9,GFX9-F32DENORM %s
3; RUN: llc -march=amdgcn -mcpu=gfx803 -denormal-fp-math-f32=preserve-sign -verify-machineinstrs < %s | FileCheck -enable-var-scope -check-prefixes=GCN,GFX89 %s
4; RUN: llc -march=amdgcn -mcpu=gfx803 -denormal-fp-math-f32=ieee -verify-machineinstrs < %s | FileCheck -enable-var-scope -check-prefixes=GCN,GFX89 %s
5
6;  fold (fadd (fpext (fmul x, y)), z) -> (fma (fpext x), (fpext y), z)
7
8; GCN-LABEL: {{^}}fadd_fpext_fmul_f16_to_f32:
9; GCN: s_waitcnt
10; GFX9-F32FLUSH-NEXT: v_mad_mix_f32 v0, v0, v1, v2 op_sel_hi:[1,1,0]{{$}}
11; GFX9-F32FLUSH-NEXT: s_setpc_b64
12
13; GFX9-F32DENORM-NEXT: v_mul_f16
14; GFX9-F32DENORM-NEXT: v_cvt_f32_f16
15; GFX9-F32DENORM-NEXT: v_add_f32
16define float @fadd_fpext_fmul_f16_to_f32(half %x, half %y, float %z) #0 {
17entry:
18  %mul = fmul half %x, %y
19  %mul.ext = fpext half %mul to float
20  %add = fadd float %mul.ext, %z
21  ret float %add
22}
23
24; f16->f64 is not free.
25; GCN-LABEL: {{^}}fadd_fpext_fmul_f16_to_f64:
26; GFX89: v_mul_f16
27; GFX89: v_cvt_f32_f16
28; GFX89: v_cvt_f64_f32
29; GFX89: v_add_f64
30define double @fadd_fpext_fmul_f16_to_f64(half %x, half %y, double %z) #0 {
31entry:
32  %mul = fmul half %x, %y
33  %mul.ext = fpext half %mul to double
34  %add = fadd double %mul.ext, %z
35  ret double %add
36}
37
38; f32->f64 is not free.
39; GCN-LABEL: {{^}}fadd_fpext_fmul_f32_to_f64:
40; GCN: v_mul_f32
41; GCN: v_cvt_f64_f32
42; GCN: v_add_f64
43define double @fadd_fpext_fmul_f32_to_f64(float %x, float %y, double %z) #0 {
44entry:
45  %mul = fmul float %x, %y
46  %mul.ext = fpext float %mul to double
47  %add = fadd double %mul.ext, %z
48  ret double %add
49}
50
51; fold (fadd x, (fpext (fmul y, z))) -> (fma (fpext y), (fpext z), x)
52; GCN-LABEL: {{^}}fadd_fpext_fmul_f16_to_f32_commute:
53; GCN: s_waitcnt
54; GFX9-F32FLUSH-NEXT: v_mad_mix_f32 v0, v0, v1, v2 op_sel_hi:[1,1,0]{{$}}
55; GFX9-F32FLUSH-NEXT: s_setpc_b64
56
57; GFX9-F32DENORM-NEXT: v_mul_f16
58; GFX9-F32DENORM-NEXT: v_cvt_f32_f16
59; GFX9-F32DENORM-NEXT: v_add_f32
60; GFX9-F32DENORM-NEXT: s_setpc_b64
61define float @fadd_fpext_fmul_f16_to_f32_commute(half %x, half %y, float %z) #0 {
62entry:
63  %mul = fmul half %x, %y
64  %mul.ext = fpext half %mul to float
65  %add = fadd float %z, %mul.ext
66  ret float %add
67}
68
69; fold (fadd (fma x, y, (fpext (fmul u, v))), z)
70;   -> (fma x, y, (fma (fpext u), (fpext v), z))
71
72; GCN-LABEL: {{^}}fadd_muladd_fpext_fmul_f16_to_f32:
73; GCN: s_waitcnt
74; GFX9-F32FLUSH-NEXT: v_mad_mix_f32 v2, v2, v3, v4 op_sel_hi:[1,1,0]
75; GFX9-F32FLUSH-NEXT: v_mac_f32_e32 v2, v0, v1
76; GFX9-F32FLUSH-NEXT: v_mov_b32_e32 v0, v2
77; GFX9-F32FLUSH-NEXT: s_setpc_b64
78
79; GFX9-F32DENORM-NEXT: v_mul_f16
80; GFX9-F32DENORM-NEXT: v_cvt_f32_f16
81; GFX9-F32DENORM-NEXT: v_fma_f32
82; GFX9-F32DENORM-NEXT: v_add_f32
83; GFX9-F32DENORM-NEXT: s_setpc_b64
84define float @fadd_muladd_fpext_fmul_f16_to_f32(float %x, float %y, half %u, half %v, float %z) #0 {
85entry:
86  %mul = fmul half %u, %v
87  %mul.ext = fpext half %mul to float
88  %fma = call float @llvm.fmuladd.f32(float %x, float %y, float %mul.ext)
89  %add = fadd float %fma, %z
90  ret float %add
91}
92
93; fold (fadd x, (fma y, z, (fpext (fmul u, v)))
94;   -> (fma y, z, (fma (fpext u), (fpext v), x))
95; GCN-LABEL: {{^}}fadd_muladd_fpext_fmul_f16_to_f32_commute:
96; GCN: s_waitcnt
97; GFX9-F32FLUSH-NEXT: v_mad_mix_f32 v2, v2, v3, v4 op_sel_hi:[1,1,0]
98; GFX9-F32FLUSH-NEXT: v_mac_f32_e32 v2, v0, v1
99; GFX9-F32FLUSH-NEXT: v_mov_b32_e32 v0, v2
100; GFX9-F32FLUSH-NEXT: s_setpc_b64
101
102; GFX9-F32DENORM-NEXT: v_mul_f16
103; GFX9-F32DENORM-NEXT: v_cvt_f32_f16
104; GFX9-F32DENORM-NEXT: v_fma_f32
105; GFX9-F32DENORM-NEXT: v_add_f32
106; GFX9-F32DENORM-NEXT: s_setpc_b64
107define float @fadd_muladd_fpext_fmul_f16_to_f32_commute(float %x, float %y, half %u, half %v, float %z) #0 {
108entry:
109  %mul = fmul half %u, %v
110  %mul.ext = fpext half %mul to float
111  %fma = call float @llvm.fmuladd.f32(float %x, float %y, float %mul.ext)
112  %add = fadd float %z, %fma
113  ret float %add
114}
115
116; GCN-LABEL: {{^}}fadd_fmad_fpext_fmul_f16_to_f32:
117; GCN: s_waitcnt
118; GFX9-F32FLUSH-NEXT: v_mad_mix_f32 v2, v2, v3, v4 op_sel_hi:[1,1,0]
119; GFX9-F32FLUSH-NEXT: v_mac_f32_e32 v2, v0, v1
120; GFX9-F32FLUSH-NEXT: v_mov_b32_e32 v0, v2
121; GFX9-F32FLUSH-NEXT: s_setpc_b64
122
123; GFX9-F32DENORM-NEXT: v_mul_f16_e32 v2, v2, v3
124; GFX9-F32DENORM-NEXT: v_cvt_f32_f16_e32 v2, v2
125; GFX9-F32DENORM-NEXT: v_fma_f32 v0, v0, v1, v2
126define float @fadd_fmad_fpext_fmul_f16_to_f32(float %x, float %y, half %u, half %v, float %z) #0 {
127entry:
128  %mul = fmul half %u, %v
129  %mul.ext = fpext half %mul to float
130  %mul1 = fmul contract float %x, %y
131  %fmad = fadd contract float %mul1, %mul.ext
132  %add = fadd float %fmad, %z
133  ret float %add
134}
135
136; fold (fadd (fma x, y, (fpext (fmul u, v))), z)
137;   -> (fma x, y, (fma (fpext u), (fpext v), z))
138
139; GCN-LABEL: {{^}}fadd_fma_fpext_fmul_f16_to_f32:
140; GCN: s_waitcnt
141; GFX89: v_mul_f16
142; GFX89: v_cvt_f32_f16
143; GFX89: v_fma_f32
144; GFX89: v_add_f32
145define float @fadd_fma_fpext_fmul_f16_to_f32(float %x, float %y, half %u, half %v, float %z) #0 {
146entry:
147  %mul = fmul contract half %u, %v
148  %mul.ext = fpext half %mul to float
149  %fma = call float @llvm.fma.f32(float %x, float %y, float %mul.ext)
150  %add = fadd float %fma, %z
151  ret float %add
152}
153
154; GCN-LABEL: {{^}}fadd_fma_fpext_fmul_f16_to_f32_commute:
155; GCN: s_waitcnt
156; GFX89: v_mul_f16
157; GFX89: v_cvt_f32_f16
158; GFX89: v_fma_f32
159; GFX89: v_add_f32
160define float @fadd_fma_fpext_fmul_f16_to_f32_commute(float %x, float %y, half %u, half %v, float %z) #0 {
161entry:
162  %mul = fmul contract half %u, %v
163  %mul.ext = fpext half %mul to float
164  %fma = call float @llvm.fma.f32(float %x, float %y, float %mul.ext)
165  %add = fadd float %z, %fma
166  ret float %add
167}
168
169; fold (fadd x, (fpext (fma y, z, (fmul u, v)))
170;   -> (fma (fpext y), (fpext z), (fma (fpext u), (fpext v), x))
171
172; GCN-LABEL: {{^}}fadd_fpext_fmuladd_f16_to_f32:
173; GFX9: v_mul_f16
174; GFX9: v_fma_f16
175; GFX9: v_cvt_f32_f16
176; GFX9: v_add_f32_e32
177define float @fadd_fpext_fmuladd_f16_to_f32(float %x, half %y, half %z, half %u, half %v) #0 {
178entry:
179  %mul = fmul contract half %u, %v
180  %fma = call half @llvm.fmuladd.f16(half %y, half %z, half %mul)
181  %ext.fma = fpext half %fma to float
182  %add = fadd float %x, %ext.fma
183  ret float %add
184}
185
186; GCN-LABEL: {{^}}fadd_fpext_fma_f16_to_f32:
187; GFX9: v_mul_f16
188; GFX9: v_fma_f16
189; GFX9: v_cvt_f32_f16
190; GFX9: v_add_f32_e32
191define float @fadd_fpext_fma_f16_to_f32(float %x, half %y, half %z, half %u, half %v) #0 {
192entry:
193  %mul = fmul contract half %u, %v
194  %fma = call half @llvm.fma.f16(half %y, half %z, half %mul)
195  %ext.fma = fpext half %fma to float
196  %add = fadd float %x, %ext.fma
197  ret float %add
198}
199
200; GCN-LABEL: {{^}}fadd_fpext_fma_f16_to_f32_commute:
201; GFX9: v_mul_f16
202; GFX9: v_fma_f16
203; GFX9: v_cvt_f32_f16
204; GFX9: v_add_f32_e32
205define float @fadd_fpext_fma_f16_to_f32_commute(float %x, half %y, half %z, half %u, half %v) #0 {
206entry:
207  %mul = fmul contract half %u, %v
208  %fma = call half @llvm.fma.f16(half %y, half %z, half %mul)
209  %ext.fma = fpext half %fma to float
210  %add = fadd float %ext.fma, %x
211  ret float %add
212}
213
214; fold (fsub (fpext (fmul x, y)), z)
215;   -> (fma (fpext x), (fpext y), (fneg z))
216
217; GCN-LABEL: {{^}}fsub_fpext_fmul_f16_to_f32:
218; GCN: s_waitcnt
219; GFX9-F32FLUSH-NEXT: v_mad_mix_f32 v0, v0, v1, -v2 op_sel_hi:[1,1,0]{{$}}
220; GFX9-F32FLUSH-NEXT: s_setpc_b64
221
222; GFX9-F32DENORM-NEXT: v_mul_f16_e32 v0, v0, v1
223; GFX9-F32DENORM-NEXT: v_cvt_f32_f16_e32 v0, v0
224; GFX9-F32DENORM-NEXT: v_sub_f32_e32 v0, v0, v2
225; GFX9-F32DENORM-NEXT: s_setpc_b64
226define float @fsub_fpext_fmul_f16_to_f32(half %x, half %y, float %z) #0 {
227entry:
228  %mul = fmul half %x, %y
229  %mul.ext = fpext half %mul to float
230  %add = fsub float %mul.ext, %z
231  ret float %add
232}
233
234; fold (fsub x, (fpext (fmul y, z)))
235;   -> (fma (fneg (fpext y)), (fpext z), x)
236
237; GCN-LABEL: {{^}}fsub_fpext_fmul_f16_to_f32_commute:
238; GCN: s_waitcnt
239; GFX9-F32FLUSH-NEXT: v_mad_mix_f32 v0, -v1, v2, v0 op_sel_hi:[1,1,0]
240; GFX9-F32FLUSH-NEXT: s_setpc_b64
241
242; GFX9-F32DENORM-NEXT: v_mul_f16_e32
243; GFX9-F32DENORM-NEXT: v_cvt_f32_f16_e32
244; GFX9-F32DENORM-NEXT: v_sub_f32_e32
245; GFX9-F32DENORM-NEXT: s_setpc_b64
246define float @fsub_fpext_fmul_f16_to_f32_commute(float %x, half %y, half %z) #0 {
247entry:
248  %mul = fmul contract half %y, %z
249  %mul.ext = fpext half %mul to float
250  %add = fsub contract float %x, %mul.ext
251  ret float %add
252}
253
254; fold (fsub (fpext (fneg (fmul, x, y))), z)
255;   -> (fneg (fma (fpext x), (fpext y), z))
256
257; GCN-LABEL: {{^}}fsub_fpext_fneg_fmul_f16_to_f32:
258; GCN: s_waitcnt
259; GFX9-F32FLUSH-NEXT: v_mad_mix_f32 v0, v0, -v1, -v2 op_sel_hi:[1,1,0]{{$}}
260; GFX9-F32FLUSH-NEXT: s_setpc_b64
261
262; GFX9-F32DENORM-NEXT: v_mul_f16_e64 v0, v0, -v1
263; GFX9-F32DENORM-NEXT: v_cvt_f32_f16_e32 v0, v0
264; GFX9-F32DENORM-NEXT: v_sub_f32_e32 v0, v0, v2
265; GFX9-F32DENORM-NEXT: s_setpc_b64
266define float @fsub_fpext_fneg_fmul_f16_to_f32(half %x, half %y, float %z) #0 {
267entry:
268  %mul = fmul half %x, %y
269  %neg.mul = fsub half -0.0, %mul
270  %neg.mul.ext = fpext half %neg.mul to float
271  %add = fsub float %neg.mul.ext, %z
272  ret float %add
273}
274
275; fold (fsub (fneg (fpext (fmul, x, y))), z)
276;   -> (fneg (fma (fpext x)), (fpext y), z)
277
278; GCN-LABEL: {{^}}fsub_fneg_fpext_fmul_f16_to_f32:
279; GCN: s_waitcnt
280; GFX9-F32FLUSH-NEXT: v_mad_mix_f32 v0, v0, -v1, -v2 op_sel_hi:[1,1,0]{{$}}
281; GFX9-F32FLUSH-NEXT: s_setpc_b64
282
283; GFX9-F32DENORM-NEXT: v_mul_f16_e64 v0, v0, -v1
284; GFX9-F32DENORM-NEXT: v_cvt_f32_f16_e32 v0, v0
285; GFX9-F32DENORM-NEXT: v_sub_f32_e32 v0, v0, v2
286; GFX9-F32DENORM-NEXT: s_setpc_b64
287define float @fsub_fneg_fpext_fmul_f16_to_f32(half %x, half %y, float %z) #0 {
288entry:
289  %mul = fmul half %x, %y
290  %mul.ext = fpext half %mul to float
291  %neg.mul.ext = fneg float %mul.ext
292  %add = fsub float %neg.mul.ext, %z
293  ret float %add
294}
295
296; fold (fsub (fmad x, y, (fpext (fmul u, v))), z)
297;    -> (fmad x, y (fmad (fpext u), (fpext v), (fneg z)))
298; GCN-LABEL: {{^}}fsub_muladd_fpext_mul_f16_to_f32:
299; GCN: s_waitcnt
300; GFX9-F32FLUSH-NEXT: v_mad_mix_f32 v2, v3, v4, -v2 op_sel_hi:[1,1,0]{{$}}
301; GFX9-F32FLUSH-NEXT: v_mac_f32_e32 v2, v0, v1
302; GFX9-F32FLUSH-NEXT: v_mov_b32_e32 v0, v2
303; GFX9-F32FLUSH-NEXT: s_setpc_b64
304
305; GFX9-F32DENORM-NEXT: v_mul_f16_e32 v3, v3, v4
306; GFX9-F32DENORM-NEXT: v_cvt_f32_f16_e32 v3, v3
307; GFX9-F32DENORM-NEXT: v_fma_f32 v0, v0, v1, v3
308; GFX9-F32DENORM-NEXT: v_sub_f32_e32 v0, v0, v2
309; GFX9-F32DENORM-NEXT: s_setpc_b64
310define float @fsub_muladd_fpext_mul_f16_to_f32(float %x, float %y, float %z, half %u, half %v) #0 {
311entry:
312  %mul = fmul reassoc half %u, %v
313  %mul.ext = fpext half %mul to float
314  %fma = call float @llvm.fmuladd.f32(float %x, float %y, float %mul.ext)
315  %add = fsub reassoc float %fma, %z
316  ret float %add
317}
318
319;  fold (fsub (fpext (fmad x, y, (fmul u, v))), z)
320;    -> (fmad (fpext x), (fpext y),
321;            (fmad (fpext u), (fpext v), (fneg z)))
322
323; GCN-LABEL: {{^}}fsub_fpext_muladd_mul_f16_to_f32:
324; GFX9: v_mul_f16
325; GFX9: v_fma_f16
326; GFX9: v_cvt_f32_f16
327; GFX9: v_sub_f32
328; GCN: s_setpc_b64
329define float @fsub_fpext_muladd_mul_f16_to_f32(half %x, half %y, float %z, half %u, half %v) #0 {
330entry:
331  %mul = fmul half %u, %v
332  %fma = call half @llvm.fmuladd.f16(half %x, half %y, half %mul)
333  %fma.ext = fpext half %fma to float
334  %add = fsub float %fma.ext, %z
335  ret float %add
336}
337
338; fold (fsub x, (fmad y, z, (fpext (fmul u, v))))
339;   -> (fmad (fneg y), z, (fmad (fneg (fpext u)), (fpext v), x))
340; GCN-LABEL: {{^}}fsub_muladd_fpext_mul_f16_to_f32_commute:
341; GCN: s_waitcnt
342; GFX9-F32FLUSH-NEXT: v_mad_mix_f32 v0, -v3, v4, v0 op_sel_hi:[1,1,0]{{$}}
343; GFX9-F32FLUSH-NEXT: v_mad_f32 v0, -v1, v2, v0{{$}}
344; GFX9-F32FLUSH-NEXT: s_setpc_b64
345
346; GFX9-F32DENORM-NEXT: v_mul_f16_e32 v3, v3, v4
347; GFX9-F32DENORM-NEXT: v_cvt_f32_f16_e32 v3, v3
348; GFX9-F32DENORM-NEXT: v_fma_f32 v1, v1, v2, v3
349; GFX9-F32DENORM-NEXT: v_sub_f32_e32 v0, v0, v1
350; GFX9-F32DENORM-NEXT: s_setpc_b64
351define float @fsub_muladd_fpext_mul_f16_to_f32_commute(float %x, float %y, float %z, half %u, half %v) #0 {
352entry:
353  %mul = fmul reassoc half %u, %v
354  %mul.ext = fpext half %mul to float
355  %fma = call float @llvm.fmuladd.f32(float %y, float %z, float %mul.ext)
356  %add = fsub reassoc float %x, %fma
357  ret float %add
358}
359
360; fold (fsub x, (fpext (fma y, z, (fmul u, v))))
361;    -> (fma (fneg (fpext y)), (fpext z),
362;            (fma (fneg (fpext u)), (fpext v), x))
363; GCN-LABEL: {{^}}fsub_fpext_muladd_mul_f16_to_f32_commute:
364; GCN: s_waitcnt
365; GFX9-NEXT: v_mul_f16_e32 v3, v3, v4
366; GFX9-NEXT: v_fma_f16 v1, v1, v2, v3
367; GFX9-NEXT: v_cvt_f32_f16_e32 v1, v1
368; GFX9-NEXT: v_sub_f32_e32 v0, v0, v1
369; GFX9-NEXT: s_setpc_b64
370define float @fsub_fpext_muladd_mul_f16_to_f32_commute(float %x, half %y, half %z, half %u, half %v) #0 {
371entry:
372  %mul = fmul half %u, %v
373  %fma = call half @llvm.fmuladd.f16(half %y, half %z, half %mul)
374  %fma.ext = fpext half %fma to float
375  %add = fsub float %x, %fma.ext
376  ret float %add
377}
378
379declare float @llvm.fmuladd.f32(float, float, float) #0
380declare float @llvm.fma.f32(float, float, float) #0
381declare half @llvm.fmuladd.f16(half, half, half) #0
382declare half @llvm.fma.f16(half, half, half) #0
383
384attributes #0 = { nounwind readnone speculatable }
385