1; RUN: llc -march=amdgcn -verify-machineinstrs -enable-unsafe-fp-math < %s | FileCheck -check-prefix=GCN -check-prefix=SI -check-prefix=SIVI %s
2; RUN: llc -march=amdgcn -mcpu=fiji -mattr=-flat-for-global -verify-machineinstrs -enable-unsafe-fp-math < %s | FileCheck -check-prefix=GCN -check-prefix=VI -check-prefix=GFX89 %s
3; RUN: llc -march=amdgcn -mcpu=gfx901 -mattr=-flat-for-global -verify-machineinstrs -enable-unsafe-fp-math < %s | FileCheck -check-prefix=GCN -check-prefix=GFX9 -check-prefix=GFX89 %s
4
5; GCN-LABEL: {{^}}fpext_f16_to_f32
6; GCN: buffer_load_ushort v[[A_F16:[0-9]+]]
7; GCN: v_cvt_f32_f16_e32 v[[R_F32:[0-9]+]], v[[A_F16]]
8; GCN: buffer_store_dword v[[R_F32]]
9; GCN: s_endpgm
10define void @fpext_f16_to_f32(
11    float addrspace(1)* %r,
12    half addrspace(1)* %a) #0 {
13entry:
14  %a.val = load half, half addrspace(1)* %a
15  %r.val = fpext half %a.val to float
16  store float %r.val, float addrspace(1)* %r
17  ret void
18}
19
20; GCN-LABEL: {{^}}fpext_f16_to_f64
21; GCN: buffer_load_ushort v[[A_F16:[0-9]+]]
22; GCN: v_cvt_f32_f16_e32 v[[A_F32:[0-9]+]], v[[A_F16]]
23; GCN: v_cvt_f64_f32_e32 v{{\[}}[[R_F64_0:[0-9]+]]:[[R_F64_1:[0-9]+]]{{\]}}, v[[A_F32]]
24; GCN: buffer_store_dwordx2 v{{\[}}[[R_F64_0]]:[[R_F64_1]]{{\]}}
25; GCN: s_endpgm
26define void @fpext_f16_to_f64(
27    double addrspace(1)* %r,
28    half addrspace(1)* %a) #0 {
29entry:
30  %a.val = load half, half addrspace(1)* %a
31  %r.val = fpext half %a.val to double
32  store double %r.val, double addrspace(1)* %r
33  ret void
34}
35
36; GCN-LABEL: {{^}}fpext_v2f16_to_v2f32
37; GCN: buffer_load_dword v[[A_V2_F16:[0-9]+]]
38; GFX89-DAG:  v_lshrrev_b32_e32 v[[A_F16_1:[0-9]+]], 16, v[[A_V2_F16]]
39; GCN-DAG: v_cvt_f32_f16_e32 v[[R_F32_0:[0-9]+]], v[[A_V2_F16]]
40; SI:  v_lshrrev_b32_e32 v[[A_F16_1:[0-9]+]], 16, v[[A_V2_F16]]
41; GCN: v_cvt_f32_f16_e32 v[[R_F32_1:[0-9]+]], v[[A_F16_1]]
42; GCN: buffer_store_dwordx2 v{{\[}}[[R_F32_0]]:[[R_F32_1]]{{\]}}
43; GCN: s_endpgm
44define void @fpext_v2f16_to_v2f32(
45    <2 x float> addrspace(1)* %r,
46    <2 x half> addrspace(1)* %a) #0 {
47entry:
48  %a.val = load <2 x half>, <2 x half> addrspace(1)* %a
49  %r.val = fpext <2 x half> %a.val to <2 x float>
50  store <2 x float> %r.val, <2 x float> addrspace(1)* %r
51  ret void
52}
53
54; GCN-LABEL: {{^}}fpext_v2f16_to_v2f64
55; GCN: buffer_load_dword
56; GCN-DAG: v_lshrrev_b32_e32
57; GCN-DAG: v_cvt_f32_f16_e32
58; GCN: v_cvt_f32_f16_e32
59
60; GCN: v_cvt_f64_f32_e32
61; GCN: v_cvt_f64_f32_e32
62; GCN: buffer_store_dwordx4
63; GCN: s_endpgm
64define void @fpext_v2f16_to_v2f64(
65    <2 x double> addrspace(1)* %r,
66    <2 x half> addrspace(1)* %a) {
67entry:
68  %a.val = load <2 x half>, <2 x half> addrspace(1)* %a
69  %r.val = fpext <2 x half> %a.val to <2 x double>
70  store <2 x double> %r.val, <2 x double> addrspace(1)* %r
71  ret void
72}
73
74; GCN-LABEL: {{^}}s_fneg_fpext_f16_to_f32:
75; GCN: v_cvt_f32_f16_e32 v{{[0-9]+}}, s{{[0-9]+}}
76define void @s_fneg_fpext_f16_to_f32(float addrspace(1)* %r, i32 %a) {
77entry:
78  %a.trunc = trunc i32 %a to i16
79  %a.val = bitcast i16 %a.trunc to half
80  %r.val = fpext half %a.val to float
81  store float %r.val, float addrspace(1)* %r
82  ret void
83}
84
85; GCN-LABEL: {{^}}fneg_fpext_f16_to_f32:
86; GCN: {{buffer|flat}}_load_ushort [[A:v[0-9]+]]
87; GCN: v_cvt_f32_f16_e64 v{{[0-9]+}}, -[[A]]
88define void @fneg_fpext_f16_to_f32(
89    float addrspace(1)* %r,
90    half addrspace(1)* %a) {
91entry:
92  %a.val = load half, half addrspace(1)* %a
93  %a.neg = fsub half -0.0, %a.val
94  %r.val = fpext half %a.neg to float
95  store float %r.val, float addrspace(1)* %r
96  ret void
97}
98
99; GCN-LABEL: {{^}}fabs_fpext_f16_to_f32:
100; GCN: {{buffer|flat}}_load_ushort [[A:v[0-9]+]]
101; GCN: v_cvt_f32_f16_e64 v{{[0-9]+}}, |[[A]]|
102define void @fabs_fpext_f16_to_f32(
103    float addrspace(1)* %r,
104    half addrspace(1)* %a) {
105entry:
106  %a.val = load half, half addrspace(1)* %a
107  %a.fabs = call half @llvm.fabs.f16(half %a.val)
108  %r.val = fpext half %a.fabs to float
109  store float %r.val, float addrspace(1)* %r
110  ret void
111}
112
113; GCN-LABEL: {{^}}fneg_fabs_fpext_f16_to_f32:
114; GCN: {{buffer|flat}}_load_ushort [[A:v[0-9]+]]
115; GCN: v_cvt_f32_f16_e64 v{{[0-9]+}}, -|[[A]]|
116define void @fneg_fabs_fpext_f16_to_f32(
117    float addrspace(1)* %r,
118    half addrspace(1)* %a) {
119entry:
120  %a.val = load half, half addrspace(1)* %a
121  %a.fabs = call half @llvm.fabs.f16(half %a.val)
122  %a.fneg.fabs = fsub half -0.0, %a.fabs
123  %r.val = fpext half %a.fneg.fabs to float
124  store float %r.val, float addrspace(1)* %r
125  ret void
126}
127
128; GCN-LABEL: {{^}}fneg_multi_use_fpext_f16_to_f32:
129; GCN: {{buffer|flat}}_load_ushort [[A:v[0-9]+]]
130; GCN-DAG: v_xor_b32_e32 [[XOR:v[0-9]+]], 0x8000, [[A]]
131
132; FIXME: Using the source modifier here only wastes code size
133; SI-DAG: v_cvt_f32_f16_e32 [[CVT:v[0-9]+]], [[A]]
134; GFX89-DAG: v_cvt_f32_f16_e64 [[CVT:v[0-9]+]], -[[A]]
135
136; GCN: store_dword [[CVT]]
137; GCN: store_short [[XOR]]
138define void @fneg_multi_use_fpext_f16_to_f32(
139    float addrspace(1)* %r,
140    half addrspace(1)* %a) {
141entry:
142  %a.val = load half, half addrspace(1)* %a
143  %a.neg = fsub half -0.0, %a.val
144  %r.val = fpext half %a.neg to float
145  store volatile float %r.val, float addrspace(1)* %r
146  store volatile half %a.neg, half addrspace(1)* undef
147  ret void
148}
149
150; GCN-LABEL: {{^}}fneg_multi_foldable_use_fpext_f16_to_f32:
151; GCN: {{buffer|flat}}_load_ushort [[A:v[0-9]+]]
152; GCN-DAG: v_cvt_f32_f16_e64 [[CVTA_NEG:v[0-9]+]], -[[A]]
153; SI-DAG: v_cvt_f32_f16_e32 [[CVTA:v[0-9]+]], [[A]]
154; SI: v_mul_f32_e32 [[MUL_F32:v[0-9]+]], [[CVTA]], [[CVTA_NEG]]
155; SI: v_cvt_f16_f32_e32 [[MUL:v[0-9]+]], [[MUL_F32]]
156
157; GFX89-DAG: v_cvt_f32_f16_e64 [[CVT_NEGA:v[0-9]+]], -[[A]]
158; GFX89: v_mul_f16_e64 [[MUL:v[0-9]+]], -[[A]], [[A]]
159
160; GCN: buffer_store_dword [[CVTA_NEG]]
161; GCN: buffer_store_short [[MUL]]
162define void @fneg_multi_foldable_use_fpext_f16_to_f32(
163    float addrspace(1)* %r,
164    half addrspace(1)* %a) {
165entry:
166  %a.val = load half, half addrspace(1)* %a
167  %a.neg = fsub half -0.0, %a.val
168  %r.val = fpext half %a.neg to float
169  %mul = fmul half %a.neg, %a.val
170  store volatile float %r.val, float addrspace(1)* %r
171  store volatile half %mul, half addrspace(1)* undef
172  ret void
173}
174
175; GCN-LABEL: {{^}}fabs_multi_use_fpext_f16_to_f32:
176; GCN: {{buffer|flat}}_load_ushort [[A:v[0-9]+]]
177; GCN-DAG: v_and_b32_e32 [[XOR:v[0-9]+]], 0x7fff, [[A]]
178
179; SI-DAG: v_cvt_f32_f16_e32 [[CVT:v[0-9]+]], [[A]]
180; VI-DAG: v_cvt_f32_f16_e64 [[CVT:v[0-9]+]], |[[A]]|
181
182; GCN: store_dword [[CVT]]
183; GCN: store_short [[XOR]]
184define void @fabs_multi_use_fpext_f16_to_f32(
185    float addrspace(1)* %r,
186    half addrspace(1)* %a) {
187entry:
188  %a.val = load half, half addrspace(1)* %a
189  %a.fabs = call half @llvm.fabs.f16(half %a.val)
190  %r.val = fpext half %a.fabs to float
191  store volatile float %r.val, float addrspace(1)* %r
192  store volatile half %a.fabs, half addrspace(1)* undef
193  ret void
194}
195
196; GCN-LABEL: {{^}}fabs_multi_foldable_use_fpext_f16_to_f32:
197; GCN: {{buffer|flat}}_load_ushort [[A:v[0-9]+]]
198; SI: v_cvt_f32_f16_e32 [[CVTA:v[0-9]+]], [[A]]
199; SI: v_mul_f32_e64 [[MUL_F32:v[0-9]+]], |[[CVTA]]|, [[CVTA]]
200; SI: v_cvt_f16_f32_e32 [[MUL:v[0-9]+]], [[MUL_F32]]
201; SI: v_and_b32_e32 [[ABS_A:v[0-9]+]], 0x7fffffff, [[CVTA]]
202
203; GFX89-DAG: v_cvt_f32_f16_e64 [[ABS_A:v[0-9]+]], |[[A]]|
204; GFX89: v_mul_f16_e64 [[MUL:v[0-9]+]], |[[A]]|, [[A]]
205
206; GCN: buffer_store_dword [[ABS_A]]
207; GCN: buffer_store_short [[MUL]]
208define void @fabs_multi_foldable_use_fpext_f16_to_f32(
209    float addrspace(1)* %r,
210    half addrspace(1)* %a) {
211entry:
212  %a.val = load half, half addrspace(1)* %a
213  %a.fabs = call half @llvm.fabs.f16(half %a.val)
214  %r.val = fpext half %a.fabs to float
215  %mul = fmul half %a.fabs, %a.val
216  store volatile float %r.val, float addrspace(1)* %r
217  store volatile half %mul, half addrspace(1)* undef
218  ret void
219}
220
221; GCN-LABEL: {{^}}fabs_fneg_multi_use_fpext_f16_to_f32:
222; GCN: {{buffer|flat}}_load_ushort [[A:v[0-9]+]]
223; GCN-DAG: v_or_b32_e32 [[OR:v[0-9]+]], 0x8000, [[A]]
224
225; SI: v_cvt_f32_f16_e32 [[CVT:v[0-9]+]], [[OR]]
226; VI-DAG: v_cvt_f32_f16_e64 [[CVT:v[0-9]+]], -|[[OR]]|
227
228; GCN: buffer_store_dword [[CVT]]
229; GCN: buffer_store_short [[OR]]
230define void @fabs_fneg_multi_use_fpext_f16_to_f32(
231    float addrspace(1)* %r,
232    half addrspace(1)* %a) {
233entry:
234  %a.val = load half, half addrspace(1)* %a
235  %a.fabs = call half @llvm.fabs.f16(half %a.val)
236  %a.fneg.fabs = fsub half -0.0, %a.fabs
237  %r.val = fpext half %a.fneg.fabs to float
238  store volatile float %r.val, float addrspace(1)* %r
239  store volatile half %a.fneg.fabs, half addrspace(1)* undef
240  ret void
241}
242
243; GCN-LABEL: {{^}}fabs_fneg_multi_foldable_use_fpext_f16_to_f32:
244; GCN: {{buffer|flat}}_load_ushort [[A:v[0-9]+]]
245; SI: v_cvt_f32_f16_e32 [[CVTA:v[0-9]+]], [[A]]
246; SI: v_mul_f32_e64 [[MUL_F32:v[0-9]+]], -|[[CVTA]]|, [[CVTA]]
247; SI: v_cvt_f16_f32_e32 [[MUL:v[0-9]+]], [[MUL_F32]]
248; SI: v_or_b32_e32 [[FABS_FNEG:v[0-9]+]], 0x80000000, [[CVTA]]
249
250; GFX89-DAG: v_cvt_f32_f16_e64 [[FABS_FNEG:v[0-9]+]], -|[[A]]|
251; GFX89-DAG: v_mul_f16_e64 [[MUL:v[0-9]+]], -|[[A]]|, [[A]]
252
253; GCN: buffer_store_dword [[FABS_FNEG]]
254; GCN: buffer_store_short [[MUL]]
255define void @fabs_fneg_multi_foldable_use_fpext_f16_to_f32(
256    float addrspace(1)* %r,
257    half addrspace(1)* %a) {
258entry:
259  %a.val = load half, half addrspace(1)* %a
260  %a.fabs = call half @llvm.fabs.f16(half %a.val)
261  %a.fneg.fabs = fsub half -0.0, %a.fabs
262  %r.val = fpext half %a.fneg.fabs to float
263  %mul = fmul half %a.fneg.fabs, %a.val
264  store volatile float %r.val, float addrspace(1)* %r
265  store volatile half %mul, half addrspace(1)* undef
266  ret void
267}
268
269declare half @llvm.fabs.f16(half) #1
270
271attributes #1 = { nounwind readnone }
272