diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -2960,8 +2960,10 @@ return getFalse(ITy); } - // x >> y <=u x - // x udiv y <=u x. + // x >>u y <=u x --> true. + // x >>u y >u x --> false. + // x udiv y <=u x --> true. + // x udiv y >u x --> false. if (match(LBO, m_LShr(m_Specific(RHS), m_Value())) || match(LBO, m_UDiv(m_Specific(RHS), m_Value()))) { // icmp pred (X op Y), X @@ -2971,6 +2973,37 @@ return getTrue(ITy); } + // If x is nonzero: + // x >>u C true for C != 0. + // x >>u C != x --> true for C != 0. + // x >>u C >=u x --> false for C != 0. + // x >>u C == x --> false for C != 0. + // x udiv C true for C != 1. + // x udiv C != x --> true for C != 1. + // x udiv C >=u x --> false for C != 1. + // x udiv C == x --> false for C != 1. + // TODO: allow non-constant shift amount/divisor + const APInt *C; + if ((match(LBO, m_LShr(m_Specific(RHS), m_APInt(C))) && *C != 0) || + (match(LBO, m_UDiv(m_Specific(RHS), m_APInt(C))) && *C != 1)) { + if (isKnownNonZero(RHS, Q.DL, 0, Q.AC, Q.CxtI, Q.DT)) { + switch (Pred) { + default: + break; + case ICmpInst::ICMP_EQ: + case ICmpInst::ICMP_UGE: + return getFalse(ITy); + case ICmpInst::ICMP_NE: + case ICmpInst::ICMP_ULT: + return getTrue(ITy); + case ICmpInst::ICMP_UGT: + case ICmpInst::ICMP_ULE: + // UGT/ULE are handled by the more general case just above + llvm_unreachable("Unexpected UGT/ULE, should have been handled"); + } + } + } + // (x*C1)/C2 <= x for C1 <= C2. // This holds even if the multiplication overflows: Assume that x != 0 and // arithmetic is modulo M. For overflow to occur we must have C1 >= M/x and diff --git a/llvm/test/Transforms/InstSimplify/compare.ll b/llvm/test/Transforms/InstSimplify/compare.ll --- a/llvm/test/Transforms/InstSimplify/compare.ll +++ b/llvm/test/Transforms/InstSimplify/compare.ll @@ -582,9 +582,7 @@ ; CHECK-LABEL: @lshr_nonzero_eq( ; CHECK-NEXT: [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0 ; CHECK-NEXT: call void @llvm.assume(i1 [[X_NE_0]]) -; CHECK-NEXT: [[LHS:%.*]] = lshr i32 [[X]], 1 -; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[LHS]], [[X]] -; CHECK-NEXT: ret i1 [[CMP]] +; CHECK-NEXT: ret i1 false ; %x_ne_0 = icmp ne i32 %x, 0 call void @llvm.assume(i1 %x_ne_0) @@ -597,9 +595,7 @@ ; CHECK-LABEL: @lshr_nonzero_uge( ; CHECK-NEXT: [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0 ; CHECK-NEXT: call void @llvm.assume(i1 [[X_NE_0]]) -; CHECK-NEXT: [[LHS:%.*]] = lshr i32 [[X]], 1 -; CHECK-NEXT: [[CMP:%.*]] = icmp uge i32 [[LHS]], [[X]] -; CHECK-NEXT: ret i1 [[CMP]] +; CHECK-NEXT: ret i1 false ; %x_ne_0 = icmp ne i32 %x, 0 call void @llvm.assume(i1 %x_ne_0) @@ -612,9 +608,7 @@ ; CHECK-LABEL: @lshr_nonzero_ne( ; CHECK-NEXT: [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0 ; CHECK-NEXT: call void @llvm.assume(i1 [[X_NE_0]]) -; CHECK-NEXT: [[LHS:%.*]] = lshr i32 [[X]], 1 -; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[LHS]], [[X]] -; CHECK-NEXT: ret i1 [[CMP]] +; CHECK-NEXT: ret i1 true ; %x_ne_0 = icmp ne i32 %x, 0 call void @llvm.assume(i1 %x_ne_0) @@ -627,9 +621,7 @@ ; CHECK-LABEL: @lshr_nonzero_ult( ; CHECK-NEXT: [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0 ; CHECK-NEXT: call void @llvm.assume(i1 [[X_NE_0]]) -; CHECK-NEXT: [[LHS:%.*]] = lshr i32 [[X]], 1 -; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[LHS]], [[X]] -; CHECK-NEXT: ret i1 [[CMP]] +; CHECK-NEXT: ret i1 true ; %x_ne_0 = icmp ne i32 %x, 0 call void @llvm.assume(i1 %x_ne_0) @@ -998,9 +990,7 @@ ; CHECK-LABEL: @udiv_nonzero_eq( ; CHECK-NEXT: [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0 ; CHECK-NEXT: call void @llvm.assume(i1 [[X_NE_0]]) -; CHECK-NEXT: [[LHS:%.*]] = udiv i32 [[X]], 3 -; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[LHS]], [[X]] -; CHECK-NEXT: ret i1 [[CMP]] +; CHECK-NEXT: ret i1 false ; %x_ne_0 = icmp ne i32 %x, 0 call void @llvm.assume(i1 %x_ne_0) @@ -1013,9 +1003,7 @@ ; CHECK-LABEL: @udiv_nonzero_uge( ; CHECK-NEXT: [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0 ; CHECK-NEXT: call void @llvm.assume(i1 [[X_NE_0]]) -; CHECK-NEXT: [[LHS:%.*]] = udiv i32 [[X]], 3 -; CHECK-NEXT: [[CMP:%.*]] = icmp uge i32 [[LHS]], [[X]] -; CHECK-NEXT: ret i1 [[CMP]] +; CHECK-NEXT: ret i1 false ; %x_ne_0 = icmp ne i32 %x, 0 call void @llvm.assume(i1 %x_ne_0) @@ -1028,9 +1016,7 @@ ; CHECK-LABEL: @udiv_nonzero_ne( ; CHECK-NEXT: [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0 ; CHECK-NEXT: call void @llvm.assume(i1 [[X_NE_0]]) -; CHECK-NEXT: [[LHS:%.*]] = udiv i32 [[X]], 3 -; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[LHS]], [[X]] -; CHECK-NEXT: ret i1 [[CMP]] +; CHECK-NEXT: ret i1 true ; %x_ne_0 = icmp ne i32 %x, 0 call void @llvm.assume(i1 %x_ne_0) @@ -1043,9 +1029,7 @@ ; CHECK-LABEL: @udiv_nonzero_ult( ; CHECK-NEXT: [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0 ; CHECK-NEXT: call void @llvm.assume(i1 [[X_NE_0]]) -; CHECK-NEXT: [[LHS:%.*]] = udiv i32 [[X]], 3 -; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[LHS]], [[X]] -; CHECK-NEXT: ret i1 [[CMP]] +; CHECK-NEXT: ret i1 true ; %x_ne_0 = icmp ne i32 %x, 0 call void @llvm.assume(i1 %x_ne_0)