MSVC: Support building for AArch64.
authorNathan Bossart <nathan@postgresql.org>
Wed, 7 Jan 2026 19:42:57 +0000 (13:42 -0600)
committerNathan Bossart <nathan@postgresql.org>
Wed, 7 Jan 2026 19:42:57 +0000 (13:42 -0600)
This commit does the following to get tests passing for
MSVC/AArch64:

* Implements spin_delay() with an ISB instruction (like we do for
gcc/clang on AArch64).

* Sets USE_ARMV8_CRC32C unconditionally.  Vendor-supported versions
of Windows for AArch64 require at least ARMv8.1, which is where CRC
extension support became mandatory.

* Implements S_UNLOCK() with _InterlockedExchange().  The existing
implementation for MSVC uses _ReadWriteBarrier() (a compiler
barrier), which is insufficient for this purpose on non-TSO
architectures.

There are likely other changes required to take full advantage of
the hardware (e.g., atomics/arch-arm.h, simd.h,
pg_popcount_aarch64.c), but those can be dealt with later.

Author: Niyas Sait <niyas.sait@linaro.org>
Co-authored-by: Greg Burd <greg@burd.me>
Co-authored-by: Dave Cramer <davecramer@gmail.com>
Reviewed-by: Michael Paquier <michael@paquier.xyz>
Reviewed-by: John Naylor <johncnaylorls@gmail.com>
Reviewed-by: Peter Eisentraut <peter@eisentraut.org>
Reviewed-by: Andres Freund <andres@anarazel.de>
Reviewed-by: Thomas Munro <thomas.munro@gmail.com>
Tested-by: Andrew Dunstan <andrew@dunslane.net>
Discussion: https://postgr.es/m/A6152C7C-F5E3-4958-8F8E-7692D259FF2F%40greg.burd.me
Discussion: https://postgr.es/m/CAFPTBD-74%2BAEuN9n7caJ0YUnW5A0r-KBX8rYoEJWqFPgLKpzdg%40mail.gmail.com

doc/src/sgml/installation.sgml
meson.build
src/include/storage/s_lock.h
src/port/pg_crc32c_armv8.c
src/tools/msvc_gendef.pl

index fe8d73e1f8c010355bae8055ef28e65959281d3b..c903ccff9888e8d31f7397e005e6d8e06d86c76b 100644 (file)
@@ -3967,7 +3967,8 @@ configure ... LDFLAGS="-R /usr/sfw/lib:/opt/sfw/lib:/usr/local/lib"
    <sect3 id="install-windows-full-64-bit">
     <title>Special Considerations for 64-Bit Windows</title>
     <para>
-     PostgreSQL will only build for the x64 architecture on 64-bit Windows.
+     PostgreSQL will only build for the x64 and AArch64 architectures on 64-bit
+     Windows.
     </para>
     <para>
      Mixing 32- and 64-bit versions in the same build tree is not supported.
index c3834a9dc8fa386f68524c31a0a64d4e6c1c28be..35eb47468db6b09943032bf3cb0501d63bf613fc 100644 (file)
@@ -2523,7 +2523,11 @@ int main(void)
 }
 '''
 
-  if cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd without -march=armv8-a+crc',
+  # Vendor-supported versions of Windows for AArch64 require at least ARMv8.1,
+  # which is where CRC extension support became mandatory.  Thus, use it
+  # unconditionally on MSVC/AArch64.
+  if (host_cpu == 'aarch64' and cc.get_id() == 'msvc') or \
+        cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd without -march=armv8-a+crc',
       args: test_c_args)
     # Use ARM CRC Extension unconditionally
     cdata.set('USE_ARMV8_CRC32C', 1)
index c4e429cb16a41c372c607f8456ff2c9829596c2d..2522cae0c310e3b1ba14412787b465e8f089b4ae 100644 (file)
@@ -602,13 +602,24 @@ typedef LONG slock_t;
 
 #define SPIN_DELAY() spin_delay()
 
-/* If using Visual C++ on Win64, inline assembly is unavailable.
- * Use a _mm_pause intrinsic instead of rep nop.
- */
-#if defined(_WIN64)
+#ifdef _M_ARM64
+static __forceinline void
+spin_delay(void)
+{
+   /*
+    * Research indicates ISB is better than __yield() on AArch64.  See
+    * https://postgr.es/m/1c2a29b8-5b1e-44f7-a871-71ec5fefc120%40app.fastmail.com.
+    */
+   __isb(_ARM64_BARRIER_SY);
+}
+#elif defined(_WIN64)
 static __forceinline void
 spin_delay(void)
 {
+   /*
+    * If using Visual C++ on Win64, inline assembly is unavailable.
+    * Use a _mm_pause intrinsic instead of rep nop.
+    */
    _mm_pause();
 }
 #else
@@ -621,12 +632,21 @@ spin_delay(void)
 #endif
 
 #include <intrin.h>
-#pragma intrinsic(_ReadWriteBarrier)
 
+#ifdef _M_ARM64
+
+/* _ReadWriteBarrier() is insufficient on non-TSO architectures. */
+#pragma intrinsic(_InterlockedExchange)
+#define S_UNLOCK(lock) _InterlockedExchange(lock, 0)
+
+#else
+
+#pragma intrinsic(_ReadWriteBarrier)
 #define S_UNLOCK(lock) \
    do { _ReadWriteBarrier(); (*(lock)) = 0; } while (0)
 
 #endif
+#endif
 
 
 #endif /* !defined(HAS_TEST_AND_SET) */
index 2b669276a147f4fba9c8c2f59740cfab95924879..039986c7b33fce78a7bd1c353871527d681413fb 100644 (file)
  */
 #include "c.h"
 
+#ifdef _MSC_VER
+#include <intrin.h>
+#else
 #include <arm_acle.h>
+#endif
 
 #include "port/pg_crc32c.h"
 
index b933b5b95e31a128a9d9737783946caec670d77c..1a37fe959470596fd7dbc09f43b8ce6e894df3e9 100644 (file)
@@ -118,9 +118,9 @@ sub writedef
    {
        my $isdata = $def->{$f} eq 'data';
 
-       # Strip the leading underscore for win32, but not x64
+       # Strip the leading underscore for win32, but not x64 and aarch64
        $f =~ s/^_//
-         unless ($arch eq "x86_64");
+         unless ($arch eq "x86_64" || $arch eq "aarch64");
 
        # Emit just the name if it's a function symbol, or emit the name
        # decorated with the DATA option for variables.
@@ -141,7 +141,7 @@ sub writedef
 sub usage
 {
    die("Usage: msvc_gendef.pl --arch <arch> --deffile <deffile> --tempdir <tempdir> files-or-directories\n"
-         . "    arch: x86 | x86_64\n"
+         . "    arch: x86 | x86_64 | aarch64\n"
          . "    deffile: path of the generated file\n"
          . "    tempdir: directory for temporary files\n"
          . "    files or directories: object files or directory containing object files\n"
@@ -158,7 +158,7 @@ GetOptions(
    'tempdir:s' => \$tempdir,) or usage();
 
 usage("arch: $arch")
-  unless ($arch eq 'x86' || $arch eq 'x86_64');
+  unless ($arch eq 'x86' || $arch eq 'x86_64' || $arch eq 'aarch64');
 
 my @files;