addRegisterClass(MVT::v4i1, &Hexagon::PredRegsRegClass); // ddccbbaa
addRegisterClass(MVT::v8i1, &Hexagon::PredRegsRegClass); // hgfedcba
addRegisterClass(MVT::i32, &Hexagon::IntRegsRegClass);
- addRegisterClass(MVT::v4i8, &Hexagon::IntRegsRegClass);
addRegisterClass(MVT::v2i16, &Hexagon::IntRegsRegClass);
+ addRegisterClass(MVT::v4i8, &Hexagon::IntRegsRegClass);
addRegisterClass(MVT::i64, &Hexagon::DoubleRegsRegClass);
addRegisterClass(MVT::v8i8, &Hexagon::DoubleRegsRegClass);
addRegisterClass(MVT::v4i16, &Hexagon::DoubleRegsRegClass);
addRegisterClass(MVT::v128i8, &Hexagon::HvxWRRegClass);
addRegisterClass(MVT::v64i16, &Hexagon::HvxWRRegClass);
addRegisterClass(MVT::v32i32, &Hexagon::HvxWRRegClass);
+ // These "short" boolean vector types should be legal because
+ // they will appear as results of vector compares. If they were
+ // not legal, type legalization would try to make them legal
+ // and that would require using operations that do not use or
+ // produce such types. That, in turn, would imply using custom
+ // nodes, which would be unoptimizable by the DAG combiner.
+ // The idea is to rely on target-independent operations as much
+ // as possible.
addRegisterClass(MVT::v16i1, &Hexagon::HvxQRRegClass);
addRegisterClass(MVT::v32i1, &Hexagon::HvxQRRegClass);
addRegisterClass(MVT::v64i1, &Hexagon::HvxQRRegClass);
setLoadExtAction(ISD::SEXTLOAD, MVT::v4i16, MVT::v4i8, Legal);
// Types natively supported:
- for (MVT NativeVT : {MVT::v2i1, MVT::v4i1, MVT::v8i1, MVT::v32i1, MVT::v64i1,
- MVT::v4i8, MVT::v8i8, MVT::v2i16, MVT::v4i16, MVT::v1i32,
- MVT::v2i32, MVT::v1i64}) {
+ for (MVT NativeVT : {MVT::v32i1, MVT::v64i1, MVT::v4i8, MVT::v8i8, MVT::v2i16,
+ MVT::v4i16, MVT::v1i32, MVT::v2i32, MVT::v1i64}) {
setOperationAction(ISD::BUILD_VECTOR, NativeVT, Custom);
setOperationAction(ISD::EXTRACT_VECTOR_ELT, NativeVT, Custom);
setOperationAction(ISD::INSERT_VECTOR_ELT, NativeVT, Custom);
AddPromotedToType(Opc, FromTy, ToTy);
};
- if (Subtarget.useHVXOps()) {
- bool Use64b = Subtarget.useHVX64BOps();
- ArrayRef<MVT> LegalV = Use64b ? LegalV64 : LegalV128;
- ArrayRef<MVT> LegalW = Use64b ? LegalW64 : LegalW128;
- MVT ByteV = Use64b ? MVT::v64i8 : MVT::v128i8;
- MVT ByteW = Use64b ? MVT::v128i8 : MVT::v256i8;
-
- setOperationAction(ISD::VECTOR_SHUFFLE, ByteV, Legal);
- setOperationAction(ISD::VECTOR_SHUFFLE, ByteW, Legal);
- setOperationAction(ISD::CONCAT_VECTORS, ByteW, Legal);
- setOperationAction(ISD::AND, ByteV, Legal);
- setOperationAction(ISD::OR, ByteV, Legal);
- setOperationAction(ISD::XOR, ByteV, Legal);
-
- for (MVT T : LegalV) {
- setIndexedLoadAction(ISD::POST_INC, T, Legal);
- setIndexedStoreAction(ISD::POST_INC, T, Legal);
-
- setOperationAction(ISD::ADD, T, Legal);
- setOperationAction(ISD::SUB, T, Legal);
- setOperationAction(ISD::VSELECT, T, Legal);
- if (T != ByteV) {
- setOperationAction(ISD::SIGN_EXTEND_VECTOR_INREG, T, Legal);
- setOperationAction(ISD::ZERO_EXTEND_VECTOR_INREG, T, Legal);
- }
-
- setOperationAction(ISD::MUL, T, Custom);
- setOperationAction(ISD::SETCC, T, Custom);
- setOperationAction(ISD::BUILD_VECTOR, T, Custom);
- setOperationAction(ISD::INSERT_SUBVECTOR, T, Custom);
- setOperationAction(ISD::INSERT_VECTOR_ELT, T, Custom);
- setOperationAction(ISD::EXTRACT_SUBVECTOR, T, Custom);
- setOperationAction(ISD::EXTRACT_VECTOR_ELT, T, Custom);
- if (T != ByteV)
- setOperationAction(ISD::ANY_EXTEND_VECTOR_INREG, T, Custom);
- }
-
- for (MVT T : LegalV) {
- if (T == ByteV)
- continue;
- // Promote all shuffles and concats to operate on vectors of bytes.
- setPromoteTo(ISD::VECTOR_SHUFFLE, T, ByteV);
- setPromoteTo(ISD::CONCAT_VECTORS, T, ByteV);
- setPromoteTo(ISD::AND, T, ByteV);
- setPromoteTo(ISD::OR, T, ByteV);
- setPromoteTo(ISD::XOR, T, ByteV);
- }
-
- for (MVT T : LegalW) {
- if (T == ByteW)
- continue;
- // Promote all shuffles and concats to operate on vectors of bytes.
- setPromoteTo(ISD::VECTOR_SHUFFLE, T, ByteW);
- setPromoteTo(ISD::CONCAT_VECTORS, T, ByteW);
- }
- }
-
// Subtarget-specific operation actions.
//
if (Subtarget.hasV5TOps()) {
setIndexedStoreAction(ISD::POST_INC, VT, Legal);
}
+ if (Subtarget.useHVXOps()) {
+ bool Use64b = Subtarget.useHVX64BOps();
+ ArrayRef<MVT> LegalV = Use64b ? LegalV64 : LegalV128;
+ ArrayRef<MVT> LegalW = Use64b ? LegalW64 : LegalW128;
+ MVT ByteV = Use64b ? MVT::v64i8 : MVT::v128i8;
+ MVT ByteW = Use64b ? MVT::v128i8 : MVT::v256i8;
+
+ setOperationAction(ISD::VECTOR_SHUFFLE, ByteV, Legal);
+ setOperationAction(ISD::VECTOR_SHUFFLE, ByteW, Legal);
+ setOperationAction(ISD::CONCAT_VECTORS, ByteW, Legal);
+ setOperationAction(ISD::AND, ByteV, Legal);
+ setOperationAction(ISD::OR, ByteV, Legal);
+ setOperationAction(ISD::XOR, ByteV, Legal);
+
+ for (MVT T : LegalV) {
+ setIndexedLoadAction(ISD::POST_INC, T, Legal);
+ setIndexedStoreAction(ISD::POST_INC, T, Legal);
+
+ setOperationAction(ISD::ADD, T, Legal);
+ setOperationAction(ISD::SUB, T, Legal);
+ if (T != ByteV) {
+ setOperationAction(ISD::SIGN_EXTEND_VECTOR_INREG, T, Legal);
+ setOperationAction(ISD::ZERO_EXTEND_VECTOR_INREG, T, Legal);
+ }
+
+ setOperationAction(ISD::MUL, T, Custom);
+ setOperationAction(ISD::SETCC, T, Custom);
+ setOperationAction(ISD::BUILD_VECTOR, T, Custom);
+ setOperationAction(ISD::INSERT_SUBVECTOR, T, Custom);
+ setOperationAction(ISD::INSERT_VECTOR_ELT, T, Custom);
+ setOperationAction(ISD::EXTRACT_SUBVECTOR, T, Custom);
+ setOperationAction(ISD::EXTRACT_VECTOR_ELT, T, Custom);
+ if (T != ByteV)
+ setOperationAction(ISD::ANY_EXTEND_VECTOR_INREG, T, Custom);
+ }
+
+ for (MVT T : LegalV) {
+ if (T == ByteV)
+ continue;
+ // Promote all shuffles and concats to operate on vectors of bytes.
+ setPromoteTo(ISD::VECTOR_SHUFFLE, T, ByteV);
+ setPromoteTo(ISD::CONCAT_VECTORS, T, ByteV);
+ setPromoteTo(ISD::AND, T, ByteV);
+ setPromoteTo(ISD::OR, T, ByteV);
+ setPromoteTo(ISD::XOR, T, ByteV);
+ }
+
+ for (MVT T : LegalW) {
+ // Custom-lower BUILD_VECTOR for vector pairs. The standard (target-
+ // independent) handling of it would convert it to a load, which is
+ // not always the optimal choice.
+ setOperationAction(ISD::BUILD_VECTOR, T, Custom);
+
+ if (T == ByteW)
+ continue;
+ // Promote all shuffles and concats to operate on vectors of bytes.
+ setPromoteTo(ISD::VECTOR_SHUFFLE, T, ByteW);
+ setPromoteTo(ISD::CONCAT_VECTORS, T, ByteW);
+ }
+ }
+
computeRegisterProperties(&HRI);
//
case HexagonISD::VINSERTW0: return "HexagonISD::VINSERTW0";
case HexagonISD::VROR: return "HexagonISD::VROR";
case HexagonISD::READCYCLE: return "HexagonISD::READCYCLE";
+ case HexagonISD::VZERO: return "HexagonISD::VZERO";
case HexagonISD::OP_END: break;
}
return nullptr;
TargetLoweringBase::LegalizeTypeAction
HexagonTargetLowering::getPreferredVectorAction(EVT VT) const {
+ if (VT.getVectorNumElements() == 1)
+ return TargetLoweringBase::TypeScalarizeVector;
+
+ // Always widen vectors of i1.
+ MVT ElemTy = VT.getSimpleVT().getVectorElementType();
+ if (ElemTy == MVT::i1)
+ return TargetLoweringBase::TypeWidenVector;
+
if (Subtarget.useHVXOps()) {
// If the size of VT is at least half of the vector length,
// widen the vector. Note: the threshold was not selected in
// any scientific way.
- if (VT.getSizeInBits() >= Subtarget.getVectorLength()*8/2)
- return TargetLoweringBase::TypeWidenVector;
+ ArrayRef<MVT> Tys = Subtarget.getHVXElementTypes();
+ if (llvm::find(Tys, ElemTy) != Tys.end()) {
+ unsigned HwWidth = 8*Subtarget.getVectorLength();
+ unsigned VecWidth = VT.getSizeInBits();
+ if (VecWidth >= HwWidth/2 && VecWidth < HwWidth)
+ return TargetLoweringBase::TypeWidenVector;
+ }
}
- return TargetLowering::getPreferredVectorAction(VT);
+ return TargetLoweringBase::TypeSplitVector;
}
// Lower a vector shuffle (V1, V2, V3). V1 and V2 are the two vectors
return DAG.getNode(ISD::BITCAST, dl, VT, Result);
}
+bool
+HexagonTargetLowering::getBuildVectorConstInts(ArrayRef<SDValue> Values,
+ MVT VecTy, SelectionDAG &DAG,
+ MutableArrayRef<ConstantInt*> Consts) const {
+ MVT ElemTy = VecTy.getVectorElementType();
+ unsigned ElemWidth = ElemTy.getSizeInBits();
+ IntegerType *IntTy = IntegerType::get(*DAG.getContext(), ElemWidth);
+ bool AllConst = true;
+
+ for (unsigned i = 0, e = Values.size(); i != e; ++i) {
+ SDValue V = Values[i];
+ if (V.isUndef()) {
+ Consts[i] = ConstantInt::get(IntTy, 0);
+ continue;
+ }
+ if (auto *CN = dyn_cast<ConstantSDNode>(V.getNode())) {
+ const ConstantInt *CI = CN->getConstantIntValue();
+ Consts[i] = const_cast<ConstantInt*>(CI);
+ } else if (auto *CN = dyn_cast<ConstantFPSDNode>(V.getNode())) {
+ const ConstantFP *CF = CN->getConstantFPValue();
+ APInt A = CF->getValueAPF().bitcastToAPInt();
+ Consts[i] = ConstantInt::get(IntTy, A.getZExtValue());
+ } else {
+ AllConst = false;
+ }
+ }
+ return AllConst;
+}
+
SDValue
HexagonTargetLowering::buildVector32(ArrayRef<SDValue> Elem, const SDLoc &dl,
MVT VecTy, SelectionDAG &DAG) const {
MVT ElemTy = VecTy.getVectorElementType();
assert(VecTy.getVectorNumElements() == Elem.size());
- SmallVector<ConstantSDNode*,4> Consts;
- bool AllConst = true;
- for (SDValue V : Elem) {
- if (isUndef(V))
- V = DAG.getConstant(0, dl, ElemTy);
- auto *C = dyn_cast<ConstantSDNode>(V.getNode());
- Consts.push_back(C);
- AllConst = AllConst && C != nullptr;
- }
+ SmallVector<ConstantInt*,4> Consts(Elem.size());
+ bool AllConst = getBuildVectorConstInts(Elem, VecTy, DAG, Consts);
unsigned First, Num = Elem.size();
for (First = 0; First != Num; ++First)
if (First == Num)
return DAG.getUNDEF(VecTy);
+ if (AllConst &&
+ llvm::all_of(Consts, [](ConstantInt *CI) { return CI->isZero(); }))
+ return getZero(dl, VecTy, DAG);
+
if (ElemTy == MVT::i16) {
assert(Elem.size() == 2);
if (AllConst) {
return DAG.getBitcast(MVT::v2i16, N);
}
- // First try generating a constant.
- assert(ElemTy == MVT::i8 && Num == 4);
- if (AllConst) {
- int32_t V = (Consts[0]->getZExtValue() & 0xFF) |
- (Consts[1]->getZExtValue() & 0xFF) << 8 |
- (Consts[1]->getZExtValue() & 0xFF) << 16 |
- Consts[2]->getZExtValue() << 24;
- return DAG.getBitcast(MVT::v4i8, DAG.getConstant(V, dl, MVT::i32));
- }
+ if (ElemTy == MVT::i8) {
+ // First try generating a constant.
+ if (AllConst) {
+ int32_t V = (Consts[0]->getZExtValue() & 0xFF) |
+ (Consts[1]->getZExtValue() & 0xFF) << 8 |
+ (Consts[1]->getZExtValue() & 0xFF) << 16 |
+ Consts[2]->getZExtValue() << 24;
+ return DAG.getBitcast(MVT::v4i8, DAG.getConstant(V, dl, MVT::i32));
+ }
- // Then try splat.
- bool IsSplat = true;
- for (unsigned i = 0; i != Num; ++i) {
- if (i == First)
- continue;
- if (Elem[i] == Elem[First] || isUndef(Elem[i]))
- continue;
- IsSplat = false;
- break;
- }
- if (IsSplat) {
- // Legalize the operand to VSPLAT.
- SDValue Ext = DAG.getZExtOrTrunc(Elem[First], dl, MVT::i32);
- return DAG.getNode(HexagonISD::VSPLAT, dl, VecTy, Ext);
- }
+ // Then try splat.
+ bool IsSplat = true;
+ for (unsigned i = 0; i != Num; ++i) {
+ if (i == First)
+ continue;
+ if (Elem[i] == Elem[First] || isUndef(Elem[i]))
+ continue;
+ IsSplat = false;
+ break;
+ }
+ if (IsSplat) {
+ // Legalize the operand to VSPLAT.
+ SDValue Ext = DAG.getZExtOrTrunc(Elem[First], dl, MVT::i32);
+ return DAG.getNode(HexagonISD::VSPLAT, dl, VecTy, Ext);
+ }
+
+ // Generate
+ // (zxtb(Elem[0]) | (zxtb(Elem[1]) << 8)) |
+ // (zxtb(Elem[2]) | (zxtb(Elem[3]) << 8)) << 16
+ assert(Elem.size() == 4);
+ SDValue Vs[4];
+ for (unsigned i = 0; i != 4; ++i) {
+ Vs[i] = DAG.getZExtOrTrunc(Elem[i], dl, MVT::i32);
+ Vs[i] = DAG.getZeroExtendInReg(Vs[i], dl, MVT::i8);
+ }
+ SDValue S8 = DAG.getConstant(8, dl, MVT::i32);
+ SDValue T0 = DAG.getNode(ISD::SHL, dl, MVT::i32, {Vs[1], S8});
+ SDValue T1 = DAG.getNode(ISD::SHL, dl, MVT::i32, {Vs[3], S8});
+ SDValue B0 = DAG.getNode(ISD::OR, dl, MVT::i32, {Vs[0], T0});
+ SDValue B1 = DAG.getNode(ISD::OR, dl, MVT::i32, {Vs[2], T1});
- // Generate
- // (zxtb(Elem[0]) | (zxtb(Elem[1]) << 8)) |
- // (zxtb(Elem[2]) | (zxtb(Elem[3]) << 8)) << 16
- assert(Elem.size() == 4);
- SDValue Vs[4];
- for (unsigned i = 0; i != 4; ++i) {
- Vs[i] = DAG.getZExtOrTrunc(Elem[i], dl, MVT::i32);
- Vs[i] = DAG.getZeroExtendInReg(Vs[i], dl, MVT::i8);
+ SDValue R = getNode(Hexagon::A2_combine_ll, dl, MVT::i32, {B1, B0}, DAG);
+ return DAG.getBitcast(MVT::v4i8, R);
}
- SDValue S8 = DAG.getConstant(8, dl, MVT::i32);
- SDValue T0 = DAG.getNode(ISD::SHL, dl, MVT::i32, {Vs[1], S8});
- SDValue T1 = DAG.getNode(ISD::SHL, dl, MVT::i32, {Vs[3], S8});
- SDValue B0 = DAG.getNode(ISD::OR, dl, MVT::i32, {Vs[0], T0});
- SDValue B1 = DAG.getNode(ISD::OR, dl, MVT::i32, {Vs[2], T1});
- SDValue R = getNode(Hexagon::A2_combine_ll, dl, MVT::i32, {B1, B0}, DAG);
- return DAG.getBitcast(MVT::v4i8, R);
+#ifndef NDEBUG
+ dbgs() << "VecTy: " << EVT(VecTy).getEVTString() << '\n';
+#endif
+ llvm_unreachable("Unexpected vector element type");
}
SDValue
MVT ElemTy = VecTy.getVectorElementType();
assert(VecTy.getVectorNumElements() == Elem.size());
- SmallVector<ConstantSDNode*,8> Consts;
- bool AllConst = true;
- for (SDValue V : Elem) {
- if (isUndef(V))
- V = DAG.getConstant(0, dl, ElemTy);
- auto *C = dyn_cast<ConstantSDNode>(V.getNode());
- Consts.push_back(C);
- AllConst = AllConst && C != nullptr;
- }
+ SmallVector<ConstantInt*,8> Consts(Elem.size());
+ bool AllConst = getBuildVectorConstInts(Elem, VecTy, DAG, Consts);
unsigned First, Num = Elem.size();
for (First = 0; First != Num; ++First)
if (First == Num)
return DAG.getUNDEF(VecTy);
+ if (AllConst &&
+ llvm::all_of(Consts, [](ConstantInt *CI) { return CI->isZero(); }))
+ return getZero(dl, VecTy, DAG);
+
// First try splat if possible.
if (ElemTy == MVT::i16) {
bool IsSplat = true;
MVT HalfTy = MVT::getVectorVT(ElemTy, Num/2);
SDValue L = (ElemTy == MVT::i32)
? Elem[0]
- : buildVector32({Elem.data(), Num/2}, dl, HalfTy, DAG);
+ : buildVector32(Elem.take_front(Num/2), dl, HalfTy, DAG);
SDValue H = (ElemTy == MVT::i32)
? Elem[1]
- : buildVector32({Elem.data()+Num/2, Num/2}, dl, HalfTy, DAG);
+ : buildVector32(Elem.drop_front(Num/2), dl, HalfTy, DAG);
return DAG.getNode(HexagonISD::COMBINE, dl, VecTy, {H, L});
}
return DAG.getNode(ISD::BITCAST, dl, VecTy, InsV);
}
+SDValue
+HexagonTargetLowering::getZero(const SDLoc &dl, MVT Ty, SelectionDAG &DAG)
+ const {
+ if (Ty.isVector()) {
+ assert(Ty.isInteger() && "Only integer vectors are supported here");
+ unsigned W = Ty.getSizeInBits();
+ if (W <= 64)
+ return DAG.getBitcast(Ty, DAG.getConstant(0, dl, MVT::getIntegerVT(W)));
+ return DAG.getNode(HexagonISD::VZERO, dl, Ty);
+ }
+
+ if (Ty.isInteger())
+ return DAG.getConstant(0, dl, Ty);
+ if (Ty.isFloatingPoint())
+ return DAG.getConstantFP(0.0, dl, Ty);
+ llvm_unreachable("Invalid type for zero");
+}
+
SDValue
HexagonTargetLowering::LowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG) const {
MVT VecTy = ty(Op);
unsigned BW = VecTy.getSizeInBits();
+
+ if (Subtarget.useHVXOps() && Subtarget.isHVXVectorType(VecTy, true))
+ return LowerHvxBuildVector(Op, DAG);
+
if (BW == 32 || BW == 64) {
+ const SDLoc &dl(Op);
SmallVector<SDValue,8> Ops;
for (unsigned i = 0, e = Op.getNumOperands(); i != e; ++i)
Ops.push_back(Op.getOperand(i));
if (BW == 32)
- return buildVector32(Ops, SDLoc(Op), VecTy, DAG);
- return buildVector64(Ops, SDLoc(Op), VecTy, DAG);
+ return buildVector32(Ops, dl, VecTy, DAG);
+ return buildVector64(Ops, dl, VecTy, DAG);
}
- if (Subtarget.useHVXOps() && Subtarget.isHVXVectorType(VecTy))
- return LowerHvxBuildVector(Op, DAG);
-
return SDValue();
}
#ifndef NDEBUG
Op.getNode()->dumpr(&DAG);
if (Opc > HexagonISD::OP_BEGIN && Opc < HexagonISD::OP_END)
- errs() << "Check for a non-legal type in this operation\n";
+ errs() << "Error: check for a non-legal type in this operation\n";
#endif
llvm_unreachable("Should not custom lower this!");
case ISD::CONCAT_VECTORS: return LowerCONCAT_VECTORS(Op, DAG);
opCastElem(Op1, MVT::i8, DAG), ByteMask);
}
+MVT
+HexagonTargetLowering::getVecBoolVT() const {
+ return MVT::getVectorVT(MVT::i1, 8*Subtarget.getVectorLength());
+}
+
SDValue
-HexagonTargetLowering::LowerHvxBuildVector(SDValue Op, SelectionDAG &DAG)
- const {
- const SDLoc &dl(Op);
- BuildVectorSDNode *BN = cast<BuildVectorSDNode>(Op.getNode());
- bool IsConst = BN->isConstant();
+HexagonTargetLowering::buildHvxVectorSingle(ArrayRef<SDValue> Values,
+ const SDLoc &dl, MVT VecTy,
+ SelectionDAG &DAG) const {
+ unsigned VecLen = Values.size();
MachineFunction &MF = DAG.getMachineFunction();
- MVT VecTy = ty(Op);
+ MVT ElemTy = VecTy.getVectorElementType();
+ unsigned ElemWidth = ElemTy.getSizeInBits();
+ unsigned HwLen = Subtarget.getVectorLength();
- if (IsConst) {
- SmallVector<Constant*, 128> Elems;
- for (SDValue V : BN->op_values()) {
- if (auto *C = dyn_cast<ConstantSDNode>(V.getNode()))
- Elems.push_back(const_cast<ConstantInt*>(C->getConstantIntValue()));
- }
- Constant *CV = ConstantVector::get(Elems);
- unsigned Align = VecTy.getSizeInBits() / 8;
+ SmallVector<ConstantInt*, 128> Consts(VecLen);
+ bool AllConst = getBuildVectorConstInts(Values, VecTy, DAG, Consts);
+ if (AllConst) {
+ if (llvm::all_of(Consts, [](ConstantInt *CI) { return CI->isZero(); }))
+ return getZero(dl, VecTy, DAG);
+
+ ArrayRef<Constant*> Tmp((Constant**)Consts.begin(),
+ (Constant**)Consts.end());
+ Constant *CV = ConstantVector::get(Tmp);
+ unsigned Align = HwLen;
SDValue CP = LowerConstantPool(DAG.getConstantPool(CV, VecTy, Align), DAG);
return DAG.getLoad(VecTy, dl, DAG.getEntryNode(), CP,
MachinePointerInfo::getConstantPool(MF), Align);
}
- unsigned NumOps = Op.getNumOperands();
- unsigned HwLen = Subtarget.getVectorLength();
- unsigned ElemSize = VecTy.getVectorElementType().getSizeInBits() / 8;
- assert(ElemSize*NumOps == HwLen);
-
+ unsigned ElemSize = ElemWidth / 8;
+ assert(ElemSize*VecLen == HwLen);
SmallVector<SDValue,32> Words;
- SmallVector<SDValue,32> Ops;
- for (unsigned i = 0; i != NumOps; ++i)
- Ops.push_back(Op.getOperand(i));
if (VecTy.getVectorElementType() != MVT::i32) {
- assert(ElemSize < 4 && "vNi64 should have been promoted to vNi32");
assert((ElemSize == 1 || ElemSize == 2) && "Invalid element size");
unsigned OpsPerWord = (ElemSize == 1) ? 4 : 2;
MVT PartVT = MVT::getVectorVT(VecTy.getVectorElementType(), OpsPerWord);
- for (unsigned i = 0; i != NumOps; i += OpsPerWord) {
- SDValue W = buildVector32({&Ops[i], OpsPerWord}, dl, PartVT, DAG);
+ for (unsigned i = 0; i != VecLen; i += OpsPerWord) {
+ SDValue W = buildVector32(Values.slice(i, OpsPerWord), dl, PartVT, DAG);
Words.push_back(DAG.getBitcast(MVT::i32, W));
}
} else {
- Words.assign(Ops.begin(), Ops.end());
+ Words.assign(Values.begin(), Values.end());
}
// Construct two halves in parallel, then or them together.
return DstV;
}
+SDValue
+HexagonTargetLowering::buildHvxVectorPred(ArrayRef<SDValue> Values,
+ const SDLoc &dl, MVT VecTy,
+ SelectionDAG &DAG) const {
+ // Construct a vector V of bytes, such that a comparison V >u 0 would
+ // produce the required vector predicate.
+ unsigned VecLen = Values.size();
+ unsigned HwLen = Subtarget.getVectorLength();
+ assert(VecLen <= HwLen || VecLen == 8*HwLen);
+ SmallVector<SDValue,128> Bytes;
+
+ if (VecLen <= HwLen) {
+ // In the hardware, each bit of a vector predicate corresponds to a byte
+ // of a vector register. Calculate how many bytes does a bit of VecTy
+ // correspond to.
+ assert(HwLen % VecLen == 0);
+ unsigned BitBytes = HwLen / VecLen;
+ for (SDValue V : Values) {
+ SDValue Ext = !V.isUndef() ? DAG.getZExtOrTrunc(V, dl, MVT::i8)
+ : DAG.getConstant(0, dl, MVT::i8);
+ for (unsigned B = 0; B != BitBytes; ++B)
+ Bytes.push_back(Ext);
+ }
+ } else {
+ // There are as many i1 values, as there are bits in a vector register.
+ // Divide the values into groups of 8 and check that each group consists
+ // of the same value (ignoring undefs).
+ for (unsigned I = 0; I != VecLen; I += 8) {
+ unsigned B = 0;
+ // Find the first non-undef value in this group.
+ for (; B != 8; ++B) {
+ if (!Values[I+B].isUndef())
+ break;
+ }
+ SDValue F = Values[I+B];
+ SDValue Ext = (B < 8) ? DAG.getZExtOrTrunc(F, dl, MVT::i8)
+ : DAG.getConstant(0, dl, MVT::i8);
+ Bytes.push_back(Ext);
+ // Verify that the rest of values in the group are the same as the
+ // first.
+ for (; B != 8; ++B)
+ assert(Values[I+B].isUndef() || Values[I+B] == F);
+ }
+ }
+
+ MVT ByteTy = MVT::getVectorVT(MVT::i8, HwLen);
+ SDValue ByteVec = buildHvxVectorSingle(Bytes, dl, ByteTy, DAG);
+ SDValue Cmp = DAG.getSetCC(dl, VecTy, ByteVec, getZero(dl, ByteTy, DAG),
+ ISD::SETUGT);
+ return Cmp;
+}
+
+SDValue
+HexagonTargetLowering::LowerHvxBuildVector(SDValue Op, SelectionDAG &DAG)
+ const {
+ const SDLoc &dl(Op);
+ MVT VecTy = ty(Op);
+
+ unsigned Size = Op.getNumOperands();
+ SmallVector<SDValue,128> Ops;
+ for (unsigned i = 0; i != Size; ++i)
+ Ops.push_back(Op.getOperand(i));
+
+ if (VecTy.getVectorElementType() == MVT::i1)
+ return buildHvxVectorPred(Ops, dl, VecTy, DAG);
+
+ if (VecTy.getSizeInBits() == 16*Subtarget.getVectorLength()) {
+ ArrayRef<SDValue> A(Ops);
+ MVT SingleTy = typeSplit(VecTy).first;
+ SDValue V0 = buildHvxVectorSingle(A.take_front(Size/2), dl, SingleTy, DAG);
+ SDValue V1 = buildHvxVectorSingle(A.drop_front(Size/2), dl, SingleTy, DAG);
+ return DAG.getNode(ISD::CONCAT_VECTORS, dl, VecTy, V0, V1);
+ }
+
+ return buildHvxVectorSingle(Ops, dl, VecTy, DAG);
+}
+
SDValue
HexagonTargetLowering::LowerHvxExtractElement(SDValue Op, SelectionDAG &DAG)
const {
// (negate (swap-op NewCmp)),
// the condition code for the NewCmp should be calculated from the original
// CC by applying these operations in the reverse order.
+ //
+ // This could also be done through setCondCodeAction, but for negation it
+ // uses a xor with a vector of -1s, which it obtains from BUILD_VECTOR.
+ // That is far too expensive for what can be done with a single instruction.
switch (CC) {
case ISD::SETNE: // !eq