From: Sanjay Patel Date: Tue, 12 Feb 2019 17:07:47 +0000 (+0000) Subject: [DAGCombiner] convert logic-of-setcc into bit magic (PR40611) X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=51dad635adaf53f3e5d2d563fccbe786244de7f7;p=llvm [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 ee0d7fdd056..c2404f963ce 100644 --- a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -4123,6 +4123,32 @@ SDValue DAGCombiner::foldLogicOfSetCCs(bool IsAnd, SDValue N0, SDValue N1, 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 b0a44ad6b5b..87f73e7b2e8 100644 --- a/test/CodeGen/PowerPC/setcc-logic.ll +++ b/test/CodeGen/PowerPC/setcc-logic.ll @@ -481,11 +481,11 @@ define <4 x i1> @and_eq_vec(<4 x i32> %a, <4 x i32> %b, <4 x i32> %c, <4 x i32> 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 @or_icmps_const_1bit_diff(i64 %x) { 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 f95ce9bfae2..46db9271d31 100644 --- a/test/CodeGen/X86/setcc-logic.ll +++ b/test/CodeGen/X86/setcc-logic.ll @@ -485,11 +485,9 @@ define <4 x i1> @and_eq_vec(<4 x i32> %a, <4 x i32> %b, <4 x i32> %c, <4 x i32> 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 @or_icmps_const_1bit_diff(i8 %x) { 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