diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -2047,15 +2047,15 @@ } else if (Cmp.isSigned()) { Constant *BitWidthMinusOne = ConstantInt::get(ShiftType, TypeBits - 1); // (1 << Y) > 0 -> Y != 31 - // (1 << Y) > -1 -> Y != 31 - // TODO: This can be generalized to any negative constant. - if (Pred == ICmpInst::ICMP_SGT && (C.isZero() || C.isAllOnes())) + // (1 << Y) > C -> Y != 31 if C is negative. + if (Pred == ICmpInst::ICMP_SGT && C.sle(0)) return new ICmpInst(ICmpInst::ICMP_NE, Y, BitWidthMinusOne); // (1 << Y) < 0 -> Y == 31 // (1 << Y) < 1 -> Y == 31 - // TODO: This can be generalized to any negative constant except signed min. - if (Pred == ICmpInst::ICMP_SLT && (C.isZero() || C.isOne())) + // (1 << Y) < C -> Y == 31 if C is negative and not signed min. + // Exclude signed min by subtracting 1 and lower the upper bound to 0. + if (Pred == ICmpInst::ICMP_SLT && (C-1).sle(0)) return new ICmpInst(ICmpInst::ICMP_EQ, Y, BitWidthMinusOne); } else if (Cmp.isEquality() && CIsPowerOf2) { return new ICmpInst(Pred, Y, ConstantInt::get(ShiftType, C.logBase2())); diff --git a/llvm/test/Transforms/InstCombine/icmp.ll b/llvm/test/Transforms/InstCombine/icmp.ll --- a/llvm/test/Transforms/InstCombine/icmp.ll +++ b/llvm/test/Transforms/InstCombine/icmp.ll @@ -2178,6 +2178,26 @@ ret <2 x i1> %cmp } +define i1 @icmp_shl_1_V_sle_negative(i32 %V) { +; CHECK-LABEL: @icmp_shl_1_V_sle_negative( +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[V:%.*]], 31 +; CHECK-NEXT: ret i1 [[CMP]] +; + %shl = shl i32 1, %V + %cmp = icmp sle i32 %shl, -42 + ret i1 %cmp +} + +define <2 x i1> @icmp_shl_1_V_sle_0_negative(<2 x i32> %V) { +; CHECK-LABEL: @icmp_shl_1_V_sle_0_negative( +; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i32> [[V:%.*]], +; CHECK-NEXT: ret <2 x i1> [[CMP]] +; + %shl = shl <2 x i32> , %V + %cmp = icmp sle <2 x i32> %shl, + ret <2 x i1> %cmp +} + define i1 @icmp_shl_1_V_sgt_0(i32 %V) { ; CHECK-LABEL: @icmp_shl_1_V_sgt_0( ; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[V:%.*]], 31 @@ -2198,6 +2218,26 @@ ret <2 x i1> %cmp } +define i1 @icmp_shl_1_V_sgt_negative(i32 %V) { +; CHECK-LABEL: @icmp_shl_1_V_sgt_negative( +; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[V:%.*]], 31 +; CHECK-NEXT: ret i1 [[CMP]] +; + %shl = shl i32 1, %V + %cmp = icmp sgt i32 %shl, -12345 + ret i1 %cmp +} + +define <2 x i1> @icmp_shl_1_V_sgt_negative_vec(<2 x i32> %V) { +; CHECK-LABEL: @icmp_shl_1_V_sgt_negative_vec( +; CHECK-NEXT: [[CMP:%.*]] = icmp ne <2 x i32> [[V:%.*]], +; CHECK-NEXT: ret <2 x i1> [[CMP]] +; + %shl = shl <2 x i32> , %V + %cmp = icmp sgt <2 x i32> %shl, + ret <2 x i1> %cmp +} + define i1 @or_icmp_eq_B_0_icmp_ult_A_B(i64 %a, i64 %b) { ; CHECK-LABEL: @or_icmp_eq_B_0_icmp_ult_A_B( ; CHECK-NEXT: [[TMP1:%.*]] = add i64 [[B:%.*]], -1