diff --git a/llvm/include/llvm/CodeGen/SelectionDAG.h b/llvm/include/llvm/CodeGen/SelectionDAG.h --- a/llvm/include/llvm/CodeGen/SelectionDAG.h +++ b/llvm/include/llvm/CodeGen/SelectionDAG.h @@ -1769,6 +1769,31 @@ unsigned ComputeNumSignBits(SDValue Op, const APInt &DemandedElts, unsigned Depth = 0) const; + /// Return true if this function can prove that \p Op is never poison + /// and, if \p PoisonOnly is false, does not have undef bits. + bool isGuaranteedNotToBeUndefOrPoison(SDValue Op, bool PoisonOnly = false, + unsigned Depth = 0) const; + + /// Return true if this function can prove that \p Op is never poison + /// and, if \p PoisonOnly is false, does not have undef bits. The DemandedElts + /// argument limits the check to the requested vector elements. + bool isGuaranteedNotToBeUndefOrPoison(SDValue Op, const APInt &DemandedElts, + bool PoisonOnly = false, + unsigned Depth = 0) const; + + /// Return true if this function can prove that \p Op is never poison. + bool isGuaranteedNotToBePoison(SDValue Op, unsigned Depth = 0) const { + return isGuaranteedNotToBeUndefOrPoison(Op, /*PoisonOnly*/ true, Depth); + } + + /// Return true if this function can prove that \p Op is never poison. The + /// DemandedElts argument limits the check to the requested vector elements. + bool isGuaranteedNotToBePoison(SDValue Op, const APInt &DemandedElts, + unsigned Depth = 0) const { + return isGuaranteedNotToBeUndefOrPoison(Op, DemandedElts, + /*PoisonOnly*/ true, Depth); + } + /// Return true if the specified operand is an ISD::ADD with a ConstantSDNode /// on the right-hand side, or if it is an ISD::OR with a ConstantSDNode that /// is guaranteed to have the same semantics as an ADD. This handles the diff --git a/llvm/include/llvm/CodeGen/TargetLowering.h b/llvm/include/llvm/CodeGen/TargetLowering.h --- a/llvm/include/llvm/CodeGen/TargetLowering.h +++ b/llvm/include/llvm/CodeGen/TargetLowering.h @@ -3491,6 +3491,13 @@ SDValue Op, const APInt &DemandedBits, const APInt &DemandedElts, SelectionDAG &DAG, unsigned Depth) const; + /// Return true if this function can prove that \p Op is never poison + /// and, if \p PoisonOnly is false, does not have undef bits. The DemandedElts + /// argument limits the check to the requested vector elements. + virtual bool isGuaranteedNotToBeUndefOrPoisonForTargetNode( + SDValue Op, const APInt &DemandedElts, const SelectionDAG &DAG, + bool PoisonOnly, unsigned Depth) const; + /// Tries to build a legal vector shuffle using the provided parameters /// or equivalent variations. The Mask argument maybe be modified as the /// function tries different variations. diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp --- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -12820,12 +12820,7 @@ SDValue DAGCombiner::visitFREEZE(SDNode *N) { SDValue N0 = N->getOperand(0); - // (freeze (freeze x)) -> (freeze x) - if (N0.getOpcode() == ISD::FREEZE) - return N0; - - // If the input is a constant, return it. - if (isIntOrFPConstant(N0)) + if (DAG.isGuaranteedNotToBeUndefOrPoison(N0, /*PoisonOnly*/ false)) return N0; return SDValue(); diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -4247,6 +4247,61 @@ return std::max(FirstAnswer, Mask.countLeadingOnes()); } +bool SelectionDAG::isGuaranteedNotToBeUndefOrPoison(SDValue Op, bool PoisonOnly, + unsigned Depth) const { + // Early out for FREEZE. + if (Op.getOpcode() == ISD::FREEZE) + return true; + + // TODO: Assume we don't know anything for now. + EVT VT = Op.getValueType(); + if (VT.isScalableVector()) + return false; + + APInt DemandedElts = VT.isVector() + ? APInt::getAllOnesValue(VT.getVectorNumElements()) + : APInt(1, 1); + return isGuaranteedNotToBeUndefOrPoison(Op, DemandedElts, PoisonOnly, Depth); +} + +bool SelectionDAG::isGuaranteedNotToBeUndefOrPoison(SDValue Op, + const APInt &DemandedElts, + bool PoisonOnly, + unsigned Depth) const { + unsigned Opcode = Op.getOpcode(); + + // Early out for FREEZE. + if (Opcode == ISD::FREEZE) + return true; + + if (Depth >= MaxRecursionDepth) + return false; // Limit search depth. + + if (isIntOrFPConstant(Op)) + return true; + + switch (Opcode) { + case ISD::UNDEF: + return PoisonOnly; + + // TODO: ISD::BUILD_VECTOR handling + + // TODO: Search for noundef attributes from library functions. + + // TODO: Pointers dereferenced by ISD::LOAD/STORE ops are noundef. + + default: + // Allow the target to implement this method for its nodes. + if (Opcode >= ISD::BUILTIN_OP_END || Opcode == ISD::INTRINSIC_WO_CHAIN || + Opcode == ISD::INTRINSIC_W_CHAIN || Opcode == ISD::INTRINSIC_VOID) + return TLI->isGuaranteedNotToBeUndefOrPoisonForTargetNode( + Op, DemandedElts, *this, PoisonOnly, Depth); + break; + } + + return false; +} + bool SelectionDAG::isBaseWithConstantOffset(SDValue Op) const { if ((Op.getOpcode() != ISD::ADD && Op.getOpcode() != ISD::OR) || !isa(Op.getOperand(1))) diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp --- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -3056,6 +3056,19 @@ return nullptr; } +bool TargetLowering::isGuaranteedNotToBeUndefOrPoisonForTargetNode( + SDValue Op, const APInt &DemandedElts, const SelectionDAG &DAG, + bool PoisonOnly, 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 isGuaranteedNotToBeUndefOrPoison if you don't know whether Op" + " is a target node!"); + return false; +} + bool TargetLowering::isKnownNeverNaNForTargetNode(SDValue Op, const SelectionDAG &DAG, bool SNaN,