Windows ARM support? (prototype patch included)

I know it seems to be pretty unpopular (I do not have any hardware and have never seen any since a PocketPC in '06), but my interest was piqued and here are some basic things that make many parts of JUCE at least compile on Windows ARM (32 and 64bit). It is based on an older JUCE but mostly ports to recent easily. Test with cmake -G"Visual Studio 15 2017" -Aarm64 ../src (or -Aarm).

diff --git a/modules/juce_audio_formats/codecs/oggvorbis/libvorbis-1.3.2/lib/os.h b/modules/juce_audio_formats/codecs/oggvorbis/libvorbis-1.3.2/lib/os.h
index 412ca7622..8322011f4 100644
--- a/modules/juce_audio_formats/codecs/oggvorbis/libvorbis-1.3.2/lib/os.h
+++ b/modules/juce_audio_formats/codecs/oggvorbis/libvorbis-1.3.2/lib/os.h
@@ -120,7 +120,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 */
-#if defined(_MSC_VER) && !defined(_WIN64) && !defined(_WIN32_WCE)
+#if defined(_MSC_VER) && !defined(_WIN64) && !defined(_WIN32_WCE) && !defined(JUCE_ARM)
 #  define VORBIS_FPU_CONTROL
 
 typedef ogg_int16_t vorbis_fpu_control;
@@ -145,7 +145,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_PROJUCER_LIVE_BUILD) && ((defined(_MSC_VER) && defined(_WIN64)) || (defined(__GNUC__) && defined (__x86_64__)))
+#if (! JUCE_PROJUCER_LIVE_BUILD) && ((defined(_MSC_VER) && defined(_M_X64)) || (defined(__GNUC__) && defined (__x86_64__)))
 #  define VORBIS_FPU_CONTROL
 
 typedef ogg_int16_t vorbis_fpu_control;
diff --git a/modules/juce_core/native/juce_win32_SystemStats.cpp b/modules/juce_core/native/juce_win32_SystemStats.cpp
index d9a84082c..f7ad1b5b8 100644
--- a/modules/juce_core/native/juce_win32_SystemStats.cpp
+++ b/modules/juce_core/native/juce_win32_SystemStats.cpp
@@ -23,7 +23,7 @@
 namespace juce
 {
 
-#if ! JUCE_MINGW
+#if ! JUCE_MINGW && JUCE_INTEL
  #pragma intrinsic (__cpuid)
  #pragma intrinsic (__rdtsc)
 #endif
@@ -41,6 +41,7 @@ void Logger::outputDebugString (const String& text)
 
 //==============================================================================
 
+#if JUCE_INTEL
 #if JUCE_MINGW
 static void callCPUID (int result[4], uint32 type)
 {
@@ -67,9 +68,11 @@ static void callCPUID (int result[4], int infoType)
    #endif
 }
 #endif
+#endif
 
 String SystemStats::getCpuVendor()
 {
+   #ifdef JUCE_INTEL
     int info[4] = { 0 };
     callCPUID (info, 0);
 
@@ -79,10 +82,14 @@ String SystemStats::getCpuVendor()
     memcpy (v + 8, info + 2, 4);
 
     return String (v, 12);
+   #else
+    return String();
+   #endif
 }
 
 String SystemStats::getCpuModel()
 {
+   #ifdef JUCE_INTEL
     char name[65] = { 0 };
     int info[4] = { 0 };
 
@@ -103,6 +110,9 @@ String SystemStats::getCpuModel()
     memcpy (name + 32, info, sizeof (info));
 
     return String (name).trim();
+   #else
+    return String();
+   #endif
 }
 
 static int findNumberOfPhysicalCores() noexcept
@@ -135,6 +145,7 @@ static int findNumberOfPhysicalCores() noexcept
 //==============================================================================
 void CPUInformation::initialise() noexcept
 {
+   #if JUCE_INTEL
     int info[4] = { 0 };
     callCPUID (info, 1);
 
@@ -162,6 +173,11 @@ void CPUInformation::initialise() noexcept
     hasAVX512VL        = (info[1] & (1u << 31)) != 0;
     hasAVX512VBMI      = (info[2] & (1u <<  1)) != 0;
     hasAVX512VPOPCNTDQ = (info[2] & (1u << 14)) != 0;
+   #endif
+
+   #if JUCE_ARM
+    hasNeon = IsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE) != 0;
+   #endif
 
     SYSTEM_INFO systemInfo;
     GetNativeSystemInfo (&systemInfo);
@@ -372,7 +388,9 @@ double Time::getMillisecondCounterHiRes() noexcept       { return hiResCounterHa
 //==============================================================================
 static int64 juce_getClockCycleCounter() noexcept
 {
-   #if JUCE_MSVC
+   #if JUCE_ARM
+    return 0;
+   #elif JUCE_MSVC
     // MS intrinsics version...
     return (int64) __rdtsc();
 
diff --git a/modules/juce_core/system/juce_TargetPlatform.h b/modules/juce_core/system/juce_TargetPlatform.h
index 1d4fb0c71..0560fd8e0 100644
--- a/modules/juce_core/system/juce_TargetPlatform.h
+++ b/modules/juce_core/system/juce_TargetPlatform.h
@@ -107,7 +107,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)
+    #define JUCE_ARM 1
+  #else
+    #define JUCE_INTEL 1
+  #endif
 #endif
 
 //==============================================================================

1 Like

Nice timing! I compiled DemoRunner (juce 6.1) yesterday to run on my new Arm64 Surface Pro and your changes are about the same as I had to make. You’re definitely on the right way…