Index: lib/Analysis/InstructionSimplify.cpp =================================================================== --- lib/Analysis/InstructionSimplify.cpp +++ lib/Analysis/InstructionSimplify.cpp @@ -2128,6 +2128,41 @@ return nullptr; } +/// Return true if B is known to be implied by A. A & B must be i1 (boolean) +/// values. Note that the truth table for implication is the same as <=u on i1 +/// values (but not <=s!). The truth table for both is: +/// | T | F (B) +/// T | T | F +/// F | T | T +/// (A) +static bool implies(Value *A, Value *B) { + // TODO: Consider extending this to vector of i1? + assert(A->getType()->isIntegerTy(1) && B->getType()->isIntegerTy(1)); + + // A ==> A by definition + if (A == B) return true; + + // i +_{nsw} C_{>0} i (A); + auto *ICmpB = dyn_cast(B); + if (!ICmpA || !ICmpB || + ICmpA->getPredicate() != ICmpInst::ICMP_SLT || + ICmpB->getPredicate() != ICmpInst::ICMP_SLT || + ICmpA->getOperand(1) != ICmpB->getOperand(1)) + return false; + + auto *BO = dyn_cast(ICmpA->getOperand(0)); + if (!BO || !BO->hasNoSignedWrap() || + BO->getOperand(0) != ICmpB->getOperand(0)) + return false; + + ConstantInt *C = dyn_cast(BO->getOperand(1)); + if (!C || C->isNegative()) + return false; + + return true; +} + /// SimplifyICmpInst - Given operands for an ICmpInst, see if we can /// fold the result. If not, this returns null. static Value *SimplifyICmpInst(unsigned Predicate, Value *LHS, Value *RHS, @@ -2176,6 +2211,8 @@ // X >=u 1 -> X if (match(RHS, m_One())) return LHS; + if (implies(RHS, LHS)) + return getTrue(ITy); break; case ICmpInst::ICMP_SLT: // X X @@ -2187,6 +2224,10 @@ if (match(RHS, m_One())) return LHS; break; + case ICmpInst::ICMP_ULE: + if (implies(LHS, RHS)) + return getTrue(ITy); + break; } } Index: test/Transforms/InstSimplify/implies.ll =================================================================== --- test/Transforms/InstSimplify/implies.ll +++ test/Transforms/InstSimplify/implies.ll @@ -0,0 +1,55 @@ +; RUN: opt -S %s -instsimplify | FileCheck %s + +; A ==> A -> true +define i1 @test(i32 %length.i, i32 %i) { +; CHECK-LABEL: @test +; CHECK: ret i1 true + %var29 = icmp slt i32 %i, %length.i + %res = icmp uge i1 %var29, %var29 + ret i1 %res +} + +; i +_{nsw} C_{>0} i true +define i1 @test2(i32 %length.i, i32 %i) { +; CHECK-LABEL: @test2 +; CHECK: ret i1 true + %iplus1 = add nsw i32 %i, 1 + %var29 = icmp slt i32 %i, %length.i + %var30 = icmp slt i32 %iplus1, %length.i + %res = icmp ule i1 %var30, %var29 + ret i1 %res +} + +; i + C_{>0} i unknown without the nsw +define i1 @test2_neg(i32 %length.i, i32 %i) { +; CHECK-LABEL: @test2_neg +; CHECK: ret i1 %res + %iplus1 = add i32 %i, 1 + %var29 = icmp slt i32 %i, %length.i + %var30 = icmp slt i32 %iplus1, %length.i + %res = icmp ule i1 %var30, %var29 + ret i1 %res +} + +; sle is not implication +define i1 @test2_neg2(i32 %length.i, i32 %i) { +; CHECK-LABEL: @test2_neg2 +; CHECK: ret i1 %res + %iplus1 = add i32 %i, 1 + %var29 = icmp slt i32 %i, %length.i + %var30 = icmp slt i32 %iplus1, %length.i + %res = icmp sle i1 %var30, %var29 + ret i1 %res +} + +; i +_{nsw} C_{>0} i true +; With an inverted conditional (ule B A rather than canonical ugt A B +define i1 @test3(i32 %length.i, i32 %i) { +; CHECK-LABEL: @test3 +; CHECK: ret i1 true + %iplus1 = add nsw i32 %i, 1 + %var29 = icmp slt i32 %i, %length.i + %var30 = icmp slt i32 %iplus1, %length.i + %res = icmp uge i1 %var29, %var30 + ret i1 %res +}