This allows compiling for the ISA extensions that the currently running CPU supports.
#include "RuntimeInstance.h"
#include "CachedInterfaceDispatch.h"
#include "shash.h"
+#include <minipal/cpufeatures.h>
class AsmOffsets
{
${GC_DIR}/handletablescan.cpp
${GC_DIR}/objecthandle.cpp
${GC_DIR}/softwarewritewatch.cpp
+
+ ${CLR_SRC_NATIVE_DIR}/minipal/cpufeatures.c
)
set(SERVER_GC_SOURCES
list(APPEND FULL_RUNTIME_SOURCES windows/CoffNativeCodeManager.cpp)
set(ASM_SUFFIX asm)
-
- if (CLR_CMAKE_TARGET_ARCH_I386 OR CLR_CMAKE_TARGET_ARCH_AMD64)
- set(RUNTIME_SOURCES_ARCH_ASM ${ARCH_SOURCES_DIR}/GC.${ASM_SUFFIX})
- endif()
else()
include_directories(unix)
endif()
add_definitions(-DNO_UI_ASSERT)
include(unix/configure.cmake)
+ include(${CLR_SRC_NATIVE_DIR}/minipal/configure.cmake)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
endif()
#include "GCMemoryHelpers.inl"
#include "yieldprocessornormalized.h"
#include "RhConfig.h"
+#include <minipal/cpuid.h>
COOP_PINVOKE_HELPER(void, RhDebugBreak, ())
{
#include "CommonTypes.h"
#include "CommonMacros.h"
#include "gcenv.structs.h" // CRITICAL_SECTION
-#include "IntrinsicConstants.h"
#include "PalRedhawkCommon.h"
#ifndef PAL_REDHAWK_INCLUDED
REDHAWK_PALIMPORT int32_t __cdecl _stricmp(const char *string1, const char *string2);
#endif // TARGET_UNIX
-#if defined(HOST_X86) || defined(HOST_AMD64)
-
-#ifdef TARGET_UNIX
-// MSVC directly defines intrinsics for __cpuid and __cpuidex matching the below signatures
-// We define matching signatures for use on Unix platforms.
-//
-// IMPORTANT: Unlike MSVC, Unix does not explicitly zero ECX for __cpuid
-
-REDHAWK_PALIMPORT void __cpuid(int cpuInfo[4], int function_id);
-REDHAWK_PALIMPORT void __cpuidex(int cpuInfo[4], int function_id, int subFunction_id);
-#else
-#include <intrin.h>
-#endif
-
-REDHAWK_PALIMPORT uint32_t REDHAWK_PALAPI xmmYmmStateSupport();
-REDHAWK_PALIMPORT uint32_t REDHAWK_PALAPI avx512StateSupport();
-REDHAWK_PALIMPORT bool REDHAWK_PALAPI PalIsAvxEnabled();
-REDHAWK_PALIMPORT bool REDHAWK_PALAPI PalIsAvx512Enabled();
-
-#endif // defined(HOST_X86) || defined(HOST_AMD64)
-
-#if defined(HOST_ARM64)
-REDHAWK_PALIMPORT void REDHAWK_PALAPI PAL_GetCpuCapabilityFlags(int* flags);
-#endif //defined(HOST_ARM64)
-
#include "PalRedhawkInline.h"
#endif // !PAL_REDHAWK_INCLUDED
+++ /dev/null
-;; Licensed to the .NET Foundation under one or more agreements.
-;; The .NET Foundation licenses this file to you under the MIT license.
-
-include AsmMacros.inc
-
-;; extern "C" DWORD __stdcall xmmYmmStateSupport();
-LEAF_ENTRY xmmYmmStateSupport, _TEXT
- mov ecx, 0 ; Specify xcr0
- xgetbv ; result in EDX:EAX
- and eax, 06H
- cmp eax, 06H ; check OS has enabled both XMM and YMM state support
- jne not_supported
- mov eax, 1
- jmp done
- not_supported:
- mov eax, 0
- done:
- ret
-LEAF_END xmmYmmStateSupport, _TEXT
-
-;; extern "C" DWORD __stdcall avx512StateSupport();
-LEAF_ENTRY avx512StateSupport, _TEXT
- mov ecx, 0 ; Specify xcr0
- xgetbv ; result in EDX:EAX
- and eax, 0E6H
- cmp eax, 0E6H ; check OS has enabled XMM, YMM and ZMM state support
- jne not_supported
- mov eax, 1
- jmp done
- not_supported:
- mov eax, 0
- done:
- ret
-LEAF_END avx512StateSupport, _TEXT
-
- end
EXTERN RuntimeInstance__ShouldHijackLoopForGcStress : PROC
EXTERN g_fGcStressStarted : DWORD
-EXTERN g_fHasFastFxsave : BYTE
;;
;; INVARIANT: Don't trash the argument registers, the binder codegen depends on this.
#include "stressLog.h"
#include "RestrictedCallouts.h"
#include "yieldprocessornormalized.h"
+#include <minipal/cpufeatures.h>
#ifdef FEATURE_PERFTRACING
#include "EventPipeInterface.h"
extern RhConfig * g_pRhConfig;
-EXTERN_C bool g_fHasFastFxsave;
-bool g_fHasFastFxsave = false;
-
CrstStatic g_ThunkPoolLock;
#if defined(HOST_X86) || defined(HOST_AMD64) || defined(HOST_ARM64)
bool DetectCPUFeatures()
{
#if defined(HOST_X86) || defined(HOST_AMD64) || defined(HOST_ARM64)
-
-#if defined(HOST_X86) || defined(HOST_AMD64)
-
- int cpuidInfo[4];
-
- const int CPUID_EAX = 0;
- const int CPUID_EBX = 1;
- const int CPUID_ECX = 2;
- const int CPUID_EDX = 3;
-
- __cpuid(cpuidInfo, 0x00000000);
- uint32_t maxCpuId = static_cast<uint32_t>(cpuidInfo[CPUID_EAX]);
-
- if (maxCpuId >= 1)
- {
- __cpuid(cpuidInfo, 0x00000001);
-
- const int requiredBaselineEdxFlags = (1 << 25) // SSE
- | (1 << 26); // SSE2
-
- if ((cpuidInfo[CPUID_EDX] & requiredBaselineEdxFlags) == requiredBaselineEdxFlags)
- {
- g_cpuFeatures |= XArchIntrinsicConstants_VectorT128;
-
- if ((cpuidInfo[CPUID_ECX] & (1 << 25)) != 0) // AESNI
- {
- g_cpuFeatures |= XArchIntrinsicConstants_Aes;
- }
-
- if ((cpuidInfo[CPUID_ECX] & (1 << 1)) != 0) // PCLMULQDQ
- {
- g_cpuFeatures |= XArchIntrinsicConstants_Pclmulqdq;
- }
-
- if ((cpuidInfo[CPUID_ECX] & (1 << 0)) != 0) // SSE3
- {
- g_cpuFeatures |= XArchIntrinsicConstants_Sse3;
-
- if ((cpuidInfo[CPUID_ECX] & (1 << 9)) != 0) // SSSE3
- {
- g_cpuFeatures |= XArchIntrinsicConstants_Ssse3;
-
- if ((cpuidInfo[CPUID_ECX] & (1 << 19)) != 0) // SSE4.1
- {
- g_cpuFeatures |= XArchIntrinsicConstants_Sse41;
-
- if ((cpuidInfo[CPUID_ECX] & (1 << 20)) != 0) // SSE4.2
- {
- g_cpuFeatures |= XArchIntrinsicConstants_Sse42;
-
- if ((cpuidInfo[CPUID_ECX] & (1 << 22)) != 0) // MOVBE
- {
- g_cpuFeatures |= XArchIntrinsicConstants_Movbe;
- }
-
- if ((cpuidInfo[CPUID_ECX] & (1 << 23)) != 0) // POPCNT
- {
- g_cpuFeatures |= XArchIntrinsicConstants_Popcnt;
- }
-
- const int requiredAvxEcxFlags = (1 << 27) // OSXSAVE
- | (1 << 28); // AVX
-
- if ((cpuidInfo[CPUID_ECX] & requiredAvxEcxFlags) == requiredAvxEcxFlags)
- {
- if (PalIsAvxEnabled() && (xmmYmmStateSupport() == 1)) // XGETBV == 11
- {
- g_cpuFeatures |= XArchIntrinsicConstants_Avx;
-
- if ((cpuidInfo[CPUID_ECX] & (1 << 12)) != 0) // FMA
- {
- g_cpuFeatures |= XArchIntrinsicConstants_Fma;
- }
-
- if (maxCpuId >= 0x07)
- {
- __cpuidex(cpuidInfo, 0x00000007, 0x00000000);
-
- if ((cpuidInfo[CPUID_EBX] & (1 << 5)) != 0) // AVX2
- {
- g_cpuFeatures |= XArchIntrinsicConstants_Avx2;
- g_cpuFeatures |= XArchIntrinsicConstants_VectorT256;
-
- if (PalIsAvx512Enabled() && (avx512StateSupport() == 1)) // XGETBV XRC0[7:5] == 111
- {
- if ((cpuidInfo[CPUID_EBX] & (1 << 16)) != 0) // AVX512F
- {
- g_cpuFeatures |= XArchIntrinsicConstants_Avx512f;
- g_cpuFeatures |= XArchIntrinsicConstants_VectorT512;
-
- bool isAVX512_VLSupported = false;
- if ((cpuidInfo[CPUID_EBX] & (1 << 31)) != 0) // AVX512VL
- {
- g_cpuFeatures |= XArchIntrinsicConstants_Avx512f_vl;
- isAVX512_VLSupported = true;
- }
-
- if ((cpuidInfo[CPUID_EBX] & (1 << 30)) != 0) // AVX512BW
- {
- g_cpuFeatures |= XArchIntrinsicConstants_Avx512bw;
- if (isAVX512_VLSupported) // AVX512BW_VL
- {
- g_cpuFeatures |= XArchIntrinsicConstants_Avx512bw_vl;
- }
- }
-
- if ((cpuidInfo[CPUID_EBX] & (1 << 28)) != 0) // AVX512CD
- {
- g_cpuFeatures |= XArchIntrinsicConstants_Avx512cd;
- if (isAVX512_VLSupported) // AVX512CD_VL
- {
- g_cpuFeatures |= XArchIntrinsicConstants_Avx512cd_vl;
- }
- }
-
- if ((cpuidInfo[CPUID_EBX] & (1 << 17)) != 0) // AVX512DQ
- {
- g_cpuFeatures |= XArchIntrinsicConstants_Avx512dq;
- if (isAVX512_VLSupported) // AVX512DQ_VL
- {
- g_cpuFeatures |= XArchIntrinsicConstants_Avx512dq_vl;
- }
- }
-
- if ((cpuidInfo[CPUID_ECX] & (1 << 1)) != 0) // AVX512VBMI
- {
- g_cpuFeatures |= XArchIntrinsicConstants_Avx512Vbmi;
- if (isAVX512_VLSupported) // AVX512VBMI_VL
- {
- g_cpuFeatures |= XArchIntrinsicConstants_Avx512Vbmi_vl;
- }
- }
- }
- }
-
- __cpuidex(cpuidInfo, 0x00000007, 0x00000001);
-
- if ((cpuidInfo[CPUID_EAX] & (1 << 4)) != 0) // AVX-VNNI
- {
- g_cpuFeatures |= XArchIntrinsicConstants_AvxVnni;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
-
- if (maxCpuId >= 0x07)
- {
- __cpuidex(cpuidInfo, 0x00000007, 0x00000000);
-
- if ((cpuidInfo[CPUID_EBX] & (1 << 3)) != 0) // BMI1
- {
- g_cpuFeatures |= XArchIntrinsicConstants_Bmi1;
- }
-
- if ((cpuidInfo[CPUID_EBX] & (1 << 8)) != 0) // BMI2
- {
- g_cpuFeatures |= XArchIntrinsicConstants_Bmi2;
- }
-
- if ((cpuidInfo[CPUID_EDX] & (1 << 14)) != 0)
- {
- g_cpuFeatures |= XArchIntrinsicConstants_Serialize; // SERIALIZE
- }
- }
- }
-
- __cpuid(cpuidInfo, 0x80000000);
- uint32_t maxCpuIdEx = static_cast<uint32_t>(cpuidInfo[CPUID_EAX]);
-
- if (maxCpuIdEx >= 0x80000001)
- {
- __cpuid(cpuidInfo, 0x80000001);
-
- if ((cpuidInfo[CPUID_ECX] & (1 << 5)) != 0) // LZCNT
- {
- g_cpuFeatures |= XArchIntrinsicConstants_Lzcnt;
- }
-
-#ifdef HOST_AMD64
- // AMD has a "fast" mode for fxsave/fxrstor, which omits the saving of xmm registers. The OS will enable this mode
- // if it is supported. So if we continue to use fxsave/fxrstor, we must manually save/restore the xmm registers.
- // fxsr_opt is bit 25 of CPUID_EDX
- if ((cpuidInfo[CPUID_EDX] & (1 << 25)) != 0)
- g_fHasFastFxsave = true;
-#endif
- }
-#endif // HOST_X86 || HOST_AMD64
-
-#if defined(HOST_ARM64)
- PAL_GetCpuCapabilityFlags (&g_cpuFeatures);
-#endif
+ g_cpuFeatures = minipal_getcpufeatures();
if ((g_cpuFeatures & g_requiredCpuFeatures) != g_requiredCpuFeatures)
{
return moduleHandle;
}
-REDHAWK_PALEXPORT bool REDHAWK_PALAPI PalIsAvxEnabled()
-{
- return true;
-}
-
-REDHAWK_PALEXPORT bool REDHAWK_PALAPI PalIsAvx512Enabled()
-{
- return true;
-}
-
REDHAWK_PALEXPORT void PalPrintFatalError(const char* message)
{
// Write the message using lowest-level OS API available. This is used to print the stack overflow
#endif
}
-#if defined(HOST_X86) || defined(HOST_AMD64)
-// MSVC directly defines intrinsics for __cpuid and __cpuidex matching the below signatures
-// We define matching signatures for use on Unix platforms.
-//
-// IMPORTANT: Unlike MSVC, Unix does not explicitly zero ECX for __cpuid
-
-#if !__has_builtin(__cpuid)
-REDHAWK_PALEXPORT void __cpuid(int cpuInfo[4], int function_id)
-{
- // Based on the Clang implementation provided in cpuid.h:
- // https://github.com/llvm/llvm-project/blob/main/clang/lib/Headers/cpuid.h
-
- __asm(" cpuid\n" \
- : "=a"(cpuInfo[0]), "=b"(cpuInfo[1]), "=c"(cpuInfo[2]), "=d"(cpuInfo[3]) \
- : "0"(function_id)
- );
-}
-#endif
-
-#if !__has_builtin(__cpuidex)
-REDHAWK_PALEXPORT void __cpuidex(int cpuInfo[4], int function_id, int subFunction_id)
-{
- // Based on the Clang implementation provided in cpuid.h:
- // https://github.com/llvm/llvm-project/blob/main/clang/lib/Headers/cpuid.h
-
- __asm(" cpuid\n" \
- : "=a"(cpuInfo[0]), "=b"(cpuInfo[1]), "=c"(cpuInfo[2]), "=d"(cpuInfo[3]) \
- : "0"(function_id), "2"(subFunction_id)
- );
-}
-#endif
-
-REDHAWK_PALEXPORT uint32_t REDHAWK_PALAPI xmmYmmStateSupport()
-{
- DWORD eax;
- __asm(" xgetbv\n" \
- : "=a"(eax) /*output in eax*/\
- : "c"(0) /*inputs - 0 in ecx*/\
- : "edx" /* registers that are clobbered*/
- );
- // check OS has enabled both XMM and YMM state support
- return ((eax & 0x06) == 0x06) ? 1 : 0;
-}
-
-#ifndef XSTATE_MASK_AVX512
-#define XSTATE_MASK_AVX512 (0xE0) /* 0b1110_0000 */
-#endif // XSTATE_MASK_AVX512
-
-REDHAWK_PALEXPORT uint32_t REDHAWK_PALAPI avx512StateSupport()
-{
-#if defined(TARGET_APPLE)
- // MacOS has specialized behavior where it reports AVX512 support but doesnt
- // actually enable AVX512 until the first instruction is executed and does so
- // on a per thread basis. It does this by catching the faulting instruction and
- // checking for the EVEX encoding. The kmov instructions, despite being part
- // of the AVX512 instruction set are VEX encoded and dont trigger the enablement
- //
- // See https://github.com/apple/darwin-xnu/blob/main/osfmk/i386/fpu.c#L174
-
- // TODO-AVX512: Enabling this for OSX requires ensuring threads explicitly trigger
- // the AVX-512 enablement so that arbitrary usage doesn't cause downstream problems
-
- return false;
-#else
- DWORD eax;
- __asm(" xgetbv\n" \
- : "=a"(eax) /*output in eax*/\
- : "c"(0) /*inputs - 0 in ecx*/\
- : "edx" /* registers that are clobbered*/
- );
- // check OS has enabled XMM, YMM and ZMM state support
- return ((eax & 0xE6) == 0x0E6) ? 1 : 0;
-#endif
-}
-
-#endif // defined(HOST_X86) || defined(HOST_AMD64)
-
-#if defined (HOST_ARM64)
-
-#if HAVE_AUXV_HWCAP_H
-#include <sys/auxv.h>
-#include <asm/hwcap.h>
-#endif
-
-#if HAVE_SYSCTLBYNAME
-#include <sys/sysctl.h>
-#endif
-
-// Based on PAL_GetJitCpuCapabilityFlags from CoreCLR (jitsupport.cpp)
-REDHAWK_PALEXPORT void REDHAWK_PALAPI PAL_GetCpuCapabilityFlags(int* flags)
-{
- *flags = 0;
-
-#if HAVE_AUXV_HWCAP_H
- unsigned long hwCap = getauxval(AT_HWCAP);
-
- // HWCAP_* flags are introduced by ARM into the Linux kernel as new extensions are published.
- // For a given kernel, some of these flags may not be present yet.
- // Use ifdef for each to allow for compilation with any vintage kernel.
- // From a single binary distribution perspective, compiling with latest kernel asm/hwcap.h should
- // include all published flags. Given flags are merged to kernel and published before silicon is
- // available, using the latest kernel for release should be sufficient.
-
-#ifdef HWCAP_AES
- if (hwCap & HWCAP_AES)
- *flags |= ARM64IntrinsicConstants_Aes;
-#endif
-#ifdef HWCAP_ATOMICS
- if (hwCap & HWCAP_ATOMICS)
- *flags |= ARM64IntrinsicConstants_Atomics;
-#endif
-#ifdef HWCAP_CRC32
- if (hwCap & HWCAP_CRC32)
- *flags |= ARM64IntrinsicConstants_Crc32;
-#endif
-#ifdef HWCAP_DCPOP
-// if (hwCap & HWCAP_DCPOP)
-// *flags |= ARM64IntrinsicConstants_???;
-#endif
-#ifdef HWCAP_ASIMDDP
- if (hwCap & HWCAP_ASIMDDP)
- *flags |= ARM64IntrinsicConstants_Dp;
-#endif
-#ifdef HWCAP_FCMA
-// if (hwCap & HWCAP_FCMA)
-// *flags |= ARM64IntrinsicConstants_???;
-#endif
-#ifdef HWCAP_FP
-// if (hwCap & HWCAP_FP)
-// *flags |= ARM64IntrinsicConstants_???;
-#endif
-#ifdef HWCAP_FPHP
-// if (hwCap & HWCAP_FPHP)
-// *flags |= ARM64IntrinsicConstants_???;
-#endif
-#ifdef HWCAP_JSCVT
-// if (hwCap & HWCAP_JSCVT)
-// *flags |= ARM64IntrinsicConstants_???;
-#endif
-#ifdef HWCAP_LRCPC
- if (hwCap & HWCAP_LRCPC)
- *flags |= ARM64IntrinsicConstants_Rcpc;
-#endif
-#ifdef HWCAP_PMULL
-// if (hwCap & HWCAP_PMULL)
-// *flags |= ARM64IntrinsicConstants_???;
-#endif
-#ifdef HWCAP_SHA1
- if (hwCap & HWCAP_SHA1)
- *flags |= ARM64IntrinsicConstants_Sha1;
-#endif
-#ifdef HWCAP_SHA2
- if (hwCap & HWCAP_SHA2)
- *flags |= ARM64IntrinsicConstants_Sha256;
-#endif
-#ifdef HWCAP_SHA512
-// if (hwCap & HWCAP_SHA512)
-// *flags |= ARM64IntrinsicConstants_???;
-#endif
-#ifdef HWCAP_SHA3
-// if (hwCap & HWCAP_SHA3)
-// *flags |= ARM64IntrinsicConstants_???;
-#endif
-#ifdef HWCAP_ASIMD
- if (hwCap & HWCAP_ASIMD)
- *flags |= ARM64IntrinsicConstants_AdvSimd | ARM64IntrinsicConstants_VectorT128;
-#endif
-#ifdef HWCAP_ASIMDRDM
- if (hwCap & HWCAP_ASIMDRDM)
- *flags |= ARM64IntrinsicConstants_Rdm;
-#endif
-#ifdef HWCAP_ASIMDHP
-// if (hwCap & HWCAP_ASIMDHP)
-// *flags |= ARM64IntrinsicConstants_???;
-#endif
-#ifdef HWCAP_SM3
-// if (hwCap & HWCAP_SM3)
-// *flags |= ARM64IntrinsicConstants_???;
-#endif
-#ifdef HWCAP_SM4
-// if (hwCap & HWCAP_SM4)
-// *flags |= ARM64IntrinsicConstants_???;
-#endif
-#ifdef HWCAP_SVE
-// if (hwCap & HWCAP_SVE)
-// *flags |= ARM64IntrinsicConstants_???;
-#endif
-
-#ifdef AT_HWCAP2
- unsigned long hwCap2 = getauxval(AT_HWCAP2);
-
-#ifdef HWCAP2_DCPODP
-// if (hwCap2 & HWCAP2_DCPODP)
-// *flags |= ARM64IntrinsicConstants_???;
-#endif
-#ifdef HWCAP2_SVE2
-// if (hwCap2 & HWCAP2_SVE2)
-// *flags |= ARM64IntrinsicConstants_???;
-#endif
-#ifdef HWCAP2_SVEAES
-// if (hwCap2 & HWCAP2_SVEAES)
-// *flags |= ARM64IntrinsicConstants_???;
-#endif
-#ifdef HWCAP2_SVEPMULL
-// if (hwCap2 & HWCAP2_SVEPMULL)
-// *flags |= ARM64IntrinsicConstants_???;
-#endif
-#ifdef HWCAP2_SVEBITPERM
-// if (hwCap2 & HWCAP2_SVEBITPERM)
-// *flags |= ARM64IntrinsicConstants_???;
-#endif
-#ifdef HWCAP2_SVESHA3
-// if (hwCap2 & HWCAP2_SVESHA3)
-// *flags |= ARM64IntrinsicConstants_???;
-#endif
-#ifdef HWCAP2_SVESM4
-// if (hwCap2 & HWCAP2_SVESM4)
-// *flags |= ARM64IntrinsicConstants_???;
-#endif
-#ifdef HWCAP2_FLAGM2
-// if (hwCap2 & HWCAP2_FLAGM2)
-// *flags |= ARM64IntrinsicConstants_???;
-#endif
-#ifdef HWCAP2_FRINT
-// if (hwCap2 & HWCAP2_FRINT)
-// *flags |= ARM64IntrinsicConstants_???;
-#endif
-
-#endif // AT_HWCAP2
-
-#else // !HAVE_AUXV_HWCAP_H
-
-#if HAVE_SYSCTLBYNAME
- int64_t valueFromSysctl = 0;
- size_t sz = sizeof(valueFromSysctl);
-
- if ((sysctlbyname("hw.optional.arm.FEAT_AES", &valueFromSysctl, &sz, nullptr, 0) == 0) && (valueFromSysctl != 0))
- *flags |= ARM64IntrinsicConstants_Aes;
-
- if ((sysctlbyname("hw.optional.armv8_crc32", &valueFromSysctl, &sz, nullptr, 0) == 0) && (valueFromSysctl != 0))
- *flags |= ARM64IntrinsicConstants_Crc32;
-
- if ((sysctlbyname("hw.optional.arm.FEAT_DotProd", &valueFromSysctl, &sz, nullptr, 0) == 0) && (valueFromSysctl != 0))
- *flags |= ARM64IntrinsicConstants_Dp;
-
- if ((sysctlbyname("hw.optional.arm.FEAT_RDM", &valueFromSysctl, &sz, nullptr, 0) == 0) && (valueFromSysctl != 0))
- *flags |= ARM64IntrinsicConstants_Rdm;
-
- if ((sysctlbyname("hw.optional.arm.FEAT_SHA1", &valueFromSysctl, &sz, nullptr, 0) == 0) && (valueFromSysctl != 0))
- *flags |= ARM64IntrinsicConstants_Sha1;
-
- if ((sysctlbyname("hw.optional.arm.FEAT_SHA256", &valueFromSysctl, &sz, nullptr, 0) == 0) && (valueFromSysctl != 0))
- *flags |= ARM64IntrinsicConstants_Sha256;
-
- if ((sysctlbyname("hw.optional.armv8_1_atomics", &valueFromSysctl, &sz, nullptr, 0) == 0) && (valueFromSysctl != 0))
- *flags |= ARM64IntrinsicConstants_Atomics;
-
- if ((sysctlbyname("hw.optional.arm.FEAT_LRCPC", &valueFromSysctl, &sz, nullptr, 0) == 0) && (valueFromSysctl != 0))
- *flags |= ARM64IntrinsicConstants_Rcpc;
-#endif // HAVE_SYSCTLBYNAME
-
- // Every ARM64 CPU should support SIMD and FP
- // If the OS have no function to query for CPU capabilities we set just these
-
- *flags |= ARM64IntrinsicConstants_AdvSimd | ARM64IntrinsicConstants_VectorT128;
-#endif // HAVE_AUXV_HWCAP_H
-}
-#endif
list(APPEND CMAKE_REQUIRED_DEFINITIONS -D_FILE_OFFSET_BITS=64)
-check_include_files("sys/auxv.h;asm/hwcap.h" HAVE_AUXV_HWCAP_H)
-
check_library_exists(pthread pthread_create "" HAVE_LIBPTHREAD)
check_library_exists(c pthread_create "" HAVE_PTHREAD_IN_LIBC)
check_library_exists(${PTHREAD_LIBRARY} pthread_getthreadid_np "" HAVE_PTHREAD_GETTHREADID_NP)
check_function_exists(clock_nanosleep HAVE_CLOCK_NANOSLEEP)
-check_function_exists(sysctlbyname HAVE_SYSCTLBYNAME)
check_struct_has_member ("ucontext_t" uc_mcontext.gregs[0] ucontext.h HAVE_GREGSET_T)
check_struct_has_member ("ucontext_t" uc_mcontext.__gregs[0] ucontext.h HAVE___GREGSET_T)
return (HANDLE)module;
}
-REDHAWK_PALEXPORT bool REDHAWK_PALAPI PalIsAvxEnabled()
-{
- typedef DWORD64(WINAPI* PGETENABLEDXSTATEFEATURES)();
- PGETENABLEDXSTATEFEATURES pfnGetEnabledXStateFeatures = NULL;
-
- HMODULE hMod = LoadKernel32dll();
- if (hMod == NULL)
- return FALSE;
-
- pfnGetEnabledXStateFeatures = (PGETENABLEDXSTATEFEATURES)GetProcAddress(hMod, "GetEnabledXStateFeatures");
-
- if (pfnGetEnabledXStateFeatures == NULL)
- {
- return FALSE;
- }
-
- DWORD64 FeatureMask = pfnGetEnabledXStateFeatures();
- if ((FeatureMask & XSTATE_MASK_AVX) == 0)
- {
- return FALSE;
- }
-
- return TRUE;
-}
-
-REDHAWK_PALEXPORT bool REDHAWK_PALAPI PalIsAvx512Enabled()
-{
- typedef DWORD64(WINAPI* PGETENABLEDXSTATEFEATURES)();
- PGETENABLEDXSTATEFEATURES pfnGetEnabledXStateFeatures = NULL;
-
- HMODULE hMod = LoadKernel32dll();
- if (hMod == NULL)
- return FALSE;
-
- pfnGetEnabledXStateFeatures = (PGETENABLEDXSTATEFEATURES)GetProcAddress(hMod, "GetEnabledXStateFeatures");
-
- if (pfnGetEnabledXStateFeatures == NULL)
- {
- return FALSE;
- }
-
- DWORD64 FeatureMask = pfnGetEnabledXStateFeatures();
- if ((FeatureMask & XSTATE_MASK_AVX512) == 0)
- {
- return FALSE;
- }
-
- return TRUE;
-}
-
REDHAWK_PALEXPORT void* REDHAWK_PALAPI PalAddVectoredExceptionHandler(uint32_t firstHandler, _In_ PVECTORED_EXCEPTION_HANDLER vectoredHandler)
{
return AddVectoredExceptionHandler(firstHandler, vectoredHandler);
FlushInstructionCache(GetCurrentProcess(), pAddress, size);
}
-#if defined(HOST_ARM64)
-
-#include "IntrinsicConstants.h"
-
-REDHAWK_PALIMPORT void REDHAWK_PALAPI PAL_GetCpuCapabilityFlags(int* flags)
-{
- *flags = 0;
-
-// Older version of SDK would return false for these intrinsics
-// but make sure we pass the right values to the APIs
-#ifndef PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE
-#define PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE 34
-#endif
-#ifndef PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE
-#define PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE 43
-#endif
-#ifndef PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE
-#define PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE 45
-#endif
-
- // FP and SIMD support are enabled by default
- *flags |= ARM64IntrinsicConstants_AdvSimd | ARM64IntrinsicConstants_VectorT128;
-
- if (IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE))
- {
- *flags |= ARM64IntrinsicConstants_Aes;
- *flags |= ARM64IntrinsicConstants_Sha1;
- *flags |= ARM64IntrinsicConstants_Sha256;
- }
-
- if (IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE))
- {
- *flags |= ARM64IntrinsicConstants_Crc32;
- }
-
- if (IsProcessorFeaturePresent(PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE))
- {
- *flags |= ARM64IntrinsicConstants_Atomics;
- }
-
- if (IsProcessorFeaturePresent(PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE))
- {
- *flags |= ARM64IntrinsicConstants_Dp;
- }
-
- if (IsProcessorFeaturePresent(PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE))
- {
- *flags |= ARM64IntrinsicConstants_Rcpc;
- }
-}
-
-#endif
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System;
+using System.Diagnostics;
+
+using Internal.JitInterface;
using Internal.TypeSystem;
namespace ILCompiler
{
return !string.IsNullOrEmpty(InstructionSetSupport.GetHardwareIntrinsicId(method.Context.Target.Architecture, method.OwningType));
}
+
+ public static void AddRuntimeRequiredIsaFlagsToBuilder(InstructionSetSupportBuilder builder, int flags)
+ {
+ switch (builder.Architecture)
+ {
+ case TargetArchitecture.X86:
+ case TargetArchitecture.X64:
+ XArchIntrinsicConstants.AddToBuilder(builder, flags);
+ break;
+ case TargetArchitecture.ARM64:
+ Arm64IntrinsicConstants.AddToBuilder(builder, flags);
+ break;
+ default:
+ Debug.Fail("Probably unimplemented");
+ break;
+ }
+ }
+
+ // Keep these enumerations in sync with cpufeatures.h in the minipal.
+ private static class XArchIntrinsicConstants
+ {
+ // SSE and SSE2 are baseline ISAs - they're always available
+ public const int Aes = 0x0001;
+ public const int Pclmulqdq = 0x0002;
+ public const int Sse3 = 0x0004;
+ public const int Ssse3 = 0x0008;
+ public const int Sse41 = 0x0010;
+ public const int Sse42 = 0x0020;
+ public const int Popcnt = 0x0040;
+ public const int Avx = 0x0080;
+ public const int Fma = 0x0100;
+ public const int Avx2 = 0x0200;
+ public const int Bmi1 = 0x0400;
+ public const int Bmi2 = 0x0800;
+ public const int Lzcnt = 0x1000;
+ public const int AvxVnni = 0x2000;
+ public const int Movbe = 0x4000;
+ public const int Avx512f = 0x8000;
+ public const int Avx512f_vl = 0x10000;
+ public const int Avx512bw = 0x20000;
+ public const int Avx512bw_vl = 0x40000;
+ public const int Avx512cd = 0x80000;
+ public const int Avx512cd_vl = 0x100000;
+ public const int Avx512dq = 0x200000;
+ public const int Avx512dq_vl = 0x400000;
+ public const int Avx512Vbmi = 0x800000;
+ public const int Avx512Vbmi_vl = 0x1000000;
+ public const int Serialize = 0x2000000;
+ public const int VectorT128 = 0x4000000;
+ public const int VectorT256 = 0x8000000;
+ public const int VectorT512 = 0x10000000;
+
+ public static void AddToBuilder(InstructionSetSupportBuilder builder, int flags)
+ {
+ if ((flags & Aes) != 0)
+ builder.AddSupportedInstructionSet("aes");
+ if ((flags & Pclmulqdq) != 0)
+ builder.AddSupportedInstructionSet("pclmul");
+ if ((flags & Sse3) != 0)
+ builder.AddSupportedInstructionSet("sse3");
+ if ((flags & Ssse3) != 0)
+ builder.AddSupportedInstructionSet("ssse3");
+ if ((flags & Sse41) != 0)
+ builder.AddSupportedInstructionSet("sse4.1");
+ if ((flags & Sse42) != 0)
+ builder.AddSupportedInstructionSet("sse4.2");
+ if ((flags & Popcnt) != 0)
+ builder.AddSupportedInstructionSet("popcnt");
+ if ((flags & Avx) != 0)
+ builder.AddSupportedInstructionSet("avx");
+ if ((flags & Fma) != 0)
+ builder.AddSupportedInstructionSet("fma");
+ if ((flags & Avx2) != 0)
+ builder.AddSupportedInstructionSet("avx2");
+ if ((flags & Bmi1) != 0)
+ builder.AddSupportedInstructionSet("bmi");
+ if ((flags & Bmi2) != 0)
+ builder.AddSupportedInstructionSet("bmi2");
+ if ((flags & Lzcnt) != 0)
+ builder.AddSupportedInstructionSet("lzcnt");
+ if ((flags & AvxVnni) != 0)
+ builder.AddSupportedInstructionSet("avxvnni");
+ if ((flags & Movbe) != 0)
+ builder.AddSupportedInstructionSet("movbe");
+ if ((flags & Avx512f) != 0)
+ builder.AddSupportedInstructionSet("avx512f");
+ if ((flags & Avx512f_vl) != 0)
+ builder.AddSupportedInstructionSet("avx512f_vl");
+ if ((flags & Avx512bw) != 0)
+ builder.AddSupportedInstructionSet("avx512bw");
+ if ((flags & Avx512bw_vl) != 0)
+ builder.AddSupportedInstructionSet("avx512bw_vl");
+ if ((flags & Avx512cd) != 0)
+ builder.AddSupportedInstructionSet("avx512cd");
+ if ((flags & Avx512cd_vl) != 0)
+ builder.AddSupportedInstructionSet("avx512cd_vl");
+ if ((flags & Avx512dq) != 0)
+ builder.AddSupportedInstructionSet("avx512dq");
+ if ((flags & Avx512dq_vl) != 0)
+ builder.AddSupportedInstructionSet("avx512dq_vl");
+ if ((flags & Avx512Vbmi) != 0)
+ builder.AddSupportedInstructionSet("avx512vbmi");
+ if ((flags & Avx512Vbmi_vl) != 0)
+ builder.AddSupportedInstructionSet("avx512vbmi_vl");
+ if ((flags & Serialize) != 0)
+ builder.AddSupportedInstructionSet("serialize");
+ }
+
+ public static int FromInstructionSet(InstructionSet instructionSet)
+ {
+ Debug.Assert(InstructionSet.X64_AES == InstructionSet.X86_AES);
+ Debug.Assert(InstructionSet.X64_SSE41 == InstructionSet.X86_SSE41);
+ Debug.Assert(InstructionSet.X64_LZCNT == InstructionSet.X86_LZCNT);
+
+ return instructionSet switch
+ {
+ // Optional ISAs - only available via opt-in or opportunistic light-up
+ InstructionSet.X64_AES => Aes,
+ InstructionSet.X64_AES_X64 => Aes,
+ InstructionSet.X64_PCLMULQDQ => Pclmulqdq,
+ InstructionSet.X64_PCLMULQDQ_X64 => Pclmulqdq,
+ InstructionSet.X64_SSE3 => Sse3,
+ InstructionSet.X64_SSE3_X64 => Sse3,
+ InstructionSet.X64_SSSE3 => Ssse3,
+ InstructionSet.X64_SSSE3_X64 => Ssse3,
+ InstructionSet.X64_SSE41 => Sse41,
+ InstructionSet.X64_SSE41_X64 => Sse41,
+ InstructionSet.X64_SSE42 => Sse42,
+ InstructionSet.X64_SSE42_X64 => Sse42,
+ InstructionSet.X64_POPCNT => Popcnt,
+ InstructionSet.X64_POPCNT_X64 => Popcnt,
+ InstructionSet.X64_AVX => Avx,
+ InstructionSet.X64_AVX_X64 => Avx,
+ InstructionSet.X64_FMA => Fma,
+ InstructionSet.X64_FMA_X64 => Fma,
+ InstructionSet.X64_AVX2 => Avx2,
+ InstructionSet.X64_AVX2_X64 => Avx2,
+ InstructionSet.X64_BMI1 => Bmi1,
+ InstructionSet.X64_BMI1_X64 => Bmi1,
+ InstructionSet.X64_BMI2 => Bmi2,
+ InstructionSet.X64_BMI2_X64 => Bmi2,
+ InstructionSet.X64_LZCNT => Lzcnt,
+ InstructionSet.X64_LZCNT_X64 => Lzcnt,
+ InstructionSet.X64_AVXVNNI => AvxVnni,
+ InstructionSet.X64_AVXVNNI_X64 => AvxVnni,
+ InstructionSet.X64_MOVBE => Movbe,
+ InstructionSet.X64_MOVBE_X64 => Movbe,
+ InstructionSet.X64_AVX512F => Avx512f,
+ InstructionSet.X64_AVX512F_X64 => Avx512f,
+ InstructionSet.X64_AVX512F_VL => Avx512f_vl,
+ InstructionSet.X64_AVX512F_VL_X64 => Avx512f_vl,
+ InstructionSet.X64_AVX512BW => Avx512bw,
+ InstructionSet.X64_AVX512BW_X64 => Avx512bw,
+ InstructionSet.X64_AVX512BW_VL => Avx512bw_vl,
+ InstructionSet.X64_AVX512BW_VL_X64 => Avx512bw_vl,
+ InstructionSet.X64_AVX512CD => Avx512cd,
+ InstructionSet.X64_AVX512CD_X64 => Avx512cd,
+ InstructionSet.X64_AVX512CD_VL => Avx512cd_vl,
+ InstructionSet.X64_AVX512CD_VL_X64 => Avx512cd_vl,
+ InstructionSet.X64_AVX512DQ => Avx512dq,
+ InstructionSet.X64_AVX512DQ_X64 => Avx512dq,
+ InstructionSet.X64_AVX512DQ_VL => Avx512dq_vl,
+ InstructionSet.X64_AVX512DQ_VL_X64 => Avx512dq_vl,
+ InstructionSet.X64_AVX512VBMI => Avx512Vbmi,
+ InstructionSet.X64_AVX512VBMI_X64 => Avx512Vbmi,
+ InstructionSet.X64_AVX512VBMI_VL => Avx512Vbmi_vl,
+ InstructionSet.X64_AVX512VBMI_VL_X64 => Avx512Vbmi_vl,
+ InstructionSet.X64_X86Serialize => Serialize,
+ InstructionSet.X64_X86Serialize_X64 => Serialize,
+
+ // Baseline ISAs - they're always available
+ InstructionSet.X64_SSE => 0,
+ InstructionSet.X64_SSE_X64 => 0,
+ InstructionSet.X64_SSE2 => 0,
+ InstructionSet.X64_SSE2_X64 => 0,
+
+ InstructionSet.X64_X86Base => 0,
+ InstructionSet.X64_X86Base_X64 => 0,
+
+ // Vector<T> Sizes
+ InstructionSet.X64_VectorT128 => VectorT128,
+ InstructionSet.X64_VectorT256 => VectorT256,
+ InstructionSet.X64_VectorT512 => VectorT512,
+
+ _ => throw new NotSupportedException(((InstructionSet_X64)instructionSet).ToString())
+ };
+ }
+ }
+
+ // Keep these enumerations in sync with cpufeatures.h in the minipal.
+ private static class Arm64IntrinsicConstants
+ {
+ public const int AdvSimd = 0x0001;
+ public const int Aes = 0x0002;
+ public const int Crc32 = 0x0004;
+ public const int Dp = 0x0008;
+ public const int Rdm = 0x0010;
+ public const int Sha1 = 0x0020;
+ public const int Sha256 = 0x0040;
+ public const int Atomics = 0x0080;
+ public const int Rcpc = 0x0100;
+ public const int VectorT128 = 0x0200;
+
+ public static void AddToBuilder(InstructionSetSupportBuilder builder, int flags)
+ {
+ if ((flags & AdvSimd) != 0)
+ builder.AddSupportedInstructionSet("neon");
+ if ((flags & Aes) != 0)
+ builder.AddSupportedInstructionSet("aes");
+ if ((flags & Crc32) != 0)
+ builder.AddSupportedInstructionSet("crc");
+ if ((flags & Dp) != 0)
+ builder.AddSupportedInstructionSet("dotprod");
+ if ((flags & Rdm) != 0)
+ builder.AddSupportedInstructionSet("rdma");
+ if ((flags & Sha1) != 0)
+ builder.AddSupportedInstructionSet("sha1");
+ if ((flags & Sha256) != 0)
+ builder.AddSupportedInstructionSet("sha2");
+ if ((flags & Atomics) != 0)
+ builder.AddSupportedInstructionSet("lse");
+ if ((flags & Rcpc) != 0)
+ builder.AddSupportedInstructionSet("rcpc");
+ }
+
+ public static int FromInstructionSet(InstructionSet instructionSet)
+ {
+ return instructionSet switch
+ {
+
+ // Baseline ISAs - they're always available
+ InstructionSet.ARM64_ArmBase => 0,
+ InstructionSet.ARM64_ArmBase_Arm64 => 0,
+ InstructionSet.ARM64_AdvSimd => AdvSimd,
+ InstructionSet.ARM64_AdvSimd_Arm64 => AdvSimd,
+
+ // Optional ISAs - only available via opt-in or opportunistic light-up
+ InstructionSet.ARM64_Aes => Aes,
+ InstructionSet.ARM64_Aes_Arm64 => Aes,
+ InstructionSet.ARM64_Crc32 => Crc32,
+ InstructionSet.ARM64_Crc32_Arm64 => Crc32,
+ InstructionSet.ARM64_Dp => Dp,
+ InstructionSet.ARM64_Dp_Arm64 => Dp,
+ InstructionSet.ARM64_Rdm => Rdm,
+ InstructionSet.ARM64_Rdm_Arm64 => Rdm,
+ InstructionSet.ARM64_Sha1 => Sha1,
+ InstructionSet.ARM64_Sha1_Arm64 => Sha1,
+ InstructionSet.ARM64_Sha256 => Sha256,
+ InstructionSet.ARM64_Sha256_Arm64 => Sha256,
+ InstructionSet.ARM64_Atomics => Atomics,
+ InstructionSet.ARM64_Rcpc => Rcpc,
+
+ // Vector<T> Sizes
+ InstructionSet.ARM64_VectorT128 => VectorT128,
+
+ _ => throw new NotSupportedException(((InstructionSet_ARM64)instructionSet).ToString())
+ };
+ }
+ }
}
}
private readonly SortedSet<string> _unsupportedInstructionSets;
private readonly TargetArchitecture _architecture;
+ public TargetArchitecture Architecture => _architecture;
+
public InstructionSetSupportBuilder(TargetArchitecture architecture)
{
_supportedInstructionSets = new SortedSet<string>();
_architecture = other._architecture;
}
+ public override string ToString()
+ => (_supportedInstructionSets.Count > 0 ? "+" : "")
+ + string.Join(",+", _supportedInstructionSets)
+ + (_supportedInstructionSets.Count > 0 && _unsupportedInstructionSets.Count > 0 ? "," : "")
+ + (_unsupportedInstructionSets.Count > 0 ? "-" : "")
+ + string.Join(",-", _unsupportedInstructionSets);
+
/// <summary>
/// Add a supported instruction set to the specified list.
/// </summary>
using System.Collections.Generic;
using System.Diagnostics;
+using System.Runtime.InteropServices;
+
using ILCompiler;
+
using Internal.TypeSystem;
+
using InstructionSet = Internal.JitInterface.InstructionSet;
namespace System.CommandLine
internal static partial class Helpers
{
public static InstructionSetSupport ConfigureInstructionSetSupport(string instructionSet, int maxVectorTBitWidth, bool isVectorTOptimistic, TargetArchitecture targetArchitecture, TargetOS targetOS,
- string mustNotBeMessage, string invalidImplicationMessage)
+ string mustNotBeMessage, string invalidImplicationMessage, Logger logger)
{
InstructionSetSupportBuilder instructionSetSupportBuilder = new(targetArchitecture);
}
}
- if (instructionSet != null)
+ if (instructionSet == "native")
+ {
+ if (GetTargetArchitecture(null) != targetArchitecture)
+ {
+ throw new CommandLineException("Instruction set 'native' not supported when cross-compiling to a different architecture.");
+ }
+
+ string jitInterfaceLibrary = "jitinterface_" + RuntimeInformation.ProcessArchitecture.ToString().ToLowerInvariant();
+ nint libHandle = NativeLibrary.Load(jitInterfaceLibrary, System.Reflection.Assembly.GetExecutingAssembly(), DllImportSearchPath.ApplicationDirectory);
+ int cpuFeatures;
+ unsafe
+ {
+ var getCpuFeatures = (delegate* unmanaged<int>)NativeLibrary.GetExport(libHandle, "JitGetProcessorFeatures");
+ cpuFeatures = getCpuFeatures();
+ }
+ HardwareIntrinsicHelpers.AddRuntimeRequiredIsaFlagsToBuilder(instructionSetSupportBuilder, cpuFeatures);
+
+ if (logger.IsVerbose)
+ logger.LogMessage($"The 'native' instruction set expanded to {instructionSetSupportBuilder}");
+ }
+ else if (instructionSet != null)
{
List<string> instructionSetParams = new List<string>();
}
return result;
}
-
- // Keep these enumerations in sync with startup.cpp in the native runtime.
- private static class XArchIntrinsicConstants
- {
- // SSE and SSE2 are baseline ISAs - they're always available
- public const int Aes = 0x0001;
- public const int Pclmulqdq = 0x0002;
- public const int Sse3 = 0x0004;
- public const int Ssse3 = 0x0008;
- public const int Sse41 = 0x0010;
- public const int Sse42 = 0x0020;
- public const int Popcnt = 0x0040;
- public const int Avx = 0x0080;
- public const int Fma = 0x0100;
- public const int Avx2 = 0x0200;
- public const int Bmi1 = 0x0400;
- public const int Bmi2 = 0x0800;
- public const int Lzcnt = 0x1000;
- public const int AvxVnni = 0x2000;
- public const int Movbe = 0x4000;
- public const int Avx512f = 0x8000;
- public const int Avx512f_vl = 0x10000;
- public const int Avx512bw = 0x20000;
- public const int Avx512bw_vl = 0x40000;
- public const int Avx512cd = 0x80000;
- public const int Avx512cd_vl = 0x100000;
- public const int Avx512dq = 0x200000;
- public const int Avx512dq_vl = 0x400000;
- public const int Avx512Vbmi = 0x800000;
- public const int Avx512Vbmi_vl = 0x1000000;
- public const int Serialize = 0x2000000;
- public const int VectorT128 = 0x4000000;
- public const int VectorT256 = 0x8000000;
- public const int VectorT512 = 0x10000000;
-
- public static int FromInstructionSet(InstructionSet instructionSet)
- {
- Debug.Assert(InstructionSet.X64_AES == InstructionSet.X86_AES);
- Debug.Assert(InstructionSet.X64_SSE41 == InstructionSet.X86_SSE41);
- Debug.Assert(InstructionSet.X64_LZCNT == InstructionSet.X86_LZCNT);
-
- return instructionSet switch
- {
- // Optional ISAs - only available via opt-in or opportunistic light-up
- InstructionSet.X64_AES => Aes,
- InstructionSet.X64_AES_X64 => Aes,
- InstructionSet.X64_PCLMULQDQ => Pclmulqdq,
- InstructionSet.X64_PCLMULQDQ_X64 => Pclmulqdq,
- InstructionSet.X64_SSE3 => Sse3,
- InstructionSet.X64_SSE3_X64 => Sse3,
- InstructionSet.X64_SSSE3 => Ssse3,
- InstructionSet.X64_SSSE3_X64 => Ssse3,
- InstructionSet.X64_SSE41 => Sse41,
- InstructionSet.X64_SSE41_X64 => Sse41,
- InstructionSet.X64_SSE42 => Sse42,
- InstructionSet.X64_SSE42_X64 => Sse42,
- InstructionSet.X64_POPCNT => Popcnt,
- InstructionSet.X64_POPCNT_X64 => Popcnt,
- InstructionSet.X64_AVX => Avx,
- InstructionSet.X64_AVX_X64 => Avx,
- InstructionSet.X64_FMA => Fma,
- InstructionSet.X64_FMA_X64 => Fma,
- InstructionSet.X64_AVX2 => Avx2,
- InstructionSet.X64_AVX2_X64 => Avx2,
- InstructionSet.X64_BMI1 => Bmi1,
- InstructionSet.X64_BMI1_X64 => Bmi1,
- InstructionSet.X64_BMI2 => Bmi2,
- InstructionSet.X64_BMI2_X64 => Bmi2,
- InstructionSet.X64_LZCNT => Lzcnt,
- InstructionSet.X64_LZCNT_X64 => Lzcnt,
- InstructionSet.X64_AVXVNNI => AvxVnni,
- InstructionSet.X64_AVXVNNI_X64 => AvxVnni,
- InstructionSet.X64_MOVBE => Movbe,
- InstructionSet.X64_MOVBE_X64 => Movbe,
- InstructionSet.X64_AVX512F => Avx512f,
- InstructionSet.X64_AVX512F_X64 => Avx512f,
- InstructionSet.X64_AVX512F_VL => Avx512f_vl,
- InstructionSet.X64_AVX512F_VL_X64 => Avx512f_vl,
- InstructionSet.X64_AVX512BW => Avx512bw,
- InstructionSet.X64_AVX512BW_X64 => Avx512bw,
- InstructionSet.X64_AVX512BW_VL => Avx512bw_vl,
- InstructionSet.X64_AVX512BW_VL_X64 => Avx512bw_vl,
- InstructionSet.X64_AVX512CD => Avx512cd,
- InstructionSet.X64_AVX512CD_X64 => Avx512cd,
- InstructionSet.X64_AVX512CD_VL => Avx512cd_vl,
- InstructionSet.X64_AVX512CD_VL_X64 => Avx512cd_vl,
- InstructionSet.X64_AVX512DQ => Avx512dq,
- InstructionSet.X64_AVX512DQ_X64 => Avx512dq,
- InstructionSet.X64_AVX512DQ_VL => Avx512dq_vl,
- InstructionSet.X64_AVX512DQ_VL_X64 => Avx512dq_vl,
- InstructionSet.X64_AVX512VBMI => Avx512Vbmi,
- InstructionSet.X64_AVX512VBMI_X64 => Avx512Vbmi,
- InstructionSet.X64_AVX512VBMI_VL => Avx512Vbmi_vl,
- InstructionSet.X64_AVX512VBMI_VL_X64 => Avx512Vbmi_vl,
- InstructionSet.X64_X86Serialize => Serialize,
- InstructionSet.X64_X86Serialize_X64 => Serialize,
-
- // Baseline ISAs - they're always available
- InstructionSet.X64_SSE => 0,
- InstructionSet.X64_SSE_X64 => 0,
- InstructionSet.X64_SSE2 => 0,
- InstructionSet.X64_SSE2_X64 => 0,
-
- InstructionSet.X64_X86Base => 0,
- InstructionSet.X64_X86Base_X64 => 0,
-
- // Vector<T> Sizes
- InstructionSet.X64_VectorT128 => VectorT128,
- InstructionSet.X64_VectorT256 => VectorT256,
- InstructionSet.X64_VectorT512 => VectorT512,
-
- _ => throw new NotSupportedException(((InstructionSet_X64)instructionSet).ToString())
- };
- }
- }
-
- private static class Arm64IntrinsicConstants
- {
- public const int AdvSimd = 0x0001;
- public const int Aes = 0x0002;
- public const int Crc32 = 0x0004;
- public const int Dp = 0x0008;
- public const int Rdm = 0x0010;
- public const int Sha1 = 0x0020;
- public const int Sha256 = 0x0040;
- public const int Atomics = 0x0080;
- public const int Rcpc = 0x0100;
- public const int VectorT128 = 0x0200;
-
- public static int FromInstructionSet(InstructionSet instructionSet)
- {
- return instructionSet switch
- {
-
- // Baseline ISAs - they're always available
- InstructionSet.ARM64_ArmBase => 0,
- InstructionSet.ARM64_ArmBase_Arm64 => 0,
- InstructionSet.ARM64_AdvSimd => AdvSimd,
- InstructionSet.ARM64_AdvSimd_Arm64 => AdvSimd,
-
- // Optional ISAs - only available via opt-in or opportunistic light-up
- InstructionSet.ARM64_Aes => Aes,
- InstructionSet.ARM64_Aes_Arm64 => Aes,
- InstructionSet.ARM64_Crc32 => Crc32,
- InstructionSet.ARM64_Crc32_Arm64 => Crc32,
- InstructionSet.ARM64_Dp => Dp,
- InstructionSet.ARM64_Dp_Arm64 => Dp,
- InstructionSet.ARM64_Rdm => Rdm,
- InstructionSet.ARM64_Rdm_Arm64 => Rdm,
- InstructionSet.ARM64_Sha1 => Sha1,
- InstructionSet.ARM64_Sha1_Arm64 => Sha1,
- InstructionSet.ARM64_Sha256 => Sha256,
- InstructionSet.ARM64_Sha256_Arm64 => Sha256,
- InstructionSet.ARM64_Atomics => Atomics,
- InstructionSet.ARM64_Rcpc => Rcpc,
-
- // Vector<T> Sizes
- InstructionSet.ARM64_VectorT128 => VectorT128,
-
- _ => throw new NotSupportedException(((InstructionSet_ARM64)instructionSet).ToString())
- };
- }
- }
}
}
if (outputFilePath == null)
throw new CommandLineException("Output filename must be specified (/out <file>)");
+ var suppressedWarningCategories = new List<string>();
+ if (Get(_command.NoTrimWarn))
+ suppressedWarningCategories.Add(MessageSubCategory.TrimAnalysis);
+ if (Get(_command.NoAotWarn))
+ suppressedWarningCategories.Add(MessageSubCategory.AotAnalysis);
+
+ ILProvider ilProvider = new NativeAotILProvider();
+
+ var logger = new Logger(Console.Out, ilProvider, Get(_command.IsVerbose), ProcessWarningCodes(Get(_command.SuppressedWarnings)),
+ Get(_command.SingleWarn), Get(_command.SingleWarnEnabledAssemblies), Get(_command.SingleWarnDisabledAssemblies), suppressedWarningCategories);
+
// NativeAOT is full AOT and its pre-compiled methods can not be
// thrown away at runtime if they mismatch in required ISAs or
// computed layouts of structs. The worst case scenario is simply
TargetArchitecture targetArchitecture = Get(_command.TargetArchitecture);
TargetOS targetOS = Get(_command.TargetOS);
InstructionSetSupport instructionSetSupport = Helpers.ConfigureInstructionSetSupport(Get(_command.InstructionSet), Get(_command.MaxVectorTBitWidth), isVectorTOptimistic, targetArchitecture, targetOS,
- "Unrecognized instruction set {0}", "Unsupported combination of instruction sets: {0}/{1}");
+ "Unrecognized instruction set {0}", "Unsupported combination of instruction sets: {0}/{1}", logger);
string systemModuleName = Get(_command.SystemModuleName);
string reflectionData = Get(_command.ReflectionData);
PInvokeILEmitterConfiguration pinvokePolicy = new ConfigurablePInvokePolicy(typeSystemContext.Target,
Get(_command.DirectPInvokes), Get(_command.DirectPInvokeLists));
- ILProvider ilProvider = new NativeAotILProvider();
-
- var suppressedWarningCategories = new List<string>();
- if (Get(_command.NoTrimWarn))
- suppressedWarningCategories.Add(MessageSubCategory.TrimAnalysis);
- if (Get(_command.NoAotWarn))
- suppressedWarningCategories.Add(MessageSubCategory.AotAnalysis);
-
- var logger = new Logger(Console.Out, ilProvider, Get(_command.IsVerbose), ProcessWarningCodes(Get(_command.SuppressedWarnings)),
- Get(_command.SingleWarn), Get(_command.SingleWarnEnabledAssemblies), Get(_command.SingleWarnDisabledAssemblies), suppressedWarningCategories);
-
var featureSwitches = new Dictionary<string, bool>();
foreach (var switchPair in Get(_command.FeatureSwitches))
{
if (_singleFileCompilation && !_outNearInput)
throw new CommandLineException(SR.MissingOutNearInput);
+ var logger = new Logger(Console.Out, Get(_command.IsVerbose));
+
// Crossgen2 is partial AOT and its pre-compiled methods can be
// thrown away at runtime if they mismatch in required ISAs or
// computed layouts of structs. Thus we want to ensure that usage
TargetArchitecture targetArchitecture = Get(_command.TargetArchitecture);
TargetOS targetOS = Get(_command.TargetOS);
InstructionSetSupport instructionSetSupport = Helpers.ConfigureInstructionSetSupport(Get(_command.InstructionSet), Get(_command.MaxVectorTBitWidth), isVectorTOptimistic, targetArchitecture, targetOS,
- SR.InstructionSetMustNotBe, SR.InstructionSetInvalidImplication);
+ SR.InstructionSetMustNotBe, SR.InstructionSetInvalidImplication, logger);
SharedGenericsMode genericsMode = SharedGenericsMode.CanonicalReferenceTypes;
var targetDetails = new TargetDetails(targetArchitecture, targetOS, Crossgen2RootCommand.IsArmel ? TargetAbi.NativeAotArmel : TargetAbi.NativeAot, instructionSetSupport.GetVectorTSimdVector());
typeSystemContext.SetSystemModule((EcmaModule)typeSystemContext.GetModuleForSimpleName(systemModuleName));
}
- RunSingleCompilation(singleCompilationInputFilePaths, instructionSetSupport, compositeRootPath, unrootedInputFilePaths, singleCompilationVersionBubbleModulesHash, typeSystemContext);
+ RunSingleCompilation(singleCompilationInputFilePaths, instructionSetSupport, compositeRootPath, unrootedInputFilePaths, singleCompilationVersionBubbleModulesHash, typeSystemContext, logger);
}
// In case of inputbubble ni.dll are created as ni.dll.tmp in order to not interfere with crossgen2, move them all to ni.dll
}
else
{
- RunSingleCompilation(inputFilePaths, instructionSetSupport, compositeRootPath, unrootedInputFilePaths, versionBubbleModulesHash, typeSystemContext);
+ RunSingleCompilation(inputFilePaths, instructionSetSupport, compositeRootPath, unrootedInputFilePaths, versionBubbleModulesHash, typeSystemContext, logger);
}
return 0;
}
- private void RunSingleCompilation(Dictionary<string, string> inFilePaths, InstructionSetSupport instructionSetSupport, string compositeRootPath, Dictionary<string, string> unrootedInputFilePaths, HashSet<ModuleDesc> versionBubbleModulesHash, ReadyToRunCompilerContext typeSystemContext)
+ private void RunSingleCompilation(Dictionary<string, string> inFilePaths, InstructionSetSupport instructionSetSupport, string compositeRootPath, Dictionary<string, string> unrootedInputFilePaths, HashSet<ModuleDesc> versionBubbleModulesHash, ReadyToRunCompilerContext typeSystemContext, Logger logger)
{
//
// Initialize output filename
// Single method mode?
MethodDesc singleMethod = CheckAndParseSingleMethodModeArguments(typeSystemContext);
- var logger = new Logger(Console.Out, Get(_command.IsVerbose));
-
List<string> mibcFiles = new List<string>();
foreach (var file in Get(_command.MibcFilePaths))
{
jitinterface.cpp
jitwrapper.cpp
corinfoexception.cpp
+
+ ${CLR_SRC_NATIVE_DIR}/minipal/cpufeatures.c
)
if(CLR_CMAKE_TARGET_WIN32)
set(JITINTERFACE_RESOURCES Native.rc)
-endif(CLR_CMAKE_TARGET_WIN32)
+else()
+ include(${CLR_SRC_NATIVE_DIR}/minipal/configure.cmake)
+ include_directories(${CMAKE_CURRENT_BINARY_DIR})
+endif()
add_library_clr(jitinterface_${ARCH_HOST_NAME}
SHARED
#include <stdlib.h>
#include <stdint.h>
+#include <minipal/cpufeatures.h>
+
#include "dllexport.h"
#include "jitinterface_generated.h"
{
return pJit->ProcessShutdownWork(nullptr);
}
+
+DLL_EXPORT int JitGetProcessorFeatures()
+{
+ return minipal_getcpufeatures();
+}
--- /dev/null
+include(CheckFunctionExists)
+include(CheckIncludeFiles)
+
+check_include_files("sys/auxv.h;asm/hwcap.h" HAVE_AUXV_HWCAP_H)
+check_function_exists(sysctlbyname HAVE_SYSCTLBYNAME)
+
+configure_file(${CMAKE_CURRENT_LIST_DIR}/minipalconfig.h.in ${CMAKE_CURRENT_BINARY_DIR}/minipalconfig.h)
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+#include "cpufeatures.h"
+#include "cpuid.h"
+
+#if TARGET_WINDOWS
+
+#include <Windows.h>
+
+#else // TARGET_WINDOWS
+
+#include "minipalconfig.h"
+
+#if HAVE_AUXV_HWCAP_H
+#include <sys/auxv.h>
+#include <asm/hwcap.h>
+#endif
+
+#if HAVE_SYSCTLBYNAME
+#include <sys/sysctl.h>
+#endif
+
+#endif // !TARGET_WINDOWS
+
+#if defined(TARGET_UNIX)
+#if defined(TARGET_X86) || defined(TARGET_AMD64)
+
+static uint32_t xmmYmmStateSupport()
+{
+ uint32_t eax;
+ __asm(" xgetbv\n" \
+ : "=a"(eax) /*output in eax*/\
+ : "c"(0) /*inputs - 0 in ecx*/\
+ : "edx" /* registers that are clobbered*/
+ );
+ // check OS has enabled both XMM and YMM state support
+ return ((eax & 0x06) == 0x06) ? 1 : 0;
+}
+
+#ifndef XSTATE_MASK_AVX512
+#define XSTATE_MASK_AVX512 (0xE0) /* 0b1110_0000 */
+#endif // XSTATE_MASK_AVX512
+
+static uint32_t avx512StateSupport()
+{
+#if defined(TARGET_APPLE)
+ // MacOS has specialized behavior where it reports AVX512 support but doesnt
+ // actually enable AVX512 until the first instruction is executed and does so
+ // on a per thread basis. It does this by catching the faulting instruction and
+ // checking for the EVEX encoding. The kmov instructions, despite being part
+ // of the AVX512 instruction set are VEX encoded and dont trigger the enablement
+ //
+ // See https://github.com/apple/darwin-xnu/blob/main/osfmk/i386/fpu.c#L174
+
+ // TODO-AVX512: Enabling this for OSX requires ensuring threads explicitly trigger
+ // the AVX-512 enablement so that arbitrary usage doesn't cause downstream problems
+
+ return false;
+#else
+ uint32_t eax;
+ __asm(" xgetbv\n" \
+ : "=a"(eax) /*output in eax*/\
+ : "c"(0) /*inputs - 0 in ecx*/\
+ : "edx" /* registers that are clobbered*/
+ );
+ // check OS has enabled XMM, YMM and ZMM state support
+ return ((eax & 0xE6) == 0x0E6) ? 1 : 0;
+#endif
+}
+
+static bool IsAvxEnabled()
+{
+ return true;
+}
+
+static bool IsAvx512Enabled()
+{
+ return true;
+}
+#endif // defined(TARGET_X86) || defined(TARGET_AMD64)
+#endif // TARGET_UNIX
+
+#if defined(TARGET_WINDOWS)
+#if defined(TARGET_X86) || defined(TARGET_AMD64)
+static uint32_t xmmYmmStateSupport()
+{
+ // check OS has enabled both XMM and YMM state support
+ return ((_xgetbv(0) & 0x06) == 0x06) ? 1 : 0;
+}
+
+static uint32_t avx512StateSupport()
+{
+ // check OS has enabled XMM, YMM and ZMM state support
+ return ((_xgetbv(0) & 0xE6) == 0x0E6) ? 1 : 0;
+}
+
+static HMODULE LoadKernel32dll()
+{
+ return LoadLibraryExW(L"kernel32", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
+}
+
+static bool IsAvxEnabled()
+{
+ typedef DWORD64(WINAPI* PGETENABLEDXSTATEFEATURES)();
+ PGETENABLEDXSTATEFEATURES pfnGetEnabledXStateFeatures = NULL;
+
+ HMODULE hMod = LoadKernel32dll();
+ if (hMod == NULL)
+ return FALSE;
+
+ pfnGetEnabledXStateFeatures = (PGETENABLEDXSTATEFEATURES)GetProcAddress(hMod, "GetEnabledXStateFeatures");
+
+ if (pfnGetEnabledXStateFeatures == NULL)
+ {
+ return FALSE;
+ }
+
+ DWORD64 FeatureMask = pfnGetEnabledXStateFeatures();
+ if ((FeatureMask & XSTATE_MASK_AVX) == 0)
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static bool IsAvx512Enabled()
+{
+ typedef DWORD64(WINAPI* PGETENABLEDXSTATEFEATURES)();
+ PGETENABLEDXSTATEFEATURES pfnGetEnabledXStateFeatures = NULL;
+
+ HMODULE hMod = LoadKernel32dll();
+ if (hMod == NULL)
+ return FALSE;
+
+ pfnGetEnabledXStateFeatures = (PGETENABLEDXSTATEFEATURES)GetProcAddress(hMod, "GetEnabledXStateFeatures");
+
+ if (pfnGetEnabledXStateFeatures == NULL)
+ {
+ return FALSE;
+ }
+
+ DWORD64 FeatureMask = pfnGetEnabledXStateFeatures();
+ if ((FeatureMask & XSTATE_MASK_AVX512) == 0)
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+#endif // defined(TARGET_X86) || defined(TARGET_AMD64)
+#endif // TARGET_WINDOWS
+
+int minipal_getcpufeatures(void)
+{
+ int result = 0;
+
+#if defined(TARGET_X86) || defined(TARGET_AMD64)
+
+ int cpuidInfo[4];
+
+ const int CPUID_EAX = 0;
+ const int CPUID_EBX = 1;
+ const int CPUID_ECX = 2;
+ const int CPUID_EDX = 3;
+
+ __cpuid(cpuidInfo, 0x00000000);
+ uint32_t maxCpuId = (uint32_t)cpuidInfo[CPUID_EAX];
+
+ if (maxCpuId >= 1)
+ {
+ __cpuid(cpuidInfo, 0x00000001);
+
+ const int requiredBaselineEdxFlags = (1 << 25) // SSE
+ | (1 << 26); // SSE2
+
+ if ((cpuidInfo[CPUID_EDX] & requiredBaselineEdxFlags) == requiredBaselineEdxFlags)
+ {
+ result |= XArchIntrinsicConstants_VectorT128;
+
+ if ((cpuidInfo[CPUID_ECX] & (1 << 25)) != 0) // AESNI
+ {
+ result |= XArchIntrinsicConstants_Aes;
+ }
+
+ if ((cpuidInfo[CPUID_ECX] & (1 << 1)) != 0) // PCLMULQDQ
+ {
+ result |= XArchIntrinsicConstants_Pclmulqdq;
+ }
+
+ if ((cpuidInfo[CPUID_ECX] & (1 << 0)) != 0) // SSE3
+ {
+ result |= XArchIntrinsicConstants_Sse3;
+
+ if ((cpuidInfo[CPUID_ECX] & (1 << 9)) != 0) // SSSE3
+ {
+ result |= XArchIntrinsicConstants_Ssse3;
+
+ if ((cpuidInfo[CPUID_ECX] & (1 << 19)) != 0) // SSE4.1
+ {
+ result |= XArchIntrinsicConstants_Sse41;
+
+ if ((cpuidInfo[CPUID_ECX] & (1 << 20)) != 0) // SSE4.2
+ {
+ result |= XArchIntrinsicConstants_Sse42;
+
+ if ((cpuidInfo[CPUID_ECX] & (1 << 22)) != 0) // MOVBE
+ {
+ result |= XArchIntrinsicConstants_Movbe;
+ }
+
+ if ((cpuidInfo[CPUID_ECX] & (1 << 23)) != 0) // POPCNT
+ {
+ result |= XArchIntrinsicConstants_Popcnt;
+ }
+
+ const int requiredAvxEcxFlags = (1 << 27) // OSXSAVE
+ | (1 << 28); // AVX
+
+ if ((cpuidInfo[CPUID_ECX] & requiredAvxEcxFlags) == requiredAvxEcxFlags)
+ {
+ if (IsAvxEnabled() && (xmmYmmStateSupport() == 1)) // XGETBV == 11
+ {
+ result |= XArchIntrinsicConstants_Avx;
+
+ if ((cpuidInfo[CPUID_ECX] & (1 << 12)) != 0) // FMA
+ {
+ result |= XArchIntrinsicConstants_Fma;
+ }
+
+ if (maxCpuId >= 0x07)
+ {
+ __cpuidex(cpuidInfo, 0x00000007, 0x00000000);
+
+ if ((cpuidInfo[CPUID_EBX] & (1 << 5)) != 0) // AVX2
+ {
+ result |= XArchIntrinsicConstants_Avx2;
+ result |= XArchIntrinsicConstants_VectorT256;
+
+ if (IsAvx512Enabled() && (avx512StateSupport() == 1)) // XGETBV XRC0[7:5] == 111
+ {
+ if ((cpuidInfo[CPUID_EBX] & (1 << 16)) != 0) // AVX512F
+ {
+ result |= XArchIntrinsicConstants_Avx512f;
+ result |= XArchIntrinsicConstants_VectorT512;
+
+ bool isAVX512_VLSupported = false;
+ if ((cpuidInfo[CPUID_EBX] & (1 << 31)) != 0) // AVX512VL
+ {
+ result |= XArchIntrinsicConstants_Avx512f_vl;
+ isAVX512_VLSupported = true;
+ }
+
+ if ((cpuidInfo[CPUID_EBX] & (1 << 30)) != 0) // AVX512BW
+ {
+ result |= XArchIntrinsicConstants_Avx512bw;
+ if (isAVX512_VLSupported) // AVX512BW_VL
+ {
+ result |= XArchIntrinsicConstants_Avx512bw_vl;
+ }
+ }
+
+ if ((cpuidInfo[CPUID_EBX] & (1 << 28)) != 0) // AVX512CD
+ {
+ result |= XArchIntrinsicConstants_Avx512cd;
+ if (isAVX512_VLSupported) // AVX512CD_VL
+ {
+ result |= XArchIntrinsicConstants_Avx512cd_vl;
+ }
+ }
+
+ if ((cpuidInfo[CPUID_EBX] & (1 << 17)) != 0) // AVX512DQ
+ {
+ result |= XArchIntrinsicConstants_Avx512dq;
+ if (isAVX512_VLSupported) // AVX512DQ_VL
+ {
+ result |= XArchIntrinsicConstants_Avx512dq_vl;
+ }
+ }
+
+ if ((cpuidInfo[CPUID_ECX] & (1 << 1)) != 0) // AVX512VBMI
+ {
+ result |= XArchIntrinsicConstants_Avx512Vbmi;
+ if (isAVX512_VLSupported) // AVX512VBMI_VL
+ {
+ result |= XArchIntrinsicConstants_Avx512Vbmi_vl;
+ }
+ }
+ }
+ }
+
+ __cpuidex(cpuidInfo, 0x00000007, 0x00000001);
+
+ if ((cpuidInfo[CPUID_EAX] & (1 << 4)) != 0) // AVX-VNNI
+ {
+ result |= XArchIntrinsicConstants_AvxVnni;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (maxCpuId >= 0x07)
+ {
+ __cpuidex(cpuidInfo, 0x00000007, 0x00000000);
+
+ if ((cpuidInfo[CPUID_EBX] & (1 << 3)) != 0) // BMI1
+ {
+ result |= XArchIntrinsicConstants_Bmi1;
+ }
+
+ if ((cpuidInfo[CPUID_EBX] & (1 << 8)) != 0) // BMI2
+ {
+ result |= XArchIntrinsicConstants_Bmi2;
+ }
+
+ if ((cpuidInfo[CPUID_EDX] & (1 << 14)) != 0)
+ {
+ result |= XArchIntrinsicConstants_Serialize; // SERIALIZE
+ }
+ }
+ }
+
+ __cpuid(cpuidInfo, 0x80000000);
+ uint32_t maxCpuIdEx = (uint32_t)cpuidInfo[CPUID_EAX];
+
+ if (maxCpuIdEx >= 0x80000001)
+ {
+ __cpuid(cpuidInfo, 0x80000001);
+
+ if ((cpuidInfo[CPUID_ECX] & (1 << 5)) != 0) // LZCNT
+ {
+ result |= XArchIntrinsicConstants_Lzcnt;
+ }
+
+ }
+#endif // TARGET_X86 || TARGET_AMD64
+
+#if defined(TARGET_ARM64)
+#if defined(TARGET_UNIX)
+ #if HAVE_AUXV_HWCAP_H
+ unsigned long hwCap = getauxval(AT_HWCAP);
+
+ // HWCAP_* flags are introduced by ARM into the Linux kernel as new extensions are published.
+ // For a given kernel, some of these flags may not be present yet.
+ // Use ifdef for each to allow for compilation with any vintage kernel.
+ // From a single binary distribution perspective, compiling with latest kernel asm/hwcap.h should
+ // include all published flags. Given flags are merged to kernel and published before silicon is
+ // available, using the latest kernel for release should be sufficient.
+
+#ifdef HWCAP_AES
+ if (hwCap & HWCAP_AES)
+ result |= ARM64IntrinsicConstants_Aes;
+#endif
+#ifdef HWCAP_ATOMICS
+ if (hwCap & HWCAP_ATOMICS)
+ result |= ARM64IntrinsicConstants_Atomics;
+#endif
+#ifdef HWCAP_CRC32
+ if (hwCap & HWCAP_CRC32)
+ result |= ARM64IntrinsicConstants_Crc32;
+#endif
+#ifdef HWCAP_DCPOP
+// if (hwCap & HWCAP_DCPOP)
+// result |= ARM64IntrinsicConstants_???;
+#endif
+#ifdef HWCAP_ASIMDDP
+ if (hwCap & HWCAP_ASIMDDP)
+ result |= ARM64IntrinsicConstants_Dp;
+#endif
+#ifdef HWCAP_FCMA
+// if (hwCap & HWCAP_FCMA)
+// result |= ARM64IntrinsicConstants_???;
+#endif
+#ifdef HWCAP_FP
+// if (hwCap & HWCAP_FP)
+// result |= ARM64IntrinsicConstants_???;
+#endif
+#ifdef HWCAP_FPHP
+// if (hwCap & HWCAP_FPHP)
+// result |= ARM64IntrinsicConstants_???;
+#endif
+#ifdef HWCAP_JSCVT
+// if (hwCap & HWCAP_JSCVT)
+// result |= ARM64IntrinsicConstants_???;
+#endif
+#ifdef HWCAP_LRCPC
+ if (hwCap & HWCAP_LRCPC)
+ result |= ARM64IntrinsicConstants_Rcpc;
+#endif
+#ifdef HWCAP_PMULL
+// if (hwCap & HWCAP_PMULL)
+// result |= ARM64IntrinsicConstants_???;
+#endif
+#ifdef HWCAP_SHA1
+ if (hwCap & HWCAP_SHA1)
+ result |= ARM64IntrinsicConstants_Sha1;
+#endif
+#ifdef HWCAP_SHA2
+ if (hwCap & HWCAP_SHA2)
+ result |= ARM64IntrinsicConstants_Sha256;
+#endif
+#ifdef HWCAP_SHA512
+// if (hwCap & HWCAP_SHA512)
+// result |= ARM64IntrinsicConstants_???;
+#endif
+#ifdef HWCAP_SHA3
+// if (hwCap & HWCAP_SHA3)
+// result |= ARM64IntrinsicConstants_???;
+#endif
+#ifdef HWCAP_ASIMD
+ if (hwCap & HWCAP_ASIMD)
+ result |= ARM64IntrinsicConstants_AdvSimd | ARM64IntrinsicConstants_VectorT128;
+#endif
+#ifdef HWCAP_ASIMDRDM
+ if (hwCap & HWCAP_ASIMDRDM)
+ result |= ARM64IntrinsicConstants_Rdm;
+#endif
+#ifdef HWCAP_ASIMDHP
+// if (hwCap & HWCAP_ASIMDHP)
+// result |= ARM64IntrinsicConstants_???;
+#endif
+#ifdef HWCAP_SM3
+// if (hwCap & HWCAP_SM3)
+// result |= ARM64IntrinsicConstants_???;
+#endif
+#ifdef HWCAP_SM4
+// if (hwCap & HWCAP_SM4)
+// result |= ARM64IntrinsicConstants_???;
+#endif
+#ifdef HWCAP_SVE
+// if (hwCap & HWCAP_SVE)
+// result |= ARM64IntrinsicConstants_???;
+#endif
+
+#ifdef AT_HWCAP2
+ unsigned long hwCap2 = getauxval(AT_HWCAP2);
+
+#ifdef HWCAP2_DCPODP
+// if (hwCap2 & HWCAP2_DCPODP)
+// result |= ARM64IntrinsicConstants_???;
+#endif
+#ifdef HWCAP2_SVE2
+// if (hwCap2 & HWCAP2_SVE2)
+// result |= ARM64IntrinsicConstants_???;
+#endif
+#ifdef HWCAP2_SVEAES
+// if (hwCap2 & HWCAP2_SVEAES)
+// result |= ARM64IntrinsicConstants_???;
+#endif
+#ifdef HWCAP2_SVEPMULL
+// if (hwCap2 & HWCAP2_SVEPMULL)
+// result |= ARM64IntrinsicConstants_???;
+#endif
+#ifdef HWCAP2_SVEBITPERM
+// if (hwCap2 & HWCAP2_SVEBITPERM)
+// result |= ARM64IntrinsicConstants_???;
+#endif
+#ifdef HWCAP2_SVESHA3
+// if (hwCap2 & HWCAP2_SVESHA3)
+// result |= ARM64IntrinsicConstants_???;
+#endif
+#ifdef HWCAP2_SVESM4
+// if (hwCap2 & HWCAP2_SVESM4)
+// result |= ARM64IntrinsicConstants_???;
+#endif
+#ifdef HWCAP2_FLAGM2
+// if (hwCap2 & HWCAP2_FLAGM2)
+// result |= ARM64IntrinsicConstants_???;
+#endif
+#ifdef HWCAP2_FRINT
+// if (hwCap2 & HWCAP2_FRINT)
+// result |= ARM64IntrinsicConstants_???;
+#endif
+
+#endif // AT_HWCAP2
+
+#else // !HAVE_AUXV_HWCAP_H
+
+#if HAVE_SYSCTLBYNAME
+ int64_t valueFromSysctl = 0;
+ size_t sz = sizeof(valueFromSysctl);
+
+ if ((sysctlbyname("hw.optional.arm.FEAT_AES", &valueFromSysctl, &sz, NULL, 0) == 0) && (valueFromSysctl != 0))
+ result |= ARM64IntrinsicConstants_Aes;
+
+ if ((sysctlbyname("hw.optional.armv8_crc32", &valueFromSysctl, &sz, NULL, 0) == 0) && (valueFromSysctl != 0))
+ result |= ARM64IntrinsicConstants_Crc32;
+
+ if ((sysctlbyname("hw.optional.arm.FEAT_DotProd", &valueFromSysctl, &sz, NULL, 0) == 0) && (valueFromSysctl != 0))
+ result |= ARM64IntrinsicConstants_Dp;
+
+ if ((sysctlbyname("hw.optional.arm.FEAT_RDM", &valueFromSysctl, &sz, NULL, 0) == 0) && (valueFromSysctl != 0))
+ result |= ARM64IntrinsicConstants_Rdm;
+
+ if ((sysctlbyname("hw.optional.arm.FEAT_SHA1", &valueFromSysctl, &sz, NULL, 0) == 0) && (valueFromSysctl != 0))
+ result |= ARM64IntrinsicConstants_Sha1;
+
+ if ((sysctlbyname("hw.optional.arm.FEAT_SHA256", &valueFromSysctl, &sz, NULL, 0) == 0) && (valueFromSysctl != 0))
+ result |= ARM64IntrinsicConstants_Sha256;
+
+ if ((sysctlbyname("hw.optional.armv8_1_atomics", &valueFromSysctl, &sz, NULL, 0) == 0) && (valueFromSysctl != 0))
+ result |= ARM64IntrinsicConstants_Atomics;
+
+ if ((sysctlbyname("hw.optional.arm.FEAT_LRCPC", &valueFromSysctl, &sz, NULL, 0) == 0) && (valueFromSysctl != 0))
+ result |= ARM64IntrinsicConstants_Rcpc;
+#endif // HAVE_SYSCTLBYNAME
+
+ // Every ARM64 CPU should support SIMD and FP
+ // If the OS have no function to query for CPU capabilities we set just these
+
+ result |= ARM64IntrinsicConstants_AdvSimd | ARM64IntrinsicConstants_VectorT128;
+#endif // HAVE_AUXV_HWCAP_H
+#endif // TARGET_UNIX
+
+#if defined(TARGET_WINDOWS)
+// Older version of SDK would return false for these intrinsics
+// but make sure we pass the right values to the APIs
+#ifndef PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE
+#define PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE 34
+#endif
+#ifndef PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE
+#define PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE 43
+#endif
+#ifndef PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE
+#define PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE 45
+#endif
+
+ // FP and SIMD support are enabled by default
+ result |= ARM64IntrinsicConstants_AdvSimd | ARM64IntrinsicConstants_VectorT128;
+
+ if (IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE))
+ {
+ result |= ARM64IntrinsicConstants_Aes;
+ result |= ARM64IntrinsicConstants_Sha1;
+ result |= ARM64IntrinsicConstants_Sha256;
+ }
+
+ if (IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE))
+ {
+ result |= ARM64IntrinsicConstants_Crc32;
+ }
+
+ if (IsProcessorFeaturePresent(PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE))
+ {
+ result |= ARM64IntrinsicConstants_Atomics;
+ }
+
+ if (IsProcessorFeaturePresent(PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE))
+ {
+ result |= ARM64IntrinsicConstants_Dp;
+ }
+
+ if (IsProcessorFeaturePresent(PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE))
+ {
+ result |= ARM64IntrinsicConstants_Rcpc;
+ }
+#endif // TARGET_WINDOWS
+
+#endif // TARGET_ARM64
+
+ return result;
+}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-#ifndef INTRINSICCONSTANTS_INCLUDED
-#define INTRINSICCONSTANTS_INCLUDED
+#ifndef HAVE_MINIPAL_CPUFEATURES_H
+#define HAVE_MINIPAL_CPUFEATURES_H
-// Should match the constants defined in the compiler in HardwareIntrinsicHelpers.Aot.cs
+//
+// Should match the constants defined in the compiler in HardwareIntrinsicHelpers.cs
+//
-#if defined(HOST_X86) || defined(HOST_AMD64)
+#if defined(TARGET_X86) || defined(TARGET_AMD64)
enum XArchIntrinsicConstants
{
XArchIntrinsicConstants_Aes = 0x0001,
XArchIntrinsicConstants_VectorT256 = 0x8000000,
XArchIntrinsicConstants_VectorT512 = 0x10000000,
};
-#endif //HOST_X86 || HOST_AMD64
+#endif // TARGET_X86 || TARGET_AMD64
-#if defined(HOST_ARM64)
+#if defined(TARGET_ARM64)
enum ARM64IntrinsicConstants
{
ARM64IntrinsicConstants_AdvSimd = 0x0001,
ARM64IntrinsicConstants_VectorT128 = 0x0200,
};
+#include <assert.h>
+
// Bit position for the ARM64IntrinsicConstants_Atomics flags, to be used with tbz / tbnz instructions
-static const int ARM64_ATOMICS_FEATURE_FLAG_BIT = 7;
+#define ARM64_ATOMICS_FEATURE_FLAG_BIT 7
static_assert((1 << ARM64_ATOMICS_FEATURE_FLAG_BIT) == ARM64IntrinsicConstants_Atomics, "ARM64_ATOMICS_FEATURE_FLAG_BIT must match with ARM64IntrinsicConstants_Atomics");
-#endif //HOST_ARM64
+#endif // TARGET_ARM64
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+
+int minipal_getcpufeatures(void);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
-#endif //!INTRINSICCONSTANTS_INCLUDED
+#endif
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#ifndef HAVE_MINIPAL_CPUID_H
+#define HAVE_MINIPAL_CPUID_H
+
+#if defined(TARGET_X86) || defined(TARGET_AMD64)
+
+#if defined(TARGET_WINDOWS)
+
+#include <intrin.h>
+
+#endif // TARGET_WINDOWS
+
+#if defined(TARGET_UNIX)
+// MSVC directly defines intrinsics for __cpuid and __cpuidex matching the below signatures
+// We define matching signatures for use on Unix platforms.
+//
+// IMPORTANT: Unlike MSVC, Unix does not explicitly zero ECX for __cpuid
+
+#if !__has_builtin(__cpuid)
+static void __cpuid(int cpuInfo[4], int function_id)
+{
+ // Based on the Clang implementation provided in cpuid.h:
+ // https://github.com/llvm/llvm-project/blob/main/clang/lib/Headers/cpuid.h
+
+ __asm(" cpuid\n" \
+ : "=a"(cpuInfo[0]), "=b"(cpuInfo[1]), "=c"(cpuInfo[2]), "=d"(cpuInfo[3]) \
+ : "0"(function_id)
+ );
+}
+#else
+void __cpuid(int cpuInfo[4], int function_id);
+#endif
+
+#if !__has_builtin(__cpuidex)
+static void __cpuidex(int cpuInfo[4], int function_id, int subFunction_id)
+{
+ // Based on the Clang implementation provided in cpuid.h:
+ // https://github.com/llvm/llvm-project/blob/main/clang/lib/Headers/cpuid.h
+
+ __asm(" cpuid\n" \
+ : "=a"(cpuInfo[0]), "=b"(cpuInfo[1]), "=c"(cpuInfo[2]), "=d"(cpuInfo[3]) \
+ : "0"(function_id), "2"(subFunction_id)
+ );
+}
+#else
+void __cpuidex(int cpuInfo[4], int function_id, int subFunction_id);
+#endif
+
+#endif // TARGET_UNIX
+#endif // defined(TARGET_X86) || defined(TARGET_AMD64)
+
+#endif
--- /dev/null
+#ifndef HAVE_MINIPAL_MINIPALCONFIG_H
+#define HAVE_MINIPAL_MINIPALCONFIG_H
+
+#cmakedefine01 HAVE_AUXV_HWCAP_H
+#cmakedefine01 HAVE_SYSCTLBYNAME
+
+#endif