summaryrefslogtreecommitdiff
path: root/lib/Target/Hexagon/HexagonISelLoweringHVX.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Target/Hexagon/HexagonISelLoweringHVX.cpp')
-rw-r--r--lib/Target/Hexagon/HexagonISelLoweringHVX.cpp463
1 files changed, 463 insertions, 0 deletions
diff --git a/lib/Target/Hexagon/HexagonISelLoweringHVX.cpp b/lib/Target/Hexagon/HexagonISelLoweringHVX.cpp
new file mode 100644
index 0000000000000..c1d44cb0e7dec
--- /dev/null
+++ b/lib/Target/Hexagon/HexagonISelLoweringHVX.cpp
@@ -0,0 +1,463 @@
+//===-- 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::getByteShuffle(const SDLoc &dl, SDValue Op0,
+ SDValue Op1, ArrayRef<int> Mask,
+ SelectionDAG &DAG) const {
+ MVT OpTy = ty(Op0);
+ assert(OpTy == ty(Op1));
+
+ MVT ElemTy = OpTy.getVectorElementType();
+ if (ElemTy == MVT::i8)
+ return DAG.getVectorShuffle(OpTy, dl, Op0, Op1, Mask);
+ assert(ElemTy.getSizeInBits() >= 8);
+
+ MVT ResTy = tyVector(OpTy, MVT::i8);
+ unsigned ElemSize = ElemTy.getSizeInBits() / 8;
+
+ SmallVector<int,128> ByteMask;
+ for (int M : Mask) {
+ if (M < 0) {
+ for (unsigned I = 0; I != ElemSize; ++I)
+ ByteMask.push_back(-1);
+ } else {
+ int NewM = M*ElemSize;
+ for (unsigned I = 0; I != ElemSize; ++I)
+ ByteMask.push_back(NewM+I);
+ }
+ }
+ assert(ResTy.getVectorNumElements() == ByteMask.size());
+ return DAG.getVectorShuffle(ResTy, dl, opCastElem(Op0, MVT::i8, DAG),
+ opCastElem(Op1, MVT::i8, DAG), ByteMask);
+}
+
+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);
+ (void)ElemWidth;
+
+ 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);
+ (void)ElemWidth;
+
+ 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, ElemTy, 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();
+}
+
+SDValue
+HexagonTargetLowering::LowerHvxMul(SDValue Op, SelectionDAG &DAG) const {
+ MVT ResTy = ty(Op);
+ if (!ResTy.isVector())
+ return SDValue();
+ const SDLoc &dl(Op);
+ SmallVector<int,256> ShuffMask;
+
+ MVT ElemTy = ResTy.getVectorElementType();
+ unsigned VecLen = ResTy.getVectorNumElements();
+ SDValue Vs = Op.getOperand(0);
+ SDValue Vt = Op.getOperand(1);
+
+ switch (ElemTy.SimpleTy) {
+ case MVT::i8:
+ case MVT::i16: {
+ // For i8 vectors Vs = (a0, a1, ...), Vt = (b0, b1, ...),
+ // V6_vmpybv Vs, Vt produces a pair of i16 vectors Hi:Lo,
+ // where Lo = (a0*b0, a2*b2, ...), Hi = (a1*b1, a3*b3, ...).
+ // For i16, use V6_vmpyhv, which behaves in an analogous way to
+ // V6_vmpybv: results Lo and Hi are products of even/odd elements
+ // respectively.
+ MVT ExtTy = typeExtElem(ResTy, 2);
+ unsigned MpyOpc = ElemTy == MVT::i8 ? Hexagon::V6_vmpybv
+ : Hexagon::V6_vmpyhv;
+ SDValue M = getNode(MpyOpc, dl, ExtTy, {Vs, Vt}, DAG);
+
+ // Discard high halves of the resulting values, collect the low halves.
+ for (unsigned I = 0; I < VecLen; I += 2) {
+ ShuffMask.push_back(I); // Pick even element.
+ ShuffMask.push_back(I+VecLen); // Pick odd element.
+ }
+ VectorPair P = opSplit(opCastElem(M, ElemTy, DAG), dl, DAG);
+ return getByteShuffle(dl, P.first, P.second, ShuffMask, DAG);
+ }
+ case MVT::i32: {
+ // Use the following sequence for signed word multiply:
+ // T0 = V6_vmpyiowh Vs, Vt
+ // T1 = V6_vaslw T0, 16
+ // T2 = V6_vmpyiewuh_acc T1, Vs, Vt
+ SDValue S16 = DAG.getConstant(16, dl, MVT::i32);
+ SDValue T0 = getNode(Hexagon::V6_vmpyiowh, dl, ResTy, {Vs, Vt}, DAG);
+ SDValue T1 = getNode(Hexagon::V6_vaslw, dl, ResTy, {T0, S16}, DAG);
+ SDValue T2 = getNode(Hexagon::V6_vmpyiewuh_acc, dl, ResTy,
+ {T1, Vs, Vt}, DAG);
+ return T2;
+ }
+ default:
+ break;
+ }
+ return SDValue();
+}
+
+SDValue
+HexagonTargetLowering::LowerHvxSetCC(SDValue Op, SelectionDAG &DAG) const {
+ MVT VecTy = ty(Op.getOperand(0));
+ assert(VecTy == ty(Op.getOperand(1)));
+
+ SDValue Cmp = Op.getOperand(2);
+ ISD::CondCode CC = cast<CondCodeSDNode>(Cmp)->get();
+ bool Negate = false, Swap = false;
+
+ // HVX has instructions for SETEQ, SETGT, SETUGT. The other comparisons
+ // can be arranged as operand-swapped/negated versions of these. Since
+ // the generated code will have the original CC expressed as
+ // (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.
+
+ switch (CC) {
+ case ISD::SETNE: // !eq
+ case ISD::SETLE: // !gt
+ case ISD::SETGE: // !lt
+ case ISD::SETULE: // !ugt
+ case ISD::SETUGE: // !ult
+ CC = ISD::getSetCCInverse(CC, true);
+ Negate = true;
+ break;
+ default:
+ break;
+ }
+
+ switch (CC) {
+ case ISD::SETLT: // swap gt
+ case ISD::SETULT: // swap ugt
+ CC = ISD::getSetCCSwappedOperands(CC);
+ Swap = true;
+ break;
+ default:
+ break;
+ }
+
+ assert(CC == ISD::SETEQ || CC == ISD::SETGT || CC == ISD::SETUGT);
+
+ MVT ElemTy = VecTy.getVectorElementType();
+ unsigned ElemWidth = ElemTy.getSizeInBits();
+ assert(isPowerOf2_32(ElemWidth));
+
+ auto getIdx = [] (unsigned Code) {
+ static const unsigned Idx[] = { ISD::SETEQ, ISD::SETGT, ISD::SETUGT };
+ for (unsigned I = 0, E = array_lengthof(Idx); I != E; ++I)
+ if (Code == Idx[I])
+ return I;
+ llvm_unreachable("Unhandled CondCode");
+ };
+
+ static unsigned OpcTable[3][3] = {
+ // SETEQ SETGT, SETUGT
+ /* Byte */ { Hexagon::V6_veqb, Hexagon::V6_vgtb, Hexagon::V6_vgtub },
+ /* Half */ { Hexagon::V6_veqh, Hexagon::V6_vgth, Hexagon::V6_vgtuh },
+ /* Word */ { Hexagon::V6_veqw, Hexagon::V6_vgtw, Hexagon::V6_vgtuw }
+ };
+
+ unsigned CmpOpc = OpcTable[Log2_32(ElemWidth)-3][getIdx(CC)];
+
+ MVT ResTy = ty(Op);
+ const SDLoc &dl(Op);
+ SDValue OpL = Swap ? Op.getOperand(1) : Op.getOperand(0);
+ SDValue OpR = Swap ? Op.getOperand(0) : Op.getOperand(1);
+ SDValue CmpV = getNode(CmpOpc, dl, ResTy, {OpL, OpR}, DAG);
+ return Negate ? getNode(Hexagon::V6_pred_not, dl, ResTy, {CmpV}, DAG)
+ : CmpV;
+}
+
+SDValue
+HexagonTargetLowering::LowerHvxExtend(SDValue Op, SelectionDAG &DAG) const {
+ // Sign- and zero-extends are legal.
+ assert(Op.getOpcode() == ISD::ANY_EXTEND_VECTOR_INREG);
+ return DAG.getZeroExtendVectorInReg(Op.getOperand(0), SDLoc(Op), ty(Op));
+}