diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 619b175f7e33b7..24174988f3dae6 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -631,8 +631,8 @@ class LclVarDsc unsigned char lvLRACandidate : 1; // Tracked for linear scan register allocation purposes #ifdef FEATURE_SIMD - unsigned char lvUsedInSIMDIntrinsic : 1; // This tells lclvar is used for simd intrinsic -#endif // FEATURE_SIMD + unsigned char lvIsBitcastToSimd : 1; // This tracks whether the lclvar was bitcast to a simd type +#endif // FEATURE_SIMD unsigned char lvRegStruct : 1; // This is a reg-sized non-field-addressed struct. @@ -833,13 +833,13 @@ class LclVarDsc ///////////////////// #ifdef FEATURE_SIMD - // Is this is a SIMD struct which is used for SIMD intrinsic? - bool lvIsUsedInSIMDIntrinsic() const + // Is this a TY_STRUCT which is bitcast to a TYP_SIMD + bool IsBitcastToSimd() const { - return lvUsedInSIMDIntrinsic; + return lvIsBitcastToSimd; } #else - bool lvIsUsedInSIMDIntrinsic() const + bool IsBitcastToSimd() const { return false; } @@ -3363,10 +3363,6 @@ class Compiler GenTreeFieldList* gtNewFieldList(); -#ifdef FEATURE_SIMD - void SetOpLclRelatedToSIMDIntrinsic(GenTree* op); -#endif - #ifdef FEATURE_HW_INTRINSICS GenTreeHWIntrinsic* gtNewSimdHWIntrinsicNode(var_types type, NamedIntrinsic hwIntrinsicID, @@ -10040,90 +10036,6 @@ class Compiler // by the hardware. It is allocated when/if such situations are encountered during Lowering. unsigned lvaSIMDInitTempVarNum = BAD_VAR_NUM; - struct SIMDHandlesCache - { - CORINFO_CLASS_HANDLE PlaneHandle; - CORINFO_CLASS_HANDLE QuaternionHandle; - CORINFO_CLASS_HANDLE Vector2Handle; - CORINFO_CLASS_HANDLE Vector3Handle; - CORINFO_CLASS_HANDLE Vector4Handle; - CORINFO_CLASS_HANDLE VectorHandle; - - SIMDHandlesCache() - { - memset(this, 0, sizeof(*this)); - } - }; - - SIMDHandlesCache* m_simdHandleCache = nullptr; - - // Returns true if this is a SIMD type that should be considered an opaque - // vector type (i.e. do not analyze or promote its fields). - // Note that all but the fixed vector types are opaque, even though they may - // actually be declared as having fields. - bool isOpaqueSIMDType(CORINFO_CLASS_HANDLE structHandle) const - { - // We order the checks roughly by expected hit count so early exits are possible - - if (m_simdHandleCache == nullptr) - { - return false; - } - - if (structHandle == m_simdHandleCache->Vector4Handle) - { - return false; - } - - if (structHandle == m_simdHandleCache->Vector3Handle) - { - return false; - } - - if (structHandle == m_simdHandleCache->Vector2Handle) - { - return false; - } - - if (structHandle == m_simdHandleCache->QuaternionHandle) - { - return false; - } - - if (structHandle == m_simdHandleCache->PlaneHandle) - { - return false; - } - - return true; - } - - bool isOpaqueSIMDType(ClassLayout* layout) const - { - if (layout->IsCustomLayout()) - { - return true; - } - - return isOpaqueSIMDType(layout->GetClassHandle()); - } - - // Returns true if the lclVar is an opaque SIMD type. - bool isOpaqueSIMDLclVar(const LclVarDsc* varDsc) const - { - if (!varTypeIsSIMD(varDsc)) - { - return false; - } - - if (varDsc->GetLayout() == nullptr) - { - return true; - } - - return isOpaqueSIMDType(varDsc->GetLayout()); - } - bool isSystemHalfClass(CORINFO_CLASS_HANDLE clsHnd) { if (isIntrinsicType(clsHnd)) @@ -10177,8 +10089,6 @@ class Compiler GenTree* impSIMDPopStack(); - void setLclRelatedToSIMDIntrinsic(GenTree* tree); - // Get the size of the SIMD type in bytes int getSIMDTypeSizeInBytes(CORINFO_CLASS_HANDLE typeHnd) { @@ -10436,10 +10346,6 @@ class Compiler unsigned getSIMDInitTempVarNum(var_types simdType); #else // !FEATURE_SIMD - bool isOpaqueSIMDLclVar(LclVarDsc* varDsc) - { - return false; - } unsigned int roundUpSIMDSize(unsigned size) { return 0; diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index ead7edca7308b0..f5c6aeffa6e2e9 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -10064,8 +10064,7 @@ GenTreeFieldAddr* Compiler::gtNewFieldAddrNode(var_types type, CORINFO_FIELD_HAN //------------------------------------------------------------------------ // gtInitializeStoreNode: Initialize a store node. // -// Common initialization for all STORE nodes. Marks SIMD locals as "used in -// a HW intrinsic". +// Common initialization for all STORE nodes. // // Arguments: // store - The store node @@ -10075,21 +10074,6 @@ void Compiler::gtInitializeStoreNode(GenTree* store, GenTree* value) { // TODO-ASG: add asserts that the types match here. assert(store->Data() == value); - -#if defined(FEATURE_SIMD) - if (varTypeIsSIMDOrMask(store)) - { - // TODO-ASG: delete this zero-diff quirk. - if (!value->IsCall() || !value->AsCall()->ShouldHaveRetBufArg()) - { - // We want to track SIMD/Mask stores as being intrinsics since they - // are functionally `mov` instructions and are more efficient when - // we don't promote, particularly when it occurs due to inlining. - SetOpLclRelatedToSIMDIntrinsic(store); - SetOpLclRelatedToSIMDIntrinsic(value); - } - } -#endif // FEATURE_SIMD } //------------------------------------------------------------------------ @@ -21884,21 +21868,6 @@ FieldSeq::FieldSeq(CORINFO_FIELD_HANDLE fieldHnd, ssize_t offset, FieldKind fiel } #ifdef FEATURE_SIMD -//------------------------------------------------------------------- -// SetOpLclRelatedToSIMDIntrinsic: Determine if the tree has a local var that needs to be set -// as used by a SIMD intrinsic, and if so, set that local var appropriately. -// -// Arguments: -// op - The tree, to be an operand of a new SIMD-related node, to check. -// -void Compiler::SetOpLclRelatedToSIMDIntrinsic(GenTree* op) -{ - if ((op != nullptr) && op->OperIsScalarLocal()) - { - setLclRelatedToSIMDIntrinsic(op); - } -} - void GenTreeMultiOp::ResetOperandArray(size_t newOperandCount, Compiler* compiler, GenTree** inlineOperands, @@ -22679,8 +22648,6 @@ GenTreeHWIntrinsic* Compiler::gtNewSimdHWIntrinsicNode(var_types type, GenTreeHWIntrinsic* Compiler::gtNewSimdHWIntrinsicNode( var_types type, GenTree* op1, NamedIntrinsic hwIntrinsicID, var_types simdBaseType, unsigned simdSize) { - SetOpLclRelatedToSIMDIntrinsic(op1); - return new (this, GT_HWINTRINSIC) GenTreeHWIntrinsic(type, getAllocator(CMK_ASTNode), hwIntrinsicID, simdBaseType, simdSize, op1); } @@ -22688,9 +22655,6 @@ GenTreeHWIntrinsic* Compiler::gtNewSimdHWIntrinsicNode( GenTreeHWIntrinsic* Compiler::gtNewSimdHWIntrinsicNode( var_types type, GenTree* op1, GenTree* op2, NamedIntrinsic hwIntrinsicID, var_types simdBaseType, unsigned simdSize) { - SetOpLclRelatedToSIMDIntrinsic(op1); - SetOpLclRelatedToSIMDIntrinsic(op2); - return new (this, GT_HWINTRINSIC) GenTreeHWIntrinsic(type, getAllocator(CMK_ASTNode), hwIntrinsicID, simdBaseType, simdSize, op1, op2); } @@ -22703,10 +22667,6 @@ GenTreeHWIntrinsic* Compiler::gtNewSimdHWIntrinsicNode(var_types type, var_types simdBaseType, unsigned simdSize) { - SetOpLclRelatedToSIMDIntrinsic(op1); - SetOpLclRelatedToSIMDIntrinsic(op2); - SetOpLclRelatedToSIMDIntrinsic(op3); - return new (this, GT_HWINTRINSIC) GenTreeHWIntrinsic(type, getAllocator(CMK_ASTNode), hwIntrinsicID, simdBaseType, simdSize, op1, op2, op3); } @@ -22720,11 +22680,6 @@ GenTreeHWIntrinsic* Compiler::gtNewSimdHWIntrinsicNode(var_types type, var_types simdBaseType, unsigned simdSize) { - SetOpLclRelatedToSIMDIntrinsic(op1); - SetOpLclRelatedToSIMDIntrinsic(op2); - SetOpLclRelatedToSIMDIntrinsic(op3); - SetOpLclRelatedToSIMDIntrinsic(op4); - return new (this, GT_HWINTRINSIC) GenTreeHWIntrinsic(type, getAllocator(CMK_ASTNode), hwIntrinsicID, simdBaseType, simdSize, op1, op2, op3, op4); } @@ -22740,7 +22695,6 @@ GenTreeHWIntrinsic* Compiler::gtNewSimdHWIntrinsicNode(var_types type, for (size_t i = 0; i < operandCount; i++) { nodeBuilder.AddOperand(i, operands[i]); - SetOpLclRelatedToSIMDIntrinsic(operands[i]); } return new (this, GT_HWINTRINSIC) @@ -22753,11 +22707,6 @@ GenTreeHWIntrinsic* Compiler::gtNewSimdHWIntrinsicNode(var_types ty var_types simdBaseType, unsigned simdSize) { - for (size_t i = 0; i < nodeBuilder.GetOperandCount(); i++) - { - SetOpLclRelatedToSIMDIntrinsic(nodeBuilder.GetOperand(i)); - } - return new (this, GT_HWINTRINSIC) GenTreeHWIntrinsic(type, std::move(nodeBuilder), hwIntrinsicID, simdBaseType, simdSize); } @@ -25815,10 +25764,9 @@ GenTree* Compiler::gtNewSimdLoadNode(var_types type, GenTree* op1, var_types sim assert(getSIMDTypeForSize(simdSize) == type); assert(op1 != nullptr); - assert(varTypeIsArithmetic(simdBaseType)); - return gtNewIndir(type, op1); + return gtNewLoadValueNode(type, op1); } //---------------------------------------------------------------------------------------------- @@ -28540,12 +28488,12 @@ GenTree* Compiler::gtNewSimdStoreNode(GenTree* op1, GenTree* op2, var_types simd assert(op1 != nullptr); assert(op2 != nullptr); + assert(varTypeIsArithmetic(simdBaseType)); + assert(varTypeIsSIMD(op2)); assert(getSIMDTypeForSize(simdSize) == op2->TypeGet()); - assert(varTypeIsArithmetic(simdBaseType)); - - return gtNewStoreIndNode(op2->TypeGet(), op1, op2); + return gtNewStoreValueNode(op2->TypeGet(), op1, op2); } //---------------------------------------------------------------------------------------------- @@ -29781,8 +29729,6 @@ GenTreeHWIntrinsic* Compiler::gtNewScalarHWIntrinsicNode(var_types type, NamedIn GenTreeHWIntrinsic* Compiler::gtNewScalarHWIntrinsicNode(var_types type, GenTree* op1, NamedIntrinsic hwIntrinsicID) { - SetOpLclRelatedToSIMDIntrinsic(op1); - return new (this, GT_HWINTRINSIC) GenTreeHWIntrinsic(type, getAllocator(CMK_ASTNode), hwIntrinsicID, TYP_UNKNOWN, 0, op1); } @@ -29792,9 +29738,6 @@ GenTreeHWIntrinsic* Compiler::gtNewScalarHWIntrinsicNode(var_types type, GenTree* op2, NamedIntrinsic hwIntrinsicID) { - SetOpLclRelatedToSIMDIntrinsic(op1); - SetOpLclRelatedToSIMDIntrinsic(op2); - return new (this, GT_HWINTRINSIC) GenTreeHWIntrinsic(type, getAllocator(CMK_ASTNode), hwIntrinsicID, TYP_UNKNOWN, 0, op1, op2); } @@ -29802,10 +29745,6 @@ GenTreeHWIntrinsic* Compiler::gtNewScalarHWIntrinsicNode(var_types type, GenTreeHWIntrinsic* Compiler::gtNewScalarHWIntrinsicNode( var_types type, GenTree* op1, GenTree* op2, GenTree* op3, NamedIntrinsic hwIntrinsicID) { - SetOpLclRelatedToSIMDIntrinsic(op1); - SetOpLclRelatedToSIMDIntrinsic(op2); - SetOpLclRelatedToSIMDIntrinsic(op3); - return new (this, GT_HWINTRINSIC) GenTreeHWIntrinsic(type, getAllocator(CMK_ASTNode), hwIntrinsicID, TYP_UNKNOWN, 0, op1, op2, op3); } diff --git a/src/coreclr/jit/hwintrinsicarm64.cpp b/src/coreclr/jit/hwintrinsicarm64.cpp index 9a29130d21e054..e1872311de6224 100644 --- a/src/coreclr/jit/hwintrinsicarm64.cpp +++ b/src/coreclr/jit/hwintrinsicarm64.cpp @@ -844,7 +844,6 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, // and the signature return type are both the same TYP_SIMD. retNode = impSIMDPopStack(); - SetOpLclRelatedToSIMDIntrinsic(retNode); assert(retNode->gtType == getSIMDTypeForSize(getSIMDTypeSizeInBytes(sig->retTypeSigClass))); break; } @@ -939,7 +938,6 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, // and the signature return type are both the same TYP_SIMD. retNode = impSIMDPopStack(); - SetOpLclRelatedToSIMDIntrinsic(retNode); assert(retNode->gtType == getSIMDTypeForSize(getSIMDTypeSizeInBytes(sig->retTypeSigClass))); break; } @@ -3421,11 +3419,6 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, argType = JITtype2varType(strip(info.compCompHnd->getArgType(sig, arg1, &argClass))); op1 = getArgForHWIntrinsic(argType, argClass); - SetOpLclRelatedToSIMDIntrinsic(op1); - SetOpLclRelatedToSIMDIntrinsic(op2); - SetOpLclRelatedToSIMDIntrinsic(op3); - SetOpLclRelatedToSIMDIntrinsic(op4); - SetOpLclRelatedToSIMDIntrinsic(op5); retNode = new (this, GT_HWINTRINSIC) GenTreeHWIntrinsic(retType, getAllocator(CMK_ASTNode), intrinsic, simdBaseType, simdSize, op1, op2, op3, op4, op5); break; diff --git a/src/coreclr/jit/hwintrinsicxarch.cpp b/src/coreclr/jit/hwintrinsicxarch.cpp index 4b6a2f065690f6..095f47469183bc 100644 --- a/src/coreclr/jit/hwintrinsicxarch.cpp +++ b/src/coreclr/jit/hwintrinsicxarch.cpp @@ -1523,7 +1523,6 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, assert(sig->numArgs == 1); retNode = impSIMDPopStack(); - SetOpLclRelatedToSIMDIntrinsic(retNode); assert(retNode->gtType == getSIMDTypeForSize(getSIMDTypeSizeInBytes(sig->retTypeSigClass))); break; } @@ -1613,7 +1612,6 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, // and the signature return type are both the same TYP_SIMD. retNode = impSIMDPopStack(); - SetOpLclRelatedToSIMDIntrinsic(retNode); assert(retNode->gtType == getSIMDTypeForSize(getSIMDTypeSizeInBytes(sig->retTypeSigClass))); break; @@ -1673,7 +1671,6 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, // and the signature return type are both the same TYP_SIMD. retNode = impSIMDPopStack(); - SetOpLclRelatedToSIMDIntrinsic(retNode); assert(retNode->gtType == getSIMDTypeForSize(getSIMDTypeSizeInBytes(sig->retTypeSigClass))); break; @@ -5467,24 +5464,19 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, argType = JITtype2varType(strip(info.compCompHnd->getArgType(sig, arg5, &argClass))); GenTree* op5 = getArgForHWIntrinsic(argType, argClass); - SetOpLclRelatedToSIMDIntrinsic(op5); argType = JITtype2varType(strip(info.compCompHnd->getArgType(sig, arg4, &argClass))); GenTree* op4 = getArgForHWIntrinsic(argType, argClass); - SetOpLclRelatedToSIMDIntrinsic(op4); argType = JITtype2varType(strip(info.compCompHnd->getArgType(sig, arg3, &argClass))); var_types indexBaseType = getBaseTypeOfSIMDType(argClass); GenTree* op3 = getArgForHWIntrinsic(argType, argClass); - SetOpLclRelatedToSIMDIntrinsic(op3); argType = JITtype2varType(strip(info.compCompHnd->getArgType(sig, arg2, &argClass))); op2 = getArgForHWIntrinsic(argType, argClass); - SetOpLclRelatedToSIMDIntrinsic(op2); argType = JITtype2varType(strip(info.compCompHnd->getArgType(sig, argList, &argClass))); op1 = getArgForHWIntrinsic(argType, argClass); - SetOpLclRelatedToSIMDIntrinsic(op1); retNode = new (this, GT_HWINTRINSIC) GenTreeHWIntrinsic(retType, getAllocator(CMK_ASTNode), intrinsic, simdBaseType, simdSize, op1, op2, op3, op4, op5); diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 9c860424faa158..d72f3f6059cf00 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -11004,6 +11004,28 @@ void Compiler::impImportBlockCode(BasicBlock* block) op1 = impPopStack().val; assertImp((genActualType(op1) == TYP_I_IMPL) || op1->TypeIs(TYP_BYREF)); +#if defined(FEATURE_SIMD) + if (varTypeIsSIMD(lclTyp)) + { + // We want to handle the general pattern of *(VectorN*)(&lcl) + // so we can recognize it as a form of bitcasting and mark the + // underlying value to prevent its promotion. This is generally + // some form of `ldarga, conv.u, ldobj` in IL + + GenTree* addr = op1->gtEffectiveVal(); + + if (addr->IsLclVarAddr()) + { + LclVarDsc* lclVar = lvaGetDesc(addr->AsLclFld()); + + if ((lclVar->lvType == TYP_STRUCT) && (lclVar->lvExactSize() == genTypeSize(lclTyp))) + { + lclVar->lvIsBitcastToSimd = true; + } + } + } +#endif // FEATURE_SIMD + op1 = gtNewLoadValueNode(lclTyp, layout, op1, impPrefixFlagsToIndirFlags(prefixFlags)); impPushOnStack(op1, tiRetVal); break; diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index 7fd54532ce41b3..f310642119dd1d 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -5334,18 +5334,17 @@ GenTree* Compiler::impSRCSUnsafeIntrinsic(NamedIntrinsic intrinsic, case NI_SRCS_UNSAFE_As: { - assert((sig->sigInst.methInstCount == 1) || (sig->sigInst.methInstCount == 2)); + GenTree* op = impPopStack().val; if (sig->sigInst.methInstCount == 1) { + assert(op->TypeIs(TYP_REF)); + CORINFO_SIG_INFO exactSig; info.compCompHnd->getMethodSig(pResolvedToken->hMethod, &exactSig); const CORINFO_CLASS_HANDLE inst = exactSig.sigInst.methInst[0]; assert(inst != nullptr); - GenTree* op = impPopStack().val; - assert(op->TypeIs(TYP_REF)); - JITDUMP("Expanding Unsafe.As<%s>(...)\n", eeGetClassName(inst)); bool isExact, isNonNull; @@ -5367,10 +5366,33 @@ GenTree* Compiler::impSRCSUnsafeIntrinsic(NamedIntrinsic intrinsic, return gtNewLclvNode(localNum, TYP_REF); } + assert(sig->sigInst.methInstCount == 2); + // ldarg.0 // ret - return impPopStack().val; +#if defined(FEATURE_SIMD) + GenTree* addr = op->gtEffectiveVal(); + + if (addr->IsLclVarAddr()) + { + CORINFO_CLASS_HANDLE toTypeHnd = sig->sigInst.methInst[1]; + var_types toType = TypeHandleToVarType(toTypeHnd); + + if (varTypeIsSIMD(toType)) + { + CORINFO_CLASS_HANDLE fromTypeHnd = sig->sigInst.methInst[0]; + ClassLayout* fromLayout = nullptr; + TypeHandleToVarType(fromTypeHnd, &fromLayout); + + if ((fromLayout != nullptr) && (fromLayout->GetSize() == genTypeSize(toType))) + { + lvaGetDesc(addr->AsLclFld())->lvIsBitcastToSimd = true; + } + } + } +#endif // FEATURE_SIMD + return op; } case NI_SRCS_UNSAFE_AsPointer: @@ -5516,6 +5538,13 @@ GenTree* Compiler::impSRCSUnsafeIntrinsic(NamedIntrinsic intrinsic, else { addr = impGetNodeAddr(op1, CHECK_SPILL_ALL, GTF_IND_MUST_PRESERVE_FLAGS, &indirFlags); + +#if defined(FEATURE_SIMD) + if (varTypeIsSIMD(toType) && addr->IsLclVarAddr()) + { + lvaGetDesc(addr->AsLclFld())->lvIsBitcastToSimd = true; + } +#endif // FEATURE_SIMD } if (info.compCompHnd->getClassAlignmentRequirement(fromTypeHnd) < diff --git a/src/coreclr/jit/lclvars.cpp b/src/coreclr/jit/lclvars.cpp index baa018d700ce40..0dc864bd54e00d 100644 --- a/src/coreclr/jit/lclvars.cpp +++ b/src/coreclr/jit/lclvars.cpp @@ -1729,12 +1729,27 @@ bool Compiler::StructPromotionHelper::CanPromoteStructVar(unsigned lclNum) assert(varTypeIsStruct(varDsc)); assert(!varDsc->lvPromoted); // Don't ask again :) - // If this lclVar is used in a SIMD intrinsic, then we don't want to struct promote it. - // Note, however, that SIMD lclVars that are NOT used in a SIMD intrinsic may be - // profitably promoted. - if (varDsc->lvIsUsedInSIMDIntrinsic()) + if (varTypeIsSIMDOrMask(varDsc->lvType)) { - JITDUMP(" struct promotion of V%02u is disabled because lvIsUsedInSIMDIntrinsic()\n", lclNum); + // TYP_SIMD and TYP_MASK locals should never be promoted because they either don't have accessible fields + // or they have specialized IR support that transforms those field accesses into appropriate codegen. While + // could potentially be a little smarter here if the user is only touching the fields, this is not a recommended + // pattern in the first place and so its not something we want to spend effort optimizing. Rather, developers + // should treat it as a proper SIMD primitive type and do the "right" thing. + + JITDUMP(" struct promotion of V%02u is disabled because it is a SIMD or MASK type\n", lclNum); + return false; + } + + if (varDsc->IsBitcastToSimd()) + { + // The local is effectively bitcast to one of the recognized TYP_SIMD structs and so we use this as a hint that + // it is likely a user-defined vector wrapper and they want it to be optimized accordingly. This may pessimize + // some rare edge cases where devs are mixing SIMD and non-SIMD patterns, but as with the comment above we want + // to discourage doing that and for them to pick one pattern, because it otherwise ends up non-optimal no matter + // what we do. + + JITDUMP(" struct promotion of V%02u is disabled because IsBitcastToSimd()\n", lclNum); return false; } @@ -1824,16 +1839,6 @@ bool Compiler::StructPromotionHelper::CanPromoteStructVar(unsigned lclNum) { canPromote = false; } -#if defined(FEATURE_SIMD) - // If we have a register-passed struct with mixed non-opaque SIMD types (i.e. with defined fields) - // and non-SIMD types, we don't currently handle that case in the prolog, so we can't promote. - else if ((fieldCnt > 1) && varTypeIsStruct(fieldType) && - (structPromotionInfo.fields[i].fldSIMDTypeHnd != NO_CLASS_HANDLE) && - !m_compiler->isOpaqueSIMDType(structPromotionInfo.fields[i].fldSIMDTypeHnd)) - { - canPromote = false; - } -#endif // FEATURE_SIMD } } #elif defined(UNIX_AMD64_ABI) diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index 8f32ee00f0d34c..3903ca67bb098c 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -15154,10 +15154,9 @@ PhaseStatus Compiler::fgPromoteStructs() bool promotedVar = false; LclVarDsc* varDsc = lvaGetDesc(lclNum); - // If we have marked this as lvUsedInSIMDIntrinsic, then we do not want to promote - // its fields. Instead, we will attempt to enregister the entire struct. - if (varTypeIsSIMD(varDsc) && (varDsc->lvIsUsedInSIMDIntrinsic() || isOpaqueSIMDLclVar(varDsc))) + if (varTypeIsSIMDOrMask(varDsc) || varDsc->IsBitcastToSimd()) { + // Attempt to enregister the entire struct. varDsc->lvRegStruct = true; } // Don't promote if we have reached the tracking limit. diff --git a/src/coreclr/jit/simd.cpp b/src/coreclr/jit/simd.cpp index 196b28a98a02e3..79469cc05890b1 100644 --- a/src/coreclr/jit/simd.cpp +++ b/src/coreclr/jit/simd.cpp @@ -144,9 +144,8 @@ unsigned Compiler::getFFRegisterVarNum() { if (lvaFfrRegister == BAD_VAR_NUM) { - lvaFfrRegister = lvaGrabTemp(false DEBUGARG("Save the FFR value.")); - lvaTable[lvaFfrRegister].lvType = TYP_MASK; - lvaTable[lvaFfrRegister].lvUsedInSIMDIntrinsic = true; + lvaFfrRegister = lvaGrabTemp(false DEBUGARG("Save the FFR value.")); + lvaTable[lvaFfrRegister].lvType = TYP_MASK; } return lvaFfrRegister; } @@ -188,25 +187,6 @@ var_types Compiler::getBaseTypeForPrimitiveNumericClass(CORINFO_CLASS_HANDLE cls // var_types Compiler::getBaseTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeHnd, unsigned* sizeBytes /*= nullptr */) { - if (m_simdHandleCache == nullptr) - { - if (impInlineInfo == nullptr) - { - m_simdHandleCache = new (this, CMK_Generic) SIMDHandlesCache(); - } - else - { - // Steal the inliner compiler's cache (create it if not available). - - if (impInlineInfo->InlineRoot->m_simdHandleCache == nullptr) - { - impInlineInfo->InlineRoot->m_simdHandleCache = new (this, CMK_Generic) SIMDHandlesCache(); - } - - m_simdHandleCache = impInlineInfo->InlineRoot->m_simdHandleCache; - } - } - if (sizeBytes != nullptr) { *sizeBytes = 0; @@ -220,7 +200,6 @@ var_types Compiler::getBaseTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeHnd, u const char* namespaceName; const char* className = getClassNameFromMetadata(typeHnd, &namespaceName); - // fast path search using cached type handles of important types var_types simdBaseType = TYP_UNDEF; unsigned size = 0; @@ -236,7 +215,6 @@ var_types Compiler::getBaseTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeHnd, u } JITDUMP(" Known type Plane\n"); - m_simdHandleCache->PlaneHandle = typeHnd; simdBaseType = TYP_FLOAT; size = 4 * genTypeSize(TYP_FLOAT); @@ -251,7 +229,6 @@ var_types Compiler::getBaseTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeHnd, u } JITDUMP(" Known type Quaternion\n"); - m_simdHandleCache->QuaternionHandle = typeHnd; simdBaseType = TYP_FLOAT; size = 4 * genTypeSize(TYP_FLOAT); @@ -270,7 +247,6 @@ var_types Compiler::getBaseTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeHnd, u case '\0': { JITDUMP(" Found type Vector\n"); - m_simdHandleCache->VectorHandle = typeHnd; break; } @@ -282,7 +258,6 @@ var_types Compiler::getBaseTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeHnd, u } JITDUMP(" Found Vector2\n"); - m_simdHandleCache->Vector2Handle = typeHnd; simdBaseType = TYP_FLOAT; size = 2 * genTypeSize(TYP_FLOAT); @@ -297,7 +272,6 @@ var_types Compiler::getBaseTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeHnd, u } JITDUMP(" Found Vector3\n"); - m_simdHandleCache->Vector3Handle = typeHnd; simdBaseType = TYP_FLOAT; size = 3 * genTypeSize(TYP_FLOAT); @@ -312,7 +286,6 @@ var_types Compiler::getBaseTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeHnd, u } JITDUMP(" Found Vector4\n"); - m_simdHandleCache->Vector4Handle = typeHnd; simdBaseType = TYP_FLOAT; size = 4 * genTypeSize(TYP_FLOAT); @@ -500,17 +473,4 @@ GenTree* Compiler::impSIMDPopStack() return tree; } -//------------------------------------------------------------------- -// Set the flag that indicates that the lclVar referenced by this tree -// is used in a SIMD intrinsic. -// Arguments: -// tree - GenTree* -// -void Compiler::setLclRelatedToSIMDIntrinsic(GenTree* tree) -{ - assert(tree->OperIsScalarLocal() || tree->IsLclVarAddr()); - LclVarDsc* lclVarDsc = lvaGetDesc(tree->AsLclVarCommon()); - lclVarDsc->lvUsedInSIMDIntrinsic = true; -} - #endif // FEATURE_SIMD