diff options
Diffstat (limited to 'llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp')
| -rw-r--r-- | llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp | 71 |
1 files changed, 60 insertions, 11 deletions
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp index 20bf00344b14..ab55f235920a 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -1171,14 +1171,15 @@ static Value *foldSelectCttzCtlz(ICmpInst *ICI, Value *TrueVal, Value *FalseVal, return nullptr; } -static Instruction *canonicalizeSPF(SelectInst &Sel, ICmpInst &Cmp, - InstCombinerImpl &IC) { +static Value *canonicalizeSPF(ICmpInst &Cmp, Value *TrueVal, Value *FalseVal, + InstCombinerImpl &IC) { Value *LHS, *RHS; // TODO: What to do with pointer min/max patterns? - if (!Sel.getType()->isIntOrIntVectorTy()) + if (!TrueVal->getType()->isIntOrIntVectorTy()) return nullptr; - SelectPatternFlavor SPF = matchSelectPattern(&Sel, LHS, RHS).Flavor; + SelectPatternFlavor SPF = + matchDecomposedSelectPattern(&Cmp, TrueVal, FalseVal, LHS, RHS).Flavor; if (SPF == SelectPatternFlavor::SPF_ABS || SPF == SelectPatternFlavor::SPF_NABS) { if (!Cmp.hasOneUse() && !RHS->hasOneUse()) @@ -1188,13 +1189,13 @@ static Instruction *canonicalizeSPF(SelectInst &Sel, ICmpInst &Cmp, bool IntMinIsPoison = SPF == SelectPatternFlavor::SPF_ABS && match(RHS, m_NSWNeg(m_Specific(LHS))); Constant *IntMinIsPoisonC = - ConstantInt::get(Type::getInt1Ty(Sel.getContext()), IntMinIsPoison); + ConstantInt::get(Type::getInt1Ty(Cmp.getContext()), IntMinIsPoison); Instruction *Abs = IC.Builder.CreateBinaryIntrinsic(Intrinsic::abs, LHS, IntMinIsPoisonC); if (SPF == SelectPatternFlavor::SPF_NABS) - return BinaryOperator::CreateNeg(Abs); // Always without NSW flag! - return IC.replaceInstUsesWith(Sel, Abs); + return IC.Builder.CreateNeg(Abs); // Always without NSW flag! + return Abs; } if (SelectPatternResult::isMinOrMax(SPF)) { @@ -1215,8 +1216,7 @@ static Instruction *canonicalizeSPF(SelectInst &Sel, ICmpInst &Cmp, default: llvm_unreachable("Unexpected SPF"); } - return IC.replaceInstUsesWith( - Sel, IC.Builder.CreateBinaryIntrinsic(IntrinsicID, LHS, RHS)); + return IC.Builder.CreateBinaryIntrinsic(IntrinsicID, LHS, RHS); } return nullptr; @@ -1677,8 +1677,9 @@ Instruction *InstCombinerImpl::foldSelectInstWithICmp(SelectInst &SI, if (Instruction *NewSel = foldSelectValueEquivalence(SI, *ICI)) return NewSel; - if (Instruction *NewSPF = canonicalizeSPF(SI, *ICI, *this)) - return NewSPF; + if (Value *V = + canonicalizeSPF(*ICI, SI.getTrueValue(), SI.getFalseValue(), *this)) + return replaceInstUsesWith(SI, V); if (Value *V = foldSelectInstWithICmpConst(SI, ICI, Builder)) return replaceInstUsesWith(SI, V); @@ -2363,6 +2364,9 @@ static Instruction *foldSelectToCopysign(SelectInst &Sel, Value *FVal = Sel.getFalseValue(); Type *SelType = Sel.getType(); + if (ICmpInst::makeCmpResultType(TVal->getType()) != Cond->getType()) + return nullptr; + // Match select ?, TC, FC where the constants are equal but negated. // TODO: Generalize to handle a negated variable operand? const APFloat *TC, *FC; @@ -3790,5 +3794,50 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) { if (Instruction *I = foldBitCeil(SI, Builder)) return I; + // Fold: + // (select A && B, T, F) -> (select A, (select B, T, F), F) + // (select A || B, T, F) -> (select A, T, (select B, T, F)) + // if (select B, T, F) is foldable. + // TODO: preserve FMF flags + auto FoldSelectWithAndOrCond = [&](bool IsAnd, Value *A, + Value *B) -> Instruction * { + if (Value *V = simplifySelectInst(B, TrueVal, FalseVal, + SQ.getWithInstruction(&SI))) + return SelectInst::Create(A, IsAnd ? V : TrueVal, IsAnd ? FalseVal : V); + + // Is (select B, T, F) a SPF? + if (CondVal->hasOneUse() && SelType->isIntOrIntVectorTy()) { + if (ICmpInst *Cmp = dyn_cast<ICmpInst>(B)) + if (Value *V = canonicalizeSPF(*Cmp, TrueVal, FalseVal, *this)) + return SelectInst::Create(A, IsAnd ? V : TrueVal, + IsAnd ? FalseVal : V); + } + + return nullptr; + }; + + Value *LHS, *RHS; + if (match(CondVal, m_And(m_Value(LHS), m_Value(RHS)))) { + if (Instruction *I = FoldSelectWithAndOrCond(/*IsAnd*/ true, LHS, RHS)) + return I; + if (Instruction *I = FoldSelectWithAndOrCond(/*IsAnd*/ true, RHS, LHS)) + return I; + } else if (match(CondVal, m_Or(m_Value(LHS), m_Value(RHS)))) { + if (Instruction *I = FoldSelectWithAndOrCond(/*IsAnd*/ false, LHS, RHS)) + return I; + if (Instruction *I = FoldSelectWithAndOrCond(/*IsAnd*/ false, RHS, LHS)) + return I; + } else { + // We cannot swap the operands of logical and/or. + // TODO: Can we swap the operands by inserting a freeze? + if (match(CondVal, m_LogicalAnd(m_Value(LHS), m_Value(RHS)))) { + if (Instruction *I = FoldSelectWithAndOrCond(/*IsAnd*/ true, LHS, RHS)) + return I; + } else if (match(CondVal, m_LogicalOr(m_Value(LHS), m_Value(RHS)))) { + if (Instruction *I = FoldSelectWithAndOrCond(/*IsAnd*/ false, LHS, RHS)) + return I; + } + } + return nullptr; } |
