return isOpaqueSIMDType(varDsc->lvVerTypeInfo.GetClassHandle());
}
- // Returns true if the type of the tree is a byref of TYP_SIMD
- bool isAddrOfSIMDType(GenTree* tree)
- {
- if (tree->TypeGet() == TYP_BYREF || tree->TypeGet() == TYP_I_IMPL)
- {
- switch (tree->OperGet())
- {
- case GT_ADDR:
- return varTypeIsSIMD(tree->gtGetOp1());
-
- case GT_LCL_VAR_ADDR:
- return lvaTable[tree->AsLclVarCommon()->GetLclNum()].lvSIMDType;
-
- default:
- return isSIMDTypeLocal(tree);
- }
- }
-
- return false;
- }
-
static bool isRelOpSIMDIntrinsic(SIMDIntrinsicID intrinsicId)
{
return (intrinsicId == SIMDIntrinsicEqual || intrinsicId == SIMDIntrinsicLessThan ||
}
}
-// return op that is the load equivalent of the given addr opcode
-genTreeOps loadForm(genTreeOps addrForm)
-{
- switch (addrForm)
- {
- case GT_LCL_VAR_ADDR:
- return GT_LCL_VAR;
- case GT_LCL_FLD_ADDR:
- return GT_LCL_FLD;
- default:
- noway_assert(!"not a local address opcode\n");
- unreached();
- }
-}
-
// copy the flags determined by mask from src to dst
void copyFlags(GenTree* dst, GenTree* src, unsigned mask)
{
return;
}
- // If we have GT_IND(GT_LCL_VAR_ADDR) and the GT_LCL_VAR_ADDR is TYP_BYREF/TYP_I_IMPL,
- // and the var is a SIMD type, replace the expression by GT_LCL_VAR.
+ // If we have GT_IND(GT_LCL_VAR_ADDR) and the var is a SIMD type,
+ // replace the expression by GT_LCL_VAR or GT_LCL_FLD.
GenTree* addr = tree->AsIndir()->Addr();
- if (addr->OperIsLocalAddr() && comp->isAddrOfSIMDType(addr))
+ if (addr->OperIs(GT_LCL_VAR_ADDR) && comp->lvaGetDesc(addr->AsLclVar())->lvSIMDType)
{
BlockRange().Remove(tree);
- addr->SetOper(loadForm(addr->OperGet()));
+ var_types lclType = comp->lvaGetDesc(addr->AsLclVar())->TypeGet();
+
+ if (lclType == simdType)
+ {
+ addr->SetOper(GT_LCL_VAR);
+ }
+ else
+ {
+ addr->SetOper(GT_LCL_FLD);
+ addr->AsLclFld()->gtLclOffs = 0;
+ addr->AsLclFld()->gtFieldSeq = FieldSeqStore::NotAField();
+
+ if (((addr->gtFlags & GTF_VAR_DEF) != 0) && (genTypeSize(simdType) < genTypeSize(lclType)))
+ {
+ addr->gtFlags |= GTF_VAR_USEASG;
+ }
+
+ comp->lvaSetVarDoNotEnregister(addr->AsLclFld()->GetLclNum() DEBUGARG(Compiler::DNER_LocalField));
+ }
+
addr->gtType = simdType;
use.ReplaceWith(comp, addr);
}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Numerics;
+using System.Runtime.CompilerServices;
+
+class Program
+{
+ static int Main()
+ {
+ Vector3 v3 = Test1(new Vector4(1, 2, 3, 4));
+ if (v3.X != 1 || v3.Y != 2 || v3.Z != 3)
+ {
+ return 42;
+ }
+
+ Vector4 v4 = Test2(new Vector4(1, 2, 3, 4), new Vector4(2, 1, 4, 3));
+ if (v4.X != 3 || v4.Y != 6 || v4.Z != 21 || v4.W != 0)
+ {
+ return 43;
+ }
+
+ return 100;
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
+ public static Vector3 Test1(Vector4 value)
+ {
+ return Unsafe.As<Vector4, Vector3>(ref value);
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
+ static Vector4 Test2(Vector4 a, Vector4 b)
+ {
+ Vector4 c = a + b;
+ Vector3 d = Unsafe.As<Vector4, Vector3>(ref c);
+ return a * new Vector4(d, 0);
+ }
+}
--- /dev/null
+<Project Sdk="Microsoft.NET.Sdk">
+ <PropertyGroup>
+ <OutputType>Exe</OutputType>
+ </PropertyGroup>
+ <PropertyGroup>
+ <DebugType>None</DebugType>
+ <Optimize>True</Optimize>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="$(MSBuildProjectName).cs" />
+ </ItemGroup>
+</Project>