+ return SDValue();
+}
+
+static SDValue LowerI64Math(SDValue Op, SelectionDAG &DAG, unsigned Opc)
+{
+ MVT VT = Op.getValueType();
+ MVT VecVT = MVT::getVectorVT(VT, (128 / VT.getSizeInBits()));
+
+ SDValue Op0 = Op.getOperand(0);
+
+ switch (Opc) {
+ case ISD::ZERO_EXTEND:
+ case ISD::SIGN_EXTEND:
+ case ISD::ANY_EXTEND: {
+ MVT Op0VT = Op0.getValueType();
+ MVT Op0VecVT = MVT::getVectorVT(Op0VT, (128 / Op0VT.getSizeInBits()));
+
+ assert(Op0VT == MVT::i32
+ && "CellSPU: Zero/sign extending something other than i32");
+ DEBUG(cerr << "CellSPU: LowerI64Math custom lowering zero/sign/any extend\n");
+
+ unsigned NewOpc = (Opc == ISD::SIGN_EXTEND
+ ? SPUISD::ROTBYTES_RIGHT_S
+ : SPUISD::ROTQUAD_RZ_BYTES);
+ SDValue PromoteScalar =
+ DAG.getNode(SPUISD::PROMOTE_SCALAR, Op0VecVT, Op0);
+
+ return DAG.getNode(SPUISD::EXTRACT_ELT0, VT,
+ DAG.getNode(ISD::BIT_CONVERT, VecVT,
+ DAG.getNode(NewOpc, Op0VecVT,
+ PromoteScalar,
+ DAG.getConstant(4, MVT::i32))));
+ }
+
+ case ISD::ADD: {
+ // Turn operands into vectors to satisfy type checking (shufb works on
+ // vectors)
+ SDValue Op0 =
+ DAG.getNode(SPUISD::PROMOTE_SCALAR, MVT::v2i64, Op.getOperand(0));
+ SDValue Op1 =
+ DAG.getNode(SPUISD::PROMOTE_SCALAR, MVT::v2i64, Op.getOperand(1));
+ SmallVector<SDValue, 16> ShufBytes;
+
+ // Create the shuffle mask for "rotating" the borrow up one register slot
+ // once the borrow is generated.
+ ShufBytes.push_back(DAG.getConstant(0x04050607, MVT::i32));
+ ShufBytes.push_back(DAG.getConstant(0x80808080, MVT::i32));
+ ShufBytes.push_back(DAG.getConstant(0x0c0d0e0f, MVT::i32));
+ ShufBytes.push_back(DAG.getConstant(0x80808080, MVT::i32));
+
+ SDValue CarryGen =
+ DAG.getNode(SPUISD::CARRY_GENERATE, MVT::v2i64, Op0, Op1);
+ SDValue ShiftedCarry =
+ DAG.getNode(SPUISD::SHUFB, MVT::v2i64,
+ CarryGen, CarryGen,
+ DAG.getNode(ISD::BUILD_VECTOR, MVT::v4i32,
+ &ShufBytes[0], ShufBytes.size()));
+
+ return DAG.getNode(SPUISD::EXTRACT_ELT0, MVT::i64,
+ DAG.getNode(SPUISD::ADD_EXTENDED, MVT::v2i64,
+ Op0, Op1, ShiftedCarry));
+ }
+
+ case ISD::SUB: {
+ // Turn operands into vectors to satisfy type checking (shufb works on
+ // vectors)
+ SDValue Op0 =
+ DAG.getNode(SPUISD::PROMOTE_SCALAR, MVT::v2i64, Op.getOperand(0));
+ SDValue Op1 =
+ DAG.getNode(SPUISD::PROMOTE_SCALAR, MVT::v2i64, Op.getOperand(1));
+ SmallVector<SDValue, 16> ShufBytes;
+
+ // Create the shuffle mask for "rotating" the borrow up one register slot
+ // once the borrow is generated.
+ ShufBytes.push_back(DAG.getConstant(0x04050607, MVT::i32));
+ ShufBytes.push_back(DAG.getConstant(0xc0c0c0c0, MVT::i32));
+ ShufBytes.push_back(DAG.getConstant(0x0c0d0e0f, MVT::i32));
+ ShufBytes.push_back(DAG.getConstant(0xc0c0c0c0, MVT::i32));
+
+ SDValue BorrowGen =
+ DAG.getNode(SPUISD::BORROW_GENERATE, MVT::v2i64, Op0, Op1);
+ SDValue ShiftedBorrow =
+ DAG.getNode(SPUISD::SHUFB, MVT::v2i64,
+ BorrowGen, BorrowGen,
+ DAG.getNode(ISD::BUILD_VECTOR, MVT::v4i32,
+ &ShufBytes[0], ShufBytes.size()));
+
+ return DAG.getNode(SPUISD::EXTRACT_ELT0, MVT::i64,
+ DAG.getNode(SPUISD::SUB_EXTENDED, MVT::v2i64,
+ Op0, Op1, ShiftedBorrow));
+ }
+
+ case ISD::SHL: {
+ SDValue ShiftAmt = Op.getOperand(1);
+ MVT ShiftAmtVT = ShiftAmt.getValueType();
+ SDValue Op0Vec = DAG.getNode(SPUISD::PROMOTE_SCALAR, VecVT, Op0);
+ SDValue MaskLower =
+ DAG.getNode(SPUISD::SELB, VecVT,
+ Op0Vec,
+ DAG.getConstant(0, VecVT),
+ DAG.getNode(SPUISD::SELECT_MASK, VecVT,
+ DAG.getConstant(0xff00ULL, MVT::i16)));
+ SDValue ShiftAmtBytes =
+ DAG.getNode(ISD::SRL, ShiftAmtVT,
+ ShiftAmt,
+ DAG.getConstant(3, ShiftAmtVT));
+ SDValue ShiftAmtBits =
+ DAG.getNode(ISD::AND, ShiftAmtVT,
+ ShiftAmt,
+ DAG.getConstant(7, ShiftAmtVT));
+
+ return DAG.getNode(SPUISD::EXTRACT_ELT0, VT,
+ DAG.getNode(SPUISD::SHLQUAD_L_BITS, VecVT,
+ DAG.getNode(SPUISD::SHLQUAD_L_BYTES, VecVT,
+ MaskLower, ShiftAmtBytes),
+ ShiftAmtBits));
+ }
+
+ case ISD::SRL: {
+ MVT VT = Op.getValueType();
+ SDValue ShiftAmt = Op.getOperand(1);
+ MVT ShiftAmtVT = ShiftAmt.getValueType();
+ SDValue ShiftAmtBytes =
+ DAG.getNode(ISD::SRL, ShiftAmtVT,
+ ShiftAmt,
+ DAG.getConstant(3, ShiftAmtVT));
+ SDValue ShiftAmtBits =
+ DAG.getNode(ISD::AND, ShiftAmtVT,
+ ShiftAmt,
+ DAG.getConstant(7, ShiftAmtVT));
+
+ return DAG.getNode(SPUISD::ROTQUAD_RZ_BITS, VT,
+ DAG.getNode(SPUISD::ROTQUAD_RZ_BYTES, VT,
+ Op0, ShiftAmtBytes),
+ ShiftAmtBits);
+ }
+
+ case ISD::SRA: {
+ // Promote Op0 to vector
+ SDValue Op0 =
+ DAG.getNode(SPUISD::PROMOTE_SCALAR, MVT::v2i64, Op.getOperand(0));
+ SDValue ShiftAmt = Op.getOperand(1);
+ MVT ShiftVT = ShiftAmt.getValueType();
+
+ // Negate variable shift amounts
+ if (!isa<ConstantSDNode>(ShiftAmt)) {
+ ShiftAmt = DAG.getNode(ISD::SUB, ShiftVT,
+ DAG.getConstant(0, ShiftVT), ShiftAmt);
+ }
+
+ SDValue UpperHalfSign =
+ DAG.getNode(SPUISD::EXTRACT_ELT0, MVT::i32,
+ DAG.getNode(ISD::BIT_CONVERT, MVT::v4i32,
+ DAG.getNode(SPUISD::VEC_SRA, MVT::v2i64,
+ Op0, DAG.getConstant(31, MVT::i32))));
+ SDValue UpperHalfSignMask =
+ DAG.getNode(SPUISD::SELECT_MASK, MVT::v2i64, UpperHalfSign);
+ SDValue UpperLowerMask =
+ DAG.getNode(SPUISD::SELECT_MASK, MVT::v2i64,
+ DAG.getConstant(0xff00, MVT::i16));
+ SDValue UpperLowerSelect =
+ DAG.getNode(SPUISD::SELB, MVT::v2i64,
+ UpperHalfSignMask, Op0, UpperLowerMask);
+ SDValue RotateLeftBytes =
+ DAG.getNode(SPUISD::ROTBYTES_LEFT_BITS, MVT::v2i64,
+ UpperLowerSelect, ShiftAmt);
+ SDValue RotateLeftBits =
+ DAG.getNode(SPUISD::ROTBYTES_LEFT, MVT::v2i64,
+ RotateLeftBytes, ShiftAmt);
+
+ return DAG.getNode(SPUISD::EXTRACT_ELT0, MVT::i64,
+ RotateLeftBits);
+ }
+ }
+
+ return SDValue();