diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index d7ebb305c99124..e16467b3ed4a37 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -2303,9 +2303,10 @@ class Compiler void gtBlockOpInit(GenTree* result, GenTree* dst, GenTree* srcOrFillVal, bool isVolatile); public: + GenTreeObj* gtNewObjNode(ClassLayout* layout, GenTree* addr); GenTreeObj* gtNewObjNode(CORINFO_CLASS_HANDLE structHnd, GenTree* addr); void gtSetObjGcInfo(GenTreeObj* objNode); - GenTree* gtNewStructVal(CORINFO_CLASS_HANDLE structHnd, GenTree* addr); + GenTree* gtNewStructVal(ClassLayout* layout, GenTree* addr); GenTree* gtNewBlockVal(GenTree* addr, unsigned size); GenTree* gtNewCpObjNode(GenTree* dst, GenTree* src, CORINFO_CLASS_HANDLE structHnd, bool isVolatile); diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index d9234846e2269b..d00129b1972a46 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -7196,21 +7196,20 @@ GenTreeOp* Compiler::gtNewAssignNode(GenTree* dst, GenTree* src) } //------------------------------------------------------------------------ -// gtNewObjNode: Creates a new Obj node. +// gtNewObjNode: Creates a new Obj node with the given layout. // // Arguments: -// structHnd - The class handle of the struct type. -// addr - The address of the struct. +// layout - The struct layout +// addr - The address of the struct // // Return Value: // Returns a node representing the struct value at the given address. // -GenTreeObj* Compiler::gtNewObjNode(CORINFO_CLASS_HANDLE structHnd, GenTree* addr) +GenTreeObj* Compiler::gtNewObjNode(ClassLayout* layout, GenTree* addr) { - var_types nodeType = impNormStructType(structHnd); - assert(varTypeIsStruct(nodeType)); + assert(layout != nullptr); - GenTreeObj* objNode = new (this, GT_OBJ) GenTreeObj(nodeType, addr, typGetObjLayout(structHnd)); + GenTreeObj* objNode = new (this, GT_OBJ) GenTreeObj(layout->GetType(), addr, layout); // An Obj is not a global reference, if it is known to be a local struct. if ((addr->gtFlags & GTF_GLOB_REF) == 0) @@ -7225,6 +7224,25 @@ GenTreeObj* Compiler::gtNewObjNode(CORINFO_CLASS_HANDLE structHnd, GenTree* addr } } } + + return objNode; +} + +//------------------------------------------------------------------------ +// gtNewObjNode: Creates a new Obj node with the layout for the given handle. +// +// Arguments: +// structHnd - The class handle of the struct type +// addr - The address of the struct +// +// Return Value: +// Returns a node representing the struct value at the given address. +// +GenTreeObj* Compiler::gtNewObjNode(CORINFO_CLASS_HANDLE structHnd, GenTree* addr) +{ + ClassLayout* layout = typGetObjLayout(structHnd); + GenTreeObj* objNode = gtNewObjNode(layout, addr); + return objNode; } @@ -7233,7 +7251,7 @@ GenTreeObj* Compiler::gtNewObjNode(CORINFO_CLASS_HANDLE structHnd, GenTree* addr // // Arguments: // objNode - The object node of interest - +// void Compiler::gtSetObjGcInfo(GenTreeObj* objNode) { assert(varTypeIsStruct(objNode->TypeGet())); @@ -7249,28 +7267,31 @@ void Compiler::gtSetObjGcInfo(GenTreeObj* objNode) // gtNewStructVal: Return a node that represents a struct value // // Arguments: -// structHnd - The class for the struct -// addr - The address of the struct +// layout - The struct's layout +// addr - The address of the struct // // Return Value: -// A block, object or local node that represents the struct value pointed to by 'addr'. - -GenTree* Compiler::gtNewStructVal(CORINFO_CLASS_HANDLE structHnd, GenTree* addr) +// An "OBJ" node, or "LCL_VAR" node if "addr" points to a local with +// a layout compatible with "layout". +// +GenTree* Compiler::gtNewStructVal(ClassLayout* layout, GenTree* addr) { - if (addr->gtOper == GT_ADDR) + if (addr->OperIs(GT_ADDR)) { - GenTree* val = addr->gtGetOp1(); - if (val->OperGet() == GT_LCL_VAR) + GenTree* location = addr->gtGetOp1(); + if (location->OperIs(GT_LCL_VAR)) { - unsigned lclNum = addr->gtGetOp1()->AsLclVarCommon()->GetLclNum(); - LclVarDsc* varDsc = &(lvaTable[lclNum]); - if (varTypeIsStruct(varDsc) && (varDsc->GetStructHnd() == structHnd) && !lvaIsImplicitByRefLocal(lclNum)) + unsigned lclNum = location->AsLclVar()->GetLclNum(); + LclVarDsc* varDsc = lvaGetDesc(lclNum); + if (!lvaIsImplicitByRefLocal(lclNum) && varTypeIsStruct(varDsc) && + ClassLayout::AreCompatible(layout, varDsc->GetLayout())) { - return addr->gtGetOp1(); + return location; } } } - return gtNewObjNode(structHnd, addr); + + return gtNewObjNode(layout, addr); } //------------------------------------------------------------------------ @@ -7320,8 +7341,9 @@ GenTree* Compiler::gtNewBlockVal(GenTree* addr, unsigned size) GenTree* Compiler::gtNewCpObjNode(GenTree* dstAddr, GenTree* srcAddr, CORINFO_CLASS_HANDLE structHnd, bool isVolatile) { - GenTree* lhs = gtNewStructVal(structHnd, dstAddr); - GenTree* src = nullptr; + ClassLayout* layout = typGetObjLayout(structHnd); + GenTree* lhs = gtNewStructVal(layout, dstAddr); + GenTree* src = gtNewStructVal(layout, srcAddr); if (lhs->OperIs(GT_OBJ)) { @@ -7340,15 +7362,6 @@ GenTree* Compiler::gtNewCpObjNode(GenTree* dstAddr, GenTree* srcAddr, CORINFO_CL gtSetObjGcInfo(lhsObj); } - if (srcAddr->OperGet() == GT_ADDR) - { - src = srcAddr->AsOp()->gtOp1; - } - else - { - src = gtNewOperNode(GT_IND, lhs->TypeGet(), srcAddr); - } - GenTree* result = gtNewBlkOpNode(lhs, src, isVolatile, true); return result; } @@ -7693,14 +7706,8 @@ void Compiler::gtBlockOpInit(GenTree* result, GenTree* dst, GenTree* srcOrFillVa GenTree* Compiler::gtNewBlkOpNode(GenTree* dst, GenTree* srcOrFillVal, bool isVolatile, bool isCopyBlock) { assert(dst->OperIsBlk() || dst->OperIsLocal()); - if (isCopyBlock) - { - if (srcOrFillVal->OperIsIndir() && (srcOrFillVal->gtGetOp1()->gtOper == GT_ADDR)) - { - srcOrFillVal = srcOrFillVal->gtGetOp1()->gtGetOp1(); - } - } - else + + if (!isCopyBlock) { // InitBlk assert(varTypeIsIntegral(srcOrFillVal)); diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 3b0a7795c5b9a7..e2360e7f7c80d6 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -17203,7 +17203,7 @@ void Compiler::impImportBlockCode(BasicBlock* block) if (eeIsValueClass(resolvedToken.hClass)) { - op1 = gtNewStructVal(resolvedToken.hClass, op1); + op1 = gtNewStructVal(typGetObjLayout(resolvedToken.hClass), op1); if (op1->OperIs(GT_OBJ)) { gtSetObjGcInfo(op1->AsObj()); diff --git a/src/coreclr/jit/layout.cpp b/src/coreclr/jit/layout.cpp index 1e71517c897dae..d420f9f57b1d08 100644 --- a/src/coreclr/jit/layout.cpp +++ b/src/coreclr/jit/layout.cpp @@ -334,12 +334,15 @@ ClassLayout* ClassLayout::Create(Compiler* compiler, CORINFO_CLASS_HANDLE classH size = compiler->info.compCompHnd->getHeapClassSize(classHandle); } + var_types type = compiler->impNormStructType(classHandle); + INDEBUG(const char* className = compiler->eeGetClassName(classHandle);) INDEBUG(const char16_t* shortClassName = compiler->eeGetShortClassName(classHandle);) ClassLayout* layout = new (compiler, CMK_ClassLayout) - ClassLayout(classHandle, isValueClass, size DEBUGARG(className) DEBUGARG(shortClassName)); + ClassLayout(classHandle, isValueClass, size, type DEBUGARG(className) DEBUGARG(shortClassName)); layout->InitializeGCPtrs(compiler); + return layout; } @@ -400,7 +403,11 @@ void ClassLayout::InitializeGCPtrs(Compiler* compiler) // static bool ClassLayout::AreCompatible(const ClassLayout* layout1, const ClassLayout* layout2) { - assert((layout1 != nullptr) && (layout2 != nullptr)); + if ((layout1 == nullptr) || (layout2 == nullptr)) + { + return false; + } + CORINFO_CLASS_HANDLE clsHnd1 = layout1->GetClassHandle(); CORINFO_CLASS_HANDLE clsHnd2 = layout2->GetClassHandle(); @@ -419,6 +426,11 @@ bool ClassLayout::AreCompatible(const ClassLayout* layout1, const ClassLayout* l return false; } + if (layout1->GetType() != layout2->GetType()) + { + return false; + } + if (!layout1->HasGCPtr() && !layout2->HasGCPtr()) { return true; diff --git a/src/coreclr/jit/layout.h b/src/coreclr/jit/layout.h index b2d37c4163480f..01040f8eede39b 100644 --- a/src/coreclr/jit/layout.h +++ b/src/coreclr/jit/layout.h @@ -35,6 +35,9 @@ class ClassLayout BYTE m_gcPtrsArray[sizeof(BYTE*)]; }; + // The normalized type to use in IR for block nodes with this layout. + const var_types m_type; + // Class name as reported by ICorJitInfo::getClassName INDEBUG(const char* m_className;) @@ -53,6 +56,7 @@ class ClassLayout #endif , m_gcPtrCount(0) , m_gcPtrs(nullptr) + , m_type(TYP_STRUCT) #ifdef DEBUG , m_className("block") , m_shortClassName(u"block") @@ -64,7 +68,8 @@ class ClassLayout ClassLayout(CORINFO_CLASS_HANDLE classHandle, bool isValueClass, - unsigned size DEBUGARG(const char* className) DEBUGARG(const char16_t* shortClassName)) + unsigned size, + var_types type DEBUGARG(const char* className) DEBUGARG(const char16_t* shortClassName)) : m_classHandle(classHandle) , m_size(size) , m_isValueClass(isValueClass) @@ -73,6 +78,7 @@ class ClassLayout #endif , m_gcPtrCount(0) , m_gcPtrs(nullptr) + , m_type(type) #ifdef DEBUG , m_className(className) , m_shortClassName(shortClassName) @@ -120,6 +126,11 @@ class ClassLayout return m_size; } + var_types GetType() const + { + return m_type; + } + //------------------------------------------------------------------------ // GetRegisterType: Determine register type for the layout. // diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_69232/Runtime_69232.cs b/src/tests/JIT/Regression/JitBlue/Runtime_69232/Runtime_69232.cs new file mode 100644 index 00000000000000..53e0d546e23c49 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_69232/Runtime_69232.cs @@ -0,0 +1,31 @@ +// 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; + +public unsafe class Runtime_69232 +{ + public static int Main() + { + return Problem(new(1, 1, 1, 1)) ? 101 : 100; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool Problem(Vector4 vtor) + { + FakeVtor a = GetFakeVtor(vtor); + + return a.FirstFlt != 1; + } + + private static FakeVtor GetFakeVtor(Vector4 v) => *(FakeVtor*)&v; + + struct FakeVtor + { + public float FirstFlt; + public float SecondFlt; + public float ThirdFlt; + public float FourthFlt; + } +} diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_69232/Runtime_69232.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_69232/Runtime_69232.csproj new file mode 100644 index 00000000000000..cf94135633b19a --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_69232/Runtime_69232.csproj @@ -0,0 +1,10 @@ + + + Exe + True + true + + + + + \ No newline at end of file diff --git a/src/tests/issues.targets b/src/tests/issues.targets index 265461e41ab0e6..a12139bd64117c 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -250,9 +250,6 @@ https://github.com/dotnet/runtime/issues/60154 - - https://github.com/dotnet/runtime/issues/69232 -