diff options
author | Duncan Sands <baldrick@free.fr> | 2008-02-27 13:34:40 +0000 |
---|---|---|
committer | Duncan Sands <baldrick@free.fr> | 2008-02-27 13:34:40 +0000 |
commit | 077f9b20d0e8659d00a09046a63e28edf0665ffe (patch) | |
tree | 19536af56a9bc4a2f026f4b006c016d51fbff242 /lib/CodeGen/SelectionDAG/LegalizeTypesSplit.cpp | |
parent | 0a4c3782c8d558a9859a90ae8e2d5d0efa057e41 (diff) |
LegalizeTypes support for EXTRACT_VECTOR_ELT. The
approach taken is different to that in LegalizeDAG
when it is a question of expanding or promoting the
result type: for example, if extracting an i64 from
a <2 x i64>, when i64 needs expanding, it bitcasts
the vector to <4 x i32>, extracts the appropriate
two i32's, and uses those for the Lo and Hi parts.
Likewise, when extracting an i16 from a <4 x i16>,
and i16 needs promoting, it bitcasts the vector to
<2 x i32>, extracts the appropriate i32, twiddles
the bits if necessary, and uses that as the promoted
value. This puts more pressure on bitcast legalization,
and I've added the appropriate cases. They needed to
be added anyway since users can generate such bitcasts
too if they want to. Also, when considering various
cases (Legal, Promote, Expand, Scalarize, Split) it is
a pain that expand can correspond to Expand, Scalarize
or Split, so I've changed the LegalizeTypes enum so it
lists those different cases - now Expand only means
splitting a scalar in two.
The code produced is the same as by LegalizeDAG for
all relevant testcases, except for
2007-10-31-extractelement-i64.ll, where the code seems
to have improved (see below; can an expert please tell
me if it is better or not).
Before < vs after >.
< subl $92, %esp
< movaps %xmm0, 64(%esp)
< movaps %xmm0, (%esp)
< movl 4(%esp), %eax
< movl %eax, 28(%esp)
< movl (%esp), %eax
< movl %eax, 24(%esp)
< movq 24(%esp), %mm0
< movq %mm0, 56(%esp)
---
> subl $44, %esp
> movaps %xmm0, 16(%esp)
> pshufd $1, %xmm0, %xmm1
> movd %xmm1, 4(%esp)
> movd %xmm0, (%esp)
> movq (%esp), %mm0
> movq %mm0, 8(%esp)
< subl $92, %esp
< movaps %xmm0, 64(%esp)
< movaps %xmm0, (%esp)
< movl 12(%esp), %eax
< movl %eax, 28(%esp)
< movl 8(%esp), %eax
< movl %eax, 24(%esp)
< movq 24(%esp), %mm0
< movq %mm0, 56(%esp)
---
> subl $44, %esp
> movaps %xmm0, 16(%esp)
> pshufd $3, %xmm0, %xmm1
> movd %xmm1, 4(%esp)
> movhlps %xmm0, %xmm0
> movd %xmm0, (%esp)
> movq (%esp), %mm0
> movq %mm0, 8(%esp)
< subl $92, %esp
< movaps %xmm0, 64(%esp)
---
> subl $44, %esp
< movl 16(%esp), %eax
< movl %eax, 48(%esp)
< movl 20(%esp), %eax
< movl %eax, 52(%esp)
< movaps %xmm0, (%esp)
< movl 4(%esp), %eax
< movl %eax, 60(%esp)
< movl (%esp), %eax
< movl %eax, 56(%esp)
---
> pshufd $1, %xmm0, %xmm1
> movd %xmm1, 4(%esp)
> movd %xmm0, (%esp)
> movd %xmm1, 12(%esp)
> movd %xmm0, 8(%esp)
< subl $92, %esp
< movaps %xmm0, 64(%esp)
---
> subl $44, %esp
< movl 24(%esp), %eax
< movl %eax, 48(%esp)
< movl 28(%esp), %eax
< movl %eax, 52(%esp)
< movaps %xmm0, (%esp)
< movl 12(%esp), %eax
< movl %eax, 60(%esp)
< movl 8(%esp), %eax
< movl %eax, 56(%esp)
---
> pshufd $3, %xmm0, %xmm1
> movd %xmm1, 4(%esp)
> movhlps %xmm0, %xmm0
> movd %xmm0, (%esp)
> movd %xmm1, 12(%esp)
> movd %xmm0, 8(%esp)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@47672 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen/SelectionDAG/LegalizeTypesSplit.cpp')
-rw-r--r-- | lib/CodeGen/SelectionDAG/LegalizeTypesSplit.cpp | 120 |
1 files changed, 108 insertions, 12 deletions
diff --git a/lib/CodeGen/SelectionDAG/LegalizeTypesSplit.cpp b/lib/CodeGen/SelectionDAG/LegalizeTypesSplit.cpp index 80718d3834..c0168f0460 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeTypesSplit.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeTypesSplit.cpp @@ -172,7 +172,6 @@ void DAGTypeLegalizer::SplitRes_INSERT_VECTOR_ELT(SDNode *N, SDOperand &Lo, else Hi = DAG.getNode(ISD::INSERT_VECTOR_ELT, Hi.getValueType(), Hi, ScalarOp, DAG.getConstant(Index - LoNumElts, TLI.getPointerTy())); - } void DAGTypeLegalizer::SplitRes_VECTOR_SHUFFLE(SDNode *N, @@ -253,22 +252,50 @@ void DAGTypeLegalizer::SplitRes_BIT_CONVERT(SDNode *N, SDOperand &Lo, SDOperand &Hi) { // We know the result is a vector. The input may be either a vector or a // scalar value. + MVT::ValueType LoVT, HiVT; + GetSplitDestVTs(N->getValueType(0), LoVT, HiVT); + SDOperand InOp = N->getOperand(0); - if (MVT::isVector(InOp.getValueType()) && - MVT::getVectorNumElements(InOp.getValueType()) != 1) { - // If this is a vector, split the vector and convert each of the pieces now. - GetSplitOp(InOp, Lo, Hi); - - MVT::ValueType LoVT, HiVT; - GetSplitDestVTs(N->getValueType(0), LoVT, HiVT); + MVT::ValueType InVT = InOp.getValueType(); + MVT::ValueType NewInVT = TLI.getTypeToTransformTo(InVT); + switch (getTypeAction(InVT)) { + default: + assert(false && "Unknown type action!"); + case Legal: + break; + case Promote: + break; + case Scalarize: + // While it is tempting to extract the scalarized operand, check whether it + // needs expansion, and if so process it in the Expand case below, there is + // no guarantee that the scalarized operand has been processed yet. If it + // hasn't then the call to GetExpandedOp will abort. So just give up. + break; + case Expand: + // A scalar to vector conversion, where the scalar needs expansion. + // Check that the vector is being split in two. + if (MVT::getSizeInBits(NewInVT) == MVT::getSizeInBits(LoVT)) { + // Convert each expanded piece of the scalar now. + GetExpandedOp(InOp, Lo, Hi); + if (TLI.isBigEndian()) + std::swap(Lo, Hi); + Lo = DAG.getNode(ISD::BIT_CONVERT, LoVT, Lo); + Hi = DAG.getNode(ISD::BIT_CONVERT, HiVT, Hi); + return; + } + break; + case Split: + // If the input is a vector that needs to be split, convert each split + // piece of the input now. + GetSplitOp(InOp, Lo, Hi); Lo = DAG.getNode(ISD::BIT_CONVERT, LoVT, Lo); Hi = DAG.getNode(ISD::BIT_CONVERT, HiVT, Hi); return; } - + // Lower the bit-convert to a store/load from the stack, then split the load. - SDOperand Op = CreateStackStoreLoad(N->getOperand(0), N->getValueType(0)); + SDOperand Op = CreateStackStoreLoad(InOp, N->getValueType(0)); SplitRes_LOAD(cast<LoadSDNode>(Op.Val), Lo, Hi); } @@ -340,8 +367,11 @@ bool DAGTypeLegalizer::SplitOperand(SDNode *N, unsigned OpNo) { case ISD::STORE: Res = SplitOp_STORE(cast<StoreSDNode>(N), OpNo); break; case ISD::RET: Res = SplitOp_RET(N, OpNo); break; - case ISD::EXTRACT_SUBVECTOR: Res = SplitOp_EXTRACT_SUBVECTOR(N); break; - case ISD::VECTOR_SHUFFLE: Res = SplitOp_VECTOR_SHUFFLE(N, OpNo); break; + case ISD::BIT_CONVERT: Res = SplitOp_BIT_CONVERT(N); break; + + case ISD::EXTRACT_VECTOR_ELT: Res = SplitOp_EXTRACT_VECTOR_ELT(N); break; + case ISD::EXTRACT_SUBVECTOR: Res = SplitOp_EXTRACT_SUBVECTOR(N); break; + case ISD::VECTOR_SHUFFLE: Res = SplitOp_VECTOR_SHUFFLE(N, OpNo); break; } } @@ -402,6 +432,72 @@ SDOperand DAGTypeLegalizer::SplitOp_RET(SDNode *N, unsigned OpNo) { return DAG.getNode(ISD::RET, MVT::Other, Chain, Lo, Sign, Hi, Sign); } +SDOperand DAGTypeLegalizer::SplitOp_BIT_CONVERT(SDNode *N) { + // For example, i64 = BIT_CONVERT v4i16 on alpha. Typically the vector will + // end up being split all the way down to individual components. Convert the + // split pieces into integers and reassemble. + SDOperand Lo, Hi; + GetSplitOp(N->getOperand(0), Lo, Hi); + + unsigned LoBits = MVT::getSizeInBits(Lo.getValueType()); + Lo = DAG.getNode(ISD::BIT_CONVERT, MVT::getIntegerType(LoBits), Lo); + + unsigned HiBits = MVT::getSizeInBits(Hi.getValueType()); + Hi = DAG.getNode(ISD::BIT_CONVERT, MVT::getIntegerType(HiBits), Hi); + + if (TLI.isBigEndian()) + std::swap(Lo, Hi); + + assert(LoBits == HiBits && "Do not know how to assemble odd sized vectors!"); + + return DAG.getNode(ISD::BIT_CONVERT, N->getValueType(0), + DAG.getNode(ISD::BUILD_PAIR, + MVT::getIntegerType(LoBits+HiBits), Lo, Hi)); +} + +SDOperand DAGTypeLegalizer::SplitOp_EXTRACT_VECTOR_ELT(SDNode *N) { + SDOperand Vec = N->getOperand(0); + SDOperand Idx = N->getOperand(1); + MVT::ValueType VecVT = Vec.getValueType(); + + if (isa<ConstantSDNode>(Idx)) { + uint64_t IdxVal = cast<ConstantSDNode>(Idx)->getValue(); + assert(IdxVal < MVT::getVectorNumElements(VecVT) && + "Invalid vector index!"); + + SDOperand Lo, Hi; + GetSplitOp(Vec, Lo, Hi); + + uint64_t LoElts = MVT::getVectorNumElements(Lo.getValueType()); + + if (IdxVal < LoElts) + return DAG.UpdateNodeOperands(SDOperand(N, 0), Lo, Idx); + else + return DAG.UpdateNodeOperands(SDOperand(N, 0), Hi, + DAG.getConstant(IdxVal - LoElts, + Idx.getValueType())); + } + + // Store the vector to the stack and load back the required element. + SDOperand StackPtr = DAG.CreateStackTemporary(VecVT); + SDOperand Store = DAG.getStore(DAG.getEntryNode(), Vec, StackPtr, NULL, 0); + + // Add the offset to the index. + MVT::ValueType EltVT = MVT::getVectorElementType(VecVT); + unsigned EltSize = MVT::getSizeInBits(EltVT)/8; // FIXME: should be ABI size. + Idx = DAG.getNode(ISD::MUL, Idx.getValueType(), Idx, + DAG.getConstant(EltSize, Idx.getValueType())); + + if (MVT::getSizeInBits(Idx.getValueType()) > + MVT::getSizeInBits(TLI.getPointerTy())) + Idx = DAG.getNode(ISD::TRUNCATE, TLI.getPointerTy(), Idx); + else + Idx = DAG.getNode(ISD::ZERO_EXTEND, TLI.getPointerTy(), Idx); + + StackPtr = DAG.getNode(ISD::ADD, Idx.getValueType(), Idx, StackPtr); + return DAG.getLoad(EltVT, Store, StackPtr, NULL, 0); +} + SDOperand DAGTypeLegalizer::SplitOp_EXTRACT_SUBVECTOR(SDNode *N) { // We know that the extracted result type is legal. For now, assume the index // is a constant. |