1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

Windows: Added Windows ARM support to JUCE

This commit is contained in:
hogliux 2022-10-19 13:25:33 +02:00
parent 5f48ca7269
commit 2d42b9a44f
8 changed files with 189 additions and 93 deletions

View file

@ -1430,34 +1430,44 @@ void JUCE_CALLTYPE FloatVectorOperations::convertFixedToFloat (float* dest, cons
intptr_t JUCE_CALLTYPE FloatVectorOperations::getFpStatusRegister() noexcept
{
intptr_t fpsr = 0;
#if JUCE_INTEL && JUCE_USE_SSE_INTRINSICS
#if JUCE_INTEL && JUCE_USE_SSE_INTRINSICS
fpsr = static_cast<intptr_t> (_mm_getcsr());
#elif defined(__arm64__) || defined(__aarch64__) || JUCE_USE_ARM_NEON
#if defined(__arm64__) || defined(__aarch64__)
#elif (JUCE_64BIT && JUCE_ARM) || JUCE_USE_ARM_NEON
#if _MSC_VER
// _control87 returns static values for x86 bits that don't exist on arm
// to emulate x86 behaviour. We are only ever interested in de-normal bits
// so mask out only those.
fpsr = (intptr_t) (_control87 (0, 0) & _MCW_DN);
#else
#if JUCE_64BIT
asm volatile("mrs %0, fpcr"
: "=r"(fpsr));
#elif JUCE_USE_ARM_NEON
asm volatile("vmrs %0, fpscr"
: "=r"(fpsr));
#endif
#else
#if ! (defined(JUCE_INTEL) || defined(JUCE_ARM))
jassertfalse; // No support for getting the floating point status register for your platform
#endif
#endif
#else
#if ! (defined (JUCE_INTEL) || defined (JUCE_ARM))
jassertfalse; // No support for getting the floating point status register for your platform
#endif
#endif
return fpsr;
}
void JUCE_CALLTYPE FloatVectorOperations::setFpStatusRegister (intptr_t fpsr) noexcept
{
#if JUCE_INTEL && JUCE_USE_SSE_INTRINSICS
#if JUCE_INTEL && JUCE_USE_SSE_INTRINSICS
// the volatile keyword here is needed to workaround a bug in AppleClang 13.0
// which aggressively optimises away the variable otherwise
volatile auto fpsr_w = static_cast<uint32_t> (fpsr);
_mm_setcsr (fpsr_w);
#elif defined(__arm64__) || defined(__aarch64__) || JUCE_USE_ARM_NEON
#if defined(__arm64__) || defined(__aarch64__)
#elif (JUCE_64BIT && JUCE_ARM) || JUCE_USE_ARM_NEON
#if _MSC_VER
_control87 ((unsigned int) fpsr, _MCW_DN);
#else
#if JUCE_64BIT
asm volatile("msr fpcr, %0"
:
: "ri"(fpsr));
@ -1466,17 +1476,18 @@ void JUCE_CALLTYPE FloatVectorOperations::setFpStatusRegister (intptr_t fpsr) no
:
: "ri"(fpsr));
#endif
#else
#if ! (defined(JUCE_INTEL) || defined(JUCE_ARM))
jassertfalse; // No support for getting the floating point status register for your platform
#endif
ignoreUnused (fpsr);
#endif
#else
#if ! (defined (JUCE_INTEL) || defined (JUCE_ARM))
jassertfalse; // No support for getting the floating point status register for your platform
#endif
ignoreUnused (fpsr);
#endif
}
void JUCE_CALLTYPE FloatVectorOperations::enableFlushToZeroMode (bool shouldEnable) noexcept
{
#if JUCE_USE_SSE_INTRINSICS || (JUCE_USE_ARM_NEON || defined(__arm64__) || defined(__aarch64__))
#if JUCE_USE_SSE_INTRINSICS || (JUCE_USE_ARM_NEON || (JUCE_64BIT && JUCE_ARM))
#if JUCE_USE_SSE_INTRINSICS
intptr_t mask = _MM_FLUSH_ZERO_MASK;
#else /*JUCE_USE_ARM_NEON*/
@ -1484,7 +1495,7 @@ void JUCE_CALLTYPE FloatVectorOperations::enableFlushToZeroMode (bool shouldEnab
#endif
setFpStatusRegister ((getFpStatusRegister() & (~mask)) | (shouldEnable ? mask : 0));
#else
#if ! (defined(JUCE_INTEL) || defined(JUCE_ARM))
#if ! (defined (JUCE_INTEL) || defined (JUCE_ARM))
jassertfalse; // No support for flush to zero mode on your platform
#endif
ignoreUnused (shouldEnable);
@ -1493,7 +1504,7 @@ void JUCE_CALLTYPE FloatVectorOperations::enableFlushToZeroMode (bool shouldEnab
void JUCE_CALLTYPE FloatVectorOperations::disableDenormalisedNumberSupport (bool shouldDisable) noexcept
{
#if JUCE_USE_SSE_INTRINSICS || (JUCE_USE_ARM_NEON || defined(__arm64__) || defined(__aarch64__))
#if JUCE_USE_SSE_INTRINSICS || (JUCE_USE_ARM_NEON || (JUCE_64BIT && JUCE_ARM))
#if JUCE_USE_SSE_INTRINSICS
intptr_t mask = 0x8040;
#else /*JUCE_USE_ARM_NEON*/
@ -1504,7 +1515,7 @@ void JUCE_CALLTYPE FloatVectorOperations::disableDenormalisedNumberSupport (bool
#else
ignoreUnused (shouldDisable);
#if ! (defined(JUCE_INTEL) || defined(JUCE_ARM))
#if ! (defined (JUCE_INTEL) || defined (JUCE_ARM))
jassertfalse; // No support for disable denormals mode on your platform
#endif
#endif
@ -1512,7 +1523,7 @@ void JUCE_CALLTYPE FloatVectorOperations::disableDenormalisedNumberSupport (bool
bool JUCE_CALLTYPE FloatVectorOperations::areDenormalsDisabled() noexcept
{
#if JUCE_USE_SSE_INTRINSICS || (JUCE_USE_ARM_NEON || defined(__arm64__) || defined(__aarch64__))
#if JUCE_USE_SSE_INTRINSICS || (JUCE_USE_ARM_NEON || (JUCE_64BIT && JUCE_ARM))
#if JUCE_USE_SSE_INTRINSICS
intptr_t mask = 0x8040;
#else /*JUCE_USE_ARM_NEON*/
@ -1527,7 +1538,7 @@ bool JUCE_CALLTYPE FloatVectorOperations::areDenormalsDisabled() noexcept
ScopedNoDenormals::ScopedNoDenormals() noexcept
{
#if JUCE_USE_SSE_INTRINSICS || (JUCE_USE_ARM_NEON || defined(__arm64__) || defined(__aarch64__))
#if JUCE_USE_SSE_INTRINSICS || (JUCE_USE_ARM_NEON || (JUCE_64BIT && JUCE_ARM))
#if JUCE_USE_SSE_INTRINSICS
intptr_t mask = 0x8040;
#else /*JUCE_USE_ARM_NEON*/
@ -1541,7 +1552,7 @@ ScopedNoDenormals::ScopedNoDenormals() noexcept
ScopedNoDenormals::~ScopedNoDenormals() noexcept
{
#if JUCE_USE_SSE_INTRINSICS || (JUCE_USE_ARM_NEON || defined(__arm64__) || defined(__aarch64__))
#if JUCE_USE_SSE_INTRINSICS || (JUCE_USE_ARM_NEON || (JUCE_64BIT && JUCE_ARM))
FloatVectorOperations::setFpStatusRegister (fpsr);
#endif
}

View file

@ -261,7 +261,7 @@ public:
~ScopedNoDenormals() noexcept;
private:
#if JUCE_USE_SSE_INTRINSICS || (JUCE_USE_ARM_NEON || defined (__arm64__) || defined (__aarch64__))
#if JUCE_USE_SSE_INTRINSICS || (JUCE_USE_ARM_NEON || (JUCE_64BIT && JUCE_ARM))
intptr_t fpsr;
#endif
};

View file

@ -119,7 +119,7 @@ static inline int vorbis_ftoi(double f){ /* yes, double! Otherwise,
/* MSVC inline assembly. 32 bit only; inline ASM isn't implemented in the
* 64 bit compiler and doesn't work on arm. */
#if defined(_MSC_VER) && defined(_M_IX86) && !defined(_WIN32_WCE)
#if (defined(_MSC_VER) && defined(_M_IX86) && !defined(_WIN32_WCE)) && (! JUCE_ARM)
# define VORBIS_FPU_CONTROL
typedef ogg_int16_t vorbis_fpu_control;
@ -146,7 +146,7 @@ static __inline void vorbis_fpu_restore(vorbis_fpu_control fpu){
/* Optimized code path for x86_64 builds. Uses SSE2 intrinsics. This can be
done safely because all x86_64 CPUs supports SSE2. */
#if ((JUCE_MSVC && JUCE_64BIT) || (JUCE_GCC && defined (__x86_64__)))
#if (((JUCE_MSVC && JUCE_64BIT) || (JUCE_GCC && defined (__x86_64__)))) && (! JUCE_ARM)
# define VORBIS_FPU_CONTROL
typedef ogg_int16_t vorbis_fpu_control;

View file

@ -23,11 +23,6 @@
namespace juce
{
#if JUCE_MSVC && ! defined (__INTEL_COMPILER)
#pragma intrinsic (__cpuid)
#pragma intrinsic (__rdtsc)
#endif
void Logger::outputDebugString (const String& text)
{
OutputDebugString ((text + "\n").toWideCharPointer());
@ -39,9 +34,50 @@ void Logger::outputDebugString (const String& text)
JUCE_API void juceDLL_free (void* block) { std::free (block); }
#endif
//==============================================================================
static int findNumberOfPhysicalCores() noexcept
{
#if JUCE_MINGW
// Not implemented in MinGW
jassertfalse;
#if JUCE_MINGW || JUCE_CLANG
return 1;
#else
DWORD bufferSize = 0;
GetLogicalProcessorInformation (nullptr, &bufferSize);
const auto numBuffers = (size_t) (bufferSize / sizeof (SYSTEM_LOGICAL_PROCESSOR_INFORMATION));
if (numBuffers == 0)
{
jassertfalse;
return 0;
};
HeapBlock<SYSTEM_LOGICAL_PROCESSOR_INFORMATION> buffer (numBuffers);
if (! GetLogicalProcessorInformation (buffer, &bufferSize))
{
jassertfalse;
return 0;
}
return (int) std::count_if (buffer.get(), buffer.get() + numBuffers, [] (const auto& info)
{
return info.Relationship == RelationProcessorCore;
});
#endif // JUCE_MINGW
}
//==============================================================================
#if JUCE_INTEL
#if JUCE_MSVC && ! defined (__INTEL_COMPILER)
#pragma intrinsic (__cpuid)
#pragma intrinsic (__rdtsc)
#endif
#if JUCE_MINGW || JUCE_CLANG
static void callCPUID (int result[4], uint32 type)
{
uint32 la = (uint32) result[0], lb = (uint32) result[1],
@ -59,12 +95,12 @@ static void callCPUID (int result[4], uint32 type)
result[0] = (int) la; result[1] = (int) lb;
result[2] = (int) lc; result[3] = (int) ld;
}
#else
#else
static void callCPUID (int result[4], int infoType)
{
__cpuid (result, infoType);
}
#endif
#endif
String SystemStats::getCpuVendor()
{
@ -103,34 +139,6 @@ String SystemStats::getCpuModel()
return String (name).trim();
}
static int findNumberOfPhysicalCores() noexcept
{
#if JUCE_MINGW
// Not implemented in MinGW
jassertfalse;
return 1;
#else
int numPhysicalCores = 0;
DWORD bufferSize = 0;
GetLogicalProcessorInformation (nullptr, &bufferSize);
if (auto numBuffers = (size_t) (bufferSize / sizeof (SYSTEM_LOGICAL_PROCESSOR_INFORMATION)))
{
HeapBlock<SYSTEM_LOGICAL_PROCESSOR_INFORMATION> buffer (numBuffers);
if (GetLogicalProcessorInformation (buffer, &bufferSize))
for (size_t i = 0; i < numBuffers; ++i)
if (buffer[i].Relationship == RelationProcessorCore)
++numPhysicalCores;
}
return numPhysicalCores;
#endif // JUCE_MINGW
}
//==============================================================================
void CPUInformation::initialise() noexcept
{
int info[4] = { 0 };
@ -176,6 +184,49 @@ void CPUInformation::initialise() noexcept
if (numPhysicalCPUs <= 0)
numPhysicalCPUs = numLogicalCPUs;
}
#elif JUCE_ARM
String SystemStats::getCpuVendor()
{
static const auto cpuVendor = []
{
static constexpr auto* path = "HKEY_LOCAL_MACHINE\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0\\VendorIdentifier";
auto vendor = RegistryKeyWrapper::getValue (path, {}, 0).trim();
return vendor.isEmpty() ? String ("Unknown Vendor") : vendor;
}();
return cpuVendor;
}
String SystemStats::getCpuModel()
{
static const auto cpuModel = []
{
static constexpr auto* path = "HKEY_LOCAL_MACHINE\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0\\ProcessorNameString";
auto model = RegistryKeyWrapper::getValue (path, {}, 0).trim();
return model.isEmpty() ? String ("Unknown Model") : model;
}();
return cpuModel;
}
void CPUInformation::initialise() noexcept
{
// Windows for arm requires at least armv7 which has neon support
hasNeon = true;
SYSTEM_INFO systemInfo;
GetNativeSystemInfo (&systemInfo);
numLogicalCPUs = (int) systemInfo.dwNumberOfProcessors;
numPhysicalCPUs = findNumberOfPhysicalCores();
if (numPhysicalCPUs <= 0)
numPhysicalCPUs = numLogicalCPUs;
}
#else
#error Unknown CPU architecture type
#endif
#if JUCE_MSVC && JUCE_CHECK_MEMORY_LEAKS
struct DebugFlagsInitialiser
@ -442,11 +493,21 @@ double Time::getMillisecondCounterHiRes() noexcept { return hiResCounterHa
//==============================================================================
static int64 juce_getClockCycleCounter() noexcept
{
#if JUCE_MSVC
#if JUCE_MSVC
#if JUCE_INTEL
// MS intrinsics version...
return (int64) __rdtsc();
#elif JUCE_GCC || JUCE_CLANG
#elif JUCE_ARM
#if defined (_M_ARM)
return __rdpmccntr64();
#elif defined (_M_ARM64)
return _ReadStatusReg (ARM64_PMCCNTR_EL0);
#else
#error Unknown arm architecture
#endif
#endif
#elif JUCE_GCC || JUCE_CLANG
#if JUCE_INTEL
// GNU inline asm version...
unsigned int hi = 0, lo = 0;
@ -462,9 +523,15 @@ static int64 juce_getClockCycleCounter() noexcept
: "cc", "eax", "ebx", "ecx", "edx", "memory");
return (int64) ((((uint64) hi) << 32) | lo);
#else
#error "unknown compiler?"
#endif
#elif JUCE_ARM
int64 retval;
__asm__ __volatile__ ("mrs %0, cntvct_el0" : "=r"(retval));
return retval;
#endif
#else
#error "unknown compiler?"
#endif
}
int SystemStats::getCpuSpeedInMegahertz()

View file

@ -109,7 +109,11 @@
/** If defined, this indicates that the processor is little-endian. */
#define JUCE_LITTLE_ENDIAN 1
#define JUCE_INTEL 1
#if defined (_M_ARM) || defined (_M_ARM64) || defined (__arm__) || defined (__aarch64__)
#define JUCE_ARM 1
#else
#define JUCE_INTEL 1
#endif
#endif
//==============================================================================

View file

@ -79,13 +79,13 @@
#include "widgets/juce_Chorus.cpp"
#if JUCE_USE_SIMD
#if defined(__i386__) || defined(__amd64__) || defined(_M_X64) || defined(_X86_) || defined(_M_IX86)
#if JUCE_INTEL
#ifdef __AVX2__
#include "native/juce_avx_SIMDNativeOps.cpp"
#else
#include "native/juce_sse_SIMDNativeOps.cpp"
#endif
#elif defined(__arm__) || defined(_M_ARM) || defined (__arm64__) || defined (__aarch64__)
#elif JUCE_ARM
#include "native/juce_neon_SIMDNativeOps.cpp"
#else
#error "SIMD register support not implemented for this platform"

View file

@ -74,7 +74,9 @@
#include <immintrin.h>
#endif
#elif defined (__ARM_NEON__) || defined (__ARM_NEON) || defined (__arm64__) || defined (__aarch64__)
// it's ok to check for _M_ARM below as this is only defined on Windows for Arm 32-bit
// which has a minimum requirement of armv7, which supports neon.
#elif defined (__ARM_NEON__) || defined (__ARM_NEON) || defined (__arm64__) || defined (__aarch64__) || defined (_M_ARM) || defined (_M_ARM64)
#ifndef JUCE_USE_SIMD
#define JUCE_USE_SIMD 1
@ -227,7 +229,7 @@ namespace juce
#else
#include "native/juce_sse_SIMDNativeOps.h"
#endif
#elif defined(__arm__) || defined(_M_ARM) || defined (__arm64__) || defined (__aarch64__)
#elif JUCE_ARM
#include "native/juce_neon_SIMDNativeOps.h"
#else
#error "SIMD register support not implemented for this platform"