Skip to content

Commit

Permalink
[SelectionDAG] Expand [US]CMP using arithmetic on boolean values
Browse files Browse the repository at this point in the history
The previous expansion of [US]CMP was done using two selects and two
compares. It produced decent code, but on many platforms it is better
to implement [US]CMP nodes by performing the following operation:
  [us]cmp(x, y) = (x [us]> y) - (x [us]< y)
This patch adds this new expansion, as well as a hook in TargetLowering
to allow some targets to still use the select-based approach.
  • Loading branch information
Poseydon42 committed Jul 13, 2024
1 parent 66cd2e0 commit 3ab33c8
Show file tree
Hide file tree
Showing 5 changed files with 2,374 additions and 2,853 deletions.
4 changes: 4 additions & 0 deletions llvm/include/llvm/CodeGen/TargetLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -3390,6 +3390,10 @@ class TargetLoweringBase {
return isOperationLegalOrCustom(Op, VT);
}

/// Should we expand [US]CMP nodes using two selects and two compares, or by
/// doing arithmetic on boolean types
virtual bool shouldExpandCmpUsingSelects() const { return false; }

/// Does this target support complex deinterleaving
virtual bool isComplexDeinterleavingSupported() const { return false; }

Expand Down
22 changes: 16 additions & 6 deletions llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10381,14 +10381,24 @@ SDValue TargetLowering::expandCMP(SDNode *Node, SelectionDAG &DAG) const {

auto LTPredicate = (Opcode == ISD::UCMP ? ISD::SETULT : ISD::SETLT);
auto GTPredicate = (Opcode == ISD::UCMP ? ISD::SETUGT : ISD::SETGT);

SDValue IsLT = DAG.getSetCC(dl, BoolVT, LHS, RHS, LTPredicate);
SDValue IsGT = DAG.getSetCC(dl, BoolVT, LHS, RHS, GTPredicate);
SDValue SelectZeroOrOne =
DAG.getSelect(dl, ResVT, IsGT, DAG.getConstant(1, dl, ResVT),
DAG.getConstant(0, dl, ResVT));
return DAG.getSelect(dl, ResVT, IsLT, DAG.getConstant(-1, dl, ResVT),
SelectZeroOrOne);

// We can't perform arithmetic on i1 values. Extending them would
// probably result in worse codegen, so let's just use two selects instead.
// Some targets are also just better off using selects rather than subtraction
// because one of the conditions can be merged with one of the selects
EVT BoolElVT = BoolVT.isVector() ? BoolVT.getVectorElementType() : BoolVT;
if (shouldExpandCmpUsingSelects() || !BoolElVT.knownBitsGT(MVT::i1)) {
SDValue SelectZeroOrOne =
DAG.getSelect(dl, ResVT, IsGT, DAG.getConstant(1, dl, ResVT),
DAG.getConstant(0, dl, ResVT));
return DAG.getSelect(dl, ResVT, IsLT, DAG.getConstant(-1, dl, ResVT),
SelectZeroOrOne);
}

return DAG.getSExtOrTrunc(DAG.getNode(ISD::SUB, dl, BoolVT, IsGT, IsLT), dl,
ResVT);
}

SDValue TargetLowering::expandShlSat(SDNode *Node, SelectionDAG &DAG) const {
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Target/AArch64/AArch64ISelLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -907,6 +907,8 @@ class AArch64TargetLowering : public TargetLowering {

bool shouldConvertFpToSat(unsigned Op, EVT FPVT, EVT VT) const override;

bool shouldExpandCmpUsingSelects() const override { return true; }

bool isComplexDeinterleavingSupported() const override;
bool isComplexDeinterleavingOperationSupported(
ComplexDeinterleavingOperation Operation, Type *Ty) const override;
Expand Down
Loading

0 comments on commit 3ab33c8

Please sign in to comment.