diff options
-rw-r--r-- | llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 14 | ||||
-rw-r--r-- | llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp | 20 | ||||
-rw-r--r-- | llvm/lib/Target/Hexagon/HexagonISelDAGToDAG.cpp | 12 | ||||
-rw-r--r-- | llvm/lib/Target/Hexagon/HexagonISelDAGToDAG.h | 1 | ||||
-rw-r--r-- | llvm/lib/Target/Hexagon/HexagonISelLowering.cpp | 37 | ||||
-rw-r--r-- | llvm/lib/Target/Hexagon/HexagonISelLowering.h | 3 | ||||
-rw-r--r-- | llvm/test/CodeGen/Hexagon/adde.ll | 27 | ||||
-rw-r--r-- | llvm/test/CodeGen/Hexagon/addsubcarry.ll | 25 | ||||
-rw-r--r-- | llvm/test/CodeGen/Hexagon/sube.ll | 26 |
9 files changed, 98 insertions, 67 deletions
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp index 93d9cfd73bd..3db05a56c5b 100644 --- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -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(); } diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp index 7c9c06b6250..feb67819201 100644 --- a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp @@ -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)); diff --git a/llvm/lib/Target/Hexagon/HexagonISelDAGToDAG.cpp b/llvm/lib/Target/Hexagon/HexagonISelDAGToDAG.cpp index 0d0b35118c1..efb4c2eb0fc 100644 --- a/llvm/lib/Target/Hexagon/HexagonISelDAGToDAG.cpp +++ b/llvm/lib/Target/Hexagon/HexagonISelDAGToDAG.cpp @@ -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); diff --git a/llvm/lib/Target/Hexagon/HexagonISelDAGToDAG.h b/llvm/lib/Target/Hexagon/HexagonISelDAGToDAG.h index 1c3379bf015..f4f09dd4e75 100644 --- a/llvm/lib/Target/Hexagon/HexagonISelDAGToDAG.h +++ b/llvm/lib/Target/Hexagon/HexagonISelDAGToDAG.h @@ -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); diff --git a/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp b/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp index 4a85427032c..a63af51bf86 100644 --- a/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp +++ b/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp @@ -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"; @@ -2706,6 +2713,24 @@ HexagonTargetLowering::LowerUnalignedLoad(SDValue Op, SelectionDAG &DAG) } 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); SDValue Offset = Op.getOperand(1); @@ -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); diff --git a/llvm/lib/Target/Hexagon/HexagonISelLowering.h b/llvm/lib/Target/Hexagon/HexagonISelLowering.h index 5ed26101d58..cb570b4dc7f 100644 --- a/llvm/lib/Target/Hexagon/HexagonISelLowering.h +++ b/llvm/lib/Target/Hexagon/HexagonISelLowering.h @@ -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; diff --git a/llvm/test/CodeGen/Hexagon/adde.ll b/llvm/test/CodeGen/Hexagon/adde.ll deleted file mode 100644 index 12913eea7e8..00000000000 --- a/llvm/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 -} diff --git a/llvm/test/CodeGen/Hexagon/addsubcarry.ll b/llvm/test/CodeGen/Hexagon/addsubcarry.ll new file mode 100644 index 00000000000..b5e981c52f5 --- /dev/null +++ b/llvm/test/CodeGen/Hexagon/addsubcarry.ll @@ -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 +} + + diff --git a/llvm/test/CodeGen/Hexagon/sube.ll b/llvm/test/CodeGen/Hexagon/sube.ll deleted file mode 100644 index 2b09a998eff..00000000000 --- a/llvm/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 -} |