Skip to content

Commit 8017079

Browse files
authored
JIT: Fix small->float casts with AVX-512 (#112892)
1 parent c7a2924 commit 8017079

File tree

4 files changed

+40
-52
lines changed

4 files changed

+40
-52
lines changed

src/coreclr/jit/codegenxarch.cpp

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7287,7 +7287,7 @@ void CodeGen::genIntToFloatCast(GenTree* treeNode)
72877287
#endif
72887288

72897289
var_types dstType = treeNode->CastToType();
7290-
var_types srcType = op1->TypeGet();
7290+
var_types srcType = genActualType(op1->TypeGet());
72917291
assert(!varTypeIsFloating(srcType) && varTypeIsFloating(dstType));
72927292

72937293
// Since xarch emitter doesn't handle reporting gc-info correctly while casting away gc-ness we
@@ -7302,15 +7302,6 @@ void CodeGen::genIntToFloatCast(GenTree* treeNode)
73027302
srcType = TYP_I_IMPL;
73037303
}
73047304

7305-
// At this point, we should not see a srcType that is not int or long.
7306-
// For conversions from byte/sbyte/int16/uint16 to float/double, we would expect
7307-
// either the front-end or lowering phase to have generated two levels of cast.
7308-
// The first one is for widening smaller int type to int32 and the second one is
7309-
// to the float/double.
7310-
// On 32-bit, we expect morph to replace long to float/double casts with helper calls,
7311-
// so we should only see int here.
7312-
noway_assert(varTypeIsIntOrI(srcType));
7313-
73147305
// To convert integral type to floating, the cvt[u]si2ss/sd instruction is used
73157306
// which does a partial write to lower 4/8 bytes of xmm register keeping the other
73167307
// upper bytes unmodified. If "cvt[u]si2ss/sd xmmReg, r32/r64" occurs inside a loop,

src/coreclr/jit/lowerxarch.cpp

Lines changed: 8 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -823,7 +823,6 @@ GenTree* Lowering::LowerCast(GenTree* tree)
823823
var_types castToType = tree->CastToType();
824824
var_types dstType = castToType;
825825
var_types srcType = castOp->TypeGet();
826-
var_types tmpType = TYP_UNDEF;
827826

828827
// force the srcType to unsigned if GT_UNSIGNED flag is set
829828
if (tree->IsUnsigned())
@@ -837,11 +836,14 @@ GenTree* Lowering::LowerCast(GenTree* tree)
837836
// Reason: must be converted to a helper call
838837
// srcType = float/double, castToType = ulong
839838
// Reason: must be converted to a helper call
839+
// srcType = float/double, castToType = byte/sbyte/ushort/short
840+
// Reason: must have intermediate cast to int
840841
// srcType = uint castToType = float/double
841842
// Reason: uint -> float/double = uint -> long -> float/double
842843
if (varTypeIsFloating(srcType))
843844
{
844845
noway_assert(!tree->gtOverflow());
846+
assert(!varTypeIsSmall(dstType));
845847
assert(castToType != TYP_ULONG || comp->canUseEvexEncodingDebugOnly());
846848
}
847849
else if (srcType == TYP_UINT)
@@ -1164,30 +1166,6 @@ GenTree* Lowering::LowerCast(GenTree* tree)
11641166
}
11651167
#endif // TARGET_AMD64
11661168

1167-
// Case of src is a small type and dst is a floating point type.
1168-
if (varTypeIsSmall(srcType) && varTypeIsFloating(castToType))
1169-
{
1170-
// These conversions can never be overflow detecting ones.
1171-
noway_assert(!tree->gtOverflow());
1172-
tmpType = TYP_INT;
1173-
}
1174-
// case of src is a floating point type and dst is a small type.
1175-
else if (varTypeIsFloating(srcType) && varTypeIsSmall(castToType))
1176-
{
1177-
tmpType = TYP_INT;
1178-
}
1179-
1180-
if (tmpType != TYP_UNDEF)
1181-
{
1182-
GenTree* tmp = comp->gtNewCastNode(tmpType, castOp, tree->IsUnsigned(), tmpType);
1183-
tmp->gtFlags |= (tree->gtFlags & (GTF_OVERFLOW | GTF_EXCEPT));
1184-
1185-
tree->gtFlags &= ~GTF_UNSIGNED;
1186-
tree->AsOp()->gtOp1 = tmp;
1187-
BlockRange().InsertAfter(castOp, tmp);
1188-
ContainCheckCast(tmp->AsCast());
1189-
}
1190-
11911169
// Now determine if we have operands that should be contained.
11921170
ContainCheckCast(tree->AsCast());
11931171
return nullptr;
@@ -8567,26 +8545,14 @@ void Lowering::ContainCheckCast(GenTreeCast* node)
85678545

85688546
if (varTypeIsFloating(castToType) || varTypeIsFloating(srcType))
85698547
{
8570-
#ifdef DEBUG
8571-
// If converting to float/double, the operand must be 4 or 8 byte in size.
8572-
if (varTypeIsFloating(castToType))
8548+
if (castOp->IsCnsNonZeroFltOrDbl())
85738549
{
8574-
unsigned opSize = genTypeSize(srcType);
8575-
assert(opSize == 4 || opSize == 8);
8550+
MakeSrcContained(node, castOp);
85768551
}
8577-
#endif // DEBUG
8578-
8579-
// U8 -> R8 conversion requires that the operand be in a register.
8580-
if (srcType != TYP_ULONG)
8552+
else
85818553
{
8582-
if (castOp->IsCnsNonZeroFltOrDbl())
8583-
{
8584-
MakeSrcContained(node, castOp);
8585-
}
8586-
else
8587-
{
8588-
srcIsContainable = true;
8589-
}
8554+
// The ulong->floating SSE2 fallback requires the source to be in register
8555+
srcIsContainable = !varTypeIsSmall(srcType) && ((srcType != TYP_ULONG) || comp->canUseEvexEncoding());
85908556
}
85918557
}
85928558
else if (comp->opts.OptimizationEnabled() && varTypeIsIntegral(castOp) && varTypeIsIntegral(castToType))
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
// Generated by Fuzzlyn v2.4 on 2025-02-23 17:30:17
5+
// Run on X64 Windows
6+
// Seed: 18098778274409643257-vectort,vector128,vector256,x86aes,x86avx,x86avx2,x86avx512bw,x86avx512bwvl,x86avx512cd,x86avx512cdvl,x86avx512dq,x86avx512dqvl,x86avx512f,x86avx512fvl,x86avx512fx64,x86bmi1,x86bmi1x64,x86bmi2,x86bmi2x64,x86fma,x86lzcnt,x86lzcntx64,x86pclmulqdq,x86popcnt,x86popcntx64,x86sse,x86ssex64,x86sse2,x86sse2x64,x86sse3,x86sse41,x86sse41x64,x86sse42,x86sse42x64,x86ssse3,x86x86base
7+
// Reduced from 23.4 KiB to 0.4 KiB in 00:01:16
8+
9+
using System;
10+
using Xunit;
11+
12+
public class Runtime_112871
13+
{
14+
public static short s_1;
15+
16+
[Fact]
17+
public static void Problem()
18+
{
19+
ushort vr0 = default(ushort);
20+
s_1 = -1;
21+
Assert.True((double)0 <= (uint)s_1);
22+
}
23+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<Optimize>False</Optimize>
4+
</PropertyGroup>
5+
<ItemGroup>
6+
<Compile Include="$(MSBuildProjectName).cs" />
7+
</ItemGroup>
8+
</Project>

0 commit comments

Comments
 (0)