[DAGCombiner] convert logic-of-setcc into bit magic (PR40611)

If we're comparing some value for equality against 2 constants
and those constants have an absolute difference of just 1 bit,
then we can offset and mask off that 1 bit and reduce to a single
compare against zero:
         and/or (setcc X, C0, ne), (setcc X, C1, ne/eq) -->
         setcc ((add X, -C1), ~(C0 - C1)), 0, ne/eq

https://rise4fun.com/Alive/XslKj

This transform is disabled by default using a TLI hook
("convertSetCCLogicToBitwiseLogic()").

That should be overridden for AArch64, MIPS, Sparc and possibly
others based on the asm shown in:
https://bugs.llvm.org/show_bug.cgi?id=40611

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@353859 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index ee0d7fd..c2404f9 100644
--- a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -4123,6 +4123,32 @@
       SDValue Zero = DAG.getConstant(0, DL, OpVT);
       return DAG.getSetCC(DL, VT, Or, Zero, CC1);
     }
+
+    // Turn compare of constants whose difference is 1 bit into add+and+setcc.
+    if ((IsAnd && CC1 == ISD::SETNE) || (!IsAnd && CC1 == ISD::SETEQ)) {
+      // Match a shared variable operand and 2 non-opaque constant operands.
+      ConstantSDNode *C0 = isConstOrConstSplat(LR);
+      ConstantSDNode *C1 = isConstOrConstSplat(RR);
+      if (LL == RL && C0 && C1 && !C0->isOpaque() && !C1->isOpaque()) {
+        // Canonicalize larger constant as C0.
+        if (C1->getAPIntValue().ugt(C0->getAPIntValue()))
+          std::swap(C0, C1);
+
+        // The difference of the constants must be a single bit.
+        const APInt &C0Val = C0->getAPIntValue();
+        const APInt &C1Val = C1->getAPIntValue();
+        if ((C0Val - C1Val).isPowerOf2()) {
+          // and/or (setcc X, C0, ne), (setcc X, C1, ne/eq) -->
+          // setcc ((add X, -C1), ~(C0 - C1)), 0, ne/eq
+          SDValue OffsetC = DAG.getConstant(-C1Val, DL, OpVT);
+          SDValue Add = DAG.getNode(ISD::ADD, DL, OpVT, LL, OffsetC);
+          SDValue MaskC = DAG.getConstant(~(C0Val - C1Val), DL, OpVT);
+          SDValue And = DAG.getNode(ISD::AND, DL, OpVT, Add, MaskC);
+          SDValue Zero = DAG.getConstant(0, DL, OpVT);
+          return DAG.getSetCC(DL, VT, And, Zero, CC0);
+        }
+      }
+    }
   }
 
   // Canonicalize equivalent operands to LL == RL.
diff --git a/test/CodeGen/PowerPC/setcc-logic.ll b/test/CodeGen/PowerPC/setcc-logic.ll
index b0a44ad..87f73e7 100644
--- a/test/CodeGen/PowerPC/setcc-logic.ll
+++ b/test/CodeGen/PowerPC/setcc-logic.ll
@@ -481,11 +481,11 @@
 define i1 @or_icmps_const_1bit_diff(i64 %x) {
 ; CHECK-LABEL: or_icmps_const_1bit_diff:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    cmpdi 3, 17
-; CHECK-NEXT:    cmpdi 1, 3, 13
-; CHECK-NEXT:    li 3, 1
-; CHECK-NEXT:    crnor 20, 2, 6
-; CHECK-NEXT:    isel 3, 0, 3, 20
+; CHECK-NEXT:    li 4, -5
+; CHECK-NEXT:    addi 3, 3, -13
+; CHECK-NEXT:    and 3, 3, 4
+; CHECK-NEXT:    cntlzd 3, 3
+; CHECK-NEXT:    rldicl 3, 3, 58, 63
 ; CHECK-NEXT:    blr
   %a = icmp eq i64 %x, 17
   %b = icmp eq i64 %x, 13
@@ -496,11 +496,11 @@
 define i1 @and_icmps_const_1bit_diff(i32 %x) {
 ; CHECK-LABEL: and_icmps_const_1bit_diff:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    cmpwi 3, 4625
-; CHECK-NEXT:    cmpwi 1, 3, 4641
-; CHECK-NEXT:    li 3, 1
-; CHECK-NEXT:    cror 20, 6, 2
-; CHECK-NEXT:    isel 3, 0, 3, 20
+; CHECK-NEXT:    addi 3, 3, -4625
+; CHECK-NEXT:    rlwinm 3, 3, 0, 28, 26
+; CHECK-NEXT:    cntlzw 3, 3
+; CHECK-NEXT:    nor 3, 3, 3
+; CHECK-NEXT:    rlwinm 3, 3, 27, 31, 31
 ; CHECK-NEXT:    blr
   %a = icmp ne i32 %x, 4625
   %b = icmp ne i32 %x, 4641
diff --git a/test/CodeGen/X86/setcc-logic.ll b/test/CodeGen/X86/setcc-logic.ll
index f95ce9b..46db927 100644
--- a/test/CodeGen/X86/setcc-logic.ll
+++ b/test/CodeGen/X86/setcc-logic.ll
@@ -485,11 +485,9 @@
 define i1 @or_icmps_const_1bit_diff(i8 %x) {
 ; CHECK-LABEL: or_icmps_const_1bit_diff:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    cmpb $43, %dil
-; CHECK-NEXT:    sete %cl
-; CHECK-NEXT:    cmpb $45, %dil
+; CHECK-NEXT:    addb $-43, %dil
+; CHECK-NEXT:    testb $-3, %dil
 ; CHECK-NEXT:    sete %al
-; CHECK-NEXT:    orb %cl, %al
 ; CHECK-NEXT:    retq
   %a = icmp eq i8 %x, 43
   %b = icmp eq i8 %x, 45
@@ -500,11 +498,9 @@
 define i1 @and_icmps_const_1bit_diff(i32 %x) {
 ; CHECK-LABEL: and_icmps_const_1bit_diff:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    cmpl $44, %edi
-; CHECK-NEXT:    setne %cl
-; CHECK-NEXT:    cmpl $60, %edi
+; CHECK-NEXT:    addl $-44, %edi
+; CHECK-NEXT:    testl $-17, %edi
 ; CHECK-NEXT:    setne %al
-; CHECK-NEXT:    andb %cl, %al
 ; CHECK-NEXT:    retq
   %a = icmp ne i32 %x, 44
   %b = icmp ne i32 %x, 60