mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-12-14 07:09:08 +00:00
[InstCombine] Try to reuse constant from select in leading comparison
Summary: If we have e.g.: ``` %t = icmp ult i32 %x, 65536 %r = select i1 %t, i32 %y, i32 65535 ``` the constants `65535` and `65536` are suspiciously close. We could perform a transformation to deduplicate them: ``` Name: ult %t = icmp ult i32 %x, 65536 %r = select i1 %t, i32 %y, i32 65535 => %t.inv = icmp ugt i32 %x, 65535 %r = select i1 %t.inv, i32 65535, i32 %y ``` https://rise4fun.com/Alive/avb While this may seem esoteric, this should certainly be good for vectors (less constant pool usage) and for opt-for-size - need to have only one constant. But the real fun part here is that it allows further transformation, in particular it finishes cleaning up the `clamp` folding, see e.g. `canonicalize-clamp-with-select-of-constant-threshold-pattern.ll`. We start with e.g. ``` %dont_need_to_clamp_positive = icmp sle i32 %X, 32767 %dont_need_to_clamp_negative = icmp sge i32 %X, -32768 %clamp_limit = select i1 %dont_need_to_clamp_positive, i32 -32768, i32 32767 %dont_need_to_clamp = and i1 %dont_need_to_clamp_positive, %dont_need_to_clamp_negative %R = select i1 %dont_need_to_clamp, i32 %X, i32 %clamp_limit ``` without this patch we currently produce ``` %1 = icmp slt i32 %X, 32768 %2 = icmp sgt i32 %X, -32768 %3 = select i1 %2, i32 %X, i32 -32768 %R = select i1 %1, i32 %3, i32 32767 ``` which isn't really a `clamp` - both comparisons are performed on the original value, this patch changes it into ``` %1.inv = icmp sgt i32 %X, 32767 %2 = icmp sgt i32 %X, -32768 %3 = select i1 %2, i32 %X, i32 -32768 %R = select i1 %1.inv, i32 32767, i32 %3 ``` and then the magic happens! Some further transform finishes polishing it and we finally get: ``` %t1 = icmp sgt i32 %X, -32768 %t2 = select i1 %t1, i32 %X, i32 -32768 %t3 = icmp slt i32 %t2, 32767 %R = select i1 %t3, i32 %t2, i32 32767 ``` which is beautiful and just what we want. Proofs for `getFlippedStrictnessPredicateAndConstant()` for de-canonicalization: https://rise4fun.com/Alive/THl Proofs for the fold itself: https://rise4fun.com/Alive/THl Reviewers: spatel, dmgreen, nikic, xbolva00 Reviewed By: spatel Subscribers: hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D66232 llvm-svn: 369840
This commit is contained in:
parent
190850ddfb
commit
c7933992b4
@ -4912,20 +4912,27 @@ llvm::Optional<std::pair<CmpInst::Predicate, Constant *>>
|
||||
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<ConstantInt>(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<ConstantInt>(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 @@ llvm::getFlippedStrictnessPredicateAndConstant(CmpInst::Predicate Pred,
|
||||
// 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<ConstantInt>(Elt);
|
||||
if (!CI || (IsLE ? CI->isMaxValue(IsSigned) : CI->isMinValue(IsSigned)))
|
||||
if (!CI || !ConstantIsOk(CI))
|
||||
return llvm::None;
|
||||
}
|
||||
} else {
|
||||
@ -4953,7 +4960,7 @@ llvm::getFlippedStrictnessPredicateAndConstant(CmpInst::Predicate Pred,
|
||||
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);
|
||||
|
@ -1261,6 +1261,95 @@ static Instruction *canonicalizeClampLike(SelectInst &Sel0, ICmpInst &Cmp0,
|
||||
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<Constant>(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 @@ Instruction *InstCombiner::foldSelectInstWithICmp(SelectInst &SI,
|
||||
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))
|
||||
|
@ -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 @t0_select_cond_and_v0(i32 %X) {
|
||||
}
|
||||
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 @t1_select_cond_and_v1(i32 %X) {
|
||||
|
||||
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 @t2_select_cond_or_v0(i32 %X) {
|
||||
}
|
||||
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 @t3_select_cond_or_v1(i32 %X) {
|
||||
|
||||
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_v0(i32 %X) {
|
||||
}
|
||||
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 @t4_select_cond_xor_v1(i32 %X) {
|
||||
|
||||
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_v2(i32 %X) {
|
||||
}
|
||||
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
|
||||
|
@ -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 @p0_ult_65536(i32 %x, i32 %y) {
|
||||
}
|
||||
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 @p1_ugt(i32 %x, i32 %y) {
|
||||
}
|
||||
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 @p2_slt_65536(i32 %x, i32 %y) {
|
||||
}
|
||||
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 i32 @p3_sgt(i32 %x, i32 %y) {
|
||||
|
||||
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:%.*]], <i32 65536, i32 65536>
|
||||
; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[T]], <2 x i32> [[Y:%.*]], <2 x i32> <i32 65535, i32 65535>
|
||||
; CHECK-NEXT: [[T_INV:%.*]] = icmp ugt <2 x i32> [[X:%.*]], <i32 65535, i32 65535>
|
||||
; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[T_INV]], <2 x i32> <i32 65535, i32 65535>, <2 x i32> [[Y:%.*]]
|
||||
; CHECK-NEXT: ret <2 x i32> [[R]]
|
||||
;
|
||||
%t = icmp ult <2 x i32> %x, <i32 65536, i32 65536>
|
||||
@ -73,8 +73,8 @@ define <2 x i32> @p4_vec_splat_ult_65536(<2 x i32> %x, <2 x i32> %y) {
|
||||
}
|
||||
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:%.*]], <i32 65534, i32 65534>
|
||||
; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[T]], <2 x i32> [[Y:%.*]], <2 x i32> <i32 65535, i32 65535>
|
||||
; CHECK-NEXT: [[T_INV:%.*]] = icmp ult <2 x i32> [[X:%.*]], <i32 65535, i32 65535>
|
||||
; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[T_INV]], <2 x i32> <i32 65535, i32 65535>, <2 x i32> [[Y:%.*]]
|
||||
; CHECK-NEXT: ret <2 x i32> [[R]]
|
||||
;
|
||||
%t = icmp ugt <2 x i32> %x, <i32 65534, i32 65534>
|
||||
@ -83,8 +83,8 @@ define <2 x i32> @p5_vec_splat_ugt(<2 x i32> %x, <2 x i32> %y) {
|
||||
}
|
||||
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:%.*]], <i32 65536, i32 65536>
|
||||
; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[T]], <2 x i32> [[Y:%.*]], <2 x i32> <i32 65535, i32 65535>
|
||||
; CHECK-NEXT: [[T_INV:%.*]] = icmp sgt <2 x i32> [[X:%.*]], <i32 65535, i32 65535>
|
||||
; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[T_INV]], <2 x i32> <i32 65535, i32 65535>, <2 x i32> [[Y:%.*]]
|
||||
; CHECK-NEXT: ret <2 x i32> [[R]]
|
||||
;
|
||||
%t = icmp slt <2 x i32> %x, <i32 65536, i32 65536>
|
||||
@ -93,8 +93,8 @@ define <2 x i32> @p6_vec_splat_slt_65536(<2 x i32> %x, <2 x i32> %y) {
|
||||
}
|
||||
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:%.*]], <i32 65534, i32 65534>
|
||||
; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[T]], <2 x i32> [[Y:%.*]], <2 x i32> <i32 65535, i32 65535>
|
||||
; CHECK-NEXT: [[T_INV:%.*]] = icmp slt <2 x i32> [[X:%.*]], <i32 65535, i32 65535>
|
||||
; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[T_INV]], <2 x i32> <i32 65535, i32 65535>, <2 x i32> [[Y:%.*]]
|
||||
; CHECK-NEXT: ret <2 x i32> [[R]]
|
||||
;
|
||||
%t = icmp sgt <2 x i32> %x, <i32 65534, i32 65534>
|
||||
@ -106,8 +106,8 @@ define <2 x i32> @p7_vec_splat_sgt(<2 x i32> %x, <2 x i32> %y) {
|
||||
|
||||
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:%.*]], <i32 65536, i32 undef>
|
||||
; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[T]], <2 x i32> [[Y:%.*]], <2 x i32> <i32 65535, i32 65535>
|
||||
; CHECK-NEXT: [[T_INV:%.*]] = icmp ugt <2 x i32> [[X:%.*]], <i32 65535, i32 undef>
|
||||
; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[T_INV]], <2 x i32> <i32 65535, i32 65535>, <2 x i32> [[Y:%.*]]
|
||||
; CHECK-NEXT: ret <2 x i32> [[R]]
|
||||
;
|
||||
%t = icmp ult <2 x i32> %x, <i32 65536, i32 undef>
|
||||
@ -116,8 +116,8 @@ define <2 x i32> @p8_vec_nonsplat_undef0(<2 x i32> %x, <2 x i32> %y) {
|
||||
}
|
||||
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:%.*]], <i32 65536, i32 65536>
|
||||
; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[T]], <2 x i32> [[Y:%.*]], <2 x i32> <i32 65535, i32 undef>
|
||||
; CHECK-NEXT: [[T_INV:%.*]] = icmp ugt <2 x i32> [[X:%.*]], <i32 65535, i32 65535>
|
||||
; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[T_INV]], <2 x i32> <i32 65535, i32 undef>, <2 x i32> [[Y:%.*]]
|
||||
; CHECK-NEXT: ret <2 x i32> [[R]]
|
||||
;
|
||||
%t = icmp ult <2 x i32> %x, <i32 65536, i32 65536>
|
||||
@ -126,8 +126,8 @@ define <2 x i32> @p9_vec_nonsplat_undef1(<2 x i32> %x, <2 x i32> %y) {
|
||||
}
|
||||
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:%.*]], <i32 65536, i32 undef>
|
||||
; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[T]], <2 x i32> [[Y:%.*]], <2 x i32> <i32 65535, i32 undef>
|
||||
; CHECK-NEXT: [[T_INV:%.*]] = icmp ugt <2 x i32> [[X:%.*]], <i32 65535, i32 undef>
|
||||
; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[T_INV]], <2 x i32> <i32 65535, i32 undef>, <2 x i32> [[Y:%.*]]
|
||||
; CHECK-NEXT: ret <2 x i32> [[R]]
|
||||
;
|
||||
%t = icmp ult <2 x i32> %x, <i32 65536, i32 undef>
|
||||
@ -139,8 +139,8 @@ define <2 x i32> @p10_vec_nonsplat_undef2(<2 x i32> %x, <2 x i32> %y) {
|
||||
|
||||
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:%.*]], <i32 65536, i32 32768>
|
||||
; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[T]], <2 x i32> [[Y:%.*]], <2 x i32> <i32 65535, i32 32767>
|
||||
; CHECK-NEXT: [[T_INV:%.*]] = icmp ugt <2 x i32> [[X:%.*]], <i32 65535, i32 32767>
|
||||
; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[T_INV]], <2 x i32> <i32 65535, i32 32767>, <2 x i32> [[Y:%.*]]
|
||||
; CHECK-NEXT: ret <2 x i32> [[R]]
|
||||
;
|
||||
%t = icmp ult <2 x i32> %x, <i32 65536, i32 32768>
|
||||
@ -174,8 +174,8 @@ define i32 @n12_extrause(i32 %x, i32 %y) {
|
||||
; 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 @@ define i32 @p13_commutativity0(i32 %x, i32 %y) {
|
||||
; 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 @p14_commutativity1(i32 %x, i32 %y) {
|
||||
}
|
||||
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 @@ define i32 @n21_equality(i32 %x, i32 %y) {
|
||||
; 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_check(i32 %x, i32 %y) {
|
||||
}
|
||||
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 @@ define i32 @n26_all_good1(i32 %x, i32 %y) {
|
||||
|
||||
|
||||
|
||||
; CHECK: !0 = !{!"branch_weights", i32 2000, i32 1}
|
||||
; CHECK: !0 = !{!"branch_weights", i32 1, i32 2000}
|
||||
|
@ -36,10 +36,14 @@ exit:
|
||||
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 @@ exit:
|
||||
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
|
||||
|
@ -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 @v1_select_of_var_and_const(i32 %X, i32 %Y, i32* %selected) {
|
||||
}
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user