summaryrefslogtreecommitdiff
path: root/llvm/lib/Analysis/InstructionSimplify.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Analysis/InstructionSimplify.cpp')
-rw-r--r--llvm/lib/Analysis/InstructionSimplify.cpp198
1 files changed, 149 insertions, 49 deletions
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 07f4a8e5c889..e08ef60dbede 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -671,12 +671,12 @@ Value *llvm::simplifyAddInst(Value *Op0, Value *Op1, bool IsNSW, bool IsNUW,
/// This is very similar to stripAndAccumulateConstantOffsets(), except it
/// normalizes the offset bitwidth to the stripped pointer type, not the
/// original pointer type.
-static APInt stripAndComputeConstantOffsets(const DataLayout &DL, Value *&V,
- bool AllowNonInbounds = false) {
+static APInt stripAndComputeConstantOffsets(const DataLayout &DL, Value *&V) {
assert(V->getType()->isPtrOrPtrVectorTy());
APInt Offset = APInt::getZero(DL.getIndexTypeSizeInBits(V->getType()));
- V = V->stripAndAccumulateConstantOffsets(DL, Offset, AllowNonInbounds);
+ V = V->stripAndAccumulateConstantOffsets(DL, Offset,
+ /*AllowNonInbounds=*/true);
// As that strip may trace through `addrspacecast`, need to sext or trunc
// the offset calculated.
return Offset.sextOrTrunc(DL.getIndexTypeSizeInBits(V->getType()));
@@ -853,10 +853,12 @@ static Value *simplifySubInst(Value *Op0, Value *Op1, bool IsNSW, bool IsNUW,
return W;
// Variations on GEP(base, I, ...) - GEP(base, i, ...) -> GEP(null, I-i, ...).
- if (match(Op0, m_PtrToInt(m_Value(X))) && match(Op1, m_PtrToInt(m_Value(Y))))
+ if (match(Op0, m_PtrToIntOrAddr(m_Value(X))) &&
+ match(Op1, m_PtrToIntOrAddr(m_Value(Y)))) {
if (Constant *Result = computePointerDifference(Q.DL, X, Y))
return ConstantFoldIntegerCast(Result, Op0->getType(), /*IsSigned*/ true,
Q.DL);
+ }
// i1 sub -> xor.
if (MaxRecurse && Op0->getType()->isIntOrIntVectorTy(1))
@@ -4164,6 +4166,10 @@ static Value *simplifyFCmpInst(CmpPredicate Pred, Value *LHS, Value *RHS,
return ConstantInt::get(RetTy, Pred == CmpInst::FCMP_UNO);
}
+ if (std::optional<bool> Res =
+ isImpliedByDomCondition(Pred, LHS, RHS, Q.CxtI, Q.DL))
+ return ConstantInt::getBool(RetTy, *Res);
+
const APFloat *C = nullptr;
match(RHS, m_APFloatAllowPoison(C));
std::optional<KnownFPClass> FullKnownClassLHS;
@@ -5421,15 +5427,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;
}
}
@@ -6469,7 +6468,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);
@@ -6508,6 +6508,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,
@@ -6568,7 +6644,7 @@ Value *llvm::simplifyBinaryIntrinsic(Intrinsic::ID IID, Type *ReturnType,
"Invalid mask width");
// If index-width (mask size) is less than pointer-size then mask is
// 1-extended.
- if (match(Op1, m_PtrToInt(m_Specific(Op0))))
+ if (match(Op1, m_PtrToIntOrAddr(m_Specific(Op0))))
return Op0;
// NOTE: We may have attributes associated with the return value of the
@@ -6776,8 +6852,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;
@@ -6785,40 +6870,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: