diff --git a/src/coreclr/jit/assertionprop.cpp b/src/coreclr/jit/assertionprop.cpp index 1bd0c2677f7975..033f1af84c5342 100644 --- a/src/coreclr/jit/assertionprop.cpp +++ b/src/coreclr/jit/assertionprop.cpp @@ -3211,7 +3211,7 @@ GenTree* Compiler::optVNConstantPropOnTree(BasicBlock* block, GenTree* tree) { simd8_t value = vnStore->ConstantValue(vnCns); - GenTreeVecCon* vecCon = gtNewVconNode(tree->TypeGet(), CORINFO_TYPE_FLOAT); + GenTreeVecCon* vecCon = gtNewVconNode(tree->TypeGet()); vecCon->gtSimd8Val = value; conValTree = vecCon; @@ -3222,7 +3222,7 @@ GenTree* Compiler::optVNConstantPropOnTree(BasicBlock* block, GenTree* tree) { simd12_t value = vnStore->ConstantValue(vnCns); - GenTreeVecCon* vecCon = gtNewVconNode(tree->TypeGet(), CORINFO_TYPE_FLOAT); + GenTreeVecCon* vecCon = gtNewVconNode(tree->TypeGet()); vecCon->gtSimd12Val = value; conValTree = vecCon; @@ -3233,7 +3233,7 @@ GenTree* Compiler::optVNConstantPropOnTree(BasicBlock* block, GenTree* tree) { simd16_t value = vnStore->ConstantValue(vnCns); - GenTreeVecCon* vecCon = gtNewVconNode(tree->TypeGet(), CORINFO_TYPE_FLOAT); + GenTreeVecCon* vecCon = gtNewVconNode(tree->TypeGet()); vecCon->gtSimd16Val = value; conValTree = vecCon; @@ -3244,7 +3244,7 @@ GenTree* Compiler::optVNConstantPropOnTree(BasicBlock* block, GenTree* tree) { simd32_t value = vnStore->ConstantValue(vnCns); - GenTreeVecCon* vecCon = gtNewVconNode(tree->TypeGet(), CORINFO_TYPE_FLOAT); + GenTreeVecCon* vecCon = gtNewVconNode(tree->TypeGet()); vecCon->gtSimd32Val = value; conValTree = vecCon; diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index c16c3547791fa1..d5b1e1e0479261 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -2295,13 +2295,11 @@ class Compiler GenTree* gtNewSconNode(int CPX, CORINFO_MODULE_HANDLE scpHandle); - GenTreeVecCon* gtNewVconNode(var_types type, CorInfoType simdBaseJitType); + GenTreeVecCon* gtNewVconNode(var_types type); GenTree* gtNewAllBitsSetConNode(var_types type); - GenTree* gtNewAllBitsSetConNode(var_types type, CorInfoType simdBaseJitType); GenTree* gtNewZeroConNode(var_types type); - GenTree* gtNewZeroConNode(var_types type, CorInfoType simdBaseJitType); GenTree* gtNewOneConNode(var_types type); @@ -8312,6 +8310,10 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX #endif // defined(TARGET_XARCH) #endif // FEATURE_HW_INTRINSICS + CORINFO_CLASS_HANDLE CanonicalSimd8Handle; + CORINFO_CLASS_HANDLE CanonicalSimd16Handle; + CORINFO_CLASS_HANDLE CanonicalSimd32Handle; + SIMDHandlesCache() { memset(this, 0, sizeof(*this)); @@ -8404,6 +8406,44 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX } #endif // FEATURE_HW_INTRINSICS + //------------------------------------------------------------------------ + // gtGetCanonicalStructHandleForSIMD: Get the "canonical" SIMD type handle. + // + // Some SIMD-typed trees do not carry struct handles with them (and in + // some cases, they cannot, due to being created by the compiler itself). + // To enable CSEing of these trees, we use "canonical" handles. These are + // captured during importation, and can represent any type normalized to + // be TYP_SIMD. + // + // Arguments: + // simdType - The SIMD type + // + // Return Value: + // The "canonical" type handle for "simdType", if one was available. + // "NO_CLASS_HANDLE" otherwise. + // + CORINFO_CLASS_HANDLE gtGetCanonicalStructHandleForSIMD(var_types simdType) + { + if (m_simdHandleCache == nullptr) + { + return NO_CLASS_HANDLE; + } + + switch (simdType) + { + case TYP_SIMD8: + return m_simdHandleCache->CanonicalSimd8Handle; + case TYP_SIMD12: + return m_simdHandleCache->SIMDVector3Handle; + case TYP_SIMD16: + return m_simdHandleCache->CanonicalSimd16Handle; + case TYP_SIMD32: + return m_simdHandleCache->CanonicalSimd32Handle; + default: + unreached(); + } + } + // 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 diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 1e97a840a32635..4567b290379890 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -252,7 +252,9 @@ void GenTree::InitNodeSize() } GenTree::s_gtNodeSizes[GT_CALL] = TREE_NODE_SZ_LARGE; +#ifndef HOST_64BIT GenTree::s_gtNodeSizes[GT_CNS_VEC] = TREE_NODE_SZ_LARGE; +#endif GenTree::s_gtNodeSizes[GT_CAST] = TREE_NODE_SZ_LARGE; GenTree::s_gtNodeSizes[GT_FTN_ADDR] = TREE_NODE_SZ_LARGE; GenTree::s_gtNodeSizes[GT_BOX] = TREE_NODE_SZ_LARGE; @@ -300,7 +302,11 @@ void GenTree::InitNodeSize() static_assert_no_msg(sizeof(GenTreeLngCon) <= TREE_NODE_SZ_SMALL); static_assert_no_msg(sizeof(GenTreeDblCon) <= TREE_NODE_SZ_SMALL); static_assert_no_msg(sizeof(GenTreeStrCon) <= TREE_NODE_SZ_SMALL); +#ifdef HOST_64BIT + static_assert_no_msg(sizeof(GenTreeVecCon) <= TREE_NODE_SZ_SMALL); +#else static_assert_no_msg(sizeof(GenTreeVecCon) <= TREE_NODE_SZ_LARGE); // *** large node +#endif static_assert_no_msg(sizeof(GenTreeLclVarCommon) <= TREE_NODE_SZ_SMALL); static_assert_no_msg(sizeof(GenTreeLclVar) <= TREE_NODE_SZ_SMALL); static_assert_no_msg(sizeof(GenTreeLclFld) <= TREE_NODE_SZ_SMALL); @@ -2898,8 +2904,6 @@ unsigned Compiler::gtHashValue(GenTree* tree) unreached(); } } - - add = genTreeHashAdd(ulo32(add), vecCon->GetSimdBaseType()); break; } @@ -7087,9 +7091,9 @@ GenTree* Compiler::gtNewSconNode(int CPX, CORINFO_MODULE_HANDLE scpHandle) return node; } -GenTreeVecCon* Compiler::gtNewVconNode(var_types type, CorInfoType simdBaseJitType) +GenTreeVecCon* Compiler::gtNewVconNode(var_types type) { - GenTreeVecCon* vecCon = new (this, GT_CNS_VEC) GenTreeVecCon(type, simdBaseJitType); + GenTreeVecCon* vecCon = new (this, GT_CNS_VEC) GenTreeVecCon(type); return vecCon; } @@ -7107,45 +7111,36 @@ GenTree* Compiler::gtNewAllBitsSetConNode(var_types type) allBitsSet = gtNewLconNode(-1); break; - default: - noway_assert(!"Bad type in gtNewAllBitsSetConNode"); - allBitsSet = nullptr; +#ifdef FEATURE_SIMD + case TYP_SIMD8: + case TYP_SIMD12: + case TYP_SIMD16: + case TYP_SIMD32: + allBitsSet = gtNewVconNode(type); + allBitsSet->AsVecCon()->gtSimd32Val.i64[0] = -1; + allBitsSet->AsVecCon()->gtSimd32Val.i64[1] = -1; + allBitsSet->AsVecCon()->gtSimd32Val.i64[2] = -1; + allBitsSet->AsVecCon()->gtSimd32Val.i64[3] = -1; break; +#endif // FEATURE_SIMD + + default: + unreached(); } return allBitsSet; } -GenTree* Compiler::gtNewAllBitsSetConNode(var_types type, CorInfoType simdBaseJitType) -{ - assert(varTypeIsSIMD(type)); - assert(simdBaseJitType != CORINFO_TYPE_UNDEF); - - GenTreeVecCon* vecCon = gtNewVconNode(type, simdBaseJitType); - - vecCon->gtSimd32Val.i64[0] = -1; - vecCon->gtSimd32Val.i64[1] = -1; - vecCon->gtSimd32Val.i64[2] = -1; - vecCon->gtSimd32Val.i64[3] = -1; - - return vecCon; -} - GenTree* Compiler::gtNewZeroConNode(var_types type) { GenTree* zero; + switch (type) { case TYP_INT: - zero = gtNewIconNode(0); - break; - - case TYP_BYREF: - FALLTHROUGH; - case TYP_REF: - zero = gtNewIconNode(0); - zero->gtType = type; + case TYP_BYREF: + zero = gtNewIconNode(0, type); break; case TYP_LONG: @@ -7153,12 +7148,8 @@ GenTree* Compiler::gtNewZeroConNode(var_types type) break; case TYP_FLOAT: - zero = gtNewDconNode(0.0); - zero->gtType = type; - break; - case TYP_DOUBLE: - zero = gtNewDconNode(0.0); + zero = gtNewDconNode(0.0, type); break; #ifdef FEATURE_SIMD @@ -7166,26 +7157,16 @@ GenTree* Compiler::gtNewZeroConNode(var_types type) case TYP_SIMD12: case TYP_SIMD16: case TYP_SIMD32: - zero = gtNewZeroConNode(type, CORINFO_TYPE_FLOAT); + zero = gtNewVconNode(type); + zero->AsVecCon()->gtSimd32Val = {}; break; #endif // FEATURE_SIMD default: - noway_assert(!"Bad type in gtNewZeroConNode"); - zero = nullptr; - break; + unreached(); } - return zero; -} - -GenTree* Compiler::gtNewZeroConNode(var_types type, CorInfoType simdBaseJitType) -{ - assert(varTypeIsSIMD(type)); - assert(simdBaseJitType != CORINFO_TYPE_UNDEF); - GenTreeVecCon* vecCon = gtNewVconNode(type, simdBaseJitType); - vecCon->gtSimd32Val = {}; - return vecCon; + return zero; } GenTree* Compiler::gtNewOneConNode(var_types type) @@ -7205,15 +7186,13 @@ GenTree* Compiler::gtNewOneConNode(var_types type) case TYP_FLOAT: case TYP_DOUBLE: - one = gtNewDconNode(1.0); - one->gtType = type; + one = gtNewDconNode(1.0, type); break; default: - noway_assert(!"Bad type in gtNewOneConNode"); - one = nullptr; - break; + unreached(); } + return one; } @@ -8165,7 +8144,7 @@ GenTree* Compiler::gtClone(GenTree* tree, bool complexOK) case GT_CNS_VEC: { - GenTreeVecCon* vecCon = gtNewVconNode(tree->TypeGet(), tree->AsVecCon()->GetSimdBaseJitType()); + GenTreeVecCon* vecCon = gtNewVconNode(tree->TypeGet()); vecCon->gtSimd32Val = tree->AsVecCon()->gtSimd32Val; copy = vecCon; break; @@ -8345,7 +8324,7 @@ GenTree* Compiler::gtCloneExpr( case GT_CNS_VEC: { - GenTreeVecCon* vecCon = gtNewVconNode(tree->TypeGet(), tree->AsVecCon()->GetSimdBaseJitType()); + GenTreeVecCon* vecCon = gtNewVconNode(tree->TypeGet()); vecCon->gtSimd32Val = tree->AsVecCon()->gtSimd32Val; copy = vecCon; goto DONE; @@ -16670,7 +16649,7 @@ GenTreeLclVar* GenTree::IsImplicitByrefParameterValue(Compiler* compiler) { lcl = AsLclVar(); } - else if (OperIs(GT_OBJ)) + else if (OperIsIndir()) { GenTree* addr = AsIndir()->Addr(); @@ -17252,22 +17231,6 @@ bool GenTreeVecCon::HandleArgForHWIntrinsicCreate(GenTree* arg, int argIdx, simd } #endif // FEATURE_HW_INTRINSICS -//---------------------------------------------------------------------------------------------- -// GetSimdBaseType: Gets the var_type for the SimdBaseJitType of a GenTreeVecCon node -// -// Returns: -// the var_type for the SimdBaseJitType of a GenTreeVecCon -var_types GenTreeVecCon::GetSimdBaseType() const -{ - CorInfoType simdBaseJitType = GetSimdBaseJitType(); - - if (simdBaseJitType == CORINFO_TYPE_UNDEF) - { - return TYP_UNKNOWN; - } - return JitType2PreciseVarType(simdBaseJitType); -} - //------------------------------------------------------------------------ // IsFieldAddr: Is "this" a static or class field address? // @@ -17390,8 +17353,6 @@ CORINFO_CLASS_HANDLE Compiler::gtGetStructHandleIfPresent(GenTree* tree) { switch (tree->gtOper) { - default: - break; case GT_MKREFANY: structHnd = impGetRefAnyClass(); break; @@ -17417,79 +17378,45 @@ CORINFO_CLASS_HANDLE Compiler::gtGetStructHandleIfPresent(GenTree* tree) #ifdef FEATURE_SIMD if (varTypeIsSIMD(tree)) { - structHnd = gtGetStructHandleForSIMD(tree->gtType, CORINFO_TYPE_FLOAT); -#ifdef FEATURE_HW_INTRINSICS - if (structHnd == NO_CLASS_HANDLE) - { - structHnd = gtGetStructHandleForHWSIMD(tree->gtType, CORINFO_TYPE_FLOAT); - } -#endif + structHnd = gtGetCanonicalStructHandleForSIMD(tree->TypeGet()); } else -#endif +#endif // FEATURE_SIMD { structHnd = tree->AsLclFld()->GetLayout()->GetClassHandle(); } break; case GT_LCL_VAR: - { - unsigned lclNum = tree->AsLclVarCommon()->GetLclNum(); - structHnd = lvaGetStruct(lclNum); + structHnd = lvaGetDesc(tree->AsLclVar())->GetStructHnd(); break; - } case GT_RETURN: structHnd = gtGetStructHandleIfPresent(tree->AsOp()->gtOp1); break; - case GT_IND: #ifdef FEATURE_SIMD + case GT_IND: if (varTypeIsSIMD(tree)) { - structHnd = gtGetStructHandleForSIMD(tree->gtType, CORINFO_TYPE_FLOAT); -#ifdef FEATURE_HW_INTRINSICS - if (structHnd == NO_CLASS_HANDLE) - { - structHnd = gtGetStructHandleForHWSIMD(tree->gtType, CORINFO_TYPE_FLOAT); - } -#endif + structHnd = gtGetCanonicalStructHandleForSIMD(tree->TypeGet()); } -#endif break; -#ifdef FEATURE_SIMD case GT_SIMD: structHnd = gtGetStructHandleForSIMD(tree->gtType, tree->AsSIMD()->GetSimdBaseJitType()); break; + case GT_CNS_VEC: + structHnd = gtGetCanonicalStructHandleForSIMD(tree->TypeGet()); + break; #endif // FEATURE_SIMD #ifdef FEATURE_HW_INTRINSICS case GT_HWINTRINSIC: - if ((tree->gtFlags & GTF_SIMDASHW_OP) != 0) - { - structHnd = gtGetStructHandleForSIMD(tree->gtType, tree->AsHWIntrinsic()->GetSimdBaseJitType()); - } - else - { - structHnd = gtGetStructHandleForHWSIMD(tree->gtType, tree->AsHWIntrinsic()->GetSimdBaseJitType()); - } + structHnd = gtGetStructHandleForSimdOrHW(tree->TypeGet(), tree->AsHWIntrinsic()->GetSimdBaseJitType(), + tree->AsHWIntrinsic()->IsSimdAsHWIntrinsic()); break; #endif - case GT_CNS_VEC: - { -#if defined(FEATURE_HW_INTRINSICS) - structHnd = gtGetStructHandleForHWSIMD(tree->gtType, tree->AsVecCon()->GetSimdBaseJitType()); -#endif // FEATURE_HW_INTRINSICS - -#if defined(FEATURE_SIMD) - if (structHnd == NO_CLASS_HANDLE) - { - structHnd = gtGetStructHandleForSIMD(tree->gtType, tree->AsVecCon()->GetSimdBaseJitType()); - } -#endif // FEATURE_SIMD + default: break; - } } - // TODO-1stClassStructs: add a check that `structHnd != NO_CLASS_HANDLE`, - // nowadays it won't work because the right part of an ASG could have struct type without a handle - // (check `fgMorphBlockOperand(isBlkReqd`) and a few other cases. } + return structHnd; } @@ -18931,11 +18858,11 @@ GenTree* Compiler::gtNewSimdAbsNode( impCloneExpr(op1Dup1, &op1Dup2, clsHnd, CHECK_SPILL_ALL, nullptr DEBUGARG("Clone op1 for vector abs")); // op1 = op1 < Zero - tmp = gtNewZeroConNode(type, simdBaseJitType); + tmp = gtNewZeroConNode(type); op1 = gtNewSimdCmpOpNode(GT_LT, type, op1, tmp, simdBaseJitType, simdSize, isSimdAsHWIntrinsic); // tmp = Zero - op1Dup1 - tmp = gtNewZeroConNode(type, simdBaseJitType); + tmp = gtNewZeroConNode(type); tmp = gtNewSimdBinOpNode(GT_SUB, type, tmp, op1Dup1, simdBaseJitType, simdSize, isSimdAsHWIntrinsic); // result = ConditionalSelect(op1, tmp, op1Dup2) @@ -20386,6 +20313,7 @@ GenTree* Compiler::gtNewSimdCmpOpAllNode(genTreeOps op, op1 = gtNewSimdCmpOpNode(op, simdType, op1, op2, simdBaseJitType, simdSize, /* isSimdAsHWIntrinsic */ false); + op2 = gtNewAllBitsSetConNode(simdType); if (simdBaseType == TYP_FLOAT) { @@ -20397,8 +20325,6 @@ GenTree* Compiler::gtNewSimdCmpOpAllNode(genTreeOps op, simdBaseType = TYP_LONG; simdBaseJitType = CORINFO_TYPE_LONG; } - - op2 = gtNewAllBitsSetConNode(simdType, simdBaseJitType); break; } #elif defined(TARGET_ARM64) @@ -20427,6 +20353,7 @@ GenTree* Compiler::gtNewSimdCmpOpAllNode(genTreeOps op, op1 = gtNewSimdCmpOpNode(op, simdType, op1, op2, simdBaseJitType, simdSize, /* isSimdAsHWIntrinsic */ false); + op2 = gtNewAllBitsSetConNode(simdType); if (simdBaseType == TYP_FLOAT) { @@ -20438,8 +20365,6 @@ GenTree* Compiler::gtNewSimdCmpOpAllNode(genTreeOps op, simdBaseType = TYP_LONG; simdBaseJitType = CORINFO_TYPE_LONG; } - - op2 = gtNewAllBitsSetConNode(simdType, simdBaseJitType); break; } #else @@ -20510,6 +20435,7 @@ GenTree* Compiler::gtNewSimdCmpOpAnyNode(genTreeOps op, op1 = gtNewSimdCmpOpNode(op, simdType, op1, op2, simdBaseJitType, simdSize, /* isSimdAsHWIntrinsic */ false); + op2 = gtNewZeroConNode(simdType); if (simdBaseType == TYP_FLOAT) { @@ -20521,8 +20447,6 @@ GenTree* Compiler::gtNewSimdCmpOpAnyNode(genTreeOps op, simdBaseType = TYP_LONG; simdBaseJitType = CORINFO_TYPE_LONG; } - - op2 = gtNewZeroConNode(simdType, simdBaseJitType); break; } @@ -20555,6 +20479,7 @@ GenTree* Compiler::gtNewSimdCmpOpAnyNode(genTreeOps op, op1 = gtNewSimdCmpOpNode(op, simdType, op1, op2, simdBaseJitType, simdSize, /* isSimdAsHWIntrinsic */ false); + op2 = gtNewZeroConNode(simdType); if (simdBaseType == TYP_FLOAT) { @@ -20566,8 +20491,6 @@ GenTree* Compiler::gtNewSimdCmpOpAnyNode(genTreeOps op, simdBaseType = TYP_LONG; simdBaseJitType = CORINFO_TYPE_LONG; } - - op2 = gtNewZeroConNode(simdType, simdBaseJitType); break; } @@ -21641,7 +21564,7 @@ GenTree* Compiler::gtNewSimdShuffleNode(var_types type, { // AllBitsSet represents indices that are always "out of range" which means zero should be // selected for every element. We can special-case this down to just returning a zero node - return gtNewZeroConNode(type, simdBaseJitType); + return gtNewZeroConNode(type); } if (op2->IsVectorZero()) @@ -21760,7 +21683,7 @@ GenTree* Compiler::gtNewSimdShuffleNode(var_types type, GenTree* op1Lower = gtNewSimdHWIntrinsicNode(type, op1, NI_Vector256_GetLower, simdBaseJitType, simdSize, isSimdAsHWIntrinsic); - op2 = gtNewVconNode(TYP_SIMD16, simdBaseJitType); + op2 = gtNewVconNode(TYP_SIMD16); op2->AsVecCon()->gtSimd16Val = vecCns.v128[0]; op1Lower = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1Lower, op2, NI_SSSE3_Shuffle, simdBaseJitType, 16, @@ -21769,7 +21692,7 @@ GenTree* Compiler::gtNewSimdShuffleNode(var_types type, GenTree* op1Upper = gtNewSimdHWIntrinsicNode(type, op1Dup, gtNewIconNode(1), NI_AVX_ExtractVector128, simdBaseJitType, simdSize, isSimdAsHWIntrinsic); - op2 = gtNewVconNode(TYP_SIMD16, simdBaseJitType); + op2 = gtNewVconNode(TYP_SIMD16); op2->AsVecCon()->gtSimd16Val = vecCns.v128[1]; op1Upper = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1Upper, op2, NI_SSSE3_Shuffle, simdBaseJitType, 16, @@ -21786,7 +21709,7 @@ GenTree* Compiler::gtNewSimdShuffleNode(var_types type, vecCns.u32[i] = (uint8_t)(vecCns.u8[i * elementSize] / elementSize); } - op2 = gtNewVconNode(type, simdBaseJitType); + op2 = gtNewVconNode(type); op2->AsVecCon()->gtSimd32Val = vecCns; // swap the operands to match the encoding requirements @@ -21808,7 +21731,7 @@ GenTree* Compiler::gtNewSimdShuffleNode(var_types type, { simdBaseJitType = varTypeIsUnsigned(simdBaseType) ? CORINFO_TYPE_UBYTE : CORINFO_TYPE_BYTE; - op2 = gtNewVconNode(type, simdBaseJitType); + op2 = gtNewVconNode(type); op2->AsVecCon()->gtSimd16Val = vecCns.v128[0]; return gtNewSimdHWIntrinsicNode(type, op1, op2, NI_SSSE3_Shuffle, simdBaseJitType, simdSize, @@ -21855,10 +21778,10 @@ GenTree* Compiler::gtNewSimdShuffleNode(var_types type, { assert(!compIsaSupportedDebugOnly(InstructionSet_SSSE3)); - op2 = gtNewVconNode(type, simdBaseJitType); + op2 = gtNewVconNode(type); op2->AsVecCon()->gtSimd16Val = mskCns.v128[0]; - GenTree* zero = gtNewZeroConNode(type, simdBaseJitType); + GenTree* zero = gtNewZeroConNode(type); retNode = gtNewSimdCndSelNode(type, op2, retNode, zero, simdBaseJitType, simdSize, isSimdAsHWIntrinsic); } @@ -21900,7 +21823,7 @@ GenTree* Compiler::gtNewSimdShuffleNode(var_types type, // VectorTableLookup is only valid on byte/sbyte simdBaseJitType = varTypeIsUnsigned(simdBaseType) ? CORINFO_TYPE_UBYTE : CORINFO_TYPE_BYTE; - op2 = gtNewVconNode(type, simdBaseJitType); + op2 = gtNewVconNode(type); op2->AsVecCon()->gtSimd16Val = vecCns; return gtNewSimdHWIntrinsicNode(type, op1, op2, lookupIntrinsic, simdBaseJitType, simdSize, isSimdAsHWIntrinsic); @@ -22134,7 +22057,7 @@ GenTree* Compiler::gtNewSimdUnOpNode(genTreeOps op, assert(compIsaSupportedDebugOnly(InstructionSet_AVX)); assert(varTypeIsFloating(simdBaseType) || compIsaSupportedDebugOnly(InstructionSet_AVX2)); } - op2 = gtNewZeroConNode(type, simdBaseJitType); + op2 = gtNewZeroConNode(type); // Zero - op1 return gtNewSimdBinOpNode(GT_SUB, type, op2, op1, simdBaseJitType, simdSize, isSimdAsHWIntrinsic); @@ -22143,7 +22066,7 @@ GenTree* Compiler::gtNewSimdUnOpNode(genTreeOps op, case GT_NOT: { assert((simdSize != 32) || compIsaSupportedDebugOnly(InstructionSet_AVX)); - op2 = gtNewAllBitsSetConNode(type, simdBaseJitType); + op2 = gtNewAllBitsSetConNode(type); return gtNewSimdBinOpNode(GT_XOR, type, op1, op2, simdBaseJitType, simdSize, isSimdAsHWIntrinsic); } #elif defined(TARGET_ARM64) @@ -22169,7 +22092,7 @@ GenTree* Compiler::gtNewSimdUnOpNode(genTreeOps op, else { // Zero - op1 - op2 = gtNewZeroConNode(type, simdBaseJitType); + op2 = gtNewZeroConNode(type); return gtNewSimdBinOpNode(GT_SUB, type, op2, op1, simdBaseJitType, simdSize, isSimdAsHWIntrinsic); } } @@ -22296,7 +22219,7 @@ GenTree* Compiler::gtNewSimdWidenLowerNode( } else { - tmp1 = gtNewZeroConNode(type, simdBaseJitType); + tmp1 = gtNewZeroConNode(type); if (varTypeIsSigned(simdBaseType)) { @@ -22472,7 +22395,7 @@ GenTree* Compiler::gtNewSimdWidenUpperNode( } else { - tmp1 = gtNewZeroConNode(type, simdBaseJitType); + tmp1 = gtNewZeroConNode(type); if (varTypeIsSigned(simdBaseType)) { @@ -22535,7 +22458,7 @@ GenTree* Compiler::gtNewSimdWidenUpperNode( assert(intrinsic != NI_Illegal); tmp1 = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, intrinsic, simdBaseJitType, simdSize, isSimdAsHWIntrinsic); - zero = gtNewZeroConNode(TYP_SIMD16, simdBaseJitType); + zero = gtNewZeroConNode(TYP_SIMD16); tmp1 = gtNewSimdHWIntrinsicNode(TYP_SIMD16, tmp1, zero, gtNewIconNode(index), NI_AdvSimd_ExtractVector128, simdBaseJitType, 16, isSimdAsHWIntrinsic); return gtNewSimdHWIntrinsicNode(type, tmp1, NI_Vector128_GetLower, simdBaseJitType, simdSize, diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index 0658db6409138d..5ce4afae2e4409 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -3377,26 +3377,6 @@ struct GenTreeVecCon : public GenTree simd32_t gtSimd32Val; }; -private: - // TODO-1stClassStructs: Tracking the size and base type should be unnecessary since the - // size should be `gtType` and the handle should be looked up at callsites where required - - unsigned char gtSimdBaseJitType; // SIMD vector base JIT type - -public: - CorInfoType GetSimdBaseJitType() const - { - return (CorInfoType)gtSimdBaseJitType; - } - - void SetSimdBaseJitType(CorInfoType simdBaseJitType) - { - gtSimdBaseJitType = (unsigned char)simdBaseJitType; - assert(gtSimdBaseJitType == simdBaseJitType); - } - - var_types GetSimdBaseType() const; - #if defined(FEATURE_HW_INTRINSICS) static bool IsHWIntrinsicCreateConstant(GenTreeHWIntrinsic* node, simd32_t& simd32Val); @@ -3519,11 +3499,9 @@ struct GenTreeVecCon : public GenTree } } - GenTreeVecCon(var_types type, CorInfoType simdBaseJitType) - : GenTree(GT_CNS_VEC, type), gtSimdBaseJitType((unsigned char)simdBaseJitType) + GenTreeVecCon(var_types type) : GenTree(GT_CNS_VEC, type) { assert(varTypeIsSIMD(type)); - assert(gtSimdBaseJitType == simdBaseJitType); } #if DEBUGGABLE_GENTREE diff --git a/src/coreclr/jit/hwintrinsicarm64.cpp b/src/coreclr/jit/hwintrinsicarm64.cpp index 2523d3d9dd15d7..8f4734e0a909f0 100644 --- a/src/coreclr/jit/hwintrinsicarm64.cpp +++ b/src/coreclr/jit/hwintrinsicarm64.cpp @@ -595,7 +595,7 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, // We do this as it simplifies the logic and allows certain code paths to // have better codegen, such as for 0, AllBitsSet, or certain small constants - GenTreeVecCon* vecCon = gtNewVconNode(retType, simdBaseJitType); + GenTreeVecCon* vecCon = gtNewVconNode(retType); switch (simdBaseType) { @@ -968,7 +968,7 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, /* isSimdAsHWIntrinsic */ false); op1 = gtNewCastNode(TYP_INT, op1, /* isUnsigned */ true, TYP_INT); - GenTree* zero = gtNewZeroConNode(simdType, simdBaseJitType); + GenTree* zero = gtNewZeroConNode(simdType); ssize_t index = 8 / genTypeSize(simdBaseType); op2 = gtNewSimdHWIntrinsicNode(simdType, op2, zero, gtNewIconNode(index), NI_AdvSimd_ExtractVector128, @@ -1035,7 +1035,7 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, case NI_Vector128_get_AllBitsSet: { assert(sig->numArgs == 0); - retNode = gtNewAllBitsSetConNode(retType, simdBaseJitType); + retNode = gtNewAllBitsSetConNode(retType); break; } @@ -1043,7 +1043,7 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, case NI_Vector128_get_Zero: { assert(sig->numArgs == 0); - retNode = gtNewZeroConNode(retType, simdBaseJitType); + retNode = gtNewZeroConNode(retType); break; } @@ -1067,7 +1067,7 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, // AdvSimd.ExtractVector128(vector, Vector128.Zero, 8 / sizeof(T)).GetLower(); assert(numArgs == 1); op1 = impPopStack().val; - GenTree* zero = gtNewZeroConNode(retType, simdBaseJitType); + GenTree* zero = gtNewZeroConNode(retType); ssize_t index = 8 / genTypeSize(simdBaseType); retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, zero, gtNewIconNode(index), NI_AdvSimd_ExtractVector128, diff --git a/src/coreclr/jit/hwintrinsicxarch.cpp b/src/coreclr/jit/hwintrinsicxarch.cpp index e7a0ab3cda1c63..bee8e827f3a042 100644 --- a/src/coreclr/jit/hwintrinsicxarch.cpp +++ b/src/coreclr/jit/hwintrinsicxarch.cpp @@ -946,7 +946,7 @@ GenTree* Compiler::impBaseIntrinsic(NamedIntrinsic intrinsic, // We do this as it simplifies the logic and allows certain code paths to // have better codegen, such as for 0, AllBitsSet, or certain small constants - GenTreeVecCon* vecCon = gtNewVconNode(retType, simdBaseJitType); + GenTreeVecCon* vecCon = gtNewVconNode(retType); switch (simdBaseType) { @@ -1383,7 +1383,7 @@ GenTree* Compiler::impBaseIntrinsic(NamedIntrinsic intrinsic, case NI_Vector256_get_AllBitsSet: { assert(sig->numArgs == 0); - retNode = gtNewAllBitsSetConNode(retType, simdBaseJitType); + retNode = gtNewAllBitsSetConNode(retType); break; } @@ -1402,7 +1402,7 @@ GenTree* Compiler::impBaseIntrinsic(NamedIntrinsic intrinsic, case NI_Vector256_get_Zero: { assert(sig->numArgs == 0); - retNode = gtNewZeroConNode(retType, simdBaseJitType); + retNode = gtNewZeroConNode(retType); break; } diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 39ac0f5c6f18c9..993ee9fbddfeff 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -4526,7 +4526,7 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis, impPopStack(); impPopStack(); - GenTreeVecCon* vecCon = gtNewVconNode(TYP_SIMD16, callJitType); + GenTreeVecCon* vecCon = gtNewVconNode(TYP_SIMD16); if (callJitType == CORINFO_TYPE_FLOAT) { diff --git a/src/coreclr/jit/importer_vectorization.cpp b/src/coreclr/jit/importer_vectorization.cpp index 073eb4d1490b97..dea8b5c8bc36ae 100644 --- a/src/coreclr/jit/importer_vectorization.cpp +++ b/src/coreclr/jit/importer_vectorization.cpp @@ -236,7 +236,7 @@ GenTree* Compiler::impExpandHalfConstEqualsSIMD( return nullptr; } - GenTree* zero = gtNewZeroConNode(simdType, baseType); + GenTree* zero = gtNewZeroConNode(simdType); GenTree* offset1 = gtNewIconNode(dataOffset, TYP_I_IMPL); GenTree* offset2 = gtNewIconNode(dataOffset + len * sizeof(USHORT) - simdSize, TYP_I_IMPL); diff --git a/src/coreclr/jit/lclmorph.cpp b/src/coreclr/jit/lclmorph.cpp index b976cf6663a052..b344f37c09d878 100644 --- a/src/coreclr/jit/lclmorph.cpp +++ b/src/coreclr/jit/lclmorph.cpp @@ -993,7 +993,7 @@ class LocalAddressVisitor final : public GenTreeVisitor return IndirTransform::None; } - if (!varTypeIsStruct(indir)) + if (!indir->TypeIs(TYP_STRUCT)) { if (varDsc->lvPromoted) { @@ -1008,13 +1008,6 @@ class LocalAddressVisitor final : public GenTreeVisitor return IndirTransform::LclFld; } - if (varTypeIsSIMD(indir)) - { - // TODO-ADDR: Skip SIMD indirs for now, SIMD typed LCL_FLDs works most of the time - // but there are exceptions - fgMorphFieldAssignToSimdSetElement for example. - return IndirTransform::None; - } - ClassLayout* indirLayout = nullptr; if (indir->OperIs(GT_FIELD)) diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index 5bf930cc82f248..176828d17edd3d 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -3490,7 +3490,7 @@ void Lowering::LowerStoreLocCommon(GenTreeLclVarCommon* lclStore) #ifdef FEATURE_SIMD if (varTypeIsSIMD(lclRegType)) { - GenTree* zeroCon = comp->gtNewZeroConNode(lclRegType, CORINFO_TYPE_FLOAT); + GenTree* zeroCon = comp->gtNewZeroConNode(lclRegType); BlockRange().InsertAfter(src, zeroCon); BlockRange().Remove(src); diff --git a/src/coreclr/jit/lowerarmarch.cpp b/src/coreclr/jit/lowerarmarch.cpp index 451b91163b0cce..03b3e3985d26ba 100644 --- a/src/coreclr/jit/lowerarmarch.cpp +++ b/src/coreclr/jit/lowerarmarch.cpp @@ -1312,7 +1312,7 @@ GenTree* Lowering::LowerHWIntrinsicCreate(GenTreeHWIntrinsic* node) BlockRange().Remove(arg); } - GenTreeVecCon* vecCon = comp->gtNewVconNode(simdType, simdBaseJitType); + GenTreeVecCon* vecCon = comp->gtNewVconNode(simdType); vecCon->gtSimd32Val = simd32Val; BlockRange().InsertBefore(node, vecCon); diff --git a/src/coreclr/jit/lowerxarch.cpp b/src/coreclr/jit/lowerxarch.cpp index 3ef7660e6fa115..282a5713c80780 100644 --- a/src/coreclr/jit/lowerxarch.cpp +++ b/src/coreclr/jit/lowerxarch.cpp @@ -1614,7 +1614,7 @@ GenTree* Lowering::LowerHWIntrinsicCreate(GenTreeHWIntrinsic* node) BlockRange().Remove(arg); } - GenTreeVecCon* vecCon = comp->gtNewVconNode(simdType, simdBaseJitType); + GenTreeVecCon* vecCon = comp->gtNewVconNode(simdType); vecCon->gtSimd32Val = simd32Val; BlockRange().InsertBefore(node, vecCon); @@ -1760,7 +1760,7 @@ GenTree* Lowering::LowerHWIntrinsicCreate(GenTreeHWIntrinsic* node) // var tmp2 = Vector128.Zero; // return Ssse3.Shuffle(tmp1, tmp2); - tmp2 = comp->gtNewZeroConNode(simdType, simdBaseJitType); + tmp2 = comp->gtNewZeroConNode(simdType); BlockRange().InsertAfter(tmp1, tmp2); LowerNode(tmp2); @@ -3393,7 +3393,7 @@ GenTree* Lowering::LowerHWIntrinsicDot(GenTreeHWIntrinsic* node) // op1 = Sse.And(op1, tmp1); // ... - GenTreeVecCon* vecCon1 = comp->gtNewVconNode(simdType, simdBaseJitType); + GenTreeVecCon* vecCon1 = comp->gtNewVconNode(simdType); vecCon1->gtSimd16Val = simd16Val; BlockRange().InsertAfter(op1, vecCon1); @@ -3422,7 +3422,7 @@ GenTree* Lowering::LowerHWIntrinsicDot(GenTreeHWIntrinsic* node) // op2 = Sse.And(op2, tmp2); // ... - GenTreeVecCon* vecCon2 = comp->gtNewVconNode(simdType, simdBaseJitType); + GenTreeVecCon* vecCon2 = comp->gtNewVconNode(simdType); vecCon2->gtSimd16Val = simd16Val; BlockRange().InsertAfter(op2, vecCon2); diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index ef932bbe2489c2..b99ec4e14797df 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -4807,7 +4807,7 @@ GenTree* Compiler::fgMorphExpandStackArgForVarArgs(GenTreeLclVarCommon* lclNode) } GenTree* argNode; - if (varTypeIsStruct(lclNode)) + if (lclNode->TypeIs(TYP_STRUCT)) { argNode = gtNewObjNode(lclNode->GetLayout(this), argAddr); } @@ -4887,7 +4887,7 @@ GenTree* Compiler::fgMorphExpandImplicitByRefArg(GenTreeLclVarCommon* lclNode) unsigned offset = lclNode->GetLclOffs() + fieldOffset; var_types argNodeType = lclNode->TypeGet(); ClassLayout* argNodeLayout = nullptr; - if (varTypeIsStruct(argNodeType)) + if (argNodeType == TYP_STRUCT) { argNodeLayout = lclNode->GetLayout(this); } @@ -4909,7 +4909,7 @@ GenTree* Compiler::fgMorphExpandImplicitByRefArg(GenTreeLclVarCommon* lclNode) GenTree* newArgNode; if (!isAddress) { - if (varTypeIsStruct(argNodeType)) + if (argNodeType == TYP_STRUCT) { newArgNode = gtNewObjNode(argNodeLayout, addrNode); } @@ -9158,7 +9158,7 @@ GenTree* Compiler::fgMorphOneAsgBlockOp(GenTree* tree) noway_assert(src->IsIntegralConst(0)); noway_assert(destVarDsc != nullptr); - src = gtNewZeroConNode(asgType, CORINFO_TYPE_FLOAT); + src = gtNewZeroConNode(asgType); } else #endif @@ -12361,7 +12361,7 @@ GenTree* Compiler::fgOptimizeHWIntrinsic(GenTreeHWIntrinsic* node) if (GenTreeVecCon::IsHWIntrinsicCreateConstant(node, simd32Val)) { - GenTreeVecCon* vecCon = gtNewVconNode(node->TypeGet(), node->GetSimdBaseJitType()); + GenTreeVecCon* vecCon = gtNewVconNode(node->TypeGet()); for (GenTree* arg : node->Operands()) { diff --git a/src/coreclr/jit/morphblock.cpp b/src/coreclr/jit/morphblock.cpp index 662e527bc8ccf1..288f55657cc4d0 100644 --- a/src/coreclr/jit/morphblock.cpp +++ b/src/coreclr/jit/morphblock.cpp @@ -363,7 +363,7 @@ void MorphInitBlockHelper::MorphStructCases() if (varTypeIsSIMD(m_asg) && (m_dst == m_dstLclNode) && m_src->IsIntegralConst(0)) { assert(m_dstVarDsc != nullptr); - m_src = m_comp->gtNewZeroConNode(m_asg->TypeGet(), CORINFO_TYPE_FLOAT); + m_src = m_comp->gtNewZeroConNode(m_asg->TypeGet()); m_result->AsOp()->gtOp2 = m_src; } #endif // FEATURE_SIMD @@ -655,18 +655,15 @@ void MorphInitBlockHelper::TryInitFieldByField() break; case TYP_REF: case TYP_BYREF: - assert(initPattern == 0); - src = m_comp->gtNewZeroConNode(fieldType); - break; #ifdef FEATURE_SIMD case TYP_SIMD8: case TYP_SIMD12: case TYP_SIMD16: case TYP_SIMD32: +#endif // FEATURE_SIMD assert(initPattern == 0); - src = m_comp->gtNewZeroConNode(fieldType, CORINFO_TYPE_FLOAT); + src = m_comp->gtNewZeroConNode(fieldType); break; -#endif // FEATURE_SIMD default: unreached(); } diff --git a/src/coreclr/jit/rationalize.cpp b/src/coreclr/jit/rationalize.cpp index 981df75d0a0f44..7e2b2376391f8d 100644 --- a/src/coreclr/jit/rationalize.cpp +++ b/src/coreclr/jit/rationalize.cpp @@ -432,7 +432,7 @@ void Rationalizer::RewriteAssignment(LIR::Use& use) if (initVal->IsIntegralConst(0)) { - GenTree* zeroCon = comp->gtNewZeroConNode(simdType, simdBaseJitType); + GenTree* zeroCon = comp->gtNewZeroConNode(simdType); assignment->gtOp2 = zeroCon; value = zeroCon; diff --git a/src/coreclr/jit/simd.cpp b/src/coreclr/jit/simd.cpp index 1682c43461fb9c..7c16993e4e16d0 100644 --- a/src/coreclr/jit/simd.cpp +++ b/src/coreclr/jit/simd.cpp @@ -910,6 +910,30 @@ CorInfoType Compiler::getBaseJitTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeH if (simdBaseJitType != CORINFO_TYPE_UNDEF) { setUsesSIMDTypes(true); + + CORINFO_CLASS_HANDLE* pCanonicalHnd = nullptr; + switch (size) + { + case 8: + pCanonicalHnd = &m_simdHandleCache->CanonicalSimd8Handle; + break; + case 12: + // There is no need for a canonical SIMD12 handle because it is always Vector3. + break; + case 16: + pCanonicalHnd = &m_simdHandleCache->CanonicalSimd16Handle; + break; + case 32: + pCanonicalHnd = &m_simdHandleCache->CanonicalSimd32Handle; + break; + default: + unreached(); + } + + if ((pCanonicalHnd != nullptr) && (*pCanonicalHnd == NO_CLASS_HANDLE)) + { + *pCanonicalHnd = typeHnd; + } } return simdBaseJitType; diff --git a/src/coreclr/jit/simdashwintrinsic.cpp b/src/coreclr/jit/simdashwintrinsic.cpp index 6d9da02d0bb9b3..dce3bb604c46cd 100644 --- a/src/coreclr/jit/simdashwintrinsic.cpp +++ b/src/coreclr/jit/simdashwintrinsic.cpp @@ -559,7 +559,7 @@ GenTree* Compiler::impSimdAsHWIntrinsicSpecial(NamedIntrinsic intrinsic, case NI_VectorT128_get_AllBitsSet: case NI_VectorT256_get_AllBitsSet: { - return gtNewAllBitsSetConNode(retType, simdBaseJitType); + return gtNewAllBitsSetConNode(retType); } case NI_VectorT128_get_Count: @@ -576,7 +576,7 @@ GenTree* Compiler::impSimdAsHWIntrinsicSpecial(NamedIntrinsic intrinsic, case NI_VectorT128_get_One: case NI_VectorT256_get_One: { - GenTreeVecCon* vecCon = gtNewVconNode(retType, simdBaseJitType); + GenTreeVecCon* vecCon = gtNewVconNode(retType); uint32_t simdLength = getSIMDVectorLength(simdSize, simdBaseType); switch (simdBaseType) @@ -654,12 +654,12 @@ GenTree* Compiler::impSimdAsHWIntrinsicSpecial(NamedIntrinsic intrinsic, case NI_VectorT128_get_Zero: case NI_VectorT256_get_Zero: { - return gtNewZeroConNode(retType, simdBaseJitType); + return gtNewZeroConNode(retType); } #elif defined(TARGET_ARM64) case NI_VectorT128_get_AllBitsSet: { - return gtNewAllBitsSetConNode(retType, simdBaseJitType); + return gtNewAllBitsSetConNode(retType); } case NI_VectorT128_get_Count: @@ -674,7 +674,7 @@ GenTree* Compiler::impSimdAsHWIntrinsicSpecial(NamedIntrinsic intrinsic, case NI_Vector4_get_One: case NI_VectorT128_get_One: { - GenTreeVecCon* vecCon = gtNewVconNode(retType, simdBaseJitType); + GenTreeVecCon* vecCon = gtNewVconNode(retType); uint32_t simdLength = getSIMDVectorLength(simdSize, simdBaseType); switch (simdBaseType) @@ -751,7 +751,7 @@ GenTree* Compiler::impSimdAsHWIntrinsicSpecial(NamedIntrinsic intrinsic, case NI_Vector4_get_Zero: case NI_VectorT128_get_Zero: { - return gtNewZeroConNode(retType, simdBaseJitType); + return gtNewZeroConNode(retType); } #else #error Unsupported platform