Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dotnet/runtime.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSingleAccretion <62474226+SingleAccretion@users.noreply.github.com>2021-06-25 09:32:54 +0300
committerGitHub <noreply@github.com>2021-06-25 09:32:54 +0300
commitec42090f311ae3239abe61830e75bddc761fc828 (patch)
tree77bd8891d6eee118f67cf97ef6b671b18e49b4cd /src/coreclr/jit
parentb5b8863005d0d95cc470be458108b5176396a522 (diff)
Eliminate chained casts to small types (#52561)
We can take advantage of the implicit zero/sign-extension for small integer types and eliminate some casts.
Diffstat (limited to 'src/coreclr/jit')
-rw-r--r--src/coreclr/jit/morph.cpp46
1 files changed, 43 insertions, 3 deletions
diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp
index e53c2d9e8ff..946fe11cbec 100644
--- a/src/coreclr/jit/morph.cpp
+++ b/src/coreclr/jit/morph.cpp
@@ -730,14 +730,54 @@ OPTIMIZECAST:
break;
case GT_CAST:
- /* Check for two consecutive casts into the same dstType */
+ // Check for two consecutive casts into the same dstType.
+ // Also check for consecutive casts to small types.
if (!tree->gtOverflow())
{
- var_types dstType2 = oper->CastToType();
- if (dstType == dstType2)
+ var_types dstCastToType = dstType;
+ var_types srcCastToType = oper->CastToType();
+ if (dstCastToType == srcCastToType)
{
goto REMOVE_CAST;
}
+ // We can take advantage of the implicit zero/sign-extension for
+ // small integer types and eliminate some casts.
+ if (opts.OptimizationEnabled() && !oper->gtOverflow() && !gtIsActiveCSE_Candidate(oper) &&
+ varTypeIsSmall(dstCastToType) && varTypeIsSmall(srcCastToType))
+ {
+ // Gather some facts about our casts.
+ bool srcZeroExtends = varTypeIsUnsigned(srcCastToType);
+ bool dstZeroExtends = varTypeIsUnsigned(dstCastToType);
+ unsigned srcCastToSize = genTypeSize(srcCastToType);
+ unsigned dstCastToSize = genTypeSize(dstCastToType);
+
+ // If the previous cast to a smaller type was zero-extending,
+ // this cast will also always be zero-extending. Example:
+ // CAST(ubyte): 000X => CAST(short): Sign-extend(0X) => 000X.
+ if (srcZeroExtends && (dstCastToSize > srcCastToSize))
+ {
+ dstZeroExtends = true;
+ }
+
+ // Case #1: cast to a smaller or equal in size type.
+ // We can discard the intermediate cast. Examples:
+ // CAST(short): --XX => CAST(ubyte): 000X.
+ // CAST(ushort): 00XX => CAST(short): --XX.
+ if (dstCastToSize <= srcCastToSize)
+ {
+ tree->AsCast()->CastOp() = oper->AsCast()->CastOp();
+ DEBUG_DESTROY_NODE(oper);
+ }
+ // Case #2: cast to a larger type with the same effect.
+ // Here we can eliminate the outer cast. Example:
+ // CAST(byte): ---X => CAST(short): Sign-extend(-X) => ---X.
+ // Example of a sequence where this does not hold:
+ // CAST(byte): ---X => CAST(ushort): Zero-extend(-X) => 00-X.
+ else if (srcZeroExtends == dstZeroExtends)
+ {
+ goto REMOVE_CAST;
+ }
+ }
}
break;