diff --git a/src/coreclr/interpreter/compiler.cpp b/src/coreclr/interpreter/compiler.cpp index 095fb63c5f3e39..5114d86a6909eb 100644 --- a/src/coreclr/interpreter/compiler.cpp +++ b/src/coreclr/interpreter/compiler.cpp @@ -765,7 +765,7 @@ int32_t InterpCompiler::CreateVarExplicit(InterpType interpType, CORINFO_CLASS_H m_varsCapacity *= 2; if (m_varsCapacity < 16) m_varsCapacity = 16; - + m_pVars = getAllocator(IMK_Var).allocateZeroed(m_varsCapacity); if (oldVars != NULL) { @@ -791,7 +791,7 @@ void InterpCompiler::EnsureStack(int additional) m_stackCapacity *= 2; if (m_stackCapacity < 4) m_stackCapacity = 4; - + m_pStackBase = new (getAllocator(IMK_StackInfo)) StackInfo[m_stackCapacity]; if (oldStackBase != NULL) { @@ -2026,23 +2026,23 @@ InterpMethod* InterpCompiler::FinalizeMethodData(void* baseAddressRW, void* base uint32_t currentIntervalMapOffset = intervalMapsOffset; const uint32_t asyncSuspendDataSectionEnd = asyncSuspendDataOffset + asyncSuspendDataSectionSize; const uint32_t intervalMapsSectionEnd = intervalMapsOffset + intervalMapsSectionSize; - + InterpByteCodeStart* pByteCodeStart = (InterpByteCodeStart*)rxBase; - + for (int32_t i = 0; i < m_asyncSuspendDataItems.GetSize(); i++) { assert(currentAsyncOffset + sizeof(InterpAsyncSuspendData) <= asyncSuspendDataSectionEnd); InterpAsyncSuspendData* srcData = m_asyncSuspendDataItems.Get(i); InterpAsyncSuspendData* dstDataRW = (InterpAsyncSuspendData*)(rwBase + currentAsyncOffset); - + // Copy the struct memcpy(dstDataRW, srcData, sizeof(InterpAsyncSuspendData)); - + // Fix up the methodStartIP to point to the final bytecode start dstDataRW->methodStartIP = pByteCodeStart; dstDataRW->resumeInfo.DiagnosticIP += (TARGET_SIZE_T)pByteCodeStart; - + // Fix up interval map pointers if they exist // Note: The interval maps were allocated via AllocMethodData in the old model, // we need to copy them to the new allocation and fix up the pointers @@ -2055,14 +2055,14 @@ InterpMethod* InterpCompiler::FinalizeMethodData(void* baseAddressRW, void* base uint32_t mapSize = (uint32_t)count * sizeof(InterpIntervalMapEntry); assert(currentIntervalMapOffset + mapSize <= intervalMapsSectionEnd); - + InterpIntervalMapEntry* dstMapRW = (InterpIntervalMapEntry*)(rwBase + currentIntervalMapOffset); InterpIntervalMapEntry* dstMapRX = (InterpIntervalMapEntry*)(rxBase + currentIntervalMapOffset); memcpy(dstMapRW, srcData->liveLocalsIntervals, mapSize); dstDataRW->liveLocalsIntervals = dstMapRX; currentIntervalMapOffset += mapSize; } - + if (srcData->zeroedLocalsIntervals != nullptr) { // Count entries @@ -2072,7 +2072,7 @@ InterpMethod* InterpCompiler::FinalizeMethodData(void* baseAddressRW, void* base uint32_t mapSize = (uint32_t)count * sizeof(InterpIntervalMapEntry); assert(currentIntervalMapOffset + mapSize <= intervalMapsSectionEnd); - + InterpIntervalMapEntry* dstMapRW = (InterpIntervalMapEntry*)(rwBase + currentIntervalMapOffset); InterpIntervalMapEntry* dstMapRX = (InterpIntervalMapEntry*)(rxBase + currentIntervalMapOffset); memcpy(dstMapRW, srcData->zeroedLocalsIntervals, mapSize); @@ -2121,7 +2121,7 @@ InterpMethod* InterpCompiler::FinalizeMethodData(void* baseAddressRW, void* base { DataItemAsyncSuspendRef ref = m_dataItemAsyncSuspendRefs.Get(i); // Calculate the final address of this async suspend data in the RX allocation - InterpAsyncSuspendData* finalAddr = (InterpAsyncSuspendData*)(rxBase + asyncSuspendDataOffset + + InterpAsyncSuspendData* finalAddr = (InterpAsyncSuspendData*)(rxBase + asyncSuspendDataOffset + ref.asyncSuspendDataIndex * sizeof(InterpAsyncSuspendData)); pDataItemsRW[ref.dataItemIndex] = finalAddr; } @@ -3562,6 +3562,44 @@ bool InterpCompiler::EmitNamedIntrinsicCall(NamedIntrinsic ni, bool nonVirtualCa m_pLastNewIns->SetDVar(m_pStackPointer[-1].var); return true; + case NI_IsSupported_Type: + { + CORINFO_CLASS_HANDLE typeArgHnd = m_compHnd->getTypeInstantiationArgument(clsHnd, 0); + CorInfoType simdBaseJitType = m_compHnd->getTypeForPrimitiveNumericClass(typeArgHnd); + + AddIns(INTOP_LDC_I4); + + switch (simdBaseJitType) + { + case CORINFO_TYPE_BYTE: + case CORINFO_TYPE_UBYTE: + case CORINFO_TYPE_SHORT: + case CORINFO_TYPE_USHORT: + case CORINFO_TYPE_INT: + case CORINFO_TYPE_UINT: + case CORINFO_TYPE_LONG: + case CORINFO_TYPE_ULONG: + case CORINFO_TYPE_FLOAT: + case CORINFO_TYPE_DOUBLE: + case CORINFO_TYPE_NATIVEINT: + case CORINFO_TYPE_NATIVEUINT: + { + m_pLastNewIns->data[0] = true; + break; + } + + default: + { + m_pLastNewIns->data[0] = false; + break; + } + } + + PushStackType(StackTypeI4, NULL); + m_pLastNewIns->SetDVar(m_pStackPointer[-1].var); + return true; + } + case NI_PRIMITIVE_ConvertToIntegerNative: { CHECK_STACK(1); @@ -4423,7 +4461,7 @@ void InterpCompiler::EmitCalli(bool isTailCall, void* calliCookie, int callIFunc { if (m_compHnd->pInvokeMarshalingRequired(NULL, callSiteSig)) { - // If we remove this restriction, we should handle the track transitions scenario by forcing a + // If we remove this restriction, we should handle the track transitions scenario by forcing a // p/invoke marshaling calli stub even when not needed. BADCODE("PInvoke marshalling for calli is not supported in interpreted code"); } @@ -6011,7 +6049,7 @@ void InterpCompiler::EmitSuspend(const CORINFO_CALL_INFO &callInfo, Continuation } InterpType interpType = m_pVars[var].interpType; CORINFO_CLASS_HANDLE clsHnd = m_pVars[var].clsHnd; - + int32_t alignUNUSED; int32_t size = GetInterpTypeStackSize(clsHnd, interpType, &alignUNUSED); @@ -6058,7 +6096,7 @@ void InterpCompiler::EmitSuspend(const CORINFO_CALL_INFO &callInfo, Continuation SetSlotToTrue(objRefSlots, currentOffset + slotInfo.m_offsetBytes); } } - + currentOffset += size; } @@ -6099,7 +6137,7 @@ void InterpCompiler::EmitSuspend(const CORINFO_CALL_INFO &callInfo, Continuation suspendData->suspensionPointIndex = suspensionPointIndex; CORINFO_ASYNC_INFO asyncInfo; m_compHnd->getAsyncInfo(&asyncInfo); - + GetDataForHelperFtn(CORINFO_HELP_ALLOC_CONTINUATION); suspendData->continuationTypeHnd = continuationTypeHnd; AllocateIntervalMapData_ForVars(&suspendData->liveLocalsIntervals, liveVars); @@ -6232,13 +6270,13 @@ void InterpCompiler::EmitSuspend(const CORINFO_CALL_INFO &callInfo, Continuation AddIns(handleContinuationOpcode); int32_t suspendDataIndex = GetDataItemIndex(suspendData); - + // Track this data item -> async suspend data reference for fixup during finalization DataItemAsyncSuspendRef ref; ref.dataItemIndex = suspendDataIndex; ref.asyncSuspendDataIndex = m_asyncSuspendDataItems.GetSize() - 1; // suspendData was just added m_dataItemAsyncSuspendRefs.Add(ref); - + m_pLastNewIns->data[0] = suspendDataIndex; m_pLastNewIns->data[1] = GetDataForHelperFtn(helperFuncForAllocatingContinuation); PushInterpType(InterpTypeO, NULL); @@ -6279,7 +6317,7 @@ void InterpCompiler::EmitSuspend(const CORINFO_CALL_INFO &callInfo, Continuation // Add location to resume to. The implementation of this opcode will: // - restore the data captured // - If there is an exception, throw it - // - if there is a captured exec context, call the restoration function. + // - if there is a captured exec context, call the restoration function. AddIns(INTOP_HANDLE_CONTINUATION_RESUME); m_pLastNewIns->data[0] = suspendDataIndex; @@ -9930,7 +9968,7 @@ void InterpCompiler::GenerateCode(CORINFO_METHOD_INFO* methodInfo) BADCODE("CEE_JMP in synchronized or async method"); } EmitCall(m_pConstrainedToken, readonly, true /* tailcall */, false /*newObj*/, false /*isCalli*/); - EmitRet(methodInfo); // The tail-call infrastructure in the interpreter is not 100% guaranteed to do a + EmitRet(methodInfo); // The tail-call infrastructure in the interpreter is not 100% guaranteed to do a // tail-call, so inject the ret logic here to cover that case. linkBBlocks = false; break; diff --git a/src/coreclr/interpreter/intrinsics.cpp b/src/coreclr/interpreter/intrinsics.cpp index 0bdcb718d5b6e7..8460b89a378b16 100644 --- a/src/coreclr/interpreter/intrinsics.cpp +++ b/src/coreclr/interpreter/intrinsics.cpp @@ -74,14 +74,23 @@ NamedIntrinsic GetNamedIntrinsic(COMP_HANDLE compHnd, CORINFO_METHOD_HANDLE comp if (!strcmp(className, "Vector") && !strcmp(methodName, "get_IsHardwareAccelerated")) return NI_IsSupported_False; + if (!strcmp(className, "Vector`1") && !strcmp(methodName, "get_IsSupported")) + return NI_IsSupported_Type; + // Fall back to managed implementation for everything else. return NI_Illegal; } else if (!strcmp(namespaceName, "System.Runtime.Intrinsics")) { // Vector128 etc - if (HAS_PREFIX(className, "Vector") && !strcmp(methodName, "get_IsHardwareAccelerated")) - return NI_IsSupported_False; + if (HAS_PREFIX(className, "Vector")) + { + if (!strcmp(methodName, "get_IsHardwareAccelerated")) + return NI_IsSupported_False; + + if (!strcmp(methodName, "get_IsSupported")) + return NI_IsSupported_Type; + } // Fall back to managed implementation for everything else. return NI_Illegal; diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128_1.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128_1.cs index c4da470bb3f20c..244ea695071e9b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128_1.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128_1.cs @@ -82,18 +82,7 @@ public static bool IsSupported [MethodImpl(MethodImplOptions.AggressiveInlining)] get { - return (typeof(T) == typeof(byte)) - || (typeof(T) == typeof(double)) - || (typeof(T) == typeof(short)) - || (typeof(T) == typeof(int)) - || (typeof(T) == typeof(long)) - || (typeof(T) == typeof(nint)) - || (typeof(T) == typeof(sbyte)) - || (typeof(T) == typeof(float)) - || (typeof(T) == typeof(ushort)) - || (typeof(T) == typeof(uint)) - || (typeof(T) == typeof(ulong)) - || (typeof(T) == typeof(nuint)); + return Scalar.IsSupported; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256_1.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256_1.cs index 39c3404eff5d0d..e8583987454580 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256_1.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256_1.cs @@ -81,18 +81,7 @@ public static bool IsSupported [MethodImpl(MethodImplOptions.AggressiveInlining)] get { - return (typeof(T) == typeof(byte)) - || (typeof(T) == typeof(double)) - || (typeof(T) == typeof(short)) - || (typeof(T) == typeof(int)) - || (typeof(T) == typeof(long)) - || (typeof(T) == typeof(nint)) - || (typeof(T) == typeof(sbyte)) - || (typeof(T) == typeof(float)) - || (typeof(T) == typeof(ushort)) - || (typeof(T) == typeof(uint)) - || (typeof(T) == typeof(ulong)) - || (typeof(T) == typeof(nuint)); + return Scalar.IsSupported; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512_1.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512_1.cs index e408bc81abd35b..a63cd92c5e6dcc 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512_1.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512_1.cs @@ -81,18 +81,7 @@ public static bool IsSupported [MethodImpl(MethodImplOptions.AggressiveInlining)] get { - return (typeof(T) == typeof(byte)) - || (typeof(T) == typeof(double)) - || (typeof(T) == typeof(short)) - || (typeof(T) == typeof(int)) - || (typeof(T) == typeof(long)) - || (typeof(T) == typeof(nint)) - || (typeof(T) == typeof(sbyte)) - || (typeof(T) == typeof(float)) - || (typeof(T) == typeof(ushort)) - || (typeof(T) == typeof(uint)) - || (typeof(T) == typeof(ulong)) - || (typeof(T) == typeof(nuint)); + return Scalar.IsSupported; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64_1.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64_1.cs index d863f0543f1323..1a243dcc6facd4 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64_1.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64_1.cs @@ -81,18 +81,7 @@ public static bool IsSupported [MethodImpl(MethodImplOptions.AggressiveInlining)] get { - return (typeof(T) == typeof(byte)) - || (typeof(T) == typeof(double)) - || (typeof(T) == typeof(short)) - || (typeof(T) == typeof(int)) - || (typeof(T) == typeof(long)) - || (typeof(T) == typeof(nint)) - || (typeof(T) == typeof(sbyte)) - || (typeof(T) == typeof(float)) - || (typeof(T) == typeof(ushort)) - || (typeof(T) == typeof(uint)) - || (typeof(T) == typeof(ulong)) - || (typeof(T) == typeof(nuint)); + return Scalar.IsSupported; } } diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index e27b3e2daa26a9..756e31e561beec 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -2677,9 +2677,22 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas *op = MINT_LDC_I4_0; } else if (in_corlib && (!strncmp ("System.Runtime.Intrinsics", klass_name_space, 25))) { if (klass_name_space[25] == '\0' && - !strncmp ("Vector", klass_name, 6) && - !strcmp (tm, "get_IsHardwareAccelerated")) { - *op = MINT_LDC_I4_0; + !strncmp ("Vector", klass_name, 6)) { + if (!strcmp (tm, "get_IsHardwareAccelerated")) { + *op = MINT_LDC_I4_0; + } else if (!strcmp (tm, "get_IsSupported")) { + g_assert (mono_class_is_ginst (target_method->klass)); + + // Apart from filtering out non-primitive types this also filters out shared generic instance types like: T_BYTE which cannot be intrinsified + MonoType *etype = mono_class_get_context (target_method->klass)->class_inst->type_argv [0]; + + if (MONO_TYPE_IS_VECTOR_PRIMITIVE (etype)) { + *op = MINT_LDC_I4_1; + } else if (mini_type_get_underlying_type (etype)->type == MONO_TYPE_OBJECT) { + // Happens often in gshared code + *op = MINT_LDC_I4_0; + } + } } else if (klass_name_space[25] == '.') { if (!strncmp ("Arm", klass_name_space + 26, 3) || !strncmp ("X86", klass_name_space + 26, 3)) { @@ -2712,9 +2725,24 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas } } } else if (in_corlib && !strncmp ("System.Numerics", klass_name_space, 15)) { - if (!strcmp ("Vector", klass_name) && - !strcmp (tm, "get_IsHardwareAccelerated")) { - *op = MINT_LDC_I4_0; + if (!strcmp ("Vector", klass_name)) { + if (!strcmp (tm, "get_IsHardwareAccelerated")) { + *op = MINT_LDC_I4_0; + } + } else if (!strcmp ("Vector`1", klass_name)) { + if (!strcmp (tm, "get_IsSupported")) { + g_assert (mono_class_is_ginst (target_method->klass)); + + // Apart from filtering out non-primitive types this also filters out shared generic instance types like: T_BYTE which cannot be intrinsified + MonoType *etype = mono_class_get_context (target_method->klass)->class_inst->type_argv [0]; + + if (MONO_TYPE_IS_VECTOR_PRIMITIVE (etype)) { + *op = MINT_LDC_I4_1; + } else if (mini_type_get_underlying_type (etype)->type == MONO_TYPE_OBJECT) { + // Happens often in gshared code + *op = MINT_LDC_I4_0; + } + } } else if (!strcmp ("BitOperations", klass_name)) { int arg_type = (csignature->param_count > 0) ? csignature->params [0]->type : MONO_TYPE_VOID; if ((!strcmp (tm, "RotateLeft") || !strcmp (tm, "RotateRight")) && MINT_IS_LDC_I4 (td->last_ins->opcode)) { diff --git a/src/mono/mono/mini/intrinsics.c b/src/mono/mono/mini/intrinsics.c index 6ec87adc090b77..c6ccaf7d0701db 100644 --- a/src/mono/mono/mini/intrinsics.c +++ b/src/mono/mono/mini/intrinsics.c @@ -2436,6 +2436,28 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign ins->type = STACK_I4; return ins; } + + if (!strcmp (cmethod_name, "get_IsSupported")) { + if (mono_class_is_ginst (cmethod->klass)) { + // Apart from filtering out non-primitive types this also filters out shared generic instance types like: T_BYTE which cannot be intrinsified + MonoType *etype = mono_class_get_context (cmethod->klass)->class_inst->type_argv [0]; + + if (MONO_TYPE_IS_VECTOR_PRIMITIVE (etype)) { + EMIT_NEW_ICONST (cfg, ins, 1); + ins->type = STACK_I4; + return ins; + } else if (mini_type_get_underlying_type (etype)->type == MONO_TYPE_OBJECT) { + // Happens often in gshared code + EMIT_NEW_ICONST (cfg, ins, 0); + ins->type = STACK_I4; + return ins; + } + } else { + EMIT_NEW_ICONST (cfg, ins, 0); + ins->type = STACK_I4; + return ins; + } + } } // On FullAOT, return false for RuntimeFeature: diff --git a/src/mono/mono/mini/simd-intrinsics.c b/src/mono/mono/mini/simd-intrinsics.c index 21295764fad806..7f226a2d826afa 100644 --- a/src/mono/mono/mini/simd-intrinsics.c +++ b/src/mono/mono/mini/simd-intrinsics.c @@ -2020,8 +2020,14 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi else return NULL; - if (vector_size == 256 || vector_size == 512) + if (vector_size == 256 || vector_size == 512) { + if (id == SN_get_IsHardwareAccelerated) { + MonoInst* ins; + EMIT_NEW_ICONST (cfg, ins, 0); + return ins; + } return NULL; + } if (!(cfg->opt & MONO_OPT_SIMD)) return NULL;