From fab62634aa40d1996c7e0e4db616e27c240e47ae Mon Sep 17 00:00:00 2001 From: Sebastian Nickolls Date: Tue, 23 Sep 2025 08:49:18 +0000 Subject: [PATCH 01/12] Directly map SIMD types from class names Current implementation derives a size based on the identified SIMD type, and then uses the size to derive the node type. It should instead directly derive the node type from the identified SIMD type, because some SIMD types will not have a statically known size, and this size may conflict with other SIMD types. --- src/coreclr/jit/compiler.h | 4 + src/coreclr/jit/gentree.cpp | 144 +++++++++----------- src/coreclr/jit/hwintrinsic.cpp | 35 ++--- src/coreclr/jit/hwintrinsicarm64.cpp | 4 +- src/coreclr/jit/importer.cpp | 10 +- src/coreclr/jit/lclvars.cpp | 11 +- src/coreclr/jit/simd.cpp | 193 +++++++++++++++++---------- 7 files changed, 208 insertions(+), 193 deletions(-) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index e7f3dae76f4102..b71d1e270ba9bc 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -9079,6 +9079,10 @@ class Compiler return isSIMDClass(clsHnd) || isHWSIMDClass(clsHnd); } + var_types getSIMDType(CORINFO_CLASS_HANDLE typeHnd, CorInfoType* baseType = nullptr); + + unsigned getSizeOfSIMDType(var_types simdType); + // Get the base (element) type and size in bytes for a SIMD type. Returns CORINFO_TYPE_UNDEF // if it is not a SIMD type or is an unsupported base JIT type. CorInfoType getBaseJitTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeHnd, unsigned* sizeBytes = nullptr); diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 0178826d918017..5e2da75aa353c6 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -20925,7 +20925,7 @@ GenTreeHWIntrinsic* Compiler::gtNewSimdHWIntrinsicNode(var_types ty GenTree* Compiler::gtNewSimdAbsNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeGet() == type); @@ -21018,7 +21018,7 @@ GenTree* Compiler::gtNewSimdBinOpNode( genTreeOps op, var_types type, GenTree* op1, GenTree* op2, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType); assert(varTypeIsArithmetic(simdBaseType)); @@ -21732,7 +21732,7 @@ GenTree* Compiler::gtNewSimdBinOpNode( GenTree* Compiler::gtNewSimdCeilNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -21812,7 +21812,7 @@ GenTree* Compiler::gtNewSimdCvtNode(var_types type, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -21948,7 +21948,7 @@ GenTree* Compiler::gtNewSimdCvtNativeNode(var_types type, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -22200,7 +22200,7 @@ GenTree* Compiler::gtNewSimdCmpOpNode( genTreeOps op, var_types type, GenTree* op1, GenTree* op2, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -22489,12 +22489,11 @@ GenTree* Compiler::gtNewSimdCmpOpAllNode( genTreeOps op, var_types type, GenTree* op1, GenTree* op2, CorInfoType simdBaseJitType, unsigned simdSize) { assert(type == TYP_INT); + assert(op1 != nullptr); - var_types simdType = getSIMDTypeForSize(simdSize); + var_types simdType = op1->TypeGet(); assert(varTypeIsSIMD(simdType)); - - assert(op1 != nullptr); - assert(op1->TypeIs(simdType)); + assert(getSizeOfSIMDType(simdType) == simdSize); assert(op2 != nullptr); assert(op2->TypeIs(simdType)); @@ -22624,11 +22623,10 @@ GenTree* Compiler::gtNewSimdCmpOpAnyNode( { assert(type == TYP_INT); - var_types simdType = getSIMDTypeForSize(simdSize); - assert(varTypeIsSIMD(simdType)); - assert(op1 != nullptr); - assert(op1->TypeIs(simdType)); + var_types simdType = op1->TypeGet(); + assert(varTypeIsSIMD(simdType)); + assert(getSizeOfSIMDType(simdType) == simdSize); assert(op2 != nullptr); assert(op2->TypeIs(simdType)); @@ -22754,7 +22752,7 @@ GenTree* Compiler::gtNewSimdCndSelNode( var_types type, GenTree* op1, GenTree* op2, GenTree* op3, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -23179,7 +23177,7 @@ GenTree* Compiler::gtNewSimdCreateSequenceNode( // is constant than there isn't any real optimization we can do and we need the full computation. assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType); assert(varTypeIsArithmetic(simdBaseType)); @@ -23350,14 +23348,14 @@ GenTree* Compiler::gtNewSimdCreateSequenceNode( GenTree* Compiler::gtNewSimdDotProdNode( var_types type, GenTree* op1, GenTree* op2, CorInfoType simdBaseJitType, unsigned simdSize) { - var_types simdType = getSIMDTypeForSize(simdSize); - assert(varTypeIsSIMD(simdType)); + assert(varTypeIsSIMD(type)); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); - assert(op1->TypeIs(simdType)); + assert(op1->TypeIs(type)); assert(op2 != nullptr); - assert(op2->TypeIs(simdType)); + assert(op2->TypeIs(type)); var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType); assert(varTypeIsSIMD(type)); @@ -23391,7 +23389,7 @@ GenTree* Compiler::gtNewSimdDotProdNode( GenTree* Compiler::gtNewSimdFloorNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -23436,7 +23434,7 @@ GenTree* Compiler::gtNewSimdFmaNode( var_types type, GenTree* op1, GenTree* op2, GenTree* op3, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -23551,7 +23549,7 @@ GenTree* Compiler::gtNewSimdGetElementNode( GenTree* Compiler::gtNewSimdGetIndicesNode(var_types type, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType); assert(varTypeIsArithmetic(simdBaseType)); @@ -23704,7 +23702,7 @@ GenTree* Compiler::gtNewSimdIsEvenIntegerNode(var_types type, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -23731,7 +23729,7 @@ GenTree* Compiler::gtNewSimdIsEvenIntegerNode(var_types type, GenTree* Compiler::gtNewSimdIsFiniteNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -23782,7 +23780,7 @@ GenTree* Compiler::gtNewSimdIsFiniteNode(var_types type, GenTree* op1, CorInfoTy GenTree* Compiler::gtNewSimdIsInfinityNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -23813,7 +23811,7 @@ GenTree* Compiler::gtNewSimdIsInfinityNode(var_types type, GenTree* op1, CorInfo GenTree* Compiler::gtNewSimdIsIntegerNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -23853,7 +23851,7 @@ GenTree* Compiler::gtNewSimdIsIntegerNode(var_types type, GenTree* op1, CorInfoT GenTree* Compiler::gtNewSimdIsNaNNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -23884,7 +23882,7 @@ GenTree* Compiler::gtNewSimdIsNaNNode(var_types type, GenTree* op1, CorInfoType GenTree* Compiler::gtNewSimdIsNegativeNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -23926,7 +23924,7 @@ GenTree* Compiler::gtNewSimdIsNegativeInfinityNode(var_types type, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -23974,7 +23972,7 @@ GenTree* Compiler::gtNewSimdIsNegativeInfinityNode(var_types type, GenTree* Compiler::gtNewSimdIsNormalNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -24037,7 +24035,7 @@ GenTree* Compiler::gtNewSimdIsOddIntegerNode(var_types type, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -24064,7 +24062,7 @@ GenTree* Compiler::gtNewSimdIsOddIntegerNode(var_types type, GenTree* Compiler::gtNewSimdIsPositiveNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -24106,7 +24104,7 @@ GenTree* Compiler::gtNewSimdIsPositiveInfinityNode(var_types type, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -24157,7 +24155,7 @@ GenTree* Compiler::gtNewSimdIsSubnormalNode(var_types type, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -24214,7 +24212,7 @@ GenTree* Compiler::gtNewSimdIsSubnormalNode(var_types type, GenTree* Compiler::gtNewSimdIsZeroNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -24240,7 +24238,7 @@ GenTree* Compiler::gtNewSimdIsZeroNode(var_types type, GenTree* op1, CorInfoType GenTree* Compiler::gtNewSimdLoadNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); @@ -24435,7 +24433,7 @@ GenTree* Compiler::gtNewSimdMinMaxNode(var_types type, else if (!varTypeIsLong(simdBaseType)) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); } NamedIntrinsic intrinsic = NI_Illegal; @@ -25077,7 +25075,7 @@ GenTree* Compiler::gtNewSimdMinMaxNativeNode( else { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); } NamedIntrinsic intrinsic = NI_Illegal; @@ -25190,7 +25188,7 @@ GenTree* Compiler::gtNewSimdNarrowNode( var_types type, GenTree* op1, GenTree* op2, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -25662,7 +25660,7 @@ GenTree* Compiler::gtNewSimdNarrowNode( GenTree* Compiler::gtNewSimdRoundNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -25723,7 +25721,7 @@ GenTree* Compiler::gtNewSimdShuffleVariableNode( var_types type, GenTree* op1, GenTree* op2, CorInfoType simdBaseJitType, unsigned simdSize, bool isShuffleNative) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -26326,7 +26324,7 @@ GenTree* Compiler::gtNewSimdShuffleNode( var_types type, GenTree* op1, GenTree* op2, CorInfoType simdBaseJitType, unsigned simdSize, bool isShuffleNative) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -26909,7 +26907,7 @@ GenTree* Compiler::gtNewSimdShuffleNode( GenTree* Compiler::gtNewSimdSqrtNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -26967,7 +26965,7 @@ GenTree* Compiler::gtNewSimdStoreNode(GenTree* op1, GenTree* op2, CorInfoType si assert(op2 != nullptr); assert(varTypeIsSIMD(op2)); - assert(getSIMDTypeForSize(simdSize) == op2->TypeGet()); + assert(getSizeOfSIMDType(op2->TypeGet()) == simdSize); var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType); assert(varTypeIsArithmetic(simdBaseType)); @@ -27084,11 +27082,10 @@ GenTree* Compiler::gtNewSimdStoreNonTemporalNode(GenTree* op1, GenTree* Compiler::gtNewSimdSumNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { - var_types simdType = getSIMDTypeForSize(simdSize); - assert(varTypeIsSIMD(simdType)); - assert(op1 != nullptr); - assert(op1->TypeIs(simdType)); + var_types simdType = op1->TypeGet(); + assert(varTypeIsSIMD(simdType)); + assert(getSizeOfSIMDType(simdType) == simdSize); var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType); assert(varTypeIsArithmetic(simdBaseType)); @@ -27416,7 +27413,7 @@ GenTree* Compiler::gtNewSimdToScalarNode(var_types type, GenTree* op1, CorInfoTy GenTree* Compiler::gtNewSimdTruncNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -27461,7 +27458,7 @@ GenTree* Compiler::gtNewSimdUnOpNode( genTreeOps op, var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -27556,7 +27553,7 @@ GenTree* Compiler::gtNewSimdUnOpNode( GenTree* Compiler::gtNewSimdWidenLowerNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -27752,7 +27749,7 @@ GenTree* Compiler::gtNewSimdWidenLowerNode(var_types type, GenTree* op1, CorInfo GenTree* Compiler::gtNewSimdWidenUpperNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -28078,15 +28075,15 @@ GenTreeFieldList* Compiler::gtConvertParamOpToFieldList(GenTree* op, unsigned fi unsigned fieldSize = opVarDsc->lvExactSize() / fieldCount; GenTreeFieldList* fieldList = new (this, GT_FIELD_LIST) GenTreeFieldList(); int offset = 0; - unsigned sizeBytes = 0; CORINFO_CLASS_HANDLE structType; for (unsigned fieldId = 0; fieldId < fieldCount; fieldId++) { CORINFO_FIELD_HANDLE fieldHandle = info.compCompHnd->getFieldInClass(clsHnd, fieldId); JitType2PreciseVarType(info.compCompHnd->getFieldType(fieldHandle, &structType)); - getBaseJitTypeAndSizeOfSIMDType(structType, &sizeBytes); - var_types simdType = getSIMDTypeForSize(sizeBytes); + + unsigned int size = info.compCompHnd->getClassSize(structType); + var_types simdType = getSIMDTypeForSize(size); GenTreeLclFld* fldNode = gtNewLclFldNode(lclNum, simdType, offset); fieldList->AddField(this, fldNode, offset, simdType); @@ -29626,10 +29623,8 @@ genTreeOps GenTreeHWIntrinsic::GetOperForHWIntrinsicId(NamedIntrinsic id, var_ty NamedIntrinsic GenTreeHWIntrinsic::GetHWIntrinsicIdForUnOp( Compiler* comp, genTreeOps oper, GenTree* op1, var_types simdBaseType, unsigned simdSize, bool isScalar) { - var_types simdType = comp->getSIMDTypeForSize(simdSize); assert(varTypeIsArithmetic(simdBaseType)); - assert(varTypeIsSIMD(simdType)); #if defined(TARGET_XARCH) if ((simdSize == 64) || (simdSize == 32)) @@ -29647,7 +29642,9 @@ NamedIntrinsic GenTreeHWIntrinsic::GetHWIntrinsicIdForUnOp( } assert(op1 != nullptr); - assert(op1->TypeIs(simdType)); + var_types simdType = op1->TypeGet(); + assert(varTypeIsSIMD(simdType)); + assert(comp->getSizeOfSIMDType(simdType) == simdSize); NamedIntrinsic id = NI_Illegal; @@ -29720,13 +29717,12 @@ NamedIntrinsic GenTreeHWIntrinsic::GetHWIntrinsicIdForBinOp(Compiler* comp, unsigned simdSize, bool isScalar) { - var_types simdType = comp->getSIMDTypeForSize(simdSize); - assert(varTypeIsArithmetic(simdBaseType)); - assert(varTypeIsSIMD(simdType)); assert(op1 != nullptr); - assert(op1->TypeIs(simdType)); + var_types simdType = op1->TypeGet(); + assert(varTypeIsSIMD(simdType)); + assert(comp->getSizeOfSIMDType(simdType) == simdSize); assert(op2 != nullptr); #if defined(TARGET_XARCH) @@ -30293,16 +30289,14 @@ NamedIntrinsic GenTreeHWIntrinsic::GetHWIntrinsicIdForCmpOp(Compiler* comp, bool isScalar, bool reverseCond) { - var_types simdType = comp->getSIMDTypeForSize(simdSize); + assert(op1 != nullptr); + assert(op2 != nullptr); + var_types simdType = op1->TypeGet(); + assert(comp->getSizeOfSIMDType(simdType) == simdSize); assert(varTypeIsMask(type) || (type == simdType)); - assert(varTypeIsArithmetic(simdBaseType)); assert(varTypeIsSIMD(simdType)); - assert(op1 != nullptr); - assert(op1->TypeIs(simdType)); - assert(op2 != nullptr); - #if defined(TARGET_XARCH) if (varTypeIsMask(type)) { @@ -30634,11 +30628,9 @@ NamedIntrinsic GenTreeHWIntrinsic::GetHWIntrinsicIdForCmpOp(Compiler* comp, var_types GenTreeHWIntrinsic::GetLookupTypeForCmpOp( Compiler* comp, genTreeOps oper, var_types type, var_types simdBaseType, unsigned simdSize, bool reverseCond) { - var_types simdType = comp->getSIMDTypeForSize(simdSize); - assert(varTypeIsMask(type) || (type == simdType)); - + assert(varTypeIsMask(type) || varTypeIsSIMD(type)); assert(varTypeIsArithmetic(simdBaseType)); - assert(varTypeIsSIMD(simdType)); + assert(comp->getSizeOfSIMDType(type) == simdSize); var_types lookupType = type; @@ -32479,8 +32471,6 @@ GenTree* Compiler::gtFoldExprHWIntrinsic(GenTreeHWIntrinsic* tree) case NI_Vector512_ToScalar: #endif { - var_types simdType = getSIMDTypeForSize(simdSize); - if (varTypeIsFloating(retType)) { double result = cnsNode->AsVecCon()->ToScalarFloating(simdBaseType); @@ -32740,8 +32730,6 @@ GenTree* Compiler::gtFoldExprHWIntrinsic(GenTreeHWIntrinsic* tree) break; } - var_types simdType = getSIMDTypeForSize(simdSize); - if (varTypeIsFloating(retType)) { double result = cnsNode->AsVecCon()->GetElementFloating(simdBaseType, index); @@ -33684,8 +33672,6 @@ GenTree* Compiler::gtFoldExprHWIntrinsic(GenTreeHWIntrinsic* tree) break; } - var_types simdType = getSIMDTypeForSize(simdSize); - if (varTypeIsFloating(simdBaseType)) { double value = op3->AsDblCon()->DconValue(); diff --git a/src/coreclr/jit/hwintrinsic.cpp b/src/coreclr/jit/hwintrinsic.cpp index 83909542992db3..5a4ed811abdcc1 100644 --- a/src/coreclr/jit/hwintrinsic.cpp +++ b/src/coreclr/jit/hwintrinsic.cpp @@ -1502,9 +1502,7 @@ GenTree* Compiler::getArgForHWIntrinsic(var_types argType, CORINFO_CLASS_HANDLE { if (!varTypeIsSIMD(argType)) { - unsigned int argSizeBytes; - (void)getBaseJitTypeAndSizeOfSIMDType(argClass, &argSizeBytes); - argType = getSIMDTypeForSize(argSizeBytes); + argType = getSIMDType(argClass); } assert(varTypeIsSIMD(argType)); @@ -1889,29 +1887,20 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic, CorInfoType simdBaseJitType = CORINFO_TYPE_UNDEF; GenTree* retNode = nullptr; - if (retType == TYP_STRUCT) + if (retType == TYP_STRUCT && !HWIntrinsicInfo::IsMultiReg(intrinsic)) { - unsigned int sizeBytes; - simdBaseJitType = getBaseJitTypeAndSizeOfSIMDType(sig->retTypeSigClass, &sizeBytes); - - if (HWIntrinsicInfo::IsMultiReg(intrinsic)) - { - assert(sizeBytes == 0); - } + retType = impNormStructType(sig->retTypeSigClass, &simdBaseJitType); #ifdef TARGET_ARM64 - else if ((intrinsic == NI_AdvSimd_LoadAndInsertScalar) || (intrinsic == NI_AdvSimd_Arm64_LoadAndInsertScalar)) + if ((intrinsic == NI_AdvSimd_LoadAndInsertScalar) || (intrinsic == NI_AdvSimd_Arm64_LoadAndInsertScalar)) { - CorInfoType pSimdBaseJitType = CORINFO_TYPE_UNDEF; - var_types retFieldType = impNormStructType(sig->retTypeSigClass, &pSimdBaseJitType); - - if (retFieldType == TYP_STRUCT) + if (retType == TYP_STRUCT) { CORINFO_CLASS_HANDLE structType; unsigned int sizeBytes = 0; // LoadAndInsertScalar that returns 2,3 or 4 vectors - assert(pSimdBaseJitType == CORINFO_TYPE_UNDEF); + assert(simdBaseJitType == CORINFO_TYPE_UNDEF); unsigned fieldCount = info.compCompHnd->getClassNumInstanceFields(sig->retTypeSigClass); assert(fieldCount > 1); CORINFO_FIELD_HANDLE fieldHandle = info.compCompHnd->getFieldInClass(sig->retTypeClass, 0); @@ -1937,24 +1926,20 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic, } else { - assert((retFieldType == TYP_SIMD8) || (retFieldType == TYP_SIMD16)); + assert((retType == TYP_SIMD8) || (retType == TYP_SIMD16)); assert(isSupportedBaseType(intrinsic, simdBaseJitType)); - retType = getSIMDTypeForSize(sizeBytes); } } -#endif else - { +#endif // We want to return early here for cases where retType was TYP_STRUCT as per method signature and // rather than deferring the decision after getting the simdBaseJitType of arg. - if (!isSupportedBaseType(intrinsic, simdBaseJitType)) + if (retType == TYP_UNDEF || !isSupportedBaseType(intrinsic, simdBaseJitType)) { return nullptr; } - assert(sizeBytes != 0); - retType = getSIMDTypeForSize(sizeBytes); - } + assert((varTypeIsSIMD(retType) || varTypeIsStruct(retType)) && isSupportedBaseType(intrinsic, simdBaseJitType)); } simdBaseJitType = getBaseJitTypeFromArgIfNeeded(intrinsic, sig, simdBaseJitType); diff --git a/src/coreclr/jit/hwintrinsicarm64.cpp b/src/coreclr/jit/hwintrinsicarm64.cpp index 7e73e3e2fee48c..9a89ac905074cf 100644 --- a/src/coreclr/jit/hwintrinsicarm64.cpp +++ b/src/coreclr/jit/hwintrinsicarm64.cpp @@ -1339,12 +1339,10 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, if (!varTypeIsLong(simdBaseType)) { - var_types simdType = getSIMDTypeForSize(simdSize); - op2 = impSIMDPopStack(); op1 = impSIMDPopStack(); - retNode = gtNewSimdDotProdNode(simdType, op1, op2, simdBaseJitType, simdSize); + retNode = gtNewSimdDotProdNode(op1->TypeGet(), op1, op2, simdBaseJitType, simdSize); retNode = gtNewSimdGetElementNode(retType, retNode, gtNewIconNode(0), simdBaseJitType, simdSize); } break; diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 3bd72cb08e609a..c0b28d6b74654a 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -1185,12 +1185,12 @@ var_types Compiler::impNormStructType(CORINFO_CLASS_HANDLE structHnd, CorInfoTyp if (structSizeMightRepresentSIMDType(originalSize)) { - unsigned int sizeBytes; - CorInfoType simdBaseJitType = getBaseJitTypeAndSizeOfSIMDType(structHnd, &sizeBytes); - if (simdBaseJitType != CORINFO_TYPE_UNDEF) + CorInfoType simdBaseJitType = CORINFO_TYPE_UNDEF; + var_types simdType = getSIMDType(structHnd, &simdBaseJitType); + if (simdBaseJitType != CORINFO_TYPE_UNDEF && simdType != TYP_UNDEF) { - assert(sizeBytes == originalSize); - structType = getSIMDTypeForSize(sizeBytes); + assert(getSizeOfSIMDType(simdType) == originalSize); + structType = simdType; if (pSimdBaseJitType != nullptr) { *pSimdBaseJitType = simdBaseJitType; diff --git a/src/coreclr/jit/lclvars.cpp b/src/coreclr/jit/lclvars.cpp index 4e6b559c989baf..02ad1bced19fd5 100644 --- a/src/coreclr/jit/lclvars.cpp +++ b/src/coreclr/jit/lclvars.cpp @@ -1435,15 +1435,10 @@ var_types Compiler::StructPromotionHelper::TryPromoteValueClassAsPrimitive(CORIN #ifdef FEATURE_SIMD if (compiler->isRuntimeIntrinsicsNamespace(namespaceName) || compiler->isNumericsNamespace(namespaceName)) { - unsigned simdSize; - CorInfoType simdBaseJitType = compiler->getBaseJitTypeAndSizeOfSIMDType(node.simdTypeHnd, &simdSize); - // We will only promote fields of SIMD types that fit into a SIMD register. - if (simdBaseJitType != CORINFO_TYPE_UNDEF) + var_types type = compiler->getSIMDType(node.simdTypeHnd); + if (type != TYP_UNDEF) { - if (compiler->structSizeMightRepresentSIMDType(simdSize)) - { - return compiler->getSIMDTypeForSize(simdSize); - } + return type; } } #endif diff --git a/src/coreclr/jit/simd.cpp b/src/coreclr/jit/simd.cpp index 7fdbd76afb0081..d4e4ba31f5bb5a 100644 --- a/src/coreclr/jit/simd.cpp +++ b/src/coreclr/jit/simd.cpp @@ -153,32 +153,21 @@ unsigned Compiler::getFFRegisterVarNum() } #endif -//---------------------------------------------------------------------------------- -// Return the base type and size of SIMD vector type given its type handle. -// -// Arguments: -// typeHnd - The handle of the type we're interested in. -// sizeBytes - out param -// -// Return Value: -// base type of SIMD vector. -// sizeBytes if non-null is set to size in bytes. -// -// Notes: -// If the size of the struct is already known call structSizeMightRepresentSIMDType -// to determine if this api needs to be called. -// -// The type handle passed here can only be used in a subset of JIT-EE calls -// since it may be called by promotion during AOT of a method that does -// not version with SPC. See CORINFO_TYPE_LAYOUT_NODE for the contract on -// the supported JIT-EE calls. -// -// TODO-Throughput: current implementation parses class name to find base type. Change -// this when we implement SIMD intrinsic identification for the final -// product. -// -CorInfoType Compiler::getBaseJitTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeHnd, unsigned* sizeBytes /*= nullptr */) +var_types Compiler::getSIMDType(CORINFO_CLASS_HANDLE typeHnd, CorInfoType* baseType) { + var_types type = TYP_UNDEF; + CorInfoType simdBaseJitType = CORINFO_TYPE_UNDEF; + + if ((typeHnd == nullptr) || !isIntrinsicType(typeHnd)) + { + return TYP_UNDEF; + } + + if (baseType != nullptr) + { + *baseType = simdBaseJitType; + } + if (m_simdHandleCache == nullptr) { if (impInlineInfo == nullptr) @@ -198,23 +187,9 @@ CorInfoType Compiler::getBaseJitTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeH } } - if (sizeBytes != nullptr) - { - *sizeBytes = 0; - } - - if ((typeHnd == nullptr) || !isIntrinsicType(typeHnd)) - { - return CORINFO_TYPE_UNDEF; - } - const char* namespaceName; const char* className = getClassNameFromMetadata(typeHnd, &namespaceName); - // fast path search using cached type handles of important types - CorInfoType simdBaseJitType = CORINFO_TYPE_UNDEF; - unsigned size = 0; - if (isNumericsNamespace(namespaceName)) { switch (className[0]) @@ -223,14 +198,14 @@ CorInfoType Compiler::getBaseJitTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeH { if (strcmp(className, "Plane") != 0) { - return CORINFO_TYPE_UNDEF; + return TYP_UNDEF; } JITDUMP(" Known type Plane\n"); m_simdHandleCache->PlaneHandle = typeHnd; + type = TYP_SIMD16; simdBaseJitType = CORINFO_TYPE_FLOAT; - size = 4 * genTypeSize(TYP_FLOAT); break; } @@ -238,14 +213,14 @@ CorInfoType Compiler::getBaseJitTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeH { if (strcmp(className, "Quaternion") != 0) { - return CORINFO_TYPE_UNDEF; + return TYP_UNDEF; } JITDUMP(" Known type Quaternion\n"); m_simdHandleCache->QuaternionHandle = typeHnd; + type = TYP_SIMD16; simdBaseJitType = CORINFO_TYPE_FLOAT; - size = 4 * genTypeSize(TYP_FLOAT); break; } @@ -253,7 +228,7 @@ CorInfoType Compiler::getBaseJitTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeH { if (strncmp(className, "Vector", 6) != 0) { - return CORINFO_TYPE_UNDEF; + return TYP_UNDEF; } switch (className[6]) @@ -269,14 +244,14 @@ CorInfoType Compiler::getBaseJitTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeH { if (className[7] != '\0') { - return CORINFO_TYPE_UNDEF; + return TYP_UNDEF; } JITDUMP(" Found Vector2\n"); m_simdHandleCache->Vector2Handle = typeHnd; + type = TYP_SIMD8; simdBaseJitType = CORINFO_TYPE_FLOAT; - size = 2 * genTypeSize(TYP_FLOAT); break; } @@ -284,14 +259,14 @@ CorInfoType Compiler::getBaseJitTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeH { if (className[7] != '\0') { - return CORINFO_TYPE_UNDEF; + return TYP_UNDEF; } JITDUMP(" Found Vector3\n"); m_simdHandleCache->Vector3Handle = typeHnd; + type = TYP_SIMD12; simdBaseJitType = CORINFO_TYPE_FLOAT; - size = 3 * genTypeSize(TYP_FLOAT); break; } @@ -299,14 +274,14 @@ CorInfoType Compiler::getBaseJitTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeH { if (className[7] != '\0') { - return CORINFO_TYPE_UNDEF; + return TYP_UNDEF; } JITDUMP(" Found Vector4\n"); m_simdHandleCache->Vector4Handle = typeHnd; + type = TYP_SIMD16; simdBaseJitType = CORINFO_TYPE_FLOAT; - size = 4 * genTypeSize(TYP_FLOAT); break; } @@ -314,7 +289,7 @@ CorInfoType Compiler::getBaseJitTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeH { if ((className[7] != '1') || (className[8] != '\0')) { - return CORINFO_TYPE_UNDEF; + return TYP_UNDEF; } CORINFO_CLASS_HANDLE typeArgHnd = info.compCompHnd->getTypeInstantiationArgument(typeHnd, 0); @@ -322,22 +297,24 @@ CorInfoType Compiler::getBaseJitTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeH if ((simdBaseJitType < CORINFO_TYPE_BYTE) || (simdBaseJitType > CORINFO_TYPE_DOUBLE)) { - return CORINFO_TYPE_UNDEF; + return TYP_UNDEF; } JITDUMP(" Found Vector<%s>\n", varTypeName(JitType2PreciseVarType(simdBaseJitType))); - size = getVectorTByteLength(); - if (size == 0) + uint32_t vectlen = getVectorTByteLength(); + if (vectlen == 0) { - return CORINFO_TYPE_UNDEF; + return TYP_UNDEF; } + + type = getSIMDTypeForSize(vectlen); break; } default: { - return CORINFO_TYPE_UNDEF; + return TYP_UNDEF; } } break; @@ -345,14 +322,14 @@ CorInfoType Compiler::getBaseJitTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeH default: { - return CORINFO_TYPE_UNDEF; + return TYP_UNDEF; } } } #ifdef FEATURE_HW_INTRINSICS else { - size = info.compCompHnd->getClassSize(typeHnd); + unsigned int size = info.compCompHnd->getClassSize(typeHnd); switch (size) { @@ -361,7 +338,7 @@ CorInfoType Compiler::getBaseJitTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeH { if (strcmp(className, "Vector64`1") != 0) { - return CORINFO_TYPE_UNDEF; + return TYP_UNDEF; } CORINFO_CLASS_HANDLE typeArgHnd = info.compCompHnd->getTypeInstantiationArgument(typeHnd, 0); @@ -369,10 +346,11 @@ CorInfoType Compiler::getBaseJitTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeH if ((simdBaseJitType < CORINFO_TYPE_BYTE) || (simdBaseJitType > CORINFO_TYPE_DOUBLE)) { - return CORINFO_TYPE_UNDEF; + return TYP_UNDEF; } JITDUMP(" Found Vector64<%s>\n", varTypeName(JitType2PreciseVarType(simdBaseJitType))); + type = TYP_SIMD8; break; } #endif // TARGET_ARM64 @@ -381,7 +359,7 @@ CorInfoType Compiler::getBaseJitTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeH { if (strcmp(className, "Vector128`1") != 0) { - return CORINFO_TYPE_UNDEF; + return TYP_UNDEF; } CORINFO_CLASS_HANDLE typeArgHnd = info.compCompHnd->getTypeInstantiationArgument(typeHnd, 0); @@ -389,10 +367,11 @@ CorInfoType Compiler::getBaseJitTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeH if ((simdBaseJitType < CORINFO_TYPE_BYTE) || (simdBaseJitType > CORINFO_TYPE_DOUBLE)) { - return CORINFO_TYPE_UNDEF; + return TYP_UNDEF; } JITDUMP(" Found Vector128<%s>\n", varTypeName(JitType2PreciseVarType(simdBaseJitType))); + type = TYP_SIMD16; break; } @@ -401,7 +380,7 @@ CorInfoType Compiler::getBaseJitTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeH { if (strcmp(className, "Vector256`1") != 0) { - return CORINFO_TYPE_UNDEF; + return TYP_UNDEF; } CORINFO_CLASS_HANDLE typeArgHnd = info.compCompHnd->getTypeInstantiationArgument(typeHnd, 0); @@ -409,16 +388,17 @@ CorInfoType Compiler::getBaseJitTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeH if ((simdBaseJitType < CORINFO_TYPE_BYTE) || (simdBaseJitType > CORINFO_TYPE_DOUBLE)) { - return CORINFO_TYPE_UNDEF; + return TYP_UNDEF; } if (!compOpportunisticallyDependsOn(InstructionSet_AVX)) { // We must treat as a regular struct if AVX isn't supported - return CORINFO_TYPE_UNDEF; + return TYP_UNDEF; } JITDUMP(" Found Vector256<%s>\n", varTypeName(JitType2PreciseVarType(simdBaseJitType))); + type = TYP_SIMD32; break; } @@ -426,7 +406,7 @@ CorInfoType Compiler::getBaseJitTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeH { if (strcmp(className, "Vector512`1") != 0) { - return CORINFO_TYPE_UNDEF; + return TYP_UNDEF; } CORINFO_CLASS_HANDLE typeArgHnd = info.compCompHnd->getTypeInstantiationArgument(typeHnd, 0); @@ -434,40 +414,107 @@ CorInfoType Compiler::getBaseJitTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeH if ((simdBaseJitType < CORINFO_TYPE_BYTE) || (simdBaseJitType > CORINFO_TYPE_DOUBLE)) { - return CORINFO_TYPE_UNDEF; + return TYP_UNDEF; } if (!compOpportunisticallyDependsOn(InstructionSet_AVX512)) { // We must treat as a regular struct if AVX512 isn't supported - return CORINFO_TYPE_UNDEF; + return TYP_UNDEF; } JITDUMP(" Found Vector512<%s>\n", varTypeName(JitType2PreciseVarType(simdBaseJitType))); + type = TYP_SIMD64; break; } #endif // TARGET_XARCH default: { - return CORINFO_TYPE_UNDEF; + return TYP_UNDEF; } } } #endif // FEATURE_HW_INTRINSICS - if (sizeBytes != nullptr) + if (baseType != nullptr) { - *sizeBytes = size; + *baseType = simdBaseJitType; } if (simdBaseJitType != CORINFO_TYPE_UNDEF) { - assert(size == info.compCompHnd->getClassSize(typeHnd)); + assert(getSizeOfSIMDType(type) == info.compCompHnd->getClassSize(typeHnd)); setUsesSIMDTypes(true); } - return simdBaseJitType; + return type; +} + +unsigned Compiler::getSizeOfSIMDType(var_types simdType) +{ + assert(varTypeIsSIMD(simdType)); + unsigned size = 0; + switch (simdType) + { + case TYP_SIMD8: + case TYP_SIMD12: + case TYP_SIMD16: +#ifdef TARGET_XARCH + case TYP_SIMD32: + case TYP_SIMD64: +#endif + size = genTypeSize(simdType); + break; + + default: + unreached(); + } + assert(size != 0); + return size; +} + +//---------------------------------------------------------------------------------- +// Return the base type and size of SIMD vector type given its type handle. +// +// Arguments: +// typeHnd - The handle of the type we're interested in. +// sizeBytes - out param +// +// Return Value: +// base type of SIMD vector. +// sizeBytes if non-null is set to size in bytes. +// +// Notes: +// If the size of the struct is already known call structSizeMightRepresentSIMDType +// to determine if this api needs to be called. +// +// The type handle passed here can only be used in a subset of JIT-EE calls +// since it may be called by promotion during AOT of a method that does +// not version with SPC. See CORINFO_TYPE_LAYOUT_NODE for the contract on +// the supported JIT-EE calls. +// +// TODO-Throughput: current implementation parses class name to find base type. Change +// this when we implement SIMD intrinsic identification for the final +// product. +// +CorInfoType Compiler::getBaseJitTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeHnd, unsigned* sizeBytes /*= nullptr */) +{ + CorInfoType baseType = CORINFO_TYPE_UNDEF; + + if (sizeBytes != nullptr) + { + *sizeBytes = 0; + } + + var_types type = getSIMDType(typeHnd, &baseType); + + if (sizeBytes != nullptr && type != TYP_UNDEF) + { + *sizeBytes = getSizeOfSIMDType(type); + } + + return baseType; } //------------------------------------------------------------------------ From 6a4a2a4b972cedc34ebec5f02b5dc5c4afbd462d Mon Sep 17 00:00:00 2001 From: Sebastian Nickolls Date: Wed, 1 Oct 2025 10:38:30 +0000 Subject: [PATCH 02/12] Replace LclVarDsc::lvExactSize with Compiler::lvaLclExactSize The function that determines the size of a local variable needs to have access to compiler state at runtime to handle variable types with sizes that depend on some runtime value, for example Vector when backed by ARM64 scalable vectors. --- src/coreclr/jit/codegencommon.cpp | 2 +- src/coreclr/jit/compiler.cpp | 32 +++++++++++++++++++++++++++++ src/coreclr/jit/compiler.h | 6 ++++-- src/coreclr/jit/gcencode.cpp | 2 +- src/coreclr/jit/gentree.cpp | 6 +++--- src/coreclr/jit/importer.cpp | 2 +- src/coreclr/jit/lclmorph.cpp | 6 +++--- src/coreclr/jit/lclvars.cpp | 34 +++++++++++++++---------------- src/coreclr/jit/lower.cpp | 2 +- src/coreclr/jit/lowerxarch.cpp | 6 ++++-- src/coreclr/jit/morph.cpp | 2 +- src/coreclr/jit/morphblock.cpp | 8 ++++---- 12 files changed, 72 insertions(+), 36 deletions(-) diff --git a/src/coreclr/jit/codegencommon.cpp b/src/coreclr/jit/codegencommon.cpp index d673a0678ceee5..acaf4edb2ac1e4 100644 --- a/src/coreclr/jit/codegencommon.cpp +++ b/src/coreclr/jit/codegencommon.cpp @@ -3827,7 +3827,7 @@ void CodeGen::genZeroInitFrame(int untrLclHi, int untrLclLo, regNumber initReg, compiler->opts.compDbgCode); if (varDsc->TypeIs(TYP_STRUCT) && !compiler->info.compInitMem && - (varDsc->lvExactSize() >= TARGET_POINTER_SIZE)) + (compiler->lvaLclExactSize(varDsc) >= TARGET_POINTER_SIZE)) { // We only initialize the GC variables in the TYP_STRUCT const unsigned slots = (unsigned)compiler->lvaLclStackHomeSize(varNum) / REGSIZE_BYTES; diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index f5c618fccea289..1bd79546f8458d 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -10884,3 +10884,35 @@ void Compiler::EnregisterStats::Dump(FILE* fout) const PRINT_STATS(m_externallyVisibleImplicitly, m_addrExposed); } #endif // TRACK_ENREG_STATS + +// Get the size of a JIT internal type. +// +// This function will resolve the size of types that aren't necessarily determinable +// from a static context, for example ARM64 scalable vector types. For primitive types +// and types that are obviously fixed size, use genTypeSize instead. +unsigned Compiler::getSizeOfType(var_types type) +{ +#ifdef FEATURE_SIMD + if (varTypeIsSIMD(type)) + { + return getSizeOfSIMDType(type); + } +#endif + +#if defined(FEATURE_MASKED_HW_INTRINSICS) && defined(TARGET_ARM64) + if (type == TYP_MASK) + { + // A predicate register has a bit for each byte in the vector register. + // We need to overallocate for 128-bit VL because the JIT makes assumptions + // about types being larger than an integer at the moment. + return roundUp((size_t)(getVectorTByteLength() / 8), sizeof(int)); + } +#endif + + return genTypeSize(type); +} + +unsigned Compiler::getSizeOfType(GenTree* tree) +{ + return getSizeOfType(tree->TypeGet()); +} diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index b71d1e270ba9bc..a2c72113987d17 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -980,8 +980,6 @@ class LclVarDsc lvStkOffs = offset; } - unsigned lvExactSize() const; - unsigned lvSlotNum; // original slot # (if remapped) // class handle for the local or null if not known or not a class @@ -4180,6 +4178,7 @@ class Compiler unsigned lvaLclStackHomeSize(unsigned varNum); unsigned lvaLclExactSize(unsigned varNum); + unsigned lvaLclExactSize(const LclVarDsc* varDsc); bool lvaHaveManyLocals(float percent = 1.0f) const; @@ -9430,6 +9429,9 @@ class Compiler return result; } + unsigned getSizeOfType(var_types type); + unsigned getSizeOfType(GenTree* tree); + enum UnrollKind { Memset, diff --git a/src/coreclr/jit/gcencode.cpp b/src/coreclr/jit/gcencode.cpp index 2f4ad6c3322931..c1711253d5b403 100644 --- a/src/coreclr/jit/gcencode.cpp +++ b/src/coreclr/jit/gcencode.cpp @@ -4250,7 +4250,7 @@ void GCInfo::gcMakeRegPtrTable( // If this is a TYP_STRUCT, handle its GC pointers. // Note that the enregisterable struct types cannot have GC pointers in them. if (varDsc->TypeIs(TYP_STRUCT) && varDsc->GetLayout()->HasGCPtr() && varDsc->lvOnFrame && - (varDsc->lvExactSize() >= TARGET_POINTER_SIZE)) + (compiler->lvaLclExactSize(varDsc) >= TARGET_POINTER_SIZE)) { ClassLayout* layout = varDsc->GetLayout(); unsigned slots = layout->GetSlotCount(); diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 5e2da75aa353c6..d3c3626b4c6d7b 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -17866,7 +17866,7 @@ bool GenTree::IsLclVarAddr() const bool GenTree::IsPartialLclFld(Compiler* comp) { return OperIs(GT_LCL_FLD, GT_STORE_LCL_FLD) && - (comp->lvaGetDesc(AsLclFld())->lvExactSize() != AsLclFld()->GetSize()); + (comp->lvaLclExactSize(comp->lvaGetDesc(AsLclFld())) != AsLclFld()->GetSize()); } //------------------------------------------------------------------------ @@ -28041,7 +28041,7 @@ GenTreeFieldList* Compiler::gtConvertTableOpToFieldList(GenTree* op, unsigned fi { unsigned lclNum = op->AsLclVar()->GetLclNum(); LclVarDsc* opVarDsc = lvaGetDesc(lclNum); - unsigned fieldSize = opVarDsc->lvExactSize() / fieldCount; + unsigned fieldSize = lvaLclExactSize(opVarDsc) / fieldCount; var_types fieldType = Compiler::getSIMDTypeForSize(fieldSize); GenTreeFieldList* fieldList = new (this, GT_FIELD_LIST) GenTreeFieldList(); @@ -28072,7 +28072,7 @@ GenTreeFieldList* Compiler::gtConvertParamOpToFieldList(GenTree* op, unsigned fi { unsigned lclNum = op->AsLclVar()->GetLclNum(); LclVarDsc* opVarDsc = lvaGetDesc(lclNum); - unsigned fieldSize = opVarDsc->lvExactSize() / fieldCount; + unsigned fieldSize = lvaLclExactSize(opVarDsc) / fieldCount; GenTreeFieldList* fieldList = new (this, GT_FIELD_LIST) GenTreeFieldList(); int offset = 0; CORINFO_CLASS_HANDLE structType; diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index c0b28d6b74654a..d0a4a4aabf0c51 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -3709,7 +3709,7 @@ void Compiler::impImportNewObjArray(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORI // Increase size of lvaNewObjArrayArgs to be the largest size needed to hold 'numArgs' integers // for our call to CORINFO_HELP_NEW_MDARR. - if (dimensionsSize > lvaTable[lvaNewObjArrayArgs].lvExactSize()) + if (dimensionsSize > lvaLclExactSize(&lvaTable[lvaNewObjArrayArgs])) { lvaTable[lvaNewObjArrayArgs].GrowBlockLayout(typGetBlkLayout(dimensionsSize)); } diff --git a/src/coreclr/jit/lclmorph.cpp b/src/coreclr/jit/lclmorph.cpp index 4bda0cfcb4c827..296ac279a104ed 100644 --- a/src/coreclr/jit/lclmorph.cpp +++ b/src/coreclr/jit/lclmorph.cpp @@ -1504,8 +1504,8 @@ class LocalAddressVisitor final : public GenTreeVisitor callUser->gtCallMoreFlags |= GTF_CALL_M_RETBUFFARG_LCLOPT; defFlag = GTF_VAR_DEF; - if ((val.Offset() != 0) || - (varDsc->lvExactSize() != m_compiler->typGetObjLayout(callUser->gtRetClsHnd)->GetSize())) + if ((val.Offset() != 0) || (m_compiler->lvaLclExactSize(varDsc) != + m_compiler->typGetObjLayout(callUser->gtRetClsHnd)->GetSize())) { defFlag |= GTF_VAR_USEASG; } @@ -1521,7 +1521,7 @@ class LocalAddressVisitor final : public GenTreeVisitor escapeAddr = false; defFlag = GTF_VAR_DEF; - if ((val.Offset() != 0) || (varDsc->lvExactSize() != 1)) + if ((val.Offset() != 0) || (m_compiler->lvaLclExactSize(varDsc) != 1)) { defFlag |= GTF_VAR_USEASG; } diff --git a/src/coreclr/jit/lclvars.cpp b/src/coreclr/jit/lclvars.cpp index 02ad1bced19fd5..d4f9096c3faf23 100644 --- a/src/coreclr/jit/lclvars.cpp +++ b/src/coreclr/jit/lclvars.cpp @@ -1992,8 +1992,8 @@ void Compiler::StructPromotionHelper::PromoteStructVar(unsigned lclNum) var_types hfaType = compiler->GetHfaType(pFieldInfo->fldSIMDTypeHnd); if (varTypeIsValidHfaType(hfaType)) { - fieldVarDsc->lvIsMultiRegArg = - (varDsc->lvIsMultiRegArg != 0) && (fieldVarDsc->lvExactSize() > genTypeSize(hfaType)); + fieldVarDsc->lvIsMultiRegArg = (varDsc->lvIsMultiRegArg != 0) && + (compiler->lvaLclExactSize(fieldVarDsc) > genTypeSize(hfaType)); } } } @@ -2764,7 +2764,7 @@ unsigned Compiler::lvaLclStackHomeSize(unsigned varNum) // There are other cases where the caller has allocated space for the // parameter, like windows-x64 with shadow space for register // parameters, but in those cases this rounding is fine. - return roundUp(varDsc->lvExactSize(), TARGET_POINTER_SIZE); + return roundUp(lvaLclExactSize(varDsc), TARGET_POINTER_SIZE); } #if defined(FEATURE_SIMD) && !defined(TARGET_64BIT) @@ -2778,7 +2778,7 @@ unsigned Compiler::lvaLclStackHomeSize(unsigned varNum) } #endif // defined(FEATURE_SIMD) && !defined(TARGET_64BIT) - return roundUp(varDsc->lvExactSize(), TARGET_POINTER_SIZE); + return roundUp(lvaLclExactSize(varDsc), TARGET_POINTER_SIZE); } // @@ -2788,7 +2788,19 @@ unsigned Compiler::lvaLclStackHomeSize(unsigned varNum) unsigned Compiler::lvaLclExactSize(unsigned varNum) { assert(varNum < lvaCount); - return lvaGetDesc(varNum)->lvExactSize(); + return lvaLclExactSize(lvaGetDesc(varNum)); +} + +//------------------------------------------------------------------------ +// lvaLclExactSize: Get the exact size of the type of this local. +// +// Return Value: +// Size in bytes. Always non-zero, but not necessarily a multiple of the +// stack slot size. +// +unsigned Compiler::lvaLclExactSize(const LclVarDsc* desc) +{ + return (desc->lvType == TYP_STRUCT) ? desc->GetLayout()->GetSize() : getSizeOfType(desc->lvType); } // LclVarDsc "less" comparer used to compare the weight of two locals, when optimizing for small code. @@ -3218,18 +3230,6 @@ void Compiler::lvaSortByRefCount() #endif } -//------------------------------------------------------------------------ -// lvExactSize: Get the exact size of the type of this local. -// -// Return Value: -// Size in bytes. Always non-zero, but not necessarily a multiple of the -// stack slot size. -// -unsigned LclVarDsc::lvExactSize() const -{ - return (lvType == TYP_STRUCT) ? GetLayout()->GetSize() : genTypeSize(lvType); -} - //------------------------------------------------------------------------ // GetRegisterType: Determine register type for this local var. // diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index 25e5db40c20c6c..dc73ad573d0183 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -8609,7 +8609,7 @@ void Lowering::MapParameterRegisterLocals() continue; } - if (fieldDsc->lvFldOffset + fieldDsc->lvExactSize() <= segment.Offset) + if (fieldDsc->lvFldOffset + comp->lvaLclExactSize(fieldDsc) <= segment.Offset) { // This register does not map to this field (starts after the field ends) continue; diff --git a/src/coreclr/jit/lowerxarch.cpp b/src/coreclr/jit/lowerxarch.cpp index 2f394610d4f877..9b295308809365 100644 --- a/src/coreclr/jit/lowerxarch.cpp +++ b/src/coreclr/jit/lowerxarch.cpp @@ -5076,7 +5076,8 @@ GenTree* Lowering::LowerHWIntrinsicGetElement(GenTreeHWIntrinsic* node) uint32_t lclOffs = lclVar->GetLclOffs() + (imm8 * elemSize); LclVarDsc* lclDsc = comp->lvaGetDesc(lclVar); - if (lclDsc->lvDoNotEnregister && (lclOffs <= 0xFFFF) && ((lclOffs + elemSize) <= lclDsc->lvExactSize())) + if (lclDsc->lvDoNotEnregister && (lclOffs <= 0xFFFF) && + ((lclOffs + elemSize) <= comp->lvaLclExactSize(lclDsc))) { GenTree* lclFld = comp->gtNewLclFldNode(lclVar->GetLclNum(), JITtype2varType(simdBaseJitType), static_cast(lclOffs)); @@ -6307,7 +6308,8 @@ GenTree* Lowering::LowerHWIntrinsicToScalar(GenTreeHWIntrinsic* node) uint32_t lclOffs = lclVar->GetLclOffs() + (0 * elemSize); LclVarDsc* lclDsc = comp->lvaGetDesc(lclVar); - if (lclDsc->lvDoNotEnregister && (lclOffs <= 0xFFFF) && ((lclOffs + elemSize) <= lclDsc->lvExactSize())) + if (lclDsc->lvDoNotEnregister && (lclOffs <= 0xFFFF) && + ((lclOffs + elemSize) <= comp->lvaLclExactSize(lclDsc))) { GenTree* lclFld = comp->gtNewLclFldNode(lclVar->GetLclNum(), JITtype2varType(simdBaseJitType), lclVar->GetLclOffs()); diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index 96026d8948c8f0..34148ec10077c9 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -6896,7 +6896,7 @@ GenTree* Compiler::getSIMDStructFromField(GenTree* tree, if (varTypeIsArithmetic(elementType) && ((fieldOffset % elementSize) == 0)) { - *simdSizeOut = varDsc->lvExactSize(); + *simdSizeOut = lvaLclExactSize(varDsc); *indexOut = fieldOffset / elementSize; return objRef; diff --git a/src/coreclr/jit/morphblock.cpp b/src/coreclr/jit/morphblock.cpp index 452983ffc50597..920ff1c8c08d46 100644 --- a/src/coreclr/jit/morphblock.cpp +++ b/src/coreclr/jit/morphblock.cpp @@ -355,7 +355,7 @@ void MorphInitBlockHelper::TryInitFieldByField() return; } - if (destLclVar->lvExactSize() != blockSize) + if (m_comp->lvaLclExactSize(destLclVar) != blockSize) { JITDUMP(" dest size mismatch.\n"); return; @@ -711,7 +711,7 @@ void MorphCopyBlockHelper::MorphStructCases() noway_assert(varTypeIsStruct(m_dstVarDsc)); noway_assert(!m_comp->opts.MinOpts()); - if (m_blockSize == m_dstVarDsc->lvExactSize()) + if (m_blockSize == m_comp->lvaLclExactSize(m_dstVarDsc)) { JITDUMP(" (m_dstDoFldStore=true)"); // We may decide later that a copyblk is required when this struct has holes @@ -731,7 +731,7 @@ void MorphCopyBlockHelper::MorphStructCases() noway_assert(varTypeIsStruct(m_srcVarDsc)); noway_assert(!m_comp->opts.MinOpts()); - if (m_blockSize == m_srcVarDsc->lvExactSize()) + if (m_blockSize == m_comp->lvaLclExactSize(m_srcVarDsc)) { JITDUMP(" (m_srcDoFldStore=true)"); // We may decide later that a copyblk is required when this struct has holes @@ -1310,7 +1310,7 @@ GenTree* MorphCopyBlockHelper::CopyFieldByField() assert(destType != TYP_STRUCT); unsigned destSize = genTypeSize(destType); m_srcVarDsc = m_comp->lvaGetDesc(m_srcLclNum); - unsigned srcSize = m_srcVarDsc->lvExactSize(); + unsigned srcSize = m_comp->lvaLclExactSize(m_srcVarDsc); if (destSize == srcSize) { m_srcLclNode->ChangeOper(GT_LCL_FLD); From c05d886fcf34fe3b20144ab2fadf58460f929ac4 Mon Sep 17 00:00:00 2001 From: Sebastian Nickolls Date: Wed, 1 Oct 2025 14:19:59 +0000 Subject: [PATCH 03/12] Replace GenTreeIndir::Size with Compiler::gtGetSizeOfIndirection The function that determines the size of an indirection needs to have access to compiler state at runtime to handle variable types with sizes that depend on some runtime value, for example Vector when backed by ARM64 scalable vectors. --- src/coreclr/jit/compiler.h | 2 ++ src/coreclr/jit/gentree.cpp | 14 +++++++++++--- src/coreclr/jit/lclmorph.cpp | 4 ++-- src/coreclr/jit/lower.cpp | 14 ++++++++------ src/coreclr/jit/lowerarmarch.cpp | 2 +- src/coreclr/jit/lowerxarch.cpp | 4 ++-- src/coreclr/jit/morph.cpp | 2 +- src/coreclr/jit/valuenum.cpp | 15 ++++++++------- 8 files changed, 35 insertions(+), 22 deletions(-) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index a2c72113987d17..fcb6ab779a71bc 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -3631,6 +3631,8 @@ class Compiler void gtGetLclFldNodeCost(GenTreeLclFld* node, int* pCostEx, int* pCostSz); bool gtGetIndNodeCost(GenTreeIndir* node, int* pCostEx, int* pCostSz); + unsigned gtGetSizeOfIndirection(GenTreeIndir* indir); + // Returns true iff the secondNode can be swapped with firstNode. bool gtCanSwapOrder(GenTree* firstNode, GenTree* secondNode); diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index d3c3626b4c6d7b..9198a2bbaee29c 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -18178,10 +18178,18 @@ ssize_t GenTreeIndir::Offset() } } -unsigned GenTreeIndir::Size() const +// Compiler::gtGetSizeOfIndirection: Get the size associated with this indirection. +// +// Arguments: +// indir - Indirection to process +// +// Return Value: +// If the indirection is a block load or store, then it's the size of the block. +// Otherwise it's the size of the type of the indirection. +// +unsigned Compiler::gtGetSizeOfIndirection(GenTreeIndir* indir) { - assert(isIndir() || OperIsBlk()); - return OperIsBlk() ? AsBlk()->Size() : genTypeSize(TypeGet()); + return indir->OperIsBlk() ? indir->AsBlk()->Size() : getSizeOfType(indir->TypeGet()); } //------------------------------------------------------------------------ diff --git a/src/coreclr/jit/lclmorph.cpp b/src/coreclr/jit/lclmorph.cpp index 296ac279a104ed..1c4bf4201666ba 100644 --- a/src/coreclr/jit/lclmorph.cpp +++ b/src/coreclr/jit/lclmorph.cpp @@ -1591,7 +1591,7 @@ class LocalAddressVisitor final : public GenTreeVisitor unsigned lclNum = val.LclNum(); unsigned offset = val.Offset(); LclVarDsc* varDsc = m_compiler->lvaGetDesc(lclNum); - unsigned indirSize = node->AsIndir()->Size(); + unsigned indirSize = m_compiler->gtGetSizeOfIndirection(node->AsIndir()); bool isWide; // TODO-Cleanup: delete "indirSize == 0", use "Compiler::IsValidLclAddr". @@ -2062,7 +2062,7 @@ class LocalAddressVisitor final : public GenTreeVisitor return false; } - unsigned fieldLclNum = MorphStructFieldAddress(addr, node->Size()); + unsigned fieldLclNum = MorphStructFieldAddress(addr, m_compiler->gtGetSizeOfIndirection(node)); if (fieldLclNum == BAD_VAR_NUM) { return false; diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index dc73ad573d0183..8ef5e236555a04 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -5710,7 +5710,7 @@ void Lowering::LowerRetStruct(GenTreeUnOp* ret) { // Spill to a local if sizes don't match so we can avoid the "load more than requested" // problem, e.g. struct size is 5 and we emit "ldr x0, [x1]" - if (genTypeSize(nativeReturnType) > retVal->AsIndir()->Size()) + if (genTypeSize(nativeReturnType) > comp->gtGetSizeOfIndirection(retVal->AsIndir())) { LIR::Use retValUse(BlockRange(), &ret->gtOp1, ret); unsigned tmpNum = comp->lvaGrabTemp(true DEBUGARG("mis-sized struct return")); @@ -10837,23 +10837,25 @@ bool Lowering::TryMakeIndirsAdjacent(GenTreeIndir* prevIndir, GenTreeIndir* indi target_ssize_t storeOffs = 0; comp->gtPeelOffsets(&storeAddr, &storeOffs); - bool distinct = (storeOffs + (target_ssize_t)store->Size() <= offs) || - (offs + (target_ssize_t)indir->Size() <= storeOffs); + unsigned storeSize = comp->gtGetSizeOfIndirection(store); + unsigned indirSize = comp->gtGetSizeOfIndirection(indir); + bool distinct = + (storeOffs + (target_ssize_t)storeSize <= offs) || (offs + (target_ssize_t)indirSize <= storeOffs); if (checkLocal && GenTree::Compare(indirAddr, storeAddr) && distinct) { JITDUMP("Cannot interfere with [%06u] since they are off the same local V%02u and indir range " "[%03u..%03u) does not interfere with store range [%03u..%03u)\n", Compiler::dspTreeID(node), indirAddr->AsLclVarCommon()->GetLclNum(), (unsigned)offs, - (unsigned)offs + indir->Size(), (unsigned)storeOffs, (unsigned)storeOffs + store->Size()); + (unsigned)offs + indirSize, (unsigned)storeOffs, (unsigned)storeOffs + storeSize); } // Two indirs off of TYP_REFs cannot overlap if their offset ranges are distinct. else if (indirAddr->TypeIs(TYP_REF) && storeAddr->TypeIs(TYP_REF) && distinct) { JITDUMP("Cannot interfere with [%06u] since they are both off TYP_REF bases and indir range " "[%03u..%03u) does not interfere with store range [%03u..%03u)\n", - Compiler::dspTreeID(node), (unsigned)offs, (unsigned)offs + indir->Size(), - (unsigned)storeOffs, (unsigned)storeOffs + store->Size()); + Compiler::dspTreeID(node), (unsigned)offs, (unsigned)offs + indirSize, (unsigned)storeOffs, + (unsigned)storeOffs + storeSize); } else { diff --git a/src/coreclr/jit/lowerarmarch.cpp b/src/coreclr/jit/lowerarmarch.cpp index a75814b38d3cc4..af74a6267036d6 100644 --- a/src/coreclr/jit/lowerarmarch.cpp +++ b/src/coreclr/jit/lowerarmarch.cpp @@ -2864,7 +2864,7 @@ void Lowering::ContainCheckIndir(GenTreeIndir* indirNode) } } else if (addr->OperIs(GT_LCL_ADDR) && !indirNode->OperIs(GT_NULLCHECK) && - IsContainableLclAddr(addr->AsLclFld(), indirNode->Size())) + IsContainableLclAddr(addr->AsLclFld(), comp->gtGetSizeOfIndirection(indirNode))) { // These nodes go into an addr mode: // - GT_LCL_ADDR is a stack addr mode. diff --git a/src/coreclr/jit/lowerxarch.cpp b/src/coreclr/jit/lowerxarch.cpp index 9b295308809365..4cb4dc322b4f5d 100644 --- a/src/coreclr/jit/lowerxarch.cpp +++ b/src/coreclr/jit/lowerxarch.cpp @@ -7278,7 +7278,7 @@ void Lowering::ContainCheckIndir(GenTreeIndir* node) // The address of an indirection that requires its address in a reg. // Skip any further processing that might otherwise make it contained. } - else if (addr->OperIs(GT_LCL_ADDR) && IsContainableLclAddr(addr->AsLclFld(), node->Size())) + else if (addr->OperIs(GT_LCL_ADDR) && IsContainableLclAddr(addr->AsLclFld(), comp->gtGetSizeOfIndirection(node))) { // These nodes go into an addr mode: // - GT_LCL_ADDR is a stack addr mode. @@ -8239,7 +8239,7 @@ bool Lowering::LowerRMWMemOp(GenTreeIndir* storeInd) // If it is a GT_LCL_VAR, it still needs the reg to hold the address. // We would still need a reg for GT_CNS_INT if it doesn't fit within addressing mode base. if (indirCandidateChild->OperIs(GT_LCL_ADDR) && - IsContainableLclAddr(indirCandidateChild->AsLclFld(), storeInd->Size())) + IsContainableLclAddr(indirCandidateChild->AsLclFld(), comp->gtGetSizeOfIndirection(storeInd))) { indirDst->SetContained(); } diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index 34148ec10077c9..59ff422a656b2e 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -8546,7 +8546,7 @@ GenTree* Compiler::fgMorphFinalizeIndir(GenTreeIndir* indir) if (!indir->IsVolatile() && !indir->TypeIs(TYP_STRUCT) && addr->OperIs(GT_LCL_ADDR)) { - unsigned size = indir->Size(); + unsigned size = gtGetSizeOfIndirection(indir); unsigned offset = addr->AsLclVarCommon()->GetLclOffs(); unsigned extent = offset + size; unsigned lclSize = lvaLclExactSize(addr->AsLclVarCommon()->GetLclNum()); diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index e2de675a651578..431ec1b5e3b2bf 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -6277,7 +6277,7 @@ void Compiler::fgValueNumberArrayElemLoad(GenTree* loadTree, VNFuncApp* addrFunc unsigned elemSize = (elemType == TYP_STRUCT) ? info.compCompHnd->getClassSize(elemTypeEq) : genTypeSize(elemType); var_types loadType = loadTree->TypeGet(); - unsigned loadSize = loadTree->AsIndir()->Size(); + unsigned loadSize = gtGetSizeOfIndirection(loadTree->AsIndir()); ValueNum loadValueVN = vnStore->VNForLoad(VNK_Liberal, wholeElem, elemSize, loadType, offset, loadSize); loadTree->gtVNPair.SetLiberal(loadValueVN); @@ -6406,9 +6406,10 @@ void Compiler::fgValueNumberFieldLoad(GenTree* loadTree, GenTree* baseAddr, Fiel ValueNum fieldValueVN = vnStore->VNForMapSelect(VNK_Liberal, fieldType, fieldMapVN, fieldValueSelectorVN); // Finally, account for the struct fields and type mismatches. - var_types loadType = loadTree->TypeGet(); - unsigned loadSize = loadTree->OperIsBlk() ? loadTree->AsBlk()->Size() : genTypeSize(loadTree); - ValueNum loadValueVN = vnStore->VNForLoad(VNK_Liberal, fieldValueVN, fieldSize, loadType, offset, loadSize); + var_types loadType = loadTree->TypeGet(); + unsigned loadSize = gtGetSizeOfIndirection(loadTree->AsIndir()); + + ValueNum loadValueVN = vnStore->VNForLoad(VNK_Liberal, fieldValueVN, fieldSize, loadType, offset, loadSize); loadTree->gtVNPair.SetLiberal(loadValueVN); loadTree->gtVNPair.SetConservative(vnStore->VNForExpr(compCurBB, loadType)); @@ -12119,7 +12120,7 @@ void Compiler::fgValueNumberStore(GenTree* store) GenTreeLclVarCommon* lclVarTree = nullptr; ssize_t offset = 0; - unsigned storeSize = store->AsIndir()->Size(); + unsigned storeSize = gtGetSizeOfIndirection(store->AsIndir()); GenTree* baseAddr = nullptr; FieldSeq* fldSeq = nullptr; @@ -12402,7 +12403,7 @@ bool Compiler::fgValueNumberConstLoad(GenTreeIndir* tree) ssize_t byteOffset = 0; FieldSeq* fieldSeq = nullptr; CORINFO_OBJECT_HANDLE obj = nullptr; - int size = (int)genTypeSize(tree->TypeGet()); + int size = (int)gtGetSizeOfIndirection(tree); const int maxElementSize = sizeof(simd_t); if (!tree->TypeIs(TYP_BYREF, TYP_STRUCT) && @@ -12768,7 +12769,7 @@ void Compiler::fgValueNumberTree(GenTree* tree) { var_types loadType = tree->TypeGet(); ssize_t offset = 0; - unsigned loadSize = tree->AsIndir()->Size(); + unsigned loadSize = gtGetSizeOfIndirection(tree->AsIndir()); VNFuncApp funcApp{VNF_COUNT}; if (fgValueNumberConstLoad(tree->AsIndir())) From bf82fa3cbdd17f6fbab5a92166ba9e7575bcb769 Mon Sep 17 00:00:00 2001 From: Sebastian Nickolls Date: Fri, 3 Oct 2025 12:38:18 +0000 Subject: [PATCH 04/12] Add scalable vector type to JIT and HFA type for Vector Create a new type designed to support Vector with size evaluated at runtime. Adds a new HFA type to the VM to support passing Vector as a scalable vector register on ARM64. Both types are experimental and locked behind the DOTNET_JitUseScalableVectorT configuration option. This first patch implements SVE codegen for Vector, mainly for managing Vector as a data structure that can be placed in a Z register. When DOTNET_JitUseScalableVectorT=1, the JIT will move the type around using SVE instructions operating on Z registers. It does not yet unlock longer vector lengths or implement operations from the Vector API surface using SVE. This API still generates NEON code, which is functionally equivalent so long as Vector.Count is limited to 128-bits. When DOTNET_JitUseScalableVectorT=0 the code generated for Vector should have zero functional difference but may have some cosmetic differences as some refactoring has been done on general SIMD codegen to support the new type. --- src/coreclr/inc/clrconfigvalues.h | 4 + src/coreclr/inc/corhdr.h | 1 + src/coreclr/jit/assertionprop.cpp | 2 +- src/coreclr/jit/async.cpp | 4 +- src/coreclr/jit/codegenarm64.cpp | 26 ++- src/coreclr/jit/codegenarmarch.cpp | 7 +- src/coreclr/jit/codegencommon.cpp | 20 ++- src/coreclr/jit/codegenlinear.cpp | 13 +- src/coreclr/jit/compiler.cpp | 47 +++-- src/coreclr/jit/compiler.h | 12 +- src/coreclr/jit/compiler.hpp | 14 +- src/coreclr/jit/emitarm64.cpp | 34 ++-- src/coreclr/jit/fgdiagnostic.cpp | 4 +- src/coreclr/jit/gentree.cpp | 87 ++++++++-- src/coreclr/jit/gentree.h | 31 +++- src/coreclr/jit/hwintrinsicarm64.cpp | 45 ++++- src/coreclr/jit/hwintrinsiccodegenarm64.cpp | 61 +++---- src/coreclr/jit/importercalls.cpp | 2 +- src/coreclr/jit/inductionvariableopts.cpp | 2 +- src/coreclr/jit/instr.cpp | 23 +++ src/coreclr/jit/jitconfigvalues.h | 3 + src/coreclr/jit/lclmorph.cpp | 20 ++- src/coreclr/jit/lclvars.cpp | 23 ++- src/coreclr/jit/lower.cpp | 116 +++++++------ src/coreclr/jit/lsra.cpp | 2 + src/coreclr/jit/lsraarm64.cpp | 2 +- src/coreclr/jit/morph.cpp | 4 +- src/coreclr/jit/morphblock.cpp | 6 +- src/coreclr/jit/optimizer.cpp | 2 +- src/coreclr/jit/promotion.cpp | 80 +++++---- src/coreclr/jit/promotion.h | 8 +- src/coreclr/jit/promotiondecomposition.cpp | 33 ++-- src/coreclr/jit/promotionliveness.cpp | 20 +-- src/coreclr/jit/regset.cpp | 4 +- src/coreclr/jit/scopeinfo.cpp | 4 + src/coreclr/jit/simd.cpp | 21 ++- src/coreclr/jit/targetarm64.cpp | 8 +- src/coreclr/jit/typelist.h | 9 + src/coreclr/jit/valuenum.cpp | 163 +++++++++++++----- src/coreclr/jit/valuenum.h | 4 + src/coreclr/vm/callingconvention.h | 1 + src/coreclr/vm/class.cpp | 63 ++++--- src/coreclr/vm/classlayoutinfo.cpp | 4 + src/coreclr/vm/codeman.cpp | 29 ++++ src/coreclr/vm/codeman.h | 14 ++ src/coreclr/vm/methodtable.h | 4 +- src/coreclr/vm/methodtablebuilder.cpp | 21 +-- src/tests/JIT/opt/SVE/ConstantMasks.cs | 16 +- .../JIT/opt/SVE/ConstantMasksOp2Fixed.cs | 2 +- 49 files changed, 758 insertions(+), 367 deletions(-) diff --git a/src/coreclr/inc/clrconfigvalues.h b/src/coreclr/inc/clrconfigvalues.h index e5dc2fe9d8fd06..943aeef021caa2 100644 --- a/src/coreclr/inc/clrconfigvalues.h +++ b/src/coreclr/inc/clrconfigvalues.h @@ -349,6 +349,10 @@ RETAIL_CONFIG_DWORD_INFO(INTERNAL_MultiCoreJitNoProfileGather, W("MultiCoreJitNo #endif +#ifdef TARGET_ARM64 +CONFIG_DWORD_INFO(EXTERNAL_JitUseScalableVectorT, W("JitUseScalableVectorT"), 0, "Accelerate Vector with SVE if available.") +#endif + /// /// Loader heap /// diff --git a/src/coreclr/inc/corhdr.h b/src/coreclr/inc/corhdr.h index 291cadbe2c18a6..3546c88c5884e3 100644 --- a/src/coreclr/inc/corhdr.h +++ b/src/coreclr/inc/corhdr.h @@ -1761,6 +1761,7 @@ typedef enum CorInfoHFAElemType : unsigned { CORINFO_HFA_ELEM_DOUBLE, CORINFO_HFA_ELEM_VECTOR64, CORINFO_HFA_ELEM_VECTOR128, + CORINFO_HFA_ELEM_VECTORT, } CorInfoHFAElemType; // diff --git a/src/coreclr/jit/assertionprop.cpp b/src/coreclr/jit/assertionprop.cpp index c4d832dd39d57f..a4cc3a738855b8 100644 --- a/src/coreclr/jit/assertionprop.cpp +++ b/src/coreclr/jit/assertionprop.cpp @@ -2471,7 +2471,7 @@ GenTree* Compiler::optVNBasedFoldExpr_Call_Memset(GenTreeCall* call) CallArg* valArg = call->gtArgs.GetUserArgByIndex(2); var_types valType = valArg->GetSignatureType(); - unsigned lengthScale = genTypeSize(valType); + unsigned lengthScale = getSizeOfType(valType); if (lengthScale == 1) { diff --git a/src/coreclr/jit/async.cpp b/src/coreclr/jit/async.cpp index 4d43458c89e569..e0b6fa38a2f9bb 100644 --- a/src/coreclr/jit/async.cpp +++ b/src/coreclr/jit/async.cpp @@ -1058,7 +1058,7 @@ ContinuationLayout AsyncTransformation::LayOutContinuation(BasicBlock* assert(!dsc->TypeIs(TYP_BYREF)); inf.Alignment = genTypeAlignments[dsc->TypeGet()]; - inf.Size = genTypeSize(dsc); + inf.Size = m_comp->getSizeOfType(dsc->TypeGet()); } } @@ -1090,7 +1090,7 @@ ContinuationLayout AsyncTransformation::LayOutContinuation(BasicBlock* } else { - layout.ReturnSize = genTypeSize(call->gtReturnType); + layout.ReturnSize = m_comp->getSizeOfType(call->gtReturnType); layout.ReturnAlignment = layout.ReturnSize; } diff --git a/src/coreclr/jit/codegenarm64.cpp b/src/coreclr/jit/codegenarm64.cpp index 4c3bf607017696..d2521de5a41b24 100644 --- a/src/coreclr/jit/codegenarm64.cpp +++ b/src/coreclr/jit/codegenarm64.cpp @@ -362,6 +362,15 @@ bool CodeGen::genInstrWithConstant(instruction ins, immFitsInIns = emitter::emitIns_valid_imm_for_ldst_offset(imm, size); break; + case INS_sve_ldr: + case INS_sve_str: + { + assert(size == EA_SCALABLE); + ssize_t count = imm / compiler->getSizeOfType(TYP_SIMDSV); + immFitsInIns = (-256 <= count && count < 256); + } + break; + default: assert(!"Unexpected instruction in genInstrWithConstant"); break; @@ -2075,10 +2084,14 @@ void CodeGen::instGen_Set_Reg_To_Base_Plus_Imm(emitAttr size, // If the imm values < 12 bits, we can use a single "add rsvd, reg2, #imm". // Otherwise, use "mov rsvd, #imm", followed up "add rsvd, reg2, rsvd". - if (imm < 4096) + if (0 <= imm && imm < 4096) { GetEmitter()->emitIns_R_R_I(INS_add, EA_PTRSIZE, dstReg, baseReg, imm); } + else if (-4095 <= imm < 0) + { + GetEmitter()->emitIns_R_R_I(INS_sub, EA_PTRSIZE, dstReg, baseReg, -imm); + } else { instGen_Set_Reg_To_Imm(size, dstReg, imm); @@ -2274,6 +2287,9 @@ void CodeGen::genSetRegToConst(regNumber targetReg, var_types targetType, GenTre switch (tree->TypeGet()) { + case TYP_SIMDSV: + attr = EA_16BYTE; // TODO-SVE: Implement scalable vector constant + FALLTHROUGH; case TYP_SIMD8: case TYP_SIMD12: case TYP_SIMD16: @@ -2991,7 +3007,7 @@ void CodeGen::genSimpleReturn(GenTree* treeNode) var_types op1Type = genActualType(op1->TypeGet()); var_types lclType = genActualType(varDsc->TypeGet()); - if (genTypeSize(op1Type) < genTypeSize(lclType)) + if (compiler->getSizeOfType(op1Type) < compiler->getSizeOfType(lclType)) { movRequired = true; } @@ -2999,7 +3015,7 @@ void CodeGen::genSimpleReturn(GenTree* treeNode) } } emitAttr attr = emitActualTypeSize(targetType); - GetEmitter()->emitIns_Mov(INS_mov, attr, retReg, op1->GetRegNum(), /* canSkip */ !movRequired); + inst_Mov(targetType, retReg, op1->GetRegNum(), !movRequired, attr); } /*********************************************************************************************** @@ -5306,7 +5322,7 @@ void CodeGen::genSimdUpperSave(GenTreeIntrinsic* node) GenTreeLclVar* lclNode = op1->AsLclVar(); LclVarDsc* varDsc = compiler->lvaGetDesc(lclNode); - assert(emitTypeSize(varDsc->GetRegisterType(lclNode)) == 16); + assert(varDsc->TypeIs(TYP_STRUCT, TYP_SIMD12, TYP_SIMD16, TYP_SIMDSV)); // TODO-SVE: Handle AAPCS for Z registers regNumber tgtReg = node->GetRegNum(); assert(tgtReg != REG_NA); @@ -5362,7 +5378,7 @@ void CodeGen::genSimdUpperRestore(GenTreeIntrinsic* node) GenTreeLclVar* lclNode = op1->AsLclVar(); LclVarDsc* varDsc = compiler->lvaGetDesc(lclNode); - assert(emitTypeSize(varDsc->GetRegisterType(lclNode)) == 16); + assert(varDsc->TypeIs(TYP_STRUCT, TYP_SIMD12, TYP_SIMD16, TYP_SIMDSV)); // TODO-SVE: Handle AAPCS for Z registers regNumber srcReg = node->GetRegNum(); assert(srcReg != REG_NA); diff --git a/src/coreclr/jit/codegenarmarch.cpp b/src/coreclr/jit/codegenarmarch.cpp index 8d90b0d3766f10..3c70b65f7a8b69 100644 --- a/src/coreclr/jit/codegenarmarch.cpp +++ b/src/coreclr/jit/codegenarmarch.cpp @@ -809,8 +809,13 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode) #endif // TARGET_ARM64 { emitAttr storeAttr = emitTypeSize(source->TypeGet()); - emit->emitIns_S_R(INS_str, storeAttr, srcReg, varNumOut, argOffsetOut); + emit->emitIns_S_R(ins_Store(source->TypeGet()), storeAttr, srcReg, varNumOut, argOffsetOut); +#ifdef TARGET_ARM64 + argOffsetOut += + storeAttr == EA_SCALABLE ? compiler->getVectorTByteLength() : EA_SIZE_IN_BYTES(storeAttr); +#else argOffsetOut += EA_SIZE_IN_BYTES(storeAttr); +#endif } assert(argOffsetOut <= argOffsetMax); // We can't write beyond the outgoing arg area return; diff --git a/src/coreclr/jit/codegencommon.cpp b/src/coreclr/jit/codegencommon.cpp index acaf4edb2ac1e4..6ccca634ae928c 100644 --- a/src/coreclr/jit/codegencommon.cpp +++ b/src/coreclr/jit/codegencommon.cpp @@ -2850,13 +2850,13 @@ class RegGraph for (RegNodeEdge* incoming = regNode->incoming; incoming != nullptr; incoming = incoming->nextIncoming) { unsigned destStart = incoming->destOffset; - unsigned destEnd = destStart + genTypeSize(incoming->type); + unsigned destEnd = destStart + m_comp->getSizeOfType(incoming->type); for (RegNodeEdge* otherIncoming = incoming->nextIncoming; otherIncoming != nullptr; otherIncoming = otherIncoming->nextIncoming) { unsigned otherDestStart = otherIncoming->destOffset; - unsigned otherDestEnd = otherDestStart + genTypeSize(otherIncoming->type); + unsigned otherDestEnd = otherDestStart + m_comp->getSizeOfType(otherIncoming->type); if (otherDestEnd <= destStart) { continue; @@ -2972,7 +2972,8 @@ void CodeGen::genSpillOrAddRegisterParam( LclVarDsc* paramVarDsc = compiler->lvaGetDesc(paramLclNum); var_types storeType = genParamStackType(paramVarDsc, segment); - if (!varDsc->TypeIs(TYP_STRUCT) && (genTypeSize(genActualType(varDsc)) < genTypeSize(storeType))) + if (!varDsc->TypeIs(TYP_STRUCT) && + (compiler->getSizeOfType(genActualType(varDsc)) < compiler->getSizeOfType(storeType))) { // Can happen for struct fields due to padding. storeType = genActualType(varDsc); @@ -2991,7 +2992,7 @@ void CodeGen::genSpillOrAddRegisterParam( // Some parameters can be passed in multiple registers but enregistered // in a single one (e.g. SIMD types on arm64). In this case the edges // we add here represent insertions of each element. - if (segment.Size < genTypeSize(edgeType)) + if (segment.Size < compiler->getSizeOfType(edgeType)) { edgeType = segment.GetRegisterType(); } @@ -3266,8 +3267,9 @@ void CodeGen::genHomeRegisterParams(regNumber initReg, bool* initRegStillZeroed) #if defined(TARGET_ARM64) // On arm64 SIMD parameters are HFAs and passed in multiple float // registers while we can enregister them as single registers. + // TODO-SVE: Ensure this works for Z registers as well. GetEmitter()->emitIns_R_R_I_I(INS_mov, emitTypeSize(edge->type), node->reg, sourceReg, - edge->destOffset / genTypeSize(edge->type), 0); + edge->destOffset / compiler->getSizeOfType(edge->type), 0); #elif defined(UNIX_AMD64_ABI) // For SysV x64 the only insertions we should have is to offset 8, // which happens for example for Vector3 which can be passed in @@ -3526,7 +3528,7 @@ void CodeGen::genCheckUseBlockInit() else { // Var is partially enregistered - noway_assert(genTypeSize(varDsc->TypeGet()) > sizeof(int) && + noway_assert(compiler->getSizeOfType(varDsc->TypeGet()) > sizeof(int) && varDsc->GetOtherReg() == REG_STK); initStkLclCnt += genTypeStSz(TYP_INT); counted = true; @@ -5906,7 +5908,7 @@ unsigned Compiler::GetHfaCount(CORINFO_CLASS_HANDLE hClass) var_types hfaType = GetHfaType(hClass); unsigned classSize = info.compCompHnd->getClassSize(hClass); // Note that the retail build issues a warning about a potential division by zero without the Max function - unsigned elemSize = Max((unsigned)1, EA_SIZE_IN_BYTES(emitActualTypeSize(hfaType))); + unsigned elemSize = Max((unsigned)1, getSizeOfType(genActualType(hfaType))); return classSize / elemSize; #endif // TARGET_ARM64 } @@ -7179,7 +7181,7 @@ void CodeGen::genStructReturn(GenTree* treeNode) #endif GetEmitter()->emitIns_R_S(ins_Load(type), emitTypeSize(type), toReg, lclNode->GetLclNum(), offset); - offset += genTypeSize(type); + offset += compiler->getSizeOfType(type); } #endif // !TARGET_LOONGARCH64 && !TARGET_RISCV64 } @@ -7579,7 +7581,7 @@ void CodeGen::genMultiRegStoreToLocal(GenTreeLclVar* lclNode) // It could rewrite memory outside of the fields but local on the stack are rounded to POINTER_SIZE so // it is safe to store a long register into a byte field as it is known that we have enough padding after. GetEmitter()->emitIns_S_R(ins_Store(srcType), emitTypeSize(srcType), reg, lclNum, offset); - offset += genTypeSize(srcType); + offset += compiler->getSizeOfType(srcType); #ifdef DEBUG unsigned stackHomeSize = compiler->lvaLclStackHomeSize(lclNum); diff --git a/src/coreclr/jit/codegenlinear.cpp b/src/coreclr/jit/codegenlinear.cpp index 339ac1eab1610d..875794610309cf 100644 --- a/src/coreclr/jit/codegenlinear.cpp +++ b/src/coreclr/jit/codegenlinear.cpp @@ -1880,7 +1880,7 @@ void CodeGen::genPutArgStkFieldList(GenTreePutArgStk* putArgStk, unsigned outArg } #endif - assert((thisFieldOffset + genTypeSize(type)) <= areaSize); + assert((thisFieldOffset + compiler->getSizeOfType(type)) <= areaSize); #endif } } @@ -2269,8 +2269,19 @@ void CodeGen::genCodeForCast(GenTreeOp* tree) genLongToIntCast(tree); } #endif // !TARGET_64BIT +#ifdef TARGET_ARM64 + else if (targetType == TYP_SIMDSV || tree->gtOp1->TypeGet() == TYP_SIMDSV) + { + // TODO-SVE: Can we avoid generating these casts altogether? + assert(compiler->getSizeOfType(tree->CastToType()) == compiler->getSizeOfType(tree->CastFromType())); + genConsumeOperands(tree); + inst_Mov(tree->CastToType(), tree->GetRegNum(), tree->gtOp1->GetRegNum(), true); + genProduceReg(tree); + } +#endif else { + assert(varTypeIsIntegral(targetType) && varTypeIsIntegral(tree->gtOp1)); // Casts int <--> int genIntToIntCast(tree->AsCast()); } diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index 1bd79546f8458d..4e1342ea104e2a 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -609,29 +609,30 @@ var_types Compiler::getPrimitiveTypeForStruct(unsigned structSize, CORINFO_CLASS // Start by determining if we have an HFA/HVA with a single element. if (GlobalJitOptions::compFeatureHfa) { - switch (structSize) - { - case 4: - case 8: + if (structSize == 4 || + structSize == 8 #ifdef TARGET_ARM64 - case 16: -#endif // TARGET_ARM64 + // Can pass in V register if structSize == 16, and Z registers for structs with sizes in + // multiples of 16-bytes, depending on hardware availability. + || structSize == 16 || ((structSize % 16 == 0) && (structSize == getSizeOfType(TYP_SIMDSV))) +#endif + ) + { + var_types hfaType = GetHfaType(clsHnd); + // We're only interested in the case where the struct size is equal to the size of the hfaType. + if (varTypeIsValidHfaType(hfaType)) { - var_types hfaType = GetHfaType(clsHnd); - // We're only interested in the case where the struct size is equal to the size of the hfaType. - if (varTypeIsValidHfaType(hfaType)) + if (getSizeOfType(hfaType) == structSize) { - if (genTypeSize(hfaType) == structSize) - { - useType = hfaType; - } - else - { - return TYP_UNKNOWN; - } + useType = hfaType; + } + else + { + return TYP_UNKNOWN; } } } + if (useType != TYP_UNKNOWN) { return useType; @@ -861,7 +862,15 @@ var_types Compiler::getReturnTypeForStruct(CORINFO_CLASS_HANDLE clsHnd, // The largest "primitive type" is MAX_PASS_SINGLEREG_BYTES // so we can skip calling getPrimitiveTypeForStruct when we // have a struct that is larger than that. - if (canReturnInRegister && (useType == TYP_UNKNOWN) && (structSize <= MAX_PASS_SINGLEREG_BYTES)) + // + // On ARM64 we can pass structures in scalable vector registers + // which may allow larger structures on some hardware. +#ifdef TARGET_ARM64 + unsigned maxStructSize = max((unsigned)MAX_PASS_SINGLEREG_BYTES, getVectorTByteLength()); +#else + unsigned maxStructSize = MAX_PASS_SINGLEREG_BYTES; +#endif + if (canReturnInRegister && (useType == TYP_UNKNOWN) && (structSize <= maxStructSize)) { // We set the "primitive" useType based upon the structSize // and also examine the clsHnd to see if it is an HFA of count one @@ -872,7 +881,7 @@ var_types Compiler::getReturnTypeForStruct(CORINFO_CLASS_HANDLE clsHnd, if (useType != TYP_UNKNOWN) { - if (structSize == genTypeSize(useType)) + if (structSize == getSizeOfType(useType)) { // Currently: 1, 2, 4, or 8 byte structs howToReturnStruct = SPK_PrimitiveType; diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index fcb6ab779a71bc..9a59623e25d872 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -157,6 +157,10 @@ inline var_types HfaTypeFromElemKind(CorInfoHFAElemType kind) return TYP_SIMD8; case CORINFO_HFA_ELEM_VECTOR128: return TYP_SIMD16; +#ifdef TARGET_ARM64 + case CORINFO_HFA_ELEM_VECTORT: + return TYP_SIMDSV; +#endif #endif case CORINFO_HFA_ELEM_NONE: return TYP_UNDEF; @@ -178,6 +182,10 @@ inline CorInfoHFAElemType HfaElemKindFromType(var_types type) return CORINFO_HFA_ELEM_VECTOR64; case TYP_SIMD16: return CORINFO_HFA_ELEM_VECTOR128; +#ifdef TARGET_ARM64 + case TYP_SIMDSV: + return CORINFO_HFA_ELEM_VECTORT; +#endif #endif case TYP_UNDEF: return CORINFO_HFA_ELEM_NONE; @@ -8213,7 +8221,7 @@ class Compiler assert(type != TYP_STRUCT); // ARM64 ABI FP Callee save registers only require Callee to save lower 8 Bytes // For SIMD types longer than 8 bytes Caller is responsible for saving and restoring Upper bytes. - return ((type == TYP_SIMD16) || (type == TYP_SIMD12)); + return ((type == TYP_SIMDSV) || (type == TYP_SIMD16) || (type == TYP_SIMD12)); } #else // !defined(TARGET_AMD64) && !defined(TARGET_ARM64) #error("Unknown target architecture for FEATURE_PARTIAL_SIMD_CALLEE_SAVE") @@ -10651,6 +10659,8 @@ class Compiler } #endif // !DEBUG + unsigned GetReturnFieldOffset(const ReturnTypeDesc& retDesc, unsigned index); + ReturnTypeDesc compRetTypeDesc; // ABI return type descriptor for the method //------------------------------------------------------------------------ diff --git a/src/coreclr/jit/compiler.hpp b/src/coreclr/jit/compiler.hpp index 12280cde617228..b0021a352ce182 100644 --- a/src/coreclr/jit/compiler.hpp +++ b/src/coreclr/jit/compiler.hpp @@ -1142,6 +1142,11 @@ extern const BYTE genTypeSizes[TYP_COUNT]; template inline unsigned genTypeSize(T value) { +#ifdef TARGET_ARM64 + // The size of these types cannot be evaluated in static contexts. + noway_assert(TypeGet(value) != TYP_SIMDSV); + noway_assert(TypeGet(value) != TYP_MASK); +#endif assert((unsigned)TypeGet(value) < ArrLen(genTypeSizes)); return genTypeSizes[TypeGet(value)]; @@ -1158,6 +1163,11 @@ extern const BYTE genTypeStSzs[TYP_COUNT]; template inline unsigned genTypeStSz(T value) { +#ifdef TARGET_ARM64 + // The size of these types cannot be evaluated in static contexts. + noway_assert(TypeGet(value) != TYP_SIMDSV); + noway_assert(TypeGet(value) != TYP_MASK); +#endif assert((unsigned)TypeGet(value) < ArrLen(genTypeStSzs)); return genTypeStSzs[TypeGet(value)]; @@ -1704,7 +1714,7 @@ inline GenTreeIndexAddr* Compiler::gtNewIndexAddr(GenTree* arrayOp, unsigned lengthOffset) { unsigned elemSize = - (elemType == TYP_STRUCT) ? info.compCompHnd->getClassSize(elemClassHandle) : genTypeSize(elemType); + (elemType == TYP_STRUCT) ? info.compCompHnd->getClassSize(elemClassHandle) : getSizeOfType(elemType); #ifdef DEBUG bool boundsCheck = JitConfig.JitSkipArrayBoundCheck() != 1; @@ -4699,7 +4709,7 @@ GenTree::VisitResult GenTree::VisitLocalDefs(Compiler* comp, TVisitor visitor) if (OperIs(GT_STORE_LCL_FLD)) { GenTreeLclFld* fld = AsLclFld(); - return visitor(LocalDef(fld, !fld->IsPartialLclFld(comp), fld->GetLclOffs(), fld->GetSize())); + return visitor(LocalDef(fld, !fld->IsPartialLclFld(comp), fld->GetLclOffs(), fld->GetSize(comp))); } if (OperIs(GT_CALL)) { diff --git a/src/coreclr/jit/emitarm64.cpp b/src/coreclr/jit/emitarm64.cpp index e88e10568712d3..c326462538f2cb 100644 --- a/src/coreclr/jit/emitarm64.cpp +++ b/src/coreclr/jit/emitarm64.cpp @@ -4266,6 +4266,13 @@ void emitter::emitIns_Mov( { assert(insOptsNone(opt)); + if (attr == EA_SCALABLE) + { + // NEON mov is acceptable for scalable vectors when the vector byte length is 128-bit. + // TODO-SVE: This should not be permitted once Vector has been migrated to SVE. + assert(codeGen->compiler->getVectorTByteLength() == 16); + } + if (IsRedundantMov(ins, size, dstReg, srcReg, canSkip)) { // These instructions have no side effect and can be skipped @@ -4340,6 +4347,7 @@ void emitter::emitIns_Mov( case INS_fmov: { assert(isValidVectorElemsizeFloat(size)); + assert(attr != EA_SCALABLE); if (canSkip && (dstReg == srcReg)) { @@ -4387,35 +4395,22 @@ void emitter::emitIns_Mov( case INS_sve_mov: { + assert(attr == EA_SCALABLE); if (isPredicateRegister(dstReg) && isPredicateRegister(srcReg)) { assert((opt == INS_OPTS_SCALABLE_B) || insOptsNone(opt)); - opt = INS_OPTS_SCALABLE_B; - attr = EA_SCALABLE; - - if (IsRedundantMov(ins, size, dstReg, srcReg, canSkip)) - { - return; - } + opt = INS_OPTS_SCALABLE_B; fmt = IF_SVE_CZ_4A_L; } else if (isVectorRegister(dstReg) && isVectorRegister(srcReg)) { - assert(insOptsScalable(opt)); - - if (IsRedundantMov(ins, size, dstReg, srcReg, canSkip)) - { - return; - } + assert(insOptsScalable(opt) || insOptsNone(opt)); + opt = INS_OPTS_SCALABLE_D; fmt = IF_SVE_AU_3A; } else if (isVectorRegister(dstReg) && isGeneralRegisterOrSP(srcReg)) { assert(insOptsScalable(opt)); - if (IsRedundantMov(ins, size, dstReg, srcReg, canSkip)) - { - return; - } srcReg = encodingSPtoZR(srcReg); fmt = IF_SVE_CB_2A; } @@ -4424,6 +4419,11 @@ void emitter::emitIns_Mov( unreached(); } + if (IsRedundantMov(ins, size, dstReg, srcReg, canSkip)) + { + return; + } + break; } default: diff --git a/src/coreclr/jit/fgdiagnostic.cpp b/src/coreclr/jit/fgdiagnostic.cpp index 602612767a2567..023eef785a67ca 100644 --- a/src/coreclr/jit/fgdiagnostic.cpp +++ b/src/coreclr/jit/fgdiagnostic.cpp @@ -4299,8 +4299,8 @@ class SsaCheckVisitor : public GenTreeVisitor { ProcessDef(def.Def, fieldLclNum, fieldSsaNum); - if (!ValueNumStore::LoadStoreIsEntire(genTypeSize(fieldVarDsc), fieldStoreOffset, - fieldStoreSize)) + if (!ValueNumStore::LoadStoreIsEntire(m_compiler->getSizeOfType(fieldVarDsc->TypeGet()), + fieldStoreOffset, fieldStoreSize)) { assert(isUse); unsigned const fieldUseSsaNum = fieldVarDsc->GetPerSsaData(fieldSsaNum)->GetUseDefSsaNum(); diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 9198a2bbaee29c..6dc39a275e7233 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -3276,6 +3276,9 @@ unsigned Compiler::gtHashValue(GenTree* tree) #endif // TARGET_XARCH case TYP_SIMD16: +#ifdef TARGET_ARM64 + case TYP_SIMDSV: // TODO-SVE: Implement scalable vector constant +#endif { add = genTreeHashAdd(ulo32(add), vecCon->gtSimdVal.u32[3]); FALLTHROUGH; @@ -4532,6 +4535,12 @@ bool Compiler::gtMarkAddrMode(GenTree* addr, int* pCostEx, int* pCostSz, var_typ unsigned naturalMul = 0; #ifdef TARGET_ARM64 + if (type == TYP_SIMDSV) + { + // TODO-SVE: Investigate separately if it's worth using addressing modes + // for scalable types. + return false; + } // Multiplier should be a "natural-scale" power of two number which is equal to target's width. // // *(ulong*)(data + index * 8); - can be optimized @@ -7986,7 +7995,8 @@ GenTreeVecCon* Compiler::gtNewVconNode(var_types type) GenTreeVecCon* Compiler::gtNewVconNode(var_types type, void* data) { GenTreeVecCon* vecCon = new (this, GT_CNS_VEC) GenTreeVecCon(type); - memcpy(&vecCon->gtSimdVal, data, genTypeSize(type)); + // TODO-SVE: Implement scalable vector constant + memcpy(&vecCon->gtSimdVal, data, getSizeOfType(type)); return vecCon; } #endif // FEATURE_SIMD @@ -8089,7 +8099,7 @@ GenTree* Compiler::gtNewOneConNode(var_types type, var_types simdBaseType /* = T { GenTreeVecCon* one = gtNewVconNode(type); - unsigned simdSize = genTypeSize(type); + unsigned simdSize = max(getSizeOfType(type), (unsigned)sizeof(simd_t)); uint32_t simdLength = getSIMDVectorLength(simdSize, simdBaseType); switch (simdBaseType) @@ -8326,6 +8336,8 @@ GenTree* Compiler::gtNewConWithPattern(var_types type, uint8_t pattern) #if defined(TARGET_XARCH) case TYP_SIMD32: case TYP_SIMD64: +#elif defined(TARGET_ARM64) + case TYP_SIMDSV: // TODO-SVE: Implement scalable vector constant #endif // TARGET_XARCH { GenTreeVecCon* node = gtNewVconNode(type); @@ -12276,6 +12288,9 @@ void Compiler::gtDispConst(GenTree* tree) } case TYP_SIMD16: +#ifdef TARGET_ARM64 + case TYP_SIMDSV: // TODO-SVE: Implement scalable vector constant +#endif { printf("<0x%08x, 0x%08x, 0x%08x, 0x%08x>", vecCon->gtSimdVal.u32[0], vecCon->gtSimdVal.u32[1], vecCon->gtSimdVal.u32[2], vecCon->gtSimdVal.u32[3]); @@ -17866,7 +17881,7 @@ bool GenTree::IsLclVarAddr() const bool GenTree::IsPartialLclFld(Compiler* comp) { return OperIs(GT_LCL_FLD, GT_STORE_LCL_FLD) && - (comp->lvaLclExactSize(comp->lvaGetDesc(AsLclFld())) != AsLclFld()->GetSize()); + (comp->lvaLclExactSize(comp->lvaGetDesc(AsLclFld())) != AsLclFld()->GetSize(comp)); } //------------------------------------------------------------------------ @@ -18397,6 +18412,9 @@ void GenTreeVecCon::EvaluateUnaryInPlace(genTreeOps oper, bool scalar, var_types } case TYP_SIMD16: +#ifdef TARGET_ARM64 + case TYP_SIMDSV: +#endif { simd16_t result = {}; EvaluateUnarySimd(oper, scalar, baseType, &result, gtSimd16Val); @@ -18459,6 +18477,9 @@ void GenTreeVecCon::EvaluateBinaryInPlace(genTreeOps oper, bool scalar, var_type } case TYP_SIMD16: +#ifdef TARGET_ARM64 + case TYP_SIMDSV: // TODO-SVE: Implement scalable vector constant +#endif { simd16_t result = {}; EvaluateBinarySimd(oper, scalar, baseType, &result, gtSimd16Val, other->gtSimd16Val); @@ -18601,7 +18622,11 @@ bool GenTreeVecCon::IsBroadcast(var_types simdBaseType) const assert(varTypeIsSIMD(gtType)); assert(varTypeIsArithmetic(simdBaseType)); +#ifdef TARGET_ARM64 + int elementCount = ElementCount(genTypeSize(gtType == TYP_SIMDSV ? TYP_SIMD16 : gtType), simdBaseType); +#else int elementCount = ElementCount(genTypeSize(gtType), simdBaseType); +#endif switch (simdBaseType) { @@ -18650,7 +18675,11 @@ bool GenTreeVecCon::IsBroadcast(var_types simdBaseType) const bool GenTreeVecCon::IsNaN(var_types simdBaseType) const { assert(varTypeIsFloating(simdBaseType)); +#ifdef TARGET_ARM64 + uint32_t elementCount = ElementCount(genTypeSize(gtType == TYP_SIMDSV ? TYP_SIMD16 : gtType), simdBaseType); +#else uint32_t elementCount = ElementCount(genTypeSize(gtType), simdBaseType); +#endif for (uint32_t i = 0; i < elementCount; i++) { @@ -18677,7 +18706,11 @@ bool GenTreeVecCon::IsNaN(var_types simdBaseType) const bool GenTreeVecCon::IsNegativeZero(var_types simdBaseType) const { assert(varTypeIsFloating(simdBaseType)); +#ifdef TARGET_ARM64 + uint32_t elementCount = ElementCount(genTypeSize(gtType == TYP_SIMDSV ? TYP_SIMD16 : gtType), simdBaseType); +#else uint32_t elementCount = ElementCount(genTypeSize(gtType), simdBaseType); +#endif for (uint32_t i = 0; i < elementCount; i++) { @@ -18861,7 +18894,7 @@ bool Compiler::gtStoreDefinesField( LclVarDsc* fieldVarDsc, ssize_t offset, unsigned size, ssize_t* pFieldStoreOffset, unsigned* pFieldStoreSize) { ssize_t fieldOffset = fieldVarDsc->lvFldOffset; - unsigned fieldSize = genTypeSize(fieldVarDsc); // No TYP_STRUCT field locals. + unsigned fieldSize = getSizeOfType(fieldVarDsc->TypeGet()); // No TYP_STRUCT field locals. ssize_t storeEndOffset = offset + static_cast(size); ssize_t fieldEndOffset = fieldOffset + static_cast(fieldSize); @@ -19614,7 +19647,7 @@ void GenTreeArrAddr::ParseArrayAddress(Compiler* comp, GenTree** pArr, ValueNum* } unsigned elemSizeUn = (GetElemType() == TYP_STRUCT) ? comp->typGetObjLayout(GetElemClassHandle())->GetSize() - : genTypeSize(GetElemType()); + : comp->getSizeOfType(GetElemType()); assert(FitsIn(elemSizeUn)); target_ssize_t elemSize = static_cast(elemSizeUn); @@ -27748,6 +27781,12 @@ GenTree* Compiler::gtNewSimdWidenLowerNode(var_types type, GenTree* op1, CorInfo tmp1 = gtNewSimdGetLowerNode(TYP_SIMD8, tmp1, simdBaseJitType, 16); } + if (type == TYP_SIMDSV) + { + // TODO-SVE: Implement SVE widen for Vector + tmp1 = gtNewCastNode(type, tmp1, false, tmp1->TypeGet()); + } + return tmp1; #else #error Unsupported platform @@ -30001,6 +30040,7 @@ NamedIntrinsic GenTreeHWIntrinsic::GetHWIntrinsicIdForBinOp(Compiler* comp, id = NI_X86Base_MultiplyLow; } #elif defined(TARGET_ARM64) + // TODO-SVE: When SVE is enabled for Vector, use SVE intrinsic instead. if ((simdSize == 8) && (isScalar || (simdBaseType == TYP_DOUBLE))) { id = NI_AdvSimd_MultiplyScalar; @@ -30865,7 +30905,7 @@ void ReturnTypeDesc::InitializeStructReturnType(Compiler* comp, assert(varTypeIsValidHfaType(hfaType)); // Note that the retail build issues a warning about a potential divsion by zero without this "max", - unsigned elemSize = max(1u, genTypeSize(hfaType)); + unsigned elemSize = max(1u, comp->getSizeOfType(hfaType)); // The size of this struct should be evenly divisible by elemSize assert((structSize % elemSize) == 0); @@ -31070,6 +31110,7 @@ void ReturnTypeDesc::InitializeReturnType(Compiler* comp, } } +#ifndef TARGET_ARM64 //------------------------------------------------------------------- // GetReturnFieldOffset: // For the N'th returned register, identified by "index", returns the @@ -31093,6 +31134,28 @@ unsigned ReturnTypeDesc::GetReturnFieldOffset(unsigned index) const return offset; #endif } +#endif + +//------------------------------------------------------------------- +// GetReturnFieldOffset: +// For the N'th returned register, identified by "index", returns the +// starting offset in the struct return type of the data being returned. +// +// Arguments: +// retDesc - The return type descriptor +// index - The register whose offset to get +// +// Return Value: +// Starting offset of data returned in that register. +// +unsigned Compiler::GetReturnFieldOffset(const ReturnTypeDesc& retDesc, unsigned index) +{ + assert(retDesc.GetReturnRegType(index) != TYP_UNKNOWN); + unsigned offset = 0; + for (unsigned i = 0; i < index; i++) + offset += getSizeOfType(retDesc.GetReturnRegType(i)); + return offset; +} //------------------------------------------------------------------- // GetABIReturnReg: Return i'th return register as per target ABI @@ -31589,9 +31652,9 @@ unsigned GenTreeHWIntrinsic::GetResultOpNumForRmwIntrinsic(GenTree* use, GenTree } #endif // TARGET_XARCH && FEATURE_HW_INTRINSICS -unsigned GenTreeLclFld::GetSize() const +unsigned GenTreeLclFld::GetSize(Compiler* comp) const { - return TypeIs(TYP_STRUCT) ? GetLayout()->GetSize() : genTypeSize(TypeGet()); + return TypeIs(TYP_STRUCT) ? GetLayout()->GetSize() : comp->getSizeOfType(TypeGet()); } #ifdef TARGET_ARM @@ -33608,8 +33671,9 @@ GenTree* Compiler::gtFoldExprHWIntrinsic(GenTreeHWIntrinsic* tree) if (op2->IsCnsVec() && op3->IsCnsVec()) { assert(ni == NI_Sve_ConditionalSelect); - assert(op2->gtType == TYP_SIMD16); - assert(op3->gtType == TYP_SIMD16); + // TODO-SVE: Implement scalable vector constant + assert(op2->gtType == TYP_SIMD16 || op2->gtType == TYP_SIMDSV); + assert(op3->gtType == TYP_SIMD16 || op3->gtType == TYP_SIMDSV); simd16_t op1SimdVal = {}; EvaluateSimdCvtMaskToVector(simdBaseType, &op1SimdVal, op1->AsMskCon()->gtSimdMaskVal); @@ -33814,6 +33878,9 @@ GenTreeMskCon* Compiler::gtFoldExprConvertVecCnsToMask(GenTreeHWIntrinsic* tree, } case TYP_SIMD16: +#ifdef TARGET_ARM64 + case TYP_SIMDSV: // TODO-SVE: Implement scalable vector constant +#endif { EvaluateSimdCvtVectorToMask(simdBaseType, &mskCon->gtSimdMaskVal, vecCon->gtSimd16Val); break; diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index 100f17301ea267..dea9069ab91ceb 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -3959,7 +3959,7 @@ struct GenTreeLclFld : public GenTreeLclVarCommon m_layout = layout; } - unsigned GetSize() const; + unsigned GetSize(Compiler* comp) const; #ifdef TARGET_ARM bool IsOffsetMisaligned() const; @@ -4574,7 +4574,9 @@ struct ReturnTypeDesc #endif } +#ifndef TARGET_ARM64 unsigned GetReturnFieldOffset(unsigned index) const; +#endif // Get i'th ABI return register regNumber GetABIReturnReg(unsigned idx, CorInfoCallConvExtension callConv) const; @@ -7020,7 +7022,11 @@ struct GenTreeVecCon : public GenTree } case TYP_SIMD16: +#ifdef TARGET_ARM64 + case TYP_SIMDSV: +#endif { + // TODO-SVE: Implement scalable vector constant simd16_t result = {}; BroadcastConstantToSimd(&result, scalar); gtSimd16Val = result; @@ -7076,6 +7082,9 @@ struct GenTreeVecCon : public GenTree } case TYP_SIMD16: +#ifdef TARGET_ARM64 + case TYP_SIMDSV: +#endif { simd16_t result = {}; EvaluateWithElementFloating(simdBaseType, &result, gtSimd16Val, index, value); @@ -7129,6 +7138,9 @@ struct GenTreeVecCon : public GenTree } case TYP_SIMD16: +#ifdef TARGET_ARM64 + case TYP_SIMDSV: +#endif { simd16_t result = {}; EvaluateWithElementIntegral(simdBaseType, &result, gtSimd16Val, index, value); @@ -7176,6 +7188,9 @@ struct GenTreeVecCon : public GenTree } case TYP_SIMD16: +#ifdef TARGET_ARM64 + case TYP_SIMDSV: +#endif { return gtSimd16Val.IsAllBitsSet(); } @@ -7224,6 +7239,9 @@ struct GenTreeVecCon : public GenTree } case TYP_SIMD16: +#ifdef TARGET_ARM64 + case TYP_SIMDSV: // TODO-SVE: Implement scalable vector constant +#endif { return left->gtSimd16Val == right->gtSimd16Val; } @@ -7267,6 +7285,9 @@ struct GenTreeVecCon : public GenTree } case TYP_SIMD16: +#ifdef TARGET_ARM64 + case TYP_SIMDSV: +#endif { return gtSimd16Val.IsZero(); } @@ -7306,6 +7327,9 @@ struct GenTreeVecCon : public GenTree } case TYP_SIMD16: +#ifdef TARGET_ARM64 + case TYP_SIMDSV: +#endif { return EvaluateGetElementFloating(simdBaseType, gtSimd16Val, index); } @@ -7344,6 +7368,9 @@ struct GenTreeVecCon : public GenTree } case TYP_SIMD16: +#ifdef TARGET_ARM64 + case TYP_SIMDSV: +#endif { return EvaluateGetElementIntegral(simdBaseType, gtSimd16Val, index); } @@ -7934,8 +7961,6 @@ struct GenTreeIndir : public GenTreeOp unsigned Scale(); ssize_t Offset(); - unsigned Size() const; - GenTreeIndir(genTreeOps oper, var_types type, GenTree* addr, GenTree* data) : GenTreeOp(oper, type, addr, data) { diff --git a/src/coreclr/jit/hwintrinsicarm64.cpp b/src/coreclr/jit/hwintrinsicarm64.cpp index 9a89ac905074cf..2a3d49a77d6a13 100644 --- a/src/coreclr/jit/hwintrinsicarm64.cpp +++ b/src/coreclr/jit/hwintrinsicarm64.cpp @@ -612,9 +612,9 @@ GenTree* Compiler::impNonConstFallback(NamedIntrinsic intrinsic, var_types simdT unreached(); } - GenTree* tmpOp = gtNewSimdCreateBroadcastNode(simdType, op2, simdBaseJitType, genTypeSize(simdType)); + GenTree* tmpOp = gtNewSimdCreateBroadcastNode(simdType, op2, simdBaseJitType, getSizeOfType(simdType)); return gtNewSimdHWIntrinsicNode(simdType, op1, tmpOp, fallbackIntrinsic, simdBaseJitType, - genTypeSize(simdType)); + getSizeOfType(simdType)); } default: @@ -800,13 +800,22 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, assert(!sig->hasThis()); assert(numArgs == 1); - // We fold away the cast here, as it only exists to satisfy - // the type system. It is safe to do this here since the retNode type - // and the signature return type are both the same TYP_SIMD. - retNode = impSIMDPopStack(); SetOpLclRelatedToSIMDIntrinsic(retNode); - assert(retNode->gtType == getSIMDTypeForSize(getSIMDTypeSizeInBytes(sig->retTypeSigClass))); + + if (intrinsic == NI_Vector128_AsVector && JitConfig.JitUseScalableVectorT()) + { + // A cast node is required to convert from TYP_SIMD16 to TYP_SIMDSV. + assert(retNode->TypeGet() == TYP_SIMD16); + retNode = gtNewCastNode(TYP_SIMDSV, retNode, false, retNode->TypeGet()); + } + else + { + // We fold away the cast here, as it only exists to satisfy + // the type system. It is safe to do this here since the retNode type + // and the signature return type are both the same TYP_SIMD. + assert(retNode->gtType == getSIMDType(sig->retTypeSigClass)); + } break; } @@ -901,7 +910,20 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, retNode = impSIMDPopStack(); SetOpLclRelatedToSIMDIntrinsic(retNode); - assert(retNode->gtType == getSIMDTypeForSize(getSIMDTypeSizeInBytes(sig->retTypeSigClass))); + + if (retNode->TypeGet() == TYP_SIMDSV) + { + // Truncate TYP_SIMDSV to TYP_SIMD16. This is a no-op and just keeps + // the type system consistent. + retNode = gtNewCastNode(TYP_SIMD16, retNode, false, retNode->TypeGet()); + } + else + { + // We fold away the cast here, as it only exists to satisfy + // the type system. It is safe to do this here since the retNode type + // and the signature return type are both the same TYP_SIMD. + } + assert(retNode->gtType == getSIMDType(sig->retTypeSigClass)); break; } @@ -3501,6 +3523,13 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, } } + if (retNode != nullptr && retType == TYP_SIMDSV) + { + // If we've been asked to return a scalable Vector we should either see + // a scalable vector type or a mask type come out of this function. + assert(retNode->TypeIs(TYP_SIMDSV, TYP_MASK)); + } + assert(!isScalar || isValidScalarIntrinsic); return retNode; diff --git a/src/coreclr/jit/hwintrinsiccodegenarm64.cpp b/src/coreclr/jit/hwintrinsiccodegenarm64.cpp index 624c59347b475b..048ffa2fc17c17 100644 --- a/src/coreclr/jit/hwintrinsiccodegenarm64.cpp +++ b/src/coreclr/jit/hwintrinsiccodegenarm64.cpp @@ -82,7 +82,7 @@ CodeGen::HWIntrinsicImmOpHelper::HWIntrinsicImmOpHelper(CodeGen* code assert(varTypeIsSIMD(indexedElementOpType)); - const unsigned int indexedElementSimdSize = genTypeSize(indexedElementOpType); + const unsigned int indexedElementSimdSize = codeGen->compiler->getSizeOfType(indexedElementOpType); HWIntrinsicInfo::lookupImmBounds(intrin->GetHWIntrinsicId(), indexedElementSimdSize, intrin->GetSimdBaseType(), 1, &immLowerBound, &immUpperBound); } @@ -370,7 +370,8 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) { assert((targetReg == op1Reg) || (targetReg != op2Reg) || genIsSameLocalVar(intrin.op1, intrin.op2)); assert((targetReg == op1Reg) || (targetReg != op3Reg) || genIsSameLocalVar(intrin.op1, intrin.op3)); - GetEmitter()->emitIns_Mov(INS_mov, emitTypeSize(node), targetReg, op1Reg, /* canSkip */ true); + + inst_Mov(node->TypeGet(), targetReg, op1Reg, true); HWIntrinsicImmOpHelper helper(this, intrin.op4, node); @@ -414,7 +415,7 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) { assert((targetReg == op1Reg) || (targetReg != op2Reg) || genIsSameLocalVar(intrin.op1, intrin.op2)); assert((targetReg == op1Reg) || (targetReg != op3Reg) || genIsSameLocalVar(intrin.op1, intrin.op3)); - GetEmitter()->emitIns_Mov(INS_mov, emitTypeSize(node), targetReg, op1Reg, /* canSkip */ true); + inst_Mov(node->TypeGet(), targetReg, op1Reg, true); GetEmitter()->emitIns_R_R_R_I(ins, emitSize, targetReg, op2Reg, op3Reg, 0, opt); } else @@ -441,7 +442,7 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) if (isRMW) { - GetEmitter()->emitIns_Mov(INS_mov, emitTypeSize(node), targetReg, op1Reg, /* canSkip */ true); + inst_Mov(node->TypeGet(), targetReg, op1Reg, true); emitShift(intrin.op3, op2Reg); } else @@ -545,8 +546,7 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) // If falseReg value and embMaskOp1Reg value are same, then just mov the value // to the target. - GetEmitter()->emitIns_Mov(INS_mov, emitTypeSize(node), targetReg, embMaskOp1Reg, - /* canSkip */ true); + inst_Mov(node->TypeGet(), targetReg, embMaskOp1Reg, true); } else { @@ -651,8 +651,7 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) // At this point, target != embMaskOp1Reg != falseReg, so just go ahead // and move the falseReg unpredicated into targetReg. // Cannot use movprfx for zeroing mask operations. - GetEmitter()->emitIns_Mov(INS_mov, emitTypeSize(node), targetReg, falseReg, - /* canSkip */ true); + inst_Mov(node->TypeGet(), targetReg, falseReg, true); } else { @@ -1083,9 +1082,7 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) { assert((targetReg == op2Reg) || (targetReg != op1Reg) || genIsSameLocalVar(intrin.op1, intrin.op2)); - GetEmitter()->emitIns_Mov(ins_Move_Extend(intrin.op2->TypeGet(), false), - emitTypeSize(node), targetReg, op2Reg, - /* canSkip */ true); + inst_Mov(node->TypeGet(), targetReg, op2Reg, true); GetEmitter()->emitIns_R_R(ins, emitSize, targetReg, op1Reg, opt); } else @@ -1104,8 +1101,7 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) { assert((targetReg == op1Reg) || (targetReg != op2Reg) || genIsSameLocalVar(intrin.op1, intrin.op2)); - GetEmitter()->emitIns_Mov(INS_mov, emitTypeSize(node), targetReg, op1Reg, - /* canSkip */ true); + inst_Mov(node->TypeGet(), targetReg, op1Reg, true); GetEmitter()->emitIns_R_R(ins, emitSize, targetReg, op2Reg, opt); } else @@ -1126,8 +1122,7 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) assert((targetReg == op2Reg) || (targetReg != op3Reg) || genIsSameLocalVar(intrin.op2, intrin.op3)); - GetEmitter()->emitIns_Mov(INS_mov, emitTypeSize(node), targetReg, op2Reg, - /* canSkip */ true); + inst_Mov(node->TypeGet(), targetReg, op2Reg, true); GetEmitter()->emitIns_R_R_R(ins, emitSize, targetReg, op1Reg, op3Reg, opt); } else @@ -1137,8 +1132,7 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) assert((targetReg == op1Reg) || (targetReg != op3Reg) || genIsSameLocalVar(intrin.op1, intrin.op3)); - GetEmitter()->emitIns_Mov(INS_mov, emitTypeSize(node), targetReg, op1Reg, - /* canSkip */ true); + inst_Mov(node->TypeGet(), targetReg, op1Reg, true); GetEmitter()->emitIns_R_R_R(ins, emitSize, targetReg, op2Reg, op3Reg, opt); } } @@ -1353,7 +1347,7 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) { assert(isRMW); - GetEmitter()->emitIns_Mov(INS_mov, emitTypeSize(node), targetReg, op1Reg, /* canSkip */ true); + inst_Mov(node->TypeGet(), targetReg, op1Reg, true); // fmov (scalar) zeros the upper bits and is not safe to use assert(!intrin.op3->isContainedFltOrDblImmed()); @@ -1387,7 +1381,8 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) { assert(isRMW); assert((targetReg == op1Reg) || (targetReg != op3Reg) || genIsSameLocalVar(intrin.op1, intrin.op3)); - GetEmitter()->emitIns_Mov(INS_mov, emitTypeSize(node), targetReg, op1Reg, /* canSkip */ true); + + inst_Mov(node->TypeGet(), targetReg, op1Reg, true); HWIntrinsicImmOpHelper helper(this, intrin.op2, node); @@ -1404,7 +1399,8 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) { assert(isRMW); assert((targetReg == op1Reg) || (targetReg != op3Reg) || genIsSameLocalVar(intrin.op1, intrin.op3)); - GetEmitter()->emitIns_Mov(INS_mov, emitTypeSize(node), targetReg, op1Reg, /* canSkip */ true); + + inst_Mov(node->TypeGet(), targetReg, op1Reg, true); const int resultIndex = (int)intrin.op2->AsIntCon()->gtIconVal; const int valueIndex = (int)intrin.op4->AsIntCon()->gtIconVal; @@ -1416,7 +1412,8 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) { assert(isRMW); assert((targetReg == op1Reg) || (targetReg != op3Reg) || genIsSameLocalVar(intrin.op1, intrin.op3)); - GetEmitter()->emitIns_Mov(INS_mov, emitTypeSize(node), targetReg, op1Reg, /* canSkip */ true); + + inst_Mov(node->TypeGet(), targetReg, op1Reg, true); HWIntrinsicImmOpHelper helper(this, intrin.op2, node); @@ -1456,8 +1453,7 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) targetFieldReg = node->GetRegByIndex(fieldIdx); op1FieldReg = fieldNode->GetRegNum(); - GetEmitter()->emitIns_Mov(INS_mov, emitTypeSize(fieldNode), targetFieldReg, op1FieldReg, - /* canSkip */ true); + inst_Mov(fieldNode->TypeGet(), targetFieldReg, op1FieldReg, true); fieldIdx++; } @@ -1643,7 +1639,7 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) { ins = varTypeIsUnsigned(intrin.baseType) ? INS_usqadd : INS_suqadd; - GetEmitter()->emitIns_Mov(INS_mov, emitTypeSize(node), targetReg, op1Reg, /* canSkip */ true); + inst_Mov(node->TypeGet(), targetReg, op1Reg, true); GetEmitter()->emitIns_R_R(ins, emitSize, targetReg, op2Reg, opt); } else @@ -2012,7 +2008,7 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) } assert((targetReg == op1Reg) || (targetReg != op3Reg) || genIsSameLocalVar(intrin.op1, intrin.op3)); - GetEmitter()->emitIns_Mov(INS_mov, emitTypeSize(node), targetReg, op1Reg, /* canSkip */ true); + inst_Mov(node->TypeGet(), targetReg, op1Reg, true); GetEmitter()->emitIns_R_R_R(ins, emitSize, targetReg, op2Reg, op3Reg, opt); break; } @@ -2400,7 +2396,7 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) assert(isRMW); assert((targetReg == op1Reg) || (targetReg != op2Reg) || genIsSameLocalVar(intrin.op1, intrin.op2)); assert((targetReg == op1Reg) || (targetReg != op3Reg) || genIsSameLocalVar(intrin.op1, intrin.op3)); - GetEmitter()->emitIns_Mov(INS_mov, emitTypeSize(node), targetReg, op1Reg, /* canSkip */ true); + inst_Mov(node->TypeGet(), targetReg, op1Reg, true); if (intrin.op2->IsCnsIntOrI() && intrin.op3->IsCnsIntOrI()) { @@ -2453,7 +2449,7 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) { // RMW semantics assert((targetReg == op1Reg) || (targetReg != op2Reg) || genIsSameLocalVar(intrin.op1, intrin.op2)); - GetEmitter()->emitIns_Mov(INS_mov, emitTypeSize(node), targetReg, op1Reg, /* canSkip */ true); + inst_Mov(node->TypeGet(), targetReg, op1Reg, true); // Switch instruction if arg1 is unsigned. if (varTypeIsUnsigned(node->GetAuxiliaryType())) @@ -2493,7 +2489,7 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) { assert(isRMW); assert((targetReg == op1Reg) || (targetReg != op2Reg) || genIsSameLocalVar(intrin.op1, intrin.op2)); - GetEmitter()->emitIns_Mov(INS_mov, emitTypeSize(node), targetReg, op1Reg, /* canSkip */ true); + GetEmitter()->emitIns_Mov(INS_sve_mov, EA_SCALABLE, targetReg, op1Reg, /* canSkip */ true); HWIntrinsicImmOpHelper helper(this, intrin.op3, node); @@ -2512,7 +2508,7 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) assert(isRMW); assert(emitter::isFloatReg(op2Reg) == varTypeIsFloating(intrin.baseType)); assert((targetReg == op1Reg) || (targetReg != op2Reg) || genIsSameLocalVar(intrin.op1, intrin.op2)); - GetEmitter()->emitIns_Mov(INS_mov, emitTypeSize(node), targetReg, op1Reg, + GetEmitter()->emitIns_Mov(INS_sve_mov, EA_SCALABLE, targetReg, op1Reg, /* canSkip */ true); GetEmitter()->emitInsSve_R_R(ins, emitSize, targetReg, op2Reg, opt); break; @@ -2538,7 +2534,7 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) assert(isRMW); assert(HWIntrinsicInfo::IsExplicitMaskedOperation(intrin.id)); assert((targetReg == op2Reg) || (targetReg != op1Reg) || genIsSameLocalVar(intrin.op2, intrin.op1)); - GetEmitter()->emitIns_Mov(INS_sve_mov, emitTypeSize(node), targetReg, op2Reg, /* canSkip */ true); + GetEmitter()->emitIns_Mov(INS_sve_mov, EA_SCALABLE, targetReg, op2Reg, /* canSkip */ true); GetEmitter()->emitIns_R_R(ins, emitSize, targetReg, op1Reg, INS_OPTS_SCALABLE_B); break; } @@ -2594,8 +2590,7 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) assert((targetReg == op2Reg) || (targetReg != op1Reg)); assert((targetReg == op2Reg) || (targetReg != op3Reg)); - GetEmitter()->emitIns_Mov(INS_mov, emitSize, targetReg, op2Reg, - /* canSkip */ true); + inst_Mov(node->TypeGet(), targetReg, op2Reg, true); GetEmitter()->emitInsSve_R_R_R(ins, emitSize, targetReg, op1Reg, op3Reg, opt, INS_SCALABLE_OPTS_NONE); break; @@ -2737,7 +2732,7 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) case NI_Sve2_AddCarryWideningOdd: if (targetReg != op3Reg) { - GetEmitter()->emitIns_Mov(INS_mov, emitTypeSize(node), targetReg, op3Reg, /* canSkip */ true); + inst_Mov(node->TypeGet(), targetReg, op3Reg, true); } GetEmitter()->emitInsSve_R_R_R(ins, emitSize, targetReg, op1Reg, op2Reg, opt); break; diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index beca2374c6713a..5dd759e71938fa 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -11755,7 +11755,7 @@ GenTree* Compiler::impArrayAccessIntrinsic( } } - unsigned arrayElemSize = (elemType == TYP_STRUCT) ? elemLayout->GetSize() : genTypeSize(elemType); + unsigned arrayElemSize = (elemType == TYP_STRUCT) ? elemLayout->GetSize() : getSizeOfType(elemType); if (!FitsIn(arrayElemSize)) { diff --git a/src/coreclr/jit/inductionvariableopts.cpp b/src/coreclr/jit/inductionvariableopts.cpp index e107701219edc6..9e1885a44c5d31 100644 --- a/src/coreclr/jit/inductionvariableopts.cpp +++ b/src/coreclr/jit/inductionvariableopts.cpp @@ -2332,7 +2332,7 @@ bool StrengthReductionContext::StaysWithinManagedObject(ArrayStack* unsigned arrElemSize = arrAddr->GetElemType() == TYP_STRUCT ? m_comp->typGetObjLayout(arrAddr->GetElemClassHandle())->GetSize() - : genTypeSize(arrAddr->GetElemType()); + : m_comp->getSizeOfType(arrAddr->GetElemType()); int64_t stepCns; if (!addRec->Step->GetConstantValue(m_comp, &stepCns) || ((unsigned)stepCns > arrElemSize)) diff --git a/src/coreclr/jit/instr.cpp b/src/coreclr/jit/instr.cpp index 5e918a8481823f..797aca21f6e85e 100644 --- a/src/coreclr/jit/instr.cpp +++ b/src/coreclr/jit/instr.cpp @@ -2183,6 +2183,13 @@ instruction CodeGenInterface::ins_Load(var_types srcType, bool aligned /*=false* return ins; } +#if defined(TARGET_ARM64) && defined(FEATURE_SIMD) + if (srcType == TYP_SIMDSV) + { + return INS_sve_ldr; + } +#endif + #if defined(FEATURE_MASKED_HW_INTRINSICS) if (varTypeUsesMaskReg(srcType)) { @@ -2386,6 +2393,15 @@ instruction CodeGen::ins_Copy(regNumber srcReg, var_types dstType) #endif } +#if defined(TARGET_ARM64) && defined(FEATURE_SIMD) + if (dstType == TYP_SIMDSV) + { + // Can only copy vector to other vector. + assert(genIsValidFloatReg(srcReg)); + return INS_sve_mov; + } +#endif + #if defined(FEATURE_MASKED_HW_INTRINSICS) if (varTypeUsesMaskReg(dstType)) { @@ -2507,6 +2523,13 @@ instruction CodeGenInterface::ins_Store(var_types dstType, bool aligned /*=false return ins; } +#if defined(TARGET_ARM64) && defined(FEATURE_SIMD) + if (dstType == TYP_SIMDSV) + { + return INS_sve_str; + } +#endif + #if defined(FEATURE_MASKED_HW_INTRINSICS) if (varTypeUsesMaskReg(dstType)) { diff --git a/src/coreclr/jit/jitconfigvalues.h b/src/coreclr/jit/jitconfigvalues.h index 3a9188a3e1eb0f..af4f3baca368f6 100644 --- a/src/coreclr/jit/jitconfigvalues.h +++ b/src/coreclr/jit/jitconfigvalues.h @@ -844,6 +844,9 @@ CONFIG_STRING(JitRawHexCodeFile, "JitRawHexCodeFile") // 3: force all frames to use the frame types that save FP/LR registers with the callee-saved registers (at the top // of the frame) and also force using the large funclet frame variation (frame 5) if possible. CONFIG_INTEGER(JitSaveFpLrWithCalleeSavedRegisters, "JitSaveFpLrWithCalleeSavedRegisters", 0) + +// Experimental support for vector length agnostic implementation of Vector +CONFIG_INTEGER(JitUseScalableVectorT, "JitUseScalableVectorT", 0) #endif // defined(TARGET_ARM64) #if defined(TARGET_LOONGARCH64) diff --git a/src/coreclr/jit/lclmorph.cpp b/src/coreclr/jit/lclmorph.cpp index 1c4bf4201666ba..f02a52bf1d89d4 100644 --- a/src/coreclr/jit/lclmorph.cpp +++ b/src/coreclr/jit/lclmorph.cpp @@ -1733,8 +1733,9 @@ class LocalAddressVisitor final : public GenTreeVisitor { // Handle case 1 or the float field of case 2 GenTree* indexNode = m_compiler->gtNewIconNode(offset / genTypeSize(elementType)); - hwiNode = m_compiler->gtNewSimdGetElementNode(elementType, lclNode, indexNode, - CORINFO_TYPE_FLOAT, genTypeSize(varDsc)); + hwiNode = + m_compiler->gtNewSimdGetElementNode(elementType, lclNode, indexNode, CORINFO_TYPE_FLOAT, + m_compiler->getSizeOfType(varDsc->TypeGet())); break; } @@ -1791,9 +1792,9 @@ class LocalAddressVisitor final : public GenTreeVisitor { // Handle case 1 or the float field of case 2 GenTree* indexNode = m_compiler->gtNewIconNode(offset / genTypeSize(elementType)); - hwiNode = - m_compiler->gtNewSimdWithElementNode(varDsc->TypeGet(), simdLclNode, indexNode, elementNode, - CORINFO_TYPE_FLOAT, genTypeSize(varDsc)); + hwiNode = m_compiler->gtNewSimdWithElementNode(varDsc->TypeGet(), simdLclNode, indexNode, + elementNode, CORINFO_TYPE_FLOAT, + m_compiler->getSizeOfType(varDsc->TypeGet())); break; } @@ -2019,8 +2020,11 @@ class LocalAddressVisitor final : public GenTreeVisitor return IndirTransform::NarrowCast; } - if ((genTypeSize(indir) == genTypeSize(varDsc)) && (genTypeSize(indir) <= TARGET_POINTER_SIZE) && - (varTypeIsFloating(indir) || varTypeIsFloating(varDsc)) && !varDsc->lvPromoted) + unsigned indirTypeSize = m_compiler->getSizeOfType(indir->TypeGet()); + + if ((indirTypeSize == m_compiler->getSizeOfType(varDsc->TypeGet())) && + (indirTypeSize <= TARGET_POINTER_SIZE) && (varTypeIsFloating(indir) || varTypeIsFloating(varDsc)) && + !varDsc->lvPromoted) { return IndirTransform::BitCast; } @@ -2143,7 +2147,7 @@ class LocalAddressVisitor final : public GenTreeVisitor // Retargeting the indirection to reference the promoted field would make it "wide", exposing // the whole parent struct (with all of its fields). - if (accessSize > genTypeSize(fieldVarDsc)) + if (accessSize > m_compiler->getSizeOfType(fieldVarDsc->TypeGet())) { return BAD_VAR_NUM; } diff --git a/src/coreclr/jit/lclvars.cpp b/src/coreclr/jit/lclvars.cpp index d4f9096c3faf23..9acc38b523afb2 100644 --- a/src/coreclr/jit/lclvars.cpp +++ b/src/coreclr/jit/lclvars.cpp @@ -102,8 +102,8 @@ void Compiler::lvaInitTypeRef() varTypeIsStruct(info.compRetType) ? eeGetClassName(retClass) : ""); for (unsigned i = 0; i < returnRegCount; i++) { - unsigned offset = compRetTypeDesc.GetReturnFieldOffset(i); - unsigned size = genTypeSize(compRetTypeDesc.GetReturnRegType(i)); + unsigned offset = GetReturnFieldOffset(compRetTypeDesc, i); + unsigned size = getSizeOfType(compRetTypeDesc.GetReturnRegType(i)); printf(" [%02u..%02u) reg %s\n", offset, offset + size, getRegName(compRetTypeDesc.GetABIReturnReg(i, info.compCallConv))); } @@ -1992,8 +1992,9 @@ void Compiler::StructPromotionHelper::PromoteStructVar(unsigned lclNum) var_types hfaType = compiler->GetHfaType(pFieldInfo->fldSIMDTypeHnd); if (varTypeIsValidHfaType(hfaType)) { - fieldVarDsc->lvIsMultiRegArg = (varDsc->lvIsMultiRegArg != 0) && - (compiler->lvaLclExactSize(fieldVarDsc) > genTypeSize(hfaType)); + fieldVarDsc->lvIsMultiRegArg = + (varDsc->lvIsMultiRegArg != 0) && + (compiler->lvaLclExactSize(fieldVarDsc) > compiler->getSizeOfType(hfaType)); } } } @@ -2736,6 +2737,13 @@ unsigned Compiler::lvaLclStackHomeSize(unsigned varNum) LclVarDsc* varDsc = lvaGetDesc(varNum); var_types varType = varDsc->TypeGet(); +#ifdef TARGET_ARM64 + if (varType == TYP_SIMDSV) + { + return getSizeOfSIMDType(varType); + } +#endif + if (!varTypeIsStruct(varType)) { #ifdef TARGET_64BIT @@ -3147,6 +3155,9 @@ void Compiler::lvaSortByRefCount() case TYP_SIMD32: case TYP_SIMD64: #endif // TARGET_XARCH +#ifdef TARGET_ARM64 + case TYP_SIMDSV: +#endif #ifdef FEATURE_MASKED_HW_INTRINSICS case TYP_MASK: #endif // FEATURE_MASKED_HW_INTRINSICS @@ -6327,7 +6338,7 @@ void Compiler::lvaDumpEntry(unsigned lclNum, FrameLayoutState curState, size_t r refCntWtd2str(varDsc->lvRefCntWtd(lvaRefCountState), /* padForDecimalPlaces */ true)); printf(" %7s ", varTypeName(type)); - if (genTypeSize(type) == 0) + if (getSizeOfType(type) == 0) { printf("(%2d) ", lvaLclStackHomeSize(lclNum)); } @@ -7005,7 +7016,7 @@ Compiler::fgWalkResult Compiler::lvaStressLclFldCB(GenTree** pTree, fgWalkData* // node with the accurate small type. If we bash lvaTable[].lvType, // then there will be no indication that it was ever a small type. - if (genTypeSize(varType) != genTypeSize(genActualType(varType))) + if (pComp->getSizeOfType(varType) != pComp->getSizeOfType(genActualType(varType))) { varDsc->lvNoLclFldStress = true; return WALK_CONTINUE; diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index 8ef5e236555a04..d98f870584b5da 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -1692,7 +1692,7 @@ void Lowering::SplitArgumentBetweenRegistersAndStack(GenTreeCall* call, CallArg* break; } - if (use.GetOffset() + genTypeSize(use.GetType()) > stackSeg.Offset) + if (use.GetOffset() + comp->getSizeOfType(use.GetType()) > stackSeg.Offset) { // Field overlaps partially into the stack segment, cannot // handle this without spilling. @@ -1932,7 +1932,7 @@ void Lowering::InsertBitCastIfNecessary(GenTree** argNode, const ABIPassingSegme // such cases we cut off the end of the segment to get an appropriate // register type for the bitcast. ABIPassingSegment cutRegisterSegment = registerSegment; - unsigned argNodeSize = genTypeSize(genActualType(*argNode)); + unsigned argNodeSize = comp->getSizeOfType(genActualType(*argNode)); if (registerSegment.Size > argNodeSize) { cutRegisterSegment = @@ -2304,7 +2304,7 @@ bool Lowering::LowerCallMemset(GenTreeCall* call, GenTree** next) valueArg = valueCallArg->GetNode(); // Get that from the signature - lengthScale = genTypeSize(valueCallArg->GetSignatureType()); + lengthScale = comp->getSizeOfType(valueCallArg->GetSignatureType()); // NOTE: structs and TYP_REF will be ignored by the "Value is not a constant" check // Some of those cases can be enabled in future, e.g. s } @@ -2612,10 +2612,10 @@ bool Lowering::LowerCallMemcmp(GenTreeCall* call, GenTree** next) { assert(type == TYP_INT); return comp->gtNewSimdCmpOpAllNode(oper, TYP_INT, op1, op2, CORINFO_TYPE_NATIVEUINT, - genTypeSize(op1)); + comp->getSizeOfType(op1)); } return comp->gtNewSimdBinOpNode(oper, op1->TypeGet(), op1, op2, CORINFO_TYPE_NATIVEUINT, - genTypeSize(op1)); + comp->getSizeOfType(op1)); } #endif return comp->gtNewOperNode(oper, type, op1, op2); @@ -4364,7 +4364,7 @@ GenTree* Lowering::OptimizeConstCompare(GenTree* cmp) andOp1->gtType = TYP_UBYTE; andOp2->gtType = TYP_UBYTE; } - else if (FitsIn(mask) && genTypeSize(andOp1) == 2) + else if (FitsIn(mask) && comp->getSizeOfType(andOp1) == 2) { andOp1->gtType = TYP_USHORT; andOp2->gtType = TYP_USHORT; @@ -4564,7 +4564,7 @@ GenTree* Lowering::LowerJTrue(GenTreeOp* jtrue) cc = cond->OperIs(GT_LT) ? GenCondition(GenCondition::NE) : GenCondition(GenCondition::EQ); // x < 0 => (x & signBit) != 0. Update the constant to be the sign bit. relopOp2->AsIntConCommon()->SetIntegralValue( - (static_cast(1) << (8 * genTypeSize(genActualType(relopOp1)) - 1))); + (static_cast(1) << (8 * comp->getSizeOfType(genActualType(relopOp1)) - 1))); } else if (cond->OperIs(GT_TEST_EQ, GT_TEST_NE) && isPow2(relopOp2->AsIntCon()->IconValue())) { @@ -4995,8 +4995,9 @@ void Lowering::LowerRet(GenTreeOp* ret) var_types retActualType = genActualType(comp->info.compRetNativeType); var_types retValActualType = genActualType(retVal->TypeGet()); - bool constStructInit = retVal->IsConstInitVal(); - bool implicitCastFromSameOrBiggerSize = (genTypeSize(retActualType) <= genTypeSize(retValActualType)); + bool constStructInit = retVal->IsConstInitVal(); + bool implicitCastFromSameOrBiggerSize = + (comp->getSizeOfType(retActualType) <= comp->getSizeOfType(retValActualType)); // This could happen if we have retyped op1 as a primitive type during struct promotion. bool actualTypesMatch = (retActualType == retValActualType); @@ -5055,7 +5056,7 @@ void Lowering::LowerRetFieldList(GenTreeOp* ret, GenTreeFieldList* fieldList) unsigned numRegs = retDesc.GetReturnRegCount(); auto getRegInfo = [=, &retDesc](unsigned regIndex) { - unsigned offset = retDesc.GetReturnFieldOffset(regIndex); + unsigned offset = comp->GetReturnFieldOffset(retDesc, regIndex); var_types regType = retDesc.GetReturnRegType(regIndex); return LowerFieldListRegisterInfo(offset, regType); }; @@ -5198,7 +5199,7 @@ bool Lowering::IsFieldListCompatibleWithRegisters(GenTreeFieldList* fieldList, LowerFieldListRegisterInfo regInfo = getRegInfo(i); unsigned regStart = regInfo.Offset; var_types regType = regInfo.RegType; - unsigned regEnd = regStart + genTypeSize(regType); + unsigned regEnd = regStart + comp->getSizeOfType(regType); if ((i == numRegs - 1) && !varTypeUsesFloatReg(regType)) { @@ -5230,7 +5231,7 @@ bool Lowering::IsFieldListCompatibleWithRegisters(GenTreeFieldList* fieldList, break; } - unsigned fieldEnd = fieldStart + genTypeSize(use->GetType()); + unsigned fieldEnd = fieldStart + comp->getSizeOfType(use->GetType()); if (fieldEnd > regEnd) { JITDUMP("it is not; field [%06u] ends after register %u\n", Compiler::dspTreeID(use->GetNode()), i); @@ -5248,10 +5249,10 @@ bool Lowering::IsFieldListCompatibleWithRegisters(GenTreeFieldList* fieldList, // int -> float is currently only supported if we can do it as a single bitcast (i.e. without insertions // required) if (varTypeUsesIntReg(use->GetNode()) && varTypeUsesFloatReg(regType) && - (genTypeSize(regType) > TARGET_POINTER_SIZE)) + (comp->getSizeOfType(regType) > TARGET_POINTER_SIZE)) { JITDUMP("it is not; field [%06u] requires an insertion into float register %u of size %d\n", - Compiler::dspTreeID(use->GetNode()), i, genTypeSize(regType)); + Compiler::dspTreeID(use->GetNode()), i, comp->getSizeOfType(regType)); return false; } @@ -5291,7 +5292,7 @@ void Lowering::LowerFieldListToFieldListOfRegisters(GenTreeFieldList* fieldLis LowerFieldListRegisterInfo regInfo = getRegInfo(i); unsigned regStart = regInfo.Offset; var_types regType = regInfo.RegType; - unsigned regEnd = regStart + genTypeSize(regType); + unsigned regEnd = regStart + comp->getSizeOfType(regType); if ((i == numRegs - 1) && !varTypeUsesFloatReg(regType)) { @@ -5325,7 +5326,7 @@ void Lowering::LowerFieldListToFieldListOfRegisters(GenTreeFieldList* fieldLis // First ensure the value does not have upper bits set that // interfere with the next field. if ((nextUse != nullptr) && (nextUse->GetOffset() < regEnd) && - (fieldStart + genTypeSize(genActualType(fieldType)) > nextUse->GetOffset())) + (fieldStart + comp->getSizeOfType(genActualType(fieldType)) > nextUse->GetOffset())) { assert(varTypeIsSmall(fieldType)); // This value may interfere with the next field. Ensure that doesn't happen. @@ -5339,13 +5340,13 @@ void Lowering::LowerFieldListToFieldListOfRegisters(GenTreeFieldList* fieldLis // If this is a float -> int insertion, then we need the bitcast now. if (varTypeUsesFloatReg(value) && varTypeUsesIntReg(regInfo.RegType)) { - assert((genTypeSize(value) == 4) || (genTypeSize(value) == 8)); - var_types castType = genTypeSize(value) == 4 ? TYP_INT : TYP_LONG; + assert((comp->getSizeOfType(value->TypeGet()) == 4) || (comp->getSizeOfType(value->TypeGet()) == 8)); + var_types castType = comp->getSizeOfType(value->TypeGet()) == 4 ? TYP_INT : TYP_LONG; value = comp->gtNewBitCastNode(castType, value); BlockRange().InsertBefore(fieldList, value); } - if (insertOffset + genTypeSize(fieldType) > genTypeSize(genActualType(value))) + if (insertOffset + comp->getSizeOfType(fieldType) > comp->getSizeOfType(genActualType(value))) { value = comp->gtNewCastNode(TYP_LONG, value, true, TYP_LONG); BlockRange().InsertBefore(fieldList, value); @@ -5399,7 +5400,7 @@ void Lowering::LowerFieldListToFieldListOfRegisters(GenTreeFieldList* fieldLis // ABIs for structs. while (node->OperIs(GT_CAST) && !node->gtOverflow() && (genActualType(node->CastFromType()) == TYP_INT) && (genActualType(node->CastToType()) == TYP_INT) && - (genTypeSize(regType) <= genTypeSize(node->CastToType()))) + (comp->getSizeOfType(regType) <= comp->getSizeOfType(node->CastToType()))) { GenTree* op = node->AsCast()->CastOp(); regEntry->SetNode(op); @@ -5686,7 +5687,8 @@ void Lowering::LowerRetStruct(GenTreeUnOp* ret) if (varTypeUsesFloatReg(nativeReturnType)) { // ZeroObj assertion propagation can create INT zeros for DOUBLE returns. - assert((genTypeSize(retVal) == genTypeSize(nativeReturnType)) || retVal->IsIntegralConst(0)); + assert((comp->getSizeOfType(retVal) == comp->getSizeOfType(nativeReturnType)) || + retVal->IsIntegralConst(0)); int64_t value = retVal->AsIntCon()->IconValue(); if (nativeReturnType == TYP_FLOAT) @@ -5710,7 +5712,7 @@ void Lowering::LowerRetStruct(GenTreeUnOp* ret) { // Spill to a local if sizes don't match so we can avoid the "load more than requested" // problem, e.g. struct size is 5 and we emit "ldr x0, [x1]" - if (genTypeSize(nativeReturnType) > comp->gtGetSizeOfIndirection(retVal->AsIndir())) + if (comp->getSizeOfType(nativeReturnType) > comp->gtGetSizeOfIndirection(retVal->AsIndir())) { LIR::Use retValUse(BlockRange(), &ret->gtOp1, ret); unsigned tmpNum = comp->lvaGrabTemp(true DEBUGARG("mis-sized struct return")); @@ -5781,9 +5783,9 @@ void Lowering::LowerRetSingleRegStructLclVar(GenTreeUnOp* ret) // We are returning as a primitive type and the lcl is of struct type. assert(comp->info.compRetNativeType != TYP_STRUCT); - assert((genTypeSize(comp->info.compRetNativeType) == genTypeSize(ret)) || + assert((comp->getSizeOfType(comp->info.compRetNativeType) == comp->getSizeOfType(ret)) || (varTypeIsIntegral(ret) && varTypeIsIntegral(comp->info.compRetNativeType) && - (genTypeSize(comp->info.compRetNativeType) <= genTypeSize(ret)))); + (comp->getSizeOfType(comp->info.compRetNativeType) <= comp->getSizeOfType(ret)))); // If the actual return type requires normalization, then make sure we // do so by using the correct small type for the GT_LCL_FLD. It would // be conservative to check just compRetNativeType for this since small @@ -5791,7 +5793,7 @@ void Lowering::LowerRetSingleRegStructLclVar(GenTreeUnOp* ret) // registers, so we would normalize for them as well. if (varTypeIsSmall(comp->info.compRetType)) { - assert(genTypeSize(comp->info.compRetNativeType) == genTypeSize(comp->info.compRetType)); + assert(comp->getSizeOfType(comp->info.compRetNativeType) == comp->getSizeOfType(comp->info.compRetType)); lclVar->ChangeType(comp->info.compRetType); } else @@ -7347,6 +7349,12 @@ bool Lowering::TryCreateAddrMode(GenTree* addr, bool isContainable, GenTree* par // because we won't be able to use ldar/star return false; } + + if (parent->TypeIs(TYP_SIMDSV)) + { + // TODO-SVE: Investigate addressing modes for scalable types. + return false; + } #endif GenTree* base = nullptr; @@ -7365,7 +7373,7 @@ bool Lowering::TryCreateAddrMode(GenTree* addr, bool isContainable, GenTree* par // *(ulong*)(data + index * 7); - can not be optimized // *(int*)(data + index * 2); - can not be optimized // - naturalMul = genTypeSize(targetType); + naturalMul = comp->getSizeOfType(targetType); #endif // Find out if an addressing mode can be constructed @@ -7508,7 +7516,7 @@ bool Lowering::TryCreateAddrMode(GenTree* addr, bool isContainable, GenTree* par // 'scale' and 'offset' have to be unset since we're going to use [base + index * SXTW/UXTW scale] form // where there is no room for additional offsets/scales on ARM64. 'shiftBy' has to match target's width. if (cast->CastOp()->TypeIs(TYP_INT) && cast->TypeIs(TYP_LONG) && - (genTypeSize(targetType) == (1U << shiftBy)) && (scale == 1) && (offset == 0)) + (comp->getSizeOfType(targetType) == (1U << shiftBy)) && (scale == 1) && (offset == 0)) { if (IsInvariantInRange(index, parent)) { @@ -7598,7 +7606,7 @@ GenTree* Lowering::LowerAdd(GenTreeOp* node) int64_t c2 = cns2->IntegralValue(); int64_t result; - if (genTypeSize(node) == sizeof(int64_t)) + if (comp->getSizeOfType(node) == sizeof(int64_t)) { result = c1 + c2; } @@ -8152,7 +8160,7 @@ bool Lowering::TryLowerConstIntDivOrMod(GenTree* node, GenTree** nextNode) adjusted = mulhi; } - GenTree* shiftBy = comp->gtNewIconNode(genTypeSize(type) * 8 - 1, type); + GenTree* shiftBy = comp->gtNewIconNode(comp->getSizeOfType(type) * 8 - 1, type); GenTree* signBit = comp->gtNewOperNode(GT_RSZ, type, adjusted, shiftBy); BlockRange().InsertBefore(divMod, shiftBy, signBit); @@ -8419,9 +8427,10 @@ void Lowering::LowerShift(GenTreeOp* shift) cast->CastOp()->TypeIs(TYP_LONG, TYP_INT)) { // Cast is either "TYP_LONG <- TYP_INT" or "TYP_INT <- %SMALL_INT% <- TYP_INT" (signed or unsigned) - unsigned dstBits = genTypeSize(cast) * BITS_PER_BYTE; - unsigned srcBits = varTypeIsSmall(cast->CastToType()) ? genTypeSize(cast->CastToType()) * BITS_PER_BYTE - : genTypeSize(cast->CastOp()) * BITS_PER_BYTE; + unsigned dstBits = comp->getSizeOfType(cast) * BITS_PER_BYTE; + unsigned srcBits = varTypeIsSmall(cast->CastToType()) + ? comp->getSizeOfType(cast->CastToType()) * BITS_PER_BYTE + : comp->getSizeOfType(cast->CastOp()) * BITS_PER_BYTE; // It has to be an upcast and CNS must be in [1..srcBits) range if ((srcBits < dstBits) && (cns->IconValue() > 0) && (cns->IconValue() < srcBits)) @@ -8747,7 +8756,7 @@ void Lowering::FindInducedParameterRegisterLocals() assert(fld->GetLclOffs() <= comp->lvaLclExactSize(fld->GetLclNum())); unsigned structAccessedSize = - min(genTypeSize(fld), comp->lvaLclExactSize(fld->GetLclNum()) - fld->GetLclOffs()); + min(comp->getSizeOfType(fld), comp->lvaLclExactSize(fld->GetLclNum()) - fld->GetLclOffs()); if ((fld->GetLclOffs() < segment.Offset) || (fld->GetLclOffs() + structAccessedSize > segment.Offset + segment.Size)) { @@ -8854,16 +8863,17 @@ void Lowering::FindInducedParameterRegisterLocals() // Insert explicit normalization for small types (the LCL_FLD we // are replacing comes with this normalization). This is only required // if we didn't get the normalization via a right shift. - if (varTypeIsSmall(fld) && (regSegment->Offset + genTypeSize(fld) != genTypeSize(registerType))) + if (varTypeIsSmall(fld) && + (regSegment->Offset + comp->getSizeOfType(fld) != comp->getSizeOfType(registerType))) { value = comp->gtNewCastNode(TYP_INT, value, false, fld->TypeGet()); } // If the node is still too large then get it to the right size - if (genTypeSize(value) != genTypeSize(genActualType((fld)))) + if (comp->getSizeOfType(value) != comp->getSizeOfType(genActualType((fld)))) { - assert(genTypeSize(value) == 8); - assert(genTypeSize(genActualType(fld)) == 4); + assert(comp->getSizeOfType(value) == 8); + assert(comp->getSizeOfType(genActualType(fld)) == 4); if (value->OperIsScalarLocal()) { @@ -9601,7 +9611,7 @@ bool Lowering::TryRemoveBitCast(GenTreeUnOp* node) } GenTree* op = node->gtGetOp1(); - assert(genTypeSize(node) == genTypeSize(genActualType(op))); + assert(comp->getSizeOfType(node) == comp->getSizeOfType(genActualType(op))); bool changed = false; #ifdef FEATURE_SIMD @@ -9613,17 +9623,17 @@ bool Lowering::TryRemoveBitCast(GenTreeUnOp* node) if (isConst) { uint8_t bits[sizeof(simd_t)]; - assert(sizeof(bits) >= genTypeSize(genActualType(op))); + assert(sizeof(bits) >= comp->getSizeOfType(genActualType(op))); if (op->OperIs(GT_CNS_INT)) { ssize_t cns = op->AsIntCon()->IconValue(); - assert(sizeof(ssize_t) >= genTypeSize(genActualType(op))); - memcpy(bits, &cns, genTypeSize(genActualType(op))); + assert(sizeof(ssize_t) >= comp->getSizeOfType(genActualType(op))); + memcpy(bits, &cns, comp->getSizeOfType(genActualType(op))); } #ifdef FEATURE_SIMD else if (op->OperIs(GT_CNS_VEC)) { - memcpy(bits, &op->AsVecCon()->gtSimdVal, genTypeSize(op)); + memcpy(bits, &op->AsVecCon()->gtSimdVal, comp->getSizeOfType(op)); } #endif else @@ -9682,7 +9692,7 @@ bool Lowering::TryRemoveBitCast(GenTreeUnOp* node) void Lowering::ContainCheckBitCast(GenTreeUnOp* node) { GenTree* const op1 = node->gtGetOp1(); - if (op1->OperIs(GT_LCL_VAR) && (genTypeSize(op1) == genTypeSize(node))) + if (op1->OperIs(GT_LCL_VAR) && (comp->getSizeOfType(op1) == comp->getSizeOfType(node))) { if (IsContainableMemoryOp(op1) && IsSafeToContainMem(node, op1)) { @@ -10172,7 +10182,7 @@ void Lowering::LowerStoreIndirCoalescing(GenTreeIndir* ind) // Otherwise, the difference between two offsets has to match the size of the type. // We don't support overlapping stores. - if (abs(prevData.offset - currData.offset) != (int)genTypeSize(prevData.targetType)) + if (abs(prevData.offset - currData.offset) != (int)comp->getSizeOfType(prevData.targetType)) { return; } @@ -10198,7 +10208,7 @@ void Lowering::LowerStoreIndirCoalescing(GenTreeIndir* ind) allowsNonAtomic = true; } - if (!allowsNonAtomic && (genTypeSize(ind) > 1) && !varTypeIsSIMD(ind)) + if (!allowsNonAtomic && (comp->getSizeOfType(ind) > 1) && !varTypeIsSIMD(ind)) { // TODO-CQ: if we see that the target is a local memory (non address exposed) // we can use any type (including SIMD) for a new load. @@ -10217,10 +10227,10 @@ void Lowering::LowerStoreIndirCoalescing(GenTreeIndir* ind) } // Check whether the combined indir is still aligned. - bool isCombinedIndirAtomic = (genTypeSize(ind) < TARGET_POINTER_SIZE) && - (min(prevData.offset, currData.offset) % (genTypeSize(ind) * 2)) == 0; + bool isCombinedIndirAtomic = (comp->getSizeOfType(ind) < TARGET_POINTER_SIZE) && + (min(prevData.offset, currData.offset) % (comp->getSizeOfType(ind) * 2)) == 0; - if (genTypeSize(ind) == TARGET_POINTER_SIZE) + if (comp->getSizeOfType(ind) == TARGET_POINTER_SIZE) { #ifdef TARGET_ARM64 // Per Arm Architecture Reference Manual for A-profile architecture: @@ -10378,7 +10388,7 @@ void Lowering::LowerStoreIndirCoalescing(GenTreeIndir* ind) } simd_t newCns = {}; - uint32_t oldWidth = genTypeSize(oldType); + uint32_t oldWidth = comp->getSizeOfType(oldType); memcpy(newCns.i8, lowerCns, oldWidth); memcpy(newCns.i8 + oldWidth, upperCns, oldWidth); @@ -10416,15 +10426,15 @@ void Lowering::LowerStoreIndirCoalescing(GenTreeIndir* ind) // Trim the constants to the size of the type, e.g. for TYP_SHORT and TYP_USHORT // the mask will be 0xFFFF, for TYP_INT - 0xFFFFFFFF. - size_t mask = ~(size_t(0)) >> (sizeof(size_t) - genTypeSize(oldType)) * BITS_PER_BYTE; + size_t mask = ~(size_t(0)) >> (sizeof(size_t) - comp->getSizeOfType(oldType)) * BITS_PER_BYTE; lowerCns &= mask; upperCns &= mask; - size_t val = (lowerCns | (upperCns << (genTypeSize(oldType) * BITS_PER_BYTE))); + size_t val = (lowerCns | (upperCns << (comp->getSizeOfType(oldType) * BITS_PER_BYTE))); JITDUMP("Coalesced two stores into a single store with value %lld\n", (int64_t)val); ind->Data()->AsIntCon()->gtIconVal = (ssize_t)val; - if (genTypeSize(oldType) == 1) + if (comp->getSizeOfType(oldType) == 1) { // A mark for future foldings that this IND doesn't need to be atomic. ind->gtFlags |= GTF_IND_ALLOW_NON_ATOMIC; @@ -10638,7 +10648,7 @@ bool Lowering::OptimizeForLdpStp(GenTreeIndir* ind) JITDUMP("[%06u] and [%06u] are indirs off the same base with offsets +%03u and +%03u\n", Compiler::dspTreeID(ind), Compiler::dspTreeID(prevIndir), (unsigned)offs, (unsigned)prev.Offset); - if (std::abs(offs - prev.Offset) == genTypeSize(ind)) + if (std::abs(offs - prev.Offset) == comp->getSizeOfType(ind)) { JITDUMP(" ..and they are amenable to ldp/stp optimization\n"); if (TryMakeIndirsAdjacent(prevIndir, ind)) diff --git a/src/coreclr/jit/lsra.cpp b/src/coreclr/jit/lsra.cpp index a2dd58244be7b1..5145977ff9c606 100644 --- a/src/coreclr/jit/lsra.cpp +++ b/src/coreclr/jit/lsra.cpp @@ -1689,6 +1689,8 @@ bool LinearScan::isRegCandidate(LclVarDsc* varDsc) #if defined(TARGET_XARCH) case TYP_SIMD32: case TYP_SIMD64: +#elif defined(TARGET_ARM64) + case TYP_SIMDSV: #endif // TARGET_XARCH #ifdef FEATURE_MASKED_HW_INTRINSICS case TYP_MASK: diff --git a/src/coreclr/jit/lsraarm64.cpp b/src/coreclr/jit/lsraarm64.cpp index 5fb1d1f10e76d9..4d3e465610daf2 100644 --- a/src/coreclr/jit/lsraarm64.cpp +++ b/src/coreclr/jit/lsraarm64.cpp @@ -1585,7 +1585,7 @@ void LinearScan::BuildHWIntrinsicImmediate(GenTreeHWIntrinsic* intrinsicTree, co assert(varTypeIsSIMD(indexedElementOpType)); - const unsigned int indexedElementSimdSize = genTypeSize(indexedElementOpType); + const unsigned int indexedElementSimdSize = compiler->getSizeOfType(indexedElementOpType); HWIntrinsicInfo::lookupImmBounds(intrin.id, indexedElementSimdSize, intrin.baseType, 1, &immLowerBound, &immUpperBound); } diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index 59ff422a656b2e..d77ba2f72567ed 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -288,7 +288,7 @@ GenTree* Compiler::fgMorphExpandCast(GenTreeCast* tree) GenTree* oper = tree->CastOp(); var_types srcType = genActualType(oper); var_types dstType = tree->CastToType(); - unsigned dstSize = genTypeSize(dstType); + unsigned dstSize = getSizeOfType(dstType); // See if the cast has to be done in two steps. R -> I if (varTypeIsFloating(srcType) && varTypeIsIntegral(dstType)) @@ -10856,7 +10856,7 @@ GenTree* Compiler::fgMorphRetInd(GenTreeOp* ret) if (fgGlobalMorph && varTypeIsStruct(lclFld) && !lvaIsImplicitByRefLocal(lclNum)) { LclVarDsc* varDsc = lvaGetDesc(lclNum); - unsigned indSize = lclFld->GetSize(); + unsigned indSize = lclFld->GetSize(this); unsigned lclVarSize = lvaLclExactSize(lclNum); // TODO: change conditions in `canFold` to `indSize <= lclVarSize`, but currently do not support `BITCAST diff --git a/src/coreclr/jit/morphblock.cpp b/src/coreclr/jit/morphblock.cpp index 920ff1c8c08d46..9ad705dc33e334 100644 --- a/src/coreclr/jit/morphblock.cpp +++ b/src/coreclr/jit/morphblock.cpp @@ -194,7 +194,7 @@ void MorphInitBlockHelper::PrepareDst() } else { - m_blockSize = genTypeSize(m_store); + m_blockSize = m_comp->getSizeOfType(m_store->TypeGet()); } assert(m_blockSize != 0); @@ -995,7 +995,7 @@ void MorphCopyBlockHelper::TryPrimitiveCopy() // Can we use the LHS local directly? if (m_store->OperIs(GT_STORE_LCL_FLD)) { - if (m_blockSize == genTypeSize(m_dstVarDsc)) + if (m_blockSize == m_comp->getSizeOfType(m_dstVarDsc->TypeGet())) { storeType = m_dstVarDsc->TypeGet(); } @@ -1308,7 +1308,7 @@ GenTree* MorphCopyBlockHelper::CopyFieldByField() { noway_assert(m_srcLclNode != nullptr); assert(destType != TYP_STRUCT); - unsigned destSize = genTypeSize(destType); + unsigned destSize = m_comp->getSizeOfType(destType); m_srcVarDsc = m_comp->lvaGetDesc(m_srcLclNum); unsigned srcSize = m_comp->lvaLclExactSize(m_srcVarDsc); if (destSize == srcSize) diff --git a/src/coreclr/jit/optimizer.cpp b/src/coreclr/jit/optimizer.cpp index d538ca44b2413d..4387e027af3632 100644 --- a/src/coreclr/jit/optimizer.cpp +++ b/src/coreclr/jit/optimizer.cpp @@ -5805,7 +5805,7 @@ PhaseStatus Compiler::optVNBasedDeadStoreRemoval() ValueNum oldLclValue = varDsc->GetPerSsaData(defDsc->GetUseDefSsaNum())->m_vnPair.GetConservative(); oldStoreValue = vnStore->VNForLoad(VNK_Conservative, oldLclValue, lvaLclExactSize(lclNum), store->TypeGet(), - store->AsLclFld()->GetLclOffs(), store->AsLclFld()->GetSize()); + store->AsLclFld()->GetLclOffs(), store->AsLclFld()->GetSize(this)); } GenTree* data = store->AsLclVarCommon()->Data(); diff --git a/src/coreclr/jit/promotion.cpp b/src/coreclr/jit/promotion.cpp index 119e5ba2eeceaf..1c50b8a4dd2ea8 100644 --- a/src/coreclr/jit/promotion.cpp +++ b/src/coreclr/jit/promotion.cpp @@ -121,14 +121,14 @@ struct Access { } - unsigned GetAccessSize() const + unsigned GetAccessSize(Compiler* comp) const { - return AccessType == TYP_STRUCT ? Layout->GetSize() : genTypeSize(AccessType); + return AccessType == TYP_STRUCT ? Layout->GetSize() : comp->getSizeOfType(AccessType); } - bool Overlaps(unsigned otherStart, unsigned otherSize) const + bool Overlaps(Compiler* comp, unsigned otherStart, unsigned otherSize) const { - unsigned end = Offset + GetAccessSize(); + unsigned end = Offset + GetAccessSize(comp); if (end <= otherStart) { return false; @@ -196,10 +196,8 @@ inline AccessKindFlags& operator&=(AccessKindFlags& a, AccessKindFlags b) // Returns: // True if any replacement overlaps; otherwise false. // -bool AggregateInfo::OverlappingReplacements(unsigned offset, - unsigned size, - Replacement** firstReplacement, - Replacement** endReplacement) +bool AggregateInfo::OverlappingReplacements( + Compiler* comp, unsigned offset, unsigned size, Replacement** firstReplacement, Replacement** endReplacement) { size_t firstIndex = Promotion::BinarySearch(Replacements, offset); if ((ssize_t)firstIndex < 0) @@ -208,7 +206,7 @@ bool AggregateInfo::OverlappingReplacements(unsigned offset, if (firstIndex > 0) { Replacement& lastRepBefore = Replacements[firstIndex - 1]; - if ((lastRepBefore.Offset + genTypeSize(lastRepBefore.AccessType)) > offset) + if ((lastRepBefore.Offset + comp->getSizeOfType(lastRepBefore.AccessType)) > offset) { // Overlap with last entry starting before offs. firstIndex--; @@ -228,7 +226,7 @@ bool AggregateInfo::OverlappingReplacements(unsigned offset, } } - assert((firstIndex < Replacements.size()) && Replacements[firstIndex].Overlaps(offset, size)); + assert((firstIndex < Replacements.size()) && Replacements[firstIndex].Overlaps(comp, offset, size)); *firstReplacement = &Replacements[firstIndex]; if (endReplacement != nullptr) @@ -577,12 +575,13 @@ class LocalUses continue; } - if (inducedAccess.Offset + genTypeSize(inducedAccess.AccessType) <= otherInducedAccess.Offset) + if (inducedAccess.Offset + comp->getSizeOfType(inducedAccess.AccessType) <= otherInducedAccess.Offset) { break; } - if (otherInducedAccess.Offset + genTypeSize(otherInducedAccess.AccessType) <= inducedAccess.Offset) + if (otherInducedAccess.Offset + comp->getSizeOfType(otherInducedAccess.AccessType) <= + inducedAccess.Offset) { continue; } @@ -625,8 +624,9 @@ class LocalUses { #ifdef DEBUG Replacement* overlapRep; - assert(!agg->OverlappingReplacements(inducedAccess.Offset, genTypeSize(inducedAccess.AccessType), - &overlapRep, nullptr)); + assert(!agg->OverlappingReplacements(comp, inducedAccess.Offset, + comp->getSizeOfType(inducedAccess.AccessType), &overlapRep, + nullptr)); #endif insertionIndex = @@ -685,7 +685,7 @@ class LocalUses LclVarDsc* lcl = comp->lvaGetDesc(lclNum); ClassLayout* layout = lcl->GetLayout(); - if (layout->IntersectsGCPtr(access.Offset, genTypeSize(access.AccessType))) + if (layout->IntersectsGCPtr(access.Offset, comp->getSizeOfType(access.AccessType))) { if (((access.Offset % TARGET_POINTER_SIZE) != 0) || (layout->GetGCPtrType(access.Offset / TARGET_POINTER_SIZE) != access.AccessType)) @@ -715,7 +715,7 @@ class LocalUses continue; } - if (!otherAccess.Overlaps(access.Offset, genTypeSize(access.AccessType))) + if (!otherAccess.Overlaps(comp, access.Offset, comp->getSizeOfType(access.AccessType))) { continue; } @@ -1302,7 +1302,7 @@ class LocalsUseVisitor : public GenTreeVisitor { #ifdef DEBUG rep.Description = m_compiler->printfAlloc("V%02u.[%03u..%03u)", agg->LclNum, rep.Offset, - rep.Offset + genTypeSize(rep.AccessType)); + rep.Offset + m_compiler->getSizeOfType(rep.AccessType)); #endif rep.LclNum = m_compiler->lvaGrabTemp(false DEBUGARG(rep.Description)); @@ -1321,15 +1321,17 @@ class LocalsUseVisitor : public GenTreeVisitor JITDUMP("V%02u promoted with %d replacements\n", agg->LclNum, (int)reps.size()); for (const Replacement& rep : reps) { - JITDUMP(" [%03u..%03u) promoted as %s V%02u\n", rep.Offset, rep.Offset + genTypeSize(rep.AccessType), - varTypeName(rep.AccessType), rep.LclNum); + JITDUMP(" [%03u..%03u) promoted as %s V%02u\n", rep.Offset, + rep.Offset + m_compiler->getSizeOfType(rep.AccessType), varTypeName(rep.AccessType), + rep.LclNum); } #endif agg->Unpromoted = m_compiler->lvaGetDesc(agg->LclNum)->GetLayout()->GetNonPadding(m_compiler); for (Replacement& rep : reps) { - agg->Unpromoted.Subtract(SegmentList::Segment(rep.Offset, rep.Offset + genTypeSize(rep.AccessType))); + agg->Unpromoted.Subtract( + SegmentList::Segment(rep.Offset, rep.Offset + m_compiler->getSizeOfType(rep.AccessType))); } JITDUMP(" Unpromoted remainder: "); @@ -1400,7 +1402,7 @@ class LocalsUseVisitor : public GenTreeVisitor { LclVarDsc* fieldDsc = m_compiler->lvaGetDesc(fieldLcl); if ((fieldDsc->lvFldOffset >= regPromOffs) && - (fieldDsc->lvFldOffset + genTypeSize(fieldDsc->lvType) <= (regPromOffs + size))) + (fieldDsc->lvFldOffset + m_compiler->getSizeOfType(fieldDsc->lvType) <= (regPromOffs + size))) { InduceAccess(aggregates, candidateLcl->GetLclNum(), candidateLcl->GetLclOffs() + (fieldDsc->lvFldOffset - regPromOffs), fieldDsc->lvType, @@ -1435,12 +1437,12 @@ class LocalsUseVisitor : public GenTreeVisitor { Replacement* firstRep; Replacement* endRep; - if (inducerAgg->OverlappingReplacements(inducerOffs, size, &firstRep, &endRep)) + if (inducerAgg->OverlappingReplacements(m_compiler, inducerOffs, size, &firstRep, &endRep)) { for (Replacement* rep = firstRep; rep < endRep; rep++) { if ((rep->Offset >= inducerOffs) && - (rep->Offset + genTypeSize(rep->AccessType) <= (inducerOffs + size))) + (rep->Offset + m_compiler->getSizeOfType(rep->AccessType) <= (inducerOffs + size))) { InduceAccess(aggregates, candidate->GetLclNum(), candOffs + (rep->Offset - inducerOffs), rep->AccessType, block); @@ -1468,7 +1470,7 @@ class LocalsUseVisitor : public GenTreeVisitor if (agg != nullptr) { Replacement* overlapRep; - if (agg->OverlappingReplacements(offset, genTypeSize(type), &overlapRep, nullptr)) + if (agg->OverlappingReplacements(m_compiler, offset, m_compiler->getSizeOfType(type), &overlapRep, nullptr)) { return; } @@ -1556,15 +1558,16 @@ class LocalsUseVisitor : public GenTreeVisitor // Check if this replacement overlaps the specified range. // // Parameters: +// comp - The compiler // otherStart - Start of the other range. // otherSize - Size of the other range. // // Returns: // True if they overlap. // -bool Replacement::Overlaps(unsigned otherStart, unsigned otherSize) const +bool Replacement::Overlaps(Compiler* comp, unsigned otherStart, unsigned otherSize) const { - unsigned end = Offset + genTypeSize(AccessType); + unsigned end = Offset + comp->getSizeOfType(AccessType); if (end <= otherStart) { return false; @@ -1751,7 +1754,7 @@ void ReplaceVisitor::EndBlock() if (m_liveness->IsReplacementLiveOut(m_currentBlock, agg->LclNum, (unsigned)i)) { JITDUMP("Reading back replacement V%02u.[%03u..%03u) -> V%02u near the end of " FMT_BB ":\n", - agg->LclNum, rep.Offset, rep.Offset + genTypeSize(rep.AccessType), rep.LclNum, + agg->LclNum, rep.Offset, rep.Offset + m_compiler->getSizeOfType(rep.AccessType), rep.LclNum, m_currentBlock->bbNum); GenTree* readBack = Promotion::CreateReadBack(m_compiler, agg->LclNum, rep); @@ -1778,7 +1781,7 @@ void ReplaceVisitor::EndBlock() JITDUMP("Skipping reading back dead replacement V%02u.[%03u..%03u) -> V%02u near the end of " FMT_BB "\n", - agg->LclNum, rep.Offset, rep.Offset + genTypeSize(rep.AccessType), rep.LclNum, + agg->LclNum, rep.Offset, rep.Offset + m_compiler->getSizeOfType(rep.AccessType), rep.LclNum, m_currentBlock->bbNum); } @@ -2004,7 +2007,8 @@ void ReplaceVisitor::InsertPreStatementReadBackIfNecessary(unsigned aggLclNum, R } JITDUMP("Reading back replacement V%02u.[%03u..%03u) -> V%02u before [%06u]:\n", aggLclNum, rep.Offset, - rep.Offset + genTypeSize(rep.AccessType), rep.LclNum, Compiler::dspTreeID(m_currentStmt->GetRootNode())); + rep.Offset + m_compiler->getSizeOfType(rep.AccessType), rep.LclNum, + Compiler::dspTreeID(m_currentStmt->GetRootNode())); GenTree* readBack = Promotion::CreateReadBack(m_compiler, aggLclNum, rep); Statement* stmt = m_compiler->fgNewStmtFromTree(readBack); @@ -2041,7 +2045,7 @@ bool ReplaceVisitor::VisitOverlappingReplacements(unsigned lcl, unsigned offs, u if ((ssize_t)index < 0) { index = ~index; - if ((index > 0) && replacements[index - 1].Overlaps(offs, size)) + if ((index > 0) && replacements[index - 1].Overlaps(m_compiler, offs, size)) { index--; } @@ -2183,7 +2187,7 @@ GenTree** ReplaceVisitor::InsertMidTreeReadBacks(GenTree** use) } JITDUMP(" V%02u.[%03u..%03u) -> V%02u\n", agg->LclNum, rep.Offset, - rep.Offset + genTypeSize(rep.AccessType), rep.LclNum); + rep.Offset + m_compiler->getSizeOfType(rep.AccessType), rep.LclNum); ClearNeedsReadBack(rep); GenTree* readBack = Promotion::CreateReadBack(m_compiler, agg->LclNum, rep); @@ -2313,8 +2317,8 @@ GenTreeFieldList* ReplaceVisitor::CreateFieldListForStructLocal(GenTreeLclVarCom } auto checkPartialOverlap = [=](Replacement& rep) { - bool contained = - (rep.Offset >= startOffset) && (rep.Offset + genTypeSize(rep.AccessType) <= startOffset + returnValueSize); + bool contained = (rep.Offset >= startOffset) && + (rep.Offset + m_compiler->getSizeOfType(rep.AccessType) <= startOffset + returnValueSize); if (contained) { @@ -2620,10 +2624,10 @@ void ReplaceVisitor::ReplaceLocal(GenTree** use, GenTree* user) } #ifdef DEBUG - unsigned accessSize = genTypeSize(accessType); + unsigned accessSize = m_compiler->getSizeOfType(accessType); for (const Replacement& rep : replacements) { - assert(!rep.Overlaps(offs, accessSize) || ((rep.Offset == offs) && (rep.AccessType == accessType))); + assert(!rep.Overlaps(m_compiler, offs, accessSize) || ((rep.Offset == offs) && (rep.AccessType == accessType))); } JITDUMP("Processing primitive use [%06u] of V%02u.[%03u..%03u)\n", Compiler::dspTreeID(lcl), lclNum, offs, @@ -2817,7 +2821,7 @@ void ReplaceVisitor::MarkForReadBack(GenTreeLclVarCommon* lcl, unsigned size DEB if ((ssize_t)index < 0) { index = ~index; - if ((index > 0) && replacements[index - 1].Overlaps(offs, size)) + if ((index > 0) && replacements[index - 1].Overlaps(m_compiler, offs, size)) { index--; } @@ -2837,7 +2841,7 @@ void ReplaceVisitor::MarkForReadBack(GenTreeLclVarCommon* lcl, unsigned size DEB do { Replacement& rep = replacements[index]; - assert(rep.Overlaps(offs, size)); + assert(rep.Overlaps(m_compiler, offs, size)); if (deaths.IsReplacementDying((unsigned)index)) { @@ -3054,7 +3058,7 @@ bool Promotion::MapsToParameterRegister(Compiler* comp, unsigned lclNum, unsigne for (const ABIPassingSegment& seg : abiInfo.Segments()) { // This code corresponds to code in Lower::FindInducedParameterRegisterLocals - if ((offset < seg.Offset) || (offset + genTypeSize(accessType) > seg.Offset + seg.Size)) + if ((offset < seg.Offset) || (offset + comp->getSizeOfType(accessType) > seg.Offset + seg.Size)) { continue; } diff --git a/src/coreclr/jit/promotion.h b/src/coreclr/jit/promotion.h index db24874ad69992..b75f947e5803e9 100644 --- a/src/coreclr/jit/promotion.h +++ b/src/coreclr/jit/promotion.h @@ -37,7 +37,7 @@ struct Replacement { } - bool Overlaps(unsigned otherStart, unsigned otherSize) const; + bool Overlaps(Compiler* comp, unsigned otherStart, unsigned otherSize) const; }; // Represents information about an aggregate that now has replacements in it. @@ -59,10 +59,8 @@ struct AggregateInfo { } - bool OverlappingReplacements(unsigned offset, - unsigned size, - Replacement** firstReplacement, - Replacement** endReplacement); + bool OverlappingReplacements( + Compiler* comp, unsigned offset, unsigned size, Replacement** firstReplacement, Replacement** endReplacement); }; // Map that stores information about promotions made for each local. diff --git a/src/coreclr/jit/promotiondecomposition.cpp b/src/coreclr/jit/promotiondecomposition.cpp index 7f2dbf0257fa2f..ee6e30b29cc167 100644 --- a/src/coreclr/jit/promotiondecomposition.cpp +++ b/src/coreclr/jit/promotiondecomposition.cpp @@ -271,7 +271,7 @@ class DecompositionPlan { const Entry& entry = m_entries.BottomRef(i); - segments.Subtract(SegmentList::Segment(entry.Offset, entry.Offset + genTypeSize(entry.Type))); + segments.Subtract(SegmentList::Segment(entry.Offset, entry.Offset + m_compiler->getSizeOfType(entry.Type))); } #ifdef DEBUG @@ -931,14 +931,15 @@ class DecompositionPlan for (int i = 0; i < m_entries.Height(); i++) { const Entry& entry = m_entries.BottomRef(i); - if (entry.Offset + genTypeSize(entry.Type) <= remainderStrategy.PrimitiveOffset) + if (entry.Offset + m_compiler->getSizeOfType(entry.Type) <= remainderStrategy.PrimitiveOffset) { // Entry ends before remainder starts continue; } // Remainder ends before entry starts - if (remainderStrategy.PrimitiveOffset + genTypeSize(remainderStrategy.PrimitiveType) <= + if (remainderStrategy.PrimitiveOffset + + m_compiler->getSizeOfType(remainderStrategy.PrimitiveType) <= entry.Offset) { continue; @@ -1023,7 +1024,8 @@ class DecompositionPlan { if (m_addr != nullptr) { - GenTreeIndir* indir = comp->gtNewIndir(type, GrabAddress(offs, comp), GetIndirFlags(type)); + GenTreeIndir* indir = + comp->gtNewIndir(type, GrabAddress(offs, comp), GetIndirFlags(comp->getSizeOfType(type))); return indir; } @@ -1056,7 +1058,8 @@ class DecompositionPlan { if (m_addr != nullptr) { - GenTreeIndir* indir = comp->gtNewStoreIndNode(type, GrabAddress(offs, comp), src, GetIndirFlags(type)); + GenTreeIndir* indir = comp->gtNewStoreIndNode(type, GrabAddress(offs, comp), src, + GetIndirFlags(comp->getSizeOfType(type))); return indir; } @@ -1162,14 +1165,14 @@ class DecompositionPlan // Get the flags to set on a new indir. // // Parameters: - // type - Type of the indirection + // size - Size of the indirection // // Returns: // Flags to set. // - GenTreeFlags GetIndirFlags(var_types type) + GenTreeFlags GetIndirFlags(unsigned size) { - if (genTypeSize(type) == 1) + if (size == 1) { return m_indirFlags & ~GTF_IND_UNALIGNED; } @@ -1221,7 +1224,7 @@ class DecompositionPlan { var_types regPromFieldType = m_compiler->lvaGetDesc(srcPromField != BAD_VAR_NUM ? srcPromField : storePromField)->TypeGet(); - if (genTypeSize(regPromFieldType) == genTypeSize(primitiveType)) + if (m_compiler->getSizeOfType(regPromFieldType) == m_compiler->getSizeOfType(primitiveType)) { primitiveType = regPromFieldType; } @@ -1376,7 +1379,7 @@ void ReplaceVisitor::HandleStructStore(GenTree** use, GenTree* user) if (dstEndRep > dstFirstRep) { Replacement* dstLastRep = dstEndRep - 1; - if (dstLastRep->Offset + genTypeSize(dstLastRep->AccessType) > dstLclOffs + dstLclSize) + if (dstLastRep->Offset + m_compiler->getSizeOfType(dstLastRep->AccessType) > dstLclOffs + dstLclSize) { JITDUMP("*** Block operation partially overlaps with end replacement of destination V%02u (%s)\n", dstLastRep->LclNum, dstLastRep->Description); @@ -1417,7 +1420,7 @@ void ReplaceVisitor::HandleStructStore(GenTree** use, GenTree* user) if (srcEndRep > srcFirstRep) { Replacement* srcLastRep = srcEndRep - 1; - if (srcLastRep->Offset + genTypeSize(srcLastRep->AccessType) > srcLclOffs + srcLclSize) + if (srcLastRep->Offset + m_compiler->getSizeOfType(srcLastRep->AccessType) > srcLclOffs + srcLclSize) { JITDUMP("*** Block operation partially overlaps with end replacement of source V%02u (%s)\n", srcLastRep->LclNum, srcLastRep->Description); @@ -1489,7 +1492,7 @@ bool ReplaceVisitor::OverlappingReplacements(GenTreeLclVarCommon* lcl, unsigned offs = lcl->GetLclOffs(); unsigned size = lcl->GetLayout(m_compiler)->GetSize(); - return agg->OverlappingReplacements(offs, size, firstReplacement, endReplacement); + return agg->OverlappingReplacements(m_compiler, offs, size, firstReplacement, endReplacement); } //------------------------------------------------------------------------ @@ -1669,7 +1672,8 @@ void ReplaceVisitor::CopyBetweenFields(GenTree* store, if ((dstRep < dstEndRep) && (srcRep < srcEndRep)) { - if (srcRep->Offset - srcBaseOffs + genTypeSize(srcRep->AccessType) <= dstRep->Offset - dstBaseOffs) + if (srcRep->Offset - srcBaseOffs + m_compiler->getSizeOfType(srcRep->AccessType) <= + dstRep->Offset - dstBaseOffs) { // This source replacement ends before the next destination replacement starts. // Write it directly to the destination struct local. @@ -1681,7 +1685,8 @@ void ReplaceVisitor::CopyBetweenFields(GenTree* store, continue; } - if (dstRep->Offset - dstBaseOffs + genTypeSize(dstRep->AccessType) <= srcRep->Offset - srcBaseOffs) + if (dstRep->Offset - dstBaseOffs + m_compiler->getSizeOfType(dstRep->AccessType) <= + srcRep->Offset - srcBaseOffs) { // Destination replacement ends before the next source replacement starts. // Read it directly from the source struct local. diff --git a/src/coreclr/jit/promotionliveness.cpp b/src/coreclr/jit/promotionliveness.cpp index e137caab827500..ca4dd5c426fc61 100644 --- a/src/coreclr/jit/promotionliveness.cpp +++ b/src/coreclr/jit/promotionliveness.cpp @@ -206,7 +206,7 @@ void PromotionLiveness::MarkUseDef(Statement* stmt, GenTreeLclVarCommon* lcl, Bi if ((ssize_t)index < 0) { index = ~index; - if ((index > 0) && reps[index - 1].Overlaps(offs, size)) + if ((index > 0) && reps[index - 1].Overlaps(m_compiler, offs, size)) { index--; } @@ -214,9 +214,9 @@ void PromotionLiveness::MarkUseDef(Statement* stmt, GenTreeLclVarCommon* lcl, Bi while ((index < reps.size()) && (reps[index].Offset < offs + size)) { - Replacement& rep = reps[index]; - bool isFullFieldDef = - isDef && (offs <= rep.Offset) && (offs + size >= rep.Offset + genTypeSize(rep.AccessType)); + Replacement& rep = reps[index]; + bool isFullFieldDef = isDef && (offs <= rep.Offset) && + (offs + size >= rep.Offset + m_compiler->getSizeOfType(rep.AccessType)); MarkIndex(baseIndex + 1 + (unsigned)index, isUse, isFullFieldDef, useSet, defSet); index++; } @@ -232,7 +232,7 @@ void PromotionLiveness::MarkUseDef(Statement* stmt, GenTreeLclVarCommon* lcl, Bi size_t index = Promotion::BinarySearch(reps, offs); if ((ssize_t)index < 0) { - unsigned size = genTypeSize(accessType); + unsigned size = m_compiler->getSizeOfType(accessType); bool isFullDefOfRemainder = isDef && (agg->UnpromotedMin >= offs) && (agg->UnpromotedMax <= (offs + size)); MarkIndex(baseIndex, isUse, isFullDefOfRemainder, useSet, defSet); } @@ -521,7 +521,7 @@ void PromotionLiveness::FillInLiveness(BitVec& life, BitVec volatileVars, Statem if ((ssize_t)index < 0) { index = ~index; - if ((index > 0) && agg->Replacements[index - 1].Overlaps(offs, size)) + if ((index > 0) && agg->Replacements[index - 1].Overlaps(m_compiler, offs, size)) { index--; } @@ -534,8 +534,8 @@ void PromotionLiveness::FillInLiveness(BitVec& life, BitVec volatileVars, Statem Replacement& rep = agg->Replacements[index]; if (BitVecOps::IsMember(m_bvTraits, life, varIndex)) { - bool isFullFieldDef = - isDef && (offs <= rep.Offset) && (offs + size >= rep.Offset + genTypeSize(rep.AccessType)); + bool isFullFieldDef = isDef && (offs <= rep.Offset) && + (offs + size >= rep.Offset + m_compiler->getSizeOfType(rep.AccessType)); if (isFullFieldDef && !BitVecOps::IsMember(m_bvTraits, volatileVars, varIndex)) { BitVecOps::RemoveElemD(m_bvTraits, life, varIndex); @@ -584,7 +584,7 @@ void PromotionLiveness::FillInLiveness(BitVec& life, BitVec volatileVars, Statem if ((ssize_t)index < 0) { // No replacement found, this is a use of the remainder. - unsigned size = genTypeSize(accessType); + unsigned size = m_compiler->getSizeOfType(accessType); if (BitVecOps::IsMember(m_bvTraits, life, baseIndex)) { lcl->gtFlags &= ~GTF_VAR_DEATH; @@ -758,7 +758,7 @@ void PromotionLiveness::DumpVarSet(BitVec set, BitVec allVars) { const Replacement& rep = agg->Replacements[j - 1]; printf("%sV%02u.[%03u..%03u)", sep, agg->LclNum, rep.Offset, - rep.Offset + genTypeSize(rep.AccessType)); + rep.Offset + m_compiler->getSizeOfType(rep.AccessType)); } sep = " "; } diff --git a/src/coreclr/jit/regset.cpp b/src/coreclr/jit/regset.cpp index 3d9354b040f48e..233ab61d395eda 100644 --- a/src/coreclr/jit/regset.cpp +++ b/src/coreclr/jit/regset.cpp @@ -618,7 +618,7 @@ var_types RegSet::tmpNormalizeType(var_types type) TempDsc* RegSet::tmpGetTemp(var_types type) { type = tmpNormalizeType(type); - unsigned size = genTypeSize(type); + unsigned size = m_rsCompiler->getSizeOfType(type); // If TYP_STRUCT ever gets in here we do bad things (tmpSlot returns -1) noway_assert(size >= sizeof(int)); @@ -680,7 +680,7 @@ TempDsc* RegSet::tmpGetTemp(var_types type) void RegSet::tmpPreAllocateTemps(var_types type, unsigned count) { assert(type == tmpNormalizeType(type)); - unsigned size = genTypeSize(type); + unsigned size = m_rsCompiler->getSizeOfType(type); // If TYP_STRUCT ever gets in here we do bad things (tmpSlot returns -1) noway_assert(size >= sizeof(int)); diff --git a/src/coreclr/jit/scopeinfo.cpp b/src/coreclr/jit/scopeinfo.cpp index df9b0083798d1a..402fb111fcb206 100644 --- a/src/coreclr/jit/scopeinfo.cpp +++ b/src/coreclr/jit/scopeinfo.cpp @@ -295,6 +295,8 @@ void CodeGenInterface::siVarLoc::siFillStackVarLoc( #if defined(TARGET_XARCH) case TYP_SIMD32: case TYP_SIMD64: +#elif defined(TARGET_ARM64) + case TYP_SIMDSV: #endif // TARGET_XARCH #endif // FEATURE_SIMD #ifdef TARGET_64BIT @@ -435,6 +437,8 @@ void CodeGenInterface::siVarLoc::siFillRegisterVarLoc( #if defined(TARGET_XARCH) case TYP_SIMD32: case TYP_SIMD64: +#elif defined(TARGET_ARM64) + case TYP_SIMDSV: #endif // TARGET_XARCH #if defined(FEATURE_MASKED_HW_INTRINSICS) case TYP_MASK: diff --git a/src/coreclr/jit/simd.cpp b/src/coreclr/jit/simd.cpp index d4e4ba31f5bb5a..e66cc9f5b9e7ac 100644 --- a/src/coreclr/jit/simd.cpp +++ b/src/coreclr/jit/simd.cpp @@ -66,9 +66,9 @@ int Compiler::getSIMDVectorLength(CORINFO_CLASS_HANDLE typeHnd) // int Compiler::getSIMDTypeAlignment(var_types simdType) { +#ifdef TARGET_XARCH unsigned size = genTypeSize(simdType); -#ifdef TARGET_XARCH // Fixed length vectors have the following alignment preference // Vector2 = 8 byte alignment // Vector3/4 = 16-byte alignment @@ -93,9 +93,8 @@ int Compiler::getSIMDTypeAlignment(var_types simdType) return 64; } #elif defined(TARGET_ARM64) - // preferred alignment for 64-bit vectors is 8-bytes. - // For everything else, 16-bytes. - return (size == 8) ? 8 : 16; + assert(varTypeIsSIMD(simdType)); + return genTypeAlignments[simdType]; #else assert(!"getSIMDTypeAlignment() unimplemented on target arch"); unreached(); @@ -120,7 +119,7 @@ unsigned Compiler::getSIMDInitTempVarNum(var_types simdType) lvaSIMDInitTempVarNum = lvaGrabTempWithImplicitUse(false DEBUGARG("SIMDInitTempVar")); lvaTable[lvaSIMDInitTempVarNum].lvType = simdType; } - else if (genTypeSize(lvaTable[lvaSIMDInitTempVarNum].lvType) < genTypeSize(simdType)) + else if (getSizeOfType(lvaTable[lvaSIMDInitTempVarNum].lvType) < getSizeOfType(simdType)) { // We want the largest required type size for the temp. JITDUMP("Increasing SIMDInitTempVar type size from %s to %s\n", @@ -308,7 +307,11 @@ var_types Compiler::getSIMDType(CORINFO_CLASS_HANDLE typeHnd, CorInfoType* baseT return TYP_UNDEF; } +#ifdef TARGET_ARM64 + type = JitConfig.JitUseScalableVectorT() ? TYP_SIMDSV : getSIMDTypeForSize(vectlen); +#else type = getSIMDTypeForSize(vectlen); +#endif break; } @@ -467,6 +470,12 @@ unsigned Compiler::getSizeOfSIMDType(var_types simdType) size = genTypeSize(simdType); break; +#ifdef TARGET_ARM64 + case TYP_SIMDSV: + size = getVectorTByteLength(); + break; +#endif + default: unreached(); } @@ -785,7 +794,7 @@ GenTree* Compiler::CreateAddressNodeForSimdHWIntrinsicCreate(GenTree* tree, var_ assert(index->IsCnsIntOrI()); unsigned indexVal = (unsigned)index->AsIntCon()->gtIconVal; - unsigned offset = indexVal * genTypeSize(tree->TypeGet()); + unsigned offset = indexVal * getSizeOfType(tree->TypeGet()); // Generate the boundary check exception. // The length for boundary check should be the maximum index number which should be diff --git a/src/coreclr/jit/targetarm64.cpp b/src/coreclr/jit/targetarm64.cpp index 244ffddaaff231..b0af41c001a079 100644 --- a/src/coreclr/jit/targetarm64.cpp +++ b/src/coreclr/jit/targetarm64.cpp @@ -71,7 +71,7 @@ ABIPassingInformation Arm64Classifier::Classify(Compiler* comp, if (hfaType != TYP_UNDEF) { - unsigned elemSize = genTypeSize(hfaType); + unsigned elemSize = comp->getSizeOfType(hfaType); unsigned slots = structLayout->GetSize() / elemSize; ABIPassingInformation info; if (m_floatRegs.Count() >= slots) @@ -122,9 +122,9 @@ ABIPassingInformation Arm64Classifier::Classify(Compiler* comp, } else { - assert(genTypeSize(type) <= TARGET_POINTER_SIZE); + assert(comp->getSizeOfType(type) <= TARGET_POINTER_SIZE); slots = 1; - passedSize = genTypeSize(type); + passedSize = comp->getSizeOfType(type); } assert((slots == 1) || (slots == 2)); @@ -182,7 +182,7 @@ ABIPassingInformation Arm64Classifier::Classify(Compiler* comp, unsigned alignment; if (compAppleArm64Abi()) { - alignment = varTypeIsStruct(type) ? TARGET_POINTER_SIZE : genTypeSize(type); + alignment = varTypeIsStruct(type) ? TARGET_POINTER_SIZE : comp->getSizeOfType(type); m_stackArgSize = roundUp(m_stackArgSize, alignment); segment = alignment < TARGET_POINTER_SIZE ? ABIPassingSegment::OnStackWithoutConsumingFullSlot(m_stackArgSize, 0, passedSize) diff --git a/src/coreclr/jit/typelist.h b/src/coreclr/jit/typelist.h index 865c177bc7bc32..627b5e1069ce26 100644 --- a/src/coreclr/jit/typelist.h +++ b/src/coreclr/jit/typelist.h @@ -4,6 +4,9 @@ #define GCS EA_GCREF #define BRS EA_BYREF #define EPS EA_PTRSIZE +#ifdef TARGET_ARM64 +#define EAS EA_SCALABLE +#endif #define PS TARGET_POINTER_SIZE #define PST (TARGET_POINTER_SIZE / sizeof(int)) @@ -63,9 +66,15 @@ DEF_TP(SIMD16 ,"simd16" , TYP_SIMD16, 16,16, 16, 4,16, VTR_FLOAT, available #if defined(TARGET_XARCH) DEF_TP(SIMD32 ,"simd32" , TYP_SIMD32, 32,32, 32, 8,16, VTR_FLOAT, availableDoubleRegs, RBM_FLT_CALLEE_SAVED, RBM_FLT_CALLEE_TRASH, VTF_S|VTF_VEC) DEF_TP(SIMD64 ,"simd64" , TYP_SIMD64, 64,64, 64, 16,16, VTR_FLOAT, availableDoubleRegs, RBM_FLT_CALLEE_SAVED, RBM_FLT_CALLEE_TRASH, VTF_S|VTF_VEC) +#elif defined(TARGET_ARM64) +DEF_TP(SIMDSV ,"simdsv" , TYP_SIMDSV, 0,EAS,EAS, 0,16, VTR_FLOAT, availableDoubleRegs, RBM_FLT_CALLEE_SAVED, RBM_FLT_CALLEE_TRASH, VTF_S|VTF_VEC) #endif // TARGET_XARCH #if defined(FEATURE_MASKED_HW_INTRINSICS) +#ifdef TARGET_ARM64 +DEF_TP(MASK ,"mask" , TYP_MASK, 0,EAS,EAS, 0, 8, VTR_MASK, availableMaskRegs, RBM_MSK_CALLEE_SAVED, RBM_MSK_CALLEE_TRASH, VTF_S) +#else DEF_TP(MASK ,"mask" , TYP_MASK, 8, 8, 8, 2, 8, VTR_MASK, availableMaskRegs, RBM_MSK_CALLEE_SAVED, RBM_MSK_CALLEE_TRASH, VTF_S) +#endif #endif // FEATURE_MASKED_HW_INTRINSICS #endif // FEATURE_SIMD diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index 431ec1b5e3b2bf..950463eebe9129 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -1701,6 +1701,9 @@ ValueNumStore::Chunk::Chunk(CompAllocator alloc, ValueNum* pNextBaseVN, var_type } case TYP_SIMD16: +#ifdef TARGET_ARM64 + case TYP_SIMDSV: +#endif { m_defs = new (alloc) Alloc::Type[ChunkSize]; break; @@ -1986,6 +1989,9 @@ ValueNum ValueNumStore::VNForGenericCon(var_types typ, uint8_t* cnsVal) return VNForSimd12Con(val); } case TYP_SIMD16: +#ifdef TARGET_ARM64 + case TYP_SIMDSV: +#endif { READ_VALUE(simd16_t); return VNForSimd16Con(val); @@ -2108,6 +2114,9 @@ ValueNum ValueNumStore::VNZeroForType(var_types typ) } case TYP_SIMD16: +#ifdef TARGET_ARM64 + case TYP_SIMDSV: // TODO-SVE: Implement scalable vector constant +#endif { return VNForSimd16Con(simd16_t::Zero()); } @@ -2205,6 +2214,9 @@ ValueNum ValueNumStore::VNAllBitsForType(var_types typ, unsigned elementCount) } case TYP_SIMD16: +#ifdef TARGET_ARM64 + case TYP_SIMDSV: +#endif { return VNForSimd16Con(simd16_t::AllBitsSet()); } @@ -2321,6 +2333,9 @@ ValueNum ValueNumStore::VNBroadcastForSimdType(var_types simdType, var_types sim } case TYP_SIMD16: +#ifdef TARGET_ARM64 + case TYP_SIMDSV: +#endif { simd16_t result = BroadcastConstantToSimd(this, simdBaseType, valVN); return VNForSimd16Con(result); @@ -2386,7 +2401,11 @@ bool ValueNumStore::VNIsVectorNaN(var_types simdType, var_types simdBaseType, Va } case TYP_SIMD16: +#ifdef TARGET_ARM64 + case TYP_SIMDSV: +#endif { + simdType = TYP_SIMD16; simd16_t tmp = GetConstantSimd16(valVN); memcpy(&vector, &tmp, genTypeSize(simdType)); break; @@ -2452,7 +2471,11 @@ bool ValueNumStore::VNIsVectorNegativeZero(var_types simdType, var_types simdBas } case TYP_SIMD16: +#ifdef TARGET_ARM64 + case TYP_SIMDSV: +#endif { + simdType = TYP_SIMD16; simd16_t tmp = GetConstantSimd16(valVN); memcpy(&vector, &tmp, genTypeSize(simdType)); break; @@ -4509,6 +4532,18 @@ ValueNum ValueNumStore::EvalCastForConstantArgs(var_types typ, VNFunc func, Valu unreached(); } } +#ifdef TARGET_ARM64 + case TYP_SIMD16: + case TYP_SIMDSV: + { + // TODO-SVE: VN for constant SIMDSV is borrowing from SIMD16, + // does this need to change? + assert(castToType == TYP_SIMD16 || castToType == TYP_SIMDSV); + simd16_t arg0Val = GetConstantSimd16(arg0VN); + return VNForSimd16Con(arg0Val); + } +#endif + default: unreached(); } @@ -6002,7 +6037,7 @@ ValueNum ValueNumStore::VNForLoadStoreBitCast(ValueNum value, var_types indType, if (typeOfValue != indType) { - assert((typeOfValue == TYP_STRUCT) || (indType == TYP_STRUCT) || (genTypeSize(indType) == indSize)); + assert((typeOfValue == TYP_STRUCT) || (indType == TYP_STRUCT) || (m_pComp->getSizeOfType(indType) == indSize)); value = VNForBitCast(value, indType, indSize); @@ -6214,7 +6249,7 @@ void Compiler::fgValueNumberLocalStore(GenTree* storeNode, { // TYP_STRUCT can represent the general case where the value could be of any size. var_types fieldStoreType = TYP_STRUCT; - if (vnStore->LoadStoreIsEntire(genTypeSize(fieldVarDsc), fieldStoreOffset, fieldStoreSize)) + if (vnStore->LoadStoreIsEntire(getSizeOfType(fieldVarDsc->TypeGet()), fieldStoreOffset, fieldStoreSize)) { // Avoid redundant bitcasts for the common case of a full definition. fieldStoreType = fieldVarDsc->TypeGet(); @@ -6278,7 +6313,8 @@ void Compiler::fgValueNumberArrayElemLoad(GenTree* loadTree, VNFuncApp* addrFunc unsigned elemSize = (elemType == TYP_STRUCT) ? info.compCompHnd->getClassSize(elemTypeEq) : genTypeSize(elemType); var_types loadType = loadTree->TypeGet(); unsigned loadSize = gtGetSizeOfIndirection(loadTree->AsIndir()); - ValueNum loadValueVN = vnStore->VNForLoad(VNK_Liberal, wholeElem, elemSize, loadType, offset, loadSize); + + ValueNum loadValueVN = vnStore->VNForLoad(VNK_Liberal, wholeElem, elemSize, loadType, offset, loadSize); loadTree->gtVNPair.SetLiberal(loadValueVN); @@ -6327,7 +6363,7 @@ void Compiler::fgValueNumberArrayElemStore(GenTree* storeNode, VNFuncApp* addrFu ValueNum hAtArrTypeAtArr = vnStore->VNForMapSelect(VNK_Liberal, TYP_MEM, hAtArrType, arrVN); JITDUMP(" GcHeap[elemTypeEq][array: " FMT_VN "] is " FMT_VN "\n", arrVN, hAtArrTypeAtArr); - unsigned elemSize = (elemType == TYP_STRUCT) ? info.compCompHnd->getClassSize(elemTypeEq) : genTypeSize(elemType); + unsigned elemSize = (elemType == TYP_STRUCT) ? info.compCompHnd->getClassSize(elemTypeEq) : getSizeOfType(elemType); // This is the value that should be stored at "arr[inx]". ValueNum newWholeElem = ValueNumStore::NoVN; @@ -7548,6 +7584,9 @@ ValueNum EvaluateUnarySimd( } case TYP_SIMD16: +#ifdef TARGET_ARM64 + case TYP_SIMDSV: +#endif { simd16_t arg0 = GetConstantSimd16(vns, baseType, arg0VN); @@ -7614,6 +7653,9 @@ ValueNum EvaluateBinarySimd(ValueNumStore* vns, } case TYP_SIMD16: +#ifdef TARGET_ARM64 + case TYP_SIMDSV: +#endif { simd16_t arg0 = GetConstantSimd16(vns, baseType, arg0VN); simd16_t arg1 = GetConstantSimd16(vns, baseType, arg1VN); @@ -7744,6 +7786,9 @@ ValueNum EvaluateSimdGetElement( } case TYP_SIMD16: +#ifdef TARGET_ARM64 + case TYP_SIMDSV: +#endif { return EvaluateSimdGetElement(vns, baseType, vns->GetConstantSimd16(arg0VN), arg1); } @@ -7788,6 +7833,9 @@ ValueNum EvaluateSimdCvtMaskToVector(ValueNumStore* vns, var_types simdType, var } case TYP_SIMD16: +#ifdef TARGET_ARM64 + case TYP_SIMDSV: +#endif { simd16_t result = {}; EvaluateSimdCvtMaskToVector(baseType, &result, arg0); @@ -7838,6 +7886,9 @@ ValueNum EvaluateSimdCvtVectorToMask(ValueNumStore* vns, var_types simdType, var } case TYP_SIMD16: +#ifdef TARGET_ARM64 + case TYP_SIMDSV: +#endif { simd16_t arg0 = GetConstantSimd16(vns, baseType, arg0VN); EvaluateSimdCvtVectorToMask(baseType, &result, arg0); @@ -8877,7 +8928,10 @@ ValueNum ValueNumStore::EvalHWIntrinsicFunBinary( case NI_AdvSimd_MultiplyByScalar: case NI_AdvSimd_Arm64_MultiplyByScalar: { - assert((TypeOfVN(arg0VN) == type) && (TypeOfVN(arg1VN) == TYP_SIMD8)); + // TODO-SVE: We shouldn't see this intrinsic operating on Vector after porting to SVE + assert(TypeOfVN(arg0VN) == type || (type == TYP_SIMDSV && TypeOfVN(arg0VN) == TYP_SIMD16 && + m_pComp->getSizeOfType(TYP_SIMDSV) == genTypeSize(TYP_SIMD16))); + assert(TypeOfVN(arg1VN) == TYP_SIMD8); if (!varTypeIsFloating(baseType)) { @@ -9126,50 +9180,53 @@ ValueNum ValueNumStore::EvalHWIntrinsicFunBinary( return VNForFunc(type, func, arg0VN, arg1VN, resultTypeVN); } -ValueNum EvaluateSimdWithElementFloating( - ValueNumStore* vns, var_types simdType, var_types baseType, ValueNum arg0VN, int32_t arg1, double arg2) +ValueNum ValueNumStore::EvaluateSimdWithElementFloating( + var_types simdType, var_types baseType, ValueNum arg0VN, int32_t arg1, double arg2) { assert(varTypeIsFloating(baseType)); - assert(vns->IsVNConstant(arg0VN)); - assert(simdType == vns->TypeOfVN(arg0VN)); - assert(static_cast(arg1) < GenTreeVecCon::ElementCount(genTypeSize(simdType), baseType)); + assert(IsVNConstant(arg0VN)); + assert(simdType == TypeOfVN(arg0VN)); + assert(static_cast(arg1) < GenTreeVecCon::ElementCount(m_pComp->getSizeOfType(simdType), baseType)); switch (simdType) { case TYP_SIMD8: { simd8_t result = {}; - EvaluateWithElementFloating(baseType, &result, vns->GetConstantSimd8(arg0VN), arg1, arg2); - return vns->VNForSimd8Con(result); + EvaluateWithElementFloating(baseType, &result, GetConstantSimd8(arg0VN), arg1, arg2); + return VNForSimd8Con(result); } case TYP_SIMD12: { simd12_t result = {}; - EvaluateWithElementFloating(baseType, &result, vns->GetConstantSimd12(arg0VN), arg1, arg2); - return vns->VNForSimd12Con(result); + EvaluateWithElementFloating(baseType, &result, GetConstantSimd12(arg0VN), arg1, arg2); + return VNForSimd12Con(result); } case TYP_SIMD16: +#ifdef TARGET_ARM64 + case TYP_SIMDSV: +#endif { simd16_t result = {}; - EvaluateWithElementFloating(baseType, &result, vns->GetConstantSimd16(arg0VN), arg1, arg2); - return vns->VNForSimd16Con(result); + EvaluateWithElementFloating(baseType, &result, GetConstantSimd16(arg0VN), arg1, arg2); + return VNForSimd16Con(result); } #if defined TARGET_XARCH case TYP_SIMD32: { simd32_t result = {}; - EvaluateWithElementFloating(baseType, &result, vns->GetConstantSimd32(arg0VN), arg1, arg2); - return vns->VNForSimd32Con(result); + EvaluateWithElementFloating(baseType, &result, GetConstantSimd32(arg0VN), arg1, arg2); + return VNForSimd32Con(result); } case TYP_SIMD64: { simd64_t result = {}; - EvaluateWithElementFloating(baseType, &result, vns->GetConstantSimd64(arg0VN), arg1, arg2); - return vns->VNForSimd64Con(result); + EvaluateWithElementFloating(baseType, &result, GetConstantSimd64(arg0VN), arg1, arg2); + return VNForSimd64Con(result); } #endif // TARGET_XARCH @@ -9180,50 +9237,53 @@ ValueNum EvaluateSimdWithElementFloating( } } -ValueNum EvaluateSimdWithElementIntegral( - ValueNumStore* vns, var_types simdType, var_types baseType, ValueNum arg0VN, int32_t arg1, int64_t arg2) +ValueNum ValueNumStore::EvaluateSimdWithElementIntegral( + var_types simdType, var_types baseType, ValueNum arg0VN, int32_t arg1, int64_t arg2) { assert(varTypeIsIntegral(baseType)); - assert(simdType == vns->TypeOfVN(arg0VN)); - assert(vns->IsVNConstant(arg0VN)); - assert(static_cast(arg1) < GenTreeVecCon::ElementCount(genTypeSize(simdType), baseType)); + assert(simdType == TypeOfVN(arg0VN)); + assert(IsVNConstant(arg0VN)); + assert(static_cast(arg1) < GenTreeVecCon::ElementCount(m_pComp->getSizeOfType(simdType), baseType)); switch (simdType) { case TYP_SIMD8: { simd8_t result = {}; - EvaluateWithElementIntegral(baseType, &result, vns->GetConstantSimd8(arg0VN), arg1, arg2); - return vns->VNForSimd8Con(result); + EvaluateWithElementIntegral(baseType, &result, GetConstantSimd8(arg0VN), arg1, arg2); + return VNForSimd8Con(result); } case TYP_SIMD12: { simd12_t result = {}; - EvaluateWithElementIntegral(baseType, &result, vns->GetConstantSimd12(arg0VN), arg1, arg2); - return vns->VNForSimd12Con(result); + EvaluateWithElementIntegral(baseType, &result, GetConstantSimd12(arg0VN), arg1, arg2); + return VNForSimd12Con(result); } case TYP_SIMD16: +#ifdef TARGET_ARM64 + case TYP_SIMDSV: +#endif { simd16_t result = {}; - EvaluateWithElementIntegral(baseType, &result, vns->GetConstantSimd16(arg0VN), arg1, arg2); - return vns->VNForSimd16Con(result); + EvaluateWithElementIntegral(baseType, &result, GetConstantSimd16(arg0VN), arg1, arg2); + return VNForSimd16Con(result); } #if defined TARGET_XARCH case TYP_SIMD32: { simd32_t result = {}; - EvaluateWithElementIntegral(baseType, &result, vns->GetConstantSimd32(arg0VN), arg1, arg2); - return vns->VNForSimd32Con(result); + EvaluateWithElementIntegral(baseType, &result, GetConstantSimd32(arg0VN), arg1, arg2); + return VNForSimd32Con(result); } case TYP_SIMD64: { simd64_t result = {}; - EvaluateWithElementIntegral(baseType, &result, vns->GetConstantSimd64(arg0VN), arg1, arg2); - return vns->VNForSimd64Con(result); + EvaluateWithElementIntegral(baseType, &result, GetConstantSimd64(arg0VN), arg1, arg2); + return VNForSimd64Con(result); } #endif // TARGET_XARCH @@ -9328,7 +9388,7 @@ ValueNum ValueNumStore::EvalHWIntrinsicFunTernary( int32_t index = GetConstantInt32(arg1VN); - if (static_cast(index) >= GenTreeVecCon::ElementCount(genTypeSize(type), baseType)) + if (static_cast(index) >= GenTreeVecCon::ElementCount(m_pComp->getSizeOfType(type), baseType)) { // Nothing to fold for out of range indexes break; @@ -9346,7 +9406,7 @@ ValueNum ValueNumStore::EvalHWIntrinsicFunTernary( { value = GetConstantDouble(arg2VN); } - return EvaluateSimdWithElementFloating(this, type, baseType, arg0VN, index, value); + return EvaluateSimdWithElementFloating(type, baseType, arg0VN, index, value); } else { @@ -9361,7 +9421,7 @@ ValueNum ValueNumStore::EvalHWIntrinsicFunTernary( { value = GetConstantInt32(arg2VN); } - return EvaluateSimdWithElementIntegral(this, type, baseType, arg0VN, index, value); + return EvaluateSimdWithElementIntegral(type, baseType, arg0VN, index, value); } } @@ -10307,6 +10367,9 @@ void ValueNumStore::vnDump(Compiler* comp, ValueNum vn, bool isPtr) } case TYP_SIMD16: +#ifdef TARGET_ARM64 + case TYP_SIMDSV: +#endif { simd16_t cnsVal = GetConstantSimd16(vn); printf("Simd16Cns[0x%08x, 0x%08x, 0x%08x, 0x%08x]", cnsVal.u32[0], cnsVal.u32[1], cnsVal.u32[2], @@ -11914,6 +11977,9 @@ void Compiler::fgValueNumberTreeConst(GenTree* tree) } case TYP_SIMD16: +#ifdef TARGET_ARM64 + case TYP_SIMDSV: // TODO-SVE: Implement scalable vector constant +#endif { simd16_t simd16Val; memcpy(&simd16Val, &tree->AsVecCon()->gtSimdVal, sizeof(simd16_t)); @@ -12100,7 +12166,7 @@ void Compiler::fgValueNumberStore(GenTree* store) case GT_STORE_LCL_FLD: { GenTreeLclFld* lclFld = store->AsLclFld(); - fgValueNumberLocalStore(store, lclFld, lclFld->GetLclOffs(), lclFld->GetSize(), valueVNPair); + fgValueNumberLocalStore(store, lclFld, lclFld->GetLclOffs(), lclFld->GetSize(this), valueVNPair); } break; @@ -12189,7 +12255,7 @@ void Compiler::fgValueNumberSsaVarDef(GenTreeLclVarCommon* lcl) // Account for type mismatches. if (genActualType(varDsc) != genActualType(lcl)) { - if (genTypeSize(varDsc) != genTypeSize(lcl)) + if (getSizeOfType(varDsc->TypeGet()) != getSizeOfType(lcl->TypeGet())) { assert(varDsc->TypeIs(TYP_LONG) && lcl->TypeIs(TYP_INT)); lcl->gtVNPair = vnStore->VNPairForCast(wholeLclVarVNP, lcl->TypeGet(), varDsc->TypeGet()); @@ -12586,7 +12652,7 @@ void Compiler::fgValueNumberTree(GenTree* tree) { ValueNumPair lclVarValue = varDsc->GetPerSsaData(lclFld->GetSsaNum())->m_vnPair; lclFld->gtVNPair = vnStore->VNPairForLoad(lclVarValue, lvaLclExactSize(lclNum), lclFld->TypeGet(), - lclFld->GetLclOffs(), lclFld->GetSize()); + lclFld->GetLclOffs(), lclFld->GetSize(this)); } else if (varDsc->IsAddressExposed()) { @@ -13463,7 +13529,15 @@ void Compiler::fgValueNumberCastTree(GenTree* tree) bool srcIsUnsigned = ((tree->gtFlags & GTF_UNSIGNED) != 0); bool hasOverflowCheck = tree->gtOverflowEx(); - assert(genActualType(castToType) == genActualType(tree->TypeGet())); // Ensure that the resultType is correct + // Ensure that the resultType is correct + assert(genActualType(castToType) == genActualType(tree->TypeGet()) +#ifdef TARGET_ARM64 + // We can truncate scalable vectors to any SIMD type, and can zero + // extend SIMD types to a scalable vector. + || (tree->TypeGet() == TYP_SIMDSV && varTypeIsSIMD(castToType)) || + (varTypeIsSIMD(tree->TypeGet()) && castToType == TYP_SIMDSV) +#endif + ); tree->gtVNPair = vnStore->VNPairForCast(srcVNPair, castToType, castFromType, srcIsUnsigned, hasOverflowCheck); } @@ -13487,7 +13561,8 @@ ValueNum ValueNumStore::VNForCast(ValueNum srcVN, // For integral unchecked casts, only the "int -> long" upcasts use // "srcIsUnsigned", to decide whether to use sign or zero extension. - if (!hasOverflowCheck && !varTypeIsFloating(castToType) && (genTypeSize(castToType) <= genTypeSize(castFromType))) + if (!hasOverflowCheck && !varTypeIsFloating(castToType) && + (m_pComp->getSizeOfType(castToType) <= m_pComp->getSizeOfType(castFromType))) { srcIsUnsigned = false; } @@ -13582,7 +13657,7 @@ ValueNum ValueNumStore::EncodeBitCastType(var_types castToType, unsigned size) { if (castToType != TYP_STRUCT) { - assert(size == genTypeSize(castToType)); + assert(size == m_pComp->getSizeOfType(castToType)); return VNForIntCon(castToType); } diff --git a/src/coreclr/jit/valuenum.h b/src/coreclr/jit/valuenum.h index 77af89db114c84..e39cdc226ca741 100644 --- a/src/coreclr/jit/valuenum.h +++ b/src/coreclr/jit/valuenum.h @@ -404,6 +404,10 @@ class ValueNumStore ValueNum EvalUsingMathIdentity(var_types typ, VNFunc vnf, ValueNum vn0, ValueNum vn1); + ValueNum EvaluateSimdWithElementIntegral( + var_types simdType, var_types baseType, ValueNum arg0VN, int32_t arg1, int64_t arg2); + ValueNum EvaluateSimdWithElementFloating( + var_types simdType, var_types baseType, ValueNum arg0VN, int32_t arg1, double arg2); // This is the constant value used for the default value of m_mapSelectBudget #define DEFAULT_MAP_SELECT_BUDGET 100 // used by JitVNMapSelBudget diff --git a/src/coreclr/vm/callingconvention.h b/src/coreclr/vm/callingconvention.h index 70fc6ef34c6b4b..8b6f3ea43224bb 100644 --- a/src/coreclr/vm/callingconvention.h +++ b/src/coreclr/vm/callingconvention.h @@ -64,6 +64,7 @@ struct ArgLocDesc case CORINFO_HFA_ELEM_DOUBLE: return 8; case CORINFO_HFA_ELEM_VECTOR64: return 8; case CORINFO_HFA_ELEM_VECTOR128: return 16; + case CORINFO_HFA_ELEM_VECTORT: return ExecutionManager::GetEEJitManager()->GetSizeOfVectorT(); default: _ASSERTE(!"Invalid HFA Type"); return 0; } } diff --git a/src/coreclr/vm/class.cpp b/src/coreclr/vm/class.cpp index f42793017ee9b4..fef3e2347da689 100644 --- a/src/coreclr/vm/class.cpp +++ b/src/coreclr/vm/class.cpp @@ -1684,45 +1684,60 @@ bool MethodTable::IsHFA() #endif // !FEATURE_HFA //******************************************************************************* -int MethodTable::GetVectorSize() +CorInfoHFAElemType MethodTable::GetVectorHFA() { // This is supported for finding HVA types for Arm64. In order to support the altjit, // we support this on 64-bit platforms (i.e. Arm64 and X64). + CorInfoHFAElemType hfaType = CORINFO_HFA_ELEM_NONE; #ifdef TARGET_64BIT if (IsIntrinsicType()) { LPCUTF8 namespaceName; LPCUTF8 className = GetFullyQualifiedNameInfo(&namespaceName); - int vectorSize = 0; if (strcmp(className, "Vector`1") == 0) { _ASSERTE(strcmp(namespaceName, "System.Numerics") == 0); - vectorSize = GetNumInstanceFieldBytes(); +#ifdef TARGET_ARM64 + hfaType = ExecutionManager::GetEEJitManager()->UseScalableVectorT() ? CORINFO_HFA_ELEM_VECTORT : CORINFO_HFA_ELEM_VECTOR128; +#else + switch (GetNumInstanceFieldBytes()) + { + case 8: + hfaType = CORINFO_HFA_ELEM_VECTOR64; + break; + case 16: + hfaType = CORINFO_HFA_ELEM_VECTOR128; + break; + default: + _ASSERTE(false); + break; + } +#endif } else if (strcmp(className, "Vector128`1") == 0) { _ASSERTE(strcmp(namespaceName, "System.Runtime.Intrinsics") == 0); - vectorSize = 16; + hfaType = CORINFO_HFA_ELEM_VECTOR128; } else if (strcmp(className, "Vector64`1") == 0) { _ASSERTE(strcmp(namespaceName, "System.Runtime.Intrinsics") == 0); - vectorSize = 8; + hfaType = CORINFO_HFA_ELEM_VECTOR64; } - if (vectorSize != 0) + if (hfaType != CORINFO_HFA_ELEM_NONE) { // We need to verify that T (the element or "base" type) is a primitive type. TypeHandle typeArg = GetInstantiation()[0]; CorElementType corType = typeArg.GetSignatureCorElementType(); - if (((corType >= ELEMENT_TYPE_I1) && (corType <= ELEMENT_TYPE_R8)) || (corType == ELEMENT_TYPE_I) || (corType == ELEMENT_TYPE_U)) + if (!(((corType >= ELEMENT_TYPE_I1) && (corType <= ELEMENT_TYPE_R8)) || (corType == ELEMENT_TYPE_I) || (corType == ELEMENT_TYPE_U))) { - return vectorSize; + return CORINFO_HFA_ELEM_NONE; } } } #endif // TARGET_64BIT - return 0; + return hfaType; } //******************************************************************************* @@ -1744,10 +1759,11 @@ CorInfoHFAElemType MethodTable::GetHFAType() _ASSERTE(pMT->IsValueType()); _ASSERTE(pMT->GetNumInstanceFields() > 0); - int vectorSize = pMT->GetVectorSize(); - if (vectorSize != 0) + CorInfoHFAElemType hfaType = pMT->GetVectorHFA(); + + if (hfaType != CORINFO_HFA_ELEM_NONE) { - return (vectorSize == 8) ? CORINFO_HFA_ELEM_VECTOR64 : CORINFO_HFA_ELEM_VECTOR128; + return hfaType; } PTR_FieldDesc pFirstField = pMT->GetApproxFieldDescListRaw(); @@ -1816,7 +1832,7 @@ EEClass::CheckForHFA() // The opaque Vector types appear to have multiple fields, but need to be treated // as an opaque type of a single vector. - if (GetMethodTable()->GetVectorSize() != 0) + if (GetMethodTable()->GetVectorHFA() != CORINFO_HFA_ELEM_NONE) { #if defined(FEATURE_HFA) GetMethodTable()->SetIsHFA(); @@ -1842,27 +1858,13 @@ EEClass::CheckForHFA() { case ELEMENT_TYPE_VALUETYPE: { -#ifdef TARGET_ARM64 MethodTable* pMT; #if defined(FEATURE_HFA) pMT = pByValueClassCache[i]; #else pMT = pFD->LookupApproxFieldTypeHandle().AsMethodTable(); #endif - int thisElemSize = pMT->GetVectorSize(); - if (thisElemSize != 0) - { - fieldHFAType = (thisElemSize == 8) ? CORINFO_HFA_ELEM_VECTOR64 : CORINFO_HFA_ELEM_VECTOR128; - } - else -#endif // TARGET_ARM64 - { -#if defined(FEATURE_HFA) - fieldHFAType = pByValueClassCache[i]->GetHFAType(); -#else - fieldHFAType = pFD->LookupApproxFieldTypeHandle().AsMethodTable()->GetHFAType(); -#endif - } + fieldHFAType = pMT->GetHFAType(); int requiredAlignment; switch (fieldHFAType) @@ -1875,6 +1877,7 @@ EEClass::CheckForHFA() requiredAlignment = 8; break; case CORINFO_HFA_ELEM_VECTOR128: + case CORINFO_HFA_ELEM_VECTORT: requiredAlignment = 16; break; default: @@ -1946,6 +1949,10 @@ EEClass::CheckForHFA() case CORINFO_HFA_ELEM_VECTOR128: elemSize = 16; break; + case CORINFO_HFA_ELEM_VECTORT: + elemSize = ExecutionManager::GetEEJitManager()->GetSizeOfVectorT(); + _ASSERTE(elemSize != 0); + break; #endif default: // ELEMENT_TYPE_END diff --git a/src/coreclr/vm/classlayoutinfo.cpp b/src/coreclr/vm/classlayoutinfo.cpp index 62ca8f733a2095..4fd62cd474ad73 100644 --- a/src/coreclr/vm/classlayoutinfo.cpp +++ b/src/coreclr/vm/classlayoutinfo.cpp @@ -1186,6 +1186,10 @@ CorInfoHFAElemType EEClassNativeLayoutInfo::GetNativeHFATypeRaw() const #ifdef TARGET_ARM64 case CORINFO_HFA_ELEM_VECTOR64: elemSize = 8; break; case CORINFO_HFA_ELEM_VECTOR128: elemSize = 16; break; + case CORINFO_HFA_ELEM_VECTORT: + elemSize = ExecutionManager::GetEEJitManager()->GetSizeOfVectorT(); + _ASSERTE(elemSize != 0); + break; #endif default: _ASSERTE(!"Invalid HFA Type"); } diff --git a/src/coreclr/vm/codeman.cpp b/src/coreclr/vm/codeman.cpp index 3fe0aaf192bb89..99820e2f4ae504 100644 --- a/src/coreclr/vm/codeman.cpp +++ b/src/coreclr/vm/codeman.cpp @@ -1548,6 +1548,35 @@ void EEJitManager::SetCpuInfo() m_CPUCompileFlags = CPUCompileFlags; } +uint32_t EEJitManager::GetSizeOfVectorT() +{ + LIMITED_METHOD_CONTRACT; + + uint32_t size = 0; + +#if defined(TARGET_X86) || defined(TARGET_AMD64) + if (m_CPUCompileFlags.IsSet(InstructionSet_VectorT512)) + { + length = 64; + } + else if (CPUCompileFlags.IsSet(InstructionSet_VectorT256)) + { + length = 32; + } +#elif defined(TARGET_ARM64) + if (UseScalableVectorT()) + { + size = (uint32_t) GetSveLengthFromOS(); + } + else if (m_CPUCompileFlags.IsSet(InstructionSet_VectorT128)) + { + size = 16; + } +#endif + + return size; +} + // Define some data that we can use to get a better idea of what happened when we get a Watson dump that indicates the JIT failed to load. // This will be used and updated by the JIT loading and initialization functions, and the data written will get written into a Watson dump. diff --git a/src/coreclr/vm/codeman.h b/src/coreclr/vm/codeman.h index 0862961e8f1b62..8d82253409c2a7 100644 --- a/src/coreclr/vm/codeman.h +++ b/src/coreclr/vm/codeman.h @@ -2188,6 +2188,20 @@ class EEJitManager final : public EECodeGenManager return m_CPUCompileFlags; } + inline bool UseScalableVectorT() + { + LIMITED_METHOD_CONTRACT; +#ifdef TARGET_ARM64 + // Vector length discovery is currently dependent on running directly on Arm64. + return CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_JitUseScalableVectorT) + && m_CPUCompileFlags.IsSet(InstructionSet_Sve_Arm64); +#else + return false; +#endif + } + + uint32_t GetSizeOfVectorT(); + private : Crst m_JitLoadLock; diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index 7d21c93a5ebfc6..cca82d4d3611d8 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -2001,8 +2001,8 @@ class MethodTable bool IsHFA(); #endif // FEATURE_HFA - // Returns the size in bytes of this type if it is a HW vector type; 0 otherwise. - int GetVectorSize(); + // Returns the HFA type if it is a HW vector type. + CorInfoHFAElemType GetVectorHFA(); // Get the HFA type. This is supported both with FEATURE_HFA, in which case it // depends on the cached bit on the class, or without, in which case it is recomputed diff --git a/src/coreclr/vm/methodtablebuilder.cpp b/src/coreclr/vm/methodtablebuilder.cpp index 1195153c5b12b8..7d9634e6dd2181 100644 --- a/src/coreclr/vm/methodtablebuilder.cpp +++ b/src/coreclr/vm/methodtablebuilder.cpp @@ -1169,7 +1169,7 @@ BOOL MethodTableBuilder::CheckIfSIMDAndUpdateSize() { STANDARD_VM_CONTRACT; -#if defined(TARGET_X86) || defined(TARGET_AMD64) +#if defined(TARGET_X86) || defined(TARGET_AMD64) || defined(TARGET_ARM64) if (!bmtProp->fIsIntrinsicType) return false; @@ -1185,24 +1185,15 @@ BOOL MethodTableBuilder::CheckIfSIMDAndUpdateSize() if (strcmp(className, "Vector`1") != 0 || strcmp(nameSpace, "System.Numerics") != 0) return false; - CORJIT_FLAGS CPUCompileFlags = ExecutionManager::GetEEJitManager()->GetCPUCompileFlags(); - uint32_t numInstanceFieldBytes = 16; + uint32_t vectorTSize = ExecutionManager::GetEEJitManager()->GetSizeOfVectorT(); - if (CPUCompileFlags.IsSet(InstructionSet_VectorT512)) + if (vectorTSize > 0 && vectorTSize != 16) { - numInstanceFieldBytes = 64; - } - else if (CPUCompileFlags.IsSet(InstructionSet_VectorT256)) - { - numInstanceFieldBytes = 32; - } - - if (numInstanceFieldBytes != 16) - { - bmtFP->NumInstanceFieldBytes = numInstanceFieldBytes; + bmtFP->NumInstanceFieldBytes = vectorTSize; return true; } -#endif // TARGET_X86 || TARGET_AMD64 + +#endif // TARGET_X86 || TARGET_AMD64 || TARGET_ARM64 return false; } diff --git a/src/tests/JIT/opt/SVE/ConstantMasks.cs b/src/tests/JIT/opt/SVE/ConstantMasks.cs index 078e60e9b55411..a7aa2116f5c194 100644 --- a/src/tests/JIT/opt/SVE/ConstantMasks.cs +++ b/src/tests/JIT/opt/SVE/ConstantMasks.cs @@ -67,14 +67,14 @@ static void CndSelectEmbedded(Vector mask, Vector op1, Vector op2 [MethodImpl(MethodImplOptions.NoInlining)] static void CndSelectEmbeddedFalseMask(Vector op1, Vector op2) { - //ARM64-FULL-LINE: mov v0.16b, v1.16b + //ARM64-FULL-LINE: mov {{v0.16b, v1.16b|z0.d, z1.d}} Vector result = Sve.ConditionalSelect(Sve.CreateFalseMaskInt32(), Sve.AbsoluteDifference(op1, op2), op2); Consume(result); } [MethodImpl(MethodImplOptions.NoInlining)] static void CndSelectEmbeddedZero(Vector op1, Vector op2) { - //ARM64-FULL-LINE: mov v0.16b, v1.16b + //ARM64-FULL-LINE: mov {{v0.16b, v1.16b|z0.d, z1.d}} Vector result = Sve.ConditionalSelect(Vector.Zero, Sve.AbsoluteDifference(op1, op2), op2); Consume(result); } @@ -112,14 +112,14 @@ static void CndSelectOptionalEmbedded(Vector mask, Vector op1, Vector< [MethodImpl(MethodImplOptions.NoInlining)] static void CndSelectOptionalEmbeddedFalseMask(Vector op1, Vector op2) { - //ARM64-FULL-LINE: mov v0.16b, v1.16b + //ARM64-FULL-LINE: mov {{v0.16b, v1.16b|z0.d, z1.d}} Vector result = Sve.ConditionalSelect(Sve.CreateFalseMaskInt32(), Sve.Add(op1, op2), op2); Consume(result); } [MethodImpl(MethodImplOptions.NoInlining)] static void CndSelectOptionalEmbeddedZero(Vector op1, Vector op2) { - //ARM64-FULL-LINE: mov v0.16b, v1.16b + //ARM64-FULL-LINE: mov {{v0.16b, v1.16b|z0.d, z1.d}} Vector result = Sve.ConditionalSelect(Vector.Zero, Sve.Add(op1, op2), op2); Consume(result); } @@ -153,14 +153,14 @@ static void CndSelectEmbeddedOneOp(Vector mask, Vector op1) { [MethodImpl(MethodImplOptions.NoInlining)] static void CndSelectEmbeddedOneOpFalseMask(Vector dummy, Vector op1) { - //ARM64-FULL-LINE: mov v0.16b, v1.16b + //ARM64-FULL-LINE: mov {{v0.16b, v1.16b|z0.d, z1.d}} Vector result = Sve.ConditionalSelect(Sve.CreateFalseMaskInt32(), Sve.Abs(op1), op1); Consume(result); } [MethodImpl(MethodImplOptions.NoInlining)] static void CndSelectEmbeddedOneOpZero(Vector dummy, Vector op1) { - //ARM64-FULL-LINE: mov v0.16b, v1.16b + //ARM64-FULL-LINE: mov {{v0.16b, v1.16b|z0.d, z1.d}} Vector result = Sve.ConditionalSelect(Vector.Zero, Sve.Abs(op1), op1); Consume(result); } @@ -199,14 +199,14 @@ static void CndSelectEmbeddedReduction(Vector mask, Vector op1, Vecto [MethodImpl(MethodImplOptions.NoInlining)] static void CndSelectEmbeddedReductionFalseMask(Vector op1, Vector opf) { - //ARM64-FULL-LINE: mov v0.16b, v1.16b + //ARM64-FULL-LINE: mov {{v0.16b, v1.16b|z0.d, z1.d}} Vector result = Sve.ConditionalSelect(Sve.CreateFalseMaskInt64(), Sve.AddAcross(op1), opf); Consume(result); } [MethodImpl(MethodImplOptions.NoInlining)] static void CndSelectEmbeddedReductionZero(Vector op1, Vector opf) { - //ARM64-FULL-LINE: mov v0.16b, v1.16b + //ARM64-FULL-LINE: mov {{v0.16b, v1.16b|z0.d, z1.d}} Vector result = Sve.ConditionalSelect(Vector.Zero, Sve.AddAcross(op1), opf); Consume(result); } diff --git a/src/tests/JIT/opt/SVE/ConstantMasksOp2Fixed.cs b/src/tests/JIT/opt/SVE/ConstantMasksOp2Fixed.cs index ba23ebe08f07c9..8e9f07c5039a9c 100644 --- a/src/tests/JIT/opt/SVE/ConstantMasksOp2Fixed.cs +++ b/src/tests/JIT/opt/SVE/ConstantMasksOp2Fixed.cs @@ -235,7 +235,7 @@ static void CndSelectEmbeddedReductionF(Vector mask, Vector op1) { [MethodImpl(MethodImplOptions.NoInlining)] static void CndSelectEmbeddedReductionZ(Vector mask, Vector op1) { //ARM64-FULL-LINE: cmpne {{p[0-9]+}}.d, {{p[0-9]+}}/z, {{z[0-9]+}}.d, #0 - //ARM64-FULL-LINE-NEXT: ptrue {{p[0-9]+}}.s + //ARM64-FULL-LINE: ptrue {{p[0-9]+}}.s //ARM64-FULL-LINE-NEXT: saddv {{d[0-9]+}}, {{p[0-9]+}}, {{z[0-9]+}}.s //ARM64-FULL-LINE-NEXT: movi {{v[0-9]+}}.4s, #0 //ARM64-FULL-LINE-NEXT: sel {{z[0-9]+}}.d, {{p[0-9]+}}, {{z[0-9]+}}.d, {{z[0-9]+}}.d From 8ae80c3c64a6a07eefb95f2ef52799ae2104802a Mon Sep 17 00:00:00 2001 From: Sebastian Nickolls Date: Tue, 28 Oct 2025 10:20:08 +0000 Subject: [PATCH 05/12] Fix typo in immediate comparison in Compiler::instGen_Set_Reg_To_Base_Plus_Imm --- src/coreclr/jit/codegenarm64.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/codegenarm64.cpp b/src/coreclr/jit/codegenarm64.cpp index d2521de5a41b24..b18a9871a4cd9d 100644 --- a/src/coreclr/jit/codegenarm64.cpp +++ b/src/coreclr/jit/codegenarm64.cpp @@ -2088,7 +2088,7 @@ void CodeGen::instGen_Set_Reg_To_Base_Plus_Imm(emitAttr size, { GetEmitter()->emitIns_R_R_I(INS_add, EA_PTRSIZE, dstReg, baseReg, imm); } - else if (-4095 <= imm < 0) + else if (-4095 <= imm && imm < 0) { GetEmitter()->emitIns_R_R_I(INS_sub, EA_PTRSIZE, dstReg, baseReg, -imm); } From 5558a08d17ed9a32a0e76e6443d851132a6e9bcb Mon Sep 17 00:00:00 2001 From: Sebastian Nickolls Date: Tue, 28 Oct 2025 11:26:00 +0000 Subject: [PATCH 06/12] Fix conditional compilation for config values --- src/coreclr/inc/clrconfigvalues.h | 2 +- src/coreclr/jit/jitconfigvalues.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/inc/clrconfigvalues.h b/src/coreclr/inc/clrconfigvalues.h index 943aeef021caa2..bd7ee59e0a1017 100644 --- a/src/coreclr/inc/clrconfigvalues.h +++ b/src/coreclr/inc/clrconfigvalues.h @@ -350,7 +350,7 @@ RETAIL_CONFIG_DWORD_INFO(INTERNAL_MultiCoreJitNoProfileGather, W("MultiCoreJitNo #endif #ifdef TARGET_ARM64 -CONFIG_DWORD_INFO(EXTERNAL_JitUseScalableVectorT, W("JitUseScalableVectorT"), 0, "Accelerate Vector with SVE if available.") +RETAIL_CONFIG_DWORD_INFO(EXTERNAL_JitUseScalableVectorT, W("JitUseScalableVectorT"), 0, "Accelerate Vector with SVE if available.") #endif /// diff --git a/src/coreclr/jit/jitconfigvalues.h b/src/coreclr/jit/jitconfigvalues.h index af4f3baca368f6..445c134299c72a 100644 --- a/src/coreclr/jit/jitconfigvalues.h +++ b/src/coreclr/jit/jitconfigvalues.h @@ -846,7 +846,7 @@ CONFIG_STRING(JitRawHexCodeFile, "JitRawHexCodeFile") CONFIG_INTEGER(JitSaveFpLrWithCalleeSavedRegisters, "JitSaveFpLrWithCalleeSavedRegisters", 0) // Experimental support for vector length agnostic implementation of Vector -CONFIG_INTEGER(JitUseScalableVectorT, "JitUseScalableVectorT", 0) +RELEASE_CONFIG_INTEGER(JitUseScalableVectorT, "JitUseScalableVectorT", 0) #endif // defined(TARGET_ARM64) #if defined(TARGET_LOONGARCH64) From 79ba8ba1487a645676d3d80d007c7955357d0e77 Mon Sep 17 00:00:00 2001 From: Sebastian Nickolls Date: Tue, 28 Oct 2025 14:33:58 +0000 Subject: [PATCH 07/12] Fix macro expansion for MSVC --- src/coreclr/jit/valuenum.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index 950463eebe9129..1c153a83a30995 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -13530,14 +13530,15 @@ void Compiler::fgValueNumberCastTree(GenTree* tree) bool hasOverflowCheck = tree->gtOverflowEx(); // Ensure that the resultType is correct - assert(genActualType(castToType) == genActualType(tree->TypeGet()) #ifdef TARGET_ARM64 - // We can truncate scalable vectors to any SIMD type, and can zero - // extend SIMD types to a scalable vector. - || (tree->TypeGet() == TYP_SIMDSV && varTypeIsSIMD(castToType)) || - (varTypeIsSIMD(tree->TypeGet()) && castToType == TYP_SIMDSV) + // We can truncate scalable vectors to any SIMD type, and can zero + // extend SIMD types to a scalable vector. + assert(genActualType(castToType) == genActualType(tree->TypeGet()) || + (tree->TypeGet() == TYP_SIMDSV && varTypeIsSIMD(castToType)) || + (varTypeIsSIMD(tree->TypeGet()) && castToType == TYP_SIMDSV)); +#else + assert(genActualType(castToType) == genActualType(tree->TypeGet())); #endif - ); tree->gtVNPair = vnStore->VNPairForCast(srcVNPair, castToType, castFromType, srcIsUnsigned, hasOverflowCheck); } From 931231dd9f190207bc6d7b943ff19a3064e0e3b8 Mon Sep 17 00:00:00 2001 From: Sebastian Nickolls Date: Wed, 29 Oct 2025 14:18:10 +0000 Subject: [PATCH 08/12] Make the length of VectorT accessible to the DAC The length of VectorT is now a constant that is set on VM initialization, and the DAC needs to be able to replicate this state without access to the original SVE VL value. --- src/coreclr/inc/dacvars.h | 2 + src/coreclr/vm/callingconvention.h | 2 +- src/coreclr/vm/class.cpp | 4 +- src/coreclr/vm/classlayoutinfo.cpp | 2 +- src/coreclr/vm/codeman.cpp | 37 +++++++++++-------- src/coreclr/vm/codeman.h | 17 ++------- .../vm/datadescriptor/datadescriptor.inc | 2 + src/coreclr/vm/methodtablebuilder.cpp | 2 +- src/coreclr/vm/vars.cpp | 2 + src/coreclr/vm/vars.hpp | 2 + 10 files changed, 38 insertions(+), 34 deletions(-) diff --git a/src/coreclr/inc/dacvars.h b/src/coreclr/inc/dacvars.h index 0be37f0098163a..6dd56de621bf28 100644 --- a/src/coreclr/inc/dacvars.h +++ b/src/coreclr/inc/dacvars.h @@ -134,6 +134,8 @@ DEFINE_DACVAR(PTR_JITNotification, dac__g_pNotificationTable, ::g_pNotificationT DEFINE_DACVAR(ULONG32, dac__g_dacNotificationFlags, ::g_dacNotificationFlags) DEFINE_DACVAR(DWORD, dac__g_gcNotificationFlags, g_gcNotificationFlags) +DEFINE_DACVAR(DWORD, dac__g_vectorTByteLength, ::g_vectorTByteLength) +DEFINE_DACVAR(BOOL, dac__g_vectorTIsScalable, ::g_vectorTIsScalable) DEFINE_DACVAR(PTR_EEConfig, dac__g_pConfig, ::g_pConfig) diff --git a/src/coreclr/vm/callingconvention.h b/src/coreclr/vm/callingconvention.h index 8b6f3ea43224bb..560716689256b4 100644 --- a/src/coreclr/vm/callingconvention.h +++ b/src/coreclr/vm/callingconvention.h @@ -64,7 +64,7 @@ struct ArgLocDesc case CORINFO_HFA_ELEM_DOUBLE: return 8; case CORINFO_HFA_ELEM_VECTOR64: return 8; case CORINFO_HFA_ELEM_VECTOR128: return 16; - case CORINFO_HFA_ELEM_VECTORT: return ExecutionManager::GetEEJitManager()->GetSizeOfVectorT(); + case CORINFO_HFA_ELEM_VECTORT: return g_vectorTByteLength; default: _ASSERTE(!"Invalid HFA Type"); return 0; } } diff --git a/src/coreclr/vm/class.cpp b/src/coreclr/vm/class.cpp index fef3e2347da689..6641522bb8b1be 100644 --- a/src/coreclr/vm/class.cpp +++ b/src/coreclr/vm/class.cpp @@ -1699,7 +1699,7 @@ CorInfoHFAElemType MethodTable::GetVectorHFA() { _ASSERTE(strcmp(namespaceName, "System.Numerics") == 0); #ifdef TARGET_ARM64 - hfaType = ExecutionManager::GetEEJitManager()->UseScalableVectorT() ? CORINFO_HFA_ELEM_VECTORT : CORINFO_HFA_ELEM_VECTOR128; + hfaType = g_vectorTIsScalable ? CORINFO_HFA_ELEM_VECTORT : CORINFO_HFA_ELEM_VECTOR128; #else switch (GetNumInstanceFieldBytes()) { @@ -1950,7 +1950,7 @@ EEClass::CheckForHFA() elemSize = 16; break; case CORINFO_HFA_ELEM_VECTORT: - elemSize = ExecutionManager::GetEEJitManager()->GetSizeOfVectorT(); + elemSize = g_vectorTByteLength; _ASSERTE(elemSize != 0); break; #endif diff --git a/src/coreclr/vm/classlayoutinfo.cpp b/src/coreclr/vm/classlayoutinfo.cpp index 4fd62cd474ad73..24dc69349d117b 100644 --- a/src/coreclr/vm/classlayoutinfo.cpp +++ b/src/coreclr/vm/classlayoutinfo.cpp @@ -1187,7 +1187,7 @@ CorInfoHFAElemType EEClassNativeLayoutInfo::GetNativeHFATypeRaw() const case CORINFO_HFA_ELEM_VECTOR64: elemSize = 8; break; case CORINFO_HFA_ELEM_VECTOR128: elemSize = 16; break; case CORINFO_HFA_ELEM_VECTORT: - elemSize = ExecutionManager::GetEEJitManager()->GetSizeOfVectorT(); + elemSize = g_vectorTByteLength; _ASSERTE(elemSize != 0); break; #endif diff --git a/src/coreclr/vm/codeman.cpp b/src/coreclr/vm/codeman.cpp index 99820e2f4ae504..6fb98db256f327 100644 --- a/src/coreclr/vm/codeman.cpp +++ b/src/coreclr/vm/codeman.cpp @@ -1139,6 +1139,8 @@ EECodeGenManager::EECodeGenManager() EEJitManager::EEJitManager() : m_CPUCompileFlags() , m_JitLoadLock( CrstSingleUseLock ) + , m_vectorTByteLength(0) + , m_useScalableVectorT(false) { CONTRACTL { THROWS; @@ -1546,35 +1548,40 @@ void EEJitManager::SetCpuInfo() #endif // TARGET_X86 || TARGET_AMD64 m_CPUCompileFlags = CPUCompileFlags; -} - -uint32_t EEJitManager::GetSizeOfVectorT() -{ - LIMITED_METHOD_CONTRACT; - uint32_t size = 0; + g_vectorTIsScalable = false; + g_vectorTByteLength = 0; #if defined(TARGET_X86) || defined(TARGET_AMD64) if (m_CPUCompileFlags.IsSet(InstructionSet_VectorT512)) { - length = 64; + g_vectorTByteLength = 64; } - else if (CPUCompileFlags.IsSet(InstructionSet_VectorT256)) + else if (m_CPUCompileFlags.IsSet(InstructionSet_VectorT256)) + { + g_vectorTByteLength = 32; + } + else if (m_CPUCompileFlags.IsSet(InstructionSet_VectorT128)) { - length = 32; + g_vectorTByteLength = 16; } #elif defined(TARGET_ARM64) - if (UseScalableVectorT()) + if (m_CPUCompileFlags.IsSet(InstructionSet_VectorT128)) { - size = (uint32_t) GetSveLengthFromOS(); + g_vectorTByteLength = 16; } - else if (m_CPUCompileFlags.IsSet(InstructionSet_VectorT128)) + + if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_JitUseScalableVectorT) + && m_CPUCompileFlags.IsSet(InstructionSet_Sve_Arm64)) { - size = 16; + uint64_t sveLengthFromOS = GetSveLengthFromOS(); + if (sveLengthFromOS != 0) + { + g_vectorTIsScalable = true; + g_vectorTByteLength = static_cast(sveLengthFromOS); + } } #endif - - return size; } // Define some data that we can use to get a better idea of what happened when we get a Watson dump that indicates the JIT failed to load. diff --git a/src/coreclr/vm/codeman.h b/src/coreclr/vm/codeman.h index 8d82253409c2a7..f65b3af8c0077e 100644 --- a/src/coreclr/vm/codeman.h +++ b/src/coreclr/vm/codeman.h @@ -2188,20 +2188,6 @@ class EEJitManager final : public EECodeGenManager return m_CPUCompileFlags; } - inline bool UseScalableVectorT() - { - LIMITED_METHOD_CONTRACT; -#ifdef TARGET_ARM64 - // Vector length discovery is currently dependent on running directly on Arm64. - return CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_JitUseScalableVectorT) - && m_CPUCompileFlags.IsSet(InstructionSet_Sve_Arm64); -#else - return false; -#endif - } - - uint32_t GetSizeOfVectorT(); - private : Crst m_JitLoadLock; @@ -2239,6 +2225,9 @@ private : bool m_AltJITRequired; #endif //ALLOW_SXS_JIT + uint32_t m_vectorTByteLength; + bool m_useScalableVectorT; + friend struct ::cdac_data; }; diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.inc b/src/coreclr/vm/datadescriptor/datadescriptor.inc index e84411a6fc338b..445ce1c648b2f2 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -1028,6 +1028,8 @@ CDAC_GLOBAL(PtrArrayOffsetToDataArray, uintptr_t, offsetof(PtrArray, m_Array)) CDAC_GLOBAL(NumberOfTlsOffsetsNotUsedInNoncollectibleArray, uint8, NUMBER_OF_TLSOFFSETS_NOT_USED_IN_NONCOLLECTIBLE_ARRAY) CDAC_GLOBAL(MaxClrNotificationArgs, uint32, MAX_CLR_NOTIFICATION_ARGS) CDAC_GLOBAL(FieldOffsetBigRVA, uint32, FIELD_OFFSET_BIG_RVA) +CDAC_GLOBAL_POINTER(VectorTByteLength, &::g_vectorTByteLength) +CDAC_GLOBAL_POINTER(VectorTIsScalable, &::g_vectorTIsScalable) CDAC_GLOBAL_POINTER(ClrNotificationArguments, &::g_clrNotificationArguments) CDAC_GLOBAL_POINTER(ArrayBoundsZero, cdac_data::ArrayBoundsZero) CDAC_GLOBAL_POINTER(ExceptionMethodTable, &::g_pExceptionClass) diff --git a/src/coreclr/vm/methodtablebuilder.cpp b/src/coreclr/vm/methodtablebuilder.cpp index 7d9634e6dd2181..3b6707d31aead9 100644 --- a/src/coreclr/vm/methodtablebuilder.cpp +++ b/src/coreclr/vm/methodtablebuilder.cpp @@ -1185,7 +1185,7 @@ BOOL MethodTableBuilder::CheckIfSIMDAndUpdateSize() if (strcmp(className, "Vector`1") != 0 || strcmp(nameSpace, "System.Numerics") != 0) return false; - uint32_t vectorTSize = ExecutionManager::GetEEJitManager()->GetSizeOfVectorT(); + uint32_t vectorTSize = g_vectorTByteLength; if (vectorTSize > 0 && vectorTSize != 16) { diff --git a/src/coreclr/vm/vars.cpp b/src/coreclr/vm/vars.cpp index c5546edcb2c487..39510667c9a050 100644 --- a/src/coreclr/vm/vars.cpp +++ b/src/coreclr/vm/vars.cpp @@ -101,6 +101,8 @@ GVAL_IMPL_INIT(DWORD, g_debuggerWordTLSIndex, TLS_OUT_OF_INDEXES); GVAL_IMPL_INIT(DWORD, g_TlsIndex, TLS_OUT_OF_INDEXES); GVAL_IMPL_INIT(DWORD, g_offsetOfCurrentThreadInfo, 0); GVAL_IMPL_INIT(DWORD, g_gcNotificationFlags, 0); +GVAL_IMPL_INIT(DWORD, g_vectorTByteLength, 0); +GVAL_IMPL_INIT(BOOL, g_vectorTIsScalable, 0); MethodTable* g_pCastHelpers; diff --git a/src/coreclr/vm/vars.hpp b/src/coreclr/vm/vars.hpp index 08988b342e784b..a57d8cd0177168 100644 --- a/src/coreclr/vm/vars.hpp +++ b/src/coreclr/vm/vars.hpp @@ -364,6 +364,8 @@ GVAL_DECL(DWORD, g_debuggerWordTLSIndex); GVAL_DECL(DWORD, g_TlsIndex); GVAL_DECL(DWORD, g_offsetOfCurrentThreadInfo); GVAL_DECL(DWORD, g_gcNotificationFlags); +GVAL_DECL(DWORD, g_vectorTByteLength); +GVAL_DECL(BOOL, g_vectorTIsScalable); #ifdef FEATURE_EH_FUNCLETS GPTR_DECL(MethodTable, g_pEHClass); From ab63432e35df4797bcf581ca0322235971380b27 Mon Sep 17 00:00:00 2001 From: Sebastian Nickolls Date: Wed, 5 Nov 2025 14:34:48 +0000 Subject: [PATCH 09/12] Fix DAC compilation and implement edit to genTypeSize table for TYP_SIMDSV --- src/coreclr/inc/dacvars.h | 2 - src/coreclr/jit/assertionprop.cpp | 2 +- src/coreclr/jit/async.cpp | 4 +- src/coreclr/jit/codegenarm64.cpp | 4 +- src/coreclr/jit/codegencommon.cpp | 21 +- src/coreclr/jit/codegenlinear.cpp | 4 +- src/coreclr/jit/compiler.cpp | 65 ++-- src/coreclr/jit/compiler.h | 26 +- src/coreclr/jit/compiler.hpp | 12 +- src/coreclr/jit/fgdiagnostic.cpp | 4 +- src/coreclr/jit/gcencode.cpp | 2 +- src/coreclr/jit/gentree.cpp | 213 ++++++------- src/coreclr/jit/gentree.h | 6 +- src/coreclr/jit/hwintrinsic.cpp | 35 ++- src/coreclr/jit/hwintrinsicarm64.cpp | 8 +- src/coreclr/jit/hwintrinsiccodegenarm64.cpp | 2 +- src/coreclr/jit/importer.cpp | 12 +- src/coreclr/jit/importercalls.cpp | 2 +- src/coreclr/jit/inductionvariableopts.cpp | 2 +- src/coreclr/jit/lclmorph.cpp | 30 +- src/coreclr/jit/lclvars.cpp | 59 ++-- src/coreclr/jit/lower.cpp | 124 ++++---- src/coreclr/jit/lowerarmarch.cpp | 2 +- src/coreclr/jit/lowerxarch.cpp | 10 +- src/coreclr/jit/lsraarm64.cpp | 2 +- src/coreclr/jit/morph.cpp | 8 +- src/coreclr/jit/morphblock.cpp | 14 +- src/coreclr/jit/optimizer.cpp | 2 +- src/coreclr/jit/promotion.cpp | 80 +++-- src/coreclr/jit/promotion.h | 8 +- src/coreclr/jit/promotiondecomposition.cpp | 27 +- src/coreclr/jit/promotionliveness.cpp | 20 +- src/coreclr/jit/regset.cpp | 4 +- src/coreclr/jit/simd.cpp | 288 +++++++++++++++++- src/coreclr/jit/targetarm64.cpp | 8 +- src/coreclr/jit/valuenum.cpp | 103 +++---- src/coreclr/jit/valuenum.h | 4 - src/coreclr/vm/callingconvention.h | 2 +- src/coreclr/vm/class.cpp | 4 +- src/coreclr/vm/classlayoutinfo.cpp | 2 +- src/coreclr/vm/codeman.cpp | 36 --- src/coreclr/vm/codeman.h | 21 +- .../vm/datadescriptor/datadescriptor.inc | 2 - src/coreclr/vm/methodtablebuilder.cpp | 28 +- src/coreclr/vm/vars.cpp | 2 - src/coreclr/vm/vars.hpp | 2 - 46 files changed, 761 insertions(+), 557 deletions(-) diff --git a/src/coreclr/inc/dacvars.h b/src/coreclr/inc/dacvars.h index 6dd56de621bf28..0be37f0098163a 100644 --- a/src/coreclr/inc/dacvars.h +++ b/src/coreclr/inc/dacvars.h @@ -134,8 +134,6 @@ DEFINE_DACVAR(PTR_JITNotification, dac__g_pNotificationTable, ::g_pNotificationT DEFINE_DACVAR(ULONG32, dac__g_dacNotificationFlags, ::g_dacNotificationFlags) DEFINE_DACVAR(DWORD, dac__g_gcNotificationFlags, g_gcNotificationFlags) -DEFINE_DACVAR(DWORD, dac__g_vectorTByteLength, ::g_vectorTByteLength) -DEFINE_DACVAR(BOOL, dac__g_vectorTIsScalable, ::g_vectorTIsScalable) DEFINE_DACVAR(PTR_EEConfig, dac__g_pConfig, ::g_pConfig) diff --git a/src/coreclr/jit/assertionprop.cpp b/src/coreclr/jit/assertionprop.cpp index a4cc3a738855b8..c4d832dd39d57f 100644 --- a/src/coreclr/jit/assertionprop.cpp +++ b/src/coreclr/jit/assertionprop.cpp @@ -2471,7 +2471,7 @@ GenTree* Compiler::optVNBasedFoldExpr_Call_Memset(GenTreeCall* call) CallArg* valArg = call->gtArgs.GetUserArgByIndex(2); var_types valType = valArg->GetSignatureType(); - unsigned lengthScale = getSizeOfType(valType); + unsigned lengthScale = genTypeSize(valType); if (lengthScale == 1) { diff --git a/src/coreclr/jit/async.cpp b/src/coreclr/jit/async.cpp index e0b6fa38a2f9bb..4d43458c89e569 100644 --- a/src/coreclr/jit/async.cpp +++ b/src/coreclr/jit/async.cpp @@ -1058,7 +1058,7 @@ ContinuationLayout AsyncTransformation::LayOutContinuation(BasicBlock* assert(!dsc->TypeIs(TYP_BYREF)); inf.Alignment = genTypeAlignments[dsc->TypeGet()]; - inf.Size = m_comp->getSizeOfType(dsc->TypeGet()); + inf.Size = genTypeSize(dsc); } } @@ -1090,7 +1090,7 @@ ContinuationLayout AsyncTransformation::LayOutContinuation(BasicBlock* } else { - layout.ReturnSize = m_comp->getSizeOfType(call->gtReturnType); + layout.ReturnSize = genTypeSize(call->gtReturnType); layout.ReturnAlignment = layout.ReturnSize; } diff --git a/src/coreclr/jit/codegenarm64.cpp b/src/coreclr/jit/codegenarm64.cpp index b18a9871a4cd9d..e091061c1fcbd3 100644 --- a/src/coreclr/jit/codegenarm64.cpp +++ b/src/coreclr/jit/codegenarm64.cpp @@ -366,7 +366,7 @@ bool CodeGen::genInstrWithConstant(instruction ins, case INS_sve_str: { assert(size == EA_SCALABLE); - ssize_t count = imm / compiler->getSizeOfType(TYP_SIMDSV); + ssize_t count = imm / genTypeSize(TYP_SIMDSV); immFitsInIns = (-256 <= count && count < 256); } break; @@ -3007,7 +3007,7 @@ void CodeGen::genSimpleReturn(GenTree* treeNode) var_types op1Type = genActualType(op1->TypeGet()); var_types lclType = genActualType(varDsc->TypeGet()); - if (compiler->getSizeOfType(op1Type) < compiler->getSizeOfType(lclType)) + if (genTypeSize(op1Type) < genTypeSize(lclType)) { movRequired = true; } diff --git a/src/coreclr/jit/codegencommon.cpp b/src/coreclr/jit/codegencommon.cpp index 6ccca634ae928c..a7117310ef79cf 100644 --- a/src/coreclr/jit/codegencommon.cpp +++ b/src/coreclr/jit/codegencommon.cpp @@ -2850,13 +2850,13 @@ class RegGraph for (RegNodeEdge* incoming = regNode->incoming; incoming != nullptr; incoming = incoming->nextIncoming) { unsigned destStart = incoming->destOffset; - unsigned destEnd = destStart + m_comp->getSizeOfType(incoming->type); + unsigned destEnd = destStart + genTypeSize(incoming->type); for (RegNodeEdge* otherIncoming = incoming->nextIncoming; otherIncoming != nullptr; otherIncoming = otherIncoming->nextIncoming) { unsigned otherDestStart = otherIncoming->destOffset; - unsigned otherDestEnd = otherDestStart + m_comp->getSizeOfType(otherIncoming->type); + unsigned otherDestEnd = otherDestStart + genTypeSize(otherIncoming->type); if (otherDestEnd <= destStart) { continue; @@ -2972,8 +2972,7 @@ void CodeGen::genSpillOrAddRegisterParam( LclVarDsc* paramVarDsc = compiler->lvaGetDesc(paramLclNum); var_types storeType = genParamStackType(paramVarDsc, segment); - if (!varDsc->TypeIs(TYP_STRUCT) && - (compiler->getSizeOfType(genActualType(varDsc)) < compiler->getSizeOfType(storeType))) + if (!varDsc->TypeIs(TYP_STRUCT) && (genTypeSize(genActualType(varDsc)) < genTypeSize(storeType))) { // Can happen for struct fields due to padding. storeType = genActualType(varDsc); @@ -2992,7 +2991,7 @@ void CodeGen::genSpillOrAddRegisterParam( // Some parameters can be passed in multiple registers but enregistered // in a single one (e.g. SIMD types on arm64). In this case the edges // we add here represent insertions of each element. - if (segment.Size < compiler->getSizeOfType(edgeType)) + if (segment.Size < genTypeSize(edgeType)) { edgeType = segment.GetRegisterType(); } @@ -3269,7 +3268,7 @@ void CodeGen::genHomeRegisterParams(regNumber initReg, bool* initRegStillZeroed) // registers while we can enregister them as single registers. // TODO-SVE: Ensure this works for Z registers as well. GetEmitter()->emitIns_R_R_I_I(INS_mov, emitTypeSize(edge->type), node->reg, sourceReg, - edge->destOffset / compiler->getSizeOfType(edge->type), 0); + edge->destOffset / genTypeSize(edge->type), 0); #elif defined(UNIX_AMD64_ABI) // For SysV x64 the only insertions we should have is to offset 8, // which happens for example for Vector3 which can be passed in @@ -3528,7 +3527,7 @@ void CodeGen::genCheckUseBlockInit() else { // Var is partially enregistered - noway_assert(compiler->getSizeOfType(varDsc->TypeGet()) > sizeof(int) && + noway_assert(genTypeSize(varDsc->TypeGet()) > sizeof(int) && varDsc->GetOtherReg() == REG_STK); initStkLclCnt += genTypeStSz(TYP_INT); counted = true; @@ -3829,7 +3828,7 @@ void CodeGen::genZeroInitFrame(int untrLclHi, int untrLclLo, regNumber initReg, compiler->opts.compDbgCode); if (varDsc->TypeIs(TYP_STRUCT) && !compiler->info.compInitMem && - (compiler->lvaLclExactSize(varDsc) >= TARGET_POINTER_SIZE)) + (varDsc->lvExactSize() >= TARGET_POINTER_SIZE)) { // We only initialize the GC variables in the TYP_STRUCT const unsigned slots = (unsigned)compiler->lvaLclStackHomeSize(varNum) / REGSIZE_BYTES; @@ -5908,7 +5907,7 @@ unsigned Compiler::GetHfaCount(CORINFO_CLASS_HANDLE hClass) var_types hfaType = GetHfaType(hClass); unsigned classSize = info.compCompHnd->getClassSize(hClass); // Note that the retail build issues a warning about a potential division by zero without the Max function - unsigned elemSize = Max((unsigned)1, getSizeOfType(genActualType(hfaType))); + unsigned elemSize = Max((unsigned)1, genTypeSize(genActualType(hfaType))); return classSize / elemSize; #endif // TARGET_ARM64 } @@ -7181,7 +7180,7 @@ void CodeGen::genStructReturn(GenTree* treeNode) #endif GetEmitter()->emitIns_R_S(ins_Load(type), emitTypeSize(type), toReg, lclNode->GetLclNum(), offset); - offset += compiler->getSizeOfType(type); + offset += genTypeSize(type); } #endif // !TARGET_LOONGARCH64 && !TARGET_RISCV64 } @@ -7581,7 +7580,7 @@ void CodeGen::genMultiRegStoreToLocal(GenTreeLclVar* lclNode) // It could rewrite memory outside of the fields but local on the stack are rounded to POINTER_SIZE so // it is safe to store a long register into a byte field as it is known that we have enough padding after. GetEmitter()->emitIns_S_R(ins_Store(srcType), emitTypeSize(srcType), reg, lclNum, offset); - offset += compiler->getSizeOfType(srcType); + offset += genTypeSize(srcType); #ifdef DEBUG unsigned stackHomeSize = compiler->lvaLclStackHomeSize(lclNum); diff --git a/src/coreclr/jit/codegenlinear.cpp b/src/coreclr/jit/codegenlinear.cpp index 875794610309cf..c33beea3ea46be 100644 --- a/src/coreclr/jit/codegenlinear.cpp +++ b/src/coreclr/jit/codegenlinear.cpp @@ -1880,7 +1880,7 @@ void CodeGen::genPutArgStkFieldList(GenTreePutArgStk* putArgStk, unsigned outArg } #endif - assert((thisFieldOffset + compiler->getSizeOfType(type)) <= areaSize); + assert((thisFieldOffset + genTypeSize(type)) <= areaSize); #endif } } @@ -2273,7 +2273,7 @@ void CodeGen::genCodeForCast(GenTreeOp* tree) else if (targetType == TYP_SIMDSV || tree->gtOp1->TypeGet() == TYP_SIMDSV) { // TODO-SVE: Can we avoid generating these casts altogether? - assert(compiler->getSizeOfType(tree->CastToType()) == compiler->getSizeOfType(tree->CastFromType())); + assert(genTypeSize(tree->CastToType()) == genTypeSize(tree->CastFromType())); genConsumeOperands(tree); inst_Mov(tree->CastToType(), tree->GetRegNum(), tree->gtOp1->GetRegNum(), true); genProduceReg(tree); diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index 4e1342ea104e2a..592efec4d4b0da 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -107,11 +107,12 @@ inline bool _our_GetThreadCycles(uint64_t* cycleOut) #endif // which host OS -const BYTE genTypeSizes[] = { +BYTE _initGenTypeSizes[] = { #define DEF_TP(tn, nm, jitType, sz, sze, asze, st, al, regTyp, regFld, csr, ctr, tf) sz, #include "typelist.h" #undef DEF_TP }; +const BYTE (&genTypeSizes)[TYP_COUNT] = _initGenTypeSizes; const BYTE genTypeAlignments[] = { #define DEF_TP(tn, nm, jitType, sz, sze, asze, st, al, regTyp, regFld, csr, ctr, tf) al, @@ -614,7 +615,7 @@ var_types Compiler::getPrimitiveTypeForStruct(unsigned structSize, CORINFO_CLASS #ifdef TARGET_ARM64 // Can pass in V register if structSize == 16, and Z registers for structs with sizes in // multiples of 16-bytes, depending on hardware availability. - || structSize == 16 || ((structSize % 16 == 0) && (structSize == getSizeOfType(TYP_SIMDSV))) + || structSize == 16 || ((structSize % 16 == 0) && (structSize == genTypeSize(TYP_SIMDSV))) #endif ) { @@ -622,17 +623,21 @@ var_types Compiler::getPrimitiveTypeForStruct(unsigned structSize, CORINFO_CLASS // We're only interested in the case where the struct size is equal to the size of the hfaType. if (varTypeIsValidHfaType(hfaType)) { - if (getSizeOfType(hfaType) == structSize) + var_types hfaType = GetHfaType(clsHnd); + // We're only interested in the case where the struct size is equal to the size of the hfaType. + if (varTypeIsValidHfaType(hfaType)) { - useType = hfaType; - } - else - { - return TYP_UNKNOWN; + if (genTypeSize(hfaType) == structSize) + { + useType = hfaType; + } + else + { + return TYP_UNKNOWN; + } } } } - if (useType != TYP_UNKNOWN) { return useType; @@ -881,7 +886,7 @@ var_types Compiler::getReturnTypeForStruct(CORINFO_CLASS_HANDLE clsHnd, if (useType != TYP_UNKNOWN) { - if (structSize == getSizeOfType(useType)) + if (structSize == genTypeSize(useType)) { // Currently: 1, 2, 4, or 8 byte structs howToReturnStruct = SPK_PrimitiveType; @@ -7093,6 +7098,14 @@ int Compiler::compCompileHelper(CORINFO_MODULE_HANDLE classPtr, } #endif +#if defined(FEATURE_SIMD) && defined(TARGET_ARM64) + // Initialize the size of Vector from the EE. + _initGenTypeSizes[TYP_SIMDSV] = getVectorTByteLength(); + _initGenTypeSizes[TYP_MASK] = getMaskByteLength(); + assert(genTypeSize(TYP_SIMDSV) >= 16); + assert(genTypeSize(TYP_MASK) >= 2); +#endif + compCompile(methodCodePtr, methodCodeSize, compileFlags); #ifdef DEBUG @@ -10893,35 +10906,3 @@ void Compiler::EnregisterStats::Dump(FILE* fout) const PRINT_STATS(m_externallyVisibleImplicitly, m_addrExposed); } #endif // TRACK_ENREG_STATS - -// Get the size of a JIT internal type. -// -// This function will resolve the size of types that aren't necessarily determinable -// from a static context, for example ARM64 scalable vector types. For primitive types -// and types that are obviously fixed size, use genTypeSize instead. -unsigned Compiler::getSizeOfType(var_types type) -{ -#ifdef FEATURE_SIMD - if (varTypeIsSIMD(type)) - { - return getSizeOfSIMDType(type); - } -#endif - -#if defined(FEATURE_MASKED_HW_INTRINSICS) && defined(TARGET_ARM64) - if (type == TYP_MASK) - { - // A predicate register has a bit for each byte in the vector register. - // We need to overallocate for 128-bit VL because the JIT makes assumptions - // about types being larger than an integer at the moment. - return roundUp((size_t)(getVectorTByteLength() / 8), sizeof(int)); - } -#endif - - return genTypeSize(type); -} - -unsigned Compiler::getSizeOfType(GenTree* tree) -{ - return getSizeOfType(tree->TypeGet()); -} diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 9a59623e25d872..05f97d4b14fcd9 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -988,6 +988,8 @@ class LclVarDsc lvStkOffs = offset; } + unsigned lvExactSize() const; + unsigned lvSlotNum; // original slot # (if remapped) // class handle for the local or null if not known or not a class @@ -3639,8 +3641,6 @@ class Compiler void gtGetLclFldNodeCost(GenTreeLclFld* node, int* pCostEx, int* pCostSz); bool gtGetIndNodeCost(GenTreeIndir* node, int* pCostEx, int* pCostSz); - unsigned gtGetSizeOfIndirection(GenTreeIndir* indir); - // Returns true iff the secondNode can be swapped with firstNode. bool gtCanSwapOrder(GenTree* firstNode, GenTree* secondNode); @@ -4188,7 +4188,6 @@ class Compiler unsigned lvaLclStackHomeSize(unsigned varNum); unsigned lvaLclExactSize(unsigned varNum); - unsigned lvaLclExactSize(const LclVarDsc* varDsc); bool lvaHaveManyLocals(float percent = 1.0f) const; @@ -9088,10 +9087,6 @@ class Compiler return isSIMDClass(clsHnd) || isHWSIMDClass(clsHnd); } - var_types getSIMDType(CORINFO_CLASS_HANDLE typeHnd, CorInfoType* baseType = nullptr); - - unsigned getSizeOfSIMDType(var_types simdType); - // Get the base (element) type and size in bytes for a SIMD type. Returns CORINFO_TYPE_UNDEF // if it is not a SIMD type or is an unsupported base JIT type. CorInfoType getBaseJitTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeHnd, unsigned* sizeBytes = nullptr); @@ -9177,6 +9172,16 @@ class Compiler #endif } +#ifdef TARGET_ARM64 + uint32_t getMaskByteLength() + { + // Predicate registers have 1 bit for each byte in the vector register. + // We round up to an int as the CLR prefers to work in integers. + assert((getVectorTByteLength() % 8) == 0); + return (uint32_t)roundUp((size_t)getVectorTByteLength() / 8, sizeof(int)); + } +#endif + // The minimum and maximum possible number of bytes in a SIMD vector. // getMaxVectorByteLength @@ -9439,9 +9444,6 @@ class Compiler return result; } - unsigned getSizeOfType(var_types type); - unsigned getSizeOfType(GenTree* tree); - enum UnrollKind { Memset, @@ -10659,8 +10661,6 @@ class Compiler } #endif // !DEBUG - unsigned GetReturnFieldOffset(const ReturnTypeDesc& retDesc, unsigned index); - ReturnTypeDesc compRetTypeDesc; // ABI return type descriptor for the method //------------------------------------------------------------------------ @@ -12425,7 +12425,7 @@ const instruction INS_BREAKPOINT = INS_ebreak; /*****************************************************************************/ -extern const BYTE genTypeSizes[]; +extern const BYTE (&genTypeSizes)[TYP_COUNT]; extern const BYTE genTypeAlignments[]; extern const BYTE genTypeStSzs[]; extern const BYTE genActualTypes[]; diff --git a/src/coreclr/jit/compiler.hpp b/src/coreclr/jit/compiler.hpp index b0021a352ce182..5c9c38c7be13a6 100644 --- a/src/coreclr/jit/compiler.hpp +++ b/src/coreclr/jit/compiler.hpp @@ -1137,18 +1137,12 @@ inline regNumber genFirstRegNumFromMaskAndToggle(SingleTypeRegSet& mask) * Return the size in bytes of the given type. */ -extern const BYTE genTypeSizes[TYP_COUNT]; +extern const BYTE (&genTypeSizes)[TYP_COUNT]; template inline unsigned genTypeSize(T value) { -#ifdef TARGET_ARM64 - // The size of these types cannot be evaluated in static contexts. - noway_assert(TypeGet(value) != TYP_SIMDSV); - noway_assert(TypeGet(value) != TYP_MASK); -#endif assert((unsigned)TypeGet(value) < ArrLen(genTypeSizes)); - return genTypeSizes[TypeGet(value)]; } @@ -1714,7 +1708,7 @@ inline GenTreeIndexAddr* Compiler::gtNewIndexAddr(GenTree* arrayOp, unsigned lengthOffset) { unsigned elemSize = - (elemType == TYP_STRUCT) ? info.compCompHnd->getClassSize(elemClassHandle) : getSizeOfType(elemType); + (elemType == TYP_STRUCT) ? info.compCompHnd->getClassSize(elemClassHandle) : genTypeSize(elemType); #ifdef DEBUG bool boundsCheck = JitConfig.JitSkipArrayBoundCheck() != 1; @@ -4709,7 +4703,7 @@ GenTree::VisitResult GenTree::VisitLocalDefs(Compiler* comp, TVisitor visitor) if (OperIs(GT_STORE_LCL_FLD)) { GenTreeLclFld* fld = AsLclFld(); - return visitor(LocalDef(fld, !fld->IsPartialLclFld(comp), fld->GetLclOffs(), fld->GetSize(comp))); + return visitor(LocalDef(fld, !fld->IsPartialLclFld(comp), fld->GetLclOffs(), fld->GetSize())); } if (OperIs(GT_CALL)) { diff --git a/src/coreclr/jit/fgdiagnostic.cpp b/src/coreclr/jit/fgdiagnostic.cpp index 023eef785a67ca..602612767a2567 100644 --- a/src/coreclr/jit/fgdiagnostic.cpp +++ b/src/coreclr/jit/fgdiagnostic.cpp @@ -4299,8 +4299,8 @@ class SsaCheckVisitor : public GenTreeVisitor { ProcessDef(def.Def, fieldLclNum, fieldSsaNum); - if (!ValueNumStore::LoadStoreIsEntire(m_compiler->getSizeOfType(fieldVarDsc->TypeGet()), - fieldStoreOffset, fieldStoreSize)) + if (!ValueNumStore::LoadStoreIsEntire(genTypeSize(fieldVarDsc), fieldStoreOffset, + fieldStoreSize)) { assert(isUse); unsigned const fieldUseSsaNum = fieldVarDsc->GetPerSsaData(fieldSsaNum)->GetUseDefSsaNum(); diff --git a/src/coreclr/jit/gcencode.cpp b/src/coreclr/jit/gcencode.cpp index c1711253d5b403..2f4ad6c3322931 100644 --- a/src/coreclr/jit/gcencode.cpp +++ b/src/coreclr/jit/gcencode.cpp @@ -4250,7 +4250,7 @@ void GCInfo::gcMakeRegPtrTable( // If this is a TYP_STRUCT, handle its GC pointers. // Note that the enregisterable struct types cannot have GC pointers in them. if (varDsc->TypeIs(TYP_STRUCT) && varDsc->GetLayout()->HasGCPtr() && varDsc->lvOnFrame && - (compiler->lvaLclExactSize(varDsc) >= TARGET_POINTER_SIZE)) + (varDsc->lvExactSize() >= TARGET_POINTER_SIZE)) { ClassLayout* layout = varDsc->GetLayout(); unsigned slots = layout->GetSlotCount(); diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 6dc39a275e7233..79c4a5c2459a62 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -7996,7 +7996,7 @@ GenTreeVecCon* Compiler::gtNewVconNode(var_types type, void* data) { GenTreeVecCon* vecCon = new (this, GT_CNS_VEC) GenTreeVecCon(type); // TODO-SVE: Implement scalable vector constant - memcpy(&vecCon->gtSimdVal, data, getSizeOfType(type)); + memcpy(&vecCon->gtSimdVal, data, genTypeSize(type)); return vecCon; } #endif // FEATURE_SIMD @@ -8099,7 +8099,7 @@ GenTree* Compiler::gtNewOneConNode(var_types type, var_types simdBaseType /* = T { GenTreeVecCon* one = gtNewVconNode(type); - unsigned simdSize = max(getSizeOfType(type), (unsigned)sizeof(simd_t)); + unsigned simdSize = max(genTypeSize(type), (unsigned)sizeof(simd_t)); uint32_t simdLength = getSIMDVectorLength(simdSize, simdBaseType); switch (simdBaseType) @@ -17881,7 +17881,7 @@ bool GenTree::IsLclVarAddr() const bool GenTree::IsPartialLclFld(Compiler* comp) { return OperIs(GT_LCL_FLD, GT_STORE_LCL_FLD) && - (comp->lvaLclExactSize(comp->lvaGetDesc(AsLclFld())) != AsLclFld()->GetSize(comp)); + (comp->lvaGetDesc(AsLclFld())->lvExactSize() != AsLclFld()->GetSize()); } //------------------------------------------------------------------------ @@ -18193,18 +18193,10 @@ ssize_t GenTreeIndir::Offset() } } -// Compiler::gtGetSizeOfIndirection: Get the size associated with this indirection. -// -// Arguments: -// indir - Indirection to process -// -// Return Value: -// If the indirection is a block load or store, then it's the size of the block. -// Otherwise it's the size of the type of the indirection. -// -unsigned Compiler::gtGetSizeOfIndirection(GenTreeIndir* indir) +unsigned GenTreeIndir::Size() const { - return indir->OperIsBlk() ? indir->AsBlk()->Size() : getSizeOfType(indir->TypeGet()); + assert(isIndir() || OperIsBlk()); + return OperIsBlk() ? AsBlk()->Size() : genTypeSize(TypeGet()); } //------------------------------------------------------------------------ @@ -18622,11 +18614,7 @@ bool GenTreeVecCon::IsBroadcast(var_types simdBaseType) const assert(varTypeIsSIMD(gtType)); assert(varTypeIsArithmetic(simdBaseType)); -#ifdef TARGET_ARM64 - int elementCount = ElementCount(genTypeSize(gtType == TYP_SIMDSV ? TYP_SIMD16 : gtType), simdBaseType); -#else int elementCount = ElementCount(genTypeSize(gtType), simdBaseType); -#endif switch (simdBaseType) { @@ -18675,11 +18663,7 @@ bool GenTreeVecCon::IsBroadcast(var_types simdBaseType) const bool GenTreeVecCon::IsNaN(var_types simdBaseType) const { assert(varTypeIsFloating(simdBaseType)); -#ifdef TARGET_ARM64 - uint32_t elementCount = ElementCount(genTypeSize(gtType == TYP_SIMDSV ? TYP_SIMD16 : gtType), simdBaseType); -#else uint32_t elementCount = ElementCount(genTypeSize(gtType), simdBaseType); -#endif for (uint32_t i = 0; i < elementCount; i++) { @@ -18706,11 +18690,7 @@ bool GenTreeVecCon::IsNaN(var_types simdBaseType) const bool GenTreeVecCon::IsNegativeZero(var_types simdBaseType) const { assert(varTypeIsFloating(simdBaseType)); -#ifdef TARGET_ARM64 - uint32_t elementCount = ElementCount(genTypeSize(gtType == TYP_SIMDSV ? TYP_SIMD16 : gtType), simdBaseType); -#else uint32_t elementCount = ElementCount(genTypeSize(gtType), simdBaseType); -#endif for (uint32_t i = 0; i < elementCount; i++) { @@ -18894,7 +18874,7 @@ bool Compiler::gtStoreDefinesField( LclVarDsc* fieldVarDsc, ssize_t offset, unsigned size, ssize_t* pFieldStoreOffset, unsigned* pFieldStoreSize) { ssize_t fieldOffset = fieldVarDsc->lvFldOffset; - unsigned fieldSize = getSizeOfType(fieldVarDsc->TypeGet()); // No TYP_STRUCT field locals. + unsigned fieldSize = genTypeSize(fieldVarDsc); // No TYP_STRUCT field locals. ssize_t storeEndOffset = offset + static_cast(size); ssize_t fieldEndOffset = fieldOffset + static_cast(fieldSize); @@ -19647,7 +19627,7 @@ void GenTreeArrAddr::ParseArrayAddress(Compiler* comp, GenTree** pArr, ValueNum* } unsigned elemSizeUn = (GetElemType() == TYP_STRUCT) ? comp->typGetObjLayout(GetElemClassHandle())->GetSize() - : comp->getSizeOfType(GetElemType()); + : genTypeSize(GetElemType()); assert(FitsIn(elemSizeUn)); target_ssize_t elemSize = static_cast(elemSizeUn); @@ -20966,7 +20946,7 @@ GenTreeHWIntrinsic* Compiler::gtNewSimdHWIntrinsicNode(var_types ty GenTree* Compiler::gtNewSimdAbsNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(getSIMDTypeForSize(simdSize) == type); assert(op1 != nullptr); assert(op1->TypeGet() == type); @@ -21059,7 +21039,7 @@ GenTree* Compiler::gtNewSimdBinOpNode( genTreeOps op, var_types type, GenTree* op1, GenTree* op2, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(getSIMDTypeForSize(simdSize) == type); var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType); assert(varTypeIsArithmetic(simdBaseType)); @@ -21773,7 +21753,7 @@ GenTree* Compiler::gtNewSimdBinOpNode( GenTree* Compiler::gtNewSimdCeilNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(getSIMDTypeForSize(simdSize) == type); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -21853,7 +21833,7 @@ GenTree* Compiler::gtNewSimdCvtNode(var_types type, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(getSIMDTypeForSize(simdSize) == type); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -21989,7 +21969,7 @@ GenTree* Compiler::gtNewSimdCvtNativeNode(var_types type, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(getSIMDTypeForSize(simdSize) == type); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -22241,7 +22221,7 @@ GenTree* Compiler::gtNewSimdCmpOpNode( genTreeOps op, var_types type, GenTree* op1, GenTree* op2, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(getSIMDTypeForSize(simdSize) == type); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -22530,11 +22510,12 @@ GenTree* Compiler::gtNewSimdCmpOpAllNode( genTreeOps op, var_types type, GenTree* op1, GenTree* op2, CorInfoType simdBaseJitType, unsigned simdSize) { assert(type == TYP_INT); - assert(op1 != nullptr); - var_types simdType = op1->TypeGet(); + var_types simdType = getSIMDTypeForSize(simdSize); assert(varTypeIsSIMD(simdType)); - assert(getSizeOfSIMDType(simdType) == simdSize); + + assert(op1 != nullptr); + assert(op1->TypeIs(simdType)); assert(op2 != nullptr); assert(op2->TypeIs(simdType)); @@ -22664,10 +22645,11 @@ GenTree* Compiler::gtNewSimdCmpOpAnyNode( { assert(type == TYP_INT); - assert(op1 != nullptr); - var_types simdType = op1->TypeGet(); + var_types simdType = getSIMDTypeForSize(simdSize); assert(varTypeIsSIMD(simdType)); - assert(getSizeOfSIMDType(simdType) == simdSize); + + assert(op1 != nullptr); + assert(op1->TypeIs(simdType)); assert(op2 != nullptr); assert(op2->TypeIs(simdType)); @@ -22793,7 +22775,7 @@ GenTree* Compiler::gtNewSimdCndSelNode( var_types type, GenTree* op1, GenTree* op2, GenTree* op3, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(getSIMDTypeForSize(simdSize) == type); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -23218,7 +23200,7 @@ GenTree* Compiler::gtNewSimdCreateSequenceNode( // is constant than there isn't any real optimization we can do and we need the full computation. assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(getSIMDTypeForSize(simdSize) == type); var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType); assert(varTypeIsArithmetic(simdBaseType)); @@ -23389,14 +23371,14 @@ GenTree* Compiler::gtNewSimdCreateSequenceNode( GenTree* Compiler::gtNewSimdDotProdNode( var_types type, GenTree* op1, GenTree* op2, CorInfoType simdBaseJitType, unsigned simdSize) { - assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + var_types simdType = getSIMDTypeForSize(simdSize); + assert(varTypeIsSIMD(simdType)); assert(op1 != nullptr); - assert(op1->TypeIs(type)); + assert(op1->TypeIs(simdType)); assert(op2 != nullptr); - assert(op2->TypeIs(type)); + assert(op2->TypeIs(simdType)); var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType); assert(varTypeIsSIMD(type)); @@ -23430,7 +23412,7 @@ GenTree* Compiler::gtNewSimdDotProdNode( GenTree* Compiler::gtNewSimdFloorNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(getSIMDTypeForSize(simdSize) == type); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -23475,7 +23457,7 @@ GenTree* Compiler::gtNewSimdFmaNode( var_types type, GenTree* op1, GenTree* op2, GenTree* op3, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(getSIMDTypeForSize(simdSize) == type); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -23590,7 +23572,7 @@ GenTree* Compiler::gtNewSimdGetElementNode( GenTree* Compiler::gtNewSimdGetIndicesNode(var_types type, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(getSIMDTypeForSize(simdSize) == type); var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType); assert(varTypeIsArithmetic(simdBaseType)); @@ -23743,7 +23725,7 @@ GenTree* Compiler::gtNewSimdIsEvenIntegerNode(var_types type, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(getSIMDTypeForSize(simdSize) == type); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -23770,7 +23752,7 @@ GenTree* Compiler::gtNewSimdIsEvenIntegerNode(var_types type, GenTree* Compiler::gtNewSimdIsFiniteNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(getSIMDTypeForSize(simdSize) == type); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -23821,7 +23803,7 @@ GenTree* Compiler::gtNewSimdIsFiniteNode(var_types type, GenTree* op1, CorInfoTy GenTree* Compiler::gtNewSimdIsInfinityNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(getSIMDTypeForSize(simdSize) == type); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -23852,7 +23834,7 @@ GenTree* Compiler::gtNewSimdIsInfinityNode(var_types type, GenTree* op1, CorInfo GenTree* Compiler::gtNewSimdIsIntegerNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(getSIMDTypeForSize(simdSize) == type); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -23892,7 +23874,7 @@ GenTree* Compiler::gtNewSimdIsIntegerNode(var_types type, GenTree* op1, CorInfoT GenTree* Compiler::gtNewSimdIsNaNNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(getSIMDTypeForSize(simdSize) == type); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -23923,7 +23905,7 @@ GenTree* Compiler::gtNewSimdIsNaNNode(var_types type, GenTree* op1, CorInfoType GenTree* Compiler::gtNewSimdIsNegativeNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(getSIMDTypeForSize(simdSize) == type); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -23965,7 +23947,7 @@ GenTree* Compiler::gtNewSimdIsNegativeInfinityNode(var_types type, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(getSIMDTypeForSize(simdSize) == type); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -24013,7 +23995,7 @@ GenTree* Compiler::gtNewSimdIsNegativeInfinityNode(var_types type, GenTree* Compiler::gtNewSimdIsNormalNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(getSIMDTypeForSize(simdSize) == type); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -24076,7 +24058,7 @@ GenTree* Compiler::gtNewSimdIsOddIntegerNode(var_types type, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(getSIMDTypeForSize(simdSize) == type); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -24103,7 +24085,7 @@ GenTree* Compiler::gtNewSimdIsOddIntegerNode(var_types type, GenTree* Compiler::gtNewSimdIsPositiveNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(getSIMDTypeForSize(simdSize) == type); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -24145,7 +24127,7 @@ GenTree* Compiler::gtNewSimdIsPositiveInfinityNode(var_types type, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(getSIMDTypeForSize(simdSize) == type); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -24196,7 +24178,7 @@ GenTree* Compiler::gtNewSimdIsSubnormalNode(var_types type, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(getSIMDTypeForSize(simdSize) == type); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -24253,7 +24235,7 @@ GenTree* Compiler::gtNewSimdIsSubnormalNode(var_types type, GenTree* Compiler::gtNewSimdIsZeroNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(getSIMDTypeForSize(simdSize) == type); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -24279,7 +24261,7 @@ GenTree* Compiler::gtNewSimdIsZeroNode(var_types type, GenTree* op1, CorInfoType GenTree* Compiler::gtNewSimdLoadNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(getSIMDTypeForSize(simdSize) == type); assert(op1 != nullptr); @@ -24474,7 +24456,7 @@ GenTree* Compiler::gtNewSimdMinMaxNode(var_types type, else if (!varTypeIsLong(simdBaseType)) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(getSIMDTypeForSize(simdSize) == type); } NamedIntrinsic intrinsic = NI_Illegal; @@ -25116,7 +25098,7 @@ GenTree* Compiler::gtNewSimdMinMaxNativeNode( else { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(getSIMDTypeForSize(simdSize) == type); } NamedIntrinsic intrinsic = NI_Illegal; @@ -25229,7 +25211,7 @@ GenTree* Compiler::gtNewSimdNarrowNode( var_types type, GenTree* op1, GenTree* op2, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(getSIMDTypeForSize(simdSize) == type); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -25701,7 +25683,7 @@ GenTree* Compiler::gtNewSimdNarrowNode( GenTree* Compiler::gtNewSimdRoundNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(getSIMDTypeForSize(simdSize) == type); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -25762,7 +25744,7 @@ GenTree* Compiler::gtNewSimdShuffleVariableNode( var_types type, GenTree* op1, GenTree* op2, CorInfoType simdBaseJitType, unsigned simdSize, bool isShuffleNative) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(getSIMDTypeForSize(simdSize) == type); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -26365,7 +26347,7 @@ GenTree* Compiler::gtNewSimdShuffleNode( var_types type, GenTree* op1, GenTree* op2, CorInfoType simdBaseJitType, unsigned simdSize, bool isShuffleNative) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(getSIMDTypeForSize(simdSize) == type); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -26948,7 +26930,7 @@ GenTree* Compiler::gtNewSimdShuffleNode( GenTree* Compiler::gtNewSimdSqrtNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(getSIMDTypeForSize(simdSize) == type); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -27006,7 +26988,7 @@ GenTree* Compiler::gtNewSimdStoreNode(GenTree* op1, GenTree* op2, CorInfoType si assert(op2 != nullptr); assert(varTypeIsSIMD(op2)); - assert(getSizeOfSIMDType(op2->TypeGet()) == simdSize); + assert(getSIMDTypeForSize(simdSize) == op2->TypeGet()); var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType); assert(varTypeIsArithmetic(simdBaseType)); @@ -27123,10 +27105,11 @@ GenTree* Compiler::gtNewSimdStoreNonTemporalNode(GenTree* op1, GenTree* Compiler::gtNewSimdSumNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { - assert(op1 != nullptr); - var_types simdType = op1->TypeGet(); + var_types simdType = getSIMDTypeForSize(simdSize); assert(varTypeIsSIMD(simdType)); - assert(getSizeOfSIMDType(simdType) == simdSize); + + assert(op1 != nullptr); + assert(op1->TypeIs(simdType)); var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType); assert(varTypeIsArithmetic(simdBaseType)); @@ -27454,7 +27437,7 @@ GenTree* Compiler::gtNewSimdToScalarNode(var_types type, GenTree* op1, CorInfoTy GenTree* Compiler::gtNewSimdTruncNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(getSIMDTypeForSize(simdSize) == type); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -27499,7 +27482,7 @@ GenTree* Compiler::gtNewSimdUnOpNode( genTreeOps op, var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(getSIMDTypeForSize(simdSize) == type); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -27594,7 +27577,7 @@ GenTree* Compiler::gtNewSimdUnOpNode( GenTree* Compiler::gtNewSimdWidenLowerNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(getSIMDTypeForSize(simdSize) == type); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -27796,7 +27779,7 @@ GenTree* Compiler::gtNewSimdWidenLowerNode(var_types type, GenTree* op1, CorInfo GenTree* Compiler::gtNewSimdWidenUpperNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(getSIMDTypeForSize(simdSize) == type); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -28088,7 +28071,7 @@ GenTreeFieldList* Compiler::gtConvertTableOpToFieldList(GenTree* op, unsigned fi { unsigned lclNum = op->AsLclVar()->GetLclNum(); LclVarDsc* opVarDsc = lvaGetDesc(lclNum); - unsigned fieldSize = lvaLclExactSize(opVarDsc) / fieldCount; + unsigned fieldSize = opVarDsc->lvExactSize() / fieldCount; var_types fieldType = Compiler::getSIMDTypeForSize(fieldSize); GenTreeFieldList* fieldList = new (this, GT_FIELD_LIST) GenTreeFieldList(); @@ -28119,18 +28102,18 @@ GenTreeFieldList* Compiler::gtConvertParamOpToFieldList(GenTree* op, unsigned fi { unsigned lclNum = op->AsLclVar()->GetLclNum(); LclVarDsc* opVarDsc = lvaGetDesc(lclNum); - unsigned fieldSize = lvaLclExactSize(opVarDsc) / fieldCount; + unsigned fieldSize = opVarDsc->lvExactSize() / fieldCount; GenTreeFieldList* fieldList = new (this, GT_FIELD_LIST) GenTreeFieldList(); int offset = 0; + unsigned sizeBytes = 0; CORINFO_CLASS_HANDLE structType; for (unsigned fieldId = 0; fieldId < fieldCount; fieldId++) { CORINFO_FIELD_HANDLE fieldHandle = info.compCompHnd->getFieldInClass(clsHnd, fieldId); JitType2PreciseVarType(info.compCompHnd->getFieldType(fieldHandle, &structType)); - - unsigned int size = info.compCompHnd->getClassSize(structType); - var_types simdType = getSIMDTypeForSize(size); + getBaseJitTypeAndSizeOfSIMDType(structType, &sizeBytes); + var_types simdType = getSIMDTypeForSize(sizeBytes); GenTreeLclFld* fldNode = gtNewLclFldNode(lclNum, simdType, offset); fieldList->AddField(this, fldNode, offset, simdType); @@ -29670,8 +29653,10 @@ genTreeOps GenTreeHWIntrinsic::GetOperForHWIntrinsicId(NamedIntrinsic id, var_ty NamedIntrinsic GenTreeHWIntrinsic::GetHWIntrinsicIdForUnOp( Compiler* comp, genTreeOps oper, GenTree* op1, var_types simdBaseType, unsigned simdSize, bool isScalar) { + var_types simdType = comp->getSIMDTypeForSize(simdSize); assert(varTypeIsArithmetic(simdBaseType)); + assert(varTypeIsSIMD(simdType)); #if defined(TARGET_XARCH) if ((simdSize == 64) || (simdSize == 32)) @@ -29689,9 +29674,7 @@ NamedIntrinsic GenTreeHWIntrinsic::GetHWIntrinsicIdForUnOp( } assert(op1 != nullptr); - var_types simdType = op1->TypeGet(); - assert(varTypeIsSIMD(simdType)); - assert(comp->getSizeOfSIMDType(simdType) == simdSize); + assert(op1->TypeIs(simdType)); NamedIntrinsic id = NI_Illegal; @@ -29764,12 +29747,13 @@ NamedIntrinsic GenTreeHWIntrinsic::GetHWIntrinsicIdForBinOp(Compiler* comp, unsigned simdSize, bool isScalar) { + var_types simdType = comp->getSIMDTypeForSize(simdSize); + assert(varTypeIsArithmetic(simdBaseType)); + assert(varTypeIsSIMD(simdType)); assert(op1 != nullptr); - var_types simdType = op1->TypeGet(); - assert(varTypeIsSIMD(simdType)); - assert(comp->getSizeOfSIMDType(simdType) == simdSize); + assert(op1->TypeIs(simdType)); assert(op2 != nullptr); #if defined(TARGET_XARCH) @@ -30337,14 +30321,16 @@ NamedIntrinsic GenTreeHWIntrinsic::GetHWIntrinsicIdForCmpOp(Compiler* comp, bool isScalar, bool reverseCond) { - assert(op1 != nullptr); - assert(op2 != nullptr); - var_types simdType = op1->TypeGet(); - assert(comp->getSizeOfSIMDType(simdType) == simdSize); + var_types simdType = comp->getSIMDTypeForSize(simdSize); assert(varTypeIsMask(type) || (type == simdType)); + assert(varTypeIsArithmetic(simdBaseType)); assert(varTypeIsSIMD(simdType)); + assert(op1 != nullptr); + assert(op1->TypeIs(simdType)); + assert(op2 != nullptr); + #if defined(TARGET_XARCH) if (varTypeIsMask(type)) { @@ -30676,9 +30662,11 @@ NamedIntrinsic GenTreeHWIntrinsic::GetHWIntrinsicIdForCmpOp(Compiler* comp, var_types GenTreeHWIntrinsic::GetLookupTypeForCmpOp( Compiler* comp, genTreeOps oper, var_types type, var_types simdBaseType, unsigned simdSize, bool reverseCond) { - assert(varTypeIsMask(type) || varTypeIsSIMD(type)); + var_types simdType = comp->getSIMDTypeForSize(simdSize); + assert(varTypeIsMask(type) || (type == simdType)); + assert(varTypeIsArithmetic(simdBaseType)); - assert(comp->getSizeOfSIMDType(type) == simdSize); + assert(varTypeIsSIMD(simdType)); var_types lookupType = type; @@ -30905,7 +30893,7 @@ void ReturnTypeDesc::InitializeStructReturnType(Compiler* comp, assert(varTypeIsValidHfaType(hfaType)); // Note that the retail build issues a warning about a potential divsion by zero without this "max", - unsigned elemSize = max(1u, comp->getSizeOfType(hfaType)); + unsigned elemSize = max(1u, genTypeSize(hfaType)); // The size of this struct should be evenly divisible by elemSize assert((structSize % elemSize) == 0); @@ -31110,7 +31098,6 @@ void ReturnTypeDesc::InitializeReturnType(Compiler* comp, } } -#ifndef TARGET_ARM64 //------------------------------------------------------------------- // GetReturnFieldOffset: // For the N'th returned register, identified by "index", returns the @@ -31134,28 +31121,6 @@ unsigned ReturnTypeDesc::GetReturnFieldOffset(unsigned index) const return offset; #endif } -#endif - -//------------------------------------------------------------------- -// GetReturnFieldOffset: -// For the N'th returned register, identified by "index", returns the -// starting offset in the struct return type of the data being returned. -// -// Arguments: -// retDesc - The return type descriptor -// index - The register whose offset to get -// -// Return Value: -// Starting offset of data returned in that register. -// -unsigned Compiler::GetReturnFieldOffset(const ReturnTypeDesc& retDesc, unsigned index) -{ - assert(retDesc.GetReturnRegType(index) != TYP_UNKNOWN); - unsigned offset = 0; - for (unsigned i = 0; i < index; i++) - offset += getSizeOfType(retDesc.GetReturnRegType(i)); - return offset; -} //------------------------------------------------------------------- // GetABIReturnReg: Return i'th return register as per target ABI @@ -31652,9 +31617,9 @@ unsigned GenTreeHWIntrinsic::GetResultOpNumForRmwIntrinsic(GenTree* use, GenTree } #endif // TARGET_XARCH && FEATURE_HW_INTRINSICS -unsigned GenTreeLclFld::GetSize(Compiler* comp) const +unsigned GenTreeLclFld::GetSize() const { - return TypeIs(TYP_STRUCT) ? GetLayout()->GetSize() : comp->getSizeOfType(TypeGet()); + return TypeIs(TYP_STRUCT) ? GetLayout()->GetSize() : genTypeSize(TypeGet()); } #ifdef TARGET_ARM @@ -32542,6 +32507,8 @@ GenTree* Compiler::gtFoldExprHWIntrinsic(GenTreeHWIntrinsic* tree) case NI_Vector512_ToScalar: #endif { + var_types simdType = getSIMDTypeForSize(simdSize); + if (varTypeIsFloating(retType)) { double result = cnsNode->AsVecCon()->ToScalarFloating(simdBaseType); @@ -32801,6 +32768,8 @@ GenTree* Compiler::gtFoldExprHWIntrinsic(GenTreeHWIntrinsic* tree) break; } + var_types simdType = getSIMDTypeForSize(simdSize); + if (varTypeIsFloating(retType)) { double result = cnsNode->AsVecCon()->GetElementFloating(simdBaseType, index); @@ -33744,6 +33713,8 @@ GenTree* Compiler::gtFoldExprHWIntrinsic(GenTreeHWIntrinsic* tree) break; } + var_types simdType = getSIMDTypeForSize(simdSize); + if (varTypeIsFloating(simdBaseType)) { double value = op3->AsDblCon()->DconValue(); diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index dea9069ab91ceb..6e8737792916dc 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -3959,7 +3959,7 @@ struct GenTreeLclFld : public GenTreeLclVarCommon m_layout = layout; } - unsigned GetSize(Compiler* comp) const; + unsigned GetSize() const; #ifdef TARGET_ARM bool IsOffsetMisaligned() const; @@ -4574,9 +4574,7 @@ struct ReturnTypeDesc #endif } -#ifndef TARGET_ARM64 unsigned GetReturnFieldOffset(unsigned index) const; -#endif // Get i'th ABI return register regNumber GetABIReturnReg(unsigned idx, CorInfoCallConvExtension callConv) const; @@ -7961,6 +7959,8 @@ struct GenTreeIndir : public GenTreeOp unsigned Scale(); ssize_t Offset(); + unsigned Size() const; + GenTreeIndir(genTreeOps oper, var_types type, GenTree* addr, GenTree* data) : GenTreeOp(oper, type, addr, data) { diff --git a/src/coreclr/jit/hwintrinsic.cpp b/src/coreclr/jit/hwintrinsic.cpp index 5a4ed811abdcc1..83909542992db3 100644 --- a/src/coreclr/jit/hwintrinsic.cpp +++ b/src/coreclr/jit/hwintrinsic.cpp @@ -1502,7 +1502,9 @@ GenTree* Compiler::getArgForHWIntrinsic(var_types argType, CORINFO_CLASS_HANDLE { if (!varTypeIsSIMD(argType)) { - argType = getSIMDType(argClass); + unsigned int argSizeBytes; + (void)getBaseJitTypeAndSizeOfSIMDType(argClass, &argSizeBytes); + argType = getSIMDTypeForSize(argSizeBytes); } assert(varTypeIsSIMD(argType)); @@ -1887,20 +1889,29 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic, CorInfoType simdBaseJitType = CORINFO_TYPE_UNDEF; GenTree* retNode = nullptr; - if (retType == TYP_STRUCT && !HWIntrinsicInfo::IsMultiReg(intrinsic)) + if (retType == TYP_STRUCT) { - retType = impNormStructType(sig->retTypeSigClass, &simdBaseJitType); + unsigned int sizeBytes; + simdBaseJitType = getBaseJitTypeAndSizeOfSIMDType(sig->retTypeSigClass, &sizeBytes); + + if (HWIntrinsicInfo::IsMultiReg(intrinsic)) + { + assert(sizeBytes == 0); + } #ifdef TARGET_ARM64 - if ((intrinsic == NI_AdvSimd_LoadAndInsertScalar) || (intrinsic == NI_AdvSimd_Arm64_LoadAndInsertScalar)) + else if ((intrinsic == NI_AdvSimd_LoadAndInsertScalar) || (intrinsic == NI_AdvSimd_Arm64_LoadAndInsertScalar)) { - if (retType == TYP_STRUCT) + CorInfoType pSimdBaseJitType = CORINFO_TYPE_UNDEF; + var_types retFieldType = impNormStructType(sig->retTypeSigClass, &pSimdBaseJitType); + + if (retFieldType == TYP_STRUCT) { CORINFO_CLASS_HANDLE structType; unsigned int sizeBytes = 0; // LoadAndInsertScalar that returns 2,3 or 4 vectors - assert(simdBaseJitType == CORINFO_TYPE_UNDEF); + assert(pSimdBaseJitType == CORINFO_TYPE_UNDEF); unsigned fieldCount = info.compCompHnd->getClassNumInstanceFields(sig->retTypeSigClass); assert(fieldCount > 1); CORINFO_FIELD_HANDLE fieldHandle = info.compCompHnd->getFieldInClass(sig->retTypeClass, 0); @@ -1926,20 +1937,24 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic, } else { - assert((retType == TYP_SIMD8) || (retType == TYP_SIMD16)); + assert((retFieldType == TYP_SIMD8) || (retFieldType == TYP_SIMD16)); assert(isSupportedBaseType(intrinsic, simdBaseJitType)); + retType = getSIMDTypeForSize(sizeBytes); } } - else #endif + else + { // We want to return early here for cases where retType was TYP_STRUCT as per method signature and // rather than deferring the decision after getting the simdBaseJitType of arg. - if (retType == TYP_UNDEF || !isSupportedBaseType(intrinsic, simdBaseJitType)) + if (!isSupportedBaseType(intrinsic, simdBaseJitType)) { return nullptr; } - assert((varTypeIsSIMD(retType) || varTypeIsStruct(retType)) && isSupportedBaseType(intrinsic, simdBaseJitType)); + assert(sizeBytes != 0); + retType = getSIMDTypeForSize(sizeBytes); + } } simdBaseJitType = getBaseJitTypeFromArgIfNeeded(intrinsic, sig, simdBaseJitType); diff --git a/src/coreclr/jit/hwintrinsicarm64.cpp b/src/coreclr/jit/hwintrinsicarm64.cpp index 2a3d49a77d6a13..5b1d29033ffc10 100644 --- a/src/coreclr/jit/hwintrinsicarm64.cpp +++ b/src/coreclr/jit/hwintrinsicarm64.cpp @@ -612,9 +612,9 @@ GenTree* Compiler::impNonConstFallback(NamedIntrinsic intrinsic, var_types simdT unreached(); } - GenTree* tmpOp = gtNewSimdCreateBroadcastNode(simdType, op2, simdBaseJitType, getSizeOfType(simdType)); + GenTree* tmpOp = gtNewSimdCreateBroadcastNode(simdType, op2, simdBaseJitType, genTypeSize(simdType)); return gtNewSimdHWIntrinsicNode(simdType, op1, tmpOp, fallbackIntrinsic, simdBaseJitType, - getSizeOfType(simdType)); + genTypeSize(simdType)); } default: @@ -1361,10 +1361,12 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, if (!varTypeIsLong(simdBaseType)) { + var_types simdType = getSIMDTypeForSize(simdSize); + op2 = impSIMDPopStack(); op1 = impSIMDPopStack(); - retNode = gtNewSimdDotProdNode(op1->TypeGet(), op1, op2, simdBaseJitType, simdSize); + retNode = gtNewSimdDotProdNode(simdType, op1, op2, simdBaseJitType, simdSize); retNode = gtNewSimdGetElementNode(retType, retNode, gtNewIconNode(0), simdBaseJitType, simdSize); } break; diff --git a/src/coreclr/jit/hwintrinsiccodegenarm64.cpp b/src/coreclr/jit/hwintrinsiccodegenarm64.cpp index 048ffa2fc17c17..40fc41db5373a9 100644 --- a/src/coreclr/jit/hwintrinsiccodegenarm64.cpp +++ b/src/coreclr/jit/hwintrinsiccodegenarm64.cpp @@ -82,7 +82,7 @@ CodeGen::HWIntrinsicImmOpHelper::HWIntrinsicImmOpHelper(CodeGen* code assert(varTypeIsSIMD(indexedElementOpType)); - const unsigned int indexedElementSimdSize = codeGen->compiler->getSizeOfType(indexedElementOpType); + const unsigned int indexedElementSimdSize = genTypeSize(indexedElementOpType); HWIntrinsicInfo::lookupImmBounds(intrin->GetHWIntrinsicId(), indexedElementSimdSize, intrin->GetSimdBaseType(), 1, &immLowerBound, &immUpperBound); } diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index d0a4a4aabf0c51..3bd72cb08e609a 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -1185,12 +1185,12 @@ var_types Compiler::impNormStructType(CORINFO_CLASS_HANDLE structHnd, CorInfoTyp if (structSizeMightRepresentSIMDType(originalSize)) { - CorInfoType simdBaseJitType = CORINFO_TYPE_UNDEF; - var_types simdType = getSIMDType(structHnd, &simdBaseJitType); - if (simdBaseJitType != CORINFO_TYPE_UNDEF && simdType != TYP_UNDEF) + unsigned int sizeBytes; + CorInfoType simdBaseJitType = getBaseJitTypeAndSizeOfSIMDType(structHnd, &sizeBytes); + if (simdBaseJitType != CORINFO_TYPE_UNDEF) { - assert(getSizeOfSIMDType(simdType) == originalSize); - structType = simdType; + assert(sizeBytes == originalSize); + structType = getSIMDTypeForSize(sizeBytes); if (pSimdBaseJitType != nullptr) { *pSimdBaseJitType = simdBaseJitType; @@ -3709,7 +3709,7 @@ void Compiler::impImportNewObjArray(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORI // Increase size of lvaNewObjArrayArgs to be the largest size needed to hold 'numArgs' integers // for our call to CORINFO_HELP_NEW_MDARR. - if (dimensionsSize > lvaLclExactSize(&lvaTable[lvaNewObjArrayArgs])) + if (dimensionsSize > lvaTable[lvaNewObjArrayArgs].lvExactSize()) { lvaTable[lvaNewObjArrayArgs].GrowBlockLayout(typGetBlkLayout(dimensionsSize)); } diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index 5dd759e71938fa..beca2374c6713a 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -11755,7 +11755,7 @@ GenTree* Compiler::impArrayAccessIntrinsic( } } - unsigned arrayElemSize = (elemType == TYP_STRUCT) ? elemLayout->GetSize() : getSizeOfType(elemType); + unsigned arrayElemSize = (elemType == TYP_STRUCT) ? elemLayout->GetSize() : genTypeSize(elemType); if (!FitsIn(arrayElemSize)) { diff --git a/src/coreclr/jit/inductionvariableopts.cpp b/src/coreclr/jit/inductionvariableopts.cpp index 9e1885a44c5d31..e107701219edc6 100644 --- a/src/coreclr/jit/inductionvariableopts.cpp +++ b/src/coreclr/jit/inductionvariableopts.cpp @@ -2332,7 +2332,7 @@ bool StrengthReductionContext::StaysWithinManagedObject(ArrayStack* unsigned arrElemSize = arrAddr->GetElemType() == TYP_STRUCT ? m_comp->typGetObjLayout(arrAddr->GetElemClassHandle())->GetSize() - : m_comp->getSizeOfType(arrAddr->GetElemType()); + : genTypeSize(arrAddr->GetElemType()); int64_t stepCns; if (!addRec->Step->GetConstantValue(m_comp, &stepCns) || ((unsigned)stepCns > arrElemSize)) diff --git a/src/coreclr/jit/lclmorph.cpp b/src/coreclr/jit/lclmorph.cpp index f02a52bf1d89d4..4bda0cfcb4c827 100644 --- a/src/coreclr/jit/lclmorph.cpp +++ b/src/coreclr/jit/lclmorph.cpp @@ -1504,8 +1504,8 @@ class LocalAddressVisitor final : public GenTreeVisitor callUser->gtCallMoreFlags |= GTF_CALL_M_RETBUFFARG_LCLOPT; defFlag = GTF_VAR_DEF; - if ((val.Offset() != 0) || (m_compiler->lvaLclExactSize(varDsc) != - m_compiler->typGetObjLayout(callUser->gtRetClsHnd)->GetSize())) + if ((val.Offset() != 0) || + (varDsc->lvExactSize() != m_compiler->typGetObjLayout(callUser->gtRetClsHnd)->GetSize())) { defFlag |= GTF_VAR_USEASG; } @@ -1521,7 +1521,7 @@ class LocalAddressVisitor final : public GenTreeVisitor escapeAddr = false; defFlag = GTF_VAR_DEF; - if ((val.Offset() != 0) || (m_compiler->lvaLclExactSize(varDsc) != 1)) + if ((val.Offset() != 0) || (varDsc->lvExactSize() != 1)) { defFlag |= GTF_VAR_USEASG; } @@ -1591,7 +1591,7 @@ class LocalAddressVisitor final : public GenTreeVisitor unsigned lclNum = val.LclNum(); unsigned offset = val.Offset(); LclVarDsc* varDsc = m_compiler->lvaGetDesc(lclNum); - unsigned indirSize = m_compiler->gtGetSizeOfIndirection(node->AsIndir()); + unsigned indirSize = node->AsIndir()->Size(); bool isWide; // TODO-Cleanup: delete "indirSize == 0", use "Compiler::IsValidLclAddr". @@ -1733,9 +1733,8 @@ class LocalAddressVisitor final : public GenTreeVisitor { // Handle case 1 or the float field of case 2 GenTree* indexNode = m_compiler->gtNewIconNode(offset / genTypeSize(elementType)); - hwiNode = - m_compiler->gtNewSimdGetElementNode(elementType, lclNode, indexNode, CORINFO_TYPE_FLOAT, - m_compiler->getSizeOfType(varDsc->TypeGet())); + hwiNode = m_compiler->gtNewSimdGetElementNode(elementType, lclNode, indexNode, + CORINFO_TYPE_FLOAT, genTypeSize(varDsc)); break; } @@ -1792,9 +1791,9 @@ class LocalAddressVisitor final : public GenTreeVisitor { // Handle case 1 or the float field of case 2 GenTree* indexNode = m_compiler->gtNewIconNode(offset / genTypeSize(elementType)); - hwiNode = m_compiler->gtNewSimdWithElementNode(varDsc->TypeGet(), simdLclNode, indexNode, - elementNode, CORINFO_TYPE_FLOAT, - m_compiler->getSizeOfType(varDsc->TypeGet())); + hwiNode = + m_compiler->gtNewSimdWithElementNode(varDsc->TypeGet(), simdLclNode, indexNode, elementNode, + CORINFO_TYPE_FLOAT, genTypeSize(varDsc)); break; } @@ -2020,11 +2019,8 @@ class LocalAddressVisitor final : public GenTreeVisitor return IndirTransform::NarrowCast; } - unsigned indirTypeSize = m_compiler->getSizeOfType(indir->TypeGet()); - - if ((indirTypeSize == m_compiler->getSizeOfType(varDsc->TypeGet())) && - (indirTypeSize <= TARGET_POINTER_SIZE) && (varTypeIsFloating(indir) || varTypeIsFloating(varDsc)) && - !varDsc->lvPromoted) + if ((genTypeSize(indir) == genTypeSize(varDsc)) && (genTypeSize(indir) <= TARGET_POINTER_SIZE) && + (varTypeIsFloating(indir) || varTypeIsFloating(varDsc)) && !varDsc->lvPromoted) { return IndirTransform::BitCast; } @@ -2066,7 +2062,7 @@ class LocalAddressVisitor final : public GenTreeVisitor return false; } - unsigned fieldLclNum = MorphStructFieldAddress(addr, m_compiler->gtGetSizeOfIndirection(node)); + unsigned fieldLclNum = MorphStructFieldAddress(addr, node->Size()); if (fieldLclNum == BAD_VAR_NUM) { return false; @@ -2147,7 +2143,7 @@ class LocalAddressVisitor final : public GenTreeVisitor // Retargeting the indirection to reference the promoted field would make it "wide", exposing // the whole parent struct (with all of its fields). - if (accessSize > m_compiler->getSizeOfType(fieldVarDsc->TypeGet())) + if (accessSize > genTypeSize(fieldVarDsc)) { return BAD_VAR_NUM; } diff --git a/src/coreclr/jit/lclvars.cpp b/src/coreclr/jit/lclvars.cpp index 9acc38b523afb2..d97fdbca4a1a55 100644 --- a/src/coreclr/jit/lclvars.cpp +++ b/src/coreclr/jit/lclvars.cpp @@ -102,8 +102,8 @@ void Compiler::lvaInitTypeRef() varTypeIsStruct(info.compRetType) ? eeGetClassName(retClass) : ""); for (unsigned i = 0; i < returnRegCount; i++) { - unsigned offset = GetReturnFieldOffset(compRetTypeDesc, i); - unsigned size = getSizeOfType(compRetTypeDesc.GetReturnRegType(i)); + unsigned offset = compRetTypeDesc.GetReturnFieldOffset(i); + unsigned size = genTypeSize(compRetTypeDesc.GetReturnRegType(i)); printf(" [%02u..%02u) reg %s\n", offset, offset + size, getRegName(compRetTypeDesc.GetABIReturnReg(i, info.compCallConv))); } @@ -1435,10 +1435,15 @@ var_types Compiler::StructPromotionHelper::TryPromoteValueClassAsPrimitive(CORIN #ifdef FEATURE_SIMD if (compiler->isRuntimeIntrinsicsNamespace(namespaceName) || compiler->isNumericsNamespace(namespaceName)) { - var_types type = compiler->getSIMDType(node.simdTypeHnd); - if (type != TYP_UNDEF) + unsigned simdSize; + CorInfoType simdBaseJitType = compiler->getBaseJitTypeAndSizeOfSIMDType(node.simdTypeHnd, &simdSize); + // We will only promote fields of SIMD types that fit into a SIMD register. + if (simdBaseJitType != CORINFO_TYPE_UNDEF) { - return type; + if (compiler->structSizeMightRepresentSIMDType(simdSize)) + { + return compiler->getSIMDTypeForSize(simdSize); + } } } #endif @@ -1993,8 +1998,7 @@ void Compiler::StructPromotionHelper::PromoteStructVar(unsigned lclNum) if (varTypeIsValidHfaType(hfaType)) { fieldVarDsc->lvIsMultiRegArg = - (varDsc->lvIsMultiRegArg != 0) && - (compiler->lvaLclExactSize(fieldVarDsc) > compiler->getSizeOfType(hfaType)); + (varDsc->lvIsMultiRegArg != 0) && (fieldVarDsc->lvExactSize() > genTypeSize(hfaType)); } } } @@ -2737,13 +2741,6 @@ unsigned Compiler::lvaLclStackHomeSize(unsigned varNum) LclVarDsc* varDsc = lvaGetDesc(varNum); var_types varType = varDsc->TypeGet(); -#ifdef TARGET_ARM64 - if (varType == TYP_SIMDSV) - { - return getSizeOfSIMDType(varType); - } -#endif - if (!varTypeIsStruct(varType)) { #ifdef TARGET_64BIT @@ -2772,7 +2769,7 @@ unsigned Compiler::lvaLclStackHomeSize(unsigned varNum) // There are other cases where the caller has allocated space for the // parameter, like windows-x64 with shadow space for register // parameters, but in those cases this rounding is fine. - return roundUp(lvaLclExactSize(varDsc), TARGET_POINTER_SIZE); + return roundUp(varDsc->lvExactSize(), TARGET_POINTER_SIZE); } #if defined(FEATURE_SIMD) && !defined(TARGET_64BIT) @@ -2786,7 +2783,7 @@ unsigned Compiler::lvaLclStackHomeSize(unsigned varNum) } #endif // defined(FEATURE_SIMD) && !defined(TARGET_64BIT) - return roundUp(lvaLclExactSize(varDsc), TARGET_POINTER_SIZE); + return roundUp(varDsc->lvExactSize(), TARGET_POINTER_SIZE); } // @@ -2796,19 +2793,7 @@ unsigned Compiler::lvaLclStackHomeSize(unsigned varNum) unsigned Compiler::lvaLclExactSize(unsigned varNum) { assert(varNum < lvaCount); - return lvaLclExactSize(lvaGetDesc(varNum)); -} - -//------------------------------------------------------------------------ -// lvaLclExactSize: Get the exact size of the type of this local. -// -// Return Value: -// Size in bytes. Always non-zero, but not necessarily a multiple of the -// stack slot size. -// -unsigned Compiler::lvaLclExactSize(const LclVarDsc* desc) -{ - return (desc->lvType == TYP_STRUCT) ? desc->GetLayout()->GetSize() : getSizeOfType(desc->lvType); + return lvaGetDesc(varNum)->lvExactSize(); } // LclVarDsc "less" comparer used to compare the weight of two locals, when optimizing for small code. @@ -3241,6 +3226,18 @@ void Compiler::lvaSortByRefCount() #endif } +//------------------------------------------------------------------------ +// lvExactSize: Get the exact size of the type of this local. +// +// Return Value: +// Size in bytes. Always non-zero, but not necessarily a multiple of the +// stack slot size. +// +unsigned LclVarDsc::lvExactSize() const +{ + return (lvType == TYP_STRUCT) ? GetLayout()->GetSize() : genTypeSize(lvType); +} + //------------------------------------------------------------------------ // GetRegisterType: Determine register type for this local var. // @@ -6338,7 +6335,7 @@ void Compiler::lvaDumpEntry(unsigned lclNum, FrameLayoutState curState, size_t r refCntWtd2str(varDsc->lvRefCntWtd(lvaRefCountState), /* padForDecimalPlaces */ true)); printf(" %7s ", varTypeName(type)); - if (getSizeOfType(type) == 0) + if (genTypeSize(type) == 0) { printf("(%2d) ", lvaLclStackHomeSize(lclNum)); } @@ -7016,7 +7013,7 @@ Compiler::fgWalkResult Compiler::lvaStressLclFldCB(GenTree** pTree, fgWalkData* // node with the accurate small type. If we bash lvaTable[].lvType, // then there will be no indication that it was ever a small type. - if (pComp->getSizeOfType(varType) != pComp->getSizeOfType(genActualType(varType))) + if (genTypeSize(varType) != genTypeSize(genActualType(varType))) { varDsc->lvNoLclFldStress = true; return WALK_CONTINUE; diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index d98f870584b5da..6341e3458a4205 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -1692,7 +1692,7 @@ void Lowering::SplitArgumentBetweenRegistersAndStack(GenTreeCall* call, CallArg* break; } - if (use.GetOffset() + comp->getSizeOfType(use.GetType()) > stackSeg.Offset) + if (use.GetOffset() + genTypeSize(use.GetType()) > stackSeg.Offset) { // Field overlaps partially into the stack segment, cannot // handle this without spilling. @@ -1932,7 +1932,7 @@ void Lowering::InsertBitCastIfNecessary(GenTree** argNode, const ABIPassingSegme // such cases we cut off the end of the segment to get an appropriate // register type for the bitcast. ABIPassingSegment cutRegisterSegment = registerSegment; - unsigned argNodeSize = comp->getSizeOfType(genActualType(*argNode)); + unsigned argNodeSize = genTypeSize(genActualType(*argNode)); if (registerSegment.Size > argNodeSize) { cutRegisterSegment = @@ -2304,7 +2304,7 @@ bool Lowering::LowerCallMemset(GenTreeCall* call, GenTree** next) valueArg = valueCallArg->GetNode(); // Get that from the signature - lengthScale = comp->getSizeOfType(valueCallArg->GetSignatureType()); + lengthScale = genTypeSize(valueCallArg->GetSignatureType()); // NOTE: structs and TYP_REF will be ignored by the "Value is not a constant" check // Some of those cases can be enabled in future, e.g. s } @@ -2612,10 +2612,10 @@ bool Lowering::LowerCallMemcmp(GenTreeCall* call, GenTree** next) { assert(type == TYP_INT); return comp->gtNewSimdCmpOpAllNode(oper, TYP_INT, op1, op2, CORINFO_TYPE_NATIVEUINT, - comp->getSizeOfType(op1)); + genTypeSize(op1)); } return comp->gtNewSimdBinOpNode(oper, op1->TypeGet(), op1, op2, CORINFO_TYPE_NATIVEUINT, - comp->getSizeOfType(op1)); + genTypeSize(op1)); } #endif return comp->gtNewOperNode(oper, type, op1, op2); @@ -4364,7 +4364,7 @@ GenTree* Lowering::OptimizeConstCompare(GenTree* cmp) andOp1->gtType = TYP_UBYTE; andOp2->gtType = TYP_UBYTE; } - else if (FitsIn(mask) && comp->getSizeOfType(andOp1) == 2) + else if (FitsIn(mask) && genTypeSize(andOp1) == 2) { andOp1->gtType = TYP_USHORT; andOp2->gtType = TYP_USHORT; @@ -4564,7 +4564,7 @@ GenTree* Lowering::LowerJTrue(GenTreeOp* jtrue) cc = cond->OperIs(GT_LT) ? GenCondition(GenCondition::NE) : GenCondition(GenCondition::EQ); // x < 0 => (x & signBit) != 0. Update the constant to be the sign bit. relopOp2->AsIntConCommon()->SetIntegralValue( - (static_cast(1) << (8 * comp->getSizeOfType(genActualType(relopOp1)) - 1))); + (static_cast(1) << (8 * genTypeSize(genActualType(relopOp1)) - 1))); } else if (cond->OperIs(GT_TEST_EQ, GT_TEST_NE) && isPow2(relopOp2->AsIntCon()->IconValue())) { @@ -4995,9 +4995,8 @@ void Lowering::LowerRet(GenTreeOp* ret) var_types retActualType = genActualType(comp->info.compRetNativeType); var_types retValActualType = genActualType(retVal->TypeGet()); - bool constStructInit = retVal->IsConstInitVal(); - bool implicitCastFromSameOrBiggerSize = - (comp->getSizeOfType(retActualType) <= comp->getSizeOfType(retValActualType)); + bool constStructInit = retVal->IsConstInitVal(); + bool implicitCastFromSameOrBiggerSize = (genTypeSize(retActualType) <= genTypeSize(retValActualType)); // This could happen if we have retyped op1 as a primitive type during struct promotion. bool actualTypesMatch = (retActualType == retValActualType); @@ -5056,7 +5055,7 @@ void Lowering::LowerRetFieldList(GenTreeOp* ret, GenTreeFieldList* fieldList) unsigned numRegs = retDesc.GetReturnRegCount(); auto getRegInfo = [=, &retDesc](unsigned regIndex) { - unsigned offset = comp->GetReturnFieldOffset(retDesc, regIndex); + unsigned offset = retDesc.GetReturnFieldOffset(regIndex); var_types regType = retDesc.GetReturnRegType(regIndex); return LowerFieldListRegisterInfo(offset, regType); }; @@ -5199,7 +5198,7 @@ bool Lowering::IsFieldListCompatibleWithRegisters(GenTreeFieldList* fieldList, LowerFieldListRegisterInfo regInfo = getRegInfo(i); unsigned regStart = regInfo.Offset; var_types regType = regInfo.RegType; - unsigned regEnd = regStart + comp->getSizeOfType(regType); + unsigned regEnd = regStart + genTypeSize(regType); if ((i == numRegs - 1) && !varTypeUsesFloatReg(regType)) { @@ -5231,7 +5230,7 @@ bool Lowering::IsFieldListCompatibleWithRegisters(GenTreeFieldList* fieldList, break; } - unsigned fieldEnd = fieldStart + comp->getSizeOfType(use->GetType()); + unsigned fieldEnd = fieldStart + genTypeSize(use->GetType()); if (fieldEnd > regEnd) { JITDUMP("it is not; field [%06u] ends after register %u\n", Compiler::dspTreeID(use->GetNode()), i); @@ -5249,10 +5248,10 @@ bool Lowering::IsFieldListCompatibleWithRegisters(GenTreeFieldList* fieldList, // int -> float is currently only supported if we can do it as a single bitcast (i.e. without insertions // required) if (varTypeUsesIntReg(use->GetNode()) && varTypeUsesFloatReg(regType) && - (comp->getSizeOfType(regType) > TARGET_POINTER_SIZE)) + (genTypeSize(regType) > TARGET_POINTER_SIZE)) { JITDUMP("it is not; field [%06u] requires an insertion into float register %u of size %d\n", - Compiler::dspTreeID(use->GetNode()), i, comp->getSizeOfType(regType)); + Compiler::dspTreeID(use->GetNode()), i, genTypeSize(regType)); return false; } @@ -5292,7 +5291,7 @@ void Lowering::LowerFieldListToFieldListOfRegisters(GenTreeFieldList* fieldLis LowerFieldListRegisterInfo regInfo = getRegInfo(i); unsigned regStart = regInfo.Offset; var_types regType = regInfo.RegType; - unsigned regEnd = regStart + comp->getSizeOfType(regType); + unsigned regEnd = regStart + genTypeSize(regType); if ((i == numRegs - 1) && !varTypeUsesFloatReg(regType)) { @@ -5326,7 +5325,7 @@ void Lowering::LowerFieldListToFieldListOfRegisters(GenTreeFieldList* fieldLis // First ensure the value does not have upper bits set that // interfere with the next field. if ((nextUse != nullptr) && (nextUse->GetOffset() < regEnd) && - (fieldStart + comp->getSizeOfType(genActualType(fieldType)) > nextUse->GetOffset())) + (fieldStart + genTypeSize(genActualType(fieldType)) > nextUse->GetOffset())) { assert(varTypeIsSmall(fieldType)); // This value may interfere with the next field. Ensure that doesn't happen. @@ -5340,13 +5339,13 @@ void Lowering::LowerFieldListToFieldListOfRegisters(GenTreeFieldList* fieldLis // If this is a float -> int insertion, then we need the bitcast now. if (varTypeUsesFloatReg(value) && varTypeUsesIntReg(regInfo.RegType)) { - assert((comp->getSizeOfType(value->TypeGet()) == 4) || (comp->getSizeOfType(value->TypeGet()) == 8)); - var_types castType = comp->getSizeOfType(value->TypeGet()) == 4 ? TYP_INT : TYP_LONG; + assert((genTypeSize(value) == 4) || (genTypeSize(value) == 8)); + var_types castType = genTypeSize(value) == 4 ? TYP_INT : TYP_LONG; value = comp->gtNewBitCastNode(castType, value); BlockRange().InsertBefore(fieldList, value); } - if (insertOffset + comp->getSizeOfType(fieldType) > comp->getSizeOfType(genActualType(value))) + if (insertOffset + genTypeSize(fieldType) > genTypeSize(genActualType(value))) { value = comp->gtNewCastNode(TYP_LONG, value, true, TYP_LONG); BlockRange().InsertBefore(fieldList, value); @@ -5400,7 +5399,7 @@ void Lowering::LowerFieldListToFieldListOfRegisters(GenTreeFieldList* fieldLis // ABIs for structs. while (node->OperIs(GT_CAST) && !node->gtOverflow() && (genActualType(node->CastFromType()) == TYP_INT) && (genActualType(node->CastToType()) == TYP_INT) && - (comp->getSizeOfType(regType) <= comp->getSizeOfType(node->CastToType()))) + (genTypeSize(regType) <= genTypeSize(node->CastToType()))) { GenTree* op = node->AsCast()->CastOp(); regEntry->SetNode(op); @@ -5687,8 +5686,7 @@ void Lowering::LowerRetStruct(GenTreeUnOp* ret) if (varTypeUsesFloatReg(nativeReturnType)) { // ZeroObj assertion propagation can create INT zeros for DOUBLE returns. - assert((comp->getSizeOfType(retVal) == comp->getSizeOfType(nativeReturnType)) || - retVal->IsIntegralConst(0)); + assert((genTypeSize(retVal) == genTypeSize(nativeReturnType)) || retVal->IsIntegralConst(0)); int64_t value = retVal->AsIntCon()->IconValue(); if (nativeReturnType == TYP_FLOAT) @@ -5712,7 +5710,7 @@ void Lowering::LowerRetStruct(GenTreeUnOp* ret) { // Spill to a local if sizes don't match so we can avoid the "load more than requested" // problem, e.g. struct size is 5 and we emit "ldr x0, [x1]" - if (comp->getSizeOfType(nativeReturnType) > comp->gtGetSizeOfIndirection(retVal->AsIndir())) + if (genTypeSize(nativeReturnType) > retVal->AsIndir()->Size()) { LIR::Use retValUse(BlockRange(), &ret->gtOp1, ret); unsigned tmpNum = comp->lvaGrabTemp(true DEBUGARG("mis-sized struct return")); @@ -5783,9 +5781,9 @@ void Lowering::LowerRetSingleRegStructLclVar(GenTreeUnOp* ret) // We are returning as a primitive type and the lcl is of struct type. assert(comp->info.compRetNativeType != TYP_STRUCT); - assert((comp->getSizeOfType(comp->info.compRetNativeType) == comp->getSizeOfType(ret)) || + assert((genTypeSize(comp->info.compRetNativeType) == genTypeSize(ret)) || (varTypeIsIntegral(ret) && varTypeIsIntegral(comp->info.compRetNativeType) && - (comp->getSizeOfType(comp->info.compRetNativeType) <= comp->getSizeOfType(ret)))); + (genTypeSize(comp->info.compRetNativeType) <= genTypeSize(ret)))); // If the actual return type requires normalization, then make sure we // do so by using the correct small type for the GT_LCL_FLD. It would // be conservative to check just compRetNativeType for this since small @@ -5793,7 +5791,7 @@ void Lowering::LowerRetSingleRegStructLclVar(GenTreeUnOp* ret) // registers, so we would normalize for them as well. if (varTypeIsSmall(comp->info.compRetType)) { - assert(comp->getSizeOfType(comp->info.compRetNativeType) == comp->getSizeOfType(comp->info.compRetType)); + assert(genTypeSize(comp->info.compRetNativeType) == genTypeSize(comp->info.compRetType)); lclVar->ChangeType(comp->info.compRetType); } else @@ -7373,7 +7371,7 @@ bool Lowering::TryCreateAddrMode(GenTree* addr, bool isContainable, GenTree* par // *(ulong*)(data + index * 7); - can not be optimized // *(int*)(data + index * 2); - can not be optimized // - naturalMul = comp->getSizeOfType(targetType); + naturalMul = genTypeSize(targetType); #endif // Find out if an addressing mode can be constructed @@ -7516,7 +7514,7 @@ bool Lowering::TryCreateAddrMode(GenTree* addr, bool isContainable, GenTree* par // 'scale' and 'offset' have to be unset since we're going to use [base + index * SXTW/UXTW scale] form // where there is no room for additional offsets/scales on ARM64. 'shiftBy' has to match target's width. if (cast->CastOp()->TypeIs(TYP_INT) && cast->TypeIs(TYP_LONG) && - (comp->getSizeOfType(targetType) == (1U << shiftBy)) && (scale == 1) && (offset == 0)) + (genTypeSize(targetType) == (1U << shiftBy)) && (scale == 1) && (offset == 0)) { if (IsInvariantInRange(index, parent)) { @@ -7606,7 +7604,7 @@ GenTree* Lowering::LowerAdd(GenTreeOp* node) int64_t c2 = cns2->IntegralValue(); int64_t result; - if (comp->getSizeOfType(node) == sizeof(int64_t)) + if (genTypeSize(node) == sizeof(int64_t)) { result = c1 + c2; } @@ -8160,7 +8158,7 @@ bool Lowering::TryLowerConstIntDivOrMod(GenTree* node, GenTree** nextNode) adjusted = mulhi; } - GenTree* shiftBy = comp->gtNewIconNode(comp->getSizeOfType(type) * 8 - 1, type); + GenTree* shiftBy = comp->gtNewIconNode(genTypeSize(type) * 8 - 1, type); GenTree* signBit = comp->gtNewOperNode(GT_RSZ, type, adjusted, shiftBy); BlockRange().InsertBefore(divMod, shiftBy, signBit); @@ -8427,10 +8425,9 @@ void Lowering::LowerShift(GenTreeOp* shift) cast->CastOp()->TypeIs(TYP_LONG, TYP_INT)) { // Cast is either "TYP_LONG <- TYP_INT" or "TYP_INT <- %SMALL_INT% <- TYP_INT" (signed or unsigned) - unsigned dstBits = comp->getSizeOfType(cast) * BITS_PER_BYTE; - unsigned srcBits = varTypeIsSmall(cast->CastToType()) - ? comp->getSizeOfType(cast->CastToType()) * BITS_PER_BYTE - : comp->getSizeOfType(cast->CastOp()) * BITS_PER_BYTE; + unsigned dstBits = genTypeSize(cast) * BITS_PER_BYTE; + unsigned srcBits = varTypeIsSmall(cast->CastToType()) ? genTypeSize(cast->CastToType()) * BITS_PER_BYTE + : genTypeSize(cast->CastOp()) * BITS_PER_BYTE; // It has to be an upcast and CNS must be in [1..srcBits) range if ((srcBits < dstBits) && (cns->IconValue() > 0) && (cns->IconValue() < srcBits)) @@ -8618,7 +8615,7 @@ void Lowering::MapParameterRegisterLocals() continue; } - if (fieldDsc->lvFldOffset + comp->lvaLclExactSize(fieldDsc) <= segment.Offset) + if (fieldDsc->lvFldOffset + fieldDsc->lvExactSize() <= segment.Offset) { // This register does not map to this field (starts after the field ends) continue; @@ -8756,7 +8753,7 @@ void Lowering::FindInducedParameterRegisterLocals() assert(fld->GetLclOffs() <= comp->lvaLclExactSize(fld->GetLclNum())); unsigned structAccessedSize = - min(comp->getSizeOfType(fld), comp->lvaLclExactSize(fld->GetLclNum()) - fld->GetLclOffs()); + min(genTypeSize(fld), comp->lvaLclExactSize(fld->GetLclNum()) - fld->GetLclOffs()); if ((fld->GetLclOffs() < segment.Offset) || (fld->GetLclOffs() + structAccessedSize > segment.Offset + segment.Size)) { @@ -8863,17 +8860,16 @@ void Lowering::FindInducedParameterRegisterLocals() // Insert explicit normalization for small types (the LCL_FLD we // are replacing comes with this normalization). This is only required // if we didn't get the normalization via a right shift. - if (varTypeIsSmall(fld) && - (regSegment->Offset + comp->getSizeOfType(fld) != comp->getSizeOfType(registerType))) + if (varTypeIsSmall(fld) && (regSegment->Offset + genTypeSize(fld) != genTypeSize(registerType))) { value = comp->gtNewCastNode(TYP_INT, value, false, fld->TypeGet()); } // If the node is still too large then get it to the right size - if (comp->getSizeOfType(value) != comp->getSizeOfType(genActualType((fld)))) + if (genTypeSize(value) != genTypeSize(genActualType((fld)))) { - assert(comp->getSizeOfType(value) == 8); - assert(comp->getSizeOfType(genActualType(fld)) == 4); + assert(genTypeSize(value) == 8); + assert(genTypeSize(genActualType(fld)) == 4); if (value->OperIsScalarLocal()) { @@ -9611,7 +9607,7 @@ bool Lowering::TryRemoveBitCast(GenTreeUnOp* node) } GenTree* op = node->gtGetOp1(); - assert(comp->getSizeOfType(node) == comp->getSizeOfType(genActualType(op))); + assert(genTypeSize(node) == genTypeSize(genActualType(op))); bool changed = false; #ifdef FEATURE_SIMD @@ -9623,17 +9619,17 @@ bool Lowering::TryRemoveBitCast(GenTreeUnOp* node) if (isConst) { uint8_t bits[sizeof(simd_t)]; - assert(sizeof(bits) >= comp->getSizeOfType(genActualType(op))); + assert(sizeof(bits) >= genTypeSize(genActualType(op))); if (op->OperIs(GT_CNS_INT)) { ssize_t cns = op->AsIntCon()->IconValue(); - assert(sizeof(ssize_t) >= comp->getSizeOfType(genActualType(op))); - memcpy(bits, &cns, comp->getSizeOfType(genActualType(op))); + assert(sizeof(ssize_t) >= genTypeSize(genActualType(op))); + memcpy(bits, &cns, genTypeSize(genActualType(op))); } #ifdef FEATURE_SIMD else if (op->OperIs(GT_CNS_VEC)) { - memcpy(bits, &op->AsVecCon()->gtSimdVal, comp->getSizeOfType(op)); + memcpy(bits, &op->AsVecCon()->gtSimdVal, genTypeSize(op)); } #endif else @@ -9692,7 +9688,7 @@ bool Lowering::TryRemoveBitCast(GenTreeUnOp* node) void Lowering::ContainCheckBitCast(GenTreeUnOp* node) { GenTree* const op1 = node->gtGetOp1(); - if (op1->OperIs(GT_LCL_VAR) && (comp->getSizeOfType(op1) == comp->getSizeOfType(node))) + if (op1->OperIs(GT_LCL_VAR) && (genTypeSize(op1) == genTypeSize(node))) { if (IsContainableMemoryOp(op1) && IsSafeToContainMem(node, op1)) { @@ -10182,7 +10178,7 @@ void Lowering::LowerStoreIndirCoalescing(GenTreeIndir* ind) // Otherwise, the difference between two offsets has to match the size of the type. // We don't support overlapping stores. - if (abs(prevData.offset - currData.offset) != (int)comp->getSizeOfType(prevData.targetType)) + if (abs(prevData.offset - currData.offset) != (int)genTypeSize(prevData.targetType)) { return; } @@ -10208,7 +10204,7 @@ void Lowering::LowerStoreIndirCoalescing(GenTreeIndir* ind) allowsNonAtomic = true; } - if (!allowsNonAtomic && (comp->getSizeOfType(ind) > 1) && !varTypeIsSIMD(ind)) + if (!allowsNonAtomic && (genTypeSize(ind) > 1) && !varTypeIsSIMD(ind)) { // TODO-CQ: if we see that the target is a local memory (non address exposed) // we can use any type (including SIMD) for a new load. @@ -10227,10 +10223,10 @@ void Lowering::LowerStoreIndirCoalescing(GenTreeIndir* ind) } // Check whether the combined indir is still aligned. - bool isCombinedIndirAtomic = (comp->getSizeOfType(ind) < TARGET_POINTER_SIZE) && - (min(prevData.offset, currData.offset) % (comp->getSizeOfType(ind) * 2)) == 0; + bool isCombinedIndirAtomic = (genTypeSize(ind) < TARGET_POINTER_SIZE) && + (min(prevData.offset, currData.offset) % (genTypeSize(ind) * 2)) == 0; - if (comp->getSizeOfType(ind) == TARGET_POINTER_SIZE) + if (genTypeSize(ind) == TARGET_POINTER_SIZE) { #ifdef TARGET_ARM64 // Per Arm Architecture Reference Manual for A-profile architecture: @@ -10388,7 +10384,7 @@ void Lowering::LowerStoreIndirCoalescing(GenTreeIndir* ind) } simd_t newCns = {}; - uint32_t oldWidth = comp->getSizeOfType(oldType); + uint32_t oldWidth = genTypeSize(oldType); memcpy(newCns.i8, lowerCns, oldWidth); memcpy(newCns.i8 + oldWidth, upperCns, oldWidth); @@ -10426,15 +10422,15 @@ void Lowering::LowerStoreIndirCoalescing(GenTreeIndir* ind) // Trim the constants to the size of the type, e.g. for TYP_SHORT and TYP_USHORT // the mask will be 0xFFFF, for TYP_INT - 0xFFFFFFFF. - size_t mask = ~(size_t(0)) >> (sizeof(size_t) - comp->getSizeOfType(oldType)) * BITS_PER_BYTE; + size_t mask = ~(size_t(0)) >> (sizeof(size_t) - genTypeSize(oldType)) * BITS_PER_BYTE; lowerCns &= mask; upperCns &= mask; - size_t val = (lowerCns | (upperCns << (comp->getSizeOfType(oldType) * BITS_PER_BYTE))); + size_t val = (lowerCns | (upperCns << (genTypeSize(oldType) * BITS_PER_BYTE))); JITDUMP("Coalesced two stores into a single store with value %lld\n", (int64_t)val); ind->Data()->AsIntCon()->gtIconVal = (ssize_t)val; - if (comp->getSizeOfType(oldType) == 1) + if (genTypeSize(oldType) == 1) { // A mark for future foldings that this IND doesn't need to be atomic. ind->gtFlags |= GTF_IND_ALLOW_NON_ATOMIC; @@ -10648,7 +10644,7 @@ bool Lowering::OptimizeForLdpStp(GenTreeIndir* ind) JITDUMP("[%06u] and [%06u] are indirs off the same base with offsets +%03u and +%03u\n", Compiler::dspTreeID(ind), Compiler::dspTreeID(prevIndir), (unsigned)offs, (unsigned)prev.Offset); - if (std::abs(offs - prev.Offset) == comp->getSizeOfType(ind)) + if (std::abs(offs - prev.Offset) == genTypeSize(ind)) { JITDUMP(" ..and they are amenable to ldp/stp optimization\n"); if (TryMakeIndirsAdjacent(prevIndir, ind)) @@ -10847,25 +10843,23 @@ bool Lowering::TryMakeIndirsAdjacent(GenTreeIndir* prevIndir, GenTreeIndir* indi target_ssize_t storeOffs = 0; comp->gtPeelOffsets(&storeAddr, &storeOffs); - unsigned storeSize = comp->gtGetSizeOfIndirection(store); - unsigned indirSize = comp->gtGetSizeOfIndirection(indir); - bool distinct = - (storeOffs + (target_ssize_t)storeSize <= offs) || (offs + (target_ssize_t)indirSize <= storeOffs); + bool distinct = (storeOffs + (target_ssize_t)store->Size() <= offs) || + (offs + (target_ssize_t)indir->Size() <= storeOffs); if (checkLocal && GenTree::Compare(indirAddr, storeAddr) && distinct) { JITDUMP("Cannot interfere with [%06u] since they are off the same local V%02u and indir range " "[%03u..%03u) does not interfere with store range [%03u..%03u)\n", Compiler::dspTreeID(node), indirAddr->AsLclVarCommon()->GetLclNum(), (unsigned)offs, - (unsigned)offs + indirSize, (unsigned)storeOffs, (unsigned)storeOffs + storeSize); + (unsigned)offs + indir->Size(), (unsigned)storeOffs, (unsigned)storeOffs + store->Size()); } // Two indirs off of TYP_REFs cannot overlap if their offset ranges are distinct. else if (indirAddr->TypeIs(TYP_REF) && storeAddr->TypeIs(TYP_REF) && distinct) { JITDUMP("Cannot interfere with [%06u] since they are both off TYP_REF bases and indir range " "[%03u..%03u) does not interfere with store range [%03u..%03u)\n", - Compiler::dspTreeID(node), (unsigned)offs, (unsigned)offs + indirSize, (unsigned)storeOffs, - (unsigned)storeOffs + storeSize); + Compiler::dspTreeID(node), (unsigned)offs, (unsigned)offs + indir->Size(), + (unsigned)storeOffs, (unsigned)storeOffs + store->Size()); } else { diff --git a/src/coreclr/jit/lowerarmarch.cpp b/src/coreclr/jit/lowerarmarch.cpp index af74a6267036d6..a75814b38d3cc4 100644 --- a/src/coreclr/jit/lowerarmarch.cpp +++ b/src/coreclr/jit/lowerarmarch.cpp @@ -2864,7 +2864,7 @@ void Lowering::ContainCheckIndir(GenTreeIndir* indirNode) } } else if (addr->OperIs(GT_LCL_ADDR) && !indirNode->OperIs(GT_NULLCHECK) && - IsContainableLclAddr(addr->AsLclFld(), comp->gtGetSizeOfIndirection(indirNode))) + IsContainableLclAddr(addr->AsLclFld(), indirNode->Size())) { // These nodes go into an addr mode: // - GT_LCL_ADDR is a stack addr mode. diff --git a/src/coreclr/jit/lowerxarch.cpp b/src/coreclr/jit/lowerxarch.cpp index 4cb4dc322b4f5d..2f394610d4f877 100644 --- a/src/coreclr/jit/lowerxarch.cpp +++ b/src/coreclr/jit/lowerxarch.cpp @@ -5076,8 +5076,7 @@ GenTree* Lowering::LowerHWIntrinsicGetElement(GenTreeHWIntrinsic* node) uint32_t lclOffs = lclVar->GetLclOffs() + (imm8 * elemSize); LclVarDsc* lclDsc = comp->lvaGetDesc(lclVar); - if (lclDsc->lvDoNotEnregister && (lclOffs <= 0xFFFF) && - ((lclOffs + elemSize) <= comp->lvaLclExactSize(lclDsc))) + if (lclDsc->lvDoNotEnregister && (lclOffs <= 0xFFFF) && ((lclOffs + elemSize) <= lclDsc->lvExactSize())) { GenTree* lclFld = comp->gtNewLclFldNode(lclVar->GetLclNum(), JITtype2varType(simdBaseJitType), static_cast(lclOffs)); @@ -6308,8 +6307,7 @@ GenTree* Lowering::LowerHWIntrinsicToScalar(GenTreeHWIntrinsic* node) uint32_t lclOffs = lclVar->GetLclOffs() + (0 * elemSize); LclVarDsc* lclDsc = comp->lvaGetDesc(lclVar); - if (lclDsc->lvDoNotEnregister && (lclOffs <= 0xFFFF) && - ((lclOffs + elemSize) <= comp->lvaLclExactSize(lclDsc))) + if (lclDsc->lvDoNotEnregister && (lclOffs <= 0xFFFF) && ((lclOffs + elemSize) <= lclDsc->lvExactSize())) { GenTree* lclFld = comp->gtNewLclFldNode(lclVar->GetLclNum(), JITtype2varType(simdBaseJitType), lclVar->GetLclOffs()); @@ -7278,7 +7276,7 @@ void Lowering::ContainCheckIndir(GenTreeIndir* node) // The address of an indirection that requires its address in a reg. // Skip any further processing that might otherwise make it contained. } - else if (addr->OperIs(GT_LCL_ADDR) && IsContainableLclAddr(addr->AsLclFld(), comp->gtGetSizeOfIndirection(node))) + else if (addr->OperIs(GT_LCL_ADDR) && IsContainableLclAddr(addr->AsLclFld(), node->Size())) { // These nodes go into an addr mode: // - GT_LCL_ADDR is a stack addr mode. @@ -8239,7 +8237,7 @@ bool Lowering::LowerRMWMemOp(GenTreeIndir* storeInd) // If it is a GT_LCL_VAR, it still needs the reg to hold the address. // We would still need a reg for GT_CNS_INT if it doesn't fit within addressing mode base. if (indirCandidateChild->OperIs(GT_LCL_ADDR) && - IsContainableLclAddr(indirCandidateChild->AsLclFld(), comp->gtGetSizeOfIndirection(storeInd))) + IsContainableLclAddr(indirCandidateChild->AsLclFld(), storeInd->Size())) { indirDst->SetContained(); } diff --git a/src/coreclr/jit/lsraarm64.cpp b/src/coreclr/jit/lsraarm64.cpp index 4d3e465610daf2..5fb1d1f10e76d9 100644 --- a/src/coreclr/jit/lsraarm64.cpp +++ b/src/coreclr/jit/lsraarm64.cpp @@ -1585,7 +1585,7 @@ void LinearScan::BuildHWIntrinsicImmediate(GenTreeHWIntrinsic* intrinsicTree, co assert(varTypeIsSIMD(indexedElementOpType)); - const unsigned int indexedElementSimdSize = compiler->getSizeOfType(indexedElementOpType); + const unsigned int indexedElementSimdSize = genTypeSize(indexedElementOpType); HWIntrinsicInfo::lookupImmBounds(intrin.id, indexedElementSimdSize, intrin.baseType, 1, &immLowerBound, &immUpperBound); } diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index d77ba2f72567ed..96026d8948c8f0 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -288,7 +288,7 @@ GenTree* Compiler::fgMorphExpandCast(GenTreeCast* tree) GenTree* oper = tree->CastOp(); var_types srcType = genActualType(oper); var_types dstType = tree->CastToType(); - unsigned dstSize = getSizeOfType(dstType); + unsigned dstSize = genTypeSize(dstType); // See if the cast has to be done in two steps. R -> I if (varTypeIsFloating(srcType) && varTypeIsIntegral(dstType)) @@ -6896,7 +6896,7 @@ GenTree* Compiler::getSIMDStructFromField(GenTree* tree, if (varTypeIsArithmetic(elementType) && ((fieldOffset % elementSize) == 0)) { - *simdSizeOut = lvaLclExactSize(varDsc); + *simdSizeOut = varDsc->lvExactSize(); *indexOut = fieldOffset / elementSize; return objRef; @@ -8546,7 +8546,7 @@ GenTree* Compiler::fgMorphFinalizeIndir(GenTreeIndir* indir) if (!indir->IsVolatile() && !indir->TypeIs(TYP_STRUCT) && addr->OperIs(GT_LCL_ADDR)) { - unsigned size = gtGetSizeOfIndirection(indir); + unsigned size = indir->Size(); unsigned offset = addr->AsLclVarCommon()->GetLclOffs(); unsigned extent = offset + size; unsigned lclSize = lvaLclExactSize(addr->AsLclVarCommon()->GetLclNum()); @@ -10856,7 +10856,7 @@ GenTree* Compiler::fgMorphRetInd(GenTreeOp* ret) if (fgGlobalMorph && varTypeIsStruct(lclFld) && !lvaIsImplicitByRefLocal(lclNum)) { LclVarDsc* varDsc = lvaGetDesc(lclNum); - unsigned indSize = lclFld->GetSize(this); + unsigned indSize = lclFld->GetSize(); unsigned lclVarSize = lvaLclExactSize(lclNum); // TODO: change conditions in `canFold` to `indSize <= lclVarSize`, but currently do not support `BITCAST diff --git a/src/coreclr/jit/morphblock.cpp b/src/coreclr/jit/morphblock.cpp index 9ad705dc33e334..452983ffc50597 100644 --- a/src/coreclr/jit/morphblock.cpp +++ b/src/coreclr/jit/morphblock.cpp @@ -194,7 +194,7 @@ void MorphInitBlockHelper::PrepareDst() } else { - m_blockSize = m_comp->getSizeOfType(m_store->TypeGet()); + m_blockSize = genTypeSize(m_store); } assert(m_blockSize != 0); @@ -355,7 +355,7 @@ void MorphInitBlockHelper::TryInitFieldByField() return; } - if (m_comp->lvaLclExactSize(destLclVar) != blockSize) + if (destLclVar->lvExactSize() != blockSize) { JITDUMP(" dest size mismatch.\n"); return; @@ -711,7 +711,7 @@ void MorphCopyBlockHelper::MorphStructCases() noway_assert(varTypeIsStruct(m_dstVarDsc)); noway_assert(!m_comp->opts.MinOpts()); - if (m_blockSize == m_comp->lvaLclExactSize(m_dstVarDsc)) + if (m_blockSize == m_dstVarDsc->lvExactSize()) { JITDUMP(" (m_dstDoFldStore=true)"); // We may decide later that a copyblk is required when this struct has holes @@ -731,7 +731,7 @@ void MorphCopyBlockHelper::MorphStructCases() noway_assert(varTypeIsStruct(m_srcVarDsc)); noway_assert(!m_comp->opts.MinOpts()); - if (m_blockSize == m_comp->lvaLclExactSize(m_srcVarDsc)) + if (m_blockSize == m_srcVarDsc->lvExactSize()) { JITDUMP(" (m_srcDoFldStore=true)"); // We may decide later that a copyblk is required when this struct has holes @@ -995,7 +995,7 @@ void MorphCopyBlockHelper::TryPrimitiveCopy() // Can we use the LHS local directly? if (m_store->OperIs(GT_STORE_LCL_FLD)) { - if (m_blockSize == m_comp->getSizeOfType(m_dstVarDsc->TypeGet())) + if (m_blockSize == genTypeSize(m_dstVarDsc)) { storeType = m_dstVarDsc->TypeGet(); } @@ -1308,9 +1308,9 @@ GenTree* MorphCopyBlockHelper::CopyFieldByField() { noway_assert(m_srcLclNode != nullptr); assert(destType != TYP_STRUCT); - unsigned destSize = m_comp->getSizeOfType(destType); + unsigned destSize = genTypeSize(destType); m_srcVarDsc = m_comp->lvaGetDesc(m_srcLclNum); - unsigned srcSize = m_comp->lvaLclExactSize(m_srcVarDsc); + unsigned srcSize = m_srcVarDsc->lvExactSize(); if (destSize == srcSize) { m_srcLclNode->ChangeOper(GT_LCL_FLD); diff --git a/src/coreclr/jit/optimizer.cpp b/src/coreclr/jit/optimizer.cpp index 4387e027af3632..d538ca44b2413d 100644 --- a/src/coreclr/jit/optimizer.cpp +++ b/src/coreclr/jit/optimizer.cpp @@ -5805,7 +5805,7 @@ PhaseStatus Compiler::optVNBasedDeadStoreRemoval() ValueNum oldLclValue = varDsc->GetPerSsaData(defDsc->GetUseDefSsaNum())->m_vnPair.GetConservative(); oldStoreValue = vnStore->VNForLoad(VNK_Conservative, oldLclValue, lvaLclExactSize(lclNum), store->TypeGet(), - store->AsLclFld()->GetLclOffs(), store->AsLclFld()->GetSize(this)); + store->AsLclFld()->GetLclOffs(), store->AsLclFld()->GetSize()); } GenTree* data = store->AsLclVarCommon()->Data(); diff --git a/src/coreclr/jit/promotion.cpp b/src/coreclr/jit/promotion.cpp index 1c50b8a4dd2ea8..119e5ba2eeceaf 100644 --- a/src/coreclr/jit/promotion.cpp +++ b/src/coreclr/jit/promotion.cpp @@ -121,14 +121,14 @@ struct Access { } - unsigned GetAccessSize(Compiler* comp) const + unsigned GetAccessSize() const { - return AccessType == TYP_STRUCT ? Layout->GetSize() : comp->getSizeOfType(AccessType); + return AccessType == TYP_STRUCT ? Layout->GetSize() : genTypeSize(AccessType); } - bool Overlaps(Compiler* comp, unsigned otherStart, unsigned otherSize) const + bool Overlaps(unsigned otherStart, unsigned otherSize) const { - unsigned end = Offset + GetAccessSize(comp); + unsigned end = Offset + GetAccessSize(); if (end <= otherStart) { return false; @@ -196,8 +196,10 @@ inline AccessKindFlags& operator&=(AccessKindFlags& a, AccessKindFlags b) // Returns: // True if any replacement overlaps; otherwise false. // -bool AggregateInfo::OverlappingReplacements( - Compiler* comp, unsigned offset, unsigned size, Replacement** firstReplacement, Replacement** endReplacement) +bool AggregateInfo::OverlappingReplacements(unsigned offset, + unsigned size, + Replacement** firstReplacement, + Replacement** endReplacement) { size_t firstIndex = Promotion::BinarySearch(Replacements, offset); if ((ssize_t)firstIndex < 0) @@ -206,7 +208,7 @@ bool AggregateInfo::OverlappingReplacements( if (firstIndex > 0) { Replacement& lastRepBefore = Replacements[firstIndex - 1]; - if ((lastRepBefore.Offset + comp->getSizeOfType(lastRepBefore.AccessType)) > offset) + if ((lastRepBefore.Offset + genTypeSize(lastRepBefore.AccessType)) > offset) { // Overlap with last entry starting before offs. firstIndex--; @@ -226,7 +228,7 @@ bool AggregateInfo::OverlappingReplacements( } } - assert((firstIndex < Replacements.size()) && Replacements[firstIndex].Overlaps(comp, offset, size)); + assert((firstIndex < Replacements.size()) && Replacements[firstIndex].Overlaps(offset, size)); *firstReplacement = &Replacements[firstIndex]; if (endReplacement != nullptr) @@ -575,13 +577,12 @@ class LocalUses continue; } - if (inducedAccess.Offset + comp->getSizeOfType(inducedAccess.AccessType) <= otherInducedAccess.Offset) + if (inducedAccess.Offset + genTypeSize(inducedAccess.AccessType) <= otherInducedAccess.Offset) { break; } - if (otherInducedAccess.Offset + comp->getSizeOfType(otherInducedAccess.AccessType) <= - inducedAccess.Offset) + if (otherInducedAccess.Offset + genTypeSize(otherInducedAccess.AccessType) <= inducedAccess.Offset) { continue; } @@ -624,9 +625,8 @@ class LocalUses { #ifdef DEBUG Replacement* overlapRep; - assert(!agg->OverlappingReplacements(comp, inducedAccess.Offset, - comp->getSizeOfType(inducedAccess.AccessType), &overlapRep, - nullptr)); + assert(!agg->OverlappingReplacements(inducedAccess.Offset, genTypeSize(inducedAccess.AccessType), + &overlapRep, nullptr)); #endif insertionIndex = @@ -685,7 +685,7 @@ class LocalUses LclVarDsc* lcl = comp->lvaGetDesc(lclNum); ClassLayout* layout = lcl->GetLayout(); - if (layout->IntersectsGCPtr(access.Offset, comp->getSizeOfType(access.AccessType))) + if (layout->IntersectsGCPtr(access.Offset, genTypeSize(access.AccessType))) { if (((access.Offset % TARGET_POINTER_SIZE) != 0) || (layout->GetGCPtrType(access.Offset / TARGET_POINTER_SIZE) != access.AccessType)) @@ -715,7 +715,7 @@ class LocalUses continue; } - if (!otherAccess.Overlaps(comp, access.Offset, comp->getSizeOfType(access.AccessType))) + if (!otherAccess.Overlaps(access.Offset, genTypeSize(access.AccessType))) { continue; } @@ -1302,7 +1302,7 @@ class LocalsUseVisitor : public GenTreeVisitor { #ifdef DEBUG rep.Description = m_compiler->printfAlloc("V%02u.[%03u..%03u)", agg->LclNum, rep.Offset, - rep.Offset + m_compiler->getSizeOfType(rep.AccessType)); + rep.Offset + genTypeSize(rep.AccessType)); #endif rep.LclNum = m_compiler->lvaGrabTemp(false DEBUGARG(rep.Description)); @@ -1321,17 +1321,15 @@ class LocalsUseVisitor : public GenTreeVisitor JITDUMP("V%02u promoted with %d replacements\n", agg->LclNum, (int)reps.size()); for (const Replacement& rep : reps) { - JITDUMP(" [%03u..%03u) promoted as %s V%02u\n", rep.Offset, - rep.Offset + m_compiler->getSizeOfType(rep.AccessType), varTypeName(rep.AccessType), - rep.LclNum); + JITDUMP(" [%03u..%03u) promoted as %s V%02u\n", rep.Offset, rep.Offset + genTypeSize(rep.AccessType), + varTypeName(rep.AccessType), rep.LclNum); } #endif agg->Unpromoted = m_compiler->lvaGetDesc(agg->LclNum)->GetLayout()->GetNonPadding(m_compiler); for (Replacement& rep : reps) { - agg->Unpromoted.Subtract( - SegmentList::Segment(rep.Offset, rep.Offset + m_compiler->getSizeOfType(rep.AccessType))); + agg->Unpromoted.Subtract(SegmentList::Segment(rep.Offset, rep.Offset + genTypeSize(rep.AccessType))); } JITDUMP(" Unpromoted remainder: "); @@ -1402,7 +1400,7 @@ class LocalsUseVisitor : public GenTreeVisitor { LclVarDsc* fieldDsc = m_compiler->lvaGetDesc(fieldLcl); if ((fieldDsc->lvFldOffset >= regPromOffs) && - (fieldDsc->lvFldOffset + m_compiler->getSizeOfType(fieldDsc->lvType) <= (regPromOffs + size))) + (fieldDsc->lvFldOffset + genTypeSize(fieldDsc->lvType) <= (regPromOffs + size))) { InduceAccess(aggregates, candidateLcl->GetLclNum(), candidateLcl->GetLclOffs() + (fieldDsc->lvFldOffset - regPromOffs), fieldDsc->lvType, @@ -1437,12 +1435,12 @@ class LocalsUseVisitor : public GenTreeVisitor { Replacement* firstRep; Replacement* endRep; - if (inducerAgg->OverlappingReplacements(m_compiler, inducerOffs, size, &firstRep, &endRep)) + if (inducerAgg->OverlappingReplacements(inducerOffs, size, &firstRep, &endRep)) { for (Replacement* rep = firstRep; rep < endRep; rep++) { if ((rep->Offset >= inducerOffs) && - (rep->Offset + m_compiler->getSizeOfType(rep->AccessType) <= (inducerOffs + size))) + (rep->Offset + genTypeSize(rep->AccessType) <= (inducerOffs + size))) { InduceAccess(aggregates, candidate->GetLclNum(), candOffs + (rep->Offset - inducerOffs), rep->AccessType, block); @@ -1470,7 +1468,7 @@ class LocalsUseVisitor : public GenTreeVisitor if (agg != nullptr) { Replacement* overlapRep; - if (agg->OverlappingReplacements(m_compiler, offset, m_compiler->getSizeOfType(type), &overlapRep, nullptr)) + if (agg->OverlappingReplacements(offset, genTypeSize(type), &overlapRep, nullptr)) { return; } @@ -1558,16 +1556,15 @@ class LocalsUseVisitor : public GenTreeVisitor // Check if this replacement overlaps the specified range. // // Parameters: -// comp - The compiler // otherStart - Start of the other range. // otherSize - Size of the other range. // // Returns: // True if they overlap. // -bool Replacement::Overlaps(Compiler* comp, unsigned otherStart, unsigned otherSize) const +bool Replacement::Overlaps(unsigned otherStart, unsigned otherSize) const { - unsigned end = Offset + comp->getSizeOfType(AccessType); + unsigned end = Offset + genTypeSize(AccessType); if (end <= otherStart) { return false; @@ -1754,7 +1751,7 @@ void ReplaceVisitor::EndBlock() if (m_liveness->IsReplacementLiveOut(m_currentBlock, agg->LclNum, (unsigned)i)) { JITDUMP("Reading back replacement V%02u.[%03u..%03u) -> V%02u near the end of " FMT_BB ":\n", - agg->LclNum, rep.Offset, rep.Offset + m_compiler->getSizeOfType(rep.AccessType), rep.LclNum, + agg->LclNum, rep.Offset, rep.Offset + genTypeSize(rep.AccessType), rep.LclNum, m_currentBlock->bbNum); GenTree* readBack = Promotion::CreateReadBack(m_compiler, agg->LclNum, rep); @@ -1781,7 +1778,7 @@ void ReplaceVisitor::EndBlock() JITDUMP("Skipping reading back dead replacement V%02u.[%03u..%03u) -> V%02u near the end of " FMT_BB "\n", - agg->LclNum, rep.Offset, rep.Offset + m_compiler->getSizeOfType(rep.AccessType), rep.LclNum, + agg->LclNum, rep.Offset, rep.Offset + genTypeSize(rep.AccessType), rep.LclNum, m_currentBlock->bbNum); } @@ -2007,8 +2004,7 @@ void ReplaceVisitor::InsertPreStatementReadBackIfNecessary(unsigned aggLclNum, R } JITDUMP("Reading back replacement V%02u.[%03u..%03u) -> V%02u before [%06u]:\n", aggLclNum, rep.Offset, - rep.Offset + m_compiler->getSizeOfType(rep.AccessType), rep.LclNum, - Compiler::dspTreeID(m_currentStmt->GetRootNode())); + rep.Offset + genTypeSize(rep.AccessType), rep.LclNum, Compiler::dspTreeID(m_currentStmt->GetRootNode())); GenTree* readBack = Promotion::CreateReadBack(m_compiler, aggLclNum, rep); Statement* stmt = m_compiler->fgNewStmtFromTree(readBack); @@ -2045,7 +2041,7 @@ bool ReplaceVisitor::VisitOverlappingReplacements(unsigned lcl, unsigned offs, u if ((ssize_t)index < 0) { index = ~index; - if ((index > 0) && replacements[index - 1].Overlaps(m_compiler, offs, size)) + if ((index > 0) && replacements[index - 1].Overlaps(offs, size)) { index--; } @@ -2187,7 +2183,7 @@ GenTree** ReplaceVisitor::InsertMidTreeReadBacks(GenTree** use) } JITDUMP(" V%02u.[%03u..%03u) -> V%02u\n", agg->LclNum, rep.Offset, - rep.Offset + m_compiler->getSizeOfType(rep.AccessType), rep.LclNum); + rep.Offset + genTypeSize(rep.AccessType), rep.LclNum); ClearNeedsReadBack(rep); GenTree* readBack = Promotion::CreateReadBack(m_compiler, agg->LclNum, rep); @@ -2317,8 +2313,8 @@ GenTreeFieldList* ReplaceVisitor::CreateFieldListForStructLocal(GenTreeLclVarCom } auto checkPartialOverlap = [=](Replacement& rep) { - bool contained = (rep.Offset >= startOffset) && - (rep.Offset + m_compiler->getSizeOfType(rep.AccessType) <= startOffset + returnValueSize); + bool contained = + (rep.Offset >= startOffset) && (rep.Offset + genTypeSize(rep.AccessType) <= startOffset + returnValueSize); if (contained) { @@ -2624,10 +2620,10 @@ void ReplaceVisitor::ReplaceLocal(GenTree** use, GenTree* user) } #ifdef DEBUG - unsigned accessSize = m_compiler->getSizeOfType(accessType); + unsigned accessSize = genTypeSize(accessType); for (const Replacement& rep : replacements) { - assert(!rep.Overlaps(m_compiler, offs, accessSize) || ((rep.Offset == offs) && (rep.AccessType == accessType))); + assert(!rep.Overlaps(offs, accessSize) || ((rep.Offset == offs) && (rep.AccessType == accessType))); } JITDUMP("Processing primitive use [%06u] of V%02u.[%03u..%03u)\n", Compiler::dspTreeID(lcl), lclNum, offs, @@ -2821,7 +2817,7 @@ void ReplaceVisitor::MarkForReadBack(GenTreeLclVarCommon* lcl, unsigned size DEB if ((ssize_t)index < 0) { index = ~index; - if ((index > 0) && replacements[index - 1].Overlaps(m_compiler, offs, size)) + if ((index > 0) && replacements[index - 1].Overlaps(offs, size)) { index--; } @@ -2841,7 +2837,7 @@ void ReplaceVisitor::MarkForReadBack(GenTreeLclVarCommon* lcl, unsigned size DEB do { Replacement& rep = replacements[index]; - assert(rep.Overlaps(m_compiler, offs, size)); + assert(rep.Overlaps(offs, size)); if (deaths.IsReplacementDying((unsigned)index)) { @@ -3058,7 +3054,7 @@ bool Promotion::MapsToParameterRegister(Compiler* comp, unsigned lclNum, unsigne for (const ABIPassingSegment& seg : abiInfo.Segments()) { // This code corresponds to code in Lower::FindInducedParameterRegisterLocals - if ((offset < seg.Offset) || (offset + comp->getSizeOfType(accessType) > seg.Offset + seg.Size)) + if ((offset < seg.Offset) || (offset + genTypeSize(accessType) > seg.Offset + seg.Size)) { continue; } diff --git a/src/coreclr/jit/promotion.h b/src/coreclr/jit/promotion.h index b75f947e5803e9..db24874ad69992 100644 --- a/src/coreclr/jit/promotion.h +++ b/src/coreclr/jit/promotion.h @@ -37,7 +37,7 @@ struct Replacement { } - bool Overlaps(Compiler* comp, unsigned otherStart, unsigned otherSize) const; + bool Overlaps(unsigned otherStart, unsigned otherSize) const; }; // Represents information about an aggregate that now has replacements in it. @@ -59,8 +59,10 @@ struct AggregateInfo { } - bool OverlappingReplacements( - Compiler* comp, unsigned offset, unsigned size, Replacement** firstReplacement, Replacement** endReplacement); + bool OverlappingReplacements(unsigned offset, + unsigned size, + Replacement** firstReplacement, + Replacement** endReplacement); }; // Map that stores information about promotions made for each local. diff --git a/src/coreclr/jit/promotiondecomposition.cpp b/src/coreclr/jit/promotiondecomposition.cpp index ee6e30b29cc167..4537969099a7f3 100644 --- a/src/coreclr/jit/promotiondecomposition.cpp +++ b/src/coreclr/jit/promotiondecomposition.cpp @@ -271,7 +271,7 @@ class DecompositionPlan { const Entry& entry = m_entries.BottomRef(i); - segments.Subtract(SegmentList::Segment(entry.Offset, entry.Offset + m_compiler->getSizeOfType(entry.Type))); + segments.Subtract(SegmentList::Segment(entry.Offset, entry.Offset + genTypeSize(entry.Type))); } #ifdef DEBUG @@ -931,15 +931,14 @@ class DecompositionPlan for (int i = 0; i < m_entries.Height(); i++) { const Entry& entry = m_entries.BottomRef(i); - if (entry.Offset + m_compiler->getSizeOfType(entry.Type) <= remainderStrategy.PrimitiveOffset) + if (entry.Offset + genTypeSize(entry.Type) <= remainderStrategy.PrimitiveOffset) { // Entry ends before remainder starts continue; } // Remainder ends before entry starts - if (remainderStrategy.PrimitiveOffset + - m_compiler->getSizeOfType(remainderStrategy.PrimitiveType) <= + if (remainderStrategy.PrimitiveOffset + genTypeSize(remainderStrategy.PrimitiveType) <= entry.Offset) { continue; @@ -1024,8 +1023,7 @@ class DecompositionPlan { if (m_addr != nullptr) { - GenTreeIndir* indir = - comp->gtNewIndir(type, GrabAddress(offs, comp), GetIndirFlags(comp->getSizeOfType(type))); + GenTreeIndir* indir = comp->gtNewIndir(type, GrabAddress(offs, comp), GetIndirFlags(type)); return indir; } @@ -1058,8 +1056,7 @@ class DecompositionPlan { if (m_addr != nullptr) { - GenTreeIndir* indir = comp->gtNewStoreIndNode(type, GrabAddress(offs, comp), src, - GetIndirFlags(comp->getSizeOfType(type))); + GenTreeIndir* indir = comp->gtNewStoreIndNode(type, GrabAddress(offs, comp), src, GetIndirFlags(type)); return indir; } @@ -1224,7 +1221,7 @@ class DecompositionPlan { var_types regPromFieldType = m_compiler->lvaGetDesc(srcPromField != BAD_VAR_NUM ? srcPromField : storePromField)->TypeGet(); - if (m_compiler->getSizeOfType(regPromFieldType) == m_compiler->getSizeOfType(primitiveType)) + if (genTypeSize(regPromFieldType) == genTypeSize(primitiveType)) { primitiveType = regPromFieldType; } @@ -1379,7 +1376,7 @@ void ReplaceVisitor::HandleStructStore(GenTree** use, GenTree* user) if (dstEndRep > dstFirstRep) { Replacement* dstLastRep = dstEndRep - 1; - if (dstLastRep->Offset + m_compiler->getSizeOfType(dstLastRep->AccessType) > dstLclOffs + dstLclSize) + if (dstLastRep->Offset + genTypeSize(dstLastRep->AccessType) > dstLclOffs + dstLclSize) { JITDUMP("*** Block operation partially overlaps with end replacement of destination V%02u (%s)\n", dstLastRep->LclNum, dstLastRep->Description); @@ -1420,7 +1417,7 @@ void ReplaceVisitor::HandleStructStore(GenTree** use, GenTree* user) if (srcEndRep > srcFirstRep) { Replacement* srcLastRep = srcEndRep - 1; - if (srcLastRep->Offset + m_compiler->getSizeOfType(srcLastRep->AccessType) > srcLclOffs + srcLclSize) + if (srcLastRep->Offset + genTypeSize(srcLastRep->AccessType) > srcLclOffs + srcLclSize) { JITDUMP("*** Block operation partially overlaps with end replacement of source V%02u (%s)\n", srcLastRep->LclNum, srcLastRep->Description); @@ -1492,7 +1489,7 @@ bool ReplaceVisitor::OverlappingReplacements(GenTreeLclVarCommon* lcl, unsigned offs = lcl->GetLclOffs(); unsigned size = lcl->GetLayout(m_compiler)->GetSize(); - return agg->OverlappingReplacements(m_compiler, offs, size, firstReplacement, endReplacement); + return agg->OverlappingReplacements(offs, size, firstReplacement, endReplacement); } //------------------------------------------------------------------------ @@ -1672,8 +1669,7 @@ void ReplaceVisitor::CopyBetweenFields(GenTree* store, if ((dstRep < dstEndRep) && (srcRep < srcEndRep)) { - if (srcRep->Offset - srcBaseOffs + m_compiler->getSizeOfType(srcRep->AccessType) <= - dstRep->Offset - dstBaseOffs) + if (srcRep->Offset - srcBaseOffs + genTypeSize(srcRep->AccessType) <= dstRep->Offset - dstBaseOffs) { // This source replacement ends before the next destination replacement starts. // Write it directly to the destination struct local. @@ -1685,8 +1681,7 @@ void ReplaceVisitor::CopyBetweenFields(GenTree* store, continue; } - if (dstRep->Offset - dstBaseOffs + m_compiler->getSizeOfType(dstRep->AccessType) <= - srcRep->Offset - srcBaseOffs) + if (dstRep->Offset - dstBaseOffs + genTypeSize(dstRep->AccessType) <= srcRep->Offset - srcBaseOffs) { // Destination replacement ends before the next source replacement starts. // Read it directly from the source struct local. diff --git a/src/coreclr/jit/promotionliveness.cpp b/src/coreclr/jit/promotionliveness.cpp index ca4dd5c426fc61..e137caab827500 100644 --- a/src/coreclr/jit/promotionliveness.cpp +++ b/src/coreclr/jit/promotionliveness.cpp @@ -206,7 +206,7 @@ void PromotionLiveness::MarkUseDef(Statement* stmt, GenTreeLclVarCommon* lcl, Bi if ((ssize_t)index < 0) { index = ~index; - if ((index > 0) && reps[index - 1].Overlaps(m_compiler, offs, size)) + if ((index > 0) && reps[index - 1].Overlaps(offs, size)) { index--; } @@ -214,9 +214,9 @@ void PromotionLiveness::MarkUseDef(Statement* stmt, GenTreeLclVarCommon* lcl, Bi while ((index < reps.size()) && (reps[index].Offset < offs + size)) { - Replacement& rep = reps[index]; - bool isFullFieldDef = isDef && (offs <= rep.Offset) && - (offs + size >= rep.Offset + m_compiler->getSizeOfType(rep.AccessType)); + Replacement& rep = reps[index]; + bool isFullFieldDef = + isDef && (offs <= rep.Offset) && (offs + size >= rep.Offset + genTypeSize(rep.AccessType)); MarkIndex(baseIndex + 1 + (unsigned)index, isUse, isFullFieldDef, useSet, defSet); index++; } @@ -232,7 +232,7 @@ void PromotionLiveness::MarkUseDef(Statement* stmt, GenTreeLclVarCommon* lcl, Bi size_t index = Promotion::BinarySearch(reps, offs); if ((ssize_t)index < 0) { - unsigned size = m_compiler->getSizeOfType(accessType); + unsigned size = genTypeSize(accessType); bool isFullDefOfRemainder = isDef && (agg->UnpromotedMin >= offs) && (agg->UnpromotedMax <= (offs + size)); MarkIndex(baseIndex, isUse, isFullDefOfRemainder, useSet, defSet); } @@ -521,7 +521,7 @@ void PromotionLiveness::FillInLiveness(BitVec& life, BitVec volatileVars, Statem if ((ssize_t)index < 0) { index = ~index; - if ((index > 0) && agg->Replacements[index - 1].Overlaps(m_compiler, offs, size)) + if ((index > 0) && agg->Replacements[index - 1].Overlaps(offs, size)) { index--; } @@ -534,8 +534,8 @@ void PromotionLiveness::FillInLiveness(BitVec& life, BitVec volatileVars, Statem Replacement& rep = agg->Replacements[index]; if (BitVecOps::IsMember(m_bvTraits, life, varIndex)) { - bool isFullFieldDef = isDef && (offs <= rep.Offset) && - (offs + size >= rep.Offset + m_compiler->getSizeOfType(rep.AccessType)); + bool isFullFieldDef = + isDef && (offs <= rep.Offset) && (offs + size >= rep.Offset + genTypeSize(rep.AccessType)); if (isFullFieldDef && !BitVecOps::IsMember(m_bvTraits, volatileVars, varIndex)) { BitVecOps::RemoveElemD(m_bvTraits, life, varIndex); @@ -584,7 +584,7 @@ void PromotionLiveness::FillInLiveness(BitVec& life, BitVec volatileVars, Statem if ((ssize_t)index < 0) { // No replacement found, this is a use of the remainder. - unsigned size = m_compiler->getSizeOfType(accessType); + unsigned size = genTypeSize(accessType); if (BitVecOps::IsMember(m_bvTraits, life, baseIndex)) { lcl->gtFlags &= ~GTF_VAR_DEATH; @@ -758,7 +758,7 @@ void PromotionLiveness::DumpVarSet(BitVec set, BitVec allVars) { const Replacement& rep = agg->Replacements[j - 1]; printf("%sV%02u.[%03u..%03u)", sep, agg->LclNum, rep.Offset, - rep.Offset + m_compiler->getSizeOfType(rep.AccessType)); + rep.Offset + genTypeSize(rep.AccessType)); } sep = " "; } diff --git a/src/coreclr/jit/regset.cpp b/src/coreclr/jit/regset.cpp index 233ab61d395eda..3d9354b040f48e 100644 --- a/src/coreclr/jit/regset.cpp +++ b/src/coreclr/jit/regset.cpp @@ -618,7 +618,7 @@ var_types RegSet::tmpNormalizeType(var_types type) TempDsc* RegSet::tmpGetTemp(var_types type) { type = tmpNormalizeType(type); - unsigned size = m_rsCompiler->getSizeOfType(type); + unsigned size = genTypeSize(type); // If TYP_STRUCT ever gets in here we do bad things (tmpSlot returns -1) noway_assert(size >= sizeof(int)); @@ -680,7 +680,7 @@ TempDsc* RegSet::tmpGetTemp(var_types type) void RegSet::tmpPreAllocateTemps(var_types type, unsigned count) { assert(type == tmpNormalizeType(type)); - unsigned size = m_rsCompiler->getSizeOfType(type); + unsigned size = genTypeSize(type); // If TYP_STRUCT ever gets in here we do bad things (tmpSlot returns -1) noway_assert(size >= sizeof(int)); diff --git a/src/coreclr/jit/simd.cpp b/src/coreclr/jit/simd.cpp index e66cc9f5b9e7ac..18fe8e60c09a7d 100644 --- a/src/coreclr/jit/simd.cpp +++ b/src/coreclr/jit/simd.cpp @@ -119,7 +119,7 @@ unsigned Compiler::getSIMDInitTempVarNum(var_types simdType) lvaSIMDInitTempVarNum = lvaGrabTempWithImplicitUse(false DEBUGARG("SIMDInitTempVar")); lvaTable[lvaSIMDInitTempVarNum].lvType = simdType; } - else if (getSizeOfType(lvaTable[lvaSIMDInitTempVarNum].lvType) < getSizeOfType(simdType)) + else if (genTypeSize(lvaTable[lvaSIMDInitTempVarNum].lvType) < genTypeSize(simdType)) { // We want the largest required type size for the temp. JITDUMP("Increasing SIMDInitTempVar type size from %s to %s\n", @@ -509,21 +509,295 @@ unsigned Compiler::getSizeOfSIMDType(var_types simdType) // CorInfoType Compiler::getBaseJitTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeHnd, unsigned* sizeBytes /*= nullptr */) { - CorInfoType baseType = CORINFO_TYPE_UNDEF; + 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; } - var_types type = getSIMDType(typeHnd, &baseType); + if ((typeHnd == nullptr) || !isIntrinsicType(typeHnd)) + { + return CORINFO_TYPE_UNDEF; + } + + const char* namespaceName; + const char* className = getClassNameFromMetadata(typeHnd, &namespaceName); - if (sizeBytes != nullptr && type != TYP_UNDEF) + // fast path search using cached type handles of important types + CorInfoType simdBaseJitType = CORINFO_TYPE_UNDEF; + unsigned size = 0; + + if (isNumericsNamespace(namespaceName)) { - *sizeBytes = getSizeOfSIMDType(type); + switch (className[0]) + { + case 'P': + { + if (strcmp(className, "Plane") != 0) + { + return CORINFO_TYPE_UNDEF; + } + + JITDUMP(" Known type Plane\n"); + m_simdHandleCache->PlaneHandle = typeHnd; + + simdBaseJitType = CORINFO_TYPE_FLOAT; + size = 4 * genTypeSize(TYP_FLOAT); + break; + } + + case 'Q': + { + if (strcmp(className, "Quaternion") != 0) + { + return CORINFO_TYPE_UNDEF; + } + + JITDUMP(" Known type Quaternion\n"); + m_simdHandleCache->QuaternionHandle = typeHnd; + + simdBaseJitType = CORINFO_TYPE_FLOAT; + size = 4 * genTypeSize(TYP_FLOAT); + break; + } + + case 'V': + { + if (strncmp(className, "Vector", 6) != 0) + { + return CORINFO_TYPE_UNDEF; + } + + switch (className[6]) + { + case '\0': + { + JITDUMP(" Found type Vector\n"); + m_simdHandleCache->VectorHandle = typeHnd; + break; + } + + case '2': + { + if (className[7] != '\0') + { + return CORINFO_TYPE_UNDEF; + } + + JITDUMP(" Found Vector2\n"); + m_simdHandleCache->Vector2Handle = typeHnd; + + simdBaseJitType = CORINFO_TYPE_FLOAT; + size = 2 * genTypeSize(TYP_FLOAT); + break; + } + + case '3': + { + if (className[7] != '\0') + { + return CORINFO_TYPE_UNDEF; + } + + JITDUMP(" Found Vector3\n"); + m_simdHandleCache->Vector3Handle = typeHnd; + + simdBaseJitType = CORINFO_TYPE_FLOAT; + size = 3 * genTypeSize(TYP_FLOAT); + break; + } + + case '4': + { + if (className[7] != '\0') + { + return CORINFO_TYPE_UNDEF; + } + + JITDUMP(" Found Vector4\n"); + m_simdHandleCache->Vector4Handle = typeHnd; + + simdBaseJitType = CORINFO_TYPE_FLOAT; + size = 4 * genTypeSize(TYP_FLOAT); + break; + } + + case '`': + { + if ((className[7] != '1') || (className[8] != '\0')) + { + return CORINFO_TYPE_UNDEF; + } + + CORINFO_CLASS_HANDLE typeArgHnd = info.compCompHnd->getTypeInstantiationArgument(typeHnd, 0); + simdBaseJitType = info.compCompHnd->getTypeForPrimitiveNumericClass(typeArgHnd); + + if ((simdBaseJitType < CORINFO_TYPE_BYTE) || (simdBaseJitType > CORINFO_TYPE_DOUBLE)) + { + return CORINFO_TYPE_UNDEF; + } + + JITDUMP(" Found Vector<%s>\n", varTypeName(JitType2PreciseVarType(simdBaseJitType))); + size = getVectorTByteLength(); + + if (size == 0) + { + return CORINFO_TYPE_UNDEF; + } + break; + } + + default: + { + return CORINFO_TYPE_UNDEF; + } + } + break; + } + + default: + { + return CORINFO_TYPE_UNDEF; + } + } + } +#ifdef FEATURE_HW_INTRINSICS + else + { + size = info.compCompHnd->getClassSize(typeHnd); + + switch (size) + { +#if defined(TARGET_ARM64) + case 8: + { + if (strcmp(className, "Vector64`1") != 0) + { + return CORINFO_TYPE_UNDEF; + } + + CORINFO_CLASS_HANDLE typeArgHnd = info.compCompHnd->getTypeInstantiationArgument(typeHnd, 0); + simdBaseJitType = info.compCompHnd->getTypeForPrimitiveNumericClass(typeArgHnd); + + if ((simdBaseJitType < CORINFO_TYPE_BYTE) || (simdBaseJitType > CORINFO_TYPE_DOUBLE)) + { + return CORINFO_TYPE_UNDEF; + } + + JITDUMP(" Found Vector64<%s>\n", varTypeName(JitType2PreciseVarType(simdBaseJitType))); + break; + } +#endif // TARGET_ARM64 + + case 16: + { + if (strcmp(className, "Vector128`1") != 0) + { + return CORINFO_TYPE_UNDEF; + } + + CORINFO_CLASS_HANDLE typeArgHnd = info.compCompHnd->getTypeInstantiationArgument(typeHnd, 0); + simdBaseJitType = info.compCompHnd->getTypeForPrimitiveNumericClass(typeArgHnd); + + if ((simdBaseJitType < CORINFO_TYPE_BYTE) || (simdBaseJitType > CORINFO_TYPE_DOUBLE)) + { + return CORINFO_TYPE_UNDEF; + } + + JITDUMP(" Found Vector128<%s>\n", varTypeName(JitType2PreciseVarType(simdBaseJitType))); + break; + } + +#if defined(TARGET_XARCH) + case 32: + { + if (strcmp(className, "Vector256`1") != 0) + { + return CORINFO_TYPE_UNDEF; + } + + CORINFO_CLASS_HANDLE typeArgHnd = info.compCompHnd->getTypeInstantiationArgument(typeHnd, 0); + simdBaseJitType = info.compCompHnd->getTypeForPrimitiveNumericClass(typeArgHnd); + + if ((simdBaseJitType < CORINFO_TYPE_BYTE) || (simdBaseJitType > CORINFO_TYPE_DOUBLE)) + { + return CORINFO_TYPE_UNDEF; + } + + if (!compOpportunisticallyDependsOn(InstructionSet_AVX)) + { + // We must treat as a regular struct if AVX isn't supported + return CORINFO_TYPE_UNDEF; + } + + JITDUMP(" Found Vector256<%s>\n", varTypeName(JitType2PreciseVarType(simdBaseJitType))); + break; + } + + case 64: + { + if (strcmp(className, "Vector512`1") != 0) + { + return CORINFO_TYPE_UNDEF; + } + + CORINFO_CLASS_HANDLE typeArgHnd = info.compCompHnd->getTypeInstantiationArgument(typeHnd, 0); + simdBaseJitType = info.compCompHnd->getTypeForPrimitiveNumericClass(typeArgHnd); + + if ((simdBaseJitType < CORINFO_TYPE_BYTE) || (simdBaseJitType > CORINFO_TYPE_DOUBLE)) + { + return CORINFO_TYPE_UNDEF; + } + + if (!compOpportunisticallyDependsOn(InstructionSet_AVX512)) + { + // We must treat as a regular struct if AVX512 isn't supported + return CORINFO_TYPE_UNDEF; + } + + JITDUMP(" Found Vector512<%s>\n", varTypeName(JitType2PreciseVarType(simdBaseJitType))); + break; + } +#endif // TARGET_XARCH + + default: + { + return CORINFO_TYPE_UNDEF; + } + } + } +#endif // FEATURE_HW_INTRINSICS + + if (sizeBytes != nullptr) + { + *sizeBytes = size; + } + + if (simdBaseJitType != CORINFO_TYPE_UNDEF) + { + assert(size == info.compCompHnd->getClassSize(typeHnd)); + setUsesSIMDTypes(true); } - return baseType; + return simdBaseJitType; } //------------------------------------------------------------------------ @@ -794,7 +1068,7 @@ GenTree* Compiler::CreateAddressNodeForSimdHWIntrinsicCreate(GenTree* tree, var_ assert(index->IsCnsIntOrI()); unsigned indexVal = (unsigned)index->AsIntCon()->gtIconVal; - unsigned offset = indexVal * getSizeOfType(tree->TypeGet()); + unsigned offset = indexVal * genTypeSize(tree->TypeGet()); // Generate the boundary check exception. // The length for boundary check should be the maximum index number which should be diff --git a/src/coreclr/jit/targetarm64.cpp b/src/coreclr/jit/targetarm64.cpp index b0af41c001a079..244ffddaaff231 100644 --- a/src/coreclr/jit/targetarm64.cpp +++ b/src/coreclr/jit/targetarm64.cpp @@ -71,7 +71,7 @@ ABIPassingInformation Arm64Classifier::Classify(Compiler* comp, if (hfaType != TYP_UNDEF) { - unsigned elemSize = comp->getSizeOfType(hfaType); + unsigned elemSize = genTypeSize(hfaType); unsigned slots = structLayout->GetSize() / elemSize; ABIPassingInformation info; if (m_floatRegs.Count() >= slots) @@ -122,9 +122,9 @@ ABIPassingInformation Arm64Classifier::Classify(Compiler* comp, } else { - assert(comp->getSizeOfType(type) <= TARGET_POINTER_SIZE); + assert(genTypeSize(type) <= TARGET_POINTER_SIZE); slots = 1; - passedSize = comp->getSizeOfType(type); + passedSize = genTypeSize(type); } assert((slots == 1) || (slots == 2)); @@ -182,7 +182,7 @@ ABIPassingInformation Arm64Classifier::Classify(Compiler* comp, unsigned alignment; if (compAppleArm64Abi()) { - alignment = varTypeIsStruct(type) ? TARGET_POINTER_SIZE : comp->getSizeOfType(type); + alignment = varTypeIsStruct(type) ? TARGET_POINTER_SIZE : genTypeSize(type); m_stackArgSize = roundUp(m_stackArgSize, alignment); segment = alignment < TARGET_POINTER_SIZE ? ABIPassingSegment::OnStackWithoutConsumingFullSlot(m_stackArgSize, 0, passedSize) diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index 1c153a83a30995..d5be462aebe8b4 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -6037,7 +6037,7 @@ ValueNum ValueNumStore::VNForLoadStoreBitCast(ValueNum value, var_types indType, if (typeOfValue != indType) { - assert((typeOfValue == TYP_STRUCT) || (indType == TYP_STRUCT) || (m_pComp->getSizeOfType(indType) == indSize)); + assert((typeOfValue == TYP_STRUCT) || (indType == TYP_STRUCT) || (genTypeSize(indType) == indSize)); value = VNForBitCast(value, indType, indSize); @@ -6249,7 +6249,7 @@ void Compiler::fgValueNumberLocalStore(GenTree* storeNode, { // TYP_STRUCT can represent the general case where the value could be of any size. var_types fieldStoreType = TYP_STRUCT; - if (vnStore->LoadStoreIsEntire(getSizeOfType(fieldVarDsc->TypeGet()), fieldStoreOffset, fieldStoreSize)) + if (vnStore->LoadStoreIsEntire(genTypeSize(fieldVarDsc), fieldStoreOffset, fieldStoreSize)) { // Avoid redundant bitcasts for the common case of a full definition. fieldStoreType = fieldVarDsc->TypeGet(); @@ -6312,9 +6312,8 @@ void Compiler::fgValueNumberArrayElemLoad(GenTree* loadTree, VNFuncApp* addrFunc unsigned elemSize = (elemType == TYP_STRUCT) ? info.compCompHnd->getClassSize(elemTypeEq) : genTypeSize(elemType); var_types loadType = loadTree->TypeGet(); - unsigned loadSize = gtGetSizeOfIndirection(loadTree->AsIndir()); - - ValueNum loadValueVN = vnStore->VNForLoad(VNK_Liberal, wholeElem, elemSize, loadType, offset, loadSize); + unsigned loadSize = loadTree->AsIndir()->Size(); + ValueNum loadValueVN = vnStore->VNForLoad(VNK_Liberal, wholeElem, elemSize, loadType, offset, loadSize); loadTree->gtVNPair.SetLiberal(loadValueVN); @@ -6363,7 +6362,7 @@ void Compiler::fgValueNumberArrayElemStore(GenTree* storeNode, VNFuncApp* addrFu ValueNum hAtArrTypeAtArr = vnStore->VNForMapSelect(VNK_Liberal, TYP_MEM, hAtArrType, arrVN); JITDUMP(" GcHeap[elemTypeEq][array: " FMT_VN "] is " FMT_VN "\n", arrVN, hAtArrTypeAtArr); - unsigned elemSize = (elemType == TYP_STRUCT) ? info.compCompHnd->getClassSize(elemTypeEq) : getSizeOfType(elemType); + unsigned elemSize = (elemType == TYP_STRUCT) ? info.compCompHnd->getClassSize(elemTypeEq) : genTypeSize(elemType); // This is the value that should be stored at "arr[inx]". ValueNum newWholeElem = ValueNumStore::NoVN; @@ -6442,10 +6441,9 @@ void Compiler::fgValueNumberFieldLoad(GenTree* loadTree, GenTree* baseAddr, Fiel ValueNum fieldValueVN = vnStore->VNForMapSelect(VNK_Liberal, fieldType, fieldMapVN, fieldValueSelectorVN); // Finally, account for the struct fields and type mismatches. - var_types loadType = loadTree->TypeGet(); - unsigned loadSize = gtGetSizeOfIndirection(loadTree->AsIndir()); - - ValueNum loadValueVN = vnStore->VNForLoad(VNK_Liberal, fieldValueVN, fieldSize, loadType, offset, loadSize); + var_types loadType = loadTree->TypeGet(); + unsigned loadSize = loadTree->OperIsBlk() ? loadTree->AsBlk()->Size() : genTypeSize(loadTree); + ValueNum loadValueVN = vnStore->VNForLoad(VNK_Liberal, fieldValueVN, fieldSize, loadType, offset, loadSize); loadTree->gtVNPair.SetLiberal(loadValueVN); loadTree->gtVNPair.SetConservative(vnStore->VNForExpr(compCurBB, loadType)); @@ -8930,7 +8928,7 @@ ValueNum ValueNumStore::EvalHWIntrinsicFunBinary( { // TODO-SVE: We shouldn't see this intrinsic operating on Vector after porting to SVE assert(TypeOfVN(arg0VN) == type || (type == TYP_SIMDSV && TypeOfVN(arg0VN) == TYP_SIMD16 && - m_pComp->getSizeOfType(TYP_SIMDSV) == genTypeSize(TYP_SIMD16))); + genTypeSize(TYP_SIMDSV) == genTypeSize(TYP_SIMD16))); assert(TypeOfVN(arg1VN) == TYP_SIMD8); if (!varTypeIsFloating(baseType)) @@ -9180,28 +9178,28 @@ ValueNum ValueNumStore::EvalHWIntrinsicFunBinary( return VNForFunc(type, func, arg0VN, arg1VN, resultTypeVN); } -ValueNum ValueNumStore::EvaluateSimdWithElementFloating( - var_types simdType, var_types baseType, ValueNum arg0VN, int32_t arg1, double arg2) +ValueNum EvaluateSimdWithElementFloating( + ValueNumStore* vns, var_types simdType, var_types baseType, ValueNum arg0VN, int32_t arg1, double arg2) { assert(varTypeIsFloating(baseType)); - assert(IsVNConstant(arg0VN)); - assert(simdType == TypeOfVN(arg0VN)); - assert(static_cast(arg1) < GenTreeVecCon::ElementCount(m_pComp->getSizeOfType(simdType), baseType)); + assert(vns->IsVNConstant(arg0VN)); + assert(simdType == vns->TypeOfVN(arg0VN)); + assert(static_cast(arg1) < GenTreeVecCon::ElementCount(genTypeSize(simdType), baseType)); switch (simdType) { case TYP_SIMD8: { simd8_t result = {}; - EvaluateWithElementFloating(baseType, &result, GetConstantSimd8(arg0VN), arg1, arg2); - return VNForSimd8Con(result); + EvaluateWithElementFloating(baseType, &result, vns->GetConstantSimd8(arg0VN), arg1, arg2); + return vns->VNForSimd8Con(result); } case TYP_SIMD12: { simd12_t result = {}; - EvaluateWithElementFloating(baseType, &result, GetConstantSimd12(arg0VN), arg1, arg2); - return VNForSimd12Con(result); + EvaluateWithElementFloating(baseType, &result, vns->GetConstantSimd12(arg0VN), arg1, arg2); + return vns->VNForSimd12Con(result); } case TYP_SIMD16: @@ -9210,23 +9208,23 @@ ValueNum ValueNumStore::EvaluateSimdWithElementFloating( #endif { simd16_t result = {}; - EvaluateWithElementFloating(baseType, &result, GetConstantSimd16(arg0VN), arg1, arg2); - return VNForSimd16Con(result); + EvaluateWithElementFloating(baseType, &result, vns->GetConstantSimd16(arg0VN), arg1, arg2); + return vns->VNForSimd16Con(result); } #if defined TARGET_XARCH case TYP_SIMD32: { simd32_t result = {}; - EvaluateWithElementFloating(baseType, &result, GetConstantSimd32(arg0VN), arg1, arg2); - return VNForSimd32Con(result); + EvaluateWithElementFloating(baseType, &result, vns->GetConstantSimd32(arg0VN), arg1, arg2); + return vns->VNForSimd32Con(result); } case TYP_SIMD64: { simd64_t result = {}; - EvaluateWithElementFloating(baseType, &result, GetConstantSimd64(arg0VN), arg1, arg2); - return VNForSimd64Con(result); + EvaluateWithElementFloating(baseType, &result, vns->GetConstantSimd64(arg0VN), arg1, arg2); + return vns->VNForSimd64Con(result); } #endif // TARGET_XARCH @@ -9237,28 +9235,28 @@ ValueNum ValueNumStore::EvaluateSimdWithElementFloating( } } -ValueNum ValueNumStore::EvaluateSimdWithElementIntegral( - var_types simdType, var_types baseType, ValueNum arg0VN, int32_t arg1, int64_t arg2) +ValueNum EvaluateSimdWithElementIntegral( + ValueNumStore* vns, var_types simdType, var_types baseType, ValueNum arg0VN, int32_t arg1, int64_t arg2) { assert(varTypeIsIntegral(baseType)); - assert(simdType == TypeOfVN(arg0VN)); - assert(IsVNConstant(arg0VN)); - assert(static_cast(arg1) < GenTreeVecCon::ElementCount(m_pComp->getSizeOfType(simdType), baseType)); + assert(simdType == vns->TypeOfVN(arg0VN)); + assert(vns->IsVNConstant(arg0VN)); + assert(static_cast(arg1) < GenTreeVecCon::ElementCount(genTypeSize(simdType), baseType)); switch (simdType) { case TYP_SIMD8: { simd8_t result = {}; - EvaluateWithElementIntegral(baseType, &result, GetConstantSimd8(arg0VN), arg1, arg2); - return VNForSimd8Con(result); + EvaluateWithElementIntegral(baseType, &result, vns->GetConstantSimd8(arg0VN), arg1, arg2); + return vns->VNForSimd8Con(result); } case TYP_SIMD12: { simd12_t result = {}; - EvaluateWithElementIntegral(baseType, &result, GetConstantSimd12(arg0VN), arg1, arg2); - return VNForSimd12Con(result); + EvaluateWithElementIntegral(baseType, &result, vns->GetConstantSimd12(arg0VN), arg1, arg2); + return vns->VNForSimd12Con(result); } case TYP_SIMD16: @@ -9267,23 +9265,23 @@ ValueNum ValueNumStore::EvaluateSimdWithElementIntegral( #endif { simd16_t result = {}; - EvaluateWithElementIntegral(baseType, &result, GetConstantSimd16(arg0VN), arg1, arg2); - return VNForSimd16Con(result); + EvaluateWithElementIntegral(baseType, &result, vns->GetConstantSimd16(arg0VN), arg1, arg2); + return vns->VNForSimd16Con(result); } #if defined TARGET_XARCH case TYP_SIMD32: { simd32_t result = {}; - EvaluateWithElementIntegral(baseType, &result, GetConstantSimd32(arg0VN), arg1, arg2); - return VNForSimd32Con(result); + EvaluateWithElementIntegral(baseType, &result, vns->GetConstantSimd32(arg0VN), arg1, arg2); + return vns->VNForSimd32Con(result); } case TYP_SIMD64: { simd64_t result = {}; - EvaluateWithElementIntegral(baseType, &result, GetConstantSimd64(arg0VN), arg1, arg2); - return VNForSimd64Con(result); + EvaluateWithElementIntegral(baseType, &result, vns->GetConstantSimd64(arg0VN), arg1, arg2); + return vns->VNForSimd64Con(result); } #endif // TARGET_XARCH @@ -9388,7 +9386,7 @@ ValueNum ValueNumStore::EvalHWIntrinsicFunTernary( int32_t index = GetConstantInt32(arg1VN); - if (static_cast(index) >= GenTreeVecCon::ElementCount(m_pComp->getSizeOfType(type), baseType)) + if (static_cast(index) >= GenTreeVecCon::ElementCount(genTypeSize(type), baseType)) { // Nothing to fold for out of range indexes break; @@ -9406,7 +9404,7 @@ ValueNum ValueNumStore::EvalHWIntrinsicFunTernary( { value = GetConstantDouble(arg2VN); } - return EvaluateSimdWithElementFloating(type, baseType, arg0VN, index, value); + return EvaluateSimdWithElementFloating(this, type, baseType, arg0VN, index, value); } else { @@ -9421,7 +9419,7 @@ ValueNum ValueNumStore::EvalHWIntrinsicFunTernary( { value = GetConstantInt32(arg2VN); } - return EvaluateSimdWithElementIntegral(type, baseType, arg0VN, index, value); + return EvaluateSimdWithElementIntegral(this, type, baseType, arg0VN, index, value); } } @@ -12166,7 +12164,7 @@ void Compiler::fgValueNumberStore(GenTree* store) case GT_STORE_LCL_FLD: { GenTreeLclFld* lclFld = store->AsLclFld(); - fgValueNumberLocalStore(store, lclFld, lclFld->GetLclOffs(), lclFld->GetSize(this), valueVNPair); + fgValueNumberLocalStore(store, lclFld, lclFld->GetLclOffs(), lclFld->GetSize(), valueVNPair); } break; @@ -12186,7 +12184,7 @@ void Compiler::fgValueNumberStore(GenTree* store) GenTreeLclVarCommon* lclVarTree = nullptr; ssize_t offset = 0; - unsigned storeSize = gtGetSizeOfIndirection(store->AsIndir()); + unsigned storeSize = store->AsIndir()->Size(); GenTree* baseAddr = nullptr; FieldSeq* fldSeq = nullptr; @@ -12255,7 +12253,7 @@ void Compiler::fgValueNumberSsaVarDef(GenTreeLclVarCommon* lcl) // Account for type mismatches. if (genActualType(varDsc) != genActualType(lcl)) { - if (getSizeOfType(varDsc->TypeGet()) != getSizeOfType(lcl->TypeGet())) + if (genTypeSize(varDsc) != genTypeSize(lcl)) { assert(varDsc->TypeIs(TYP_LONG) && lcl->TypeIs(TYP_INT)); lcl->gtVNPair = vnStore->VNPairForCast(wholeLclVarVNP, lcl->TypeGet(), varDsc->TypeGet()); @@ -12469,7 +12467,7 @@ bool Compiler::fgValueNumberConstLoad(GenTreeIndir* tree) ssize_t byteOffset = 0; FieldSeq* fieldSeq = nullptr; CORINFO_OBJECT_HANDLE obj = nullptr; - int size = (int)gtGetSizeOfIndirection(tree); + int size = (int)genTypeSize(tree->TypeGet()); const int maxElementSize = sizeof(simd_t); if (!tree->TypeIs(TYP_BYREF, TYP_STRUCT) && @@ -12652,7 +12650,7 @@ void Compiler::fgValueNumberTree(GenTree* tree) { ValueNumPair lclVarValue = varDsc->GetPerSsaData(lclFld->GetSsaNum())->m_vnPair; lclFld->gtVNPair = vnStore->VNPairForLoad(lclVarValue, lvaLclExactSize(lclNum), lclFld->TypeGet(), - lclFld->GetLclOffs(), lclFld->GetSize(this)); + lclFld->GetLclOffs(), lclFld->GetSize()); } else if (varDsc->IsAddressExposed()) { @@ -12835,7 +12833,7 @@ void Compiler::fgValueNumberTree(GenTree* tree) { var_types loadType = tree->TypeGet(); ssize_t offset = 0; - unsigned loadSize = gtGetSizeOfIndirection(tree->AsIndir()); + unsigned loadSize = tree->AsIndir()->Size(); VNFuncApp funcApp{VNF_COUNT}; if (fgValueNumberConstLoad(tree->AsIndir())) @@ -13562,8 +13560,7 @@ ValueNum ValueNumStore::VNForCast(ValueNum srcVN, // For integral unchecked casts, only the "int -> long" upcasts use // "srcIsUnsigned", to decide whether to use sign or zero extension. - if (!hasOverflowCheck && !varTypeIsFloating(castToType) && - (m_pComp->getSizeOfType(castToType) <= m_pComp->getSizeOfType(castFromType))) + if (!hasOverflowCheck && !varTypeIsFloating(castToType) && (genTypeSize(castToType) <= genTypeSize(castFromType))) { srcIsUnsigned = false; } @@ -13658,7 +13655,7 @@ ValueNum ValueNumStore::EncodeBitCastType(var_types castToType, unsigned size) { if (castToType != TYP_STRUCT) { - assert(size == m_pComp->getSizeOfType(castToType)); + assert(size == genTypeSize(castToType)); return VNForIntCon(castToType); } diff --git a/src/coreclr/jit/valuenum.h b/src/coreclr/jit/valuenum.h index e39cdc226ca741..77af89db114c84 100644 --- a/src/coreclr/jit/valuenum.h +++ b/src/coreclr/jit/valuenum.h @@ -404,10 +404,6 @@ class ValueNumStore ValueNum EvalUsingMathIdentity(var_types typ, VNFunc vnf, ValueNum vn0, ValueNum vn1); - ValueNum EvaluateSimdWithElementIntegral( - var_types simdType, var_types baseType, ValueNum arg0VN, int32_t arg1, int64_t arg2); - ValueNum EvaluateSimdWithElementFloating( - var_types simdType, var_types baseType, ValueNum arg0VN, int32_t arg1, double arg2); // This is the constant value used for the default value of m_mapSelectBudget #define DEFAULT_MAP_SELECT_BUDGET 100 // used by JitVNMapSelBudget diff --git a/src/coreclr/vm/callingconvention.h b/src/coreclr/vm/callingconvention.h index 560716689256b4..3cb6dc07784324 100644 --- a/src/coreclr/vm/callingconvention.h +++ b/src/coreclr/vm/callingconvention.h @@ -64,7 +64,7 @@ struct ArgLocDesc case CORINFO_HFA_ELEM_DOUBLE: return 8; case CORINFO_HFA_ELEM_VECTOR64: return 8; case CORINFO_HFA_ELEM_VECTOR128: return 16; - case CORINFO_HFA_ELEM_VECTORT: return g_vectorTByteLength; + case CORINFO_HFA_ELEM_VECTORT: return EEJitManager::GetSizeOfVectorT(); default: _ASSERTE(!"Invalid HFA Type"); return 0; } } diff --git a/src/coreclr/vm/class.cpp b/src/coreclr/vm/class.cpp index 6641522bb8b1be..d801f4e1aca432 100644 --- a/src/coreclr/vm/class.cpp +++ b/src/coreclr/vm/class.cpp @@ -1699,7 +1699,7 @@ CorInfoHFAElemType MethodTable::GetVectorHFA() { _ASSERTE(strcmp(namespaceName, "System.Numerics") == 0); #ifdef TARGET_ARM64 - hfaType = g_vectorTIsScalable ? CORINFO_HFA_ELEM_VECTORT : CORINFO_HFA_ELEM_VECTOR128; + hfaType = ExecutionManager::GetEEJitManager()->UseScalableVectorT() ? CORINFO_HFA_ELEM_VECTORT : CORINFO_HFA_ELEM_VECTOR128; #else switch (GetNumInstanceFieldBytes()) { @@ -1950,7 +1950,7 @@ EEClass::CheckForHFA() elemSize = 16; break; case CORINFO_HFA_ELEM_VECTORT: - elemSize = g_vectorTByteLength; + elemSize = EEJitManager::GetSizeOfVectorT(); _ASSERTE(elemSize != 0); break; #endif diff --git a/src/coreclr/vm/classlayoutinfo.cpp b/src/coreclr/vm/classlayoutinfo.cpp index 24dc69349d117b..61665628d13f81 100644 --- a/src/coreclr/vm/classlayoutinfo.cpp +++ b/src/coreclr/vm/classlayoutinfo.cpp @@ -1187,7 +1187,7 @@ CorInfoHFAElemType EEClassNativeLayoutInfo::GetNativeHFATypeRaw() const case CORINFO_HFA_ELEM_VECTOR64: elemSize = 8; break; case CORINFO_HFA_ELEM_VECTOR128: elemSize = 16; break; case CORINFO_HFA_ELEM_VECTORT: - elemSize = g_vectorTByteLength; + elemSize = EEJitManager::GetSizeOfVectorT(); _ASSERTE(elemSize != 0); break; #endif diff --git a/src/coreclr/vm/codeman.cpp b/src/coreclr/vm/codeman.cpp index 6fb98db256f327..3fe0aaf192bb89 100644 --- a/src/coreclr/vm/codeman.cpp +++ b/src/coreclr/vm/codeman.cpp @@ -1139,8 +1139,6 @@ EECodeGenManager::EECodeGenManager() EEJitManager::EEJitManager() : m_CPUCompileFlags() , m_JitLoadLock( CrstSingleUseLock ) - , m_vectorTByteLength(0) - , m_useScalableVectorT(false) { CONTRACTL { THROWS; @@ -1548,40 +1546,6 @@ void EEJitManager::SetCpuInfo() #endif // TARGET_X86 || TARGET_AMD64 m_CPUCompileFlags = CPUCompileFlags; - - g_vectorTIsScalable = false; - g_vectorTByteLength = 0; - -#if defined(TARGET_X86) || defined(TARGET_AMD64) - if (m_CPUCompileFlags.IsSet(InstructionSet_VectorT512)) - { - g_vectorTByteLength = 64; - } - else if (m_CPUCompileFlags.IsSet(InstructionSet_VectorT256)) - { - g_vectorTByteLength = 32; - } - else if (m_CPUCompileFlags.IsSet(InstructionSet_VectorT128)) - { - g_vectorTByteLength = 16; - } -#elif defined(TARGET_ARM64) - if (m_CPUCompileFlags.IsSet(InstructionSet_VectorT128)) - { - g_vectorTByteLength = 16; - } - - if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_JitUseScalableVectorT) - && m_CPUCompileFlags.IsSet(InstructionSet_Sve_Arm64)) - { - uint64_t sveLengthFromOS = GetSveLengthFromOS(); - if (sveLengthFromOS != 0) - { - g_vectorTIsScalable = true; - g_vectorTByteLength = static_cast(sveLengthFromOS); - } - } -#endif } // Define some data that we can use to get a better idea of what happened when we get a Watson dump that indicates the JIT failed to load. diff --git a/src/coreclr/vm/codeman.h b/src/coreclr/vm/codeman.h index f65b3af8c0077e..cdaf5574eb0e45 100644 --- a/src/coreclr/vm/codeman.h +++ b/src/coreclr/vm/codeman.h @@ -2188,6 +2188,24 @@ class EEJitManager final : public EECodeGenManager return m_CPUCompileFlags; } + inline bool UseScalableVectorT() + { + LIMITED_METHOD_CONTRACT; +#ifdef TARGET_ARM64 + // Vector length discovery is currently dependent on running directly on Arm64. + return CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_JitUseScalableVectorT) + && m_CPUCompileFlags.IsSet(InstructionSet_Sve_Arm64); +#else + return false; +#endif + } + + static uint32_t GetSizeOfVectorT() + { + LIMITED_METHOD_CONTRACT; + return CoreLibBinder::GetClass(CLASS__VECTORT)->GetNumInstanceFieldBytes(); + } + private : Crst m_JitLoadLock; @@ -2225,9 +2243,6 @@ private : bool m_AltJITRequired; #endif //ALLOW_SXS_JIT - uint32_t m_vectorTByteLength; - bool m_useScalableVectorT; - friend struct ::cdac_data; }; diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.inc b/src/coreclr/vm/datadescriptor/datadescriptor.inc index 445ce1c648b2f2..e84411a6fc338b 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -1028,8 +1028,6 @@ CDAC_GLOBAL(PtrArrayOffsetToDataArray, uintptr_t, offsetof(PtrArray, m_Array)) CDAC_GLOBAL(NumberOfTlsOffsetsNotUsedInNoncollectibleArray, uint8, NUMBER_OF_TLSOFFSETS_NOT_USED_IN_NONCOLLECTIBLE_ARRAY) CDAC_GLOBAL(MaxClrNotificationArgs, uint32, MAX_CLR_NOTIFICATION_ARGS) CDAC_GLOBAL(FieldOffsetBigRVA, uint32, FIELD_OFFSET_BIG_RVA) -CDAC_GLOBAL_POINTER(VectorTByteLength, &::g_vectorTByteLength) -CDAC_GLOBAL_POINTER(VectorTIsScalable, &::g_vectorTIsScalable) CDAC_GLOBAL_POINTER(ClrNotificationArguments, &::g_clrNotificationArguments) CDAC_GLOBAL_POINTER(ArrayBoundsZero, cdac_data::ArrayBoundsZero) CDAC_GLOBAL_POINTER(ExceptionMethodTable, &::g_pExceptionClass) diff --git a/src/coreclr/vm/methodtablebuilder.cpp b/src/coreclr/vm/methodtablebuilder.cpp index 3b6707d31aead9..8854cece09042d 100644 --- a/src/coreclr/vm/methodtablebuilder.cpp +++ b/src/coreclr/vm/methodtablebuilder.cpp @@ -1157,6 +1157,10 @@ MethodTableBuilder::CopyParentVtable() } } +#ifdef TARGET_ARM64 +extern "C" uint64_t GetSveLengthFromOS(); +#endif + //******************************************************************************* // Determine if this is the special SIMD type System.Numerics.Vector, whose // size is determined dynamically based on the hardware and the presence of JIT @@ -1185,7 +1189,29 @@ BOOL MethodTableBuilder::CheckIfSIMDAndUpdateSize() if (strcmp(className, "Vector`1") != 0 || strcmp(nameSpace, "System.Numerics") != 0) return false; - uint32_t vectorTSize = g_vectorTByteLength; + uint32_t vectorTSize = 0; + CORJIT_FLAGS CPUCompileFlags = ExecutionManager::GetEEJitManager()->GetCPUCompileFlags(); + +#if defined(TARGET_X86) || defined(TARGET_AMD64) + if (CPUCompileFlags.IsSet(InstructionSet_VectorT512)) + { + vectorTSize = 64; + } + else if (CPUCompileFlags.IsSet(InstructionSet_VectorT256)) + { + vectorTSize = 32; + } +#elif defined(TARGET_ARM64) + if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_JitUseScalableVectorT) + && CPUCompileFlags.IsSet(InstructionSet_Sve_Arm64)) + { + vectorTSize = (uint32_t) GetSveLengthFromOS(); + } + else if (CPUCompileFlags.IsSet(InstructionSet_VectorT128)) + { + vectorTSize = 16; + } +#endif if (vectorTSize > 0 && vectorTSize != 16) { diff --git a/src/coreclr/vm/vars.cpp b/src/coreclr/vm/vars.cpp index 39510667c9a050..c5546edcb2c487 100644 --- a/src/coreclr/vm/vars.cpp +++ b/src/coreclr/vm/vars.cpp @@ -101,8 +101,6 @@ GVAL_IMPL_INIT(DWORD, g_debuggerWordTLSIndex, TLS_OUT_OF_INDEXES); GVAL_IMPL_INIT(DWORD, g_TlsIndex, TLS_OUT_OF_INDEXES); GVAL_IMPL_INIT(DWORD, g_offsetOfCurrentThreadInfo, 0); GVAL_IMPL_INIT(DWORD, g_gcNotificationFlags, 0); -GVAL_IMPL_INIT(DWORD, g_vectorTByteLength, 0); -GVAL_IMPL_INIT(BOOL, g_vectorTIsScalable, 0); MethodTable* g_pCastHelpers; diff --git a/src/coreclr/vm/vars.hpp b/src/coreclr/vm/vars.hpp index a57d8cd0177168..08988b342e784b 100644 --- a/src/coreclr/vm/vars.hpp +++ b/src/coreclr/vm/vars.hpp @@ -364,8 +364,6 @@ GVAL_DECL(DWORD, g_debuggerWordTLSIndex); GVAL_DECL(DWORD, g_TlsIndex); GVAL_DECL(DWORD, g_offsetOfCurrentThreadInfo); GVAL_DECL(DWORD, g_gcNotificationFlags); -GVAL_DECL(DWORD, g_vectorTByteLength); -GVAL_DECL(BOOL, g_vectorTIsScalable); #ifdef FEATURE_EH_FUNCLETS GPTR_DECL(MethodTable, g_pEHClass); From b950fa53eff4aff4b9db086390fce683d79dd9ec Mon Sep 17 00:00:00 2001 From: Sebastian Nickolls Date: Thu, 6 Nov 2025 09:46:59 +0000 Subject: [PATCH 10/12] Fix merge issues, replayed commits --- src/coreclr/jit/compiler.h | 4 + src/coreclr/jit/gentree.cpp | 144 ++++++-------- src/coreclr/jit/hwintrinsic.cpp | 35 +--- src/coreclr/jit/hwintrinsicarm64.cpp | 4 +- src/coreclr/jit/importer.cpp | 10 +- src/coreclr/jit/lclvars.cpp | 11 +- src/coreclr/jit/simd.cpp | 284 +-------------------------- 7 files changed, 93 insertions(+), 399 deletions(-) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 05f97d4b14fcd9..7ce47980a26811 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -9087,6 +9087,10 @@ class Compiler return isSIMDClass(clsHnd) || isHWSIMDClass(clsHnd); } + var_types getSIMDType(CORINFO_CLASS_HANDLE typeHnd, CorInfoType* baseType = nullptr); + + unsigned getSizeOfSIMDType(var_types simdType); + // Get the base (element) type and size in bytes for a SIMD type. Returns CORINFO_TYPE_UNDEF // if it is not a SIMD type or is an unsupported base JIT type. CorInfoType getBaseJitTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeHnd, unsigned* sizeBytes = nullptr); diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 79c4a5c2459a62..4c0c24454212fd 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -20946,7 +20946,7 @@ GenTreeHWIntrinsic* Compiler::gtNewSimdHWIntrinsicNode(var_types ty GenTree* Compiler::gtNewSimdAbsNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeGet() == type); @@ -21039,7 +21039,7 @@ GenTree* Compiler::gtNewSimdBinOpNode( genTreeOps op, var_types type, GenTree* op1, GenTree* op2, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType); assert(varTypeIsArithmetic(simdBaseType)); @@ -21753,7 +21753,7 @@ GenTree* Compiler::gtNewSimdBinOpNode( GenTree* Compiler::gtNewSimdCeilNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -21833,7 +21833,7 @@ GenTree* Compiler::gtNewSimdCvtNode(var_types type, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -21969,7 +21969,7 @@ GenTree* Compiler::gtNewSimdCvtNativeNode(var_types type, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -22221,7 +22221,7 @@ GenTree* Compiler::gtNewSimdCmpOpNode( genTreeOps op, var_types type, GenTree* op1, GenTree* op2, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -22510,12 +22510,11 @@ GenTree* Compiler::gtNewSimdCmpOpAllNode( genTreeOps op, var_types type, GenTree* op1, GenTree* op2, CorInfoType simdBaseJitType, unsigned simdSize) { assert(type == TYP_INT); + assert(op1 != nullptr); - var_types simdType = getSIMDTypeForSize(simdSize); + var_types simdType = op1->TypeGet(); assert(varTypeIsSIMD(simdType)); - - assert(op1 != nullptr); - assert(op1->TypeIs(simdType)); + assert(getSizeOfSIMDType(simdType) == simdSize); assert(op2 != nullptr); assert(op2->TypeIs(simdType)); @@ -22645,11 +22644,10 @@ GenTree* Compiler::gtNewSimdCmpOpAnyNode( { assert(type == TYP_INT); - var_types simdType = getSIMDTypeForSize(simdSize); - assert(varTypeIsSIMD(simdType)); - assert(op1 != nullptr); - assert(op1->TypeIs(simdType)); + var_types simdType = op1->TypeGet(); + assert(varTypeIsSIMD(simdType)); + assert(getSizeOfSIMDType(simdType) == simdSize); assert(op2 != nullptr); assert(op2->TypeIs(simdType)); @@ -22775,7 +22773,7 @@ GenTree* Compiler::gtNewSimdCndSelNode( var_types type, GenTree* op1, GenTree* op2, GenTree* op3, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -23200,7 +23198,7 @@ GenTree* Compiler::gtNewSimdCreateSequenceNode( // is constant than there isn't any real optimization we can do and we need the full computation. assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType); assert(varTypeIsArithmetic(simdBaseType)); @@ -23371,14 +23369,14 @@ GenTree* Compiler::gtNewSimdCreateSequenceNode( GenTree* Compiler::gtNewSimdDotProdNode( var_types type, GenTree* op1, GenTree* op2, CorInfoType simdBaseJitType, unsigned simdSize) { - var_types simdType = getSIMDTypeForSize(simdSize); - assert(varTypeIsSIMD(simdType)); + assert(varTypeIsSIMD(type)); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); - assert(op1->TypeIs(simdType)); + assert(op1->TypeIs(type)); assert(op2 != nullptr); - assert(op2->TypeIs(simdType)); + assert(op2->TypeIs(type)); var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType); assert(varTypeIsSIMD(type)); @@ -23412,7 +23410,7 @@ GenTree* Compiler::gtNewSimdDotProdNode( GenTree* Compiler::gtNewSimdFloorNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -23457,7 +23455,7 @@ GenTree* Compiler::gtNewSimdFmaNode( var_types type, GenTree* op1, GenTree* op2, GenTree* op3, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -23572,7 +23570,7 @@ GenTree* Compiler::gtNewSimdGetElementNode( GenTree* Compiler::gtNewSimdGetIndicesNode(var_types type, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType); assert(varTypeIsArithmetic(simdBaseType)); @@ -23725,7 +23723,7 @@ GenTree* Compiler::gtNewSimdIsEvenIntegerNode(var_types type, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -23752,7 +23750,7 @@ GenTree* Compiler::gtNewSimdIsEvenIntegerNode(var_types type, GenTree* Compiler::gtNewSimdIsFiniteNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -23803,7 +23801,7 @@ GenTree* Compiler::gtNewSimdIsFiniteNode(var_types type, GenTree* op1, CorInfoTy GenTree* Compiler::gtNewSimdIsInfinityNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -23834,7 +23832,7 @@ GenTree* Compiler::gtNewSimdIsInfinityNode(var_types type, GenTree* op1, CorInfo GenTree* Compiler::gtNewSimdIsIntegerNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -23874,7 +23872,7 @@ GenTree* Compiler::gtNewSimdIsIntegerNode(var_types type, GenTree* op1, CorInfoT GenTree* Compiler::gtNewSimdIsNaNNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -23905,7 +23903,7 @@ GenTree* Compiler::gtNewSimdIsNaNNode(var_types type, GenTree* op1, CorInfoType GenTree* Compiler::gtNewSimdIsNegativeNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -23947,7 +23945,7 @@ GenTree* Compiler::gtNewSimdIsNegativeInfinityNode(var_types type, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -23995,7 +23993,7 @@ GenTree* Compiler::gtNewSimdIsNegativeInfinityNode(var_types type, GenTree* Compiler::gtNewSimdIsNormalNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -24058,7 +24056,7 @@ GenTree* Compiler::gtNewSimdIsOddIntegerNode(var_types type, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -24085,7 +24083,7 @@ GenTree* Compiler::gtNewSimdIsOddIntegerNode(var_types type, GenTree* Compiler::gtNewSimdIsPositiveNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -24127,7 +24125,7 @@ GenTree* Compiler::gtNewSimdIsPositiveInfinityNode(var_types type, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -24178,7 +24176,7 @@ GenTree* Compiler::gtNewSimdIsSubnormalNode(var_types type, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -24235,7 +24233,7 @@ GenTree* Compiler::gtNewSimdIsSubnormalNode(var_types type, GenTree* Compiler::gtNewSimdIsZeroNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -24261,7 +24259,7 @@ GenTree* Compiler::gtNewSimdIsZeroNode(var_types type, GenTree* op1, CorInfoType GenTree* Compiler::gtNewSimdLoadNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); @@ -24456,7 +24454,7 @@ GenTree* Compiler::gtNewSimdMinMaxNode(var_types type, else if (!varTypeIsLong(simdBaseType)) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); } NamedIntrinsic intrinsic = NI_Illegal; @@ -25098,7 +25096,7 @@ GenTree* Compiler::gtNewSimdMinMaxNativeNode( else { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); } NamedIntrinsic intrinsic = NI_Illegal; @@ -25211,7 +25209,7 @@ GenTree* Compiler::gtNewSimdNarrowNode( var_types type, GenTree* op1, GenTree* op2, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -25683,7 +25681,7 @@ GenTree* Compiler::gtNewSimdNarrowNode( GenTree* Compiler::gtNewSimdRoundNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -25744,7 +25742,7 @@ GenTree* Compiler::gtNewSimdShuffleVariableNode( var_types type, GenTree* op1, GenTree* op2, CorInfoType simdBaseJitType, unsigned simdSize, bool isShuffleNative) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -26347,7 +26345,7 @@ GenTree* Compiler::gtNewSimdShuffleNode( var_types type, GenTree* op1, GenTree* op2, CorInfoType simdBaseJitType, unsigned simdSize, bool isShuffleNative) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -26930,7 +26928,7 @@ GenTree* Compiler::gtNewSimdShuffleNode( GenTree* Compiler::gtNewSimdSqrtNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -26988,7 +26986,7 @@ GenTree* Compiler::gtNewSimdStoreNode(GenTree* op1, GenTree* op2, CorInfoType si assert(op2 != nullptr); assert(varTypeIsSIMD(op2)); - assert(getSIMDTypeForSize(simdSize) == op2->TypeGet()); + assert(getSizeOfSIMDType(op2->TypeGet()) == simdSize); var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType); assert(varTypeIsArithmetic(simdBaseType)); @@ -27105,11 +27103,10 @@ GenTree* Compiler::gtNewSimdStoreNonTemporalNode(GenTree* op1, GenTree* Compiler::gtNewSimdSumNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { - var_types simdType = getSIMDTypeForSize(simdSize); - assert(varTypeIsSIMD(simdType)); - assert(op1 != nullptr); - assert(op1->TypeIs(simdType)); + var_types simdType = op1->TypeGet(); + assert(varTypeIsSIMD(simdType)); + assert(getSizeOfSIMDType(simdType) == simdSize); var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType); assert(varTypeIsArithmetic(simdBaseType)); @@ -27437,7 +27434,7 @@ GenTree* Compiler::gtNewSimdToScalarNode(var_types type, GenTree* op1, CorInfoTy GenTree* Compiler::gtNewSimdTruncNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -27482,7 +27479,7 @@ GenTree* Compiler::gtNewSimdUnOpNode( genTreeOps op, var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -27577,7 +27574,7 @@ GenTree* Compiler::gtNewSimdUnOpNode( GenTree* Compiler::gtNewSimdWidenLowerNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -27779,7 +27776,7 @@ GenTree* Compiler::gtNewSimdWidenLowerNode(var_types type, GenTree* op1, CorInfo GenTree* Compiler::gtNewSimdWidenUpperNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSIMDTypeForSize(simdSize) == type); + assert(getSizeOfSIMDType(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -28105,15 +28102,15 @@ GenTreeFieldList* Compiler::gtConvertParamOpToFieldList(GenTree* op, unsigned fi unsigned fieldSize = opVarDsc->lvExactSize() / fieldCount; GenTreeFieldList* fieldList = new (this, GT_FIELD_LIST) GenTreeFieldList(); int offset = 0; - unsigned sizeBytes = 0; CORINFO_CLASS_HANDLE structType; for (unsigned fieldId = 0; fieldId < fieldCount; fieldId++) { CORINFO_FIELD_HANDLE fieldHandle = info.compCompHnd->getFieldInClass(clsHnd, fieldId); JitType2PreciseVarType(info.compCompHnd->getFieldType(fieldHandle, &structType)); - getBaseJitTypeAndSizeOfSIMDType(structType, &sizeBytes); - var_types simdType = getSIMDTypeForSize(sizeBytes); + + unsigned int size = info.compCompHnd->getClassSize(structType); + var_types simdType = getSIMDTypeForSize(size); GenTreeLclFld* fldNode = gtNewLclFldNode(lclNum, simdType, offset); fieldList->AddField(this, fldNode, offset, simdType); @@ -29653,10 +29650,8 @@ genTreeOps GenTreeHWIntrinsic::GetOperForHWIntrinsicId(NamedIntrinsic id, var_ty NamedIntrinsic GenTreeHWIntrinsic::GetHWIntrinsicIdForUnOp( Compiler* comp, genTreeOps oper, GenTree* op1, var_types simdBaseType, unsigned simdSize, bool isScalar) { - var_types simdType = comp->getSIMDTypeForSize(simdSize); assert(varTypeIsArithmetic(simdBaseType)); - assert(varTypeIsSIMD(simdType)); #if defined(TARGET_XARCH) if ((simdSize == 64) || (simdSize == 32)) @@ -29674,7 +29669,9 @@ NamedIntrinsic GenTreeHWIntrinsic::GetHWIntrinsicIdForUnOp( } assert(op1 != nullptr); - assert(op1->TypeIs(simdType)); + var_types simdType = op1->TypeGet(); + assert(varTypeIsSIMD(simdType)); + assert(comp->getSizeOfSIMDType(simdType) == simdSize); NamedIntrinsic id = NI_Illegal; @@ -29747,13 +29744,12 @@ NamedIntrinsic GenTreeHWIntrinsic::GetHWIntrinsicIdForBinOp(Compiler* comp, unsigned simdSize, bool isScalar) { - var_types simdType = comp->getSIMDTypeForSize(simdSize); - assert(varTypeIsArithmetic(simdBaseType)); - assert(varTypeIsSIMD(simdType)); assert(op1 != nullptr); - assert(op1->TypeIs(simdType)); + var_types simdType = op1->TypeGet(); + assert(varTypeIsSIMD(simdType)); + assert(comp->getSizeOfSIMDType(simdType) == simdSize); assert(op2 != nullptr); #if defined(TARGET_XARCH) @@ -30321,16 +30317,14 @@ NamedIntrinsic GenTreeHWIntrinsic::GetHWIntrinsicIdForCmpOp(Compiler* comp, bool isScalar, bool reverseCond) { - var_types simdType = comp->getSIMDTypeForSize(simdSize); + assert(op1 != nullptr); + assert(op2 != nullptr); + var_types simdType = op1->TypeGet(); + assert(comp->getSizeOfSIMDType(simdType) == simdSize); assert(varTypeIsMask(type) || (type == simdType)); - assert(varTypeIsArithmetic(simdBaseType)); assert(varTypeIsSIMD(simdType)); - assert(op1 != nullptr); - assert(op1->TypeIs(simdType)); - assert(op2 != nullptr); - #if defined(TARGET_XARCH) if (varTypeIsMask(type)) { @@ -30662,11 +30656,9 @@ NamedIntrinsic GenTreeHWIntrinsic::GetHWIntrinsicIdForCmpOp(Compiler* comp, var_types GenTreeHWIntrinsic::GetLookupTypeForCmpOp( Compiler* comp, genTreeOps oper, var_types type, var_types simdBaseType, unsigned simdSize, bool reverseCond) { - var_types simdType = comp->getSIMDTypeForSize(simdSize); - assert(varTypeIsMask(type) || (type == simdType)); - + assert(varTypeIsMask(type) || varTypeIsSIMD(type)); assert(varTypeIsArithmetic(simdBaseType)); - assert(varTypeIsSIMD(simdType)); + assert(comp->getSizeOfSIMDType(type) == simdSize); var_types lookupType = type; @@ -32507,8 +32499,6 @@ GenTree* Compiler::gtFoldExprHWIntrinsic(GenTreeHWIntrinsic* tree) case NI_Vector512_ToScalar: #endif { - var_types simdType = getSIMDTypeForSize(simdSize); - if (varTypeIsFloating(retType)) { double result = cnsNode->AsVecCon()->ToScalarFloating(simdBaseType); @@ -32768,8 +32758,6 @@ GenTree* Compiler::gtFoldExprHWIntrinsic(GenTreeHWIntrinsic* tree) break; } - var_types simdType = getSIMDTypeForSize(simdSize); - if (varTypeIsFloating(retType)) { double result = cnsNode->AsVecCon()->GetElementFloating(simdBaseType, index); @@ -33713,8 +33701,6 @@ GenTree* Compiler::gtFoldExprHWIntrinsic(GenTreeHWIntrinsic* tree) break; } - var_types simdType = getSIMDTypeForSize(simdSize); - if (varTypeIsFloating(simdBaseType)) { double value = op3->AsDblCon()->DconValue(); diff --git a/src/coreclr/jit/hwintrinsic.cpp b/src/coreclr/jit/hwintrinsic.cpp index 83909542992db3..5a4ed811abdcc1 100644 --- a/src/coreclr/jit/hwintrinsic.cpp +++ b/src/coreclr/jit/hwintrinsic.cpp @@ -1502,9 +1502,7 @@ GenTree* Compiler::getArgForHWIntrinsic(var_types argType, CORINFO_CLASS_HANDLE { if (!varTypeIsSIMD(argType)) { - unsigned int argSizeBytes; - (void)getBaseJitTypeAndSizeOfSIMDType(argClass, &argSizeBytes); - argType = getSIMDTypeForSize(argSizeBytes); + argType = getSIMDType(argClass); } assert(varTypeIsSIMD(argType)); @@ -1889,29 +1887,20 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic, CorInfoType simdBaseJitType = CORINFO_TYPE_UNDEF; GenTree* retNode = nullptr; - if (retType == TYP_STRUCT) + if (retType == TYP_STRUCT && !HWIntrinsicInfo::IsMultiReg(intrinsic)) { - unsigned int sizeBytes; - simdBaseJitType = getBaseJitTypeAndSizeOfSIMDType(sig->retTypeSigClass, &sizeBytes); - - if (HWIntrinsicInfo::IsMultiReg(intrinsic)) - { - assert(sizeBytes == 0); - } + retType = impNormStructType(sig->retTypeSigClass, &simdBaseJitType); #ifdef TARGET_ARM64 - else if ((intrinsic == NI_AdvSimd_LoadAndInsertScalar) || (intrinsic == NI_AdvSimd_Arm64_LoadAndInsertScalar)) + if ((intrinsic == NI_AdvSimd_LoadAndInsertScalar) || (intrinsic == NI_AdvSimd_Arm64_LoadAndInsertScalar)) { - CorInfoType pSimdBaseJitType = CORINFO_TYPE_UNDEF; - var_types retFieldType = impNormStructType(sig->retTypeSigClass, &pSimdBaseJitType); - - if (retFieldType == TYP_STRUCT) + if (retType == TYP_STRUCT) { CORINFO_CLASS_HANDLE structType; unsigned int sizeBytes = 0; // LoadAndInsertScalar that returns 2,3 or 4 vectors - assert(pSimdBaseJitType == CORINFO_TYPE_UNDEF); + assert(simdBaseJitType == CORINFO_TYPE_UNDEF); unsigned fieldCount = info.compCompHnd->getClassNumInstanceFields(sig->retTypeSigClass); assert(fieldCount > 1); CORINFO_FIELD_HANDLE fieldHandle = info.compCompHnd->getFieldInClass(sig->retTypeClass, 0); @@ -1937,24 +1926,20 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic, } else { - assert((retFieldType == TYP_SIMD8) || (retFieldType == TYP_SIMD16)); + assert((retType == TYP_SIMD8) || (retType == TYP_SIMD16)); assert(isSupportedBaseType(intrinsic, simdBaseJitType)); - retType = getSIMDTypeForSize(sizeBytes); } } -#endif else - { +#endif // We want to return early here for cases where retType was TYP_STRUCT as per method signature and // rather than deferring the decision after getting the simdBaseJitType of arg. - if (!isSupportedBaseType(intrinsic, simdBaseJitType)) + if (retType == TYP_UNDEF || !isSupportedBaseType(intrinsic, simdBaseJitType)) { return nullptr; } - assert(sizeBytes != 0); - retType = getSIMDTypeForSize(sizeBytes); - } + assert((varTypeIsSIMD(retType) || varTypeIsStruct(retType)) && isSupportedBaseType(intrinsic, simdBaseJitType)); } simdBaseJitType = getBaseJitTypeFromArgIfNeeded(intrinsic, sig, simdBaseJitType); diff --git a/src/coreclr/jit/hwintrinsicarm64.cpp b/src/coreclr/jit/hwintrinsicarm64.cpp index 5b1d29033ffc10..b616b2798d7c07 100644 --- a/src/coreclr/jit/hwintrinsicarm64.cpp +++ b/src/coreclr/jit/hwintrinsicarm64.cpp @@ -1361,12 +1361,10 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, if (!varTypeIsLong(simdBaseType)) { - var_types simdType = getSIMDTypeForSize(simdSize); - op2 = impSIMDPopStack(); op1 = impSIMDPopStack(); - retNode = gtNewSimdDotProdNode(simdType, op1, op2, simdBaseJitType, simdSize); + retNode = gtNewSimdDotProdNode(op1->TypeGet(), op1, op2, simdBaseJitType, simdSize); retNode = gtNewSimdGetElementNode(retType, retNode, gtNewIconNode(0), simdBaseJitType, simdSize); } break; diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 3bd72cb08e609a..c0b28d6b74654a 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -1185,12 +1185,12 @@ var_types Compiler::impNormStructType(CORINFO_CLASS_HANDLE structHnd, CorInfoTyp if (structSizeMightRepresentSIMDType(originalSize)) { - unsigned int sizeBytes; - CorInfoType simdBaseJitType = getBaseJitTypeAndSizeOfSIMDType(structHnd, &sizeBytes); - if (simdBaseJitType != CORINFO_TYPE_UNDEF) + CorInfoType simdBaseJitType = CORINFO_TYPE_UNDEF; + var_types simdType = getSIMDType(structHnd, &simdBaseJitType); + if (simdBaseJitType != CORINFO_TYPE_UNDEF && simdType != TYP_UNDEF) { - assert(sizeBytes == originalSize); - structType = getSIMDTypeForSize(sizeBytes); + assert(getSizeOfSIMDType(simdType) == originalSize); + structType = simdType; if (pSimdBaseJitType != nullptr) { *pSimdBaseJitType = simdBaseJitType; diff --git a/src/coreclr/jit/lclvars.cpp b/src/coreclr/jit/lclvars.cpp index d97fdbca4a1a55..ef30733c5ff9cd 100644 --- a/src/coreclr/jit/lclvars.cpp +++ b/src/coreclr/jit/lclvars.cpp @@ -1435,15 +1435,10 @@ var_types Compiler::StructPromotionHelper::TryPromoteValueClassAsPrimitive(CORIN #ifdef FEATURE_SIMD if (compiler->isRuntimeIntrinsicsNamespace(namespaceName) || compiler->isNumericsNamespace(namespaceName)) { - unsigned simdSize; - CorInfoType simdBaseJitType = compiler->getBaseJitTypeAndSizeOfSIMDType(node.simdTypeHnd, &simdSize); - // We will only promote fields of SIMD types that fit into a SIMD register. - if (simdBaseJitType != CORINFO_TYPE_UNDEF) + var_types type = compiler->getSIMDType(node.simdTypeHnd); + if (type != TYP_UNDEF) { - if (compiler->structSizeMightRepresentSIMDType(simdSize)) - { - return compiler->getSIMDTypeForSize(simdSize); - } + return type; } } #endif diff --git a/src/coreclr/jit/simd.cpp b/src/coreclr/jit/simd.cpp index 18fe8e60c09a7d..3702285640e54b 100644 --- a/src/coreclr/jit/simd.cpp +++ b/src/coreclr/jit/simd.cpp @@ -509,295 +509,21 @@ unsigned Compiler::getSizeOfSIMDType(var_types simdType) // CorInfoType Compiler::getBaseJitTypeAndSizeOfSIMDType(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; - } - } + CorInfoType baseType = CORINFO_TYPE_UNDEF; if (sizeBytes != nullptr) { *sizeBytes = 0; } - if ((typeHnd == nullptr) || !isIntrinsicType(typeHnd)) - { - return CORINFO_TYPE_UNDEF; - } - - const char* namespaceName; - const char* className = getClassNameFromMetadata(typeHnd, &namespaceName); + var_types type = getSIMDType(typeHnd, &baseType); - // fast path search using cached type handles of important types - CorInfoType simdBaseJitType = CORINFO_TYPE_UNDEF; - unsigned size = 0; - - if (isNumericsNamespace(namespaceName)) + if (sizeBytes != nullptr && type != TYP_UNDEF) { - switch (className[0]) - { - case 'P': - { - if (strcmp(className, "Plane") != 0) - { - return CORINFO_TYPE_UNDEF; - } - - JITDUMP(" Known type Plane\n"); - m_simdHandleCache->PlaneHandle = typeHnd; - - simdBaseJitType = CORINFO_TYPE_FLOAT; - size = 4 * genTypeSize(TYP_FLOAT); - break; - } - - case 'Q': - { - if (strcmp(className, "Quaternion") != 0) - { - return CORINFO_TYPE_UNDEF; - } - - JITDUMP(" Known type Quaternion\n"); - m_simdHandleCache->QuaternionHandle = typeHnd; - - simdBaseJitType = CORINFO_TYPE_FLOAT; - size = 4 * genTypeSize(TYP_FLOAT); - break; - } - - case 'V': - { - if (strncmp(className, "Vector", 6) != 0) - { - return CORINFO_TYPE_UNDEF; - } - - switch (className[6]) - { - case '\0': - { - JITDUMP(" Found type Vector\n"); - m_simdHandleCache->VectorHandle = typeHnd; - break; - } - - case '2': - { - if (className[7] != '\0') - { - return CORINFO_TYPE_UNDEF; - } - - JITDUMP(" Found Vector2\n"); - m_simdHandleCache->Vector2Handle = typeHnd; - - simdBaseJitType = CORINFO_TYPE_FLOAT; - size = 2 * genTypeSize(TYP_FLOAT); - break; - } - - case '3': - { - if (className[7] != '\0') - { - return CORINFO_TYPE_UNDEF; - } - - JITDUMP(" Found Vector3\n"); - m_simdHandleCache->Vector3Handle = typeHnd; - - simdBaseJitType = CORINFO_TYPE_FLOAT; - size = 3 * genTypeSize(TYP_FLOAT); - break; - } - - case '4': - { - if (className[7] != '\0') - { - return CORINFO_TYPE_UNDEF; - } - - JITDUMP(" Found Vector4\n"); - m_simdHandleCache->Vector4Handle = typeHnd; - - simdBaseJitType = CORINFO_TYPE_FLOAT; - size = 4 * genTypeSize(TYP_FLOAT); - break; - } - - case '`': - { - if ((className[7] != '1') || (className[8] != '\0')) - { - return CORINFO_TYPE_UNDEF; - } - - CORINFO_CLASS_HANDLE typeArgHnd = info.compCompHnd->getTypeInstantiationArgument(typeHnd, 0); - simdBaseJitType = info.compCompHnd->getTypeForPrimitiveNumericClass(typeArgHnd); - - if ((simdBaseJitType < CORINFO_TYPE_BYTE) || (simdBaseJitType > CORINFO_TYPE_DOUBLE)) - { - return CORINFO_TYPE_UNDEF; - } - - JITDUMP(" Found Vector<%s>\n", varTypeName(JitType2PreciseVarType(simdBaseJitType))); - size = getVectorTByteLength(); - - if (size == 0) - { - return CORINFO_TYPE_UNDEF; - } - break; - } - - default: - { - return CORINFO_TYPE_UNDEF; - } - } - break; - } - - default: - { - return CORINFO_TYPE_UNDEF; - } - } - } -#ifdef FEATURE_HW_INTRINSICS - else - { - size = info.compCompHnd->getClassSize(typeHnd); - - switch (size) - { -#if defined(TARGET_ARM64) - case 8: - { - if (strcmp(className, "Vector64`1") != 0) - { - return CORINFO_TYPE_UNDEF; - } - - CORINFO_CLASS_HANDLE typeArgHnd = info.compCompHnd->getTypeInstantiationArgument(typeHnd, 0); - simdBaseJitType = info.compCompHnd->getTypeForPrimitiveNumericClass(typeArgHnd); - - if ((simdBaseJitType < CORINFO_TYPE_BYTE) || (simdBaseJitType > CORINFO_TYPE_DOUBLE)) - { - return CORINFO_TYPE_UNDEF; - } - - JITDUMP(" Found Vector64<%s>\n", varTypeName(JitType2PreciseVarType(simdBaseJitType))); - break; - } -#endif // TARGET_ARM64 - - case 16: - { - if (strcmp(className, "Vector128`1") != 0) - { - return CORINFO_TYPE_UNDEF; - } - - CORINFO_CLASS_HANDLE typeArgHnd = info.compCompHnd->getTypeInstantiationArgument(typeHnd, 0); - simdBaseJitType = info.compCompHnd->getTypeForPrimitiveNumericClass(typeArgHnd); - - if ((simdBaseJitType < CORINFO_TYPE_BYTE) || (simdBaseJitType > CORINFO_TYPE_DOUBLE)) - { - return CORINFO_TYPE_UNDEF; - } - - JITDUMP(" Found Vector128<%s>\n", varTypeName(JitType2PreciseVarType(simdBaseJitType))); - break; - } - -#if defined(TARGET_XARCH) - case 32: - { - if (strcmp(className, "Vector256`1") != 0) - { - return CORINFO_TYPE_UNDEF; - } - - CORINFO_CLASS_HANDLE typeArgHnd = info.compCompHnd->getTypeInstantiationArgument(typeHnd, 0); - simdBaseJitType = info.compCompHnd->getTypeForPrimitiveNumericClass(typeArgHnd); - - if ((simdBaseJitType < CORINFO_TYPE_BYTE) || (simdBaseJitType > CORINFO_TYPE_DOUBLE)) - { - return CORINFO_TYPE_UNDEF; - } - - if (!compOpportunisticallyDependsOn(InstructionSet_AVX)) - { - // We must treat as a regular struct if AVX isn't supported - return CORINFO_TYPE_UNDEF; - } - - JITDUMP(" Found Vector256<%s>\n", varTypeName(JitType2PreciseVarType(simdBaseJitType))); - break; - } - - case 64: - { - if (strcmp(className, "Vector512`1") != 0) - { - return CORINFO_TYPE_UNDEF; - } - - CORINFO_CLASS_HANDLE typeArgHnd = info.compCompHnd->getTypeInstantiationArgument(typeHnd, 0); - simdBaseJitType = info.compCompHnd->getTypeForPrimitiveNumericClass(typeArgHnd); - - if ((simdBaseJitType < CORINFO_TYPE_BYTE) || (simdBaseJitType > CORINFO_TYPE_DOUBLE)) - { - return CORINFO_TYPE_UNDEF; - } - - if (!compOpportunisticallyDependsOn(InstructionSet_AVX512)) - { - // We must treat as a regular struct if AVX512 isn't supported - return CORINFO_TYPE_UNDEF; - } - - JITDUMP(" Found Vector512<%s>\n", varTypeName(JitType2PreciseVarType(simdBaseJitType))); - break; - } -#endif // TARGET_XARCH - - default: - { - return CORINFO_TYPE_UNDEF; - } - } - } -#endif // FEATURE_HW_INTRINSICS - - if (sizeBytes != nullptr) - { - *sizeBytes = size; - } - - if (simdBaseJitType != CORINFO_TYPE_UNDEF) - { - assert(size == info.compCompHnd->getClassSize(typeHnd)); - setUsesSIMDTypes(true); + *sizeBytes = getSizeOfSIMDType(type); } - return simdBaseJitType; + return baseType; } //------------------------------------------------------------------------ From edb1ad7f7c38d7d10f270765fdff034d9bf92985 Mon Sep 17 00:00:00 2001 From: Sebastian Nickolls Date: Thu, 6 Nov 2025 11:13:56 +0000 Subject: [PATCH 11/12] Move type initialization earlier and fix cast issue on MSVC --- src/coreclr/jit/compiler.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index 592efec4d4b0da..35503b8f4185fe 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -6809,6 +6809,14 @@ int Compiler::compCompileHelper(CORINFO_MODULE_HANDLE classPtr, break; } +#if defined(FEATURE_SIMD) && defined(TARGET_ARM64) + // Initialize the size of Vector from the EE. + _initGenTypeSizes[TYP_SIMDSV] = (BYTE)getVectorTByteLength(); + _initGenTypeSizes[TYP_MASK] = (BYTE)getMaskByteLength(); + assert(genTypeSize(TYP_SIMDSV) >= 16); + assert(genTypeSize(TYP_MASK) >= 2); +#endif + info.compRetType = JITtype2varType(methodInfo->args.retType); if (info.compRetType == TYP_STRUCT) { @@ -7098,14 +7106,6 @@ int Compiler::compCompileHelper(CORINFO_MODULE_HANDLE classPtr, } #endif -#if defined(FEATURE_SIMD) && defined(TARGET_ARM64) - // Initialize the size of Vector from the EE. - _initGenTypeSizes[TYP_SIMDSV] = getVectorTByteLength(); - _initGenTypeSizes[TYP_MASK] = getMaskByteLength(); - assert(genTypeSize(TYP_SIMDSV) >= 16); - assert(genTypeSize(TYP_MASK) >= 2); -#endif - compCompile(methodCodePtr, methodCodeSize, compileFlags); #ifdef DEBUG From af6fd8099d7dd1d2ecf2fff50cc4f4b0d756f5de Mon Sep 17 00:00:00 2001 From: Sebastian Nickolls Date: Thu, 6 Nov 2025 14:46:09 +0000 Subject: [PATCH 12/12] Remove getSizeOfSIMDType genTypeSize is now sufficient for this purpose --- src/coreclr/jit/compiler.h | 2 - src/coreclr/jit/gentree.cpp | 90 ++++++++++++++++++------------------ src/coreclr/jit/importer.cpp | 2 +- src/coreclr/jit/simd.cpp | 33 +------------ 4 files changed, 48 insertions(+), 79 deletions(-) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 7ce47980a26811..79c36f24c4746d 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -9089,8 +9089,6 @@ class Compiler var_types getSIMDType(CORINFO_CLASS_HANDLE typeHnd, CorInfoType* baseType = nullptr); - unsigned getSizeOfSIMDType(var_types simdType); - // Get the base (element) type and size in bytes for a SIMD type. Returns CORINFO_TYPE_UNDEF // if it is not a SIMD type or is an unsupported base JIT type. CorInfoType getBaseJitTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeHnd, unsigned* sizeBytes = nullptr); diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 4c0c24454212fd..ca2ed9f3f86d56 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -20946,7 +20946,7 @@ GenTreeHWIntrinsic* Compiler::gtNewSimdHWIntrinsicNode(var_types ty GenTree* Compiler::gtNewSimdAbsNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(genTypeSize(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeGet() == type); @@ -21039,7 +21039,7 @@ GenTree* Compiler::gtNewSimdBinOpNode( genTreeOps op, var_types type, GenTree* op1, GenTree* op2, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(genTypeSize(type) == simdSize); var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType); assert(varTypeIsArithmetic(simdBaseType)); @@ -21753,7 +21753,7 @@ GenTree* Compiler::gtNewSimdBinOpNode( GenTree* Compiler::gtNewSimdCeilNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(genTypeSize(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -21833,7 +21833,7 @@ GenTree* Compiler::gtNewSimdCvtNode(var_types type, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(genTypeSize(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -21969,7 +21969,7 @@ GenTree* Compiler::gtNewSimdCvtNativeNode(var_types type, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(genTypeSize(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -22221,7 +22221,7 @@ GenTree* Compiler::gtNewSimdCmpOpNode( genTreeOps op, var_types type, GenTree* op1, GenTree* op2, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(genTypeSize(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -22514,7 +22514,7 @@ GenTree* Compiler::gtNewSimdCmpOpAllNode( var_types simdType = op1->TypeGet(); assert(varTypeIsSIMD(simdType)); - assert(getSizeOfSIMDType(simdType) == simdSize); + assert(genTypeSize(simdType) == simdSize); assert(op2 != nullptr); assert(op2->TypeIs(simdType)); @@ -22647,7 +22647,7 @@ GenTree* Compiler::gtNewSimdCmpOpAnyNode( assert(op1 != nullptr); var_types simdType = op1->TypeGet(); assert(varTypeIsSIMD(simdType)); - assert(getSizeOfSIMDType(simdType) == simdSize); + assert(genTypeSize(simdType) == simdSize); assert(op2 != nullptr); assert(op2->TypeIs(simdType)); @@ -22773,7 +22773,7 @@ GenTree* Compiler::gtNewSimdCndSelNode( var_types type, GenTree* op1, GenTree* op2, GenTree* op3, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(genTypeSize(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -23198,7 +23198,7 @@ GenTree* Compiler::gtNewSimdCreateSequenceNode( // is constant than there isn't any real optimization we can do and we need the full computation. assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(genTypeSize(type) == simdSize); var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType); assert(varTypeIsArithmetic(simdBaseType)); @@ -23370,7 +23370,7 @@ GenTree* Compiler::gtNewSimdDotProdNode( var_types type, GenTree* op1, GenTree* op2, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(genTypeSize(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -23410,7 +23410,7 @@ GenTree* Compiler::gtNewSimdDotProdNode( GenTree* Compiler::gtNewSimdFloorNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(genTypeSize(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -23455,7 +23455,7 @@ GenTree* Compiler::gtNewSimdFmaNode( var_types type, GenTree* op1, GenTree* op2, GenTree* op3, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(genTypeSize(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -23570,7 +23570,7 @@ GenTree* Compiler::gtNewSimdGetElementNode( GenTree* Compiler::gtNewSimdGetIndicesNode(var_types type, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(genTypeSize(type) == simdSize); var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType); assert(varTypeIsArithmetic(simdBaseType)); @@ -23723,7 +23723,7 @@ GenTree* Compiler::gtNewSimdIsEvenIntegerNode(var_types type, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(genTypeSize(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -23750,7 +23750,7 @@ GenTree* Compiler::gtNewSimdIsEvenIntegerNode(var_types type, GenTree* Compiler::gtNewSimdIsFiniteNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(genTypeSize(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -23801,7 +23801,7 @@ GenTree* Compiler::gtNewSimdIsFiniteNode(var_types type, GenTree* op1, CorInfoTy GenTree* Compiler::gtNewSimdIsInfinityNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(genTypeSize(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -23832,7 +23832,7 @@ GenTree* Compiler::gtNewSimdIsInfinityNode(var_types type, GenTree* op1, CorInfo GenTree* Compiler::gtNewSimdIsIntegerNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(genTypeSize(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -23872,7 +23872,7 @@ GenTree* Compiler::gtNewSimdIsIntegerNode(var_types type, GenTree* op1, CorInfoT GenTree* Compiler::gtNewSimdIsNaNNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(genTypeSize(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -23903,7 +23903,7 @@ GenTree* Compiler::gtNewSimdIsNaNNode(var_types type, GenTree* op1, CorInfoType GenTree* Compiler::gtNewSimdIsNegativeNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(genTypeSize(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -23945,7 +23945,7 @@ GenTree* Compiler::gtNewSimdIsNegativeInfinityNode(var_types type, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(genTypeSize(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -23993,7 +23993,7 @@ GenTree* Compiler::gtNewSimdIsNegativeInfinityNode(var_types type, GenTree* Compiler::gtNewSimdIsNormalNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(genTypeSize(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -24056,7 +24056,7 @@ GenTree* Compiler::gtNewSimdIsOddIntegerNode(var_types type, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(genTypeSize(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -24083,7 +24083,7 @@ GenTree* Compiler::gtNewSimdIsOddIntegerNode(var_types type, GenTree* Compiler::gtNewSimdIsPositiveNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(genTypeSize(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -24125,7 +24125,7 @@ GenTree* Compiler::gtNewSimdIsPositiveInfinityNode(var_types type, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(genTypeSize(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -24176,7 +24176,7 @@ GenTree* Compiler::gtNewSimdIsSubnormalNode(var_types type, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(genTypeSize(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -24233,7 +24233,7 @@ GenTree* Compiler::gtNewSimdIsSubnormalNode(var_types type, GenTree* Compiler::gtNewSimdIsZeroNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(genTypeSize(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -24259,7 +24259,7 @@ GenTree* Compiler::gtNewSimdIsZeroNode(var_types type, GenTree* op1, CorInfoType GenTree* Compiler::gtNewSimdLoadNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(genTypeSize(type) == simdSize); assert(op1 != nullptr); @@ -24454,7 +24454,7 @@ GenTree* Compiler::gtNewSimdMinMaxNode(var_types type, else if (!varTypeIsLong(simdBaseType)) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(genTypeSize(type) == simdSize); } NamedIntrinsic intrinsic = NI_Illegal; @@ -25096,7 +25096,7 @@ GenTree* Compiler::gtNewSimdMinMaxNativeNode( else { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(genTypeSize(type) == simdSize); } NamedIntrinsic intrinsic = NI_Illegal; @@ -25209,7 +25209,7 @@ GenTree* Compiler::gtNewSimdNarrowNode( var_types type, GenTree* op1, GenTree* op2, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(genTypeSize(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -25681,7 +25681,7 @@ GenTree* Compiler::gtNewSimdNarrowNode( GenTree* Compiler::gtNewSimdRoundNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(genTypeSize(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -25742,7 +25742,7 @@ GenTree* Compiler::gtNewSimdShuffleVariableNode( var_types type, GenTree* op1, GenTree* op2, CorInfoType simdBaseJitType, unsigned simdSize, bool isShuffleNative) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(genTypeSize(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -26345,7 +26345,7 @@ GenTree* Compiler::gtNewSimdShuffleNode( var_types type, GenTree* op1, GenTree* op2, CorInfoType simdBaseJitType, unsigned simdSize, bool isShuffleNative) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(genTypeSize(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -26928,7 +26928,7 @@ GenTree* Compiler::gtNewSimdShuffleNode( GenTree* Compiler::gtNewSimdSqrtNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(genTypeSize(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -26986,7 +26986,7 @@ GenTree* Compiler::gtNewSimdStoreNode(GenTree* op1, GenTree* op2, CorInfoType si assert(op2 != nullptr); assert(varTypeIsSIMD(op2)); - assert(getSizeOfSIMDType(op2->TypeGet()) == simdSize); + assert(genTypeSize(op2->TypeGet()) == simdSize); var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType); assert(varTypeIsArithmetic(simdBaseType)); @@ -27106,7 +27106,7 @@ GenTree* Compiler::gtNewSimdSumNode(var_types type, GenTree* op1, CorInfoType si assert(op1 != nullptr); var_types simdType = op1->TypeGet(); assert(varTypeIsSIMD(simdType)); - assert(getSizeOfSIMDType(simdType) == simdSize); + assert(genTypeSize(simdType) == simdSize); var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType); assert(varTypeIsArithmetic(simdBaseType)); @@ -27434,7 +27434,7 @@ GenTree* Compiler::gtNewSimdToScalarNode(var_types type, GenTree* op1, CorInfoTy GenTree* Compiler::gtNewSimdTruncNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(genTypeSize(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -27479,7 +27479,7 @@ GenTree* Compiler::gtNewSimdUnOpNode( genTreeOps op, var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(genTypeSize(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -27574,7 +27574,7 @@ GenTree* Compiler::gtNewSimdUnOpNode( GenTree* Compiler::gtNewSimdWidenLowerNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(genTypeSize(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -27776,7 +27776,7 @@ GenTree* Compiler::gtNewSimdWidenLowerNode(var_types type, GenTree* op1, CorInfo GenTree* Compiler::gtNewSimdWidenUpperNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(varTypeIsSIMD(type)); - assert(getSizeOfSIMDType(type) == simdSize); + assert(genTypeSize(type) == simdSize); assert(op1 != nullptr); assert(op1->TypeIs(type)); @@ -29671,7 +29671,7 @@ NamedIntrinsic GenTreeHWIntrinsic::GetHWIntrinsicIdForUnOp( assert(op1 != nullptr); var_types simdType = op1->TypeGet(); assert(varTypeIsSIMD(simdType)); - assert(comp->getSizeOfSIMDType(simdType) == simdSize); + assert(genTypeSize(simdType) == simdSize); NamedIntrinsic id = NI_Illegal; @@ -29749,7 +29749,7 @@ NamedIntrinsic GenTreeHWIntrinsic::GetHWIntrinsicIdForBinOp(Compiler* comp, assert(op1 != nullptr); var_types simdType = op1->TypeGet(); assert(varTypeIsSIMD(simdType)); - assert(comp->getSizeOfSIMDType(simdType) == simdSize); + assert(genTypeSize(simdType) == simdSize); assert(op2 != nullptr); #if defined(TARGET_XARCH) @@ -30320,7 +30320,7 @@ NamedIntrinsic GenTreeHWIntrinsic::GetHWIntrinsicIdForCmpOp(Compiler* comp, assert(op1 != nullptr); assert(op2 != nullptr); var_types simdType = op1->TypeGet(); - assert(comp->getSizeOfSIMDType(simdType) == simdSize); + assert(genTypeSize(simdType) == simdSize); assert(varTypeIsMask(type) || (type == simdType)); assert(varTypeIsArithmetic(simdBaseType)); assert(varTypeIsSIMD(simdType)); @@ -30658,7 +30658,7 @@ var_types GenTreeHWIntrinsic::GetLookupTypeForCmpOp( { assert(varTypeIsMask(type) || varTypeIsSIMD(type)); assert(varTypeIsArithmetic(simdBaseType)); - assert(comp->getSizeOfSIMDType(type) == simdSize); + assert(genTypeSize(type) == simdSize); var_types lookupType = type; diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index c0b28d6b74654a..1a22b3168b2fd9 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -1189,7 +1189,7 @@ var_types Compiler::impNormStructType(CORINFO_CLASS_HANDLE structHnd, CorInfoTyp var_types simdType = getSIMDType(structHnd, &simdBaseJitType); if (simdBaseJitType != CORINFO_TYPE_UNDEF && simdType != TYP_UNDEF) { - assert(getSizeOfSIMDType(simdType) == originalSize); + assert(genTypeSize(simdType) == originalSize); structType = simdType; if (pSimdBaseJitType != nullptr) { diff --git a/src/coreclr/jit/simd.cpp b/src/coreclr/jit/simd.cpp index 3702285640e54b..abe19fdb8bec1f 100644 --- a/src/coreclr/jit/simd.cpp +++ b/src/coreclr/jit/simd.cpp @@ -447,42 +447,13 @@ var_types Compiler::getSIMDType(CORINFO_CLASS_HANDLE typeHnd, CorInfoType* baseT if (simdBaseJitType != CORINFO_TYPE_UNDEF) { - assert(getSizeOfSIMDType(type) == info.compCompHnd->getClassSize(typeHnd)); + assert(genTypeSize(type) == info.compCompHnd->getClassSize(typeHnd)); setUsesSIMDTypes(true); } return type; } -unsigned Compiler::getSizeOfSIMDType(var_types simdType) -{ - assert(varTypeIsSIMD(simdType)); - unsigned size = 0; - switch (simdType) - { - case TYP_SIMD8: - case TYP_SIMD12: - case TYP_SIMD16: -#ifdef TARGET_XARCH - case TYP_SIMD32: - case TYP_SIMD64: -#endif - size = genTypeSize(simdType); - break; - -#ifdef TARGET_ARM64 - case TYP_SIMDSV: - size = getVectorTByteLength(); - break; -#endif - - default: - unreached(); - } - assert(size != 0); - return size; -} - //---------------------------------------------------------------------------------- // Return the base type and size of SIMD vector type given its type handle. // @@ -520,7 +491,7 @@ CorInfoType Compiler::getBaseJitTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeH if (sizeBytes != nullptr && type != TYP_UNDEF) { - *sizeBytes = getSizeOfSIMDType(type); + *sizeBytes = genTypeSize(type); } return baseType;