Skip to content

Commit

Permalink
[Intrinsic] Signed and Unsigned Saturation Subtraction Intirnsics
Browse files Browse the repository at this point in the history
Add an intrinsic that takes 2 integers and perform saturation subtraction on
them.

This is a part of implementing fixed point arithmetic in clang where some of
the more complex operations will be implemented as intrinsics.

Differential Revision: https://reviews.llvm.org/D53783

llvm-svn: 345512
  • Loading branch information
PiJoules committed Oct 29, 2018
1 parent 71c989a commit 905abe5
Show file tree
Hide file tree
Showing 16 changed files with 546 additions and 41 deletions.
8 changes: 8 additions & 0 deletions llvm/include/llvm/CodeGen/ISDOpcodes.h
Expand Up @@ -264,6 +264,14 @@ namespace ISD {
/// resulting value is this minimum value.
SADDSAT, UADDSAT,

/// RESULT = [US]SUBSAT(LHS, RHS) - Perform saturation subtraction on 2
/// integers with the same bit width (W). If the true value of LHS - RHS
/// exceeds the largest value that can be represented by W bits, the
/// resulting value is this maximum value. Otherwise, if this value is less
/// than the smallest value that can be represented by W bits, the
/// resulting value is this minimum value.
SSUBSAT, USUBSAT,

/// Simple binary floating point operators.
FADD, FSUB, FMUL, FDIV, FREM,

Expand Down
7 changes: 4 additions & 3 deletions llvm/include/llvm/CodeGen/TargetLowering.h
Expand Up @@ -3736,9 +3736,10 @@ class TargetLowering : public TargetLoweringBase {
SDValue getVectorElementPointer(SelectionDAG &DAG, SDValue VecPtr, EVT VecVT,
SDValue Index) const;

/// Method for building the DAG expansion of ISD::[US]ADDSAT. This method
/// accepts integers or vectors of integers as its arguments.
SDValue getExpandedSaturationAddition(SDNode *Node, SelectionDAG &DAG) const;
/// Method for building the DAG expansion of ISD::[US][ADD|SUB]SAT. This
/// method accepts integers or vectors of integers as its arguments.
SDValue getExpandedSaturationAdditionSubtraction(SDNode *Node,
SelectionDAG &DAG) const;

//===--------------------------------------------------------------------===//
// Instruction Emitting Hooks
Expand Down
6 changes: 6 additions & 0 deletions llvm/include/llvm/IR/Intrinsics.td
Expand Up @@ -716,6 +716,12 @@ def int_sadd_sat : Intrinsic<[llvm_anyint_ty],
def int_uadd_sat : Intrinsic<[llvm_anyint_ty],
[LLVMMatchType<0>, LLVMMatchType<0>],
[IntrNoMem, IntrSpeculatable, Commutative]>;
def int_ssub_sat : Intrinsic<[llvm_anyint_ty],
[LLVMMatchType<0>, LLVMMatchType<0>],
[IntrNoMem, IntrSpeculatable]>;
def int_usub_sat : Intrinsic<[llvm_anyint_ty],
[LLVMMatchType<0>, LLVMMatchType<0>],
[IntrNoMem, IntrSpeculatable]>;

//===------------------------- Memory Use Markers -------------------------===//
//
Expand Down
2 changes: 2 additions & 0 deletions llvm/include/llvm/Target/TargetSelectionDAG.td
Expand Up @@ -375,6 +375,8 @@ def umax : SDNode<"ISD::UMAX" , SDTIntBinOp,

def saddsat : SDNode<"ISD::SADDSAT" , SDTIntBinOp, [SDNPCommutative]>;
def uaddsat : SDNode<"ISD::UADDSAT" , SDTIntBinOp, [SDNPCommutative]>;
def ssubsat : SDNode<"ISD::SSUBSAT" , SDTIntBinOp>;
def usubsat : SDNode<"ISD::USUBSAT" , SDTIntBinOp>;

def sext_inreg : SDNode<"ISD::SIGN_EXTEND_INREG", SDTExtInreg>;
def sext_invec : SDNode<"ISD::SIGN_EXTEND_VECTOR_INREG", SDTExtInvec>;
Expand Down
10 changes: 7 additions & 3 deletions llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
Expand Up @@ -1115,7 +1115,9 @@ void SelectionDAGLegalize::LegalizeOp(SDNode *Node) {
Node->getValueType(0));
break;
case ISD::SADDSAT:
case ISD::UADDSAT: {
case ISD::UADDSAT:
case ISD::SSUBSAT:
case ISD::USUBSAT: {
Action = TLI.getOperationAction(Node->getOpcode(), Node->getValueType(0));
break;
}
Expand Down Expand Up @@ -3254,8 +3256,10 @@ bool SelectionDAGLegalize::ExpandNode(SDNode *Node) {
break;
}
case ISD::SADDSAT:
case ISD::UADDSAT: {
Results.push_back(TLI.getExpandedSaturationAddition(Node, DAG));
case ISD::UADDSAT:
case ISD::SSUBSAT:
case ISD::USUBSAT: {
Results.push_back(TLI.getExpandedSaturationAdditionSubtraction(Node, DAG));
break;
}
case ISD::SADDO:
Expand Down
35 changes: 25 additions & 10 deletions llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp
Expand Up @@ -142,7 +142,9 @@ void DAGTypeLegalizer::PromoteIntegerResult(SDNode *N, unsigned ResNo) {
case ISD::SUBCARRY: Res = PromoteIntRes_ADDSUBCARRY(N, ResNo); break;

case ISD::SADDSAT:
case ISD::UADDSAT: Res = PromoteIntRes_ADDSAT(N); break;
case ISD::UADDSAT:
case ISD::SSUBSAT:
case ISD::USUBSAT: Res = PromoteIntRes_ADDSUBSAT(N); break;

case ISD::ATOMIC_LOAD:
Res = PromoteIntRes_Atomic0(cast<AtomicSDNode>(N)); break;
Expand Down Expand Up @@ -549,21 +551,32 @@ SDValue DAGTypeLegalizer::PromoteIntRes_Overflow(SDNode *N) {
return SDValue(Res.getNode(), 1);
}

SDValue DAGTypeLegalizer::PromoteIntRes_ADDSAT(SDNode *N) {
SDValue DAGTypeLegalizer::PromoteIntRes_ADDSUBSAT(SDNode *N) {
// For promoting iN -> iM, this can be expanded by
// 1. ANY_EXTEND iN to iM
// 2. SHL by M-N
// 3. U/SADDSAT
// 3. [US][ADD|SUB]SAT
// 4. L/ASHR by M-N
SDLoc dl(N);
SDValue Op1 = N->getOperand(0);
SDValue Op2 = N->getOperand(1);
unsigned OldBits = Op1.getValueSizeInBits();

unsigned Opcode = N->getOpcode();
assert((Opcode == ISD::SADDSAT || Opcode == ISD::UADDSAT) &&
"Expected opcode to be SADDSAT or UADDSAT");
unsigned ShiftOp = Opcode == ISD::SADDSAT ? ISD::SRA : ISD::SRL;
unsigned ShiftOp;
switch (Opcode) {
case ISD::SADDSAT:
case ISD::SSUBSAT:
ShiftOp = ISD::SRA;
break;
case ISD::UADDSAT:
case ISD::USUBSAT:
ShiftOp = ISD::SRL;
break;
default:
llvm_unreachable("Expected opcode to be signed or unsigned saturation "
"addition or subtraction");
}

SDValue Op1Promoted = GetPromotedInteger(Op1);
SDValue Op2Promoted = GetPromotedInteger(Op2);
Expand Down Expand Up @@ -1505,7 +1518,9 @@ void DAGTypeLegalizer::ExpandIntegerResult(SDNode *N, unsigned ResNo) {
case ISD::SMULO: ExpandIntRes_XMULO(N, Lo, Hi); break;

case ISD::SADDSAT:
case ISD::UADDSAT: ExpandIntRes_ADDSAT(N, Lo, Hi); break;
case ISD::UADDSAT:
case ISD::SSUBSAT:
case ISD::USUBSAT: ExpandIntRes_ADDSUBSAT(N, Lo, Hi); break;
}

// If Lo/Hi is null, the sub-method took care of registering results etc.
Expand Down Expand Up @@ -2468,9 +2483,9 @@ void DAGTypeLegalizer::ExpandIntRes_READCYCLECOUNTER(SDNode *N, SDValue &Lo,
ReplaceValueWith(SDValue(N, 1), R.getValue(2));
}

void DAGTypeLegalizer::ExpandIntRes_ADDSAT(SDNode *N, SDValue &Lo,
SDValue &Hi) {
SDValue Result = TLI.getExpandedSaturationAddition(N, DAG);
void DAGTypeLegalizer::ExpandIntRes_ADDSUBSAT(SDNode *N, SDValue &Lo,
SDValue &Hi) {
SDValue Result = TLI.getExpandedSaturationAdditionSubtraction(N, DAG);
SplitInteger(Result, Lo, Hi);
}

Expand Down
4 changes: 2 additions & 2 deletions llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h
Expand Up @@ -330,7 +330,7 @@ class LLVM_LIBRARY_VISIBILITY DAGTypeLegalizer {
SDValue PromoteIntRes_UNDEF(SDNode *N);
SDValue PromoteIntRes_VAARG(SDNode *N);
SDValue PromoteIntRes_XMULO(SDNode *N, unsigned ResNo);
SDValue PromoteIntRes_ADDSAT(SDNode *N);
SDValue PromoteIntRes_ADDSUBSAT(SDNode *N);

// Integer Operand Promotion.
bool PromoteIntegerOperand(SDNode *N, unsigned OpNo);
Expand Down Expand Up @@ -415,7 +415,7 @@ class LLVM_LIBRARY_VISIBILITY DAGTypeLegalizer {
void ExpandIntRes_SADDSUBO (SDNode *N, SDValue &Lo, SDValue &Hi);
void ExpandIntRes_UADDSUBO (SDNode *N, SDValue &Lo, SDValue &Hi);
void ExpandIntRes_XMULO (SDNode *N, SDValue &Lo, SDValue &Hi);
void ExpandIntRes_ADDSAT (SDNode *N, SDValue &Lo, SDValue &Hi);
void ExpandIntRes_ADDSUBSAT (SDNode *N, SDValue &Lo, SDValue &Hi);

void ExpandIntRes_ATOMIC_LOAD (SDNode *N, SDValue &Lo, SDValue &Hi);

Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp
Expand Up @@ -392,6 +392,8 @@ SDValue VectorLegalizer::LegalizeOp(SDValue Op) {
case ISD::FCANONICALIZE:
case ISD::SADDSAT:
case ISD::UADDSAT:
case ISD::SSUBSAT:
case ISD::USUBSAT:
Action = TLI.getOperationAction(Node->getOpcode(), Node->getValueType(0));
break;
case ISD::FP_ROUND_INREG:
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp
Expand Up @@ -124,6 +124,8 @@ void DAGTypeLegalizer::ScalarizeVectorResult(SDNode *N, unsigned ResNo) {

case ISD::SADDSAT:
case ISD::UADDSAT:
case ISD::SSUBSAT:
case ISD::USUBSAT:

case ISD::FPOW:
case ISD::FREM:
Expand Down Expand Up @@ -807,6 +809,8 @@ void DAGTypeLegalizer::SplitVectorResult(SDNode *N, unsigned ResNo) {
case ISD::UMAX:
case ISD::SADDSAT:
case ISD::UADDSAT:
case ISD::SSUBSAT:
case ISD::USUBSAT:
SplitVecRes_BinOp(N, Lo, Hi);
break;
case ISD::FMA:
Expand Down
12 changes: 12 additions & 0 deletions llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
Expand Up @@ -5783,6 +5783,18 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) {
setValue(&I, DAG.getNode(ISD::UADDSAT, sdl, Op1.getValueType(), Op1, Op2));
return nullptr;
}
case Intrinsic::ssub_sat: {
SDValue Op1 = getValue(I.getArgOperand(0));
SDValue Op2 = getValue(I.getArgOperand(1));
setValue(&I, DAG.getNode(ISD::SSUBSAT, sdl, Op1.getValueType(), Op1, Op2));
return nullptr;
}
case Intrinsic::usub_sat: {
SDValue Op1 = getValue(I.getArgOperand(0));
SDValue Op2 = getValue(I.getArgOperand(1));
setValue(&I, DAG.getNode(ISD::USUBSAT, sdl, Op1.getValueType(), Op1, Op2));
return nullptr;
}
case Intrinsic::stacksave: {
SDValue Op = getRoot();
Res = DAG.getNode(
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
Expand Up @@ -286,6 +286,8 @@ std::string SDNode::getOperationName(const SelectionDAG *G) const {

case ISD::SADDSAT: return "saddsat";
case ISD::UADDSAT: return "uaddsat";
case ISD::SSUBSAT: return "ssubsat";
case ISD::USUBSAT: return "usubsat";

// Conversion operators.
case ISD::SIGN_EXTEND: return "sign_extend";
Expand Down
52 changes: 36 additions & 16 deletions llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
Expand Up @@ -4983,11 +4983,27 @@ SDValue TargetLowering::lowerCmpEqZeroToCtlzSrl(SDValue Op,
return SDValue();
}

SDValue TargetLowering::getExpandedSaturationAddition(SDNode *Node,
SelectionDAG &DAG) const {
SDValue TargetLowering::getExpandedSaturationAdditionSubtraction(
SDNode *Node, SelectionDAG &DAG) const {
unsigned Opcode = Node->getOpcode();
assert((Opcode == ISD::SADDSAT || Opcode == ISD::UADDSAT) &&
"Expected method to receive SADDSAT or UADDSAT node.");
unsigned OverflowOp;
switch (Opcode) {
case ISD::SADDSAT:
OverflowOp = ISD::SADDO;
break;
case ISD::UADDSAT:
OverflowOp = ISD::UADDO;
break;
case ISD::SSUBSAT:
OverflowOp = ISD::SSUBO;
break;
case ISD::USUBSAT:
OverflowOp = ISD::USUBO;
break;
default:
llvm_unreachable("Expected method to receive signed or unsigned saturation "
"addition or subtraction node.");
}
assert(Node->getNumOperands() == 2 && "Expected node to have 2 operands.");

SDLoc dl(Node);
Expand All @@ -5002,31 +5018,35 @@ SDValue TargetLowering::getExpandedSaturationAddition(SDNode *Node,
assert(LHS.getValueType() == RHS.getValueType() &&
"Expected both operands to be the same type");

unsigned OverflowOp = Opcode == ISD::SADDSAT ? ISD::SADDO : ISD::UADDO;
unsigned BitWidth = LHS.getValueSizeInBits();
EVT ResultType = LHS.getValueType();
EVT BoolVT =
getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), ResultType);
SDValue Result =
DAG.getNode(OverflowOp, dl, DAG.getVTList(ResultType, BoolVT), LHS, RHS);
SDValue Sum = Result.getValue(0);
SDValue SumDiff = Result.getValue(0);
SDValue Overflow = Result.getValue(1);
SDValue Zero = DAG.getConstant(0, dl, ResultType);

if (Opcode == ISD::SADDSAT) {
// SatMax -> Overflow && Sum < 0
// SatMin -> Overflow && Sum > 0
if (Opcode == ISD::UADDSAT) {
// Just need to check overflow for SatMax.
APInt MaxVal = APInt::getMaxValue(BitWidth);
SDValue SatMax = DAG.getConstant(MaxVal, dl, ResultType);
return DAG.getSelect(dl, ResultType, Overflow, SatMax, SumDiff);
} else if (Opcode == ISD::USUBSAT) {
// Just need to check overflow for SatMin.
APInt MinVal = APInt::getMinValue(BitWidth);
SDValue SatMin = DAG.getConstant(MinVal, dl, ResultType);
return DAG.getSelect(dl, ResultType, Overflow, SatMin, SumDiff);
} else {
// SatMax -> Overflow && SumDiff < 0
// SatMin -> Overflow && SumDiff >= 0
APInt MinVal = APInt::getSignedMinValue(BitWidth);
APInt MaxVal = APInt::getSignedMaxValue(BitWidth);
SDValue SatMin = DAG.getConstant(MinVal, dl, ResultType);
SDValue SatMax = DAG.getConstant(MaxVal, dl, ResultType);
SDValue SumNeg = DAG.getSetCC(dl, BoolVT, Sum, Zero, ISD::SETLT);
SDValue SumNeg = DAG.getSetCC(dl, BoolVT, SumDiff, Zero, ISD::SETLT);
Result = DAG.getSelect(dl, ResultType, SumNeg, SatMax, SatMin);
return DAG.getSelect(dl, ResultType, Overflow, Result, Sum);
} else {
// Just need to check overflow for SatMax.
APInt MaxVal = APInt::getMaxValue(BitWidth);
SDValue SatMax = DAG.getConstant(MaxVal, dl, ResultType);
return DAG.getSelect(dl, ResultType, Overflow, SatMax, Sum);
return DAG.getSelect(dl, ResultType, Overflow, Result, SumDiff);
}
}
2 changes: 2 additions & 0 deletions llvm/lib/CodeGen/TargetLoweringBase.cpp
Expand Up @@ -612,6 +612,8 @@ void TargetLoweringBase::initActions() {
setOperationAction(ISD::ABS, VT, Expand);
setOperationAction(ISD::SADDSAT, VT, Expand);
setOperationAction(ISD::UADDSAT, VT, Expand);
setOperationAction(ISD::SSUBSAT, VT, Expand);
setOperationAction(ISD::USUBSAT, VT, Expand);

// Overflow operations default to expand
setOperationAction(ISD::SADDO, VT, Expand);
Expand Down
16 changes: 9 additions & 7 deletions llvm/lib/IR/Verifier.cpp
Expand Up @@ -4475,15 +4475,17 @@ void Verifier::visitIntrinsicCallSite(Intrinsic::ID ID, CallSite CS) {
break;
}
case Intrinsic::sadd_sat:
case Intrinsic::uadd_sat: {
case Intrinsic::uadd_sat:
case Intrinsic::ssub_sat:
case Intrinsic::usub_sat: {
Value *Op1 = CS.getArgOperand(0);
Value *Op2 = CS.getArgOperand(1);
Assert(
Op1->getType()->isIntOrIntVectorTy(),
"first operand of [us]add_sat must be an int type or vector of ints");
Assert(
Op2->getType()->isIntOrIntVectorTy(),
"second operand of [us]add_sat must be an int type or vector of ints");
Assert(Op1->getType()->isIntOrIntVectorTy(),
"first operand of [us][add|sub]_sat must be an int type or vector "
"of ints");
Assert(Op2->getType()->isIntOrIntVectorTy(),
"second operand of [us][add|sub]_sat must be an int type or vector "
"of ints");
break;
}
};
Expand Down

0 comments on commit 905abe5

Please sign in to comment.