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