Index: lib/Analysis/ValueTracking.cpp =================================================================== --- lib/Analysis/ValueTracking.cpp +++ lib/Analysis/ValueTracking.cpp @@ -4119,6 +4119,36 @@ return !CI->isZero(); return true; } + + // If the low K bits of X are known to be zero, and both C0 and C1 + // fit in K bits, then + // + // (X | C0) u< (X | C1) iff C0 u< C1 + // (X | C0) u<= (X | C1) iff C0 u<= C1 + // + // Informally, the easiest way to justify this is to see that + // "X | C" if C fits in K bits (where the low K bits of X are + // zero) is equal to "X +_{nuw} C". Then this rule is effectively + // the same as "C0 u< C1" ==> "(X +_{nuw} C0) u< (X +_{nuw} C1)". + + Value *X; + ConstantInt *CI0, *CI1; + if (match(LHS, m_Or(m_Value(X), m_ConstantInt(CI0))) && + match(RHS, m_Or(m_Specific(X), m_ConstantInt(CI1)))) { + unsigned BitWidth = cast(LHS->getType())->getBitWidth(); + APInt KnownZero(BitWidth, 0), KnownOne(BitWidth, 0); + computeKnownBits(X, KnownZero, KnownOne, DL, Depth + 1, AC, CxtI, DT); + + unsigned LowZeroes = KnownZero.countTrailingOnes(); + APInt UpperLimit = + APInt::getBitsSet(KnownZero.getBitWidth(), LowZeroes, LowZeroes + 1); + + if (UpperLimit.ugt(CI0->getValue()) && UpperLimit.ugt(CI1->getValue())) { + if (Pred == CmpInst::ICMP_ULE) + return CI0->getValue().ule(CI1->getValue()); + return CI0->getValue().ult(CI1->getValue()); + } + } return false; } } Index: test/Transforms/InstSimplify/implies.ll =================================================================== --- test/Transforms/InstSimplify/implies.ll +++ test/Transforms/InstSimplify/implies.ll @@ -127,6 +127,46 @@ ret i1 %res } +define i1 @test10(i32 %length.i, i32 %x.full) { +; CHECK-LABEL: @test10( +; CHECK: ret i1 true + + %x = and i32 %x.full, 4294901760 ;; 4294901760 == 0xffff0000 + %large = or i32 %x, 100 + %small = or i32 %x, 90 + %known = icmp ult i32 %large, %length.i + %to.prove = icmp ult i32 %small, %length.i + %res = icmp ule i1 %known, %to.prove + ret i1 %res +} + +define i1 @test11(i32 %length.i, i32 %x) { +; CHECK-LABEL: @test11( +; CHECK: %res = icmp ule i1 %known, %to.prove +; CHECK: ret i1 %res + + %large = or i32 %x, 100 + %small = or i32 %x, 90 + %known = icmp ult i32 %large, %length.i + %to.prove = icmp ult i32 %small, %length.i + %res = icmp ule i1 %known, %to.prove + ret i1 %res +} + +define i1 @test12(i32 %length.i, i32 %x.full) { +; CHECK-LABEL: @test12( +; CHECK: %res = icmp ule i1 %known, %to.prove +; CHECK: ret i1 %res + + %x = and i32 %x.full, 4294901760 ;; 4294901760 == 0xffff0000 + %large = or i32 %x, 65536 ;; 65536 == 0x00010000 + %small = or i32 %x, 90 + %known = icmp ult i32 %large, %length.i + %to.prove = icmp ult i32 %small, %length.i + %res = icmp ule i1 %known, %to.prove + ret i1 %res +} + ; X >=(s) Y == X ==> Y (i1 1 becomes -1 for reasoning) define i1 @test_sge(i32 %length.i, i32 %i) { ; CHECK-LABEL: @test_sge