Index: lib/CodeGen/SelectionDAG/DAGCombiner.cpp =================================================================== --- lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -2283,8 +2283,11 @@ 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)) { Index: lib/CodeGen/SelectionDAG/LegalizeDAG.cpp =================================================================== --- lib/CodeGen/SelectionDAG/LegalizeDAG.cpp +++ lib/CodeGen/SelectionDAG/LegalizeDAG.cpp @@ -3499,15 +3499,25 @@ 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(!IsAdd, 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)); Index: lib/Target/Hexagon/HexagonISelDAGToDAG.h =================================================================== --- lib/Target/Hexagon/HexagonISelDAGToDAG.h +++ lib/Target/Hexagon/HexagonISelDAGToDAG.h @@ -105,6 +105,7 @@ 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); Index: lib/Target/Hexagon/HexagonISelDAGToDAG.cpp =================================================================== --- lib/Target/Hexagon/HexagonISelDAGToDAG.cpp +++ lib/Target/Hexagon/HexagonISelDAGToDAG.cpp @@ -762,6 +762,15 @@ ReplaceNode(N, R); } +void HexagonDAGToDAGISel::SelectAddSubCarry(SDNode *N) { + unsigned OpcCarry = N->getOpcode() == ISD::ADDCARRY ? 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 @@ case ISD::STORE: return SelectStore(N); case ISD::INTRINSIC_W_CHAIN: return SelectIntrinsicWChain(N); case ISD::INTRINSIC_WO_CHAIN: return SelectIntrinsicWOChain(N); + case ISD::ADDCARRY: + case ISD::SUBCARRY: return SelectAddSubCarry(N); + case HexagonISD::VALIGN: return SelectVAlign(N); case HexagonISD::VALIGNADDR: return SelectVAlignAddr(N); case HexagonISD::TYPECAST: return SelectTypecast(N); Index: lib/Target/Hexagon/HexagonISelLowering.cpp =================================================================== --- lib/Target/Hexagon/HexagonISelLowering.cpp +++ lib/Target/Hexagon/HexagonISelLowering.cpp @@ -1327,35 +1327,20 @@ setMinimumJumpTableEntries(std::numeric_limits::max()); setOperationAction(ISD::BR_JT, MVT::Other, Expand); - // Hexagon has instructions for add/sub with carry. The problem with - // modeling these instructions is that they produce 2 results: Rdd and Px. - // To model the update of Px, we will have to use Defs[p0..p3] which will - // cause any predicate live range to spill. So, we pretend we dont't have - // these instructions. - setOperationAction(ISD::ADDE, MVT::i8, Expand); - setOperationAction(ISD::ADDE, MVT::i16, Expand); - setOperationAction(ISD::ADDE, MVT::i32, Expand); - setOperationAction(ISD::ADDE, MVT::i64, Expand); - setOperationAction(ISD::SUBE, MVT::i8, Expand); - setOperationAction(ISD::SUBE, MVT::i16, Expand); - setOperationAction(ISD::SUBE, MVT::i32, Expand); - setOperationAction(ISD::SUBE, MVT::i64, Expand); - setOperationAction(ISD::ADDC, MVT::i8, Expand); - setOperationAction(ISD::ADDC, MVT::i16, Expand); - setOperationAction(ISD::ADDC, MVT::i32, Expand); - setOperationAction(ISD::ADDC, MVT::i64, Expand); - setOperationAction(ISD::SUBC, MVT::i8, Expand); - setOperationAction(ISD::SUBC, MVT::i16, Expand); - setOperationAction(ISD::SUBC, MVT::i32, Expand); - setOperationAction(ISD::SUBC, MVT::i64, 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::ADDE, VT, Expand); + setOperationAction(ISD::SUBE, 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, Legal); + setOperationAction(ISD::SUBCARRY, MVT::i64, Legal); setOperationAction(ISD::CTLZ, MVT::i8, Promote); setOperationAction(ISD::CTLZ, MVT::i16, Promote); Index: test/CodeGen/Hexagon/adde.ll =================================================================== --- test/CodeGen/Hexagon/adde.ll +++ /dev/null @@ -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 -} Index: test/CodeGen/Hexagon/sube.ll =================================================================== --- test/CodeGen/Hexagon/sube.ll +++ /dev/null @@ -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 -}