Index: llvm/trunk/lib/Analysis/InstructionSimplify.cpp =================================================================== --- llvm/trunk/lib/Analysis/InstructionSimplify.cpp +++ llvm/trunk/lib/Analysis/InstructionSimplify.cpp @@ -1492,9 +1492,8 @@ return nullptr; } -/// Simplify (and (icmp ...) (icmp ...)) to true when we can tell that the range -/// of possible values cannot be satisfied. static Value *SimplifyAndOfICmps(ICmpInst *Op0, ICmpInst *Op1) { + Type *ITy = Op0->getType(); ICmpInst::Predicate Pred0, Pred1; ConstantInt *CI1, *CI2; Value *V; @@ -1502,6 +1501,18 @@ if (Value *X = simplifyUnsignedRangeCheck(Op0, Op1, /*IsAnd=*/true)) return X; + // Look for this pattern: (icmp V, C0) & (icmp V, C1)). + const APInt *C0, *C1; + if (match(Op0, m_ICmp(Pred0, m_Value(V), m_APInt(C0))) && + match(Op1, m_ICmp(Pred1, m_Specific(V), m_APInt(C1)))) { + // Make a constant range that's the intersection of the two icmp ranges. + // If the intersection is empty, we know that the result is false. + auto Range0 = ConstantRange::makeAllowedICmpRegion(Pred0, *C0); + auto Range1 = ConstantRange::makeAllowedICmpRegion(Pred1, *C1); + if (Range0.intersectWith(Range1).isEmptySet()) + return getFalse(ITy); + } + if (!match(Op0, m_ICmp(Pred0, m_Add(m_Value(V), m_ConstantInt(CI1)), m_ConstantInt(CI2)))) return nullptr; @@ -1509,8 +1520,6 @@ if (!match(Op1, m_ICmp(Pred1, m_Specific(V), m_Specific(CI1)))) return nullptr; - Type *ITy = Op0->getType(); - auto *AddInst = cast(Op0->getOperand(0)); bool isNSW = AddInst->hasNoSignedWrap(); bool isNUW = AddInst->hasNoUnsignedWrap(); @@ -1608,6 +1617,24 @@ } } + // The compares may be hidden behind casts. Look through those and try the + // same folds as above. + auto *Cast0 = dyn_cast(Op0); + auto *Cast1 = dyn_cast(Op1); + if (Cast0 && Cast1 && Cast0->getOpcode() == Cast1->getOpcode() && + Cast0->getSrcTy() == Cast1->getSrcTy()) { + auto *Cmp0 = dyn_cast(Cast0->getOperand(0)); + auto *Cmp1 = dyn_cast(Cast1->getOperand(0)); + if (Cmp0 && Cmp1) { + Instruction::CastOps CastOpc = Cast0->getOpcode(); + Type *ResultType = Cast0->getType(); + if (auto *V = dyn_cast_or_null(SimplifyAndOfICmps(Cmp0, Cmp1))) + return ConstantExpr::getCast(CastOpc, V, ResultType); + if (auto *V = dyn_cast_or_null(SimplifyAndOfICmps(Cmp1, Cmp0))) + return ConstantExpr::getCast(CastOpc, V, ResultType); + } + } + // Try some generic simplifications for associative operations. if (Value *V = SimplifyAssociativeBinOp(Instruction::And, Op0, Op1, Q, MaxRecurse)) Index: llvm/trunk/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp =================================================================== --- llvm/trunk/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ llvm/trunk/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -968,16 +968,6 @@ RHSCC == ICmpInst::ICMP_SGE || RHSCC == ICmpInst::ICMP_SLE) return nullptr; - // Make a constant range that's the intersection of the two icmp ranges. - // If the intersection is empty, we know that the result is false. - ConstantRange LHSRange = - ConstantRange::makeAllowedICmpRegion(LHSCC, LHSCst->getValue()); - ConstantRange RHSRange = - ConstantRange::makeAllowedICmpRegion(RHSCC, RHSCst->getValue()); - - if (LHSRange.intersectWith(RHSRange).isEmptySet()) - return ConstantInt::get(CmpInst::makeCmpResultType(LHS->getType()), 0); - // We can't fold (ugt x, C) & (sgt x, C2). if (!PredicatesFoldable(LHSCC, RHSCC)) return nullptr; Index: llvm/trunk/test/Transforms/InstCombine/and.ll =================================================================== --- llvm/trunk/test/Transforms/InstCombine/and.ll +++ llvm/trunk/test/Transforms/InstCombine/and.ll @@ -228,17 +228,6 @@ ret i8 %D } -define i1 @test22(i32 %A) { -; CHECK-LABEL: @test22( -; CHECK-NEXT: ret i1 false -; - %B = icmp eq i32 %A, 1 - %C = icmp sge i32 %A, 3 - ;; false - %D = and i1 %B, %C - ret i1 %D -} - define i1 @test23(i32 %A) { ; CHECK-LABEL: @test23( ; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 %A, 2 Index: llvm/trunk/test/Transforms/InstCombine/and2.ll =================================================================== --- llvm/trunk/test/Transforms/InstCombine/and2.ll +++ llvm/trunk/test/Transforms/InstCombine/and2.ll @@ -33,16 +33,6 @@ ret i32 %b } -define i1 @test4(i32 %X) { -; CHECK-LABEL: @test4( -; CHECK-NEXT: ret i1 false -; - %a = icmp ult i32 %X, 31 - %b = icmp slt i32 %X, 0 - %c = and i1 %a, %b - ret i1 %c -} - ; Make sure we don't go into an infinite loop with this test define <4 x i32> @test5(<4 x i32> %A) { ; CHECK-LABEL: @test5( Index: llvm/trunk/test/Transforms/InstSimplify/AndOrXor.ll =================================================================== --- llvm/trunk/test/Transforms/InstSimplify/AndOrXor.ll +++ llvm/trunk/test/Transforms/InstSimplify/AndOrXor.ll @@ -231,37 +231,115 @@ ret i1 %3 } +define i1 @disjoint_cmps(i32 %A) { +; CHECK-LABEL: @disjoint_cmps( +; CHECK-NEXT: ret i1 false +; + %B = icmp eq i32 %A, 1 + %C = icmp sge i32 %A, 3 + %D = and i1 %B, %C + ret i1 %D +} + +define i1 @disjoint_cmps2(i32 %X) { +; CHECK-LABEL: @disjoint_cmps2( +; CHECK-NEXT: ret i1 false +; + %a = icmp ult i32 %X, 31 + %b = icmp slt i32 %X, 0 + %c = and i1 %a, %b + ret i1 %c +} + +; PR27869 - Look through casts to eliminate cmps and bitwise logic. + define i32 @and_of_zexted_icmps(i32 %i) { ; CHECK-LABEL: @and_of_zexted_icmps( -; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 %i, 0 -; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 -; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i32 %i, 4 -; CHECK-NEXT: [[CONV2:%.*]] = zext i1 [[CMP1]] to i32 -; CHECK-NEXT: [[AND:%.*]] = and i32 [[CONV]], [[CONV2]] -; CHECK-NEXT: ret i32 [[AND]] +; CHECK-NEXT: ret i32 0 ; - %cmp = icmp eq i32 %i, 0 - %conv = zext i1 %cmp to i32 + %cmp0 = icmp eq i32 %i, 0 + %conv0 = zext i1 %cmp0 to i32 %cmp1 = icmp ugt i32 %i, 4 - %conv2 = zext i1 %cmp1 to i32 - %and = and i32 %conv, %conv2 + %conv1 = zext i1 %cmp1 to i32 + %and = and i32 %conv0, %conv1 ret i32 %and } +; Make sure vectors work too. + define <4 x i32> @and_of_zexted_icmps_vec(<4 x i32> %i) { ; CHECK-LABEL: @and_of_zexted_icmps_vec( -; CHECK-NEXT: [[CMP:%.*]] = icmp eq <4 x i32> %i, zeroinitializer -; CHECK-NEXT: [[CONV:%.*]] = zext <4 x i1> [[CMP]] to <4 x i32> -; CHECK-NEXT: [[CMP1:%.*]] = icmp slt <4 x i32> %i, zeroinitializer -; CHECK-NEXT: [[CONV2:%.*]] = zext <4 x i1> [[CMP1]] to <4 x i32> -; CHECK-NEXT: [[AND:%.*]] = and <4 x i32> [[CONV]], [[CONV2]] -; CHECK-NEXT: ret <4 x i32> [[AND]] +; CHECK-NEXT: ret <4 x i32> zeroinitializer ; - %cmp = icmp eq <4 x i32> %i, zeroinitializer - %conv = zext <4 x i1> %cmp to <4 x i32> + %cmp0 = icmp eq <4 x i32> %i, zeroinitializer + %conv0 = zext <4 x i1> %cmp0 to <4 x i32> %cmp1 = icmp slt <4 x i32> %i, zeroinitializer - %conv2 = zext <4 x i1> %cmp1 to <4 x i32> - %and = and <4 x i32> %conv, %conv2 + %conv1 = zext <4 x i1> %cmp1 to <4 x i32> + %and = and <4 x i32> %conv0, %conv1 ret <4 x i32> %and } +; Try a different cast and weird types. + +define i5 @and_of_sexted_icmps(i3 %i) { +; CHECK-LABEL: @and_of_sexted_icmps( +; CHECK-NEXT: ret i5 0 +; + %cmp0 = icmp eq i3 %i, 0 + %conv0 = sext i1 %cmp0 to i5 + %cmp1 = icmp ugt i3 %i, 1 + %conv1 = sext i1 %cmp1 to i5 + %and = and i5 %conv0, %conv1 + ret i5 %and +} + +; Try a different cast and weird vector types. + +define i3 @and_of_bitcast_icmps_vec(<3 x i65> %i) { +; CHECK-LABEL: @and_of_bitcast_icmps_vec( +; CHECK-NEXT: ret i3 0 +; + %cmp0 = icmp sgt <3 x i65> %i, zeroinitializer + %conv0 = bitcast <3 x i1> %cmp0 to i3 + %cmp1 = icmp slt <3 x i65> %i, zeroinitializer + %conv1 = bitcast <3 x i1> %cmp1 to i3 + %and = and i3 %conv0, %conv1 + ret i3 %and +} + +; We can't do this if the casts are different. + +define i16 @and_of_different_cast_icmps(i8 %i) { +; CHECK-LABEL: @and_of_different_cast_icmps( +; CHECK-NEXT: [[CMP0:%.*]] = icmp eq i8 %i, 0 +; CHECK-NEXT: [[CONV0:%.*]] = zext i1 [[CMP0]] to i16 +; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i8 %i, 1 +; CHECK-NEXT: [[CONV1:%.*]] = sext i1 [[CMP1]] to i16 +; CHECK-NEXT: [[AND:%.*]] = and i16 [[CONV0]], [[CONV1]] +; CHECK-NEXT: ret i16 [[AND]] +; + %cmp0 = icmp eq i8 %i, 0 + %conv0 = zext i1 %cmp0 to i16 + %cmp1 = icmp eq i8 %i, 1 + %conv1 = sext i1 %cmp1 to i16 + %and = and i16 %conv0, %conv1 + ret i16 %and +} + +define <2 x i3> @and_of_different_cast_icmps_vec(<2 x i8> %i, <2 x i16> %j) { +; CHECK-LABEL: @and_of_different_cast_icmps_vec( +; CHECK-NEXT: [[CMP0:%.*]] = icmp eq <2 x i8> %i, zeroinitializer +; CHECK-NEXT: [[CONV0:%.*]] = zext <2 x i1> [[CMP0]] to <2 x i3> +; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt <2 x i16> %j, +; CHECK-NEXT: [[CONV1:%.*]] = zext <2 x i1> [[CMP1]] to <2 x i3> +; CHECK-NEXT: [[AND:%.*]] = and <2 x i3> [[CONV0]], [[CONV1]] +; CHECK-NEXT: ret <2 x i3> [[AND]] +; + %cmp0 = icmp eq <2 x i8> %i, zeroinitializer + %conv0 = zext <2 x i1> %cmp0 to <2 x i3> + %cmp1 = icmp ugt <2 x i16> %j, + %conv1 = zext <2 x i1> %cmp1 to <2 x i3> + %and = and <2 x i3> %conv0, %conv1 + ret <2 x i3> %and +} +