Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions llvm/lib/Target/X86/X86ISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51651,6 +51651,31 @@ static SDValue combineAndXorSubWithBMI(SDNode *And, const SDLoc &DL,
return AndN;
}

// fold (not (or A, B)) -> nand(A, not(B)) if BMI
static SDValue
combineReassocDemorganWithNANDWithBMI(SDNode *Xor, const SDLoc &DL,
SelectionDAG &DAG,
const X86Subtarget &Subtarget) {
using namespace llvm::SDPatternMatch;

EVT VT = Xor->getValueType(0);
// Make sure this node is a candidate for BMI instructions.
if (!Subtarget.hasBMI() || (VT != MVT::i32 && VT != MVT::i64))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please can this be handled generically in DAGCombine

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But there is no ISD::ANDN (at least that I know of)
So do you want to generally reassociate it? For all cases?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Search DAGCombiner.cpp for hasAndNot

return SDValue();

SDValue A;
SDValue B;
APInt Cst;
if (!(sd_match(Xor, m_Xor(m_Or(m_Value(A), m_Value(B)), m_ConstInt(Cst))) &&
Cst.isAllOnes()))
return SDValue();

auto Opcode =
Subtarget.is64Bit() && VT == MVT::i64 ? X86::ANDN64rr : X86::ANDN32rr;
auto AndN = DAG.getMachineNode(Opcode, DL, VT, A, DAG.getNOT(DL, B, VT));
return SDValue(AndN, 0);
}

static SDValue combineX86SubCmpForFlags(SDNode *N, SDValue Flag,
SelectionDAG &DAG,
TargetLowering::DAGCombinerInfo &DCI,
Expand Down Expand Up @@ -55150,6 +55175,9 @@ static SDValue combineXor(SDNode *N, SelectionDAG &DAG,
if (SDValue R = combineBMILogicOp(N, DAG, Subtarget))
return R;

if (SDValue R = combineReassocDemorganWithNANDWithBMI(N, DL, DAG, Subtarget))
return R;

return combineFneg(N, DAG, DCI, Subtarget);
}

Expand Down
98 changes: 98 additions & 0 deletions llvm/test/CodeGen/X86/bmi-reassoc-demorgan.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc < %s -mtriple=i686-unknown-unknown -mattr=+bmi | FileCheck %s --check-prefix=X86
; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+bmi | FileCheck %s --check-prefix=X64

define i32 @reassoc_demorgan_i32(i32 %a, i32 %b) nounwind {
; X86-LABEL: reassoc_demorgan_i32:
; X86: # %bb.0:
; X86-NEXT: movl {{[0-9]+}}(%esp), %eax
; X86-NEXT: movl {{[0-9]+}}(%esp), %ecx
; X86-NEXT: notl %ecx
; X86-NEXT: andnl %ecx, %eax, %eax
; X86-NEXT: retl
;
; X64-LABEL: reassoc_demorgan_i32:
; X64: # %bb.0:
; X64-NEXT: notl %edi
; X64-NEXT: andnl %edi, %esi, %eax
; X64-NEXT: retq
%temp = or i32 %b, %a
%res = xor i32 %temp, -1
ret i32 %res
}

define i32 @reassoc_demorgan_three_arguments_i32(i32 %a, i32 %b, i32 %c) nounwind {
; X86-LABEL: reassoc_demorgan_three_arguments_i32:
; X86: # %bb.0:
; X86-NEXT: movl {{[0-9]+}}(%esp), %eax
; X86-NEXT: movl {{[0-9]+}}(%esp), %ecx
; X86-NEXT: orl {{[0-9]+}}(%esp), %ecx
; X86-NEXT: notl %eax
; X86-NEXT: andnl %eax, %ecx, %eax
; X86-NEXT: retl
;
; X64-LABEL: reassoc_demorgan_three_arguments_i32:
; X64: # %bb.0:
; X64-NEXT: orl %esi, %edi
; X64-NEXT: notl %edx
; X64-NEXT: andnl %edx, %edi, %eax
; X64-NEXT: retq
%and.demorgan = or i32 %b, %a
%and3.demorgan = or i32 %and.demorgan, %c
%and3 = xor i32 %and3.demorgan, -1
ret i32 %and3
}

define i64 @reassoc_demorgan_i64(i64 %a, i64 %b) nounwind {
; X86-LABEL: reassoc_demorgan_i64:
; X86: # %bb.0:
; X86-NEXT: pushl %esi
; X86-NEXT: movl {{[0-9]+}}(%esp), %eax
; X86-NEXT: movl {{[0-9]+}}(%esp), %ecx
; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
; X86-NEXT: movl {{[0-9]+}}(%esp), %esi
; X86-NEXT: notl %edx
; X86-NEXT: andnl %edx, %eax, %eax
; X86-NEXT: notl %esi
; X86-NEXT: andnl %esi, %ecx, %edx
; X86-NEXT: popl %esi
; X86-NEXT: retl
;
; X64-LABEL: reassoc_demorgan_i64:
; X64: # %bb.0:
; X64-NEXT: notq %rdi
; X64-NEXT: andnq %rdi, %rsi, %rax
; X64-NEXT: retq
%temp = or i64 %b, %a
%res = xor i64 %temp, -1
ret i64 %res
}

define i64 @reassoc_demorgan_three_arguments_i64(i64 %a, i64 %b, i64 %c) nounwind {
; X86-LABEL: reassoc_demorgan_three_arguments_i64:
; X86: # %bb.0:
; X86-NEXT: pushl %esi
; X86-NEXT: movl {{[0-9]+}}(%esp), %eax
; X86-NEXT: movl {{[0-9]+}}(%esp), %ecx
; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
; X86-NEXT: movl {{[0-9]+}}(%esp), %esi
; X86-NEXT: orl {{[0-9]+}}(%esp), %esi
; X86-NEXT: orl {{[0-9]+}}(%esp), %edx
; X86-NEXT: notl %eax
; X86-NEXT: andnl %eax, %edx, %eax
; X86-NEXT: notl %ecx
; X86-NEXT: andnl %ecx, %esi, %edx
; X86-NEXT: popl %esi
; X86-NEXT: retl
;
; X64-LABEL: reassoc_demorgan_three_arguments_i64:
; X64: # %bb.0:
; X64-NEXT: orq %rsi, %rdi
; X64-NEXT: notq %rdx
; X64-NEXT: andnq %rdx, %rdi, %rax
; X64-NEXT: retq
%and.demorgan = or i64 %b, %a
%and3.demorgan = or i64 %and.demorgan, %c
%and3 = xor i64 %and3.demorgan, -1
ret i64 %and3
}
Loading