diff --git a/llvm/include/llvm/CodeGen/SelectionDAG.h b/llvm/include/llvm/CodeGen/SelectionDAG.h index b68d1fc7ea6ca..8afc9c6512b5d 100644 --- a/llvm/include/llvm/CodeGen/SelectionDAG.h +++ b/llvm/include/llvm/CodeGen/SelectionDAG.h @@ -42,6 +42,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/KnownFPClass.h" #include "llvm/Support/RecyclingAllocator.h" +#include "llvm/Support/UndefPoisonKind.h" #include #include #include @@ -1771,9 +1772,10 @@ class SelectionDAG { LLVM_ABI SDValue getFreeze(SDValue V); /// Return a freeze of V if any of the demanded elts may be undef or poison. - /// If \p PoisonOnly is true, then only check for poison elements. - LLVM_ABI SDValue getFreeze(SDValue V, const APInt &DemandedElts, - bool PoisonOnly = false); + /// The Kind argument specifies whether to check for undef, poison, or both. + LLVM_ABI SDValue + getFreeze(SDValue V, const APInt &DemandedElts, + UndefPoisonKind Kind = UndefPoisonKind::UndefOrPoison); /// Return an AssertAlignSDNode. LLVM_ABI SDValue getAssertAlign(const SDLoc &DL, SDValue V, Align A); @@ -2333,22 +2335,23 @@ class SelectionDAG { 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. - LLVM_ABI bool isGuaranteedNotToBeUndefOrPoison(SDValue Op, - bool PoisonOnly = false, - unsigned Depth = 0) const; + /// and, if \p Kind includes undef, does not have undef bits. + LLVM_ABI bool isGuaranteedNotToBeUndefOrPoison( + SDValue Op, UndefPoisonKind Kind = UndefPoisonKind::UndefOrPoison, + 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 + /// and, if \p Kind includes undef, does not have undef bits. The DemandedElts /// argument limits the check to the requested vector elements. - LLVM_ABI bool isGuaranteedNotToBeUndefOrPoison(SDValue Op, - const APInt &DemandedElts, - bool PoisonOnly = false, - unsigned Depth = 0) const; + LLVM_ABI bool isGuaranteedNotToBeUndefOrPoison( + SDValue Op, const APInt &DemandedElts, + UndefPoisonKind Kind = UndefPoisonKind::UndefOrPoison, + 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 isGuaranteedNotToBeUndefOrPoison(Op, UndefPoisonKind::PoisonOnly, + Depth); } /// Return true if this function can prove that \p Op is never poison. The @@ -2356,35 +2359,35 @@ class SelectionDAG { bool isGuaranteedNotToBePoison(SDValue Op, const APInt &DemandedElts, unsigned Depth = 0) const { return isGuaranteedNotToBeUndefOrPoison(Op, DemandedElts, - /*PoisonOnly*/ true, Depth); + UndefPoisonKind::PoisonOnly, Depth); } /// Return true if Op can create undef or poison from non-undef & non-poison - /// operands. The DemandedElts argument limits the check to the requested - /// vector elements. + /// operands based on the types specified in \p Kind. The DemandedElts + /// argument limits the check to the requested vector elements. /// /// \p ConsiderFlags controls whether poison producing flags on the - /// instruction are considered. This can be used to see if the instruction + /// instruction are considered. This can be used to see if the instruction /// could still introduce undef or poison even without poison generating flags - /// which might be on the instruction. (i.e. could the result of - /// Op->dropPoisonGeneratingFlags() still create poison or undef) - LLVM_ABI bool canCreateUndefOrPoison(SDValue Op, const APInt &DemandedElts, - bool PoisonOnly = false, - bool ConsiderFlags = true, - unsigned Depth = 0) const; + /// which might be on the instruction (i.e., could the result of + /// Op->dropPoisonGeneratingFlags() still create poison or undef). + LLVM_ABI bool + canCreateUndefOrPoison(SDValue Op, const APInt &DemandedElts, + UndefPoisonKind Kind = UndefPoisonKind::UndefOrPoison, + bool ConsiderFlags = true, unsigned Depth = 0) const; /// Return true if Op can create undef or poison from non-undef & non-poison - /// operands. + /// operands based on the types specified in \p Kind. /// /// \p ConsiderFlags controls whether poison producing flags on the - /// instruction are considered. This can be used to see if the instruction + /// instruction are considered. This can be used to see if the instruction /// could still introduce undef or poison even without poison generating flags - /// which might be on the instruction. (i.e. could the result of - /// Op->dropPoisonGeneratingFlags() still create poison or undef) - LLVM_ABI bool canCreateUndefOrPoison(SDValue Op, bool PoisonOnly = false, - bool ConsiderFlags = true, - unsigned Depth = 0) const; - + /// which might be on the instruction (i.e., could the result of + /// Op->dropPoisonGeneratingFlags() still create poison or undef). + LLVM_ABI bool + canCreateUndefOrPoison(SDValue Op, + UndefPoisonKind Kind = UndefPoisonKind::UndefOrPoison, + bool ConsiderFlags = true, unsigned Depth = 0) const; /// Return true if the specified operand is an ISD::OR or ISD::XOR node /// that can be treated as an ISD::ADD node. /// or(x,y) == add(x,y) iff haveNoCommonBitsSet(x,y) diff --git a/llvm/include/llvm/CodeGen/TargetLowering.h b/llvm/include/llvm/CodeGen/TargetLowering.h index 9b0bfa111f2d5..88a28da154619 100644 --- a/llvm/include/llvm/CodeGen/TargetLowering.h +++ b/llvm/include/llvm/CodeGen/TargetLowering.h @@ -55,6 +55,7 @@ #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/KnownFPClass.h" +#include "llvm/Support/UndefPoisonKind.h" #include #include #include @@ -4471,15 +4472,14 @@ class LLVM_ABI TargetLowering : public TargetLoweringBase { /// 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; + UndefPoisonKind Kind, unsigned Depth) const; /// Return true if Op can create undef or poison from non-undef & non-poison /// operands. The DemandedElts argument limits the check to the requested /// vector elements. - virtual bool - canCreateUndefOrPoisonForTargetNode(SDValue Op, const APInt &DemandedElts, - const SelectionDAG &DAG, bool PoisonOnly, - bool ConsiderFlags, unsigned Depth) const; + virtual bool canCreateUndefOrPoisonForTargetNode( + SDValue Op, const APInt &DemandedElts, const SelectionDAG &DAG, + UndefPoisonKind Kind, bool ConsiderFlags, 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 diff --git a/llvm/include/llvm/Support/UndefPoisonKind.h b/llvm/include/llvm/Support/UndefPoisonKind.h new file mode 100644 index 0000000000000..ec906f80ed185 --- /dev/null +++ b/llvm/include/llvm/Support/UndefPoisonKind.h @@ -0,0 +1,16 @@ +#ifndef LLVM_SUPPORT_UNDEFPOISONKIND_H +#define LLVM_SUPPORT_UNDEFPOISONKIND_H + +namespace llvm { + +/// Enumeration of the different types of "undefined" values in LLVM. +enum class UndefPoisonKind { + PoisonOnly = (1 << 0), + UndefOnly = (1 << 1), + UndefOrPoison = PoisonOnly | UndefOnly, + LLVM_MARK_AS_BITMASK_ENUM(UndefOrPoison) +}; + +} // end namespace llvm + +#endif // LLVM_SUPPORT_UNDEFPOISONKIND_H \ No newline at end of file diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index 8b82a1d413149..1f2f9fa62269d 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -75,6 +75,7 @@ #include "llvm/Support/KnownBits.h" #include "llvm/Support/KnownFPClass.h" #include "llvm/Support/MathExtras.h" +#include "llvm/Support/UndefPoisonKind.h" #include "llvm/TargetParser/RISCVTargetParser.h" #include #include @@ -7633,12 +7634,6 @@ static bool shiftAmountKnownInRange(const Value *ShiftAmount) { return Safe; } -enum class UndefPoisonKind { - PoisonOnly = (1 << 0), - UndefOnly = (1 << 1), - UndefOrPoison = PoisonOnly | UndefOnly, -}; - static bool includesPoison(UndefPoisonKind Kind) { return (unsigned(Kind) & unsigned(UndefPoisonKind::PoisonOnly)) != 0; } @@ -7796,7 +7791,8 @@ bool llvm::impliesPoison(const Value *ValAssumedPoison, const Value *V) { return ::impliesPoison(ValAssumedPoison, V, /* Depth */ 0); } -static bool programUndefinedIfUndefOrPoison(const Value *V, bool PoisonOnly); +static bool programUndefinedIfUndefOrPoison(const Value *V, + UndefPoisonKind Kind); static bool isGuaranteedNotToBeUndefOrPoison( const Value *V, AssumptionCache *AC, const Instruction *CtxI, @@ -7904,7 +7900,9 @@ static bool isGuaranteedNotToBeUndefOrPoison( I->hasMetadata(LLVMContext::MD_dereferenceable_or_null)) return true; - if (programUndefinedIfUndefOrPoison(V, !includesUndef(Kind))) + if (programUndefinedIfUndefOrPoison(V, includesUndef(Kind) + ? UndefPoisonKind::UndefOrPoison + : UndefPoisonKind::PoisonOnly)) return true; // CxtI may be null or a cloned instruction. @@ -8301,7 +8299,7 @@ bool llvm::mustTriggerUB(const Instruction *I, } static bool programUndefinedIfUndefOrPoison(const Value *V, - bool PoisonOnly) { + UndefPoisonKind Kind) { // We currently only look for uses of values within the same basic // block, as that makes it easier to guarantee that the uses will be // executed given that Inst is executed. @@ -8329,7 +8327,7 @@ static bool programUndefinedIfUndefOrPoison(const Value *V, unsigned ScanLimit = 32; BasicBlock::const_iterator End = BB->end(); - if (!PoisonOnly) { + if (includesUndef(Kind)) { // Since undef does not propagate eagerly, be conservative & just check // whether a value is directly passed to an instruction that must take // well-defined operands. @@ -8393,13 +8391,13 @@ static bool programUndefinedIfUndefOrPoison(const Value *V, } return false; } - bool llvm::programUndefinedIfUndefOrPoison(const Instruction *Inst) { - return ::programUndefinedIfUndefOrPoison(Inst, false); + return ::programUndefinedIfUndefOrPoison(Inst, + UndefPoisonKind::UndefOrPoison); } bool llvm::programUndefinedIfPoison(const Instruction *Inst) { - return ::programUndefinedIfUndefOrPoison(Inst, true); + return ::programUndefinedIfUndefOrPoison(Inst, UndefPoisonKind::PoisonOnly); } static bool isKnownNonNaN(const Value *V, FastMathFlags FMF) { diff --git a/llvm/lib/CodeGen/GlobalISel/Utils.cpp b/llvm/lib/CodeGen/GlobalISel/Utils.cpp index 37af0716df9ec..3ec55be7aadbb 100644 --- a/llvm/lib/CodeGen/GlobalISel/Utils.cpp +++ b/llvm/lib/CodeGen/GlobalISel/Utils.cpp @@ -33,6 +33,7 @@ #include "llvm/CodeGen/TargetPassConfig.h" #include "llvm/CodeGen/TargetRegisterInfo.h" #include "llvm/IR/Constants.h" +#include "llvm/Support/UndefPoisonKind.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Transforms/Utils/SizeOpts.h" #include @@ -1787,14 +1788,6 @@ static bool shiftAmountKnownInRange(Register ShiftAmount, return true; } -namespace { -enum class UndefPoisonKind { - PoisonOnly = (1 << 0), - UndefOnly = (1 << 1), - UndefOrPoison = PoisonOnly | UndefOnly, -}; -} - static bool includesPoison(UndefPoisonKind Kind) { return (unsigned(Kind) & unsigned(UndefPoisonKind::PoisonOnly)) != 0; } diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp index 75539da583342..a1a5ffa84b5f6 100644 --- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -65,6 +65,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/KnownBits.h" #include "llvm/Support/MathExtras.h" +#include "llvm/Support/UndefPoisonKind.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" @@ -17870,7 +17871,7 @@ SDValue DAGCombiner::visitBUILD_PAIR(SDNode *N) { SDValue DAGCombiner::visitFREEZE(SDNode *N) { SDValue N0 = N->getOperand(0); - if (DAG.isGuaranteedNotToBeUndefOrPoison(N0, /*PoisonOnly*/ false)) + if (DAG.isGuaranteedNotToBeUndefOrPoison(N0, UndefPoisonKind::UndefOrPoison)) return N0; // If we have frozen and unfrozen users of N0, update so everything uses N. @@ -17901,7 +17902,7 @@ SDValue DAGCombiner::visitFREEZE(SDNode *N) { // guaranteed-non-poison operands (or is a BUILD_VECTOR or similar) then push // the freeze through to the operands that are not guaranteed non-poison. // NOTE: we will strip poison-generating flags, so ignore them here. - if (DAG.canCreateUndefOrPoison(N0, /*PoisonOnly*/ false, + if (DAG.canCreateUndefOrPoison(N0, UndefPoisonKind::UndefOrPoison, /*ConsiderFlags*/ false) || N0->getNumValues() != 1 || !N0->hasOneUse()) return SDValue(); @@ -17942,7 +17943,8 @@ SDValue DAGCombiner::visitFREEZE(SDNode *N) { SmallSet MaybePoisonOperands; SmallVector MaybePoisonOperandNumbers; for (auto [OpNo, Op] : enumerate(N0->ops())) { - if (DAG.isGuaranteedNotToBeUndefOrPoison(Op, /*PoisonOnly=*/false)) + if (DAG.isGuaranteedNotToBeUndefOrPoison(Op, + UndefPoisonKind::UndefOrPoison)) continue; bool HadMaybePoisonOperands = !MaybePoisonOperands.empty(); bool IsNewMaybePoisonOperand = MaybePoisonOperands.insert(Op).second; @@ -24827,8 +24829,8 @@ SDValue DAGCombiner::visitINSERT_VECTOR_ELT(SDNode *N) { // Make sure to freeze the source vector in case any of the elements // overwritten by the insert may be poison. Otherwise those elements // could end up being poison instead of 0/-1 after the AND/OR. - CurVec = - DAG.getFreeze(CurVec, InsertedEltMask, /*PoisonOnly=*/true); + CurVec = DAG.getFreeze(CurVec, InsertedEltMask, + UndefPoisonKind::PoisonOnly); return DAG.getNode(MaskOpcode, DL, VT, CurVec, DAG.getBuildVector(VT, DL, Mask)); }; diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp index f91f0bb63cebc..7c072db9db9ef 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -2570,8 +2570,8 @@ SDValue SelectionDAG::getFreeze(SDValue V) { } SDValue SelectionDAG::getFreeze(SDValue V, const APInt &DemandedElts, - bool PoisonOnly) { - if (isGuaranteedNotToBeUndefOrPoison(V, DemandedElts, PoisonOnly)) + UndefPoisonKind Kind) { + if (isGuaranteedNotToBeUndefOrPoison(V, DemandedElts, Kind)) return V; return getFreeze(V); } @@ -3669,7 +3669,8 @@ KnownBits SelectionDAG::computeKnownBits(SDValue Op, const APInt &DemandedElts, // TODO: SelfMultiply can be poison, but not undef. if (SelfMultiply) SelfMultiply &= isGuaranteedNotToBeUndefOrPoison( - Op.getOperand(0), DemandedElts, false, Depth + 1); + Op.getOperand(0), DemandedElts, UndefPoisonKind::UndefOrPoison, + Depth + 1); Known = KnownBits::mul(Known, Known2, SelfMultiply); // If the multiplication is known not to overflow, the product of a number @@ -4158,7 +4159,8 @@ KnownBits SelectionDAG::computeKnownBits(SDValue Op, const APInt &DemandedElts, Known2 = computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1); bool SelfAdd = Op.getOperand(0) == Op.getOperand(1) && isGuaranteedNotToBeUndefOrPoison( - Op.getOperand(0), DemandedElts, false, Depth + 1); + Op.getOperand(0), DemandedElts, + UndefPoisonKind::UndefOrPoison, Depth + 1); Known = KnownBits::add(Known, Known2, Flags.hasNoSignedWrap(), Flags.hasNoUnsignedWrap(), SelfAdd); break; @@ -4935,7 +4937,8 @@ unsigned SelectionDAG::ComputeNumSignBits(SDValue Op, const APInt &DemandedElts, return VTBits-Tmp; case ISD::FREEZE: if (isGuaranteedNotToBeUndefOrPoison(Op.getOperand(0), DemandedElts, - /*PoisonOnly=*/false)) + UndefPoisonKind::UndefOrPoison, + Depth + 1)) return ComputeNumSignBits(Op.getOperand(0), DemandedElts, Depth + 1); break; case ISD::MERGE_VALUES: @@ -5609,19 +5612,23 @@ unsigned SelectionDAG::ComputeMaxSignificantBits(SDValue Op, return Op.getScalarValueSizeInBits() - SignBits + 1; } -bool SelectionDAG::isGuaranteedNotToBeUndefOrPoison(SDValue Op, bool PoisonOnly, +bool SelectionDAG::isGuaranteedNotToBeUndefOrPoison(SDValue Op, + UndefPoisonKind Kind, unsigned Depth) const { // Early out for FREEZE. if (Op.getOpcode() == ISD::FREEZE) return true; - APInt DemandedElts = getDemandAllEltsMask(Op); - return isGuaranteedNotToBeUndefOrPoison(Op, DemandedElts, PoisonOnly, Depth); + EVT VT = Op.getValueType(); + APInt DemandedElts = VT.isFixedLengthVector() + ? APInt::getAllOnes(VT.getVectorNumElements()) + : APInt(1, 1); + return isGuaranteedNotToBeUndefOrPoison(Op, DemandedElts, Kind, Depth); } bool SelectionDAG::isGuaranteedNotToBeUndefOrPoison(SDValue Op, const APInt &DemandedElts, - bool PoisonOnly, + UndefPoisonKind Kind, unsigned Depth) const { unsigned Opcode = Op.getOpcode(); @@ -5635,6 +5642,9 @@ bool SelectionDAG::isGuaranteedNotToBeUndefOrPoison(SDValue Op, if (isIntOrFPConstant(Op)) return true; + bool IncludeUndef = + ((unsigned)Kind & (unsigned)UndefPoisonKind::UndefOnly) != 0; + switch (Opcode) { case ISD::CONDCODE: case ISD::VALUETYPE: @@ -5647,16 +5657,15 @@ bool SelectionDAG::isGuaranteedNotToBeUndefOrPoison(SDValue Op, return false; case ISD::UNDEF: - return PoisonOnly; + // If we are checking for Undef, then an UNDEF node is not guaranteed. + // If we are only checking for Poison, then an UNDEF node is guaranteed. + return !IncludeUndef; case ISD::BUILD_VECTOR: - // NOTE: BUILD_VECTOR has implicit truncation of wider scalar elements - - // this shouldn't affect the result. for (unsigned i = 0, e = Op.getNumOperands(); i < e; ++i) { if (!DemandedElts[i]) continue; - if (!isGuaranteedNotToBeUndefOrPoison(Op.getOperand(i), PoisonOnly, - Depth + 1)) + if (!isGuaranteedNotToBeUndefOrPoison(Op.getOperand(i), Kind, Depth + 1)) return false; } return true; @@ -5668,7 +5677,7 @@ bool SelectionDAG::isGuaranteedNotToBeUndefOrPoison(SDValue Op, uint64_t Idx = Op.getConstantOperandVal(1); unsigned NumSrcElts = Src.getValueType().getVectorNumElements(); APInt DemandedSrcElts = DemandedElts.zext(NumSrcElts).shl(Idx); - return isGuaranteedNotToBeUndefOrPoison(Src, DemandedSrcElts, PoisonOnly, + return isGuaranteedNotToBeUndefOrPoison(Src, DemandedSrcElts, Kind, Depth + 1); } @@ -5684,10 +5693,10 @@ bool SelectionDAG::isGuaranteedNotToBeUndefOrPoison(SDValue Op, DemandedSrcElts.clearBits(Idx, Idx + NumSubElts); if (!!DemandedSubElts && !isGuaranteedNotToBeUndefOrPoison( - Sub, DemandedSubElts, PoisonOnly, Depth + 1)) + Sub, DemandedSubElts, Kind, Depth + 1)) return false; if (!!DemandedSrcElts && !isGuaranteedNotToBeUndefOrPoison( - Src, DemandedSrcElts, PoisonOnly, Depth + 1)) + Src, DemandedSrcElts, Kind, Depth + 1)) return false; return true; } @@ -5700,7 +5709,7 @@ bool SelectionDAG::isGuaranteedNotToBeUndefOrPoison(SDValue Op, IndexC->getAPIntValue().ult(SrcVT.getVectorNumElements())) { APInt DemandedSrcElts = APInt::getOneBitSet(SrcVT.getVectorNumElements(), IndexC->getZExtValue()); - return isGuaranteedNotToBeUndefOrPoison(Src, DemandedSrcElts, PoisonOnly, + return isGuaranteedNotToBeUndefOrPoison(Src, DemandedSrcElts, Kind, Depth + 1); } break; @@ -5715,14 +5724,14 @@ bool SelectionDAG::isGuaranteedNotToBeUndefOrPoison(SDValue Op, if (IndexC && VT.isFixedLengthVector() && IndexC->getAPIntValue().ult(VT.getVectorNumElements())) { if (DemandedElts[IndexC->getZExtValue()] && - !isGuaranteedNotToBeUndefOrPoison(InVal, PoisonOnly, Depth + 1)) + !isGuaranteedNotToBeUndefOrPoison(InVal, Kind, Depth + 1)) return false; APInt InVecDemandedElts = DemandedElts; InVecDemandedElts.clearBit(IndexC->getZExtValue()); if (!!InVecDemandedElts && !isGuaranteedNotToBeUndefOrPoison( peekThroughInsertVectorElt(InVec, InVecDemandedElts), - InVecDemandedElts, PoisonOnly, Depth + 1)) + InVecDemandedElts, Kind, Depth + 1)) return false; return true; } @@ -5731,17 +5740,16 @@ bool SelectionDAG::isGuaranteedNotToBeUndefOrPoison(SDValue Op, case ISD::SCALAR_TO_VECTOR: // Check upper (known undef) elements. - if (DemandedElts.ugt(1) && !PoisonOnly) + if (DemandedElts.ugt(1) && IncludeUndef) return false; // Check element zero. - if (DemandedElts[0] && !isGuaranteedNotToBeUndefOrPoison( - Op.getOperand(0), PoisonOnly, Depth + 1)) + if (DemandedElts[0] && + !isGuaranteedNotToBeUndefOrPoison(Op.getOperand(0), Kind, Depth + 1)) return false; return true; case ISD::SPLAT_VECTOR: - return isGuaranteedNotToBeUndefOrPoison(Op.getOperand(0), PoisonOnly, - Depth + 1); + return isGuaranteedNotToBeUndefOrPoison(Op.getOperand(0), Kind, Depth + 1); case ISD::VECTOR_SHUFFLE: { APInt DemandedLHS, DemandedRHS; @@ -5751,12 +5759,12 @@ bool SelectionDAG::isGuaranteedNotToBeUndefOrPoison(SDValue Op, /*AllowUndefElts=*/false)) return false; if (!DemandedLHS.isZero() && - !isGuaranteedNotToBeUndefOrPoison(Op.getOperand(0), DemandedLHS, - PoisonOnly, Depth + 1)) + !isGuaranteedNotToBeUndefOrPoison(Op.getOperand(0), DemandedLHS, Kind, + Depth + 1)) return false; if (!DemandedRHS.isZero() && - !isGuaranteedNotToBeUndefOrPoison(Op.getOperand(1), DemandedRHS, - PoisonOnly, Depth + 1)) + !isGuaranteedNotToBeUndefOrPoison(Op.getOperand(1), DemandedRHS, Kind, + Depth + 1)) return false; return true; } @@ -5764,12 +5772,10 @@ bool SelectionDAG::isGuaranteedNotToBeUndefOrPoison(SDValue Op, case ISD::SHL: case ISD::SRL: case ISD::SRA: - // Shift amount operand is checked by canCreateUndefOrPoison. So it is - // enough to check operand 0 if Op can't create undef/poison. - return !canCreateUndefOrPoison(Op, DemandedElts, PoisonOnly, + return !canCreateUndefOrPoison(Op, DemandedElts, Kind, /*ConsiderFlags*/ true, Depth) && isGuaranteedNotToBeUndefOrPoison(Op.getOperand(0), DemandedElts, - PoisonOnly, Depth + 1); + Kind, Depth + 1); case ISD::BSWAP: case ISD::CTPOP: @@ -5795,55 +5801,50 @@ bool SelectionDAG::isGuaranteedNotToBeUndefOrPoison(SDValue Op, case ISD::ANY_EXTEND: case ISD::TRUNCATE: case ISD::VSELECT: { - // If Op can't create undef/poison and none of its operands are undef/poison - // then Op is never undef/poison. A difference from the more common check - // below, outside the switch, is that we handle elementwise operations for - // which the DemandedElts mask is valid for all operands here. - return !canCreateUndefOrPoison(Op, DemandedElts, PoisonOnly, + return !canCreateUndefOrPoison(Op, DemandedElts, Kind, /*ConsiderFlags*/ true, Depth) && all_of(Op->ops(), [&](SDValue V) { - return isGuaranteedNotToBeUndefOrPoison(V, DemandedElts, - PoisonOnly, Depth + 1); + return isGuaranteedNotToBeUndefOrPoison(V, DemandedElts, Kind, + Depth + 1); }); } - - // 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); + Op, DemandedElts, *this, Kind, Depth); break; } - // If Op can't create undef/poison and none of its operands are undef/poison - // then Op is never undef/poison. - // NOTE: TargetNodes can handle this in themselves in - // isGuaranteedNotToBeUndefOrPoisonForTargetNode or let - // TargetLowering::isGuaranteedNotToBeUndefOrPoisonForTargetNode handle it. - return !canCreateUndefOrPoison(Op, PoisonOnly, /*ConsiderFlags*/ true, - Depth) && + return !canCreateUndefOrPoison(Op, Kind, /*ConsiderFlags*/ true, Depth) && all_of(Op->ops(), [&](SDValue V) { - return isGuaranteedNotToBeUndefOrPoison(V, PoisonOnly, Depth + 1); + return isGuaranteedNotToBeUndefOrPoison(V, Kind, Depth + 1); }); } -bool SelectionDAG::canCreateUndefOrPoison(SDValue Op, bool PoisonOnly, +bool SelectionDAG::canCreateUndefOrPoison(SDValue Op, UndefPoisonKind Kind, bool ConsiderFlags, unsigned Depth) const { - APInt DemandedElts = getDemandAllEltsMask(Op); - return canCreateUndefOrPoison(Op, DemandedElts, PoisonOnly, ConsiderFlags, - Depth); + EVT VT = Op.getValueType(); + APInt DemandedElts = VT.isFixedLengthVector() + ? APInt::getAllOnes(VT.getVectorNumElements()) + : APInt(1, 1); + return canCreateUndefOrPoison(Op, DemandedElts, Kind, ConsiderFlags, Depth); } bool SelectionDAG::canCreateUndefOrPoison(SDValue Op, const APInt &DemandedElts, - bool PoisonOnly, bool ConsiderFlags, + UndefPoisonKind Kind, + bool ConsiderFlags, unsigned Depth) const { - if (ConsiderFlags && Op->hasPoisonGeneratingFlags()) + bool IncludeUndef = + ((unsigned)Kind & (unsigned)UndefPoisonKind::UndefOnly) != 0; + bool IncludePoison = + ((unsigned)Kind & (unsigned)UndefPoisonKind::PoisonOnly) != 0; + + // If the instruction has poison-generating flags, it can create poison. + // We only return true here if the caller actually cares about poison. + if (ConsiderFlags && IncludePoison && Op->hasPoisonGeneratingFlags()) return true; unsigned Opcode = Op.getOpcode(); @@ -5853,7 +5854,7 @@ bool SelectionDAG::canCreateUndefOrPoison(SDValue Op, const APInt &DemandedElts, case ISD::AssertAlign: case ISD::AssertNoFPClass: // Assertion nodes can create poison if the assertion fails. - return true; + return IncludePoison; case ISD::FREEZE: case ISD::CONCAT_VECTORS: @@ -5900,13 +5901,7 @@ bool SelectionDAG::canCreateUndefOrPoison(SDValue Op, const APInt &DemandedElts, case ISD::BUILD_PAIR: case ISD::SPLAT_VECTOR: case ISD::FABS: - return false; - case ISD::ABS: - // ISD::ABS defines abs(INT_MIN) -> INT_MIN and never generates poison. - // Different to Intrinsic::abs. - return false; - case ISD::ADDC: case ISD::SUBC: case ISD::ADDE: @@ -5921,22 +5916,18 @@ bool SelectionDAG::canCreateUndefOrPoison(SDValue Op, const APInt &DemandedElts, case ISD::UMULO: case ISD::UADDO_CARRY: case ISD::USUBO_CARRY: - // No poison on result or overflow flags. + case ISD::VECTOR_COMPRESS: return false; case ISD::SELECT_CC: case ISD::SETCC: { - // Integer setcc cannot create undef or poison. if (Op.getOperand(0).getValueType().isInteger()) return false; - // FP compares are more complicated. They can create poison for nan/infinity - // based on options and flags. The options and flags also cause special - // nonan condition codes to be used. Those condition codes may be preserved - // even if the nonan flag is dropped somewhere. + // FP compares can create poison based on flags/nonan conditions. unsigned CCOp = Opcode == ISD::SETCC ? 2 : 4; ISD::CondCode CCCode = cast(Op.getOperand(CCOp))->get(); - return (unsigned)CCCode & 0x10U; + return IncludePoison && ((unsigned)CCCode & 0x10U); } case ISD::OR: @@ -5962,37 +5953,39 @@ bool SelectionDAG::canCreateUndefOrPoison(SDValue Op, const APInt &DemandedElts, case ISD::TRUNCATE_SSAT_S: case ISD::TRUNCATE_SSAT_U: case ISD::TRUNCATE_USAT_U: - // No poison except from flags (which is handled above) return false; case ISD::SHL: case ISD::SRL: case ISD::SRA: - // If the max shift amount isn't in range, then the shift can - // create poison. - return !getValidMaximumShiftAmount(Op, DemandedElts, Depth + 1); + // Shift overflows create poison. + return IncludePoison && + !getValidMaximumShiftAmount(Op, DemandedElts, Depth + 1); case ISD::CTTZ_ZERO_UNDEF: case ISD::CTLZ_ZERO_UNDEF: - // If the amount is zero then the result will be poison. - // TODO: Add isKnownNeverZero DemandedElts handling. - return !isKnownNeverZero(Op.getOperand(0), Depth + 1); + // Zero input creates poison for these opcodes. + return IncludePoison && !isKnownNeverZero(Op.getOperand(0), Depth + 1); case ISD::SCALAR_TO_VECTOR: - // Check if we demand any upper (undef) elements. - return !PoisonOnly && DemandedElts.ugt(1); + // Upper elements of SCALAR_TO_VECTOR are Undef. + return IncludeUndef && DemandedElts.ugt(1); case ISD::INSERT_VECTOR_ELT: case ISD::EXTRACT_VECTOR_ELT: { - // Ensure that the element index is in bounds. + // Out of bounds indices create poison. EVT VecVT = Op.getOperand(0).getValueType(); SDValue Idx = Op.getOperand(Opcode == ISD::INSERT_VECTOR_ELT ? 2 : 1); KnownBits KnownIdx = computeKnownBits(Idx, Depth + 1); - return KnownIdx.getMaxValue().uge(VecVT.getVectorMinNumElements()); + return IncludePoison && + KnownIdx.getMaxValue().uge(VecVT.getVectorMinNumElements()); } case ISD::VECTOR_SHUFFLE: { - // Check for any demanded shuffle element that is undef. + // If a demanded element points to a -1 (Undef) mask index, it creates + // Undef. + if (!IncludeUndef) + return false; auto *SVN = cast(Op); for (auto [Idx, Elt] : enumerate(SVN->getMask())) if (Elt < 0 && DemandedElts[Idx]) @@ -6000,19 +5993,14 @@ bool SelectionDAG::canCreateUndefOrPoison(SDValue Op, const APInt &DemandedElts, return false; } - case ISD::VECTOR_COMPRESS: - return false; - 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->canCreateUndefOrPoisonForTargetNode( - Op, DemandedElts, *this, PoisonOnly, ConsiderFlags, Depth); + Op, DemandedElts, *this, Kind, ConsiderFlags, Depth); break; } - // Be conservative and return true. return true; } @@ -6985,7 +6973,7 @@ SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, EVT VT, break; case ISD::FREEZE: assert(VT == N1.getValueType() && "Unexpected VT!"); - if (isGuaranteedNotToBeUndefOrPoison(N1, /*PoisonOnly=*/false)) + if (isGuaranteedNotToBeUndefOrPoison(N1, UndefPoisonKind::UndefOrPoison)) return N1; break; case ISD::TokenFactor: diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp index 6aaf1bed7aae8..829bb1ca53b59 100644 --- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -3374,9 +3374,8 @@ bool TargetLowering::SimplifyDemandedVectorElts( } case ISD::FREEZE: { SDValue N0 = Op.getOperand(0); - if (TLO.DAG.isGuaranteedNotToBeUndefOrPoison(N0, DemandedElts, - /*PoisonOnly=*/false, - Depth + 1)) + if (TLO.DAG.isGuaranteedNotToBeUndefOrPoison( + N0, DemandedElts, UndefPoisonKind::UndefOrPoison, Depth + 1)) return TLO.CombineTo(Op, N0); // TODO: Replace this with the general fold from DAGCombiner::visitFREEZE @@ -4033,7 +4032,7 @@ const Constant *TargetLowering::getTargetConstantFromLoad(LoadSDNode*) const { bool TargetLowering::isGuaranteedNotToBeUndefOrPoisonForTargetNode( SDValue Op, const APInt &DemandedElts, const SelectionDAG &DAG, - bool PoisonOnly, unsigned Depth) const { + UndefPoisonKind Kind, unsigned Depth) const { assert( (Op.getOpcode() >= ISD::BUILTIN_OP_END || Op.getOpcode() == ISD::INTRINSIC_WO_CHAIN || @@ -4044,17 +4043,16 @@ bool TargetLowering::isGuaranteedNotToBeUndefOrPoisonForTargetNode( // If Op can't create undef/poison and none of its operands are undef/poison // then Op is never undef/poison. - return !canCreateUndefOrPoisonForTargetNode(Op, DemandedElts, DAG, PoisonOnly, + return !canCreateUndefOrPoisonForTargetNode(Op, DemandedElts, DAG, Kind, /*ConsiderFlags*/ true, Depth) && all_of(Op->ops(), [&](SDValue V) { - return DAG.isGuaranteedNotToBeUndefOrPoison(V, PoisonOnly, - Depth + 1); + return DAG.isGuaranteedNotToBeUndefOrPoison(V, Kind, Depth + 1); }); } bool TargetLowering::canCreateUndefOrPoisonForTargetNode( SDValue Op, const APInt &DemandedElts, const SelectionDAG &DAG, - bool PoisonOnly, bool ConsiderFlags, unsigned Depth) const { + UndefPoisonKind Kind, bool ConsiderFlags, unsigned Depth) const { assert((Op.getOpcode() >= ISD::BUILTIN_OP_END || Op.getOpcode() == ISD::INTRINSIC_WO_CHAIN || Op.getOpcode() == ISD::INTRINSIC_W_CHAIN || diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp index f5082b779d1db..f1ffda6078837 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -33310,7 +33310,7 @@ bool AArch64TargetLowering::SimplifyDemandedBitsForTargetNode( bool AArch64TargetLowering::canCreateUndefOrPoisonForTargetNode( SDValue Op, const APInt &DemandedElts, const SelectionDAG &DAG, - bool PoisonOnly, bool ConsiderFlags, unsigned Depth) const { + UndefPoisonKind Kind, bool ConsiderFlags, unsigned Depth) const { // TODO: Add more target nodes. switch (Op.getOpcode()) { @@ -33326,7 +33326,7 @@ bool AArch64TargetLowering::canCreateUndefOrPoisonForTargetNode( return false; } return TargetLowering::canCreateUndefOrPoisonForTargetNode( - Op, DemandedElts, DAG, PoisonOnly, ConsiderFlags, Depth); + Op, DemandedElts, DAG, Kind, ConsiderFlags, Depth); } bool AArch64TargetLowering::isTargetCanonicalConstantNode(SDValue Op) const { diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.h b/llvm/lib/Target/AArch64/AArch64ISelLowering.h index 80d49bb2ed318..2e66b5ad896ef 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.h +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.h @@ -906,11 +906,9 @@ class AArch64TargetLowering : public TargetLowering { TargetLoweringOpt &TLO, unsigned Depth) const override; - bool canCreateUndefOrPoisonForTargetNode(SDValue Op, - const APInt &DemandedElts, - const SelectionDAG &DAG, - bool PoisonOnly, bool ConsiderFlags, - unsigned Depth) const override; + bool canCreateUndefOrPoisonForTargetNode( + SDValue Op, const APInt &DemandedElts, const SelectionDAG &DAG, + UndefPoisonKind Kind, bool ConsiderFlags, unsigned Depth) const override; bool isTargetCanonicalConstantNode(SDValue Op) const override; diff --git a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp index e05213b2aaf93..ee41e5bf73ae2 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp @@ -6070,7 +6070,8 @@ void AMDGPUTargetLowering::computeKnownBitsForTargetNode( bool SelfMultiply = Op.getOperand(0) == Op.getOperand(1); if (SelfMultiply) SelfMultiply &= DAG.isGuaranteedNotToBeUndefOrPoison( - Op.getOperand(0), DemandedElts, false, Depth + 1); + Op.getOperand(0), DemandedElts, UndefPoisonKind::UndefOrPoison, + Depth + 1); Known = KnownBits::mul(LHSKnown, RHSKnown, SelfMultiply); break; @@ -6259,7 +6260,7 @@ unsigned AMDGPUTargetLowering::computeNumSignBitsForTargetInstr( bool AMDGPUTargetLowering::canCreateUndefOrPoisonForTargetNode( SDValue Op, const APInt &DemandedElts, const SelectionDAG &DAG, - bool PoisonOnly, bool ConsiderFlags, unsigned Depth) const { + UndefPoisonKind Kind, bool ConsiderFlags, unsigned Depth) const { unsigned Opcode = Op.getOpcode(); switch (Opcode) { case AMDGPUISD::BFE_I32: @@ -6267,7 +6268,7 @@ bool AMDGPUTargetLowering::canCreateUndefOrPoisonForTargetNode( return false; } return TargetLowering::canCreateUndefOrPoisonForTargetNode( - Op, DemandedElts, DAG, PoisonOnly, ConsiderFlags, Depth); + Op, DemandedElts, DAG, Kind, ConsiderFlags, Depth); } bool AMDGPUTargetLowering::isKnownNeverNaNForTargetNode( diff --git a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h index 8085b64567c59..fc61fe033de0e 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h +++ b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h @@ -342,11 +342,9 @@ class AMDGPUTargetLowering : public TargetLowering { const MachineRegisterInfo &MRI, unsigned Depth = 0) const override; - bool canCreateUndefOrPoisonForTargetNode(SDValue Op, - const APInt &DemandedElts, - const SelectionDAG &DAG, - bool PoisonOnly, bool ConsiderFlags, - unsigned Depth) const override; + bool canCreateUndefOrPoisonForTargetNode( + SDValue Op, const APInt &DemandedElts, const SelectionDAG &DAG, + UndefPoisonKind Kind, bool ConsiderFlags, unsigned Depth) const override; bool isKnownNeverNaNForTargetNode(SDValue Op, const APInt &DemandedElts, const SelectionDAG &DAG, bool SNaN = false, diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp index cbff40f697b9b..ff8df9b33b3cc 100644 --- a/llvm/lib/Target/ARM/ARMISelLowering.cpp +++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp @@ -21540,7 +21540,7 @@ bool ARMTargetLowering::canCombineStoreAndExtract(Type *VectorTy, Value *Idx, bool ARMTargetLowering::canCreateUndefOrPoisonForTargetNode( SDValue Op, const APInt &DemandedElts, const SelectionDAG &DAG, - bool PoisonOnly, bool ConsiderFlags, unsigned Depth) const { + UndefPoisonKind Kind, bool ConsiderFlags, unsigned Depth) const { unsigned Opcode = Op.getOpcode(); switch (Opcode) { case ARMISD::VORRIMM: @@ -21548,7 +21548,7 @@ bool ARMTargetLowering::canCreateUndefOrPoisonForTargetNode( return false; } return TargetLowering::canCreateUndefOrPoisonForTargetNode( - Op, DemandedElts, DAG, PoisonOnly, ConsiderFlags, Depth); + Op, DemandedElts, DAG, Kind, ConsiderFlags, Depth); } bool ARMTargetLowering::isCheapToSpeculateCttz(Type *Ty) const { diff --git a/llvm/lib/Target/ARM/ARMISelLowering.h b/llvm/lib/Target/ARM/ARMISelLowering.h index 491beb5434555..10f5442d7429b 100644 --- a/llvm/lib/Target/ARM/ARMISelLowering.h +++ b/llvm/lib/Target/ARM/ARMISelLowering.h @@ -402,9 +402,12 @@ class VectorType; bool canCombineStoreAndExtract(Type *VectorTy, Value *Idx, unsigned &Cost) const override; - bool canCreateUndefOrPoisonForTargetNode( - SDValue Op, const APInt &DemandedElts, const SelectionDAG &DAG, - bool PoisonOnly, bool ConsiderFlags, unsigned Depth) const override; + bool canCreateUndefOrPoisonForTargetNode(SDValue Op, + const APInt &DemandedElts, + const SelectionDAG &DAG, + UndefPoisonKind Kind, + bool ConsiderFlags, + unsigned Depth) const override; bool canMergeStoresTo(unsigned AddressSpace, EVT MemVT, const MachineFunction &MF) const override { diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp index 94361f0657fed..c3fe9e65bd211 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -22974,7 +22974,7 @@ bool RISCVTargetLowering::SimplifyDemandedBitsForTargetNode( bool RISCVTargetLowering::canCreateUndefOrPoisonForTargetNode( SDValue Op, const APInt &DemandedElts, const SelectionDAG &DAG, - bool PoisonOnly, bool ConsiderFlags, unsigned Depth) const { + UndefPoisonKind Kind, bool ConsiderFlags, unsigned Depth) const { // TODO: Add more target nodes. switch (Op.getOpcode()) { @@ -22995,7 +22995,7 @@ bool RISCVTargetLowering::canCreateUndefOrPoisonForTargetNode( return false; } return TargetLowering::canCreateUndefOrPoisonForTargetNode( - Op, DemandedElts, DAG, PoisonOnly, ConsiderFlags, Depth); + Op, DemandedElts, DAG, Kind, ConsiderFlags, Depth); } const Constant * diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.h b/llvm/lib/Target/RISCV/RISCVISelLowering.h index 1be58c56d56d7..54802cf62a13e 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.h +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.h @@ -157,11 +157,9 @@ class RISCVTargetLowering : public TargetLowering { TargetLoweringOpt &TLO, unsigned Depth) const override; - bool canCreateUndefOrPoisonForTargetNode(SDValue Op, - const APInt &DemandedElts, - const SelectionDAG &DAG, - bool PoisonOnly, bool ConsiderFlags, - unsigned Depth) const override; + bool canCreateUndefOrPoisonForTargetNode( + SDValue Op, const APInt &DemandedElts, const SelectionDAG &DAG, + UndefPoisonKind Kind, bool ConsiderFlags, unsigned Depth) const override; const Constant *getTargetConstantFromLoad(LoadSDNode *LD) const override; diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp index bd9a172f9d9d7..e450b27798a57 100644 --- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp +++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp @@ -9671,10 +9671,9 @@ SystemZTargetLowering::ComputeNumSignBitsForTargetNode( return 1; } -bool SystemZTargetLowering:: -isGuaranteedNotToBeUndefOrPoisonForTargetNode(SDValue Op, - const APInt &DemandedElts, const SelectionDAG &DAG, - bool PoisonOnly, unsigned Depth) const { +bool SystemZTargetLowering::isGuaranteedNotToBeUndefOrPoisonForTargetNode( + SDValue Op, const APInt &DemandedElts, const SelectionDAG &DAG, + UndefPoisonKind Kind, unsigned Depth) const { switch (Op->getOpcode()) { case SystemZISD::PCREL_WRAPPER: case SystemZISD::PCREL_OFFSET: diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.h b/llvm/lib/Target/SystemZ/SystemZISelLowering.h index bb3eeba6446d2..65197bbf0ee1d 100644 --- a/llvm/lib/Target/SystemZ/SystemZISelLowering.h +++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.h @@ -294,7 +294,7 @@ class SystemZTargetLowering : public TargetLowering { bool isGuaranteedNotToBeUndefOrPoisonForTargetNode( SDValue Op, const APInt &DemandedElts, const SelectionDAG &DAG, - bool PoisonOnly, unsigned Depth) const override; + UndefPoisonKind Kind, unsigned Depth) const override; ISD::NodeType getExtendForAtomicOps() const override { return ISD::ANY_EXTEND; diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp index 29daeb5c23cc8..5dfe1400f1543 100644 --- a/llvm/lib/Target/X86/X86ISelLowering.cpp +++ b/llvm/lib/Target/X86/X86ISelLowering.cpp @@ -45982,7 +45982,7 @@ SDValue X86TargetLowering::SimplifyMultipleUseDemandedBitsForTargetNode( bool X86TargetLowering::isGuaranteedNotToBeUndefOrPoisonForTargetNode( SDValue Op, const APInt &DemandedElts, const SelectionDAG &DAG, - bool PoisonOnly, unsigned Depth) const { + UndefPoisonKind Kind, unsigned Depth) const { unsigned NumElts = DemandedElts.getBitWidth(); switch (Op.getOpcode()) { @@ -46001,10 +46001,10 @@ bool X86TargetLowering::isGuaranteedNotToBeUndefOrPoisonForTargetNode( DemandedRHS); return (!DemandedLHS || DAG.isGuaranteedNotToBeUndefOrPoison(Op.getOperand(0), DemandedLHS, - PoisonOnly, Depth + 1)) && + Kind, Depth + 1)) && (!DemandedRHS || DAG.isGuaranteedNotToBeUndefOrPoison(Op.getOperand(1), DemandedRHS, - PoisonOnly, Depth + 1)); + Kind, Depth + 1)); } case X86ISD::INSERTPS: case X86ISD::BLENDI: @@ -46038,7 +46038,7 @@ bool X86TargetLowering::isGuaranteedNotToBeUndefOrPoisonForTargetNode( for (auto Op : enumerate(Ops)) if (!DemandedSrcElts[Op.index()].isZero() && !DAG.isGuaranteedNotToBeUndefOrPoison( - Op.value(), DemandedSrcElts[Op.index()], PoisonOnly, Depth + 1)) + Op.value(), DemandedSrcElts[Op.index()], Kind, Depth + 1)) return false; return true; } @@ -46049,19 +46049,19 @@ bool X86TargetLowering::isGuaranteedNotToBeUndefOrPoisonForTargetNode( MVT SrcVT = Src.getSimpleValueType(); if (SrcVT.isVector()) { APInt DemandedSrc = APInt::getOneBitSet(SrcVT.getVectorNumElements(), 0); - return DAG.isGuaranteedNotToBeUndefOrPoison(Src, DemandedSrc, PoisonOnly, + return DAG.isGuaranteedNotToBeUndefOrPoison(Src, DemandedSrc, Kind, Depth + 1); } - return DAG.isGuaranteedNotToBeUndefOrPoison(Src, PoisonOnly, Depth + 1); + return DAG.isGuaranteedNotToBeUndefOrPoison(Src, Kind, Depth + 1); } } return TargetLowering::isGuaranteedNotToBeUndefOrPoisonForTargetNode( - Op, DemandedElts, DAG, PoisonOnly, Depth); + Op, DemandedElts, DAG, Kind, Depth); } bool X86TargetLowering::canCreateUndefOrPoisonForTargetNode( SDValue Op, const APInt &DemandedElts, const SelectionDAG &DAG, - bool PoisonOnly, bool ConsiderFlags, unsigned Depth) const { + UndefPoisonKind Kind, bool ConsiderFlags, unsigned Depth) const { switch (Op.getOpcode()) { // SSE bit logic. @@ -46157,7 +46157,7 @@ bool X86TargetLowering::canCreateUndefOrPoisonForTargetNode( } } return TargetLowering::canCreateUndefOrPoisonForTargetNode( - Op, DemandedElts, DAG, PoisonOnly, ConsiderFlags, Depth); + Op, DemandedElts, DAG, Kind, ConsiderFlags, Depth); } bool X86TargetLowering::isSplatValueForTargetNode(SDValue Op, diff --git a/llvm/lib/Target/X86/X86ISelLowering.h b/llvm/lib/Target/X86/X86ISelLowering.h index 515f28122a00a..0d05c5772a707 100644 --- a/llvm/lib/Target/X86/X86ISelLowering.h +++ b/llvm/lib/Target/X86/X86ISelLowering.h @@ -367,11 +367,14 @@ namespace llvm { bool isGuaranteedNotToBeUndefOrPoisonForTargetNode( SDValue Op, const APInt &DemandedElts, const SelectionDAG &DAG, - bool PoisonOnly, unsigned Depth) const override; + UndefPoisonKind Kind, unsigned Depth) const override; - bool canCreateUndefOrPoisonForTargetNode( - SDValue Op, const APInt &DemandedElts, const SelectionDAG &DAG, - bool PoisonOnly, bool ConsiderFlags, unsigned Depth) const override; + bool canCreateUndefOrPoisonForTargetNode(SDValue Op, + const APInt &DemandedElts, + const SelectionDAG &DAG, + UndefPoisonKind Kind, + bool ConsiderFlags, + unsigned Depth) const override; bool isSplatValueForTargetNode(SDValue Op, const APInt &DemandedElts, APInt &UndefElts, const SelectionDAG &DAG, diff --git a/llvm/test/CodeGen/X86/known-never-zero.ll b/llvm/test/CodeGen/X86/known-never-zero.ll index 910f1375ed1ca..2345e91fe92d9 100644 --- a/llvm/test/CodeGen/X86/known-never-zero.ll +++ b/llvm/test/CodeGen/X86/known-never-zero.ll @@ -422,15 +422,18 @@ define i32 @uaddsat_known_nonzero_vec(<16 x i8> %x, ptr %p) { ; X86-NEXT: paddusb {{\.?LCPI[0-9]+_[0-9]+}}, %xmm0 ; X86-NEXT: movdqa %xmm0, (%eax) ; X86-NEXT: movzbl (%eax), %eax -; X86-NEXT: rep bsfl %eax, %eax +; X86-NEXT: bsfl %eax, %ecx +; X86-NEXT: movl $32, %eax +; X86-NEXT: cmovnel %ecx, %eax ; X86-NEXT: retl ; ; X64-LABEL: uaddsat_known_nonzero_vec: ; X64: # %bb.0: ; X64-NEXT: vpaddusb {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0, %xmm0 ; X64-NEXT: vmovdqa %xmm0, (%rdi) -; X64-NEXT: vpextrb $0, %xmm0, %eax -; X64-NEXT: rep bsfl %eax, %eax +; X64-NEXT: vpextrb $0, %xmm0, %ecx +; X64-NEXT: movl $32, %eax +; X64-NEXT: rep bsfl %ecx, %eax ; X64-NEXT: retq %z = call <16 x i8> @llvm.uadd.sat.v16i8(<16 x i8> %x, <16 x i8> ) store <16 x i8> %z, ptr %p diff --git a/mlir/include/mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.td b/mlir/include/mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.td index 7f155c7f75d75..6a4807cbaf7fc 100644 --- a/mlir/include/mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.td +++ b/mlir/include/mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.td @@ -768,10 +768,10 @@ def LowerUnPackOp : Op:$target, DefaultValuedAttr:$lowerUnpadLikeWithExtractSlice); let results = (outs Transform_ConcreteOpType<"tensor.empty">:$empty_op, - Transform_ConcreteOpType<"linalg.transpose">:$transpose_op, - Transform_ConcreteOpType<"tensor.collapse_shape">:$collapse_shape_op, - Transform_ConcreteOpType<"tensor.extract_slice">:$extract_slice_op, - Transform_ConcreteOpType<"linalg.copy">:$copy_op); + Transform_ConcreteOpType<"linalg.transpose">:$transpose_op, + Transform_ConcreteOpType<"tensor.collapse_shape">:$collapse_shape_op, + Transform_ConcreteOpType<"tensor.extract_slice">:$extract_slice_op, + Transform_ConcreteOpType<"linalg.copy">:$copy_op); let assemblyFormat = [{ $target attr-dict `:` functional-type(operands, results) }]; diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCCGOps.td b/mlir/include/mlir/Dialect/OpenACC/OpenACCCGOps.td index 69848101a5e4d..e998c9c0ed714 100644 --- a/mlir/include/mlir/Dialect/OpenACC/OpenACCCGOps.td +++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCCGOps.td @@ -29,9 +29,9 @@ include "mlir/Interfaces/InferTypeOpInterface.td" def OpenACC_ReductionInitOp : OpenACC_Op<"reduction_init", [SameOperandsAndResultType, RecursiveMemoryEffects, - DeclareOpInterfaceMethods, + DeclareOpInterfaceMethods< + RegionBranchOpInterface, ["getRegionInvocationBounds", + "getSuccessorInputs"]>, SingleBlockImplicitTerminator<"YieldOp">]> { let summary = "Allocate and initialize a reduction variable from a recipe"; let description = [{ @@ -44,7 +44,7 @@ def OpenACC_ReductionInitOp reduction_operator specifies the reduction kind (e.g. add, mul). }]; let arguments = (ins OpenACC_AnyPointerOrMappableType:$var, - OpenACC_ReductionOperatorAttr:$reductionOperator); + OpenACC_ReductionOperatorAttr:$reductionOperator); let results = (outs OpenACC_AnyPointerOrMappableType:$result); let regions = (region AnyRegion:$region); let assemblyFormat = [{ @@ -60,9 +60,9 @@ def OpenACC_ReductionInitOp def OpenACC_ReductionCombineRegionOp : OpenACC_Op<"reduction_combine_region", [SameTypeOperands, RecursiveMemoryEffects, - DeclareOpInterfaceMethods, + DeclareOpInterfaceMethods< + RegionBranchOpInterface, ["getRegionInvocationBounds", + "getSuccessorInputs"]>, SingleBlockImplicitTerminator<"YieldOp">]> { let summary = "Combine a reduction private value with its original (recipe)"; let description = [{ @@ -76,7 +76,7 @@ def OpenACC_ReductionCombineRegionOp The srcVar operand is typically the result of acc.reduction_init. }]; let arguments = (ins OpenACC_AnyPointerOrMappableType:$destVar, - OpenACC_AnyPointerOrMappableType:$srcVar); + OpenACC_AnyPointerOrMappableType:$srcVar); let results = (outs); let regions = (region AnyRegion:$region); let assemblyFormat = [{ diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td b/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td index 32ecaa6bc2d42..17865bd29703d 100644 --- a/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td +++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td @@ -2902,10 +2902,15 @@ def OpenACC_LoopOp } // Yield operation for the acc.loop and acc.parallel operations. -def OpenACC_YieldOp : OpenACC_Op<"yield", [Pure, ReturnLike, Terminator, - ParentOneOf<["FirstprivateRecipeOp, LoopOp, ParallelOp, PrivateRecipeOp," - "ReductionRecipeOp, ReductionInitOp, ReductionCombineRegionOp," - "SerialOp, AtomicUpdateOp, ComputeRegionOp"]>]> { +def OpenACC_YieldOp + : OpenACC_Op< + "yield", [Pure, ReturnLike, Terminator, + ParentOneOf<["FirstprivateRecipeOp", "LoopOp", "ParallelOp", + "PrivateRecipeOp", "ReductionRecipeOp", + "ReductionInitOp", "ReductionCombineRegionOp", + "SerialOp", "AtomicUpdateOp", + "ComputeRegionOp"]>]> { + let summary = "Acc yield and termination operation"; let description = [{ diff --git a/mlir/include/mlir/Dialect/OpenACC/Transforms/Passes.td b/mlir/include/mlir/Dialect/OpenACC/Transforms/Passes.td index 786d338cea600..7bb73feaaf3d5 100644 --- a/mlir/include/mlir/Dialect/OpenACC/Transforms/Passes.td +++ b/mlir/include/mlir/Dialect/OpenACC/Transforms/Passes.td @@ -379,8 +379,10 @@ def OffloadLiveInValueCanonicalization : Pass<"offload-livein-value-canonicaliza let dependentDialects = ["mlir::acc::OpenACCDialect"]; } -def ACCRecipeMaterialization : Pass<"acc-recipe-materialization", "mlir::ModuleOp"> { - let summary = "Materialize OpenACC private, firstprivate and reduction recipes"; +def ACCRecipeMaterialization + : Pass<"acc-recipe-materialization", "mlir::ModuleOp"> { + let summary = + "Materialize OpenACC private, firstprivate and reduction recipes"; let description = [{ Materializes OpenACC privatization, firstprivate and reduction recipes by cloning init, copy, combiner, and destroy into the construct. Replaces recipe @@ -388,7 +390,8 @@ def ACCRecipeMaterialization : Pass<"acc-recipe-materialization", "mlir::ModuleO acc.reduction_combine_region for reductions) and removes unused recipe symbols. }]; - let dependentDialects = ["mlir::acc::OpenACCDialect", "mlir::arith::ArithDialect"]; + let dependentDialects = ["mlir::acc::OpenACCDialect", + "mlir::arith::ArithDialect"]; } def OffloadTargetVerifier : Pass<"offload-target-verifier", "mlir::func::FuncOp"> {