diff options
Diffstat (limited to 'llvm/lib/Analysis/InstructionSimplify.cpp')
-rw-r--r-- | llvm/lib/Analysis/InstructionSimplify.cpp | 182 |
1 files changed, 138 insertions, 44 deletions
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp index 0d978d4..d1977f0 100644 --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -5425,15 +5425,8 @@ static Value *simplifyCastInst(unsigned CastOpc, Value *Op, Type *Ty, if (Src->getType() == Ty) { auto FirstOp = CI->getOpcode(); auto SecondOp = static_cast<Instruction::CastOps>(CastOpc); - Type *SrcIntPtrTy = - SrcTy->isPtrOrPtrVectorTy() ? Q.DL.getIntPtrType(SrcTy) : nullptr; - Type *MidIntPtrTy = - MidTy->isPtrOrPtrVectorTy() ? Q.DL.getIntPtrType(MidTy) : nullptr; - Type *DstIntPtrTy = - DstTy->isPtrOrPtrVectorTy() ? Q.DL.getIntPtrType(DstTy) : nullptr; if (CastInst::isEliminableCastPair(FirstOp, SecondOp, SrcTy, MidTy, DstTy, - SrcIntPtrTy, MidIntPtrTy, - DstIntPtrTy) == Instruction::BitCast) + &Q.DL) == Instruction::BitCast) return Src; } } @@ -6473,7 +6466,8 @@ static Value *foldMinMaxSharedOp(Intrinsic::ID IID, Value *Op0, Value *Op1) { static Value *foldMinimumMaximumSharedOp(Intrinsic::ID IID, Value *Op0, Value *Op1) { assert((IID == Intrinsic::maxnum || IID == Intrinsic::minnum || - IID == Intrinsic::maximum || IID == Intrinsic::minimum) && + IID == Intrinsic::maximum || IID == Intrinsic::minimum || + IID == Intrinsic::maximumnum || IID == Intrinsic::minimumnum) && "Unsupported intrinsic"); auto *M0 = dyn_cast<IntrinsicInst>(Op0); @@ -6512,6 +6506,82 @@ static Value *foldMinimumMaximumSharedOp(Intrinsic::ID IID, Value *Op0, return nullptr; } +enum class MinMaxOptResult { + CannotOptimize = 0, + UseNewConstVal = 1, + UseOtherVal = 2, + // For undef/poison, we can choose to either propgate undef/poison or + // use the LHS value depending on what will allow more optimization. + UseEither = 3 +}; +// Get the optimized value for a min/max instruction with a single constant +// input (either undef or scalar constantFP). The result may indicate to +// use the non-const LHS value, use a new constant value instead (with NaNs +// quieted), or to choose either option in the case of undef/poison. +static MinMaxOptResult OptimizeConstMinMax(const Constant *RHSConst, + const Intrinsic::ID IID, + const CallBase *Call, + Constant **OutNewConstVal) { + assert(OutNewConstVal != nullptr); + + bool PropagateNaN = IID == Intrinsic::minimum || IID == Intrinsic::maximum; + bool PropagateSNaN = IID == Intrinsic::minnum || IID == Intrinsic::maxnum; + bool IsMin = IID == Intrinsic::minimum || IID == Intrinsic::minnum || + IID == Intrinsic::minimumnum; + + // min/max(x, poison) -> either x or poison + if (isa<UndefValue>(RHSConst)) { + *OutNewConstVal = const_cast<Constant *>(RHSConst); + return MinMaxOptResult::UseEither; + } + + const ConstantFP *CFP = dyn_cast<ConstantFP>(RHSConst); + if (!CFP) + return MinMaxOptResult::CannotOptimize; + APFloat CAPF = CFP->getValueAPF(); + + // minnum(x, qnan) -> x + // maxnum(x, qnan) -> x + // minnum(x, snan) -> qnan + // maxnum(x, snan) -> qnan + // minimum(X, nan) -> qnan + // maximum(X, nan) -> qnan + // minimumnum(X, nan) -> x + // maximumnum(X, nan) -> x + if (CAPF.isNaN()) { + if (PropagateNaN || (PropagateSNaN && CAPF.isSignaling())) { + *OutNewConstVal = ConstantFP::get(CFP->getType(), CAPF.makeQuiet()); + return MinMaxOptResult::UseNewConstVal; + } + return MinMaxOptResult::UseOtherVal; + } + + if (CAPF.isInfinity() || (Call && Call->hasNoInfs() && CAPF.isLargest())) { + // minnum(X, -inf) -> -inf (ignoring sNaN -> qNaN propagation) + // maxnum(X, +inf) -> +inf (ignoring sNaN -> qNaN propagation) + // minimum(X, -inf) -> -inf if nnan + // maximum(X, +inf) -> +inf if nnan + // minimumnum(X, -inf) -> -inf + // maximumnum(X, +inf) -> +inf + if (CAPF.isNegative() == IsMin && + (!PropagateNaN || (Call && Call->hasNoNaNs()))) { + *OutNewConstVal = const_cast<Constant *>(RHSConst); + return MinMaxOptResult::UseNewConstVal; + } + + // minnum(X, +inf) -> X if nnan + // maxnum(X, -inf) -> X if nnan + // minimum(X, +inf) -> X (ignoring quieting of sNaNs) + // maximum(X, -inf) -> X (ignoring quieting of sNaNs) + // minimumnum(X, +inf) -> X if nnan + // maximumnum(X, -inf) -> X if nnan + if (CAPF.isNegative() != IsMin && + (PropagateNaN || (Call && Call->hasNoNaNs()))) + return MinMaxOptResult::UseOtherVal; + } + return MinMaxOptResult::CannotOptimize; +} + Value *llvm::simplifyBinaryIntrinsic(Intrinsic::ID IID, Type *ReturnType, Value *Op0, Value *Op1, const SimplifyQuery &Q, @@ -6780,8 +6850,17 @@ Value *llvm::simplifyBinaryIntrinsic(Intrinsic::ID IID, Type *ReturnType, case Intrinsic::maxnum: case Intrinsic::minnum: case Intrinsic::maximum: - case Intrinsic::minimum: { - // If the arguments are the same, this is a no-op. + case Intrinsic::minimum: + case Intrinsic::maximumnum: + case Intrinsic::minimumnum: { + // In several cases here, we deviate from exact IEEE 754 semantics + // to enable optimizations (as allowed by the LLVM IR spec). + // + // For instance, we may return one of the arguments unmodified instead of + // inserting an llvm.canonicalize to transform input sNaNs into qNaNs, + // or may assume all NaN inputs are qNaNs. + + // If the arguments are the same, this is a no-op (ignoring NaN quieting) if (Op0 == Op1) return Op0; @@ -6789,40 +6868,55 @@ Value *llvm::simplifyBinaryIntrinsic(Intrinsic::ID IID, Type *ReturnType, if (isa<Constant>(Op0)) std::swap(Op0, Op1); - // If an argument is undef, return the other argument. - if (Q.isUndefValue(Op1)) - return Op0; + if (Constant *C = dyn_cast<Constant>(Op1)) { + MinMaxOptResult OptResult = MinMaxOptResult::CannotOptimize; + Constant *NewConst = nullptr; + + if (VectorType *VTy = dyn_cast<VectorType>(C->getType())) { + ElementCount ElemCount = VTy->getElementCount(); + + if (Constant *SplatVal = C->getSplatValue()) { + // Handle splat vectors (including scalable vectors) + OptResult = OptimizeConstMinMax(SplatVal, IID, Call, &NewConst); + if (OptResult == MinMaxOptResult::UseNewConstVal) + NewConst = ConstantVector::getSplat(ElemCount, NewConst); + + } else if (ElemCount.isFixed()) { + // Storage to build up new const return value (with NaNs quieted) + SmallVector<Constant *, 16> NewC(ElemCount.getFixedValue()); + + // Check elementwise whether we can optimize to either a constant + // value or return the LHS value. We cannot mix and match LHS + + // constant elements, as this would require inserting a new + // VectorShuffle instruction, which is not allowed in simplifyBinOp. + OptResult = MinMaxOptResult::UseEither; + for (unsigned i = 0; i != ElemCount.getFixedValue(); ++i) { + auto ElemResult = OptimizeConstMinMax(C->getAggregateElement(i), + IID, Call, &NewConst); + if (ElemResult == MinMaxOptResult::CannotOptimize || + (ElemResult != OptResult && + OptResult != MinMaxOptResult::UseEither && + ElemResult != MinMaxOptResult::UseEither)) { + OptResult = MinMaxOptResult::CannotOptimize; + break; + } + NewC[i] = NewConst; + if (ElemResult != MinMaxOptResult::UseEither) + OptResult = ElemResult; + } + if (OptResult == MinMaxOptResult::UseNewConstVal) + NewConst = ConstantVector::get(NewC); + } + } else { + // Handle scalar inputs + OptResult = OptimizeConstMinMax(C, IID, Call, &NewConst); + } - bool PropagateNaN = IID == Intrinsic::minimum || IID == Intrinsic::maximum; - bool IsMin = IID == Intrinsic::minimum || IID == Intrinsic::minnum; - - // minnum(X, nan) -> X - // maxnum(X, nan) -> X - // minimum(X, nan) -> nan - // maximum(X, nan) -> nan - if (match(Op1, m_NaN())) - return PropagateNaN ? propagateNaN(cast<Constant>(Op1)) : Op0; - - // In the following folds, inf can be replaced with the largest finite - // float, if the ninf flag is set. - const APFloat *C; - if (match(Op1, m_APFloat(C)) && - (C->isInfinity() || (Call && Call->hasNoInfs() && C->isLargest()))) { - // minnum(X, -inf) -> -inf - // maxnum(X, +inf) -> +inf - // minimum(X, -inf) -> -inf if nnan - // maximum(X, +inf) -> +inf if nnan - if (C->isNegative() == IsMin && - (!PropagateNaN || (Call && Call->hasNoNaNs()))) - return ConstantFP::get(ReturnType, *C); - - // minnum(X, +inf) -> X if nnan - // maxnum(X, -inf) -> X if nnan - // minimum(X, +inf) -> X - // maximum(X, -inf) -> X - if (C->isNegative() != IsMin && - (PropagateNaN || (Call && Call->hasNoNaNs()))) - return Op0; + if (OptResult == MinMaxOptResult::UseOtherVal || + OptResult == MinMaxOptResult::UseEither) + return Op0; // Return the other arg (ignoring NaN quieting) + else if (OptResult == MinMaxOptResult::UseNewConstVal) + return NewConst; } // Min/max of the same operation with common operand: |