From dd41c5e15eb809e671888369d0cb043e9c7fd9a4 Mon Sep 17 00:00:00 2001 From: Mike Danes Date: Sat, 7 Jan 2017 11:13:23 +0200 Subject: [PATCH] Improve int->long cast decomposition If the cast is used by a GT_MUL then don't decompose it. This avoids producing dead code that's more difficult to remove later. Commit migrated from https://github.com/dotnet/coreclr/commit/fb4447a69646dd7e1f492aa543c9485f0ee9b5b9 --- src/coreclr/src/jit/decomposelongs.cpp | 37 +++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/src/coreclr/src/jit/decomposelongs.cpp b/src/coreclr/src/jit/decomposelongs.cpp index 2716631..beb193f 100644 --- a/src/coreclr/src/jit/decomposelongs.cpp +++ b/src/coreclr/src/jit/decomposelongs.cpp @@ -574,6 +574,8 @@ GenTree* DecomposeLongs::DecomposeCast(LIR::Use& use) srcType = genUnsignedType(srcType); } + bool skipDecomposition = false; + if (varTypeIsLong(srcType)) { if (cast->gtOverflow() && (varTypeIsUnsigned(srcType) != varTypeIsUnsigned(dstType))) @@ -628,7 +630,20 @@ GenTree* DecomposeLongs::DecomposeCast(LIR::Use& use) } else { - if (varTypeIsUnsigned(srcType)) + if (!use.IsDummyUse() && (use.User()->OperGet() == GT_MUL)) + { + // + // This int->long cast is used by a GT_MUL that will be transformed by DecomposeMul into a + // GT_LONG_MUL and as a result the high operand produced by the cast will become dead. + // Skip cast decomposition so DecomposeMul doesn't need to bother with dead code removal, + // especially in the case of sign extending casts that also introduce new lclvars. + // + + assert((use.User()->gtFlags & GTF_MUL_64RSLT) != 0); + + skipDecomposition = true; + } + else if (varTypeIsUnsigned(srcType)) { loResult = cast->gtGetOp1(); hiResult = m_compiler->gtNewZeroConNode(TYP_INT); @@ -658,6 +673,11 @@ GenTree* DecomposeLongs::DecomposeCast(LIR::Use& use) NYI("Unimplemented cast decomposition"); } + if (skipDecomposition) + { + return cast->gtNext; + } + return FinalizeDecomposition(use, loResult, hiResult, hiResult); } @@ -1480,19 +1500,16 @@ GenTree* DecomposeLongs::DecomposeMul(LIR::Use& use) GenTree* op1 = tree->gtGetOp1(); GenTree* op2 = tree->gtGetOp2(); - GenTree* loOp1 = op1->gtGetOp1(); - GenTree* hiOp1 = op1->gtGetOp2(); - GenTree* loOp2 = op2->gtGetOp1(); - GenTree* hiOp2 = op2->gtGetOp2(); + // We expect both operands to be int->long casts. DecomposeCast specifically + // ignores such casts when they are used by GT_MULs. + assert((op1->OperGet() == GT_CAST) && (op1->TypeGet() == TYP_LONG)); + assert((op2->OperGet() == GT_CAST) && (op2->TypeGet() == TYP_LONG)); - Range().Remove(hiOp1); - Range().Remove(hiOp2); Range().Remove(op1); Range().Remove(op2); - // Get rid of the hi ops. We don't need them. - tree->gtOp.gtOp1 = loOp1; - tree->gtOp.gtOp2 = loOp2; + tree->gtOp.gtOp1 = op1->gtGetOp1(); + tree->gtOp.gtOp2 = op2->gtGetOp1(); tree->SetOperRaw(GT_MUL_LONG); return StoreNodeToVar(use); -- 2.7.4