diff options
author | Jiyoung Yun <jy910.yun@samsung.com> | 2017-02-10 20:35:12 +0900 |
---|---|---|
committer | Jiyoung Yun <jy910.yun@samsung.com> | 2017-02-10 20:35:12 +0900 |
commit | 4b11dc566a5bbfa1378d6266525c281b028abcc8 (patch) | |
tree | b48831a898906734f8884d08b6e18f1144ee2b82 /src/jit/decomposelongs.cpp | |
parent | db20f3f1bb8595633a7e16c8900fd401a453a6b5 (diff) | |
download | coreclr-4b11dc566a5bbfa1378d6266525c281b028abcc8.tar.gz coreclr-4b11dc566a5bbfa1378d6266525c281b028abcc8.tar.bz2 coreclr-4b11dc566a5bbfa1378d6266525c281b028abcc8.zip |
Imported Upstream version 1.0.0.9910upstream/1.0.0.9910
Diffstat (limited to 'src/jit/decomposelongs.cpp')
-rw-r--r-- | src/jit/decomposelongs.cpp | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/src/jit/decomposelongs.cpp b/src/jit/decomposelongs.cpp index 98b8b081fc..407ae1c35b 100644 --- a/src/jit/decomposelongs.cpp +++ b/src/jit/decomposelongs.cpp @@ -249,6 +249,12 @@ GenTree* DecomposeLongs::DecomposeNode(GenTree* tree) nextNode = DecomposeRotate(use); break; +#ifdef FEATURE_SIMD + case GT_SIMD: + nextNode = DecomposeSimd(use); + break; +#endif // FEATURE_SIMD + case GT_LOCKADD: case GT_XADD: case GT_XCHG: @@ -411,6 +417,8 @@ GenTree* DecomposeLongs::DecomposeLclFld(LIR::Use& use) GenTree* hiResult = m_compiler->gtNewLclFldNode(loResult->gtLclNum, TYP_INT, loResult->gtLclOffs + 4); Range().InsertAfter(loResult, hiResult); + m_compiler->lvaIncRefCnts(hiResult); + return FinalizeDecomposition(use, loResult, hiResult, hiResult); } @@ -1560,6 +1568,163 @@ GenTree* DecomposeLongs::DecomposeUMod(LIR::Use& use) return FinalizeDecomposition(use, loResult, hiResult, hiResult); } +#ifdef FEATURE_SIMD + +//------------------------------------------------------------------------ +// DecomposeSimd: Decompose GT_SIMD. +// +// Arguments: +// use - the LIR::Use object for the def that needs to be decomposed. +// +// Return Value: +// The next node to process. +// +GenTree* DecomposeLongs::DecomposeSimd(LIR::Use& use) +{ + GenTree* tree = use.Def(); + genTreeOps oper = tree->OperGet(); + + assert(oper == GT_SIMD); + + GenTreeSIMD* simdTree = tree->AsSIMD(); + + switch (simdTree->gtSIMDIntrinsicID) + { + case SIMDIntrinsicGetItem: + return DecomposeSimdGetItem(use); + + default: + noway_assert(!"unexpected GT_SIMD node in long decomposition"); + break; + } + + return nullptr; +} + +//------------------------------------------------------------------------ +// DecomposeSimdGetItem: Decompose GT_SIMD -- SIMDIntrinsicGetItem. +// +// Decompose a get[i] node on Vector<long>. For: +// +// GT_SIMD{get_item}[long](simd_var, index) +// +// create: +// +// tmp_simd_var = simd_var +// tmp_index = index +// loResult = GT_SIMD{get_item}[int](tmp_simd_var, tmp_index * 2) +// hiResult = GT_SIMD{get_item}[int](tmp_simd_var, tmp_index * 2 + 1) +// return: GT_LONG(loResult, hiResult) +// +// This isn't optimal codegen, since SIMDIntrinsicGetItem sometimes requires +// temps that could be shared, for example. +// +// Arguments: +// use - the LIR::Use object for the def that needs to be decomposed. +// +// Return Value: +// The next node to process. +// +GenTree* DecomposeLongs::DecomposeSimdGetItem(LIR::Use& use) +{ + GenTree* tree = use.Def(); + genTreeOps oper = tree->OperGet(); + + assert(oper == GT_SIMD); + + GenTreeSIMD* simdTree = tree->AsSIMD(); + var_types baseType = simdTree->gtSIMDBaseType; + unsigned simdSize = simdTree->gtSIMDSize; + + assert(simdTree->gtSIMDIntrinsicID == SIMDIntrinsicGetItem); + assert(varTypeIsLong(baseType)); + assert(varTypeIsLong(simdTree)); + assert(varTypeIsSIMD(simdTree->gtOp.gtOp1->gtType)); + assert(simdTree->gtOp.gtOp2->gtType == TYP_INT); + + bool indexIsConst = simdTree->gtOp.gtOp2->IsCnsIntOrI(); + ssize_t index = 0; + if (indexIsConst) + { + index = simdTree->gtOp.gtOp2->gtIntCon.gtIconVal; + } + + LIR::Use op1(Range(), &simdTree->gtOp.gtOp1, simdTree); + unsigned simdTmpVarNum = op1.ReplaceWithLclVar(m_compiler, m_blockWeight); + JITDUMP("[DecomposeSimdGetItem]: Saving op1 tree to a temp var:\n"); + DISPTREERANGE(Range(), op1.Def()); + + unsigned indexTmpVarNum = 0; + if (!indexIsConst) + { + LIR::Use op2(Range(), &simdTree->gtOp.gtOp2, simdTree); + indexTmpVarNum = op2.ReplaceWithLclVar(m_compiler, m_blockWeight); + JITDUMP("[DecomposeSimdGetItem]: Saving op2 tree to a temp var:\n"); + DISPTREERANGE(Range(), op2.Def()); + } + + // Create: + // loResult = GT_SIMD{get_item}[int](tmp_simd_var, index * 2) + + GenTree* simdTmpVar1 = m_compiler->gtNewLclLNode(simdTmpVarNum, simdTree->gtOp.gtOp1->gtType); + GenTree* indexTimesTwo1; + + if (indexIsConst) + { + // Reuse the existing index constant node. + indexTimesTwo1 = simdTree->gtOp.gtOp2; + Range().Remove(indexTimesTwo1); + indexTimesTwo1->gtIntCon.gtIconVal = index * 2; + + Range().InsertBefore(simdTree, simdTmpVar1, indexTimesTwo1); + } + else + { + GenTree* indexTmpVar1 = m_compiler->gtNewLclLNode(indexTmpVarNum, TYP_INT); + GenTree* two1 = m_compiler->gtNewIconNode(2, TYP_INT); + indexTimesTwo1 = m_compiler->gtNewOperNode(GT_MUL, TYP_INT, indexTmpVar1, two1); + Range().InsertBefore(simdTree, simdTmpVar1, indexTmpVar1, two1, indexTimesTwo1); + } + + GenTree* loResult = + m_compiler->gtNewSIMDNode(TYP_INT, simdTmpVar1, indexTimesTwo1, SIMDIntrinsicGetItem, TYP_INT, simdSize); + Range().InsertBefore(simdTree, loResult); + + // Create: + // hiResult = GT_SIMD{get_item}[int](tmp_simd_var, index * 2 + 1) + + GenTree* simdTmpVar2 = m_compiler->gtNewLclLNode(simdTmpVarNum, simdTree->gtOp.gtOp1->gtType); + GenTree* indexTimesTwoPlusOne; + + if (indexIsConst) + { + indexTimesTwoPlusOne = m_compiler->gtNewIconNode(index * 2 + 1, TYP_INT); + Range().InsertBefore(simdTree, simdTmpVar2, indexTimesTwoPlusOne); + } + else + { + GenTree* indexTmpVar2 = m_compiler->gtNewLclLNode(indexTmpVarNum, TYP_INT); + GenTree* two2 = m_compiler->gtNewIconNode(2, TYP_INT); + GenTree* indexTimesTwo2 = m_compiler->gtNewOperNode(GT_MUL, TYP_INT, indexTmpVar2, two2); + GenTree* one = m_compiler->gtNewIconNode(1, TYP_INT); + indexTimesTwoPlusOne = m_compiler->gtNewOperNode(GT_ADD, TYP_INT, indexTimesTwo2, one); + Range().InsertBefore(simdTree, simdTmpVar2, indexTmpVar2, two2, indexTimesTwo2); + Range().InsertBefore(simdTree, one, indexTimesTwoPlusOne); + } + + GenTree* hiResult = + m_compiler->gtNewSIMDNode(TYP_INT, simdTmpVar2, indexTimesTwoPlusOne, SIMDIntrinsicGetItem, TYP_INT, simdSize); + Range().InsertBefore(simdTree, hiResult); + + // Done with the original tree; remove it. + + Range().Remove(simdTree); + + return FinalizeDecomposition(use, loResult, hiResult, hiResult); +} + +#endif // FEATURE_SIMD + //------------------------------------------------------------------------ // StoreNodeToVar: Check if the user is a STORE_LCL_VAR, and if it isn't, // store the node to a var. Then decompose the new LclVar. |