1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 10:42:39 +01:00

[SelectionDAG] Expand UADDO/USUBO into ADD/SUBCARRY if legal for target

Additionally, implement handling of ADD/SUBCARRY on Hexagon, utilizing
the UADDO/USUBO expansion.

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

llvm-svn: 333751
This commit is contained in:
Krzysztof Parzyszek 2018-06-01 14:00:32 +00:00
parent 96090bce8b
commit 0a4ed009a4
9 changed files with 98 additions and 67 deletions

View File

@ -2283,8 +2283,11 @@ SDValue DAGCombiner::visitADDCARRY(SDNode *N) {
return DAG.getNode(ISD::ADDCARRY, DL, N->getVTList(), N1, N0, CarryIn);
// fold (addcarry x, y, false) -> (uaddo x, y)
if (isNullConstant(CarryIn))
return DAG.getNode(ISD::UADDO, DL, N->getVTList(), N0, N1);
if (isNullConstant(CarryIn)) {
if (!LegalOperations ||
TLI.isOperationLegalOrCustom(ISD::UADDO, N->getValueType(0)))
return DAG.getNode(ISD::UADDO, DL, N->getVTList(), N0, N1);
}
// fold (addcarry 0, 0, X) -> (and (ext/trunc X), 1) and no carry.
if (isNullConstant(N0) && isNullConstant(N1)) {
@ -2592,8 +2595,11 @@ SDValue DAGCombiner::visitSUBCARRY(SDNode *N) {
SDValue CarryIn = N->getOperand(2);
// fold (subcarry x, y, false) -> (usubo x, y)
if (isNullConstant(CarryIn))
return DAG.getNode(ISD::USUBO, SDLoc(N), N->getVTList(), N0, N1);
if (isNullConstant(CarryIn)) {
if (!LegalOperations ||
TLI.isOperationLegalOrCustom(ISD::USUBO, N->getValueType(0)))
return DAG.getNode(ISD::USUBO, SDLoc(N), N->getVTList(), N0, N1);
}
return SDValue();
}

View File

@ -3499,15 +3499,25 @@ bool SelectionDAGLegalize::ExpandNode(SDNode *Node) {
case ISD::USUBO: {
SDValue LHS = Node->getOperand(0);
SDValue RHS = Node->getOperand(1);
SDValue Sum = DAG.getNode(Node->getOpcode() == ISD::UADDO ?
ISD::ADD : ISD::SUB, dl, LHS.getValueType(),
LHS, RHS);
bool IsAdd = Node->getOpcode() == ISD::UADDO;
// If ADD/SUBCARRY is legal, use that instead.
unsigned OpcCarry = IsAdd ? ISD::ADDCARRY : ISD::SUBCARRY;
if (TLI.isOperationLegalOrCustom(OpcCarry, Node->getValueType(0))) {
SDValue CarryIn = DAG.getConstant(0, dl, Node->getValueType(1));
SDValue NodeCarry = DAG.getNode(OpcCarry, dl, Node->getVTList(),
{ LHS, RHS, CarryIn });
Results.push_back(SDValue(NodeCarry.getNode(), 0));
Results.push_back(SDValue(NodeCarry.getNode(), 1));
break;
}
SDValue Sum = DAG.getNode(IsAdd ? ISD::ADD : ISD::SUB, dl,
LHS.getValueType(), LHS, RHS);
Results.push_back(Sum);
EVT ResultType = Node->getValueType(1);
EVT SetCCType = getSetCCResultType(Node->getValueType(0));
ISD::CondCode CC
= Node->getOpcode() == ISD::UADDO ? ISD::SETULT : ISD::SETUGT;
ISD::CondCode CC = IsAdd ? ISD::SETULT : ISD::SETUGT;
SDValue SetCC = DAG.getSetCC(dl, SetCCType, Sum, LHS, CC);
Results.push_back(DAG.getBoolExtOrTrunc(SetCC, dl, ResultType, ResultType));

View File

@ -762,6 +762,15 @@ void HexagonDAGToDAGISel::SelectFrameIndex(SDNode *N) {
ReplaceNode(N, R);
}
void HexagonDAGToDAGISel::SelectAddSubCarry(SDNode *N) {
unsigned OpcCarry = N->getOpcode() == HexagonISD::ADDC ? Hexagon::A4_addp_c
: Hexagon::A4_subp_c;
SDNode *C = CurDAG->getMachineNode(OpcCarry, SDLoc(N), N->getVTList(),
{ N->getOperand(0), N->getOperand(1),
N->getOperand(2) });
ReplaceNode(N, C);
}
void HexagonDAGToDAGISel::SelectVAlign(SDNode *N) {
MVT ResTy = N->getValueType(0).getSimpleVT();
if (HST->isHVXVectorType(ResTy, true))
@ -875,6 +884,9 @@ void HexagonDAGToDAGISel::Select(SDNode *N) {
case ISD::STORE: return SelectStore(N);
case ISD::INTRINSIC_W_CHAIN: return SelectIntrinsicWChain(N);
case ISD::INTRINSIC_WO_CHAIN: return SelectIntrinsicWOChain(N);
case HexagonISD::ADDC:
case HexagonISD::SUBC: return SelectAddSubCarry(N);
case HexagonISD::VALIGN: return SelectVAlign(N);
case HexagonISD::VALIGNADDR: return SelectVAlignAddr(N);
case HexagonISD::TYPECAST: return SelectTypecast(N);

View File

@ -105,6 +105,7 @@ public:
void SelectV65Gather(SDNode *N);
void SelectV65GatherPred(SDNode *N);
void SelectHVXDualOutput(SDNode *N);
void SelectAddSubCarry(SDNode *N);
void SelectVAlign(SDNode *N);
void SelectVAlignAddr(SDNode *N);
void SelectTypecast(SDNode *N);

View File

@ -1327,13 +1327,18 @@ HexagonTargetLowering::HexagonTargetLowering(const TargetMachine &TM,
setMinimumJumpTableEntries(std::numeric_limits<int>::max());
setOperationAction(ISD::BR_JT, MVT::Other, Expand);
// Only add and sub that detect overflow are the saturating ones.
// Hexagon has A4_addp_c and A4_subp_c that take and generate a carry bit,
// but they only operate on i64.
for (MVT VT : MVT::integer_valuetypes()) {
setOperationAction(ISD::UADDO, VT, Expand);
setOperationAction(ISD::SADDO, VT, Expand);
setOperationAction(ISD::USUBO, VT, Expand);
setOperationAction(ISD::SSUBO, VT, Expand);
setOperationAction(ISD::UADDO, VT, Expand);
setOperationAction(ISD::USUBO, VT, Expand);
setOperationAction(ISD::SADDO, VT, Expand);
setOperationAction(ISD::SSUBO, VT, Expand);
setOperationAction(ISD::ADDCARRY, VT, Expand);
setOperationAction(ISD::SUBCARRY, VT, Expand);
}
setOperationAction(ISD::ADDCARRY, MVT::i64, Custom);
setOperationAction(ISD::SUBCARRY, MVT::i64, Custom);
setOperationAction(ISD::CTLZ, MVT::i8, Promote);
setOperationAction(ISD::CTLZ, MVT::i16, Promote);
@ -1681,6 +1686,8 @@ HexagonTargetLowering::HexagonTargetLowering(const TargetMachine &TM,
const char* HexagonTargetLowering::getTargetNodeName(unsigned Opcode) const {
switch ((HexagonISD::NodeType)Opcode) {
case HexagonISD::ADDC: return "HexagonISD::ADDC";
case HexagonISD::SUBC: return "HexagonISD::SUBC";
case HexagonISD::ALLOCA: return "HexagonISD::ALLOCA";
case HexagonISD::AT_GOT: return "HexagonISD::AT_GOT";
case HexagonISD::AT_PCREL: return "HexagonISD::AT_PCREL";
@ -2705,6 +2712,24 @@ HexagonTargetLowering::LowerUnalignedLoad(SDValue Op, SelectionDAG &DAG)
return M;
}
SDValue
HexagonTargetLowering::LowerAddSubCarry(SDValue Op, SelectionDAG &DAG) const {
const SDLoc &dl(Op);
unsigned Opc = Op.getOpcode();
SDValue X = Op.getOperand(0), Y = Op.getOperand(1), C = Op.getOperand(2);
if (Opc == ISD::ADDCARRY)
return DAG.getNode(HexagonISD::ADDC, dl, Op.getNode()->getVTList(),
{ X, Y, C });
EVT CarryTy = C.getValueType();
SDValue SubC = DAG.getNode(HexagonISD::SUBC, dl, Op.getNode()->getVTList(),
{ X, Y, DAG.getLogicalNOT(dl, C, CarryTy) });
SDValue Out[] = { SubC.getValue(0),
DAG.getLogicalNOT(dl, SubC.getValue(1), CarryTy) };
return DAG.getMergeValues(Out, dl);
}
SDValue
HexagonTargetLowering::LowerEH_RETURN(SDValue Op, SelectionDAG &DAG) const {
SDValue Chain = Op.getOperand(0);
@ -2763,6 +2788,8 @@ HexagonTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
case ISD::VECTOR_SHUFFLE: return LowerVECTOR_SHUFFLE(Op, DAG);
case ISD::BITCAST: return LowerBITCAST(Op, DAG);
case ISD::LOAD: return LowerUnalignedLoad(Op, DAG);
case ISD::ADDCARRY:
case ISD::SUBCARRY: return LowerAddSubCarry(Op, DAG);
case ISD::SRA:
case ISD::SHL:
case ISD::SRL: return LowerVECTOR_SHIFT(Op, DAG);

View File

@ -36,6 +36,8 @@ namespace HexagonISD {
CONST32 = OP_BEGIN,
CONST32_GP, // For marking data present in GP.
ADDC, // Add with carry: (X, Y, Cin) -> (X+Y, Cout).
SUBC, // Sub with carry: (X, Y, Cin) -> (X+~Y+Cin, Cout).
ALLOCA,
AT_GOT, // Index in GOT.
@ -162,6 +164,7 @@ namespace HexagonISD {
SDValue LowerSIGN_EXTEND(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerZERO_EXTEND(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerUnalignedLoad(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerAddSubCarry(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerINLINEASM(SDValue Op, SelectionDAG &DAG) const;

View File

@ -1,27 +0,0 @@
; RUN: llc -march=hexagon -hexagon-expand-condsets=0 < %s | FileCheck %s
; CHECK-DAG: r{{[0-9]+:[0-9]+}} = add(r{{[0-9]+:[0-9]+}},r{{[0-9]+:[0-9]+}})
; CHECK-DAG: r{{[0-9]+:[0-9]+}} = add(r{{[0-9]+:[0-9]+}},r{{[0-9]+:[0-9]+}})
; CHECK-DAG: p{{[0-9]+}} = cmp.gtu(r{{[0-9]+:[0-9]+}},r{{[0-9]+:[0-9]+}})
; CHECK-DAG: p{{[0-9]+}} = cmp.gtu(r{{[0-9]+:[0-9]+}},r{{[0-9]+:[0-9]+}})
; CHECK-DAG: r{{[0-9]+}} = mux(p{{[0-9]+}},r{{[0-9]+}},r{{[0-9]+}})
; CHECK-DAG: r{{[0-9]+}} = mux(p{{[0-9]+}},r{{[0-9]+}},r{{[0-9]+}})
define void @check_adde_addc(i64 %a0, i64 %a1, i64 %a2, i64 %a3, i64* %a4, i64* %a5) {
b6:
%v7 = zext i64 %a0 to i128
%v8 = zext i64 %a1 to i128
%v9 = shl i128 %v8, 64
%v10 = or i128 %v7, %v9
%v11 = zext i64 %a2 to i128
%v12 = zext i64 %a3 to i128
%v13 = shl i128 %v12, 64
%v14 = or i128 %v11, %v13
%v15 = add i128 %v10, %v14
%v16 = lshr i128 %v15, 64
%v17 = trunc i128 %v15 to i64
%v18 = trunc i128 %v16 to i64
store i64 %v17, i64* %a4
store i64 %v18, i64* %a5
ret void
}

View File

@ -0,0 +1,25 @@
; RUN: llc -march=hexagon < %s | FileCheck %s
@g = global i128 zeroinitializer, align 8
; CHECK-LABEL: addc:
; CHECK: p[[P0:[0-3]]] = and(p[[P1:[0-9]]],!p[[P1]])
; CHECK: add({{.*}},{{.*}},p[[P0]]):carry
; CHECK: add({{.*}},{{.*}},p[[P0]]):carry
define void @addc(i128 %a0, i128 %a1) #0 {
%v0 = add i128 %a0, %a1
store i128 %v0, i128* @g, align 8
ret void
}
; CHECK-LABEL: subc:
; CHECK: p[[P0:[0-3]]] = or(p[[P1:[0-9]]],!p[[P1]])
; CHECK: sub({{.*}},{{.*}},p[[P0]]):carry
; CHECK: sub({{.*}},{{.*}},p[[P0]]):carry
define void @subc(i128 %a0, i128 %a1) #0 {
%v0 = sub i128 %a0, %a1
store i128 %v0, i128* @g, align 8
ret void
}

View File

@ -1,26 +0,0 @@
; RUN: llc -march=hexagon -hexagon-expand-condsets=0 < %s | FileCheck %s
; CHECK-DAG: r{{[0-9]+:[0-9]+}} = sub(r{{[0-9]+:[0-9]+}},r{{[0-9]+:[0-9]+}})
; CHECK-DAG: r{{[0-9]+:[0-9]+}} = sub(r{{[0-9]+:[0-9]+}},r{{[0-9]+:[0-9]+}})
; CHECK-DAG: p{{[0-9]+}} = cmp.gtu(r{{[0-9]+:[0-9]+}},r{{[0-9]+:[0-9]+}})
; CHECK-DAG: r{{[0-9]+}} = mux(p{{[0-9]+}},r{{[0-9]+}},r{{[0-9]+}})
; CHECK-DAG: r{{[0-9]+}} = mux(p{{[0-9]+}},r{{[0-9]+}},r{{[0-9]+}})
define void @check_sube_subc(i64 %a0, i64 %a1, i64 %a2, i64 %a3, i64* %a4, i64* %a5) {
b6:
%v7 = zext i64 %a0 to i128
%v8 = zext i64 %a1 to i128
%v9 = shl i128 %v8, 64
%v10 = or i128 %v7, %v9
%v11 = zext i64 %a2 to i128
%v12 = zext i64 %a3 to i128
%v13 = shl i128 %v12, 64
%v14 = or i128 %v11, %v13
%v15 = sub i128 %v10, %v14
%v16 = lshr i128 %v15, 64
%v17 = trunc i128 %v15 to i64
%v18 = trunc i128 %v16 to i64
store i64 %v17, i64* %a4
store i64 %v18, i64* %a5
ret void
}