[InstCombine] fold icmp equality with 'or' mask ops

This could go either direction since the instruction
count is the same either way, but there are a few
reasons to prefer this:
1. We already do the related transform with 'and'
   (see just above the new code).
2. We try (too hard) to compensate for not having this
   and possibly other folds in transformZExtICmp(),
   and that leads to bugs like https://llvm.org/PR51762 .
3. Codegen looks better across a variety of targets.

https://alive2.llvm.org/ce/z/uEgn4P
This commit is contained in:
Sanjay Patel 2021-09-07 16:24:21 -04:00
parent 9565457aad
commit a3c1669b17
2 changed files with 29 additions and 6 deletions

View File

@ -4465,6 +4465,19 @@ Instruction *InstCombinerImpl::foldICmpEquality(ICmpInst &I) {
}
}
{
// Similar to above, but specialized for constant because invert is needed:
// (X | C) == (Y | C) --> (X ^ Y) & ~C == 0
Value *X, *Y;
Constant *C;
if (match(Op0, m_OneUse(m_Or(m_Value(X), m_Constant(C)))) &&
match(Op1, m_OneUse(m_Or(m_Value(Y), m_Specific(C))))) {
Value *Xor = Builder.CreateXor(X, Y);
Value *And = Builder.CreateAnd(Xor, ConstantExpr::getNot(C));
return new ICmpInst(Pred, And, Constant::getNullValue(And->getType()));
}
}
// Transform (zext A) == (B & (1<<X)-1) --> A == (trunc B)
// and (B & (1<<X)-1) == (zext A) --> A == (trunc B)
ConstantInt *Cst1;

View File

@ -113,9 +113,9 @@ define i1 @set_low_bit_mask_sle(i8 %x) {
define i1 @eq_const_mask(i8 %x, i8 %y) {
; CHECK-LABEL: @eq_const_mask(
; CHECK-NEXT: [[B0:%.*]] = or i8 [[X:%.*]], 42
; CHECK-NEXT: [[B1:%.*]] = or i8 [[Y:%.*]], 42
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[B0]], [[B1]]
; CHECK-NEXT: [[TMP1:%.*]] = xor i8 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[TMP2:%.*]] = and i8 [[TMP1]], -43
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[TMP2]], 0
; CHECK-NEXT: ret i1 [[CMP]]
;
%b0 = or i8 %x, 42
@ -126,9 +126,9 @@ define i1 @eq_const_mask(i8 %x, i8 %y) {
define <2 x i1> @ne_const_mask(<2 x i8> %x, <2 x i8> %y) {
; CHECK-LABEL: @ne_const_mask(
; CHECK-NEXT: [[B0:%.*]] = or <2 x i8> [[X:%.*]], <i8 -106, i8 5>
; CHECK-NEXT: [[B1:%.*]] = or <2 x i8> [[Y:%.*]], <i8 -106, i8 5>
; CHECK-NEXT: [[CMP:%.*]] = icmp ne <2 x i8> [[B0]], [[B1]]
; CHECK-NEXT: [[TMP1:%.*]] = xor <2 x i8> [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[TMP2:%.*]] = and <2 x i8> [[TMP1]], <i8 105, i8 -6>
; CHECK-NEXT: [[CMP:%.*]] = icmp ne <2 x i8> [[TMP2]], zeroinitializer
; CHECK-NEXT: ret <2 x i1> [[CMP]]
;
%b0 = or <2 x i8> %x, <i8 150, i8 5>
@ -137,6 +137,8 @@ define <2 x i1> @ne_const_mask(<2 x i8> %x, <2 x i8> %y) {
ret <2 x i1> %cmp
}
; negative test - predicate
define i1 @eq_const_mask_not_equality(i8 %x, i8 %y) {
; CHECK-LABEL: @eq_const_mask_not_equality(
; CHECK-NEXT: [[B0:%.*]] = or i8 [[X:%.*]], 5
@ -150,6 +152,8 @@ define i1 @eq_const_mask_not_equality(i8 %x, i8 %y) {
ret i1 %cmp
}
; negative test - mismatched constants
define i1 @eq_const_mask_not_same(i8 %x, i8 %y) {
; CHECK-LABEL: @eq_const_mask_not_same(
; CHECK-NEXT: [[B0:%.*]] = or i8 [[X:%.*]], 5
@ -163,6 +167,8 @@ define i1 @eq_const_mask_not_same(i8 %x, i8 %y) {
ret i1 %cmp
}
; negative test - mismatched logic
define i1 @eq_const_mask_wrong_opcode(i8 %x, i8 %y) {
; CHECK-LABEL: @eq_const_mask_wrong_opcode(
; CHECK-NEXT: [[B0:%.*]] = or i8 [[X:%.*]], 5
@ -176,6 +182,8 @@ define i1 @eq_const_mask_wrong_opcode(i8 %x, i8 %y) {
ret i1 %cmp
}
; negative test - no extra uses
define i1 @eq_const_mask_use1(i8 %x, i8 %y) {
; CHECK-LABEL: @eq_const_mask_use1(
; CHECK-NEXT: [[B0:%.*]] = or i8 [[X:%.*]], 5
@ -191,6 +199,8 @@ define i1 @eq_const_mask_use1(i8 %x, i8 %y) {
ret i1 %cmp
}
; negative test - no extra uses
define i1 @eq_const_mask_use2(i8 %x, i8 %y) {
; CHECK-LABEL: @eq_const_mask_use2(
; CHECK-NEXT: [[B0:%.*]] = or i8 [[X:%.*]], 5