Index: include/llvm/Target/TargetLowering.h =================================================================== --- include/llvm/Target/TargetLowering.h +++ include/llvm/Target/TargetLowering.h @@ -437,6 +437,15 @@ return false; } + /// Use bitwise logic to make pairs of compares more efficient. For example: + /// and (seteq A, B), (seteq C, D) --> seteq (or (xor A, B), (xor C, D)), 0 + /// This should be true when it takes more than one instruction to lower + /// setcc (cmp+set on x86 scalar), when bitwise ops are faster than logic on + /// condition bits (crand on PowerPC), and/or when reducing cmp+br is a win. + virtual bool convertSetCCLogicToBitwiseLogic(EVT VT) const { + return false; + } + /// Return the preferred operand type if the target has a quick way to compare /// integer values of the given size. Assume that any legal integer type can /// be compared efficiently. Targets may override this to allow illegal wide Index: lib/CodeGen/SelectionDAG/DAGCombiner.cpp =================================================================== --- lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -3255,6 +3255,21 @@ return DAG.getSetCC(DL, VT, Add, Two, ISD::SETUGE); } + // Try more general transforms if the predicates match and the only user of + // the compares is the 'and' or 'or'. + if (IsInteger && TLI.convertSetCCLogicToBitwiseLogic(OpVT) && CC0 == CC1 && + N0.hasOneUse() && N1.hasOneUse()) { + // and (seteq A, B), (seteq C, D) --> seteq (or (xor A, B), (xor C, D)), 0 + // or (setne A, B), (setne C, D) --> setne (or (xor A, B), (xor C, D)), 0 + if ((IsAnd && CC1 == ISD::SETEQ) || (!IsAnd && CC1 == ISD::SETNE)) { + SDValue XorL = DAG.getNode(ISD::XOR, SDLoc(N0), OpVT, LL, LR); + SDValue XorR = DAG.getNode(ISD::XOR, SDLoc(N1), OpVT, RL, RR); + SDValue Or = DAG.getNode(ISD::OR, DL, OpVT, XorL, XorR); + SDValue Zero = DAG.getConstant(0, DL, OpVT); + return DAG.getSetCC(DL, VT, Or, Zero, CC1); + } + } + // Canonicalize equivalent operands to LL == RL. if (LL == RR && LR == RL) { CC1 = ISD::getSetCCSwappedOperands(CC1); Index: lib/Target/ARM/ARMISelLowering.h =================================================================== --- lib/Target/ARM/ARMISelLowering.h +++ lib/Target/ARM/ARMISelLowering.h @@ -515,6 +515,10 @@ bool isCheapToSpeculateCttz() const override; bool isCheapToSpeculateCtlz() const override; + bool convertSetCCLogicToBitwiseLogic(EVT VT) const override { + return VT.isScalarInteger(); + } + bool supportSwiftError() const override { return true; } Index: lib/Target/PowerPC/PPCISelLowering.h =================================================================== --- lib/Target/PowerPC/PPCISelLowering.h +++ lib/Target/PowerPC/PPCISelLowering.h @@ -531,6 +531,10 @@ return true; } + bool convertSetCCLogicToBitwiseLogic(EVT VT) const override { + return VT.isScalarInteger(); + } + bool supportSplitCSR(MachineFunction *MF) const override { return MF->getFunction()->getCallingConv() == CallingConv::CXX_FAST_TLS && Index: lib/Target/X86/X86ISelLowering.h =================================================================== --- lib/Target/X86/X86ISelLowering.h +++ lib/Target/X86/X86ISelLowering.h @@ -814,6 +814,10 @@ bool hasAndNotCompare(SDValue Y) const override; + bool convertSetCCLogicToBitwiseLogic(EVT VT) const override { + return VT.isScalarInteger(); + } + /// Vector-sized comparisons are fast using PCMPEQ + PMOVMSK or PTEST. MVT hasFastEqualityCompare(unsigned NumBits) const override; Index: test/CodeGen/ARM/setcc-logic.ll =================================================================== --- test/CodeGen/ARM/setcc-logic.ll +++ test/CodeGen/ARM/setcc-logic.ll @@ -20,13 +20,11 @@ define zeroext i1 @and_eq(i32 %a, i32 %b, i32 %c, i32 %d) nounwind { ; CHECK-LABEL: and_eq: ; CHECK: @ BB#0: -; CHECK-NEXT: cmp r2, r3 -; CHECK-NEXT: mov r2, #0 -; CHECK-NEXT: movweq r2, #1 -; CHECK-NEXT: mov r12, #0 -; CHECK-NEXT: cmp r0, r1 -; CHECK-NEXT: movweq r12, #1 -; CHECK-NEXT: and r0, r12, r2 +; CHECK-NEXT: eor r2, r2, r3 +; CHECK-NEXT: eor r0, r0, r1 +; CHECK-NEXT: orrs r0, r0, r2 +; CHECK-NEXT: mov r0, #0 +; CHECK-NEXT: movweq r0, #1 ; CHECK-NEXT: bx lr %cmp1 = icmp eq i32 %a, %b %cmp2 = icmp eq i32 %c, %d @@ -37,13 +35,10 @@ define zeroext i1 @or_ne(i32 %a, i32 %b, i32 %c, i32 %d) nounwind { ; CHECK-LABEL: or_ne: ; CHECK: @ BB#0: -; CHECK-NEXT: cmp r2, r3 -; CHECK-NEXT: mov r2, #0 -; CHECK-NEXT: movwne r2, #1 -; CHECK-NEXT: mov r12, #0 -; CHECK-NEXT: cmp r0, r1 -; CHECK-NEXT: movwne r12, #1 -; CHECK-NEXT: orr r0, r12, r2 +; CHECK-NEXT: eor r2, r2, r3 +; CHECK-NEXT: eor r0, r0, r1 +; CHECK-NEXT: orrs r0, r0, r2 +; CHECK-NEXT: movwne r0, #1 ; CHECK-NEXT: bx lr %cmp1 = icmp ne i32 %a, %b %cmp2 = icmp ne i32 %c, %d Index: test/CodeGen/PowerPC/setcc-logic.ll =================================================================== --- test/CodeGen/PowerPC/setcc-logic.ll +++ test/CodeGen/PowerPC/setcc-logic.ll @@ -433,11 +433,11 @@ define zeroext i1 @and_eq(i16 zeroext %a, i16 zeroext %b, i16 zeroext %c, i16 zeroext %d) { ; CHECK-LABEL: and_eq: ; CHECK: # BB#0: -; CHECK-NEXT: cmpw 0, 3, 4 -; CHECK-NEXT: cmpw 1, 5, 6 -; CHECK-NEXT: li 3, 1 -; CHECK-NEXT: crnand 20, 2, 6 -; CHECK-NEXT: isel 3, 0, 3, 20 +; CHECK-NEXT: xor 5, 5, 6 +; CHECK-NEXT: xor 3, 3, 4 +; CHECK-NEXT: or 3, 3, 5 +; CHECK-NEXT: cntlzw 3, 3 +; CHECK-NEXT: rlwinm 3, 3, 27, 31, 31 ; CHECK-NEXT: blr %cmp1 = icmp eq i16 %a, %b %cmp2 = icmp eq i16 %c, %d @@ -448,11 +448,12 @@ define zeroext i1 @or_ne(i32 %a, i32 %b, i32 %c, i32 %d) { ; CHECK-LABEL: or_ne: ; CHECK: # BB#0: -; CHECK-NEXT: cmpw 0, 3, 4 -; CHECK-NEXT: cmpw 1, 5, 6 -; CHECK-NEXT: li 3, 1 -; CHECK-NEXT: crand 20, 6, 2 -; CHECK-NEXT: isel 3, 0, 3, 20 +; CHECK-NEXT: xor 5, 5, 6 +; CHECK-NEXT: xor 3, 3, 4 +; CHECK-NEXT: or 3, 3, 5 +; CHECK-NEXT: cntlzw 3, 3 +; CHECK-NEXT: nor 3, 3, 3 +; CHECK-NEXT: rlwinm 3, 3, 27, 31, 31 ; CHECK-NEXT: blr %cmp1 = icmp ne i32 %a, %b %cmp2 = icmp ne i32 %c, %d Index: test/CodeGen/X86/avx512-cmp.ll =================================================================== --- test/CodeGen/X86/avx512-cmp.ll +++ test/CodeGen/X86/avx512-cmp.ll @@ -120,12 +120,12 @@ define i32 @test8(i32 %a1, i32 %a2, i32 %a3) { ; ALL-LABEL: test8: ; ALL: ## BB#0: +; ALL-NEXT: notl %edi +; ALL-NEXT: xorl $-2147483648, %esi ## imm = 0x80000000 ; ALL-NEXT: testl %edx, %edx ; ALL-NEXT: movl $1, %eax ; ALL-NEXT: cmovel %eax, %edx -; ALL-NEXT: cmpl $-2147483648, %esi ## imm = 0x80000000 -; ALL-NEXT: cmovnel %edx, %eax -; ALL-NEXT: cmpl $-1, %edi +; ALL-NEXT: orl %edi, %esi ; ALL-NEXT: cmovnel %edx, %eax ; ALL-NEXT: retq %tmp1 = icmp eq i32 %a1, -1 Index: test/CodeGen/X86/setcc-logic.ll =================================================================== --- test/CodeGen/X86/setcc-logic.ll +++ test/CodeGen/X86/setcc-logic.ll @@ -440,11 +440,10 @@ define zeroext i1 @and_eq(i8 %a, i8 %b, i8 %c, i8 %d) nounwind { ; CHECK-LABEL: and_eq: ; CHECK: # BB#0: -; CHECK-NEXT: cmpb %sil, %dil -; CHECK-NEXT: sete %sil -; CHECK-NEXT: cmpb %cl, %dl +; CHECK-NEXT: xorl %esi, %edi +; CHECK-NEXT: xorl %ecx, %edx +; CHECK-NEXT: orb %dl, %dil ; CHECK-NEXT: sete %al -; CHECK-NEXT: andb %sil, %al ; CHECK-NEXT: retq %cmp1 = icmp eq i8 %a, %b %cmp2 = icmp eq i8 %c, %d @@ -455,11 +454,10 @@ define zeroext i1 @or_ne(i8 %a, i8 %b, i8 %c, i8 %d) nounwind { ; CHECK-LABEL: or_ne: ; CHECK: # BB#0: -; CHECK-NEXT: cmpb %sil, %dil -; CHECK-NEXT: setne %sil -; CHECK-NEXT: cmpb %cl, %dl +; CHECK-NEXT: xorl %esi, %edi +; CHECK-NEXT: xorl %ecx, %edx +; CHECK-NEXT: orb %dl, %dil ; CHECK-NEXT: setne %al -; CHECK-NEXT: orb %sil, %al ; CHECK-NEXT: retq %cmp1 = icmp ne i8 %a, %b %cmp2 = icmp ne i8 %c, %d