This removes the restriction for the icmp constant, but as noted by the FIXME comments,
we still need to change individual checks for binop operand constants.
llvm-svn: 277629
/// Simplify icmp_eq and icmp_ne instructions with binary operator LHS and
/// integer constant RHS.
Instruction *InstCombiner::foldICmpEqualityWithConstant(ICmpInst &ICI) {
- // FIXME: If we use m_APInt() instead of m_ConstantInt(), it would enable
- // vector types with constant splat vectors to be optimized too.
BinaryOperator *BO;
- ConstantInt *RHS;
+ const APInt *RHSV;
+ // FIXME: Some of these folds could work with arbitrary constants, but this
+ // match is limited to scalars and vector splat constants.
if (!ICI.isEquality() || !match(ICI.getOperand(0), m_BinOp(BO)) ||
- !match(ICI.getOperand(1), m_ConstantInt(RHS)))
+ !match(ICI.getOperand(1), m_APInt(RHSV)))
return nullptr;
- const APInt &RHSV = RHS->getValue();
+ Constant *RHS = cast<Constant>(ICI.getOperand(1));
bool isICMP_NE = ICI.getPredicate() == ICmpInst::ICMP_NE;
Value *BOp0 = BO->getOperand(0), *BOp1 = BO->getOperand(1);
switch (BO->getOpcode()) {
case Instruction::SRem:
// If we have a signed (X % (2^c)) == 0, turn it into an unsigned one.
- if (RHSV == 0 && isa<ConstantInt>(BOp1) && BO->hasOneUse()) {
+ // FIXME: Vectors are excluded by ConstantInt.
+ if (*RHSV == 0 && isa<ConstantInt>(BOp1) && BO->hasOneUse()) {
const APInt &V = cast<ConstantInt>(BOp1)->getValue();
if (V.sgt(1) && V.isPowerOf2()) {
Value *NewRem = Builder->CreateURem(BOp0, BOp1, BO->getName());
break;
case Instruction::Add:
// Replace ((add A, B) != C) with (A != C-B) if B & C are constants.
+ // FIXME: Vectors are excluded by ConstantInt.
if (ConstantInt *BOp1C = dyn_cast<ConstantInt>(BOp1)) {
if (BO->hasOneUse())
return new ICmpInst(ICI.getPredicate(), BOp0,
ConstantExpr::getSub(RHS, BOp1C));
- } else if (RHSV == 0) {
+ } else if (*RHSV == 0) {
// Replace ((add A, B) != 0) with (A != -B) if A or B is
// efficiently invertible, or if the add has just this one use.
if (Value *NegVal = dyn_castNegVal(BOp1))
// the explicit xor.
return new ICmpInst(ICI.getPredicate(), BOp0,
ConstantExpr::getXor(RHS, BOC));
- } else if (RHSV == 0) {
+ } else if (*RHSV == 0) {
// Replace ((xor A, B) != 0) with (A != B)
return new ICmpInst(ICI.getPredicate(), BOp0, BOp1);
}
break;
case Instruction::Sub:
if (BO->hasOneUse()) {
+ // FIXME: Vectors are excluded by ConstantInt.
if (ConstantInt *BOp0C = dyn_cast<ConstantInt>(BOp0)) {
// Replace ((sub A, B) != C) with (B != A-C) if A & C are constants.
return new ICmpInst(ICI.getPredicate(), BOp1,
ConstantExpr::getSub(BOp0C, RHS));
- } else if (RHSV == 0) {
+ } else if (*RHSV == 0) {
// Replace ((sub A, B) != 0) with (A != B)
return new ICmpInst(ICI.getPredicate(), BOp0, BOp1);
}
case Instruction::Or:
// If bits are being or'd in that are not present in the constant we
// are comparing against, then the comparison could never succeed!
+ // FIXME: Vectors are excluded by ConstantInt.
if (ConstantInt *BOC = dyn_cast<ConstantInt>(BOp1)) {
Constant *NotCI = ConstantExpr::getNot(RHS);
if (!ConstantExpr::getAnd(BOC, NotCI)->isNullValue())
break;
case Instruction::And:
+ // FIXME: Vectors are excluded by ConstantInt.
if (ConstantInt *BOC = dyn_cast<ConstantInt>(BOp1)) {
// If bits are being compared against that are and'd out, then the
// comparison can never succeed!
- if ((RHSV & ~BOC->getValue()) != 0)
+ if ((*RHSV & ~BOC->getValue()) != 0)
return replaceInstUsesWith(ICI, Builder->getInt1(isICMP_NE));
// If we have ((X & C) == C), turn it into ((X & C) != 0).
- if (RHS == BOC && RHSV.isPowerOf2())
+ if (RHS == BOC && RHSV->isPowerOf2())
return new ICmpInst(isICMP_NE ? ICmpInst::ICMP_EQ : ICmpInst::ICMP_NE,
BO, Constant::getNullValue(RHS->getType()));
}
// ((X & ~7) == 0) --> X < 8
- if (RHSV == 0 && isHighOnes(BOC)) {
+ if (*RHSV == 0 && isHighOnes(BOC)) {
Constant *NegX = ConstantExpr::getNeg(BOC);
ICmpInst::Predicate Pred =
isICMP_NE ? ICmpInst::ICMP_UGE : ICmpInst::ICMP_ULT;
}
break;
case Instruction::Mul:
- if (RHSV == 0 && BO->hasNoSignedWrap()) {
+ if (*RHSV == 0 && BO->hasNoSignedWrap()) {
+ // FIXME: Vectors are excluded by ConstantInt.
if (ConstantInt *BOC = dyn_cast<ConstantInt>(BOp1)) {
// The trivial case (mul X, 0) is handled by InstSimplify
// General case : (mul X, C) != 0 iff X != 0
}
break;
case Instruction::UDiv:
- if (RHSV == 0) {
+ if (*RHSV == 0) {
// (icmp eq/ne (udiv A, B), 0) -> (icmp ugt/ule i32 B, A)
ICmpInst::Predicate Pred =
isICMP_NE ? ICmpInst::ICMP_ULE : ICmpInst::ICMP_UGT;
ret i1 %c
}
-; FIXME: Vectors should fold the same way.
-
define <2 x i1> @test10vec(<2 x i8> %a, <2 x i8> %b) {
; CHECK-LABEL: @test10vec(
-; CHECK-NEXT: [[C:%.*]] = add <2 x i8> %a, %b
-; CHECK-NEXT: [[D:%.*]] = icmp ne <2 x i8> [[C]], zeroinitializer
+; CHECK-NEXT: [[C:%.*]] = sub <2 x i8> zeroinitializer, %b
+; CHECK-NEXT: [[D:%.*]] = icmp ne <2 x i8> %a, [[C]]
; CHECK-NEXT: ret <2 x i1> [[D]]
;
%c = add <2 x i8> %a, %b
ret i1 %c
}
-; FIXME: Vectors should fold the same way.
define <2 x i1> @test11vec(<2 x i8> %a) {
; CHECK-LABEL: @test11vec(
-; CHECK-NEXT: [[B:%.*]] = add <2 x i8> %a, <i8 -1, i8 -1>
-; CHECK-NEXT: [[C:%.*]] = icmp ne <2 x i8> [[B]], zeroinitializer
+; CHECK-NEXT: [[C:%.*]] = icmp ne <2 x i8> %a, <i8 1, i8 1>
; CHECK-NEXT: ret <2 x i1> [[C]]
;
%b = add <2 x i8> %a, <i8 -1, i8 -1>
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -instcombine -S < %s | FileCheck %s
-; FIXME: Vectors should get the same folds as scalars for all tests.
-
define i1 @test1(i32 %n, i32 %d) {
; CHECK-LABEL: @test1(
; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i32 %d, %n
define <2 x i1> @test1vec(<2 x i32> %n, <2 x i32> %d) {
; CHECK-LABEL: @test1vec(
-; CHECK-NEXT: [[DIV:%.*]] = udiv <2 x i32> %n, %d
-; CHECK-NEXT: [[CMP1:%.*]] = icmp eq <2 x i32> [[DIV]], zeroinitializer
+; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt <2 x i32> %d, %n
; CHECK-NEXT: ret <2 x i1> [[CMP1]]
;
%div = udiv <2 x i32> %n, %d
define <2 x i1> @test2vec(<2 x i32> %d) {
; CHECK-LABEL: @test2vec(
-; CHECK-NEXT: [[DIV:%.*]] = udiv <2 x i32> <i32 64, i32 63>, %d
-; CHECK-NEXT: [[CMP1:%.*]] = icmp eq <2 x i32> [[DIV]], zeroinitializer
+; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt <2 x i32> %d, <i32 64, i32 63>
; CHECK-NEXT: ret <2 x i1> [[CMP1]]
;
%div = udiv <2 x i32> <i32 64, i32 63>, %d
define <2 x i1> @test3vec(<2 x i32> %n, <2 x i32> %d) {
; CHECK-LABEL: @test3vec(
-; CHECK-NEXT: [[DIV:%.*]] = udiv <2 x i32> %n, %d
-; CHECK-NEXT: [[CMP1:%.*]] = icmp ne <2 x i32> [[DIV]], zeroinitializer
+; CHECK-NEXT: [[CMP1:%.*]] = icmp ule <2 x i32> %d, %n
; CHECK-NEXT: ret <2 x i1> [[CMP1]]
;
%div = udiv <2 x i32> %n, %d
define <2 x i1> @test4vec(<2 x i32> %d) {
; CHECK-LABEL: @test4vec(
-; CHECK-NEXT: [[DIV:%.*]] = udiv <2 x i32> <i32 64, i32 65>, %d
-; CHECK-NEXT: [[CMP1:%.*]] = icmp ne <2 x i32> [[DIV]], zeroinitializer
+; CHECK-NEXT: [[CMP1:%.*]] = icmp ult <2 x i32> %d, <i32 65, i32 66>
; CHECK-NEXT: ret <2 x i1> [[CMP1]]
;
%div = udiv <2 x i32> <i32 64, i32 65>, %d
define <2 x i1> @test5vec(<2 x i32> %d) {
; CHECK-LABEL: @test5vec(
-; CHECK-NEXT: [[DIV:%.*]] = udiv <2 x i32> <i32 -1, i32 -1>, %d
-; CHECK-NEXT: [[CMP1:%.*]] = icmp ne <2 x i32> [[DIV]], zeroinitializer
-; CHECK-NEXT: ret <2 x i1> [[CMP1]]
+; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true>
;
%div = udiv <2 x i32> <i32 -1, i32 -1>, %d
%cmp1 = icmp ne <2 x i32> %div, zeroinitializer
define <2 x i1> @test6vec(<2 x i32> %d) {
; CHECK-LABEL: @test6vec(
-; CHECK-NEXT: [[DIV:%.*]] = udiv <2 x i32> <i32 5, i32 5>, %d
-; CHECK-NEXT: [[CMP1:%.*]] = icmp ne <2 x i32> [[DIV]], zeroinitializer
+; CHECK-NEXT: [[CMP1:%.*]] = icmp ult <2 x i32> %d, <i32 6, i32 6>
; CHECK-NEXT: ret <2 x i1> [[CMP1]]
;
%div = udiv <2 x i32> <i32 5, i32 5>, %d
ret i1 %cmp1
}
+; FIXME: Vectors should get the same folds as scalars for all tests.
+
define <2 x i1> @test8vec(<2 x i32> %d) {
; CHECK-LABEL: @test8vec(
; CHECK-NEXT: [[DIV:%.*]] = udiv <2 x i32> <i32 4, i32 4>, %d
define <2 x i1> @test13_vector(<2 x i64> %X, <2 x %S*> %P) nounwind {
; CHECK-LABEL: @test13_vector(
-; CHECK-NEXT: shl nuw <2 x i64> %X, <i64 2, i64 2>
-; CHECK-NEXT: add <2 x i64> %A.idx, <i64 4, i64 4>
-; CHECK-NEXT: icmp eq <2 x i64> %A.offs, zeroinitializer
+; CHECK-NEXT: [[A_IDX:%.*]] = shl nuw <2 x i64> %X, <i64 2, i64 2>
+; CHECK-NEXT: [[C:%.*]] = icmp eq <2 x i64> [[A_IDX]], <i64 -4, i64 -4>
+; CHECK-NEXT: ret <2 x i1> [[C]]
+;
%A = getelementptr inbounds %S, <2 x %S*> %P, <2 x i64> zeroinitializer, <2 x i32> <i32 1, i32 1>, <2 x i64> %X
%B = getelementptr inbounds %S, <2 x %S*> %P, <2 x i64> <i64 0, i64 0>, <2 x i32> <i32 0, i32 0>
%C = icmp eq <2 x i32*> %A, %B
define <2 x i1> @test13_vector_as1(<2 x i16> %X, <2 x %S addrspace(1)*> %P) {
; CHECK-LABEL: @test13_vector_as1(
-; CHECK-NEXT: shl nuw <2 x i16> %X, <i16 2, i16 2>
-; CHECK-NEXT: add <2 x i16> %A.idx, <i16 4, i16 4>
-; CHECK-NEXT: icmp eq <2 x i16> %A.offs, zeroinitializer
-; CHECK-NEXT: ret <2 x i1>
+; CHECK-NEXT: [[A_IDX:%.*]] = shl nuw <2 x i16> %X, <i16 2, i16 2>
+; CHECK-NEXT: [[C:%.*]] = icmp eq <2 x i16> [[A_IDX]], <i16 -4, i16 -4>
+; CHECK-NEXT: ret <2 x i1> [[C]]
+;
%A = getelementptr inbounds %S, <2 x %S addrspace(1)*> %P, <2 x i16> <i16 0, i16 0>, <2 x i32> <i32 1, i32 1>, <2 x i16> %X
%B = getelementptr inbounds %S, <2 x %S addrspace(1)*> %P, <2 x i16> <i16 0, i16 0>, <2 x i32> <i32 0, i32 0>
%C = icmp eq <2 x i32 addrspace(1)*> %A, %B
ret i1 %D
}
-; FIXME: Vectors should get the same folds as scalars.
-
define <2 x i1> @test11vec(<2 x i8> %A, <2 x i8> %B) {
; CHECK-LABEL: @test11vec(
-; CHECK-NEXT: [[C:%.*]] = sub <2 x i8> %A, %B
-; CHECK-NEXT: [[D:%.*]] = icmp ne <2 x i8> [[C]], zeroinitializer
+; CHECK-NEXT: [[D:%.*]] = icmp ne <2 x i8> %A, %B
; CHECK-NEXT: ret <2 x i1> [[D]]
;
%C = sub <2 x i8> %A, %B
ret i1 %C
}
-; FIXME: Vectors should fold the same way.
-
define <2 x i1> @test9vec(<2 x i8> %a) {
; CHECK-LABEL: @test9vec(
-; CHECK-NEXT: [[B:%.*]] = xor <2 x i8> %a, <i8 123, i8 123>
-; CHECK-NEXT: [[C:%.*]] = icmp eq <2 x i8> [[B]], <i8 34, i8 34>
+; CHECK-NEXT: [[C:%.*]] = icmp eq <2 x i8> %a, <i8 89, i8 89>
; CHECK-NEXT: ret <2 x i1> [[C]]
;
%b = xor <2 x i8> %a, <i8 123, i8 123>
ret i1 %c
}
-; FIXME: Vectors should fold the same way.
-
define <2 x i1> @test12vec(<2 x i8> %a) {
; CHECK-LABEL: @test12vec(
-; CHECK-NEXT: [[B:%.*]] = xor <2 x i8> %a, <i8 4, i8 4>
-; CHECK-NEXT: [[C:%.*]] = icmp ne <2 x i8> [[B]], zeroinitializer
+; CHECK-NEXT: [[C:%.*]] = icmp ne <2 x i8> %a, <i8 4, i8 4>
; CHECK-NEXT: ret <2 x i1> [[C]]
;
%b = xor <2 x i8> %a, <i8 4, i8 4>