Skip to content

Commit dd1ad26

Browse files
committed
[DAG] add (~a | x) & (a | y) -> (a & (x ^ y)) ^y for foldMaskedMerge
1 parent 3f80009 commit dd1ad26

File tree

2 files changed

+63
-50
lines changed

2 files changed

+63
-50
lines changed

llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp

Lines changed: 37 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7204,6 +7204,39 @@ static SDValue foldLogicTreeOfShifts(SDNode *N, SDValue LeftHand,
72047204
return DAG.getNode(LogicOpcode, DL, VT, CombinedShifts, W);
72057205
}
72067206

7207+
/// Fold "masked merge" expressions like `(m & x) | (~m & y)` and its DeMorgan
7208+
/// variant `(~m | x) & (m | y)` into the equivalent `((x ^ y) & m) ^ y)`
7209+
/// pattern. This is typically a better representation for targets without a
7210+
/// fused "and-not" operation.
7211+
static SDValue foldMaskedMerge(SDNode *Node, SelectionDAG &DAG,
7212+
const TargetLowering &TLI, const SDLoc &DL) {
7213+
// Note that masked-merge variants using XOR or ADD expressions are
7214+
// normalized to OR by InstCombine so we only check for OR or AND.
7215+
assert(Node->getOpcode() == ISD::OR ||
7216+
Node->getOpcode() == ISD::AND &&
7217+
"Must be called with ISD::OR or ISD::AND node");
7218+
7219+
// If the target supports and-not, don't fold this.
7220+
if (TLI.hasAndNot(SDValue(Node, 0)))
7221+
return SDValue();
7222+
7223+
SDValue M, X, Y;
7224+
7225+
if (sd_match(Node,
7226+
m_Or(m_OneUse(m_And(m_OneUse(m_Not(m_Value(M))), m_Value(Y))),
7227+
m_OneUse(m_And(m_Deferred(M), m_Value(X))))) ||
7228+
sd_match(Node,
7229+
m_And(m_OneUse(m_Or(m_OneUse(m_Not(m_Value(M))), m_Value(X))),
7230+
m_OneUse(m_Or(m_Deferred(M), m_Value(Y)))))) {
7231+
EVT VT = M.getValueType();
7232+
SDValue Xor = DAG.getNode(ISD::XOR, DL, VT, X, Y);
7233+
SDValue And = DAG.getNode(ISD::AND, DL, VT, Xor, M);
7234+
return DAG.getNode(ISD::XOR, DL, VT, And, Y);
7235+
}
7236+
7237+
return SDValue();
7238+
}
7239+
72077240
SDValue DAGCombiner::visitAND(SDNode *N) {
72087241
SDValue N0 = N->getOperand(0);
72097242
SDValue N1 = N->getOperand(1);
@@ -7644,6 +7677,10 @@ SDValue DAGCombiner::visitAND(SDNode *N) {
76447677
if (SDValue R = foldLogicTreeOfShifts(N, N0, N1, DAG))
76457678
return R;
76467679

7680+
if (VT.isScalarInteger() && VT != MVT::i1)
7681+
if (SDValue R = foldMaskedMerge(N, DAG, TLI, DL))
7682+
return R;
7683+
76477684
return SDValue();
76487685
}
76497686

@@ -8128,32 +8165,6 @@ static SDValue visitORCommutative(SelectionDAG &DAG, SDValue N0, SDValue N1,
81288165
return SDValue();
81298166
}
81308167

8131-
/// Fold "masked merge" expressions like `(m & x) | (~m & y)` into the
8132-
/// equivalent `((x ^ y) & m) ^ y)` pattern.
8133-
/// This is typically a better representation for targets without a fused
8134-
/// "and-not" operation.
8135-
static SDValue foldMaskedMerge(SDNode *Node, SelectionDAG &DAG,
8136-
const TargetLowering &TLI, const SDLoc &DL) {
8137-
// Note that masked-merge variants using XOR or ADD expressions are
8138-
// normalized to OR by InstCombine so we only check for OR.
8139-
assert(Node->getOpcode() == ISD::OR && "Must be called with ISD::OR node");
8140-
8141-
// If the target supports and-not, don't fold this.
8142-
if (TLI.hasAndNot(SDValue(Node, 0)))
8143-
return SDValue();
8144-
8145-
SDValue M, X, Y;
8146-
if (sd_match(Node,
8147-
m_Or(m_OneUse(m_And(m_OneUse(m_Not(m_Value(M))), m_Value(Y))),
8148-
m_OneUse(m_And(m_Deferred(M), m_Value(X)))))) {
8149-
EVT VT = M.getValueType();
8150-
SDValue Xor = DAG.getNode(ISD::XOR, DL, VT, X, Y);
8151-
SDValue And = DAG.getNode(ISD::AND, DL, VT, Xor, M);
8152-
return DAG.getNode(ISD::XOR, DL, VT, And, Y);
8153-
}
8154-
return SDValue();
8155-
}
8156-
81578168
SDValue DAGCombiner::visitOR(SDNode *N) {
81588169
SDValue N0 = N->getOperand(0);
81598170
SDValue N1 = N->getOperand(1);

llvm/test/CodeGen/X86/fold-masked-merge-demorgan.ll

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,10 @@
88
define i32 @masked_merge0_demorgan(i32 %a0, i32 %a1, i32 %a2) {
99
; NOBMI-LABEL: masked_merge0_demorgan:
1010
; NOBMI: # %bb.0:
11-
; NOBMI-NEXT: orl %edi, %edx
12-
; NOBMI-NEXT: movl %edi, %eax
13-
; NOBMI-NEXT: notl %eax
14-
; NOBMI-NEXT: orl %esi, %eax
15-
; NOBMI-NEXT: andl %edx, %eax
11+
; NOBMI-NEXT: movl %esi, %eax
12+
; NOBMI-NEXT: xorl %edx, %eax
13+
; NOBMI-NEXT: andl %edi, %eax
14+
; NOBMI-NEXT: xorl %edx, %eax
1615
; NOBMI-NEXT: retq
1716
;
1817
; BMI-LABEL: masked_merge0_demorgan:
@@ -29,15 +28,22 @@ define i32 @masked_merge0_demorgan(i32 %a0, i32 %a1, i32 %a2) {
2928
}
3029

3130
define i16 @masked_merge1_demorgan(i16 %a0, i16 %a1, i16 %a2) {
32-
; CHECK-LABEL: masked_merge1_demorgan:
33-
; CHECK: # %bb.0:
34-
; CHECK-NEXT: orl %edi, %edx
35-
; CHECK-NEXT: movl %edi, %eax
36-
; CHECK-NEXT: notl %eax
37-
; CHECK-NEXT: orl %esi, %eax
38-
; CHECK-NEXT: andl %edx, %eax
39-
; CHECK-NEXT: # kill: def $ax killed $ax killed $eax
40-
; CHECK-NEXT: retq
31+
; NOBMI-LABEL: masked_merge1_demorgan:
32+
; NOBMI: # %bb.0:
33+
; NOBMI-NEXT: movl %esi, %eax
34+
; NOBMI-NEXT: xorl %edx, %eax
35+
; NOBMI-NEXT: andl %edi, %eax
36+
; NOBMI-NEXT: xorl %edx, %eax
37+
; NOBMI-NEXT: # kill: def $ax killed $ax killed $eax
38+
; NOBMI-NEXT: retq
39+
;
40+
; BMI-LABEL: masked_merge1_demorgan:
41+
; BMI: # %bb.0:
42+
; BMI-NEXT: andnl %edx, %edi, %eax
43+
; BMI-NEXT: andl %edi, %esi
44+
; BMI-NEXT: orl %esi, %eax
45+
; BMI-NEXT: # kill: def $ax killed $ax killed $eax
46+
; BMI-NEXT: retq
4147
%not = xor i16 %a0, -1
4248
%or0 = or i16 %not, %a1
4349
%or1 = or i16 %a0, %a2
@@ -48,11 +54,8 @@ define i16 @masked_merge1_demorgan(i16 %a0, i16 %a1, i16 %a2) {
4854
define i8 @masked_merge2_demorgan(i8 %a0, i8 %a1, i8 %a2) {
4955
; CHECK-LABEL: masked_merge2_demorgan:
5056
; CHECK: # %bb.0:
51-
; CHECK-NEXT: movl %edi, %eax
52-
; CHECK-NEXT: notb %al
53-
; CHECK-NEXT: orb %sil, %al
54-
; CHECK-NEXT: orb %sil, %dil
55-
; CHECK-NEXT: andb %dil, %al
57+
; CHECK-NEXT: movl %esi, %eax
58+
; CHECK-NEXT: # kill: def $al killed $al killed $eax
5659
; CHECK-NEXT: retq
5760
%not = xor i8 %a0, -1
5861
%or0 = or i8 %not, %a1
@@ -64,13 +67,12 @@ define i8 @masked_merge2_demorgan(i8 %a0, i8 %a1, i8 %a2) {
6467
define i64 @masked_merge3_demorgan(i64 %a0, i64 %a1, i64 %a2) {
6568
; NOBMI-LABEL: masked_merge3_demorgan:
6669
; NOBMI: # %bb.0:
70+
; NOBMI-NEXT: movq %rsi, %rax
6771
; NOBMI-NEXT: notq %rdx
68-
; NOBMI-NEXT: orq %rdi, %rdx
69-
; NOBMI-NEXT: movq %rdi, %rax
72+
; NOBMI-NEXT: xorq %rdx, %rax
7073
; NOBMI-NEXT: notq %rax
71-
; NOBMI-NEXT: notq %rsi
72-
; NOBMI-NEXT: orq %rsi, %rax
73-
; NOBMI-NEXT: andq %rdx, %rax
74+
; NOBMI-NEXT: andq %rdi, %rax
75+
; NOBMI-NEXT: xorq %rdx, %rax
7476
; NOBMI-NEXT: retq
7577
;
7678
; BMI-LABEL: masked_merge3_demorgan:

0 commit comments

Comments
 (0)