diff options
| author | Krzysztof Parzyszek <kparzysz@codeaurora.org> | 2017-12-06 16:40:37 +0000 |
|---|---|---|
| committer | Krzysztof Parzyszek <kparzysz@codeaurora.org> | 2017-12-06 16:40:37 +0000 |
| commit | 7d37dd8902e8ef8583cdbbe906eda8435426c996 (patch) | |
| tree | 1c8e0961ebc4986c6a8c6c510a4d4fc38b38a37d /llvm/lib/Target/Hexagon/HexagonISelLoweringHVX.cpp | |
| parent | aa902be15897c3fc1486481648dc3958e7aeba81 (diff) | |
| download | bcm5719-llvm-7d37dd8902e8ef8583cdbbe906eda8435426c996.tar.gz bcm5719-llvm-7d37dd8902e8ef8583cdbbe906eda8435426c996.zip | |
[Hexagon] Generate HVX code for vector construction and access
Support for:
- build vector,
- extract vector element, subvector,
- insert vector element, subvector,
- shuffle.
llvm-svn: 319901
Diffstat (limited to 'llvm/lib/Target/Hexagon/HexagonISelLoweringHVX.cpp')
| -rw-r--r-- | llvm/lib/Target/Hexagon/HexagonISelLoweringHVX.cpp | 299 |
1 files changed, 299 insertions, 0 deletions
diff --git a/llvm/lib/Target/Hexagon/HexagonISelLoweringHVX.cpp b/llvm/lib/Target/Hexagon/HexagonISelLoweringHVX.cpp new file mode 100644 index 00000000000..3a9e50826a0 --- /dev/null +++ b/llvm/lib/Target/Hexagon/HexagonISelLoweringHVX.cpp @@ -0,0 +1,299 @@ +//===-- HexagonISelLoweringHVX.cpp --- Lowering HVX operations ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "HexagonISelLowering.h" +#include "HexagonRegisterInfo.h" +#include "HexagonSubtarget.h" + +using namespace llvm; + +SDValue +HexagonTargetLowering::getInt(unsigned IntId, MVT ResTy, ArrayRef<SDValue> Ops, + const SDLoc &dl, SelectionDAG &DAG) const { + SmallVector<SDValue,4> IntOps; + IntOps.push_back(DAG.getConstant(IntId, dl, MVT::i32)); + for (const SDValue &Op : Ops) + IntOps.push_back(Op); + return DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, ResTy, IntOps); +} + +MVT +HexagonTargetLowering::typeJoin(const TypePair &Tys) const { + assert(Tys.first.getVectorElementType() == Tys.second.getVectorElementType()); + + MVT ElemTy = Tys.first.getVectorElementType(); + return MVT::getVectorVT(ElemTy, Tys.first.getVectorNumElements() + + Tys.second.getVectorNumElements()); +} + +HexagonTargetLowering::TypePair +HexagonTargetLowering::typeSplit(MVT VecTy) const { + assert(VecTy.isVector()); + unsigned NumElem = VecTy.getVectorNumElements(); + assert((NumElem % 2) == 0 && "Expecting even-sized vector type"); + MVT HalfTy = MVT::getVectorVT(VecTy.getVectorElementType(), NumElem/2); + return { HalfTy, HalfTy }; +} + +MVT +HexagonTargetLowering::typeExtElem(MVT VecTy, unsigned Factor) const { + MVT ElemTy = VecTy.getVectorElementType(); + MVT NewElemTy = MVT::getIntegerVT(ElemTy.getSizeInBits() * Factor); + return MVT::getVectorVT(NewElemTy, VecTy.getVectorNumElements()); +} + +MVT +HexagonTargetLowering::typeTruncElem(MVT VecTy, unsigned Factor) const { + MVT ElemTy = VecTy.getVectorElementType(); + MVT NewElemTy = MVT::getIntegerVT(ElemTy.getSizeInBits() / Factor); + return MVT::getVectorVT(NewElemTy, VecTy.getVectorNumElements()); +} + +SDValue +HexagonTargetLowering::opCastElem(SDValue Vec, MVT ElemTy, + SelectionDAG &DAG) const { + if (ty(Vec).getVectorElementType() == ElemTy) + return Vec; + MVT CastTy = tyVector(Vec.getValueType().getSimpleVT(), ElemTy); + return DAG.getBitcast(CastTy, Vec); +} + +SDValue +HexagonTargetLowering::opJoin(const VectorPair &Ops, const SDLoc &dl, + SelectionDAG &DAG) const { + return DAG.getNode(ISD::CONCAT_VECTORS, dl, typeJoin(ty(Ops)), + Ops.second, Ops.first); +} + +HexagonTargetLowering::VectorPair +HexagonTargetLowering::opSplit(SDValue Vec, const SDLoc &dl, + SelectionDAG &DAG) const { + TypePair Tys = typeSplit(ty(Vec)); + return DAG.SplitVector(Vec, dl, Tys.first, Tys.second); +} + +SDValue +HexagonTargetLowering::convertToByteIndex(SDValue ElemIdx, MVT ElemTy, + SelectionDAG &DAG) const { + if (ElemIdx.getValueType().getSimpleVT() != MVT::i32) + ElemIdx = DAG.getBitcast(MVT::i32, ElemIdx); + + unsigned ElemWidth = ElemTy.getSizeInBits(); + if (ElemWidth == 8) + return ElemIdx; + + unsigned L = Log2_32(ElemWidth/8); + const SDLoc &dl(ElemIdx); + return DAG.getNode(ISD::SHL, dl, MVT::i32, + {ElemIdx, DAG.getConstant(L, dl, MVT::i32)}); +} + +SDValue +HexagonTargetLowering::getIndexInWord32(SDValue Idx, MVT ElemTy, + SelectionDAG &DAG) const { + unsigned ElemWidth = ElemTy.getSizeInBits(); + assert(ElemWidth >= 8 && ElemWidth <= 32); + if (ElemWidth == 32) + return Idx; + + if (ty(Idx) != MVT::i32) + Idx = DAG.getBitcast(MVT::i32, Idx); + const SDLoc &dl(Idx); + SDValue Mask = DAG.getConstant(32/ElemWidth - 1, dl, MVT::i32); + SDValue SubIdx = DAG.getNode(ISD::AND, dl, MVT::i32, {Idx, Mask}); + return SubIdx; +} + +SDValue +HexagonTargetLowering::LowerHvxBuildVector(SDValue Op, SelectionDAG &DAG) + const { + const SDLoc &dl(Op); + BuildVectorSDNode *BN = cast<BuildVectorSDNode>(Op.getNode()); + bool IsConst = BN->isConstant(); + MachineFunction &MF = DAG.getMachineFunction(); + MVT VecTy = ty(Op); + + 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; + 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); + + 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); + Words.push_back(DAG.getBitcast(MVT::i32, W)); + } + } else { + Words.assign(Ops.begin(), Ops.end()); + } + + // Construct two halves in parallel, then or them together. + assert(4*Words.size() == Subtarget.getVectorLength()); + SDValue HalfV0 = getNode(Hexagon::V6_vd0, dl, VecTy, {}, DAG); + SDValue HalfV1 = getNode(Hexagon::V6_vd0, dl, VecTy, {}, DAG); + SDValue S = DAG.getConstant(4, dl, MVT::i32); + unsigned NumWords = Words.size(); + for (unsigned i = 0; i != NumWords/2; ++i) { + SDValue N = DAG.getNode(HexagonISD::VINSERTW0, dl, VecTy, + {HalfV0, Words[i]}); + SDValue M = DAG.getNode(HexagonISD::VINSERTW0, dl, VecTy, + {HalfV1, Words[i+NumWords/2]}); + HalfV0 = DAG.getNode(HexagonISD::VROR, dl, VecTy, {N, S}); + HalfV1 = DAG.getNode(HexagonISD::VROR, dl, VecTy, {M, S}); + } + + HalfV0 = DAG.getNode(HexagonISD::VROR, dl, VecTy, + {HalfV0, DAG.getConstant(HwLen/2, dl, MVT::i32)}); + SDValue DstV = DAG.getNode(ISD::OR, dl, VecTy, {HalfV0, HalfV1}); + return DstV; +} + +SDValue +HexagonTargetLowering::LowerHvxExtractElement(SDValue Op, SelectionDAG &DAG) + const { + // Change the type of the extracted element to i32. + SDValue VecV = Op.getOperand(0); + MVT ElemTy = ty(VecV).getVectorElementType(); + unsigned ElemWidth = ElemTy.getSizeInBits(); + assert(ElemWidth >= 8 && ElemWidth <= 32); // TODO i64 + + const SDLoc &dl(Op); + SDValue IdxV = Op.getOperand(1); + if (ty(IdxV) != MVT::i32) + IdxV = DAG.getBitcast(MVT::i32, IdxV); + + SDValue ByteIdx = convertToByteIndex(IdxV, ElemTy, DAG); + SDValue ExWord = DAG.getNode(HexagonISD::VEXTRACTW, dl, MVT::i32, + {VecV, ByteIdx}); + if (ElemTy == MVT::i32) + return ExWord; + + // Have an extracted word, need to extract the smaller element out of it. + // 1. Extract the bits of (the original) IdxV that correspond to the index + // of the desired element in the 32-bit word. + SDValue SubIdx = getIndexInWord32(IdxV, ElemTy, DAG); + // 2. Extract the element from the word. + SDValue ExVec = DAG.getBitcast(tyVector(ty(ExWord), ElemTy), ExWord); + return extractVector(ExVec, SubIdx, dl, ElemTy, MVT::i32, DAG); +} + +SDValue +HexagonTargetLowering::LowerHvxInsertElement(SDValue Op, SelectionDAG &DAG) + const { + const SDLoc &dl(Op); + SDValue VecV = Op.getOperand(0); + SDValue ValV = Op.getOperand(1); + SDValue IdxV = Op.getOperand(2); + MVT ElemTy = ty(VecV).getVectorElementType(); + unsigned ElemWidth = ElemTy.getSizeInBits(); + assert(ElemWidth >= 8 && ElemWidth <= 32); // TODO i64 + + auto InsertWord = [&DAG,&dl,this] (SDValue VecV, SDValue ValV, + SDValue ByteIdxV) { + MVT VecTy = ty(VecV); + unsigned HwLen = Subtarget.getVectorLength(); + SDValue MaskV = DAG.getNode(ISD::AND, dl, MVT::i32, + {ByteIdxV, DAG.getConstant(-4, dl, MVT::i32)}); + SDValue RotV = DAG.getNode(HexagonISD::VROR, dl, VecTy, {VecV, MaskV}); + SDValue InsV = DAG.getNode(HexagonISD::VINSERTW0, dl, VecTy, {RotV, ValV}); + SDValue SubV = DAG.getNode(ISD::SUB, dl, MVT::i32, + {DAG.getConstant(HwLen/4, dl, MVT::i32), MaskV}); + SDValue TorV = DAG.getNode(HexagonISD::VROR, dl, VecTy, {InsV, SubV}); + return TorV; + }; + + SDValue ByteIdx = convertToByteIndex(IdxV, ElemTy, DAG); + if (ElemTy == MVT::i32) + return InsertWord(VecV, ValV, ByteIdx); + + // If this is not inserting a 32-bit word, convert it into such a thing. + // 1. Extract the existing word from the target vector. + SDValue WordIdx = DAG.getNode(ISD::SRL, dl, MVT::i32, + {ByteIdx, DAG.getConstant(2, dl, MVT::i32)}); + SDValue Ex0 = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, MVT::i32, + {opCastElem(VecV, MVT::i32, DAG), WordIdx}); + SDValue Ext = LowerHvxExtractElement(Ex0, DAG); + + // 2. Treating the extracted word as a 32-bit vector, insert the given + // value into it. + SDValue SubIdx = getIndexInWord32(IdxV, ElemTy, DAG); + MVT SubVecTy = tyVector(ty(Ext), ElemTy); + SDValue Ins = insertVector(DAG.getBitcast(SubVecTy, Ext), + ValV, SubIdx, dl, SubVecTy, DAG); + + // 3. Insert the 32-bit word back into the original vector. + return InsertWord(VecV, Ins, ByteIdx); +} + +SDValue +HexagonTargetLowering::LowerHvxExtractSubvector(SDValue Op, SelectionDAG &DAG) + const { + SDValue SrcV = Op.getOperand(0); + MVT SrcTy = ty(SrcV); + unsigned SrcElems = SrcTy.getVectorNumElements(); + SDValue IdxV = Op.getOperand(1); + unsigned Idx = cast<ConstantSDNode>(IdxV.getNode())->getZExtValue(); + MVT DstTy = ty(Op); + assert(Idx == 0 || DstTy.getVectorNumElements() % Idx == 0); + const SDLoc &dl(Op); + if (Idx == 0) + return DAG.getTargetExtractSubreg(Hexagon::vsub_lo, dl, DstTy, SrcV); + if (Idx == SrcElems/2) + return DAG.getTargetExtractSubreg(Hexagon::vsub_hi, dl, DstTy, SrcV); + return SDValue(); +} + +SDValue +HexagonTargetLowering::LowerHvxInsertSubvector(SDValue Op, SelectionDAG &DAG) + const { + // Idx may be variable + SDValue IdxV = Op.getOperand(2); + auto *IdxN = dyn_cast<ConstantSDNode>(IdxV.getNode()); + if (!IdxN) + return SDValue(); + unsigned Idx = IdxN->getZExtValue(); + + SDValue DstV = Op.getOperand(0); + SDValue SrcV = Op.getOperand(1); + MVT DstTy = ty(DstV); + MVT SrcTy = ty(SrcV); + unsigned DstElems = DstTy.getVectorNumElements(); + unsigned SrcElems = SrcTy.getVectorNumElements(); + if (2*SrcElems != DstElems) + return SDValue(); + + const SDLoc &dl(Op); + if (Idx == 0) + return DAG.getTargetInsertSubreg(Hexagon::vsub_lo, dl, DstTy, DstV, SrcV); + if (Idx == SrcElems) + return DAG.getTargetInsertSubreg(Hexagon::vsub_hi, dl, DstTy, DstV, SrcV); + return SDValue(); +} |

