aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp')
-rw-r--r--llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp327
1 files changed, 278 insertions, 49 deletions
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index f26c194d31b9..ce2b913dba61 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -18,6 +18,7 @@
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/CmpInstAnalysis.h"
#include "llvm/Analysis/InstructionSimplify.h"
+#include "llvm/Analysis/OverflowInstAnalysis.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constant.h"
@@ -47,11 +48,6 @@ using namespace PatternMatch;
#define DEBUG_TYPE "instcombine"
-/// FIXME: Enabled by default until the pattern is supported well.
-static cl::opt<bool> EnableUnsafeSelectTransform(
- "instcombine-unsafe-select-transform", cl::init(true),
- cl::desc("Enable poison-unsafe select to and/or transform"));
-
static Value *createMinMax(InstCombiner::BuilderTy &Builder,
SelectPatternFlavor SPF, Value *A, Value *B) {
CmpInst::Predicate Pred = getMinMaxPred(SPF);
@@ -327,6 +323,35 @@ Instruction *InstCombinerImpl::foldSelectOpOp(SelectInst &SI, Instruction *TI,
return UnaryOperator::CreateFNegFMF(NewSel, TI);
}
+ // Min/max intrinsic with a common operand can have the common operand pulled
+ // after the select. This is the same transform as below for binops, but
+ // specialized for intrinsic matching and without the restrictive uses clause.
+ auto *TII = dyn_cast<IntrinsicInst>(TI);
+ auto *FII = dyn_cast<IntrinsicInst>(FI);
+ if (TII && FII && TII->getIntrinsicID() == FII->getIntrinsicID() &&
+ (TII->hasOneUse() || FII->hasOneUse())) {
+ Value *T0, *T1, *F0, *F1;
+ if (match(TII, m_MaxOrMin(m_Value(T0), m_Value(T1))) &&
+ match(FII, m_MaxOrMin(m_Value(F0), m_Value(F1)))) {
+ if (T0 == F0) {
+ Value *NewSel = Builder.CreateSelect(Cond, T1, F1, "minmaxop", &SI);
+ return CallInst::Create(TII->getCalledFunction(), {NewSel, T0});
+ }
+ if (T0 == F1) {
+ Value *NewSel = Builder.CreateSelect(Cond, T1, F0, "minmaxop", &SI);
+ return CallInst::Create(TII->getCalledFunction(), {NewSel, T0});
+ }
+ if (T1 == F0) {
+ Value *NewSel = Builder.CreateSelect(Cond, T0, F1, "minmaxop", &SI);
+ return CallInst::Create(TII->getCalledFunction(), {NewSel, T1});
+ }
+ if (T1 == F1) {
+ Value *NewSel = Builder.CreateSelect(Cond, T0, F0, "minmaxop", &SI);
+ return CallInst::Create(TII->getCalledFunction(), {NewSel, T1});
+ }
+ }
+ }
+
// Only handle binary operators (including two-operand getelementptr) with
// one-use here. As with the cast case above, it may be possible to relax the
// one-use constraint, but that needs be examined carefully since it may not
@@ -1095,7 +1120,10 @@ static Instruction *canonicalizeAbsNabs(SelectInst &Sel, ICmpInst &Cmp,
/// TODO: Wrapping flags could be preserved in some cases with better analysis.
Instruction *InstCombinerImpl::foldSelectValueEquivalence(SelectInst &Sel,
ICmpInst &Cmp) {
- if (!Cmp.isEquality())
+ // Value equivalence substitution requires an all-or-nothing replacement.
+ // It does not make sense for a vector compare where each lane is chosen
+ // independently.
+ if (!Cmp.isEquality() || Cmp.getType()->isVectorTy())
return nullptr;
// Canonicalize the pattern to ICMP_EQ by swapping the select operands.
@@ -1114,7 +1142,7 @@ Instruction *InstCombinerImpl::foldSelectValueEquivalence(SelectInst &Sel,
Value *CmpLHS = Cmp.getOperand(0), *CmpRHS = Cmp.getOperand(1);
if (TrueVal != CmpLHS &&
isGuaranteedNotToBeUndefOrPoison(CmpRHS, SQ.AC, &Sel, &DT)) {
- if (Value *V = SimplifyWithOpReplaced(TrueVal, CmpLHS, CmpRHS, SQ,
+ if (Value *V = simplifyWithOpReplaced(TrueVal, CmpLHS, CmpRHS, SQ,
/* AllowRefinement */ true))
return replaceOperand(Sel, Swapped ? 2 : 1, V);
@@ -1136,7 +1164,7 @@ Instruction *InstCombinerImpl::foldSelectValueEquivalence(SelectInst &Sel,
}
if (TrueVal != CmpRHS &&
isGuaranteedNotToBeUndefOrPoison(CmpLHS, SQ.AC, &Sel, &DT))
- if (Value *V = SimplifyWithOpReplaced(TrueVal, CmpRHS, CmpLHS, SQ,
+ if (Value *V = simplifyWithOpReplaced(TrueVal, CmpRHS, CmpLHS, SQ,
/* AllowRefinement */ true))
return replaceOperand(Sel, Swapped ? 2 : 1, V);
@@ -1167,9 +1195,9 @@ Instruction *InstCombinerImpl::foldSelectValueEquivalence(SelectInst &Sel,
// We have an 'EQ' comparison, so the select's false value will propagate.
// Example:
// (X == 42) ? 43 : (X + 1) --> (X == 42) ? (X + 1) : (X + 1) --> X + 1
- if (SimplifyWithOpReplaced(FalseVal, CmpLHS, CmpRHS, SQ,
+ if (simplifyWithOpReplaced(FalseVal, CmpLHS, CmpRHS, SQ,
/* AllowRefinement */ false) == TrueVal ||
- SimplifyWithOpReplaced(FalseVal, CmpRHS, CmpLHS, SQ,
+ simplifyWithOpReplaced(FalseVal, CmpRHS, CmpLHS, SQ,
/* AllowRefinement */ false) == TrueVal) {
return replaceInstUsesWith(Sel, FalseVal);
}
@@ -2351,7 +2379,7 @@ static Instruction *foldSelectFunnelShift(SelectInst &Sel,
Intrinsic::ID IID = IsFshl ? Intrinsic::fshl : Intrinsic::fshr;
Function *F = Intrinsic::getDeclaration(Sel.getModule(), IID, Sel.getType());
ShAmt = Builder.CreateZExt(ShAmt, Sel.getType());
- return IntrinsicInst::Create(F, { SV0, SV1, ShAmt });
+ return CallInst::Create(F, { SV0, SV1, ShAmt });
}
static Instruction *foldSelectToCopysign(SelectInst &Sel,
@@ -2392,7 +2420,7 @@ static Instruction *foldSelectToCopysign(SelectInst &Sel,
Value *MagArg = TC->isNegative() ? FVal : TVal;
Function *F = Intrinsic::getDeclaration(Sel.getModule(), Intrinsic::copysign,
Sel.getType());
- Instruction *CopySign = IntrinsicInst::Create(F, { MagArg, X });
+ Instruction *CopySign = CallInst::Create(F, { MagArg, X });
CopySign->setFastMathFlags(Sel.getFastMathFlags());
return CopySign;
}
@@ -2553,6 +2581,48 @@ static Value *foldSelectWithFrozenICmp(SelectInst &Sel, InstCombiner::BuilderTy
return nullptr;
}
+Instruction *InstCombinerImpl::foldAndOrOfSelectUsingImpliedCond(Value *Op,
+ SelectInst &SI,
+ bool IsAnd) {
+ Value *CondVal = SI.getCondition();
+ Value *A = SI.getTrueValue();
+ Value *B = SI.getFalseValue();
+
+ assert(Op->getType()->isIntOrIntVectorTy(1) &&
+ "Op must be either i1 or vector of i1.");
+
+ Optional<bool> Res = isImpliedCondition(Op, CondVal, DL, IsAnd);
+ if (!Res)
+ return nullptr;
+
+ Value *Zero = Constant::getNullValue(A->getType());
+ Value *One = Constant::getAllOnesValue(A->getType());
+
+ if (*Res == true) {
+ if (IsAnd)
+ // select op, (select cond, A, B), false => select op, A, false
+ // and op, (select cond, A, B) => select op, A, false
+ // if op = true implies condval = true.
+ return SelectInst::Create(Op, A, Zero);
+ else
+ // select op, true, (select cond, A, B) => select op, true, A
+ // or op, (select cond, A, B) => select op, true, A
+ // if op = false implies condval = true.
+ return SelectInst::Create(Op, One, A);
+ } else {
+ if (IsAnd)
+ // select op, (select cond, A, B), false => select op, B, false
+ // and op, (select cond, A, B) => select op, B, false
+ // if op = true implies condval = false.
+ return SelectInst::Create(Op, B, Zero);
+ else
+ // select op, true, (select cond, A, B) => select op, true, B
+ // or op, (select cond, A, B) => select op, true, B
+ // if op = false implies condval = false.
+ return SelectInst::Create(Op, One, B);
+ }
+}
+
Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
Value *CondVal = SI.getCondition();
Value *TrueVal = SI.getTrueValue();
@@ -2564,7 +2634,7 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
// don't simplify it so loop unswitch can know the equality comparison
// may have an undef operand. This is a workaround for PR31652 caused by
// descrepancy about branch on undef between LoopUnswitch and GVN.
- if (isa<UndefValue>(TrueVal) || isa<UndefValue>(FalseVal)) {
+ if (match(TrueVal, m_Undef()) || match(FalseVal, m_Undef())) {
if (llvm::any_of(SI.users(), [&](User *U) {
ICmpInst *CI = dyn_cast<ICmpInst>(U);
if (CI && CI->isEquality())
@@ -2587,47 +2657,152 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
CmpInst::Predicate Pred;
- if (SelType->isIntOrIntVectorTy(1) &&
+ // Avoid potential infinite loops by checking for non-constant condition.
+ // TODO: Can we assert instead by improving canonicalizeSelectToShuffle()?
+ // Scalar select must have simplified?
+ if (SelType->isIntOrIntVectorTy(1) && !isa<Constant>(CondVal) &&
TrueVal->getType() == CondVal->getType()) {
- if (match(TrueVal, m_One()) &&
- (EnableUnsafeSelectTransform || impliesPoison(FalseVal, CondVal))) {
+ // Folding select to and/or i1 isn't poison safe in general. impliesPoison
+ // checks whether folding it does not convert a well-defined value into
+ // poison.
+ if (match(TrueVal, m_One()) && impliesPoison(FalseVal, CondVal)) {
// Change: A = select B, true, C --> A = or B, C
return BinaryOperator::CreateOr(CondVal, FalseVal);
}
- if (match(FalseVal, m_Zero()) &&
- (EnableUnsafeSelectTransform || impliesPoison(TrueVal, CondVal))) {
+ if (match(FalseVal, m_Zero()) && impliesPoison(TrueVal, CondVal)) {
// Change: A = select B, C, false --> A = and B, C
return BinaryOperator::CreateAnd(CondVal, TrueVal);
}
+ auto *One = ConstantInt::getTrue(SelType);
+ auto *Zero = ConstantInt::getFalse(SelType);
+
+ // We match the "full" 0 or 1 constant here to avoid a potential infinite
+ // loop with vectors that may have undefined/poison elements.
// select a, false, b -> select !a, b, false
- if (match(TrueVal, m_Zero())) {
+ if (match(TrueVal, m_Specific(Zero))) {
Value *NotCond = Builder.CreateNot(CondVal, "not." + CondVal->getName());
- return SelectInst::Create(NotCond, FalseVal,
- ConstantInt::getFalse(SelType));
+ return SelectInst::Create(NotCond, FalseVal, Zero);
}
// select a, b, true -> select !a, true, b
- if (match(FalseVal, m_One())) {
+ if (match(FalseVal, m_Specific(One))) {
Value *NotCond = Builder.CreateNot(CondVal, "not." + CondVal->getName());
- return SelectInst::Create(NotCond, ConstantInt::getTrue(SelType),
- TrueVal);
+ return SelectInst::Create(NotCond, One, TrueVal);
}
// select a, a, b -> select a, true, b
if (CondVal == TrueVal)
- return replaceOperand(SI, 1, ConstantInt::getTrue(SelType));
+ return replaceOperand(SI, 1, One);
// select a, b, a -> select a, b, false
if (CondVal == FalseVal)
- return replaceOperand(SI, 2, ConstantInt::getFalse(SelType));
+ return replaceOperand(SI, 2, Zero);
// select a, !a, b -> select !a, b, false
if (match(TrueVal, m_Not(m_Specific(CondVal))))
- return SelectInst::Create(TrueVal, FalseVal,
- ConstantInt::getFalse(SelType));
+ return SelectInst::Create(TrueVal, FalseVal, Zero);
// select a, b, !a -> select !a, true, b
if (match(FalseVal, m_Not(m_Specific(CondVal))))
- return SelectInst::Create(FalseVal, ConstantInt::getTrue(SelType),
- TrueVal);
+ return SelectInst::Create(FalseVal, One, TrueVal);
+
+ Value *A, *B;
+
+ // DeMorgan in select form: !a && !b --> !(a || b)
+ // select !a, !b, false --> not (select a, true, b)
+ if (match(&SI, m_LogicalAnd(m_Not(m_Value(A)), m_Not(m_Value(B)))) &&
+ (CondVal->hasOneUse() || TrueVal->hasOneUse()) &&
+ !match(A, m_ConstantExpr()) && !match(B, m_ConstantExpr()))
+ return BinaryOperator::CreateNot(Builder.CreateSelect(A, One, B));
+
+ // DeMorgan in select form: !a || !b --> !(a && b)
+ // select !a, true, !b --> not (select a, b, false)
+ if (match(&SI, m_LogicalOr(m_Not(m_Value(A)), m_Not(m_Value(B)))) &&
+ (CondVal->hasOneUse() || FalseVal->hasOneUse()) &&
+ !match(A, m_ConstantExpr()) && !match(B, m_ConstantExpr()))
+ return BinaryOperator::CreateNot(Builder.CreateSelect(A, B, Zero));
+
+ // select (select a, true, b), true, b -> select a, true, b
+ if (match(CondVal, m_Select(m_Value(A), m_One(), m_Value(B))) &&
+ match(TrueVal, m_One()) && match(FalseVal, m_Specific(B)))
+ return replaceOperand(SI, 0, A);
+ // select (select a, b, false), b, false -> select a, b, false
+ if (match(CondVal, m_Select(m_Value(A), m_Value(B), m_Zero())) &&
+ match(TrueVal, m_Specific(B)) && match(FalseVal, m_Zero()))
+ return replaceOperand(SI, 0, A);
+
+ if (!SelType->isVectorTy()) {
+ if (Value *S = simplifyWithOpReplaced(TrueVal, CondVal, One, SQ,
+ /* AllowRefinement */ true))
+ return replaceOperand(SI, 1, S);
+ if (Value *S = simplifyWithOpReplaced(FalseVal, CondVal, Zero, SQ,
+ /* AllowRefinement */ true))
+ return replaceOperand(SI, 2, S);
+ }
+
+ if (match(FalseVal, m_Zero()) || match(TrueVal, m_One())) {
+ Use *Y = nullptr;
+ bool IsAnd = match(FalseVal, m_Zero()) ? true : false;
+ Value *Op1 = IsAnd ? TrueVal : FalseVal;
+ if (isCheckForZeroAndMulWithOverflow(CondVal, Op1, IsAnd, Y)) {
+ auto *FI = new FreezeInst(*Y, (*Y)->getName() + ".fr");
+ InsertNewInstBefore(FI, *cast<Instruction>(Y->getUser()));
+ replaceUse(*Y, FI);
+ return replaceInstUsesWith(SI, Op1);
+ }
+
+ if (auto *Op1SI = dyn_cast<SelectInst>(Op1))
+ if (auto *I = foldAndOrOfSelectUsingImpliedCond(CondVal, *Op1SI,
+ /* IsAnd */ IsAnd))
+ return I;
+
+ if (auto *ICmp0 = dyn_cast<ICmpInst>(CondVal))
+ if (auto *ICmp1 = dyn_cast<ICmpInst>(Op1))
+ if (auto *V = foldAndOrOfICmpsOfAndWithPow2(ICmp0, ICmp1, &SI, IsAnd,
+ /* IsLogical */ true))
+ return replaceInstUsesWith(SI, V);
+ }
+
+ // select (select a, true, b), c, false -> select a, c, false
+ // select c, (select a, true, b), false -> select c, a, false
+ // if c implies that b is false.
+ if (match(CondVal, m_Select(m_Value(A), m_One(), m_Value(B))) &&
+ match(FalseVal, m_Zero())) {
+ Optional<bool> Res = isImpliedCondition(TrueVal, B, DL);
+ if (Res && *Res == false)
+ return replaceOperand(SI, 0, A);
+ }
+ if (match(TrueVal, m_Select(m_Value(A), m_One(), m_Value(B))) &&
+ match(FalseVal, m_Zero())) {
+ Optional<bool> Res = isImpliedCondition(CondVal, B, DL);
+ if (Res && *Res == false)
+ return replaceOperand(SI, 1, A);
+ }
+ // select c, true, (select a, b, false) -> select c, true, a
+ // select (select a, b, false), true, c -> select a, true, c
+ // if c = false implies that b = true
+ if (match(TrueVal, m_One()) &&
+ match(FalseVal, m_Select(m_Value(A), m_Value(B), m_Zero()))) {
+ Optional<bool> Res = isImpliedCondition(CondVal, B, DL, false);
+ if (Res && *Res == true)
+ return replaceOperand(SI, 2, A);
+ }
+ if (match(CondVal, m_Select(m_Value(A), m_Value(B), m_Zero())) &&
+ match(TrueVal, m_One())) {
+ Optional<bool> Res = isImpliedCondition(FalseVal, B, DL, false);
+ if (Res && *Res == true)
+ return replaceOperand(SI, 0, A);
+ }
+
+ // sel (sel c, a, false), true, (sel !c, b, false) -> sel c, a, b
+ // sel (sel !c, a, false), true, (sel c, b, false) -> sel c, b, a
+ Value *C1, *C2;
+ if (match(CondVal, m_Select(m_Value(C1), m_Value(A), m_Zero())) &&
+ match(TrueVal, m_One()) &&
+ match(FalseVal, m_Select(m_Value(C2), m_Value(B), m_Zero()))) {
+ if (match(C2, m_Not(m_Specific(C1)))) // first case
+ return SelectInst::Create(C1, A, B);
+ else if (match(C1, m_Not(m_Specific(C2)))) // second case
+ return SelectInst::Create(C2, B, A);
+ }
}
// Selecting between two integer or vector splat integer constants?
@@ -2662,9 +2837,9 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
}
}
- // See if we are selecting two values based on a comparison of the two values.
- if (FCmpInst *FCI = dyn_cast<FCmpInst>(CondVal)) {
- Value *Cmp0 = FCI->getOperand(0), *Cmp1 = FCI->getOperand(1);
+ if (auto *FCmp = dyn_cast<FCmpInst>(CondVal)) {
+ Value *Cmp0 = FCmp->getOperand(0), *Cmp1 = FCmp->getOperand(1);
+ // Are we selecting a value based on a comparison of the two values?
if ((Cmp0 == TrueVal && Cmp1 == FalseVal) ||
(Cmp0 == FalseVal && Cmp1 == TrueVal)) {
// Canonicalize to use ordered comparisons by swapping the select
@@ -2672,13 +2847,13 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
//
// e.g.
// (X ugt Y) ? X : Y -> (X ole Y) ? Y : X
- if (FCI->hasOneUse() && FCmpInst::isUnordered(FCI->getPredicate())) {
- FCmpInst::Predicate InvPred = FCI->getInversePredicate();
+ if (FCmp->hasOneUse() && FCmpInst::isUnordered(FCmp->getPredicate())) {
+ FCmpInst::Predicate InvPred = FCmp->getInversePredicate();
IRBuilder<>::FastMathFlagGuard FMFG(Builder);
// FIXME: The FMF should propagate from the select, not the fcmp.
- Builder.setFastMathFlags(FCI->getFastMathFlags());
+ Builder.setFastMathFlags(FCmp->getFastMathFlags());
Value *NewCond = Builder.CreateFCmp(InvPred, Cmp0, Cmp1,
- FCI->getName() + ".inv");
+ FCmp->getName() + ".inv");
Value *NewSel = Builder.CreateSelect(NewCond, FalseVal, TrueVal);
return replaceInstUsesWith(SI, NewSel);
}
@@ -2691,15 +2866,13 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
// fast-math-flags (nsz) or fsub with +0.0 (not fneg) for this to work. We
// also require nnan because we do not want to unintentionally change the
// sign of a NaN value.
- // FIXME: These folds should test/propagate FMF from the select, not the
- // fsub or fneg.
// (X <= +/-0.0) ? (0.0 - X) : X --> fabs(X)
Instruction *FSub;
if (match(CondVal, m_FCmp(Pred, m_Specific(FalseVal), m_AnyZeroFP())) &&
match(TrueVal, m_FSub(m_PosZeroFP(), m_Specific(FalseVal))) &&
match(TrueVal, m_Instruction(FSub)) && FSub->hasNoNaNs() &&
(Pred == FCmpInst::FCMP_OLE || Pred == FCmpInst::FCMP_ULE)) {
- Value *Fabs = Builder.CreateUnaryIntrinsic(Intrinsic::fabs, FalseVal, FSub);
+ Value *Fabs = Builder.CreateUnaryIntrinsic(Intrinsic::fabs, FalseVal, &SI);
return replaceInstUsesWith(SI, Fabs);
}
// (X > +/-0.0) ? X : (0.0 - X) --> fabs(X)
@@ -2707,7 +2880,7 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
match(FalseVal, m_FSub(m_PosZeroFP(), m_Specific(TrueVal))) &&
match(FalseVal, m_Instruction(FSub)) && FSub->hasNoNaNs() &&
(Pred == FCmpInst::FCMP_OGT || Pred == FCmpInst::FCMP_UGT)) {
- Value *Fabs = Builder.CreateUnaryIntrinsic(Intrinsic::fabs, TrueVal, FSub);
+ Value *Fabs = Builder.CreateUnaryIntrinsic(Intrinsic::fabs, TrueVal, &SI);
return replaceInstUsesWith(SI, Fabs);
}
// With nnan and nsz:
@@ -2716,11 +2889,11 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
Instruction *FNeg;
if (match(CondVal, m_FCmp(Pred, m_Specific(FalseVal), m_AnyZeroFP())) &&
match(TrueVal, m_FNeg(m_Specific(FalseVal))) &&
- match(TrueVal, m_Instruction(FNeg)) &&
- FNeg->hasNoNaNs() && FNeg->hasNoSignedZeros() &&
+ match(TrueVal, m_Instruction(FNeg)) && FNeg->hasNoNaNs() &&
+ FNeg->hasNoSignedZeros() && SI.hasNoSignedZeros() &&
(Pred == FCmpInst::FCMP_OLT || Pred == FCmpInst::FCMP_OLE ||
Pred == FCmpInst::FCMP_ULT || Pred == FCmpInst::FCMP_ULE)) {
- Value *Fabs = Builder.CreateUnaryIntrinsic(Intrinsic::fabs, FalseVal, FNeg);
+ Value *Fabs = Builder.CreateUnaryIntrinsic(Intrinsic::fabs, FalseVal, &SI);
return replaceInstUsesWith(SI, Fabs);
}
// With nnan and nsz:
@@ -2728,11 +2901,11 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
// (X >= +/-0.0) ? X : -X --> fabs(X)
if (match(CondVal, m_FCmp(Pred, m_Specific(TrueVal), m_AnyZeroFP())) &&
match(FalseVal, m_FNeg(m_Specific(TrueVal))) &&
- match(FalseVal, m_Instruction(FNeg)) &&
- FNeg->hasNoNaNs() && FNeg->hasNoSignedZeros() &&
+ match(FalseVal, m_Instruction(FNeg)) && FNeg->hasNoNaNs() &&
+ FNeg->hasNoSignedZeros() && SI.hasNoSignedZeros() &&
(Pred == FCmpInst::FCMP_OGT || Pred == FCmpInst::FCMP_OGE ||
Pred == FCmpInst::FCMP_UGT || Pred == FCmpInst::FCMP_UGE)) {
- Value *Fabs = Builder.CreateUnaryIntrinsic(Intrinsic::fabs, TrueVal, FNeg);
+ Value *Fabs = Builder.CreateUnaryIntrinsic(Intrinsic::fabs, TrueVal, &SI);
return replaceInstUsesWith(SI, Fabs);
}
@@ -2758,6 +2931,31 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
if (Instruction *I = foldSelectExtConst(SI))
return I;
+ // Fold (select C, (gep Ptr, Idx), Ptr) -> (gep Ptr, (select C, Idx, 0))
+ // Fold (select C, Ptr, (gep Ptr, Idx)) -> (gep Ptr, (select C, 0, Idx))
+ auto SelectGepWithBase = [&](GetElementPtrInst *Gep, Value *Base,
+ bool Swap) -> GetElementPtrInst * {
+ Value *Ptr = Gep->getPointerOperand();
+ if (Gep->getNumOperands() != 2 || Gep->getPointerOperand() != Base ||
+ !Gep->hasOneUse())
+ return nullptr;
+ Type *ElementType = Gep->getResultElementType();
+ Value *Idx = Gep->getOperand(1);
+ Value *NewT = Idx;
+ Value *NewF = Constant::getNullValue(Idx->getType());
+ if (Swap)
+ std::swap(NewT, NewF);
+ Value *NewSI =
+ Builder.CreateSelect(CondVal, NewT, NewF, SI.getName() + ".idx", &SI);
+ return GetElementPtrInst::Create(ElementType, Ptr, {NewSI});
+ };
+ if (auto *TrueGep = dyn_cast<GetElementPtrInst>(TrueVal))
+ if (auto *NewGep = SelectGepWithBase(TrueGep, FalseVal, false))
+ return NewGep;
+ if (auto *FalseGep = dyn_cast<GetElementPtrInst>(FalseVal))
+ if (auto *NewGep = SelectGepWithBase(FalseGep, TrueVal, true))
+ return NewGep;
+
// See if we can fold the select into one of our operands.
if (SelType->isIntOrIntVectorTy() || SelType->isFPOrFPVectorTy()) {
if (Instruction *FoldI = foldSelectIntoOp(SI, TrueVal, FalseVal))
@@ -2890,7 +3088,7 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
// shortening paths for the values (this helps getUnderlyingObjects() for
// example).
if (TrueSI->getFalseValue() == FalseVal && TrueSI->hasOneUse()) {
- Value *And = Builder.CreateAnd(CondVal, TrueSI->getCondition());
+ Value *And = Builder.CreateLogicalAnd(CondVal, TrueSI->getCondition());
replaceOperand(SI, 0, And);
replaceOperand(SI, 1, TrueSI->getTrueValue());
return &SI;
@@ -2907,7 +3105,7 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
}
// select(C0, a, select(C1, a, b)) -> select(C0|C1, a, b)
if (FalseSI->getTrueValue() == TrueVal && FalseSI->hasOneUse()) {
- Value *Or = Builder.CreateOr(CondVal, FalseSI->getCondition());
+ Value *Or = Builder.CreateLogicalOr(CondVal, FalseSI->getCondition());
replaceOperand(SI, 0, Or);
replaceOperand(SI, 2, FalseSI->getFalseValue());
return &SI;
@@ -3018,5 +3216,36 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
if (Value *Fr = foldSelectWithFrozenICmp(SI, Builder))
return replaceInstUsesWith(SI, Fr);
+ // select(mask, mload(,,mask,0), 0) -> mload(,,mask,0)
+ // Load inst is intentionally not checked for hasOneUse()
+ if (match(FalseVal, m_Zero()) &&
+ match(TrueVal, m_MaskedLoad(m_Value(), m_Value(), m_Specific(CondVal),
+ m_CombineOr(m_Undef(), m_Zero())))) {
+ auto *MaskedLoad = cast<IntrinsicInst>(TrueVal);
+ if (isa<UndefValue>(MaskedLoad->getArgOperand(3)))
+ MaskedLoad->setArgOperand(3, FalseVal /* Zero */);
+ return replaceInstUsesWith(SI, MaskedLoad);
+ }
+
+ Value *Mask;
+ if (match(TrueVal, m_Zero()) &&
+ match(FalseVal, m_MaskedLoad(m_Value(), m_Value(), m_Value(Mask),
+ m_CombineOr(m_Undef(), m_Zero())))) {
+ // We can remove the select by ensuring the load zeros all lanes the
+ // select would have. We determine this by proving there is no overlap
+ // between the load and select masks.
+ // (i.e (load_mask & select_mask) == 0 == no overlap)
+ bool CanMergeSelectIntoLoad = false;
+ if (Value *V = SimplifyAndInst(CondVal, Mask, SQ.getWithInstruction(&SI)))
+ CanMergeSelectIntoLoad = match(V, m_Zero());
+
+ if (CanMergeSelectIntoLoad) {
+ auto *MaskedLoad = cast<IntrinsicInst>(FalseVal);
+ if (isa<UndefValue>(MaskedLoad->getArgOperand(3)))
+ MaskedLoad->setArgOperand(3, TrueVal /* Zero */);
+ return replaceInstUsesWith(SI, MaskedLoad);
+ }
+ }
+
return nullptr;
}