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/LegalizeTypesPromote.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/LegalizeTypesPromote.cpp')
-rw-r--r-- | lib/CodeGen/SelectionDAG/LegalizeTypesPromote.cpp | 111 |
1 files changed, 110 insertions, 1 deletions
diff --git a/lib/CodeGen/SelectionDAG/LegalizeTypesPromote.cpp b/lib/CodeGen/SelectionDAG/LegalizeTypesPromote.cpp index c4eb059380..f3232fc914 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeTypesPromote.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeTypesPromote.cpp @@ -50,6 +50,7 @@ void DAGTypeLegalizer::PromoteResult(SDNode *N, unsigned ResNo) { case ISD::SETCC: Result = PromoteResult_SETCC(N); break; case ISD::LOAD: Result = PromoteResult_LOAD(cast<LoadSDNode>(N)); break; case ISD::BUILD_PAIR: Result = PromoteResult_BUILD_PAIR(N); break; + case ISD::BIT_CONVERT: Result = PromoteResult_BIT_CONVERT(N); break; case ISD::AND: case ISD::OR: @@ -74,8 +75,12 @@ void DAGTypeLegalizer::PromoteResult(SDNode *N, unsigned ResNo) { case ISD::CTLZ: Result = PromoteResult_CTLZ(N); break; case ISD::CTPOP: Result = PromoteResult_CTPOP(N); break; case ISD::CTTZ: Result = PromoteResult_CTTZ(N); break; + + case ISD::EXTRACT_VECTOR_ELT: + Result = PromoteResult_EXTRACT_VECTOR_ELT(N); + break; } - + // If Result is null, the sub-method took care of registering the result. if (Result.Val) SetPromotedOp(SDOperand(N, ResNo), Result); @@ -214,6 +219,65 @@ SDOperand DAGTypeLegalizer::PromoteResult_BUILD_PAIR(SDNode *N) { return DAG.getNode(ISD::OR, NVT, Lo, Hi); } +SDOperand DAGTypeLegalizer::PromoteResult_BIT_CONVERT(SDNode *N) { + SDOperand InOp = N->getOperand(0); + MVT::ValueType InVT = InOp.getValueType(); + MVT::ValueType NInVT = TLI.getTypeToTransformTo(InVT); + MVT::ValueType OutVT = TLI.getTypeToTransformTo(N->getValueType(0)); + + switch (getTypeAction(InVT)) { + default: + assert(false && "Unknown type action!"); + break; + case Legal: + break; + case Promote: + if (MVT::getSizeInBits(OutVT) == MVT::getSizeInBits(NInVT)) + // The input promotes to the same size. Convert the promoted value. + return DAG.getNode(ISD::BIT_CONVERT, OutVT, GetPromotedOp(InOp)); + break; + case Expand: + break; + case Scalarize: + // Convert the element to an integer and promote it by hand. + InOp = DAG.getNode(ISD::BIT_CONVERT, + MVT::getIntegerType(MVT::getSizeInBits(InVT)), + GetScalarizedOp(InOp)); + InOp = DAG.getNode(ISD::ANY_EXTEND, + MVT::getIntegerType(MVT::getSizeInBits(OutVT)), InOp); + return DAG.getNode(ISD::BIT_CONVERT, OutVT, InOp); + case Split: + // For example, i32 = BIT_CONVERT v2i16 on alpha. Convert the split + // pieces of the input into integers and reassemble in the final type. + 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); + + MVT::ValueType TargetTy = MVT::getIntegerType(MVT::getSizeInBits(OutVT)); + Hi = DAG.getNode(ISD::ANY_EXTEND, TargetTy, Hi); + Hi = DAG.getNode(ISD::SHL, TargetTy, Hi, + DAG.getConstant(MVT::getSizeInBits(Lo.getValueType()), + TLI.getShiftAmountTy())); + Lo = DAG.getNode(ISD::ZERO_EXTEND, TargetTy, Lo); + + return DAG.getNode(ISD::BIT_CONVERT, OutVT, + DAG.getNode(ISD::OR, TargetTy, Lo, Hi)); + } + + // Otherwise, lower the bit-convert to a store/load from the stack, then + // promote the load. + SDOperand Op = CreateStackStoreLoad(InOp, N->getValueType(0)); + return PromoteResult_LOAD(cast<LoadSDNode>(Op.Val)); +} + SDOperand DAGTypeLegalizer::PromoteResult_SimpleIntBinOp(SDNode *N) { // The input may have strange things in the top bits of the registers, but // these operations don't care. They may have weird bits going out, but @@ -315,6 +379,51 @@ SDOperand DAGTypeLegalizer::PromoteResult_CTTZ(SDNode *N) { return DAG.getNode(ISD::CTTZ, NVT, Op); } +SDOperand DAGTypeLegalizer::PromoteResult_EXTRACT_VECTOR_ELT(SDNode *N) { + MVT::ValueType OldVT = N->getValueType(0); + SDOperand OldVec = N->getOperand(0); + unsigned OldElts = MVT::getVectorNumElements(OldVec.getValueType()); + + if (OldElts == 1) { + assert(!isTypeLegal(OldVec.getValueType()) && + "Legal one-element vector of a type needing promotion!"); + // It is tempting to follow GetScalarizedOp by a call to GetPromotedOp, + // but this would be wrong because the scalarized value may not yet have + // been processed. + return DAG.getNode(ISD::ANY_EXTEND, TLI.getTypeToTransformTo(OldVT), + GetScalarizedOp(OldVec)); + } + + // Convert to a vector half as long with an element type of twice the width, + // for example <4 x i16> -> <2 x i32>. + assert(!(OldElts & 1) && "Odd length vectors not supported!"); + MVT::ValueType NewVT = MVT::getIntegerType(2 * MVT::getSizeInBits(OldVT)); + assert(!MVT::isExtendedVT(OldVT) && !MVT::isExtendedVT(NewVT)); + + SDOperand NewVec = DAG.getNode(ISD::BIT_CONVERT, + MVT::getVectorType(NewVT, OldElts / 2), + OldVec); + + // Extract the element at OldIdx / 2 from the new vector. + SDOperand OldIdx = N->getOperand(1); + SDOperand NewIdx = DAG.getNode(ISD::SRL, OldIdx.getValueType(), OldIdx, + DAG.getConstant(1, TLI.getShiftAmountTy())); + SDOperand Elt = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, NewVT, NewVec, NewIdx); + + // Select the appropriate half of the element: Lo if OldIdx was even, + // Hi if it was odd. + SDOperand Lo = Elt; + SDOperand Hi = DAG.getNode(ISD::SRL, NewVT, Elt, + DAG.getConstant(MVT::getSizeInBits(OldVT), + TLI.getShiftAmountTy())); + if (TLI.isBigEndian()) + std::swap(Lo, Hi); + + SDOperand Odd = DAG.getNode(ISD::AND, OldIdx.getValueType(), OldIdx, + DAG.getConstant(1, TLI.getShiftAmountTy())); + return DAG.getNode(ISD::SELECT, NewVT, Odd, Hi, Lo); +} + //===----------------------------------------------------------------------===// // Operand Promotion //===----------------------------------------------------------------------===// |