Skip to content

Commit 2291d0a

Browse files
authored
[DAGCombiner] Turn (neg (max x, (neg x))) into (min x, (neg x)) (#120666)
This pattern was originally spotted in 429.mcf by @topperc. We already have a DAGCombiner pattern to turn `(neg (abs x))` into `(min x, (neg x))`. But in some cases `(neg (max x, (neg x)))` is formed by an expanded `abs` followed by a `neg` that is generated only after the `abs` expansion. This patch adds a separate pattern to match cases like this, as well as its inverse pattern: `(neg (min X, (neg X))) --> (max X, (neg X))`. This pattern is applicable to both signed and unsigned min/max.
1 parent 976f3a0 commit 2291d0a

File tree

5 files changed

+534
-0
lines changed

5 files changed

+534
-0
lines changed

llvm/include/llvm/CodeGen/ISDOpcodes.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1495,6 +1495,10 @@ inline bool isBitwiseLogicOp(unsigned Opcode) {
14951495
return Opcode == ISD::AND || Opcode == ISD::OR || Opcode == ISD::XOR;
14961496
}
14971497

1498+
/// Given a \p MinMaxOpc of ISD::(U|S)MIN or ISD::(U|S)MAX, returns
1499+
/// ISD::(U|S)MAX and ISD::(U|S)MIN, respectively.
1500+
NodeType getInverseMinMaxOpcode(unsigned MinMaxOpc);
1501+
14981502
/// Get underlying scalar opcode for VECREDUCE opcode.
14991503
/// For example ISD::AND for ISD::VECREDUCE_AND.
15001504
NodeType getVecReduceBaseOpcode(unsigned VecReduceOpcode);

llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3949,6 +3949,23 @@ SDValue DAGCombiner::visitSUB(SDNode *N) {
39493949
if (SDValue Result = TLI.expandABS(N1.getNode(), DAG, true))
39503950
return Result;
39513951

3952+
// Similar to the previous rule, but this time targeting an expanded abs.
3953+
// (sub 0, (max X, (sub 0, X))) --> (min X, (sub 0, X))
3954+
// as well as
3955+
// (sub 0, (min X, (sub 0, X))) --> (max X, (sub 0, X))
3956+
// Note that these two are applicable to both signed and unsigned min/max.
3957+
SDValue X;
3958+
SDValue S0;
3959+
auto NegPat = m_AllOf(m_Neg(m_Deferred(X)), m_Value(S0));
3960+
if (sd_match(N1, m_OneUse(m_AnyOf(m_SMax(m_Value(X), NegPat),
3961+
m_UMax(m_Value(X), NegPat),
3962+
m_SMin(m_Value(X), NegPat),
3963+
m_UMin(m_Value(X), NegPat))))) {
3964+
unsigned NewOpc = ISD::getInverseMinMaxOpcode(N1->getOpcode());
3965+
if (hasOperation(NewOpc, VT))
3966+
return DAG.getNode(NewOpc, DL, VT, X, S0);
3967+
}
3968+
39523969
// Fold neg(splat(neg(x)) -> splat(x)
39533970
if (VT.isVector()) {
39543971
SDValue N1S = DAG.getSplatValue(N1, true);

llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,21 @@ bool ISD::matchBinaryPredicate(
430430
return true;
431431
}
432432

433+
ISD::NodeType ISD::getInverseMinMaxOpcode(unsigned MinMaxOpc) {
434+
switch (MinMaxOpc) {
435+
default:
436+
llvm_unreachable("unrecognized opcode");
437+
case ISD::UMIN:
438+
return ISD::UMAX;
439+
case ISD::UMAX:
440+
return ISD::UMIN;
441+
case ISD::SMIN:
442+
return ISD::SMAX;
443+
case ISD::SMAX:
444+
return ISD::SMIN;
445+
}
446+
}
447+
433448
ISD::NodeType ISD::getVecReduceBaseOpcode(unsigned VecReduceOpcode) {
434449
switch (VecReduceOpcode) {
435450
default:

0 commit comments

Comments
 (0)