Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/coreclr/jit/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -984,7 +984,7 @@ var_types Compiler::getReturnTypeForStruct(CORINFO_CLASS_HANDLE clsHnd,

// TODO-SVE: For now, we always pass Vector<T> by reference. Support passing Vector<T> in Z registers.
unsigned simdSize = 0;
if (structSizeMightRepresentSIMDType(structSize) &&
if (structMightRepresentSIMDType(clsHnd) &&
(getBaseTypeAndSizeOfSIMDType(clsHnd, &simdSize) != TYP_UNDEF) && (simdSize == SIZE_UNKNOWN))
{
howToReturnStruct = SPK_ByReference;
Expand Down
32 changes: 28 additions & 4 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -10594,12 +10594,36 @@ class Compiler
return threshold;
}

// Use to determine if a struct *might* be a SIMD type. As this function only takes a size, many
// structs will fit the criteria.
bool structSizeMightRepresentSIMDType(size_t structSize)
//---------------------------------------------------------------------------------------------
// structMightRepresentSIMDType: Can this class handle be a SIMD type?
//
// Returns:
// false if it is not possible for this class handle to be a SIMD type, otherwise true.
//
// Notes:
// SIMD types are currently all value classes annotated with the [Intrinsic] attribute.
// This is a first stage filter, caller should verify exact SIMD types by name.
bool structMightRepresentSIMDType(CORINFO_CLASS_HANDLE clsHnd)
{
uint32_t structFlags = info.compCompHnd->getClassAttribs(clsHnd);
uint32_t filteredFlags = structFlags & (CORINFO_FLG_VALUECLASS | CORINFO_FLG_CONTAINS_GC_PTR |
CORINFO_FLG_BYREF_LIKE | CORINFO_FLG_INTRINSIC_TYPE);
uint32_t desiredFlags = (CORINFO_FLG_VALUECLASS | CORINFO_FLG_INTRINSIC_TYPE);

if (filteredFlags != desiredFlags)
{
return false;
}

unsigned structSize = info.compCompHnd->getClassSize(clsHnd);
#ifdef FEATURE_SIMD
return (structSize >= getMinVectorByteLength()) && (structSize <= getMaxVectorByteLength());
#ifdef TARGET_ARM64
const uint32_t max =
compOpportunisticallyDependsOn(InstructionSet_VectorT) ? MAX_SVE_REGSIZE_BYTES : FP_REGSIZE_BYTES;
#else
const uint32_t max = getMaxVectorByteLength();
#endif // TARGET_ARM64
return (structSize >= getMinVectorByteLength()) && (structSize <= max);
#else
return false;
#endif // FEATURE_SIMD
Expand Down
30 changes: 11 additions & 19 deletions src/coreclr/jit/importer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1154,7 +1154,7 @@ GenTree* Compiler::impGetNodeAddr(GenTree* val,
// Normalizing the type involves examining the struct type to determine if it should
// be modified to one that is handled specially by the JIT, possibly being a candidate
// for full enregistration, e.g. TYP_SIMD16. If the size of the struct is already known
// call structSizeMightRepresentSIMDType to determine if this api needs to be called.
// call structMightRepresentSIMDType to determine if this api needs to be called.
//
var_types Compiler::impNormStructType(CORINFO_CLASS_HANDLE structHnd, var_types* pSimdBaseJitType)
{
Expand All @@ -1163,28 +1163,20 @@ var_types Compiler::impNormStructType(CORINFO_CLASS_HANDLE structHnd, var_types*
var_types structType = TYP_STRUCT;

#ifdef FEATURE_SIMD
const DWORD structFlags = info.compCompHnd->getClassAttribs(structHnd);

// Don't bother if the struct contains GC references of byrefs, it can't be a SIMD type.
if ((structFlags & (CORINFO_FLG_CONTAINS_GC_PTR | CORINFO_FLG_BYREF_LIKE)) == 0)
if (structMightRepresentSIMDType(structHnd))
{
unsigned originalSize = info.compCompHnd->getClassSize(structHnd);

if (structSizeMightRepresentSIMDType(originalSize))
unsigned int sizeBytes;
var_types simdBaseType = getBaseTypeAndSizeOfSIMDType(structHnd, &sizeBytes);
if (simdBaseType != TYP_UNDEF)
{
unsigned int sizeBytes;
var_types simdBaseType = getBaseTypeAndSizeOfSIMDType(structHnd, &sizeBytes);
if (simdBaseType != TYP_UNDEF)
assert((sizeBytes == info.compCompHnd->getClassSize(structHnd)) || (sizeBytes == SIZE_UNKNOWN));
structType = getSIMDTypeForSize(sizeBytes);
if (pSimdBaseJitType != nullptr)
{
assert(sizeBytes == originalSize || sizeBytes == SIZE_UNKNOWN);
structType = getSIMDTypeForSize(sizeBytes);
if (pSimdBaseJitType != nullptr)
{
*pSimdBaseJitType = simdBaseType;
}
// Also indicate that we use floating point registers.
compFloatingPointUsed = true;
*pSimdBaseJitType = simdBaseType;
}
// Also indicate that we use floating point registers.
compFloatingPointUsed = true;
}
}
#endif // FEATURE_SIMD
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/jit/lclvars.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1615,7 +1615,7 @@ var_types Compiler::StructPromotionHelper::TryPromoteValueClassAsPrimitive(CORIN
// We will only promote fields of SIMD types that fit into a SIMD register.
if (simdBaseType != TYP_UNDEF)
{
if (m_compiler->structSizeMightRepresentSIMDType(simdSize))
if (m_compiler->structMightRepresentSIMDType(node.simdTypeHnd))
{
return m_compiler->getSIMDTypeForSize(simdSize);
}
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/jit/morph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2890,7 +2890,7 @@ GenTree* Compiler::fgMorphIndexAddr(GenTreeIndexAddr* indexAddr)
}

#ifdef FEATURE_SIMD
if (varTypeIsStruct(elemTyp) && structSizeMightRepresentSIMDType(elemSize))
if (varTypeIsStruct(elemTyp))
{
elemTyp = impNormStructType(elemStructType);
}
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/jit/simd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ var_types Compiler::getBaseTypeForPrimitiveNumericClass(CORINFO_CLASS_HANDLE cls
// sizeBytes if non-null is set to size in bytes.
//
// Notes:
// If the size of the struct is already known call structSizeMightRepresentSIMDType
// If the size of the struct is already known call structMightRepresentSIMDType
// 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
Expand Down
3 changes: 3 additions & 0 deletions src/coreclr/jit/targetarm64.h
Original file line number Diff line number Diff line change
Expand Up @@ -370,4 +370,7 @@

#define REG_UNKBASE REG_R19
#define RBM_UNKBASE RBM_R19

#define MAX_SVE_REGSIZE_BYTES 256

// clang-format on
7 changes: 1 addition & 6 deletions src/coreclr/jit/valuenum.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3769,12 +3769,7 @@ ValueNum ValueNumStore::VNForFieldSelector(CORINFO_FIELD_HANDLE fieldHnd, var_ty
if (fieldType == TYP_STRUCT)
{
structSize = m_compiler->info.compCompHnd->getClassSize(structHnd);

// We have to normalize here since there is no CorInfoType for vectors...
if (m_compiler->structSizeMightRepresentSIMDType(structSize))
{
fieldType = m_compiler->impNormStructType(structHnd);
}
fieldType = m_compiler->impNormStructType(structHnd);
}

*pFieldType = fieldType;
Expand Down
10 changes: 6 additions & 4 deletions src/coreclr/vm/codeman.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1720,10 +1720,12 @@ void EEJitManager::SetCpuInfo()
uint32_t maxVectorTLength = (maxVectorTBitWidth / 8);
uint64_t sveLengthFromOS = GetSveLengthFromOS();

// For now, enable SVE only when the system vector length is 16 bytes (128-bits)
// TODO: https://github.com/dotnet/runtime/issues/101477
if (sveLengthFromOS == 16)
// if ((maxVectorTLength >= sveLengthFromOS) || (maxVectorTBitWidth == 0))
if (sveLengthFromOS == 16
#ifdef _DEBUG
|| (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_JitUseScalableVectorT)
&& ((maxVectorTLength >= sveLengthFromOS) || (maxVectorTBitWidth == 0)))
#endif
)
{
CPUCompileFlags.Set(InstructionSet_Sve);

Expand Down
15 changes: 13 additions & 2 deletions src/coreclr/vm/methodtablebuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1174,6 +1174,10 @@ MethodTableBuilder::CopyParentVtable()
}
}

#ifdef TARGET_ARM64
extern "C" uint64_t GetSveLengthFromOS();
#endif

//*******************************************************************************
// Determine if this is the special SIMD type System.Numerics.Vector<T>, whose
// size is determined dynamically based on the hardware and the presence of JIT
Expand All @@ -1186,7 +1190,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;

Expand All @@ -1205,6 +1209,7 @@ BOOL MethodTableBuilder::CheckIfSIMDAndUpdateSize()
CORJIT_FLAGS CPUCompileFlags = ExecutionManager::GetEEJitManager()->GetCPUCompileFlags();
uint32_t numInstanceFieldBytes = 16;

#if defined(TARGET_X86) || defined(TARGET_AMD64)
if (CPUCompileFlags.IsSet(InstructionSet_VectorT512))
{
numInstanceFieldBytes = 64;
Expand All @@ -1213,13 +1218,19 @@ BOOL MethodTableBuilder::CheckIfSIMDAndUpdateSize()
{
numInstanceFieldBytes = 32;
}
#elif defined(TARGET_ARM64)
if (CPUCompileFlags.IsSet(InstructionSet_VectorT))
{
numInstanceFieldBytes = (uint32_t) GetSveLengthFromOS();
}
Comment thread
tannergooding marked this conversation as resolved.
#endif

if (numInstanceFieldBytes != 16)
{
bmtFP->NumInstanceFieldBytes = numInstanceFieldBytes;
return true;
}
#endif // TARGET_X86 || TARGET_AMD64
#endif // TARGET_X86 || TARGET_AMD64 || TARGET_ARM64

return false;
}
Expand Down
Loading