diff --git a/src/coreclr/jit/lclmorph.cpp b/src/coreclr/jit/lclmorph.cpp index 0f190907fc5233..c7cd1583816c6c 100644 --- a/src/coreclr/jit/lclmorph.cpp +++ b/src/coreclr/jit/lclmorph.cpp @@ -936,18 +936,45 @@ class LocalAddressVisitor final : public GenTreeVisitor var_types elementType = indir->TypeGet(); lclNode = indir->gtGetOp1()->BashToLclVar(m_compiler, lclNum); - if (elementType == TYP_FLOAT) + switch (elementType) { - GenTree* indexNode = m_compiler->gtNewIconNode(offset / genTypeSize(elementType)); - hwiNode = m_compiler->gtNewSimdGetElementNode(elementType, lclNode, indexNode, CORINFO_TYPE_FLOAT, - genTypeSize(varDsc)); - } - else - { - assert(elementType == TYP_SIMD12); - assert(genTypeSize(varDsc) == 16); - hwiNode = m_compiler->gtNewSimdHWIntrinsicNode(elementType, lclNode, NI_Vector128_AsVector3, - CORINFO_TYPE_FLOAT, 16); + case TYP_FLOAT: + { + GenTree* indexNode = m_compiler->gtNewIconNode(offset / genTypeSize(elementType)); + hwiNode = m_compiler->gtNewSimdGetElementNode(elementType, lclNode, indexNode, + CORINFO_TYPE_FLOAT, genTypeSize(varDsc)); + break; + } + case TYP_SIMD12: + { + assert(genTypeSize(varDsc) == 16); + hwiNode = m_compiler->gtNewSimdHWIntrinsicNode(elementType, lclNode, NI_Vector128_AsVector3, + CORINFO_TYPE_FLOAT, 16); + break; + } + case TYP_SIMD8: +#if defined(FEATURE_SIMD) && defined(TARGET_XARCH) + case TYP_SIMD16: + case TYP_SIMD32: +#endif + { + assert(genTypeSize(elementType) * 2 == genTypeSize(varDsc)); + if (offset == 0) + { + hwiNode = m_compiler->gtNewSimdGetLowerNode(elementType, lclNode, CORINFO_TYPE_FLOAT, + genTypeSize(varDsc)); + } + else + { + assert(offset == genTypeSize(elementType)); + hwiNode = m_compiler->gtNewSimdGetUpperNode(elementType, lclNode, CORINFO_TYPE_FLOAT, + genTypeSize(varDsc)); + } + + break; + } + default: + unreached(); } indir = hwiNode; @@ -962,23 +989,50 @@ class LocalAddressVisitor final : public GenTreeVisitor GenTree* simdLclNode = m_compiler->gtNewLclVarNode(lclNum); GenTree* elementNode = indir->AsIndir()->Data(); - if (elementType == TYP_FLOAT) + switch (elementType) { - GenTree* indexNode = m_compiler->gtNewIconNode(offset / genTypeSize(elementType)); - hwiNode = - m_compiler->gtNewSimdWithElementNode(varDsc->TypeGet(), simdLclNode, indexNode, elementNode, - CORINFO_TYPE_FLOAT, genTypeSize(varDsc)); - } - else - { - assert(elementType == TYP_SIMD12); - assert(varDsc->TypeGet() == TYP_SIMD16); - - // We inverse the operands here and take elementNode as the main value and simdLclNode[3] as the - // new value. This gives us a new TYP_SIMD16 with all elements in the right spots - GenTree* indexNode = m_compiler->gtNewIconNode(3, TYP_INT); - hwiNode = m_compiler->gtNewSimdWithElementNode(TYP_SIMD16, elementNode, indexNode, simdLclNode, - CORINFO_TYPE_FLOAT, 16); + case TYP_FLOAT: + { + GenTree* indexNode = m_compiler->gtNewIconNode(offset / genTypeSize(elementType)); + hwiNode = + m_compiler->gtNewSimdWithElementNode(varDsc->TypeGet(), simdLclNode, indexNode, elementNode, + CORINFO_TYPE_FLOAT, genTypeSize(varDsc)); + break; + } + case TYP_SIMD12: + { + assert(varDsc->TypeGet() == TYP_SIMD16); + + // We inverse the operands here and take elementNode as the main value and simdLclNode[3] as the + // new value. This gives us a new TYP_SIMD16 with all elements in the right spots + GenTree* indexNode = m_compiler->gtNewIconNode(3, TYP_INT); + hwiNode = m_compiler->gtNewSimdWithElementNode(TYP_SIMD16, elementNode, indexNode, simdLclNode, + CORINFO_TYPE_FLOAT, 16); + break; + } + case TYP_SIMD8: +#if defined(FEATURE_SIMD) && defined(TARGET_XARCH) + case TYP_SIMD16: + case TYP_SIMD32: +#endif + { + assert(genTypeSize(elementType) * 2 == genTypeSize(varDsc)); + if (offset == 0) + { + hwiNode = m_compiler->gtNewSimdWithLowerNode(varDsc->TypeGet(), simdLclNode, elementNode, + CORINFO_TYPE_FLOAT, genTypeSize(varDsc)); + } + else + { + assert(offset == genTypeSize(elementType)); + hwiNode = m_compiler->gtNewSimdWithUpperNode(varDsc->TypeGet(), simdLclNode, elementNode, + CORINFO_TYPE_FLOAT, genTypeSize(varDsc)); + } + + break; + } + default: + unreached(); } indir->ChangeType(varDsc->TypeGet()); @@ -1112,9 +1166,10 @@ class LocalAddressVisitor final : public GenTreeVisitor #ifdef FEATURE_HW_INTRINSICS if (varTypeIsSIMD(varDsc)) { - // We have two cases we want to handle: + // We have three cases we want to handle: // 1. Vector2/3/4 and Quaternion where we have 4x float fields // 2. Plane where we have 1x Vector3 and 1x float field + // 3. Accesses of halves of larger SIMD types if (indir->TypeIs(TYP_FLOAT)) { @@ -1125,11 +1180,27 @@ class LocalAddressVisitor final : public GenTreeVisitor } else if (indir->TypeIs(TYP_SIMD12)) { - if ((offset == 0) && m_compiler->IsBaselineSimdIsaSupported()) + if ((offset == 0) && (varDsc->TypeGet() == TYP_SIMD16) && m_compiler->IsBaselineSimdIsaSupported()) { return isDef ? IndirTransform::WithElement : IndirTransform::GetElement; } } +#ifdef TARGET_ARM64 + else if (indir->TypeIs(TYP_SIMD8)) + { + if ((varDsc->TypeGet() == TYP_SIMD16) && ((offset % 8) == 0)) + { + return isDef ? IndirTransform::WithElement : IndirTransform::GetElement; + } + } +#endif +#if defined(FEATURE_SIMD) && defined(TARGET_XARCH) + else if (indir->TypeIs(TYP_SIMD16, TYP_SIMD32) && (genTypeSize(indir) * 2 == genTypeSize(varDsc)) && + ((offset % genTypeSize(indir)) == 0)) + { + return isDef ? IndirTransform::WithElement : IndirTransform::GetElement; + } +#endif // FEATURE_SIMD && TARGET_XARCH } #endif // FEATURE_HW_INTRINSICS diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_89456/Runtime_89456.cs b/src/tests/JIT/Regression/JitBlue/Runtime_89456/Runtime_89456.cs new file mode 100644 index 00000000000000..252aa0840c4806 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_89456/Runtime_89456.cs @@ -0,0 +1,36 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +using Xunit; + +public class Runtime_89456 +{ + [MethodImpl(MethodImplOptions.NoInlining)] + private static Vector3 Reinterp128(Vector128 v) + { + return Unsafe.As, Vector3>(ref v); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static Vector3 Reinterp256(Vector256 v) + { + return Unsafe.As, Vector3>(ref v); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static Vector3 Reinterp512(Vector512 v) + { + return Unsafe.As, Vector3>(ref v); + } + + [Fact] + public static void TestEntryPoint() + { + Reinterp128(default); + Reinterp256(default); + Reinterp512(default); + } +} diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_89456/Runtime_89456.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_89456/Runtime_89456.csproj new file mode 100644 index 00000000000000..de6d5e08882e86 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_89456/Runtime_89456.csproj @@ -0,0 +1,8 @@ + + + True + + + + +