Skip to content

Commit

Permalink
[GISel] Combine (neg (max x, (neg x))) into (min x, (neg x))
Browse files Browse the repository at this point in the history
This is the GISel version of llvm#120666.
  • Loading branch information
mshockwave committed Dec 23, 2024
1 parent 2886576 commit 0776f0a
Show file tree
Hide file tree
Showing 7 changed files with 523 additions and 2 deletions.
3 changes: 3 additions & 0 deletions llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -829,6 +829,9 @@ class CombinerHelper {
/// Combine select to integer min/max.
bool matchSelectIMinMax(const MachineOperand &MO, BuildFnTy &MatchInfo);

/// Combine neg + min/max
bool matchSimplifyNegMinMax(MachineInstr &MI, BuildFnTy &MatchInfo);

/// Combine selects.
bool matchSelect(MachineInstr &MI, BuildFnTy &MatchInfo);

Expand Down
4 changes: 4 additions & 0 deletions llvm/include/llvm/CodeGen/GlobalISel/Utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,10 @@ void reportGISelWarning(MachineFunction &MF, const TargetPassConfig &TPC,
MachineOptimizationRemarkEmitter &MORE,
MachineOptimizationRemarkMissed &R);

/// Returns the inverse opcode of \p MinMaxOpc , which is a generic min/max
/// opcode like G_SMIN.
unsigned getInverseGMinMaxOpcode(unsigned MinMaxOpc);

/// If \p VReg is defined by a G_CONSTANT, return the corresponding value.
std::optional<APInt> getIConstantVRegVal(Register VReg,
const MachineRegisterInfo &MRI);
Expand Down
8 changes: 7 additions & 1 deletion llvm/include/llvm/Target/GlobalISel/Combine.td
Original file line number Diff line number Diff line change
Expand Up @@ -1372,6 +1372,12 @@ def select_to_iminmax: GICombineRule<
[{ return Helper.matchSelectIMinMax(${root}, ${info}); }]),
(apply [{ Helper.applyBuildFnMO(${root}, ${info}); }])>;

def simplify_neg_minmax : GICombineRule<
(defs root:$root, build_fn_matchinfo:$matchinfo),
(match (wip_match_opcode G_SUB):$root,
[{ return Helper.matchSimplifyNegMinMax(*${root}, ${matchinfo}); }]),
(apply [{ Helper.applyBuildFn(*${root}, ${matchinfo}); }])>;

def match_selects : GICombineRule<
(defs root:$root, build_fn_matchinfo:$matchinfo),
(match (wip_match_opcode G_SELECT):$root,
Expand Down Expand Up @@ -2008,7 +2014,7 @@ def all_combines : GICombineGroup<[integer_reassoc_combines, trivial_combines,
and_or_disjoint_mask, fma_combines, fold_binop_into_select,
sub_add_reg, select_to_minmax,
fsub_to_fneg, commute_constant_to_rhs, match_ands, match_ors,
combine_concat_vector,
simplify_neg_minmax, combine_concat_vector,
sext_trunc, zext_trunc, prefer_sign_combines, shuffle_combines,
combine_use_vector_truncate, merge_combines, overflow_combines]>;

Expand Down
36 changes: 36 additions & 0 deletions llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6999,6 +6999,42 @@ bool CombinerHelper::matchSelectIMinMax(const MachineOperand &MO,
}
}

// (neg (min/max x, (neg x))) --> (max/min x, (neg x))
bool CombinerHelper::matchSimplifyNegMinMax(MachineInstr &MI,
BuildFnTy &MatchInfo) {
assert(MI.getOpcode() == TargetOpcode::G_SUB);
Register DestReg = MI.getOperand(0).getReg();
LLT DestTy = MRI.getType(DestReg);
if (!isLegal({TargetOpcode::G_SUB, {DestTy}}))
return false;

// GISel doesn't have m_Deferred at this moment, so we have to
// match this pattern in two phases.
Register X, Y;
Register Sub0;
if (mi_match(DestReg, MRI,
m_Neg(m_OneUse(m_any_of(
m_GSMin(m_Reg(X), m_Reg(Y)), m_GSMax(m_Reg(X), m_Reg(Y)),
m_CommutativeBinOp(TargetOpcode::G_UMIN, m_Reg(X), m_Reg(Y)),
m_CommutativeBinOp(TargetOpcode::G_UMAX, m_Reg(X),
m_Reg(Y)))))) &&
(mi_match(Y, MRI, m_all_of(m_Neg(m_SpecificReg(X)), m_Reg(Sub0))) ||
mi_match(X, MRI, m_all_of(m_Neg(m_SpecificReg(Y)), m_Reg(Sub0))))) {
MachineInstr *MinMaxMI = MRI.getVRegDef(MI.getOperand(2).getReg());
MachineInstr *Sub0MI = MRI.getVRegDef(Sub0);
X = Sub0MI->getOperand(2).getReg();
unsigned NewOpc = getInverseGMinMaxOpcode(MinMaxMI->getOpcode());
if (isLegal({NewOpc, {DestTy}})) {
MatchInfo = [=](MachineIRBuilder &B) {
B.buildInstr(NewOpc, {DestReg}, {X, Sub0});
};
return true;
}
}

return false;
}

bool CombinerHelper::matchSelect(MachineInstr &MI, BuildFnTy &MatchInfo) {
GSelect *Select = cast<GSelect>(&MI);

Expand Down
15 changes: 15 additions & 0 deletions llvm/lib/CodeGen/GlobalISel/Utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,21 @@ void llvm::reportGISelFailure(MachineFunction &MF, const TargetPassConfig &TPC,
reportGISelFailure(MF, TPC, MORE, R);
}

unsigned llvm::getInverseGMinMaxOpcode(unsigned MinMaxOpc) {
switch (MinMaxOpc) {
case TargetOpcode::G_SMIN:
return TargetOpcode::G_SMAX;
case TargetOpcode::G_SMAX:
return TargetOpcode::G_SMIN;
case TargetOpcode::G_UMIN:
return TargetOpcode::G_UMAX;
case TargetOpcode::G_UMAX:
return TargetOpcode::G_UMIN;
default:
llvm_unreachable("unrecognized opcode");
}
}

std::optional<APInt> llvm::getIConstantVRegVal(Register VReg,
const MachineRegisterInfo &MRI) {
std::optional<ValueAndVReg> ValAndVReg = getIConstantVRegValWithLookThrough(
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Target/RISCV/RISCVCombine.td
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,5 @@ def RISCVPostLegalizerCombiner
: GICombiner<"RISCVPostLegalizerCombinerImpl",
[sub_to_add, combines_for_extload, redundant_and,
identity_combines, shift_immed_chain,
commute_constant_to_rhs]> {
commute_constant_to_rhs, simplify_neg_minmax]> {
}
Loading

0 comments on commit 0776f0a

Please sign in to comment.