diff --git a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp index 94953440eeb5..043f613b96cd 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp @@ -2899,6 +2899,20 @@ SDValue AMDGPUTargetLowering::performFNegCombine(SDNode *N, DAG.ReplaceAllUsesWith(N0, DAG.getNode(ISD::FNEG, SL, VT, Res)); return Res; } + case ISD::FP_EXTEND: { + SDValue CvtSrc = N0.getOperand(0); + if (CvtSrc.getOpcode() == ISD::FNEG) { + // (fneg (fp_extend (fneg x))) -> (fp_extend x) + return DAG.getNode(ISD::FP_EXTEND, SL, VT, CvtSrc.getOperand(0)); + } + + if (!N0.hasOneUse()) + return SDValue(); + + // (fneg (fp_extend x)) -> (fp_extend (fneg x)) + SDValue Neg = DAG.getNode(ISD::FNEG, SL, CvtSrc.getValueType(), CvtSrc); + return DAG.getNode(ISD::FP_EXTEND, SL, VT, Neg); + } default: return SDValue(); } diff --git a/llvm/test/CodeGen/AMDGPU/fneg-combines.ll b/llvm/test/CodeGen/AMDGPU/fneg-combines.ll index b747a7ed2c2d..69fbcf739796 100644 --- a/llvm/test/CodeGen/AMDGPU/fneg-combines.ll +++ b/llvm/test/CodeGen/AMDGPU/fneg-combines.ll @@ -655,6 +655,132 @@ define void @v_fneg_fmad_multi_use_fmad_f32(float addrspace(1)* %out, float addr ret void } +; -------------------------------------------------------------------------------- +; fp_extend tests +; -------------------------------------------------------------------------------- + +; GCN-LABEL: {{^}}v_fneg_fp_extend_f32_to_f64: +; GCN: {{buffer|flat}}_load_dword [[A:v[0-9]+]] +; GCN: v_cvt_f64_f32_e64 [[RESULT:v\[[0-9]+:[0-9]+\]]], -[[A]] +; GCN: buffer_store_dwordx2 [[RESULT]] +define void @v_fneg_fp_extend_f32_to_f64(double addrspace(1)* %out, float addrspace(1)* %a.ptr) #0 { + %tid = call i32 @llvm.amdgcn.workitem.id.x() + %tid.ext = sext i32 %tid to i64 + %a.gep = getelementptr inbounds float, float addrspace(1)* %a.ptr, i64 %tid.ext + %out.gep = getelementptr inbounds double, double addrspace(1)* %out, i64 %tid.ext + %a = load volatile float, float addrspace(1)* %a.gep + %fpext = fpext float %a to double + %fneg = fsub double -0.000000e+00, %fpext + store double %fneg, double addrspace(1)* %out.gep + ret void +} + +; GCN-LABEL: {{^}}v_fneg_fp_extend_fneg_f32_to_f64: +; GCN: {{buffer|flat}}_load_dword [[A:v[0-9]+]] +; GCN: v_cvt_f64_f32_e32 [[RESULT:v\[[0-9]+:[0-9]+\]]], [[A]] +; GCN: buffer_store_dwordx2 [[RESULT]] +define void @v_fneg_fp_extend_fneg_f32_to_f64(double addrspace(1)* %out, float addrspace(1)* %a.ptr) #0 { + %tid = call i32 @llvm.amdgcn.workitem.id.x() + %tid.ext = sext i32 %tid to i64 + %a.gep = getelementptr inbounds float, float addrspace(1)* %a.ptr, i64 %tid.ext + %out.gep = getelementptr inbounds double, double addrspace(1)* %out, i64 %tid.ext + %a = load volatile float, float addrspace(1)* %a.gep + %fneg.a = fsub float -0.000000e+00, %a + %fpext = fpext float %fneg.a to double + %fneg = fsub double -0.000000e+00, %fpext + store double %fneg, double addrspace(1)* %out.gep + ret void +} + +; GCN-LABEL: {{^}}v_fneg_fp_extend_store_use_fneg_f32_to_f64: +; GCN: {{buffer|flat}}_load_dword [[A:v[0-9]+]] +; GCN-DAG: v_cvt_f64_f32_e32 [[RESULT:v\[[0-9]+:[0-9]+\]]], [[A]] +; GCN-DAG: v_xor_b32_e32 [[FNEG_A:v[0-9]+]], 0x80000000, [[A]] +; GCN: buffer_store_dwordx2 [[RESULT]] +; GCN: buffer_store_dword [[FNEG_A]] +define void @v_fneg_fp_extend_store_use_fneg_f32_to_f64(double addrspace(1)* %out, float addrspace(1)* %a.ptr) #0 { + %tid = call i32 @llvm.amdgcn.workitem.id.x() + %tid.ext = sext i32 %tid to i64 + %a.gep = getelementptr inbounds float, float addrspace(1)* %a.ptr, i64 %tid.ext + %out.gep = getelementptr inbounds double, double addrspace(1)* %out, i64 %tid.ext + %a = load volatile float, float addrspace(1)* %a.gep + %fneg.a = fsub float -0.000000e+00, %a + %fpext = fpext float %fneg.a to double + %fneg = fsub double -0.000000e+00, %fpext + store volatile double %fneg, double addrspace(1)* %out.gep + store volatile float %fneg.a, float addrspace(1)* undef + ret void +} + +; GCN-LABEL: {{^}}v_fneg_multi_use_fp_extend_fneg_f32_to_f64: +; GCN: {{buffer|flat}}_load_dword [[A:v[0-9]+]] +; GCN-DAG: v_cvt_f64_f32_e32 v{{\[}}[[CVT_LO:[0-9]+]]:[[CVT_HI:[0-9]+]]{{\]}}, [[A]] +; GCN-DAG: v_xor_b32_e32 v[[FNEG_A:[0-9]+]], 0x80000000, v[[CVT_HI]] +; GCN: buffer_store_dwordx2 v{{\[[0-9]+}}:[[FNEG_A]]{{\]}} +; GCN: buffer_store_dwordx2 v{{\[}}[[CVT_LO]]:[[CVT_HI]]{{\]}} +define void @v_fneg_multi_use_fp_extend_fneg_f32_to_f64(double addrspace(1)* %out, float addrspace(1)* %a.ptr) #0 { + %tid = call i32 @llvm.amdgcn.workitem.id.x() + %tid.ext = sext i32 %tid to i64 + %a.gep = getelementptr inbounds float, float addrspace(1)* %a.ptr, i64 %tid.ext + %out.gep = getelementptr inbounds double, double addrspace(1)* %out, i64 %tid.ext + %a = load volatile float, float addrspace(1)* %a.gep + %fpext = fpext float %a to double + %fneg = fsub double -0.000000e+00, %fpext + store volatile double %fneg, double addrspace(1)* %out.gep + store volatile double %fpext, double addrspace(1)* undef + ret void +} + +; GCN-LABEL: {{^}}v_fneg_multi_foldable_use_fp_extend_fneg_f32_to_f64: +; GCN: {{buffer|flat}}_load_dword [[A:v[0-9]+]] +; GCN-DAG: v_cvt_f64_f32_e32 v{{\[}}[[CVT_LO:[0-9]+]]:[[CVT_HI:[0-9]+]]{{\]}}, [[A]] +; GCN-DAG: v_xor_b32_e32 v[[FNEG_A:[0-9]+]], 0x80000000, v[[CVT_HI]] +; GCN-DAG: v_mul_f64 [[MUL:v\[[0-9]+:[0-9]+\]]], v{{\[}}[[CVT_LO]]:[[CVT_HI]]{{\]}}, 4.0 +; GCN: buffer_store_dwordx2 v{{\[[0-9]+}}:[[FNEG_A]]{{\]}} +; GCN: buffer_store_dwordx2 [[MUL]] +define void @v_fneg_multi_foldable_use_fp_extend_fneg_f32_to_f64(double addrspace(1)* %out, float addrspace(1)* %a.ptr) #0 { + %tid = call i32 @llvm.amdgcn.workitem.id.x() + %tid.ext = sext i32 %tid to i64 + %a.gep = getelementptr inbounds float, float addrspace(1)* %a.ptr, i64 %tid.ext + %out.gep = getelementptr inbounds double, double addrspace(1)* %out, i64 %tid.ext + %a = load volatile float, float addrspace(1)* %a.gep + %fpext = fpext float %a to double + %fneg = fsub double -0.000000e+00, %fpext + %mul = fmul double %fpext, 4.0 + store volatile double %fneg, double addrspace(1)* %out.gep + store volatile double %mul, double addrspace(1)* %out.gep + ret void +} + +; FIXME: Source modifiers not folded for f16->f32 +; GCN-LABEL: {{^}}v_fneg_multi_use_fp_extend_fneg_f16_to_f32: +define void @v_fneg_multi_use_fp_extend_fneg_f16_to_f32(float addrspace(1)* %out, half addrspace(1)* %a.ptr) #0 { + %tid = call i32 @llvm.amdgcn.workitem.id.x() + %tid.ext = sext i32 %tid to i64 + %a.gep = getelementptr inbounds half, half addrspace(1)* %a.ptr, i64 %tid.ext + %out.gep = getelementptr inbounds float, float addrspace(1)* %out, i64 %tid.ext + %a = load volatile half, half addrspace(1)* %a.gep + %fpext = fpext half %a to float + %fneg = fsub float -0.000000e+00, %fpext + store volatile float %fneg, float addrspace(1)* %out.gep + store volatile float %fpext, float addrspace(1)* %out.gep + ret void +} + +; GCN-LABEL: {{^}}v_fneg_multi_foldable_use_fp_extend_fneg_f16_to_f32: +define void @v_fneg_multi_foldable_use_fp_extend_fneg_f16_to_f32(float addrspace(1)* %out, half addrspace(1)* %a.ptr) #0 { + %tid = call i32 @llvm.amdgcn.workitem.id.x() + %tid.ext = sext i32 %tid to i64 + %a.gep = getelementptr inbounds half, half addrspace(1)* %a.ptr, i64 %tid.ext + %out.gep = getelementptr inbounds float, float addrspace(1)* %out, i64 %tid.ext + %a = load volatile half, half addrspace(1)* %a.gep + %fpext = fpext half %a to float + %fneg = fsub float -0.000000e+00, %fpext + %mul = fmul float %fpext, 4.0 + store volatile float %fneg, float addrspace(1)* %out.gep + store volatile float %mul, float addrspace(1)* %out.gep + ret void +} declare i32 @llvm.amdgcn.workitem.id.x() #1 declare float @llvm.fma.f32(float, float, float) #1