diff --git a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp --- a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp @@ -306,6 +306,8 @@ setOperationAction(ISD::FREM, {MVT::f16, MVT::f32, MVT::f64}, Custom); + setOperationAction(ISD::IS_FPCLASS, {MVT::f16, MVT::f32, MVT::f64}, Legal); + // Expand to fneg + fadd. setOperationAction(ISD::FSUB, MVT::f64, Expand); diff --git a/llvm/lib/Target/AMDGPU/AMDGPUInstrInfo.td b/llvm/lib/Target/AMDGPU/AMDGPUInstrInfo.td --- a/llvm/lib/Target/AMDGPU/AMDGPUInstrInfo.td +++ b/llvm/lib/Target/AMDGPU/AMDGPUInstrInfo.td @@ -130,6 +130,7 @@ def AMDGPUpk_u16_u32_impl : SDNode<"AMDGPUISD::CVT_PK_U16_U32", AMDGPUIntPackOp>; def AMDGPUfp_to_f16 : SDNode<"AMDGPUISD::FP_TO_FP16" , SDTFPToIntOp>; +def AMDGPUis_fpclass_impl : SDNode<"ISD::IS_FPCLASS", AMDGPUFPClassOp>; def AMDGPUfp_class_impl : SDNode<"AMDGPUISD::FP_CLASS", AMDGPUFPClassOp>; @@ -388,7 +389,8 @@ def AMDGPUfp_class : PatFrags<(ops node:$src0, node:$src1), [(int_amdgcn_class node:$src0, node:$src1), - (AMDGPUfp_class_impl node:$src0, node:$src1)]>; + (AMDGPUfp_class_impl node:$src0, node:$src1), + (AMDGPUis_fpclass_impl node:$src0, node:$src1)]>; def AMDGPUfmed3 : PatFrags<(ops node:$src0, node:$src1, node:$src2), [(int_amdgcn_fmed3 node:$src0, node:$src1, node:$src2), diff --git a/llvm/test/CodeGen/AMDGPU/llvm.is.fpclass.ll b/llvm/test/CodeGen/AMDGPU/llvm.is.fpclass.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/AMDGPU/llvm.is.fpclass.ll @@ -0,0 +1,182 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -global-isel=0 -march=amdgcn -mcpu=gfx908 -verify-machineinstrs < %s | FileCheck --check-prefix=SELDAG %s + + +define i1 @isnan_half(half %x) nounwind { +; SELDAG-LABEL: isnan_half: +; SELDAG: ; %bb.0: +; SELDAG-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) +; SELDAG-NEXT: v_cmp_class_f16_e64 s[4:5], v0, 3 +; SELDAG-NEXT: v_cndmask_b32_e64 v0, 0, 1, s[4:5] +; SELDAG-NEXT: s_setpc_b64 s[30:31] + %1 = call i1 @llvm.is.fpclass.f16(half %x, i32 3) ; nan + ret i1 %1 +} + +define i1 @isnan_float(float %x) nounwind { +; SELDAG-LABEL: isnan_float: +; SELDAG: ; %bb.0: +; SELDAG-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) +; SELDAG-NEXT: v_cmp_class_f32_e64 s[4:5], v0, 3 +; SELDAG-NEXT: v_cndmask_b32_e64 v0, 0, 1, s[4:5] +; SELDAG-NEXT: s_setpc_b64 s[30:31] + %1 = call i1 @llvm.is.fpclass.f32(float %x, i32 3) ; nan + ret i1 %1 +} + +define i1 @isnan_double(double %x) nounwind { +; SELDAG-LABEL: isnan_double: +; SELDAG: ; %bb.0: +; SELDAG-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) +; SELDAG-NEXT: v_cmp_class_f64_e64 s[4:5], v[0:1], 3 +; SELDAG-NEXT: v_cndmask_b32_e64 v0, 0, 1, s[4:5] +; SELDAG-NEXT: s_setpc_b64 s[30:31] + %1 = call i1 @llvm.is.fpclass.f64(double %x, i32 3) ; nan + ret i1 %1 +} + +define i1 @isnan_half_strictfp(half %x) strictfp nounwind { +; SELDAG-LABEL: isnan_half_strictfp: +; SELDAG: ; %bb.0: +; SELDAG-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) +; SELDAG-NEXT: v_cmp_class_f16_e64 s[4:5], v0, 3 +; SELDAG-NEXT: v_cndmask_b32_e64 v0, 0, 1, s[4:5] +; SELDAG-NEXT: s_setpc_b64 s[30:31] + %1 = call i1 @llvm.is.fpclass.f16(half %x, i32 3) ; nan + ret i1 %1 +} + +define i1 @isnan_float_strictfp(float %x) strictfp nounwind { +; SELDAG-LABEL: isnan_float_strictfp: +; SELDAG: ; %bb.0: +; SELDAG-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) +; SELDAG-NEXT: v_cmp_class_f32_e64 s[4:5], v0, 3 +; SELDAG-NEXT: v_cndmask_b32_e64 v0, 0, 1, s[4:5] +; SELDAG-NEXT: s_setpc_b64 s[30:31] + %1 = call i1 @llvm.is.fpclass.f32(float %x, i32 3) ; nan + ret i1 %1 +} + +define i1 @isnan_double_strictfp(double %x) strictfp nounwind { +; SELDAG-LABEL: isnan_double_strictfp: +; SELDAG: ; %bb.0: +; SELDAG-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) +; SELDAG-NEXT: v_cmp_class_f64_e64 s[4:5], v[0:1], 3 +; SELDAG-NEXT: v_cndmask_b32_e64 v0, 0, 1, s[4:5] +; SELDAG-NEXT: s_setpc_b64 s[30:31] + %1 = call i1 @llvm.is.fpclass.f64(double %x, i32 3) ; nan + ret i1 %1 +} + +define i1 @isinf_half(half %x) nounwind { +; SELDAG-LABEL: isinf_half: +; SELDAG: ; %bb.0: +; SELDAG-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) +; SELDAG-NEXT: v_mov_b32_e32 v1, 0x204 +; SELDAG-NEXT: v_cmp_class_f16_e32 vcc, v0, v1 +; SELDAG-NEXT: v_cndmask_b32_e64 v0, 0, 1, vcc +; SELDAG-NEXT: s_setpc_b64 s[30:31] + %1 = call i1 @llvm.is.fpclass.f16(half %x, i32 516) ; 0x204 = "inf" + ret i1 %1 +} + +define i1 @isinf_float(float %x) nounwind { +; SELDAG-LABEL: isinf_float: +; SELDAG: ; %bb.0: +; SELDAG-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) +; SELDAG-NEXT: v_mov_b32_e32 v1, 0x204 +; SELDAG-NEXT: v_cmp_class_f32_e32 vcc, v0, v1 +; SELDAG-NEXT: v_cndmask_b32_e64 v0, 0, 1, vcc +; SELDAG-NEXT: s_setpc_b64 s[30:31] + %1 = call i1 @llvm.is.fpclass.f32(float %x, i32 516) ; 0x204 = "inf" + ret i1 %1 +} + +define i1 @isinf_double(double %x) nounwind { +; SELDAG-LABEL: isinf_double: +; SELDAG: ; %bb.0: +; SELDAG-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) +; SELDAG-NEXT: v_mov_b32_e32 v2, 0x204 +; SELDAG-NEXT: v_cmp_class_f64_e32 vcc, v[0:1], v2 +; SELDAG-NEXT: v_cndmask_b32_e64 v0, 0, 1, vcc +; SELDAG-NEXT: s_setpc_b64 s[30:31] + %1 = call i1 @llvm.is.fpclass.f64(double %x, i32 516) ; 0x204 = "inf" + ret i1 %1 +} + +define i1 @isfinite_half(half %x) nounwind { +; SELDAG-LABEL: isfinite_half: +; SELDAG: ; %bb.0: +; SELDAG-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) +; SELDAG-NEXT: v_mov_b32_e32 v1, 0x1f8 +; SELDAG-NEXT: v_cmp_class_f16_e32 vcc, v0, v1 +; SELDAG-NEXT: v_cndmask_b32_e64 v0, 0, 1, vcc +; SELDAG-NEXT: s_setpc_b64 s[30:31] + %1 = call i1 @llvm.is.fpclass.f16(half %x, i32 504) ; 0x1f8 = "finite" + ret i1 %1 +} + +define i1 @isfinite_float(float %x) nounwind { +; SELDAG-LABEL: isfinite_float: +; SELDAG: ; %bb.0: +; SELDAG-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) +; SELDAG-NEXT: v_mov_b32_e32 v1, 0x1f8 +; SELDAG-NEXT: v_cmp_class_f32_e32 vcc, v0, v1 +; SELDAG-NEXT: v_cndmask_b32_e64 v0, 0, 1, vcc +; SELDAG-NEXT: s_setpc_b64 s[30:31] + %1 = call i1 @llvm.is.fpclass.f32(float %x, i32 504) ; 0x1f8 = "finite" + ret i1 %1 +} + +define i1 @isfinite_double(double %x) nounwind { +; SELDAG-LABEL: isfinite_double: +; SELDAG: ; %bb.0: +; SELDAG-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) +; SELDAG-NEXT: v_mov_b32_e32 v2, 0x1f8 +; SELDAG-NEXT: v_cmp_class_f64_e32 vcc, v[0:1], v2 +; SELDAG-NEXT: v_cndmask_b32_e64 v0, 0, 1, vcc +; SELDAG-NEXT: s_setpc_b64 s[30:31] + %1 = call i1 @llvm.is.fpclass.f64(double %x, i32 504) ; 0x1f8 = "finite" + ret i1 %1 +} + +define i1 @isnormal_float(float %x) nounwind { +; SELDAG-LABEL: isnormal_float: +; SELDAG: ; %bb.0: +; SELDAG-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) +; SELDAG-NEXT: v_mov_b32_e32 v1, 0x108 +; SELDAG-NEXT: v_cmp_class_f32_e32 vcc, v0, v1 +; SELDAG-NEXT: v_cndmask_b32_e64 v0, 0, 1, vcc +; SELDAG-NEXT: s_setpc_b64 s[30:31] + %1 = call i1 @llvm.is.fpclass.f32(float %x, i32 264) ; 0x108 = "normal" + ret i1 %1 +} + +define i1 @issubnormal_float(float %x) nounwind { +; SELDAG-LABEL: issubnormal_float: +; SELDAG: ; %bb.0: +; SELDAG-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) +; SELDAG-NEXT: v_mov_b32_e32 v1, 0x90 +; SELDAG-NEXT: v_cmp_class_f32_e32 vcc, v0, v1 +; SELDAG-NEXT: v_cndmask_b32_e64 v0, 0, 1, vcc +; SELDAG-NEXT: s_setpc_b64 s[30:31] + %1 = call i1 @llvm.is.fpclass.f32(float %x, i32 144) ; 0x90 = "subnormal" + ret i1 %1 +} + +define i1 @iszero_float(float %x) nounwind { +; SELDAG-LABEL: iszero_float: +; SELDAG: ; %bb.0: +; SELDAG-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) +; SELDAG-NEXT: v_mov_b32_e32 v1, 0x60 +; SELDAG-NEXT: v_cmp_class_f32_e32 vcc, v0, v1 +; SELDAG-NEXT: v_cndmask_b32_e64 v0, 0, 1, vcc +; SELDAG-NEXT: s_setpc_b64 s[30:31] + %1 = call i1 @llvm.is.fpclass.f32(float %x, i32 96) ; 0x60 = "zero" + ret i1 %1 +} + +declare i1 @llvm.is.fpclass.f32(float, i32) +declare i1 @llvm.is.fpclass.f16(half, i32) +declare i1 @llvm.is.fpclass.f64(double, i32) +