diff options
author | Matt Arsenault <Matthew.Arsenault@amd.com> | 2018-08-03 18:27:52 +0000 |
---|---|---|
committer | Matt Arsenault <Matthew.Arsenault@amd.com> | 2018-08-03 18:27:52 +0000 |
commit | c3dc8e65e250831173f1f9b6b7c0718e2b4d56c4 (patch) | |
tree | 1450d951d5feab5cbdc23cc731cc92ae4ec66ac7 /llvm/lib | |
parent | ed69e1bc98c7bd3c9e4ad285915ff6422d68a8ba (diff) | |
download | bcm5719-llvm-c3dc8e65e250831173f1f9b6b7c0718e2b4d56c4.tar.gz bcm5719-llvm-c3dc8e65e250831173f1f9b6b7c0718e2b4d56c4.zip |
DAG: Enhance isKnownNeverNaN
Add a parameter for testing specifically for
sNaNs - at least one instruction pattern on AMDGPU
needs to check specifically for this.
Also handle more cases, and add a target hook
for custom nodes, similar to the hooks for known
bits.
llvm-svn: 338910
Diffstat (limited to 'llvm/lib')
-rw-r--r-- | llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 97 | ||||
-rw-r--r-- | llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp | 13 | ||||
-rw-r--r-- | llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp | 83 | ||||
-rw-r--r-- | llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h | 5 | ||||
-rw-r--r-- | llvm/lib/Target/AMDGPU/SIISelLowering.cpp | 11 |
5 files changed, 192 insertions, 17 deletions
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp index b5b1650fb5c..d103a81a21a 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -3622,21 +3622,102 @@ bool SelectionDAG::isBaseWithConstantOffset(SDValue Op) const { return true; } -bool SelectionDAG::isKnownNeverNaN(SDValue Op) const { +bool SelectionDAG::isKnownNeverNaN(SDValue Op, bool SNaN, unsigned Depth) const { // If we're told that NaNs won't happen, assume they won't. - if (getTarget().Options.NoNaNsFPMath) + if (getTarget().Options.NoNaNsFPMath || Op->getFlags().hasNoNaNs()) return true; - if (Op->getFlags().hasNoNaNs()) - return true; + if (Depth == 6) + return false; // Limit search depth. + // TODO: Handle vectors. // If the value is a constant, we can obviously see if it is a NaN or not. - if (const ConstantFPSDNode *C = dyn_cast<ConstantFPSDNode>(Op)) - return !C->getValueAPF().isNaN(); + if (const ConstantFPSDNode *C = dyn_cast<ConstantFPSDNode>(Op)) { + return !C->getValueAPF().isNaN() || + (SNaN && !C->getValueAPF().isSignaling()); + } - // TODO: Recognize more cases here. + unsigned Opcode = Op.getOpcode(); + switch (Opcode) { + case ISD::FADD: + case ISD::FSUB: + case ISD::FMUL: { + if (SNaN) + return true; + return isKnownNeverNaN(Op.getOperand(0), SNaN, Depth + 1) && + isKnownNeverNaN(Op.getOperand(1), SNaN, Depth + 1); + } + case ISD::FCANONICALIZE: + case ISD::FEXP: + case ISD::FEXP2: + case ISD::FTRUNC: + case ISD::FFLOOR: + case ISD::FCEIL: + case ISD::FROUND: + case ISD::FRINT: + case ISD::FNEARBYINT: { + if (SNaN) + return true; + return isKnownNeverNaN(Op.getOperand(0), SNaN, Depth + 1); + } + case ISD::FABS: + case ISD::FNEG: + case ISD::FCOPYSIGN: { + return isKnownNeverNaN(Op.getOperand(0), SNaN, Depth + 1); + } + case ISD::SELECT: + return isKnownNeverNaN(Op.getOperand(1), SNaN, Depth + 1) && + isKnownNeverNaN(Op.getOperand(2), SNaN, Depth + 1); + case ISD::FDIV: + case ISD::FREM: + case ISD::FSIN: + case ISD::FCOS: { + if (SNaN) + return true; + // TODO: Need isKnownNeverInfinity + return false; + } + case ISD::FP_EXTEND: + case ISD::FP_ROUND: { + if (SNaN) + return true; + return isKnownNeverNaN(Op.getOperand(0), SNaN, Depth + 1); + } + case ISD::SINT_TO_FP: + case ISD::UINT_TO_FP: + return true; + case ISD::FMA: + case ISD::FMAD: { + if (SNaN) + return true; + return isKnownNeverNaN(Op.getOperand(0), SNaN, Depth + 1) && + isKnownNeverNaN(Op.getOperand(1), SNaN, Depth + 1) && + isKnownNeverNaN(Op.getOperand(2), SNaN, Depth + 1); + } + case ISD::FSQRT: // Need is known positive + case ISD::FLOG: + case ISD::FLOG2: + case ISD::FLOG10: + case ISD::FPOWI: + case ISD::FPOW: { + if (SNaN) + return true; + // TODO: Refine on operand + return false; + } - return false; + // TODO: Handle FMINNUM/FMAXNUM/FMINNAN/FMAXNAN when there is an agreement on + // what they should do. + default: + if (Opcode >= ISD::BUILTIN_OP_END || + Opcode == ISD::INTRINSIC_WO_CHAIN || + Opcode == ISD::INTRINSIC_W_CHAIN || + Opcode == ISD::INTRINSIC_VOID) { + return TLI->isKnownNeverNaNForTargetNode(Op, *this, SNaN, Depth); + } + + return false; + } } bool SelectionDAG::isKnownNeverZeroFloat(SDValue Op) const { diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp index 1b0818d3428..aa5ed000d5e 100644 --- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -1711,6 +1711,19 @@ bool TargetLowering::SimplifyDemandedVectorEltsForTargetNode( return false; } +bool TargetLowering::isKnownNeverNaNForTargetNode(SDValue Op, + const SelectionDAG &DAG, + bool SNaN, + unsigned Depth) const { + assert((Op.getOpcode() >= ISD::BUILTIN_OP_END || + Op.getOpcode() == ISD::INTRINSIC_WO_CHAIN || + Op.getOpcode() == ISD::INTRINSIC_W_CHAIN || + Op.getOpcode() == ISD::INTRINSIC_VOID) && + "Should use isKnownNeverNaN if you don't know whether Op" + " is a target node!"); + return false; +} + // FIXME: Ideally, this would use ISD::isConstantSplatVector(), but that must // work with truncating build vectors and vectors with elements of less than // 8 bits. diff --git a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp index 21e44e9589d..311b2f7f674 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp @@ -4320,3 +4320,86 @@ unsigned AMDGPUTargetLowering::ComputeNumSignBitsForTargetNode( return 1; } } + +bool AMDGPUTargetLowering::isKnownNeverNaNForTargetNode(SDValue Op, + const SelectionDAG &DAG, + bool SNaN, + unsigned Depth) const { + unsigned Opcode = Op.getOpcode(); + switch (Opcode) { + case AMDGPUISD::FMIN_LEGACY: + case AMDGPUISD::FMAX_LEGACY: { + if (SNaN) + return true; + + // TODO: Can check no nans on one of the operands for each one, but which + // one? + return false; + } + case AMDGPUISD::FMUL_LEGACY: { + if (SNaN) + return true; + return DAG.isKnownNeverNaN(Op.getOperand(0), SNaN, Depth + 1) && + DAG.isKnownNeverNaN(Op.getOperand(1), SNaN, Depth + 1); + } + case AMDGPUISD::FMED3: + case AMDGPUISD::FMIN3: + case AMDGPUISD::FMAX3: + case AMDGPUISD::FMAD_FTZ: { + if (SNaN) + return true; + return DAG.isKnownNeverNaN(Op.getOperand(0), SNaN, Depth + 1) && + DAG.isKnownNeverNaN(Op.getOperand(1), SNaN, Depth + 1) && + DAG.isKnownNeverNaN(Op.getOperand(2), SNaN, Depth + 1); + } + case AMDGPUISD::CVT_F32_UBYTE0: + case AMDGPUISD::CVT_F32_UBYTE1: + case AMDGPUISD::CVT_F32_UBYTE2: + case AMDGPUISD::CVT_F32_UBYTE3: + return true; + + case AMDGPUISD::RCP: + case AMDGPUISD::RSQ: + case AMDGPUISD::RCP_LEGACY: + case AMDGPUISD::RSQ_LEGACY: + case AMDGPUISD::RSQ_CLAMP: { + if (SNaN) + return true; + + // TODO: Need is known positive check. + return false; + } + case AMDGPUISD::LDEXP: { + if (SNaN) + return true; + return DAG.isKnownNeverNaN(Op.getOperand(0), SNaN, Depth + 1); + } + case AMDGPUISD::DIV_SCALE: + case AMDGPUISD::DIV_FMAS: + case AMDGPUISD::DIV_FIXUP: + case AMDGPUISD::TRIG_PREOP: + // TODO: Refine on operands. + return SNaN; + case AMDGPUISD::SIN_HW: + case AMDGPUISD::COS_HW: { + // TODO: Need check for infinity + return SNaN; + } + case ISD::INTRINSIC_WO_CHAIN: { + unsigned IntrinsicID + = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue(); + // TODO: Handle more intrinsics + switch (IntrinsicID) { + case Intrinsic::amdgcn_cubeid: + return true; + + case Intrinsic::amdgcn_frexp_mant: + return DAG.isKnownNeverNaN(Op.getOperand(1), SNaN, Depth + 1); + default: + return false; + } + } + default: + return false; + } +} diff --git a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h index a4c3b413e10..1939cb9abda 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h +++ b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h @@ -246,6 +246,11 @@ public: const SelectionDAG &DAG, unsigned Depth = 0) const override; + bool isKnownNeverNaNForTargetNode(SDValue Op, + const SelectionDAG &DAG, + bool SNaN = false, + unsigned Depth = 0) const override; + /// Helper function that adds Reg to the LiveIn list of the DAG's /// MachineFunction. /// diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp index 32e1ba30b0f..9f4846f8863 100644 --- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp +++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp @@ -6745,13 +6745,6 @@ SDValue SITargetLowering::performRcpCombine(SDNode *N, return AMDGPUTargetLowering::performRcpCombine(N, DCI); } -static bool isKnownNeverSNan(SelectionDAG &DAG, SDValue Op) { - if (!DAG.getTargetLoweringInfo().hasFloatingPointExceptions()) - return true; - - return DAG.isKnownNeverNaN(Op); -} - static bool isCanonicalized(SelectionDAG &DAG, SDValue Op, const GCNSubtarget *ST, unsigned MaxDepth=5) { // If source is a result of another standard FP operation it is already in @@ -6846,7 +6839,7 @@ SDValue SITargetLowering::performFCanonicalizeCombine( bool IsIEEEMode = Subtarget->enableIEEEBit(DAG.getMachineFunction()); - if ((IsIEEEMode || isKnownNeverSNan(DAG, N0)) && + if ((IsIEEEMode || DAG.isKnownNeverSNaN(N0)) && isCanonicalized(DAG, N0, ST)) return N0; @@ -6991,7 +6984,7 @@ SDValue SITargetLowering::performFPMed3ImmCombine(SelectionDAG &DAG, // then give the other result, which is different from med3 with a NaN // input. SDValue Var = Op0.getOperand(0); - if (!isKnownNeverSNan(DAG, Var)) + if (!DAG.isKnownNeverSNaN(Var)) return SDValue(); return DAG.getNode(AMDGPUISD::FMED3, SL, K0->getValueType(0), |