From 00a8bf48a5e7df6e07546abd9d915d20ed6eb653 Mon Sep 17 00:00:00 2001 From: Mike Danes Date: Sun, 15 May 2016 14:04:13 +0300 Subject: [PATCH] Implement integer to long/ulong casts for x86 Commit migrated from https://github.com/dotnet/coreclr/commit/b0737c733f674f047cd23d272002a3427f26fad0 --- src/coreclr/src/jit/decomposelongs.cpp | 98 ++++++++++++++++++++++++++++------ 1 file changed, 83 insertions(+), 15 deletions(-) diff --git a/src/coreclr/src/jit/decomposelongs.cpp b/src/coreclr/src/jit/decomposelongs.cpp index 58eedc7..25eb5d1 100644 --- a/src/coreclr/src/jit/decomposelongs.cpp +++ b/src/coreclr/src/jit/decomposelongs.cpp @@ -496,32 +496,100 @@ GenTree* DecomposeLongs::DecomposeCast(LIR::Use& use) assert(use.IsInitialized()); assert(use.Def()->OperGet() == GT_CAST); - GenTree* tree = use.Def(); + GenTree* cast = use.Def()->AsCast(); GenTree* loResult = nullptr; GenTree* hiResult = nullptr; - assert(tree->gtPrev == tree->gtGetOp1()); - NYI_IF(tree->gtOverflow(), "TYP_LONG cast with overflow"); - switch (tree->AsCast()->CastFromType()) + var_types srcType = cast->CastFromType(); + var_types dstType = cast->CastToType(); + + if ((cast->gtFlags & GTF_UNSIGNED) != 0) + { + srcType = genUnsignedType(srcType); + } + + if (varTypeIsLong(srcType)) + { + if (cast->gtOverflow() && (varTypeIsUnsigned(srcType) != varTypeIsUnsigned(dstType))) + { + GenTree* srcOp = cast->gtGetOp1(); + noway_assert(srcOp->OperGet() == GT_LONG); + GenTree* loSrcOp = srcOp->gtGetOp1(); + GenTree* hiSrcOp = srcOp->gtGetOp2(); + + // + // When casting between long types an overflow check is needed only if the types + // have different signedness. In both cases (long->ulong and ulong->long) we only + // need to check if the high part is negative or not. Use the existing cast node + // to perform a int->uint cast of the high part to take advantage of the overflow + // check provided by codegen. + // + + loResult = loSrcOp; + + hiResult = cast; + hiResult->gtType = TYP_INT; + hiResult->AsCast()->gtCastType = TYP_UINT; + hiResult->gtFlags &= ~GTF_UNSIGNED; + hiResult->gtOp.gtOp1 = hiSrcOp; + + Range().Remove(cast); + Range().Remove(srcOp); + Range().InsertAfter(hiSrcOp, hiResult); + } + else + { + NYI("Unimplemented long->long no-op cast decomposition"); + } + } + else if (varTypeIsIntegralOrI(srcType)) { - case TYP_INT: - if (tree->gtFlags & GTF_UNSIGNED) + if (cast->gtOverflow() && !varTypeIsUnsigned(srcType) && varTypeIsUnsigned(dstType)) + { + // + // An overflow check is needed only when casting from a signed type to ulong. + // Change the cast type to uint to take advantage of the overflow check provided + // by codegen and then zero extend the resulting uint to ulong. + // + + loResult = cast; + loResult->AsCast()->gtCastType = TYP_UINT; + loResult->gtType = TYP_INT; + + hiResult = m_compiler->gtNewZeroConNode(TYP_INT); + + Range().InsertAfter(loResult, hiResult); + } + else + { + if (varTypeIsUnsigned(srcType)) { - loResult = tree->gtGetOp1(); - Range().Remove(tree); + loResult = cast->gtGetOp1(); + hiResult = m_compiler->gtNewZeroConNode(TYP_INT); - hiResult = new (m_compiler, GT_CNS_INT) GenTreeIntCon(TYP_INT, 0); + Range().Remove(cast); Range().InsertAfter(loResult, hiResult); } else { - NYI("Lowering of signed cast TYP_INT->TYP_LONG"); - } - break; + LIR::Use src(Range(), &(cast->gtOp.gtOp1), cast); + unsigned lclNum = src.ReplaceWithLclVar(m_compiler, m_blockWeight); - default: - NYI("Unimplemented type for Lowering of cast to TYP_LONG"); - break; + loResult = src.Def(); + + GenTree* loCopy = m_compiler->gtNewLclvNode(lclNum, TYP_INT); + GenTree* shiftBy = m_compiler->gtNewIconNode(31, TYP_INT); + hiResult = m_compiler->gtNewOperNode(GT_RSH, TYP_INT, loCopy, shiftBy); + + Range().Remove(cast); + Range().InsertAfter(loResult, loCopy, shiftBy, hiResult); + m_compiler->lvaIncRefCnts(loCopy); + } + } + } + else + { + NYI("Unimplemented cast decomposition"); } return FinalizeDecomposition(use, loResult, hiResult); -- 2.7.4