Index: lib/CodeGen/SelectionDAG/DAGCombiner.cpp =================================================================== --- lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -5575,6 +5575,35 @@ if (SDValue Tmp = SimplifyBinOpWithSameOpcodeHands(N)) return Tmp; + // Apply DeMorgan's Law for 'nand' logic with an inverted operand. + // xor (and (xor A, -1), B), -1 -> or (xor B, -1), A + if (isAllOnesConstant(N1)) { + SDValue A, B; + + auto matchAB = [&A, &B](SDValue And, bool swapXors) -> bool { + if (And.getOpcode() != ISD::AND || !And.hasOneUse()) + return false; + SDValue X0 = And->getOperand(0); + SDValue X1 = And->getOperand(1); + if (X0.getOpcode() != ISD::XOR || swapXors) + std::swap(X1, X0); + if (X0.getOpcode() != ISD::XOR || !isAllOnesConstant(X0->getOperand(1)) || + !X0.hasOneUse()) + return false; + A = X0->getOperand(0); + B = X1; + return true; + }; + + if (matchAB(N0, false) || matchAB(N0, true) || matchAB(N1, false) || + matchAB(N1, true)) { + SDLoc DL(N); + + SDValue NotB = DAG.getNOT(DL, B, VT); + return DAG.getNode(ISD::OR, DL, VT, NotB, A); + } + } + // Unfold ((x ^ y) & m) ^ y into (x & m) | (y & ~m) if profitable if (SDValue MM = unfoldMaskedMerge(N)) return MM; Index: test/CodeGen/AArch64/unfold-masked-merge-scalar-variablemask.ll =================================================================== --- test/CodeGen/AArch64/unfold-masked-merge-scalar-variablemask.ll +++ test/CodeGen/AArch64/unfold-masked-merge-scalar-variablemask.ll @@ -347,8 +347,7 @@ define i32 @in_constant_varx_mone(i32 %x, i32 %y, i32 %mask) { ; CHECK-LABEL: in_constant_varx_mone: ; CHECK: // %bb.0: -; CHECK-NEXT: and w8, w0, w2 -; CHECK-NEXT: orn w0, w8, w2 +; CHECK-NEXT: orn w0, w0, w2 ; CHECK-NEXT: ret %n0 = xor i32 %x, -1 ; %x %n1 = and i32 %n0, %mask @@ -370,8 +369,7 @@ define i32 @in_constant_varx_mone_invmask(i32 %x, i32 %y, i32 %mask) { ; CHECK-LABEL: in_constant_varx_mone_invmask: ; CHECK: // %bb.0: -; CHECK-NEXT: bic w8, w0, w2 -; CHECK-NEXT: orr w0, w8, w2 +; CHECK-NEXT: orr w0, w2, w0 ; CHECK-NEXT: ret %notmask = xor i32 %mask, -1 %n0 = xor i32 %x, -1 ; %x Index: test/CodeGen/MIR/Generic/demorgan-extra.ll =================================================================== --- test/CodeGen/MIR/Generic/demorgan-extra.ll +++ test/CodeGen/MIR/Generic/demorgan-extra.ll @@ -17,12 +17,11 @@ ; CHECK: liveins: $edi, $esi ; CHECK: [[COPY:%[0-9]+]]:gr32 = COPY $esi ; CHECK: [[COPY1:%[0-9]+]]:gr32 = COPY $edi - ; CHECK: [[COPY2:%[0-9]+]]:gr8 = COPY [[COPY]].sub_8bit - ; CHECK: [[COPY3:%[0-9]+]]:gr8 = COPY [[COPY1]].sub_8bit + ; CHECK: [[COPY2:%[0-9]+]]:gr8 = COPY [[COPY1]].sub_8bit + ; CHECK: [[COPY3:%[0-9]+]]:gr8 = COPY [[COPY]].sub_8bit ; CHECK: [[NOT8r:%[0-9]+]]:gr8 = NOT8r [[COPY3]] - ; CHECK: [[AND8rr:%[0-9]+]]:gr8 = AND8rr [[NOT8r]], killed [[COPY2]], implicit-def dead $eflags - ; CHECK: [[NOT8r1:%[0-9]+]]:gr8 = NOT8r [[AND8rr]] - ; CHECK: $al = COPY [[NOT8r1]] + ; CHECK: [[OR8rr:%[0-9]+]]:gr8 = OR8rr [[NOT8r]], killed [[COPY2]], implicit-def dead $eflags + ; CHECK: $al = COPY [[OR8rr]] ; CHECK: RET 0, $al %notx = xor i8 %A, -1 %c = and i8 %notx, %B @@ -40,10 +39,9 @@ ; CHECK: CALL64pcrel32 @gen8, csr_64, implicit $rsp, implicit $ssp, implicit-def $rsp, implicit-def $ssp, implicit-def $al ; CHECK: ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp ; CHECK: [[COPY2:%[0-9]+]]:gr8 = COPY $al - ; CHECK: [[NOT8r:%[0-9]+]]:gr8 = NOT8r [[COPY1]] - ; CHECK: [[AND8rr:%[0-9]+]]:gr8 = AND8rr [[COPY2]], killed [[NOT8r]], implicit-def dead $eflags - ; CHECK: [[NOT8r1:%[0-9]+]]:gr8 = NOT8r [[AND8rr]] - ; CHECK: $al = COPY [[NOT8r1]] + ; CHECK: [[NOT8r:%[0-9]+]]:gr8 = NOT8r [[COPY2]] + ; CHECK: [[OR8rr:%[0-9]+]]:gr8 = OR8rr [[NOT8r]], killed [[COPY1]], implicit-def dead $eflags + ; CHECK: $al = COPY [[OR8rr]] ; CHECK: RET 0, $al %B = call i8 @gen8() %notx = xor i8 %A, -1 @@ -67,10 +65,9 @@ ; CHECK: ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp ; CHECK: [[COPY3:%[0-9]+]]:gr8 = COPY $al ; CHECK: [[XOR8rr:%[0-9]+]]:gr8 = XOR8rr [[COPY2]], [[COPY3]], implicit-def dead $eflags - ; CHECK: [[NOT8r:%[0-9]+]]:gr8 = NOT8r [[COPY1]] - ; CHECK: [[AND8rr:%[0-9]+]]:gr8 = AND8rr [[NOT8r]], killed [[XOR8rr]], implicit-def dead $eflags - ; CHECK: [[NOT8r1:%[0-9]+]]:gr8 = NOT8r [[AND8rr]] - ; CHECK: $al = COPY [[NOT8r1]] + ; CHECK: [[NOT8r:%[0-9]+]]:gr8 = NOT8r [[XOR8rr]] + ; CHECK: [[OR8rr:%[0-9]+]]:gr8 = OR8rr [[NOT8r]], killed [[COPY1]], implicit-def dead $eflags + ; CHECK: $al = COPY [[OR8rr]] ; CHECK: RET 0, $al %V = call i8 @gen8() %Z = call i8 @gen8() @@ -96,10 +93,9 @@ ; CHECK: ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp ; CHECK: [[COPY3:%[0-9]+]]:gr8 = COPY $al ; CHECK: [[XOR8rr:%[0-9]+]]:gr8 = XOR8rr [[COPY2]], [[COPY3]], implicit-def dead $eflags - ; CHECK: [[NOT8r:%[0-9]+]]:gr8 = NOT8r [[COPY1]] - ; CHECK: [[AND8rr:%[0-9]+]]:gr8 = AND8rr [[XOR8rr]], killed [[NOT8r]], implicit-def dead $eflags - ; CHECK: [[NOT8r1:%[0-9]+]]:gr8 = NOT8r [[AND8rr]] - ; CHECK: $al = COPY [[NOT8r1]] + ; CHECK: [[NOT8r:%[0-9]+]]:gr8 = NOT8r [[XOR8rr]] + ; CHECK: [[OR8rr:%[0-9]+]]:gr8 = OR8rr [[NOT8r]], killed [[COPY1]], implicit-def dead $eflags + ; CHECK: $al = COPY [[OR8rr]] ; CHECK: RET 0, $al %V = call i8 @gen8() %Z = call i8 @gen8() Index: test/CodeGen/MIR/Generic/demorgan.ll =================================================================== --- test/CodeGen/MIR/Generic/demorgan.ll +++ test/CodeGen/MIR/Generic/demorgan.ll @@ -245,11 +245,8 @@ ; CHECK: liveins: $edi, $esi ; CHECK: [[COPY:%[0-9]+]]:gr32 = COPY $esi ; CHECK: [[COPY1:%[0-9]+]]:gr32 = COPY $edi - ; CHECK: [[NOT32r:%[0-9]+]]:gr32 = NOT32r [[COPY1]] - ; CHECK: [[NOT32r1:%[0-9]+]]:gr32 = NOT32r [[COPY]] - ; CHECK: [[AND32rr:%[0-9]+]]:gr32 = AND32rr [[NOT32r]], killed [[NOT32r1]], implicit-def dead $eflags - ; CHECK: [[NOT32r2:%[0-9]+]]:gr32 = NOT32r [[AND32rr]] - ; CHECK: $eax = COPY [[NOT32r2]] + ; CHECK: [[OR32rr:%[0-9]+]]:gr32 = OR32rr [[COPY]], [[COPY1]], implicit-def dead $eflags + ; CHECK: $eax = COPY [[OR32rr]] ; CHECK: RET 0, $eax %nota = xor i32 %A, -1 %notb = xor i32 %B, -1 @@ -306,12 +303,8 @@ ; CHECK: liveins: $rdi, $rsi ; CHECK: [[COPY:%[0-9]+]]:gr64 = COPY $rsi ; CHECK: [[COPY1:%[0-9]+]]:gr64 = COPY $rdi - ; CHECK: [[MOV64ri:%[0-9]+]]:gr64 = MOV64ri 140737488355327 - ; CHECK: [[XOR64rr:%[0-9]+]]:gr64 = XOR64rr [[COPY1]], [[MOV64ri]], implicit-def dead $eflags - ; CHECK: [[XOR64rr1:%[0-9]+]]:gr64 = XOR64rr [[COPY]], [[MOV64ri]], implicit-def dead $eflags - ; CHECK: [[AND64rr:%[0-9]+]]:gr64 = AND64rr [[XOR64rr]], killed [[XOR64rr1]], implicit-def dead $eflags - ; CHECK: [[XOR64rr2:%[0-9]+]]:gr64 = XOR64rr [[AND64rr]], [[MOV64ri]], implicit-def dead $eflags - ; CHECK: $rax = COPY [[XOR64rr2]] + ; CHECK: [[OR64rr:%[0-9]+]]:gr64 = OR64rr [[COPY]], [[COPY1]], implicit-def dead $eflags + ; CHECK: $rax = COPY [[OR64rr]] ; CHECK: RET 0, $rax %nota = xor i47 %A, -1 %notb = xor i47 %B, -1 @@ -378,12 +371,11 @@ ; CHECK: liveins: $edi, $esi ; CHECK: [[COPY:%[0-9]+]]:gr32 = COPY $esi ; CHECK: [[COPY1:%[0-9]+]]:gr32 = COPY $edi - ; CHECK: [[COPY2:%[0-9]+]]:gr8 = COPY [[COPY]].sub_8bit - ; CHECK: [[COPY3:%[0-9]+]]:gr8 = COPY [[COPY1]].sub_8bit + ; CHECK: [[COPY2:%[0-9]+]]:gr8 = COPY [[COPY1]].sub_8bit + ; CHECK: [[COPY3:%[0-9]+]]:gr8 = COPY [[COPY]].sub_8bit ; CHECK: [[NOT8r:%[0-9]+]]:gr8 = NOT8r [[COPY3]] - ; CHECK: [[AND8rr:%[0-9]+]]:gr8 = AND8rr [[NOT8r]], killed [[COPY2]], implicit-def dead $eflags - ; CHECK: [[NOT8r1:%[0-9]+]]:gr8 = NOT8r [[AND8rr]] - ; CHECK: $al = COPY [[NOT8r1]] + ; CHECK: [[OR8rr:%[0-9]+]]:gr8 = OR8rr [[NOT8r]], killed [[COPY2]], implicit-def dead $eflags + ; CHECK: $al = COPY [[OR8rr]] ; CHECK: RET 0, $al %notx = xor i8 %A, -1 %c = and i8 %notx, %B @@ -399,12 +391,11 @@ ; CHECK: liveins: $edi, $esi ; CHECK: [[COPY:%[0-9]+]]:gr32 = COPY $esi ; CHECK: [[COPY1:%[0-9]+]]:gr32 = COPY $edi - ; CHECK: [[COPY2:%[0-9]+]]:gr8 = COPY [[COPY]].sub_8bit - ; CHECK: [[COPY3:%[0-9]+]]:gr8 = COPY [[COPY1]].sub_8bit + ; CHECK: [[COPY2:%[0-9]+]]:gr8 = COPY [[COPY1]].sub_8bit + ; CHECK: [[COPY3:%[0-9]+]]:gr8 = COPY [[COPY]].sub_8bit ; CHECK: [[XOR8ri:%[0-9]+]]:gr8 = XOR8ri [[COPY3]], 127, implicit-def dead $eflags - ; CHECK: [[AND8rr:%[0-9]+]]:gr8 = AND8rr [[XOR8ri]], killed [[COPY2]], implicit-def dead $eflags - ; CHECK: [[XOR8ri1:%[0-9]+]]:gr8 = XOR8ri [[AND8rr]], 127, implicit-def dead $eflags - ; CHECK: $al = COPY [[XOR8ri1]] + ; CHECK: [[OR8rr:%[0-9]+]]:gr8 = OR8rr [[XOR8ri]], killed [[COPY2]], implicit-def dead $eflags + ; CHECK: $al = COPY [[OR8rr]] ; CHECK: RET 0, $al %nota = xor i7 %A, -1 %c = and i7 %nota, %B @@ -422,15 +413,13 @@ ; CHECK: [[COPY1:%[0-9]+]]:gr64 = COPY $rdx ; CHECK: [[COPY2:%[0-9]+]]:gr64 = COPY $rsi ; CHECK: [[COPY3:%[0-9]+]]:gr64 = COPY $rdi + ; CHECK: [[NOT64r:%[0-9]+]]:gr64 = NOT64r [[COPY1]] + ; CHECK: [[OR64rr:%[0-9]+]]:gr64 = OR64rr [[NOT64r]], [[COPY3]], implicit-def dead $eflags ; CHECK: [[MOV64ri:%[0-9]+]]:gr64 = MOV64ri 9007199254740991 - ; CHECK: [[XOR64rr:%[0-9]+]]:gr64 = XOR64rr [[COPY2]], [[MOV64ri]], implicit-def dead $eflags - ; CHECK: [[NOT64r:%[0-9]+]]:gr64 = NOT64r [[COPY3]] - ; CHECK: [[AND64rr:%[0-9]+]]:gr64 = AND64rr [[NOT64r]], [[COPY1]], implicit-def dead $eflags - ; CHECK: [[AND64rr1:%[0-9]+]]:gr64 = AND64rr [[XOR64rr]], [[COPY]], implicit-def dead $eflags - ; CHECK: [[XOR64rr1:%[0-9]+]]:gr64 = XOR64rr [[AND64rr1]], [[MOV64ri]], implicit-def dead $eflags - ; CHECK: [[NOT64r1:%[0-9]+]]:gr64 = NOT64r [[AND64rr]] - ; CHECK: $rax = COPY [[NOT64r1]] - ; CHECK: $rdx = COPY [[XOR64rr1]] + ; CHECK: [[XOR64rr:%[0-9]+]]:gr64 = XOR64rr [[COPY]], killed [[MOV64ri]], implicit-def dead $eflags + ; CHECK: [[OR64rr1:%[0-9]+]]:gr64 = OR64rr [[XOR64rr]], [[COPY2]], implicit-def dead $eflags + ; CHECK: $rax = COPY [[OR64rr]] + ; CHECK: $rdx = COPY [[OR64rr1]] ; CHECK: RET 0, $rax, $rdx %nota = xor i117 %A, -1 %c = and i117 %nota, %B Index: test/CodeGen/X86/unfold-masked-merge-scalar-variablemask.ll =================================================================== --- test/CodeGen/X86/unfold-masked-merge-scalar-variablemask.ll +++ test/CodeGen/X86/unfold-masked-merge-scalar-variablemask.ll @@ -562,15 +562,13 @@ define i32 @in_constant_varx_mone(i32 %x, i32 %y, i32 %mask) { ; CHECK-NOBMI-LABEL: in_constant_varx_mone: ; CHECK-NOBMI: # %bb.0: -; CHECK-NOBMI-NEXT: notl %edi -; CHECK-NOBMI-NEXT: andl %edx, %edi -; CHECK-NOBMI-NEXT: notl %edi -; CHECK-NOBMI-NEXT: movl %edi, %eax +; CHECK-NOBMI-NEXT: notl %edx +; CHECK-NOBMI-NEXT: orl %edi, %edx +; CHECK-NOBMI-NEXT: movl %edx, %eax ; CHECK-NOBMI-NEXT: retq ; ; CHECK-BMI-LABEL: in_constant_varx_mone: ; CHECK-BMI: # %bb.0: -; CHECK-BMI-NEXT: andl %edx, %edi ; CHECK-BMI-NEXT: notl %edx ; CHECK-BMI-NEXT: orl %edi, %edx ; CHECK-BMI-NEXT: movl %edx, %eax @@ -603,17 +601,14 @@ define i32 @in_constant_varx_mone_invmask(i32 %x, i32 %y, i32 %mask) { ; CHECK-NOBMI-LABEL: in_constant_varx_mone_invmask: ; CHECK-NOBMI: # %bb.0: -; CHECK-NOBMI-NEXT: notl %edx -; CHECK-NOBMI-NEXT: notl %edi -; CHECK-NOBMI-NEXT: andl %edx, %edi -; CHECK-NOBMI-NEXT: notl %edi +; CHECK-NOBMI-NEXT: orl %edx, %edi ; CHECK-NOBMI-NEXT: movl %edi, %eax ; CHECK-NOBMI-NEXT: retq ; ; CHECK-BMI-LABEL: in_constant_varx_mone_invmask: ; CHECK-BMI: # %bb.0: -; CHECK-BMI-NEXT: andnl %edi, %edx, %eax -; CHECK-BMI-NEXT: orl %edx, %eax +; CHECK-BMI-NEXT: orl %edx, %edi +; CHECK-BMI-NEXT: movl %edi, %eax ; CHECK-BMI-NEXT: retq %notmask = xor i32 %mask, -1 %n0 = xor i32 %x, -1 ; %x