}
Value *OrOp0 = Or->getOperand(0), *OrOp1 = Or->getOperand(1);
- if (Cmp.isEquality() && Cmp.getOperand(1) == OrOp1) {
- // X | C == C --> X <=u C
- // X | C != C --> X >u C
- // iff C+1 is a power of 2 (C is a bitmask of the low bits)
- if ((C + 1).isPowerOf2()) {
+ const APInt *MaskC;
+ if (match(OrOp1, m_APInt(MaskC)) && Cmp.isEquality()) {
+ if (*MaskC == C && (C + 1).isPowerOf2()) {
+ // X | C == C --> X <=u C
+ // X | C != C --> X >u C
+ // iff C+1 is a power of 2 (C is a bitmask of the low bits)
Pred = (Pred == CmpInst::ICMP_EQ) ? CmpInst::ICMP_ULE : CmpInst::ICMP_UGT;
return new ICmpInst(Pred, OrOp0, OrOp1);
}
- // More general: are all bits outside of a mask constant set or not set?
- // X | C == C --> (X & ~C) == 0
- // X | C != C --> (X & ~C) != 0
+
+ // More general: canonicalize 'equality with set bits mask' to
+ // 'equality with clear bits mask'.
+ // (X | MaskC) == C --> (X & ~MaskC) == C ^ MaskC
+ // (X | MaskC) != C --> (X & ~MaskC) != C ^ MaskC
if (Or->hasOneUse()) {
- Value *A = Builder.CreateAnd(OrOp0, ~C);
- return new ICmpInst(Pred, A, ConstantInt::getNullValue(OrOp0->getType()));
+ Value *And = Builder.CreateAnd(OrOp0, ~(*MaskC));
+ Constant *NewC = ConstantInt::get(Or->getType(), C ^ (*MaskC));
+ return new ICmpInst(Pred, And, NewC);
}
}
define i1 @or_eq_with_one_bit_diff_constants1(i32 %x) {
; CHECK-LABEL: @or_eq_with_one_bit_diff_constants1(
-; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[X:%.*]], 1
-; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 51
+; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[X:%.*]], -2
+; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 50
; CHECK-NEXT: ret i1 [[TMP2]]
;
%cmp1 = icmp eq i32 %x, 50
define i1 @and_ne_with_one_bit_diff_constants1(i32 %x) {
; CHECK-LABEL: @and_ne_with_one_bit_diff_constants1(
-; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[X:%.*]], 1
-; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i32 [[TMP1]], 51
+; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[X:%.*]], -2
+; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i32 [[TMP1]], 50
; CHECK-NEXT: ret i1 [[TMP2]]
;
%cmp1 = icmp ne i32 %x, 51
define i1 @or_eq_with_one_bit_diff_constants2(i32 %x) {
; CHECK-LABEL: @or_eq_with_one_bit_diff_constants2(
-; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[X:%.*]], 32
-; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 97
+; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[X:%.*]], -33
+; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 65
; CHECK-NEXT: ret i1 [[TMP2]]
;
%cmp1 = icmp eq i32 %x, 97
define i1 @and_ne_with_one_bit_diff_constants2(i19 %x) {
; CHECK-LABEL: @and_ne_with_one_bit_diff_constants2(
-; CHECK-NEXT: [[TMP1:%.*]] = or i19 [[X:%.*]], 128
-; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i19 [[TMP1]], 193
+; CHECK-NEXT: [[TMP1:%.*]] = and i19 [[X:%.*]], -129
+; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i19 [[TMP1]], 65
; CHECK-NEXT: ret i1 [[TMP2]]
;
%cmp1 = icmp ne i19 %x, 65
define i1 @or_eq_with_one_bit_diff_constants3(i8 %x) {
; CHECK-LABEL: @or_eq_with_one_bit_diff_constants3(
-; CHECK-NEXT: [[TMP1:%.*]] = or i8 [[X:%.*]], -128
-; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i8 [[TMP1]], -2
+; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[X:%.*]], 127
+; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i8 [[TMP1]], 126
; CHECK-NEXT: ret i1 [[TMP2]]
;
%cmp1 = icmp eq i8 %x, 254
define i1 @and_ne_with_one_bit_diff_constants3(i8 %x) {
; CHECK-LABEL: @and_ne_with_one_bit_diff_constants3(
-; CHECK-NEXT: [[TMP1:%.*]] = or i8 [[X:%.*]], -128
-; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i8 [[TMP1]], -63
+; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[X:%.*]], 127
+; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i8 [[TMP1]], 65
; CHECK-NEXT: ret i1 [[TMP2]]
;
%cmp1 = icmp ne i8 %x, 65
define <2 x i1> @or_eq_with_one_bit_diff_constants2_splatvec(<2 x i32> %x) {
; CHECK-LABEL: @or_eq_with_one_bit_diff_constants2_splatvec(
-; CHECK-NEXT: [[TMP1:%.*]] = or <2 x i32> [[X:%.*]], <i32 32, i32 32>
-; CHECK-NEXT: [[TMP2:%.*]] = icmp eq <2 x i32> [[TMP1]], <i32 97, i32 97>
+; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i32> [[X:%.*]], <i32 -33, i32 -33>
+; CHECK-NEXT: [[TMP2:%.*]] = icmp eq <2 x i32> [[TMP1]], <i32 65, i32 65>
; CHECK-NEXT: ret <2 x i1> [[TMP2]]
;
%cmp1 = icmp eq <2 x i32> %x, <i32 97, i32 97>
define i32 @test3(i32 %a) #0 {
; CHECK-LABEL: @test3(
-; CHECK-NEXT: [[V:%.*]] = or i32 [[A:%.*]], -16
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[V]], -11
+; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[A:%.*]], 15
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP1]], 5
; CHECK-NEXT: tail call void @llvm.assume(i1 [[CMP]])
; CHECK-NEXT: ret i32 5
;
define i32 @test4(i32 %a) #0 {
; CHECK-LABEL: @test4(
-; CHECK-NEXT: [[V:%.*]] = or i32 [[A:%.*]], -16
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[V]], -6
+; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[A:%.*]], 15
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP1]], 10
; CHECK-NEXT: tail call void @llvm.assume(i1 [[CMP]])
; CHECK-NEXT: ret i32 2
;
define i1 @set_low_bit_mask_eq(i8 %x) {
; CHECK-LABEL: @set_low_bit_mask_eq(
-; CHECK-NEXT: [[SUB:%.*]] = or i8 [[X:%.*]], 1
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[SUB]], 19
+; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[X:%.*]], -2
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[TMP1]], 18
; CHECK-NEXT: ret i1 [[CMP]]
;
%sub = or i8 %x, 1
define <2 x i1> @set_low_bit_mask_ne(<2 x i8> %x) {
; CHECK-LABEL: @set_low_bit_mask_ne(
-; CHECK-NEXT: [[SUB:%.*]] = or <2 x i8> [[X:%.*]], <i8 3, i8 3>
-; CHECK-NEXT: [[CMP:%.*]] = icmp ne <2 x i8> [[SUB]], <i8 19, i8 19>
+; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i8> [[X:%.*]], <i8 -4, i8 -4>
+; CHECK-NEXT: [[CMP:%.*]] = icmp ne <2 x i8> [[TMP1]], <i8 16, i8 16>
; CHECK-NEXT: ret <2 x i1> [[CMP]]
;
%sub = or <2 x i8> %x, <i8 3, i8 3>
define i1 @icmp_sub_3_X_ult_2(i32 %X) {
; CHECK-LABEL: @icmp_sub_3_X_ult_2(
-; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[X:%.*]], 1
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP1]], 3
+; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[X:%.*]], -2
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP1]], 2
; CHECK-NEXT: ret i1 [[CMP]]
;
%add = sub i32 3, %X
define <2 x i1> @icmp_sub_3_X_ult_2_vec(<2 x i32> %X) {
; CHECK-LABEL: @icmp_sub_3_X_ult_2_vec(
-; CHECK-NEXT: [[TMP1:%.*]] = or <2 x i32> [[X:%.*]], <i32 1, i32 1>
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i32> [[TMP1]], <i32 3, i32 3>
+; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i32> [[X:%.*]], <i32 -2, i32 -2>
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i32> [[TMP1]], <i32 2, i32 2>
; CHECK-NEXT: ret <2 x i1> [[CMP]]
;
%add = sub <2 x i32> <i32 3, i32 3>, %X
define i1 @icmp_sub_3_X_uge_2(i32 %X) {
; CHECK-LABEL: @icmp_sub_3_X_uge_2(
-; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[X:%.*]], 1
-; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[TMP1]], 3
+; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[X:%.*]], -2
+; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[TMP1]], 2
; CHECK-NEXT: ret i1 [[CMP]]
;
%add = sub i32 3, %X
define <2 x i1> @icmp_sub_3_X_uge_2_vec(<2 x i32> %X) {
; CHECK-LABEL: @icmp_sub_3_X_uge_2_vec(
-; CHECK-NEXT: [[TMP1:%.*]] = or <2 x i32> [[X:%.*]], <i32 1, i32 1>
-; CHECK-NEXT: [[CMP:%.*]] = icmp ne <2 x i32> [[TMP1]], <i32 3, i32 3>
+; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i32> [[X:%.*]], <i32 -2, i32 -2>
+; CHECK-NEXT: [[CMP:%.*]] = icmp ne <2 x i32> [[TMP1]], <i32 2, i32 2>
; CHECK-NEXT: ret <2 x i1> [[CMP]]
;
%add = sub <2 x i32> <i32 3, i32 3>, %X
define i1 @test8(i32 %X) {
; CHECK-LABEL: @test8(
-; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[X:%.*]], 1
-; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 9
+; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[X:%.*]], -2
+; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 8
; CHECK-NEXT: ret i1 [[TMP2]]
;
%P = getelementptr inbounds [10 x i16], [10 x i16]* @G16, i32 0, i32 %X