diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index b6e1f808ea9094..57153284d5bcda 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -258,17 +258,26 @@ GenTree* Compiler::fgMorphCast(GenTree* tree) } #endif //! TARGET_64BIT +#ifdef TARGET_ARMARCH + // AArch, unlike x86/amd64, has instructions that can cast directly from + // all integers (except for longs on AArch32 of course) to floats. + // Because there is no IL instruction conv.r4.un, uint/ulong -> float + // casts are always imported as CAST(float <- CAST(double <- uint/ulong)). + // We can eliminate the redundant intermediate cast as an optimization. + else if ((dstType == TYP_FLOAT) && (srcType == TYP_DOUBLE) && oper->OperIs(GT_CAST) #ifdef TARGET_ARM - else if ((dstType == TYP_FLOAT) && (srcType == TYP_DOUBLE) && (oper->gtOper == GT_CAST) && - !varTypeIsLong(oper->AsCast()->CastOp())) + && !varTypeIsLong(oper->AsCast()->CastOp()) +#endif + ) { - // optimization: conv.r4(conv.r8(?)) -> conv.r4(d) - // except when the ultimate source is a long because there is no long-to-float helper, so it must be 2 step. - // This happens semi-frequently because there is no IL 'conv.r4.un' oper->gtType = TYP_FLOAT; oper->CastToType() = TYP_FLOAT; + return fgMorphTree(oper); } +#endif // TARGET_ARMARCH + +#ifdef TARGET_ARM // converts long/ulong --> float/double casts into helper calls. else if (varTypeIsFloating(dstType) && varTypeIsLong(srcType)) {