Index: llvm/trunk/lib/Transforms/InstCombine/InstCombineCompares.cpp =================================================================== --- llvm/trunk/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ llvm/trunk/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -4912,20 +4912,27 @@ llvm::getFlippedStrictnessPredicateAndConstant(CmpInst::Predicate Pred, Constant *C) { assert(ICmpInst::isRelational(Pred) && ICmpInst::isIntPredicate(Pred) && - !isCanonicalPredicate(Pred) && - "Only for non-canonical relational integer predicates."); + "Only for relational integer predicates."); - // Check if the constant operand can be safely incremented/decremented without - // overflowing/underflowing. For scalars, SimplifyICmpInst should have already - // handled the edge cases for us, so we just assert on them. - // For vectors, we must handle the edge cases. Type *Type = C->getType(); bool IsSigned = ICmpInst::isSigned(Pred); - bool IsLE = (Pred == ICmpInst::ICMP_SLE || Pred == ICmpInst::ICMP_ULE); - auto *CI = dyn_cast(C); - if (CI) { + + CmpInst::Predicate UnsignedPred = ICmpInst::getUnsignedPredicate(Pred); + bool WillIncrement = + UnsignedPred == ICmpInst::ICMP_ULE || UnsignedPred == ICmpInst::ICMP_UGT; + + // Check if the constant operand can be safely incremented/decremented + // without overflowing/underflowing. + auto ConstantIsOk = [WillIncrement, IsSigned](ConstantInt *C) { + return WillIncrement ? !C->isMaxValue(IsSigned) : !C->isMinValue(IsSigned); + }; + + // For scalars, SimplifyICmpInst should have already handled + // the edge cases for us, so we just assert on them. + // For vectors, we must handle the edge cases. + if (auto *CI = dyn_cast(C)) { // A <= MAX -> TRUE ; A >= MIN -> TRUE - assert(IsLE ? !CI->isMaxValue(IsSigned) : !CI->isMinValue(IsSigned)); + assert(ConstantIsOk(CI)); } else if (Type->isVectorTy()) { // TODO? If the edge cases for vectors were guaranteed to be handled as they // are for scalar, we could remove the min/max checks. However, to do that, @@ -4942,7 +4949,7 @@ // Bail out if we can't determine if this constant is min/max or if we // know that this constant is min/max. auto *CI = dyn_cast(Elt); - if (!CI || (IsLE ? CI->isMaxValue(IsSigned) : CI->isMinValue(IsSigned))) + if (!CI || !ConstantIsOk(CI)) return llvm::None; } } else { @@ -4953,7 +4960,7 @@ CmpInst::Predicate NewPred = CmpInst::getFlippedStrictnessPredicate(Pred); // Increment or decrement the constant. - Constant *OneOrNegOne = ConstantInt::get(Type, IsLE ? 1 : -1, true); + Constant *OneOrNegOne = ConstantInt::get(Type, WillIncrement ? 1 : -1, true); Constant *NewC = ConstantExpr::getAdd(C, OneOrNegOne); return std::make_pair(NewPred, NewC); Index: llvm/trunk/lib/Transforms/InstCombine/InstCombineSelect.cpp =================================================================== --- llvm/trunk/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ llvm/trunk/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -1261,6 +1261,95 @@ return MaybeReplacedHigh; } +// If we have +// %cmp = icmp [canonical predicate] i32 %x, C0 +// %r = select i1 %cmp, i32 %y, i32 C1 +// Where C0 != C1 and %x may be different from %y, see if the constant that we +// will have if we flip the strictness of the predicate (i.e. without changing +// the result) is identical to the C1 in select. If it matches we can change +// original comparison to one with swapped predicate, reuse the constant, +// and swap the hands of select. +static Instruction * +tryToReuseConstantFromSelectInComparison(SelectInst &Sel, ICmpInst &Cmp, + InstCombiner::BuilderTy &Builder) { + ICmpInst::Predicate Pred; + Value *X; + Constant *C0; + if (!match(&Cmp, m_OneUse(m_ICmp( + Pred, m_Value(X), + m_CombineAnd(m_AnyIntegralConstant(), m_Constant(C0)))))) + return nullptr; + + // If comparison predicate is non-relational, we won't be able to do anything. + if (ICmpInst::isEquality(Pred)) + return nullptr; + + // If comparison predicate is non-canonical, then we certainly won't be able + // to make it canonical; canonicalizeCmpWithConstant() already tried. + if (!isCanonicalPredicate(Pred)) + return nullptr; + + // If the [input] type of comparison and select type are different, lets abort + // for now. We could try to compare constants with trunc/[zs]ext though. + if (C0->getType() != Sel.getType()) + return nullptr; + + // FIXME: are there any magic icmp predicate+constant pairs we must not touch? + + auto ConstantsAreElementWiseEqual = [](Constant *Cx, Value *Y) { + // Are they fully identical? + if (Cx == Y) + return true; + // They may still be identical element-wise (if they have `undef`s). + auto *Cy = dyn_cast(Y); + if (!Cy) + return false; + return match(ConstantExpr::getICmp(ICmpInst::Predicate::ICMP_EQ, Cx, Cy), + m_One()); + }; + + Value *SelVal0, *SelVal1; // We do not care which one is from where. + match(&Sel, m_Select(m_Value(), m_Value(SelVal0), m_Value(SelVal1))); + // At least one of these values we are selecting between must be a constant + // else we'll never succeed. + if (!match(SelVal0, m_AnyIntegralConstant()) && + !match(SelVal1, m_AnyIntegralConstant())) + return nullptr; + + // Does this constant C match any of the `select` values? + auto MatchesSelectValue = [ConstantsAreElementWiseEqual, SelVal0, + SelVal1](Constant *C) { + return ConstantsAreElementWiseEqual(C, SelVal0) || + ConstantsAreElementWiseEqual(C, SelVal1); + }; + + // If C0 *already* matches true/false value of select, we are done. + if (MatchesSelectValue(C0)) + return nullptr; + + // Check the constant we'd have with flipped-strictness predicate. + auto FlippedStrictness = getFlippedStrictnessPredicateAndConstant(Pred, C0); + if (!FlippedStrictness) + return nullptr; + + // If said constant doesn't match either, then there is no hope, + if (!MatchesSelectValue(FlippedStrictness->second)) + return nullptr; + + // It matched! Lets insert the new comparison just before select. + InstCombiner::BuilderTy::InsertPointGuard Guard(Builder); + Builder.SetInsertPoint(&Sel); + + Pred = ICmpInst::getSwappedPredicate(Pred); // Yes, swapped. + Value *NewCmp = Builder.CreateICmp(Pred, X, FlippedStrictness->second, + Cmp.getName() + ".inv"); + Sel.setCondition(NewCmp); + Sel.swapValues(); + Sel.swapProfMetadata(); + + return &Sel; +} + /// Visit a SelectInst that has an ICmpInst as its first operand. Instruction *InstCombiner::foldSelectInstWithICmp(SelectInst &SI, ICmpInst *ICI) { @@ -1276,6 +1365,10 @@ if (Instruction *NewAbs = canonicalizeClampLike(SI, *ICI, Builder)) return NewAbs; + if (Instruction *NewSel = + tryToReuseConstantFromSelectInComparison(SI, *ICI, Builder)) + return NewSel; + bool Changed = adjustMinMax(SI, *ICI); if (Value *V = foldSelectICmpAnd(SI, ICI, Builder)) Index: llvm/trunk/test/Transforms/InstCombine/canonicalize-clamp-with-select-of-constant-threshold-pattern.ll =================================================================== --- llvm/trunk/test/Transforms/InstCombine/canonicalize-clamp-with-select-of-constant-threshold-pattern.ll +++ llvm/trunk/test/Transforms/InstCombine/canonicalize-clamp-with-select-of-constant-threshold-pattern.ll @@ -7,10 +7,10 @@ define i32 @t0_select_cond_and_v0(i32 %X) { ; CHECK-LABEL: @t0_select_cond_and_v0( -; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[X:%.*]], 32768 -; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i32 [[X]], -32768 -; CHECK-NEXT: [[TMP3:%.*]] = select i1 [[TMP2]], i32 [[X]], i32 -32768 -; CHECK-NEXT: [[R:%.*]] = select i1 [[TMP1]], i32 [[TMP3]], i32 32767 +; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i32 [[X:%.*]], -32768 +; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 -32768 +; CHECK-NEXT: [[TMP3:%.*]] = icmp slt i32 [[TMP2]], 32767 +; CHECK-NEXT: [[R:%.*]] = select i1 [[TMP3]], i32 [[TMP2]], i32 32767 ; CHECK-NEXT: ret i32 [[R]] ; %dont_need_to_clamp_positive = icmp sle i32 %X, 32767 @@ -22,10 +22,10 @@ } define i32 @t1_select_cond_and_v1(i32 %X) { ; CHECK-LABEL: @t1_select_cond_and_v1( -; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[X:%.*]], 32768 -; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i32 [[X]], -32768 -; CHECK-NEXT: [[TMP3:%.*]] = select i1 [[TMP2]], i32 [[X]], i32 -32768 -; CHECK-NEXT: [[R:%.*]] = select i1 [[TMP1]], i32 [[TMP3]], i32 32767 +; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i32 [[X:%.*]], -32768 +; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 -32768 +; CHECK-NEXT: [[TMP3:%.*]] = icmp slt i32 [[TMP2]], 32767 +; CHECK-NEXT: [[R:%.*]] = select i1 [[TMP3]], i32 [[TMP2]], i32 32767 ; CHECK-NEXT: ret i32 [[R]] ; %dont_need_to_clamp_positive = icmp sle i32 %X, 32767 @@ -40,10 +40,10 @@ define i32 @t2_select_cond_or_v0(i32 %X) { ; CHECK-LABEL: @t2_select_cond_or_v0( -; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[X:%.*]], 32768 -; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i32 [[X]], -32768 -; CHECK-NEXT: [[TMP3:%.*]] = select i1 [[TMP2]], i32 [[X]], i32 -32768 -; CHECK-NEXT: [[R:%.*]] = select i1 [[TMP1]], i32 [[TMP3]], i32 32767 +; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i32 [[X:%.*]], -32768 +; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 -32768 +; CHECK-NEXT: [[TMP3:%.*]] = icmp slt i32 [[TMP2]], 32767 +; CHECK-NEXT: [[R:%.*]] = select i1 [[TMP3]], i32 [[TMP2]], i32 32767 ; CHECK-NEXT: ret i32 [[R]] ; %need_to_clamp_positive = icmp sgt i32 %X, 32767 @@ -55,10 +55,10 @@ } define i32 @t3_select_cond_or_v1(i32 %X) { ; CHECK-LABEL: @t3_select_cond_or_v1( -; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[X:%.*]], 32768 -; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i32 [[X]], -32768 -; CHECK-NEXT: [[TMP3:%.*]] = select i1 [[TMP2]], i32 [[X]], i32 -32768 -; CHECK-NEXT: [[R:%.*]] = select i1 [[TMP1]], i32 [[TMP3]], i32 32767 +; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i32 [[X:%.*]], -32768 +; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 -32768 +; CHECK-NEXT: [[TMP3:%.*]] = icmp slt i32 [[TMP2]], 32767 +; CHECK-NEXT: [[R:%.*]] = select i1 [[TMP3]], i32 [[TMP2]], i32 32767 ; CHECK-NEXT: ret i32 [[R]] ; %need_to_clamp_positive = icmp sgt i32 %X, 32767 @@ -73,10 +73,10 @@ define i32 @t4_select_cond_xor_v0(i32 %X) { ; CHECK-LABEL: @t4_select_cond_xor_v0( -; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[X:%.*]], 32768 -; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i32 [[X]], -32768 -; CHECK-NEXT: [[TMP3:%.*]] = select i1 [[TMP2]], i32 [[X]], i32 -32768 -; CHECK-NEXT: [[R:%.*]] = select i1 [[TMP1]], i32 [[TMP3]], i32 32767 +; CHECK-NEXT: [[DOTINV1:%.*]] = icmp sgt i32 [[X:%.*]], -32768 +; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[DOTINV1]], i32 [[X]], i32 -32768 +; CHECK-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP1]], 32767 +; CHECK-NEXT: [[R:%.*]] = select i1 [[TMP2]], i32 [[TMP1]], i32 32767 ; CHECK-NEXT: ret i32 [[R]] ; %need_to_clamp_positive = icmp sgt i32 %X, 32767 @@ -88,10 +88,10 @@ } define i32 @t4_select_cond_xor_v1(i32 %X) { ; CHECK-LABEL: @t4_select_cond_xor_v1( -; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[X:%.*]], 32768 -; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i32 [[X]], -32768 -; CHECK-NEXT: [[TMP3:%.*]] = select i1 [[TMP2]], i32 [[X]], i32 -32768 -; CHECK-NEXT: [[R:%.*]] = select i1 [[TMP1]], i32 [[TMP3]], i32 32767 +; CHECK-NEXT: [[DOTINV1:%.*]] = icmp sgt i32 [[X:%.*]], -32768 +; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[DOTINV1]], i32 [[X]], i32 -32768 +; CHECK-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP1]], 32767 +; CHECK-NEXT: [[R:%.*]] = select i1 [[TMP2]], i32 [[TMP1]], i32 32767 ; CHECK-NEXT: ret i32 [[R]] ; %need_to_clamp_positive = icmp sgt i32 %X, 32767 @@ -104,10 +104,10 @@ define i32 @t5_select_cond_xor_v2(i32 %X) { ; CHECK-LABEL: @t5_select_cond_xor_v2( -; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[X:%.*]], 32768 -; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i32 [[X]], -32768 -; CHECK-NEXT: [[TMP3:%.*]] = select i1 [[TMP2]], i32 [[X]], i32 -32768 -; CHECK-NEXT: [[R:%.*]] = select i1 [[TMP1]], i32 [[TMP3]], i32 32767 +; CHECK-NEXT: [[DOTINV1:%.*]] = icmp sgt i32 [[X:%.*]], -32768 +; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[DOTINV1]], i32 [[X]], i32 -32768 +; CHECK-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP1]], 32767 +; CHECK-NEXT: [[R:%.*]] = select i1 [[TMP2]], i32 [[TMP1]], i32 32767 ; CHECK-NEXT: ret i32 [[R]] ; %dont_need_to_clamp_positive = icmp sle i32 %X, 32767 @@ -119,10 +119,10 @@ } define i32 @t5_select_cond_xor_v3(i32 %X) { ; CHECK-LABEL: @t5_select_cond_xor_v3( -; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[X:%.*]], 32768 -; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i32 [[X]], -32768 -; CHECK-NEXT: [[TMP3:%.*]] = select i1 [[TMP2]], i32 [[X]], i32 -32768 -; CHECK-NEXT: [[R:%.*]] = select i1 [[TMP1]], i32 [[TMP3]], i32 32767 +; CHECK-NEXT: [[DOTINV1:%.*]] = icmp sgt i32 [[X:%.*]], -32768 +; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[DOTINV1]], i32 [[X]], i32 -32768 +; CHECK-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP1]], 32767 +; CHECK-NEXT: [[R:%.*]] = select i1 [[TMP2]], i32 [[TMP1]], i32 32767 ; CHECK-NEXT: ret i32 [[R]] ; %dont_need_to_clamp_positive = icmp sle i32 %X, 32767 Index: llvm/trunk/test/Transforms/InstCombine/reuse-constant-from-select-in-icmp.ll =================================================================== --- llvm/trunk/test/Transforms/InstCombine/reuse-constant-from-select-in-icmp.ll +++ llvm/trunk/test/Transforms/InstCombine/reuse-constant-from-select-in-icmp.ll @@ -18,8 +18,8 @@ define i32 @p0_ult_65536(i32 %x, i32 %y) { ; CHECK-LABEL: @p0_ult_65536( -; CHECK-NEXT: [[T:%.*]] = icmp ult i32 [[X:%.*]], 65536 -; CHECK-NEXT: [[R:%.*]] = select i1 [[T]], i32 [[Y:%.*]], i32 65535, !prof !0 +; CHECK-NEXT: [[T_INV:%.*]] = icmp ugt i32 [[X:%.*]], 65535 +; CHECK-NEXT: [[R:%.*]] = select i1 [[T_INV]], i32 65535, i32 [[Y:%.*]], !prof !0 ; CHECK-NEXT: ret i32 [[R]] ; %t = icmp ult i32 %x, 65536 @@ -28,8 +28,8 @@ } define i32 @p1_ugt(i32 %x, i32 %y) { ; CHECK-LABEL: @p1_ugt( -; CHECK-NEXT: [[T:%.*]] = icmp ugt i32 [[X:%.*]], 65534 -; CHECK-NEXT: [[R:%.*]] = select i1 [[T]], i32 [[Y:%.*]], i32 65535 +; CHECK-NEXT: [[T_INV:%.*]] = icmp ult i32 [[X:%.*]], 65535 +; CHECK-NEXT: [[R:%.*]] = select i1 [[T_INV]], i32 65535, i32 [[Y:%.*]] ; CHECK-NEXT: ret i32 [[R]] ; %t = icmp ugt i32 %x, 65534 @@ -38,8 +38,8 @@ } define i32 @p2_slt_65536(i32 %x, i32 %y) { ; CHECK-LABEL: @p2_slt_65536( -; CHECK-NEXT: [[T:%.*]] = icmp slt i32 [[X:%.*]], 65536 -; CHECK-NEXT: [[R:%.*]] = select i1 [[T]], i32 [[Y:%.*]], i32 65535 +; CHECK-NEXT: [[T_INV:%.*]] = icmp sgt i32 [[X:%.*]], 65535 +; CHECK-NEXT: [[R:%.*]] = select i1 [[T_INV]], i32 65535, i32 [[Y:%.*]] ; CHECK-NEXT: ret i32 [[R]] ; %t = icmp slt i32 %x, 65536 @@ -48,8 +48,8 @@ } define i32 @p3_sgt(i32 %x, i32 %y) { ; CHECK-LABEL: @p3_sgt( -; CHECK-NEXT: [[T:%.*]] = icmp sgt i32 [[X:%.*]], 65534 -; CHECK-NEXT: [[R:%.*]] = select i1 [[T]], i32 [[Y:%.*]], i32 65535 +; CHECK-NEXT: [[T_INV:%.*]] = icmp slt i32 [[X:%.*]], 65535 +; CHECK-NEXT: [[R:%.*]] = select i1 [[T_INV]], i32 65535, i32 [[Y:%.*]] ; CHECK-NEXT: ret i32 [[R]] ; %t = icmp sgt i32 %x, 65534 @@ -63,8 +63,8 @@ define <2 x i32> @p4_vec_splat_ult_65536(<2 x i32> %x, <2 x i32> %y) { ; CHECK-LABEL: @p4_vec_splat_ult_65536( -; CHECK-NEXT: [[T:%.*]] = icmp ult <2 x i32> [[X:%.*]], -; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[T]], <2 x i32> [[Y:%.*]], <2 x i32> +; CHECK-NEXT: [[T_INV:%.*]] = icmp ugt <2 x i32> [[X:%.*]], +; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[T_INV]], <2 x i32> , <2 x i32> [[Y:%.*]] ; CHECK-NEXT: ret <2 x i32> [[R]] ; %t = icmp ult <2 x i32> %x, @@ -73,8 +73,8 @@ } define <2 x i32> @p5_vec_splat_ugt(<2 x i32> %x, <2 x i32> %y) { ; CHECK-LABEL: @p5_vec_splat_ugt( -; CHECK-NEXT: [[T:%.*]] = icmp ugt <2 x i32> [[X:%.*]], -; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[T]], <2 x i32> [[Y:%.*]], <2 x i32> +; CHECK-NEXT: [[T_INV:%.*]] = icmp ult <2 x i32> [[X:%.*]], +; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[T_INV]], <2 x i32> , <2 x i32> [[Y:%.*]] ; CHECK-NEXT: ret <2 x i32> [[R]] ; %t = icmp ugt <2 x i32> %x, @@ -83,8 +83,8 @@ } define <2 x i32> @p6_vec_splat_slt_65536(<2 x i32> %x, <2 x i32> %y) { ; CHECK-LABEL: @p6_vec_splat_slt_65536( -; CHECK-NEXT: [[T:%.*]] = icmp slt <2 x i32> [[X:%.*]], -; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[T]], <2 x i32> [[Y:%.*]], <2 x i32> +; CHECK-NEXT: [[T_INV:%.*]] = icmp sgt <2 x i32> [[X:%.*]], +; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[T_INV]], <2 x i32> , <2 x i32> [[Y:%.*]] ; CHECK-NEXT: ret <2 x i32> [[R]] ; %t = icmp slt <2 x i32> %x, @@ -93,8 +93,8 @@ } define <2 x i32> @p7_vec_splat_sgt(<2 x i32> %x, <2 x i32> %y) { ; CHECK-LABEL: @p7_vec_splat_sgt( -; CHECK-NEXT: [[T:%.*]] = icmp sgt <2 x i32> [[X:%.*]], -; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[T]], <2 x i32> [[Y:%.*]], <2 x i32> +; CHECK-NEXT: [[T_INV:%.*]] = icmp slt <2 x i32> [[X:%.*]], +; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[T_INV]], <2 x i32> , <2 x i32> [[Y:%.*]] ; CHECK-NEXT: ret <2 x i32> [[R]] ; %t = icmp sgt <2 x i32> %x, @@ -106,8 +106,8 @@ define <2 x i32> @p8_vec_nonsplat_undef0(<2 x i32> %x, <2 x i32> %y) { ; CHECK-LABEL: @p8_vec_nonsplat_undef0( -; CHECK-NEXT: [[T:%.*]] = icmp ult <2 x i32> [[X:%.*]], -; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[T]], <2 x i32> [[Y:%.*]], <2 x i32> +; CHECK-NEXT: [[T_INV:%.*]] = icmp ugt <2 x i32> [[X:%.*]], +; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[T_INV]], <2 x i32> , <2 x i32> [[Y:%.*]] ; CHECK-NEXT: ret <2 x i32> [[R]] ; %t = icmp ult <2 x i32> %x, @@ -116,8 +116,8 @@ } define <2 x i32> @p9_vec_nonsplat_undef1(<2 x i32> %x, <2 x i32> %y) { ; CHECK-LABEL: @p9_vec_nonsplat_undef1( -; CHECK-NEXT: [[T:%.*]] = icmp ult <2 x i32> [[X:%.*]], -; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[T]], <2 x i32> [[Y:%.*]], <2 x i32> +; CHECK-NEXT: [[T_INV:%.*]] = icmp ugt <2 x i32> [[X:%.*]], +; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[T_INV]], <2 x i32> , <2 x i32> [[Y:%.*]] ; CHECK-NEXT: ret <2 x i32> [[R]] ; %t = icmp ult <2 x i32> %x, @@ -126,8 +126,8 @@ } define <2 x i32> @p10_vec_nonsplat_undef2(<2 x i32> %x, <2 x i32> %y) { ; CHECK-LABEL: @p10_vec_nonsplat_undef2( -; CHECK-NEXT: [[T:%.*]] = icmp ult <2 x i32> [[X:%.*]], -; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[T]], <2 x i32> [[Y:%.*]], <2 x i32> +; CHECK-NEXT: [[T_INV:%.*]] = icmp ugt <2 x i32> [[X:%.*]], +; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[T_INV]], <2 x i32> , <2 x i32> [[Y:%.*]] ; CHECK-NEXT: ret <2 x i32> [[R]] ; %t = icmp ult <2 x i32> %x, @@ -139,8 +139,8 @@ define <2 x i32> @p11_vec_nonsplat(<2 x i32> %x, <2 x i32> %y) { ; CHECK-LABEL: @p11_vec_nonsplat( -; CHECK-NEXT: [[T:%.*]] = icmp ult <2 x i32> [[X:%.*]], -; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[T]], <2 x i32> [[Y:%.*]], <2 x i32> +; CHECK-NEXT: [[T_INV:%.*]] = icmp ugt <2 x i32> [[X:%.*]], +; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[T_INV]], <2 x i32> , <2 x i32> [[Y:%.*]] ; CHECK-NEXT: ret <2 x i32> [[R]] ; %t = icmp ult <2 x i32> %x, @@ -174,8 +174,8 @@ ; We don't care if the constant in select is true value or false value define i32 @p13_commutativity0(i32 %x, i32 %y) { ; CHECK-LABEL: @p13_commutativity0( -; CHECK-NEXT: [[T:%.*]] = icmp ult i32 [[X:%.*]], 65536 -; CHECK-NEXT: [[R:%.*]] = select i1 [[T]], i32 65535, i32 [[Y:%.*]] +; CHECK-NEXT: [[T_INV:%.*]] = icmp ugt i32 [[X:%.*]], 65535 +; CHECK-NEXT: [[R:%.*]] = select i1 [[T_INV]], i32 [[Y:%.*]], i32 65535 ; CHECK-NEXT: ret i32 [[R]] ; %t = icmp ult i32 %x, 65536 @@ -186,8 +186,8 @@ ; Which means, if both possibilities are constants, we must check both of them. define i32 @p14_commutativity1(i32 %x, i32 %y) { ; CHECK-LABEL: @p14_commutativity1( -; CHECK-NEXT: [[T:%.*]] = icmp ult i32 [[X:%.*]], 65536 -; CHECK-NEXT: [[R:%.*]] = select i1 [[T]], i32 65535, i32 42 +; CHECK-NEXT: [[T_INV:%.*]] = icmp ugt i32 [[X:%.*]], 65535 +; CHECK-NEXT: [[R:%.*]] = select i1 [[T_INV]], i32 42, i32 65535 ; CHECK-NEXT: ret i32 [[R]] ; %t = icmp ult i32 %x, 65536 @@ -196,8 +196,8 @@ } define i32 @p15_commutativity2(i32 %x, i32 %y) { ; CHECK-LABEL: @p15_commutativity2( -; CHECK-NEXT: [[T:%.*]] = icmp ult i32 [[X:%.*]], 65536 -; CHECK-NEXT: [[R:%.*]] = select i1 [[T]], i32 42, i32 65535 +; CHECK-NEXT: [[T_INV:%.*]] = icmp ugt i32 [[X:%.*]], 65535 +; CHECK-NEXT: [[R:%.*]] = select i1 [[T_INV]], i32 65535, i32 42 ; CHECK-NEXT: ret i32 [[R]] ; %t = icmp ult i32 %x, 65536 @@ -266,8 +266,8 @@ ; There is nothing special about sign-bit-tests, we can fold them. define i32 @t22_sign_check(i32 %x, i32 %y) { ; CHECK-LABEL: @t22_sign_check( -; CHECK-NEXT: [[T:%.*]] = icmp slt i32 [[X:%.*]], 0 -; CHECK-NEXT: [[R:%.*]] = select i1 [[T]], i32 -1, i32 [[Y:%.*]] +; CHECK-NEXT: [[T_INV:%.*]] = icmp sgt i32 [[X:%.*]], -1 +; CHECK-NEXT: [[R:%.*]] = select i1 [[T_INV]], i32 [[Y:%.*]], i32 -1 ; CHECK-NEXT: ret i32 [[R]] ; %t = icmp slt i32 %x, 0 @@ -276,8 +276,8 @@ } define i32 @t22_sign_check2(i32 %x, i32 %y) { ; CHECK-LABEL: @t22_sign_check2( -; CHECK-NEXT: [[T:%.*]] = icmp sgt i32 [[X:%.*]], -1 -; CHECK-NEXT: [[R:%.*]] = select i1 [[T]], i32 0, i32 [[Y:%.*]] +; CHECK-NEXT: [[T_INV:%.*]] = icmp slt i32 [[X:%.*]], 0 +; CHECK-NEXT: [[R:%.*]] = select i1 [[T_INV]], i32 [[Y:%.*]], i32 0 ; CHECK-NEXT: ret i32 [[R]] ; %t = icmp sgt i32 %x, -1 @@ -333,4 +333,4 @@ -; CHECK: !0 = !{!"branch_weights", i32 2000, i32 1} +; CHECK: !0 = !{!"branch_weights", i32 1, i32 2000} Index: llvm/trunk/test/Transforms/InstCombine/unrecognized_three-way-comparison.ll =================================================================== --- llvm/trunk/test/Transforms/InstCombine/unrecognized_three-way-comparison.ll +++ llvm/trunk/test/Transforms/InstCombine/unrecognized_three-way-comparison.ll @@ -36,10 +36,14 @@ define i32 @compare_against_zero(i32 %x) { ; CHECK-LABEL: @compare_against_zero( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[TMP0:%.*]] = icmp sgt i32 [[X:%.*]], 0 -; CHECK-NEXT: br i1 [[TMP0]], label [[CALLFOO:%.*]], label [[EXIT:%.*]] +; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[X:%.*]], 0 +; CHECK-NEXT: [[CMP2_INV:%.*]] = icmp sgt i32 [[X]], -1 +; CHECK-NEXT: [[SELECT1:%.*]] = select i1 [[CMP2_INV]], i32 1, i32 -1 +; CHECK-NEXT: [[SELECT2:%.*]] = select i1 [[CMP1]], i32 0, i32 [[SELECT1]] +; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 [[SELECT2]], 0 +; CHECK-NEXT: br i1 [[COND]], label [[CALLFOO:%.*]], label [[EXIT:%.*]] ; CHECK: callfoo: -; CHECK-NEXT: call void @foo(i32 1) +; CHECK-NEXT: call void @foo(i32 [[SELECT2]]) ; CHECK-NEXT: br label [[EXIT]] ; CHECK: exit: ; CHECK-NEXT: ret i32 42 @@ -92,10 +96,14 @@ define i32 @compare_against_two(i32 %x) { ; CHECK-LABEL: @compare_against_two( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[TMP0:%.*]] = icmp sgt i32 [[X:%.*]], 2 -; CHECK-NEXT: br i1 [[TMP0]], label [[CALLFOO:%.*]], label [[EXIT:%.*]] +; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[X:%.*]], 2 +; CHECK-NEXT: [[CMP2_INV:%.*]] = icmp sgt i32 [[X]], 1 +; CHECK-NEXT: [[SELECT1:%.*]] = select i1 [[CMP2_INV]], i32 1, i32 -1 +; CHECK-NEXT: [[SELECT2:%.*]] = select i1 [[CMP1]], i32 0, i32 [[SELECT1]] +; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 [[SELECT2]], 0 +; CHECK-NEXT: br i1 [[COND]], label [[CALLFOO:%.*]], label [[EXIT:%.*]] ; CHECK: callfoo: -; CHECK-NEXT: call void @foo(i32 1) +; CHECK-NEXT: call void @foo(i32 [[SELECT2]]) ; CHECK-NEXT: br label [[EXIT]] ; CHECK: exit: ; CHECK-NEXT: ret i32 42 Index: llvm/trunk/test/Transforms/InstCombine/xor-of-icmps-with-extra-uses.ll =================================================================== --- llvm/trunk/test/Transforms/InstCombine/xor-of-icmps-with-extra-uses.ll +++ llvm/trunk/test/Transforms/InstCombine/xor-of-icmps-with-extra-uses.ll @@ -7,8 +7,8 @@ ; %cond0 is extra-used in select, which is freely invertible. define i1 @v0_select_of_consts(i32 %X, i32* %selected) { ; CHECK-LABEL: @v0_select_of_consts( -; CHECK-NEXT: [[COND0:%.*]] = icmp slt i32 [[X:%.*]], 32768 -; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND0]], i32 -32768, i32 32767 +; CHECK-NEXT: [[COND0_INV:%.*]] = icmp sgt i32 [[X:%.*]], 32767 +; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND0_INV]], i32 32767, i32 -32768 ; CHECK-NEXT: store i32 [[SELECT]], i32* [[SELECTED:%.*]], align 4 ; CHECK-NEXT: [[X_OFF:%.*]] = add i32 [[X]], 32767 ; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[X_OFF]], 65535 @@ -39,8 +39,8 @@ } define i1 @v2_select_of_const_and_var(i32 %X, i32 %Y, i32* %selected) { ; CHECK-LABEL: @v2_select_of_const_and_var( -; CHECK-NEXT: [[COND0:%.*]] = icmp slt i32 [[X:%.*]], 32768 -; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND0]], i32 [[Y:%.*]], i32 32767 +; CHECK-NEXT: [[COND0_INV:%.*]] = icmp sgt i32 [[X:%.*]], 32767 +; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND0_INV]], i32 32767, i32 [[Y:%.*]] ; CHECK-NEXT: store i32 [[SELECT]], i32* [[SELECTED:%.*]], align 4 ; CHECK-NEXT: [[X_OFF:%.*]] = add i32 [[X]], 32767 ; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[X_OFF]], 65535