We currently already canonicalize icmp eq (%x & Pow2), Pow2 to
icmp ne (%x & Pow2), 0. This patch generalizes the fold based on
known bits.
In particular, this allows us to handle comparisons against
!range !{i64 0, i64 2} loads, which addresses an optimization
regression in Rust caused by
8df376db7282b955e7990cb8887ee9dcd3565040.
Differential Revision: https://reviews.llvm.org/D146149
}
break;
}
- case Instruction::And: {
- const APInt *BOC;
- if (match(BOp1, m_APInt(BOC))) {
- // If we have ((X & C) == C), turn it into ((X & C) != 0).
- if (C == *BOC && C.isPowerOf2())
- return new ICmpInst(isICMP_NE ? ICmpInst::ICMP_EQ : ICmpInst::ICMP_NE,
- BO, Constant::getNullValue(RHS->getType()));
- }
- break;
- }
case Instruction::UDiv:
if (C.isZero()) {
// (icmp eq/ne (udiv A, B), 0) -> (icmp ugt/ule i32 B, A)
}
}
}
+
+ // Op0 eq C_Pow2 -> Op0 ne 0 if Op0 is known to be C_Pow2 or zero.
+ if (Op1Known.isConstant() && Op1Known.getConstant().isPowerOf2() &&
+ (Op0Known & Op1Known) == Op0Known)
+ return new ICmpInst(CmpInst::getInversePredicate(Pred), Op0,
+ ConstantInt::getNullValue(Op1->getType()));
break;
}
case ICmpInst::ICMP_ULT: {
define i32 @test29(i32 %a) {
; CHECK-LABEL: @test29(
-; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[A:%.*]], -1
+; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i32 [[A:%.*]], 0
; CHECK-NEXT: [[DIV:%.*]] = zext i1 [[TMP1]] to i32
; CHECK-NEXT: ret i32 [[DIV]]
;
define i1 @icmp_eq_bool_1(ptr %ptr) {
; CHECK-LABEL: @icmp_eq_bool_1(
; CHECK-NEXT: [[VAL:%.*]] = load i64, ptr [[PTR:%.*]], align 8, !range [[RNG6]]
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[VAL]], 1
+; CHECK-NEXT: [[CMP:%.*]] = icmp ne i64 [[VAL]], 0
; CHECK-NEXT: ret i1 [[CMP]]
;
%val = load i64, ptr %ptr, align 8, !range !{i64 0, i64 2}
define i1 @icmp_ne_bool_1(ptr %ptr) {
; CHECK-LABEL: @icmp_ne_bool_1(
; CHECK-NEXT: [[VAL:%.*]] = load i64, ptr [[PTR:%.*]], align 8, !range [[RNG6]]
-; CHECK-NEXT: [[CMP:%.*]] = icmp ne i64 [[VAL]], 1
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[VAL]], 0
; CHECK-NEXT: ret i1 [[CMP]]
;
%val = load i64, ptr %ptr, align 8, !range !{i64 0, i64 2}
define i1 @icmp_sgt9(i8 %x) {
; CHECK-LABEL: @icmp_sgt9(
-; CHECK-NEXT: [[CMP:%.*]] = icmp ne i8 [[X:%.*]], -1
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X:%.*]], 0
; CHECK-NEXT: ret i1 [[CMP]]
;
%shl = shl nsw i8 %x, 7
define i1 @icmp_sle9(i8 %x) {
; CHECK-LABEL: @icmp_sle9(
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X:%.*]], -1
+; CHECK-NEXT: [[CMP:%.*]] = icmp ne i8 [[X:%.*]], 0
; CHECK-NEXT: ret i1 [[CMP]]
;
%shl = shl nsw i8 %x, 7
define i1 @lshrult_03_01_exact(i4 %x) {
; CHECK-LABEL: @lshrult_03_01_exact(
-; CHECK-NEXT: [[C:%.*]] = icmp ne i4 [[X:%.*]], -8
+; CHECK-NEXT: [[C:%.*]] = icmp eq i4 [[X:%.*]], 0
; CHECK-NEXT: ret i1 [[C]]
;
%s = lshr exact i4 %x, 3
define i64 @zext_icmp_eq_bool_1(ptr %ptr) {
; CHECK-LABEL: @zext_icmp_eq_bool_1(
; CHECK-NEXT: [[VAL:%.*]] = load i64, ptr [[PTR:%.*]], align 8, !range [[RNG0]]
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[VAL]], 1
-; CHECK-NEXT: [[LEN:%.*]] = zext i1 [[CMP]] to i64
-; CHECK-NEXT: ret i64 [[LEN]]
+; CHECK-NEXT: ret i64 [[VAL]]
;
%val = load i64, ptr %ptr, align 8, !range !{i64 0, i64 2}
%cmp = icmp eq i64 %val, 1
define i64 @zext_icmp_ne_bool_1(ptr %ptr) {
; CHECK-LABEL: @zext_icmp_ne_bool_1(
; CHECK-NEXT: [[VAL:%.*]] = load i64, ptr [[PTR:%.*]], align 8, !range [[RNG0]]
-; CHECK-NEXT: [[CMP:%.*]] = icmp ne i64 [[VAL]], 1
-; CHECK-NEXT: [[LEN:%.*]] = zext i1 [[CMP]] to i64
+; CHECK-NEXT: [[LEN:%.*]] = xor i64 [[VAL]], 1
; CHECK-NEXT: ret i64 [[LEN]]
;
%val = load i64, ptr %ptr, align 8, !range !{i64 0, i64 2}