public inbox for [email protected]  
help / color / mirror / Atom feed
[PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ​barriers
42+ messages / 6 participants
[nested] [flat]

* [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ​barriers
@ 2025-11-20 20:45  Greg Burd <[email protected]>
  0 siblings, 3 replies; 42+ messages in thread

From: Greg Burd @ 2025-11-20 20:45 UTC (permalink / raw)
  To: PostgreSQL Hackers <[email protected]>; +Cc: Dave Cramer <[email protected]>

Hi all,

Dave and I have been working together to get ARM64 with MSVC functional.
 The attached patches accomplish that. Dave is the author of the first
which addresses some build issues and fixes the spin_delay() semantics,
I did the second which fixes some atomics in this combination.

PostgreSQL when compiled with MSVC on ARM64 architecture in particular
when optimizations are enabled (e.g., /O2), fails 027_stream_regress.
After some investigation and analysis of generated assembly code, Dave
Cramer and I have identified that the root cause is insufficient memory
barrier semantics in both atomic operations and spinlocks on ARM64 when
compiled with MSVC with /O2.

Dave knew I was in the process of setting up a Win11/ARM64/MSVC build
animal and pinged me with this issue.  Dave got me started on the path
to finding the issue by sending me his work around:

--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -744,6 +744,7 @@ static void
WALInsertLockUpdateInsertingAt(XLogRecPtr insertingAt);
  * before the data page can be written out.  This implements the basic
  * WAL rule "write the log before the data".)
  */
+#pragma optimize("",off)
 XLogRecPtr
 XLogInsertRecord(XLogRecData *rdata,
                                 XLogRecPtr fpw_lsn,
@@ -1088,7 +1089,7 @@ XLogInsertRecord(XLogRecData *rdata,

        return EndPos;
 }
-
+#pragma optimize("",on)
 /*


This pointed a finger at the atomics, so I started there.  We used a few
tools, but worth noting is https://godbolt.org/ where we were able to
quickly see that the MSVC assembly was missing the "dmb" barriers on
this platform.  I'm not sure how long this link will be valid, but in
the short term here's our investigation: https://godbolt.org/z/PPqfxe1bn


PROBLEM DESCRIPTION

PostgreSQL test failures occur intermittently on MSVC ARM64 builds,
manifesting as timing-dependent failures in critical sections
protected by spinlocks and atomic variables. The failures are
reproducible when the test suite is compiled with optimization flags
(/O2), particularly in the recovery/027_stream_regress test which
involves WAL replication and standby recovery.

The root cause has two components:

1. Atomic operations lack memory barriers on ARM64
2. MSVC spinlock implementation lacks memory barriers on ARM64


TECHNICAL ANALYSIS

PART 1: ATOMIC OPERATIONS MEMORY BARRIERS

GCC's __atomic_compare_exchange_n() with __ATOMIC_SEQ_CST semantics
generates a call to __aarch64_cas4_acq_rel(), which is a library
function that provides explicit acquire-release memory ordering
semantics through either:

* LSE path (modern ARM64): Using CASAL instruction with built-in
  memory ordering [1][2]

* Legacy path (older ARM64): Using LDAXR/STLXR instructions with
  explicit dmb sy instruction [3]

MSVC's _InterlockedCompareExchange() intrinsic on ARM64 performs the
atomic operation but does NOT emit the necessary Data Memory Barrier
(DMB) instructions [4][5].


PART 2: SPINLOCK IMPLEMENTATION LACKS BARRIERS

The MSVC spinlock implementation in src/include/storage/s_lock.h had
two issues on ARM64/MSVC:

#define TAS(lock) (InterlockedCompareExchange(lock, 1, 0))
#define S_UNLOCK(lock) do { _ReadWriteBarrier(); (*(lock)) = 0; } while (0)

Issue 1: TAS() uses InterlockedCompareExchange without hardware barriers

The InterlockedCompareExchange intrinsic lacks full memory barrier
semantics on ARM64, identical to the atomic operations issue.

Issue 2: S_UNLOCK() uses only a compiler barrier

_ReadWriteBarrier() is a compiler barrier, NOT a hardware memory
barrier [6].  It prevents the compiler from reordering operations, but
the CPU can still reorder memory operations. This is fundamentally
insufficient for ARM64's weaker memory model.

For comparison, GCC's __sync_lock_release() emits actual hardware
barriers.

IMPACT ON 027_STREAM_REGRESS

The 027_stream_regress test involves WAL replication and standby
recovery — heavily dependent on synchronized access to shared memory
protected by spinlocks [7].  Without proper barriers on ARM64:

1. Thread A acquires spinlock (no full barrier emitted)
2. Thread A modifies shared WAL buffer
3. Thread B acquires spinlock before Thread A's writes become visible
4. Thread B reads stale WAL data
5. WAL replication gets corrupted or hangs indefinitely
6. Test times out waiting for standby to catch up


WHY ARM32 AND X86/X64 ARE UNAFFECTED

MSVC's _InterlockedCompareExchange does provide full memory barriers on:
* x86/x64: Memory barriers are implicit in the x86 memory model [8]
* ARM32: MSVC explicitly generates full barriers for ARM32 [5]

Only ARM64 lacks the necessary barriers, making this a platform-specific
issue.

ATTACHED SOLUTION

Add explicit DMB (Data Memory Barrier) instructions before and after
atomic operations and spinlock operations on ARM64 to provide sequential
consistency semantics.

0002: src/inclue/port/atomic/generic-msvc.h

Added platform-specific DMB macros that expand to
__dmb(_ARM64_BARRIER_SY) on ARM64.

Applied to all six atomic operations:
* pg_atomic_compare_exchange_u32_impl()
* pg_atomic_exchange_u32_impl()
* pg_atomic_fetch_add_u32_impl()
* pg_atomic_compare_exchange_u64_impl()
* pg_atomic_exchange_u64_impl()
* pg_atomic_fetch_add_u64_impl()


0001: src/include/storage/s_lock.h

Added ARM64-specific spinlock implementation with explicit DMB barriers [9]:

#if defined(_M_ARM64)
#define TAS(lock) tas_msvc_arm64(lock)

static __forceinline int
tas_msvc_arm64(volatile slock_t *lock)
{
  int result;

  /* Full barrier before atomic operation */
  __dmb(_ARM64_BARRIER_SY);

  /* Atomic compare-and-swap */
  result = InterlockedCompareExchange(lock, 1, 0);

  /* Full barrier after atomic operation */
  __dmb(_ARM64_BARRIER_SY);

  return result;
}

#define S_UNLOCK(lock)
do {
  __dmb(_ARM64_BARRIER_SY); /* Full barrier before release /
  ((lock)) = 0;
} while (0)

#else
  /* Non-ARM64 MSVC: existing implementation unchanged */
#endif


The spinlock acquire now ensures:

* Before CAS: All prior memory operations complete before
  acquiring the lock.

* After CAS: The CAS completes before subsequent operations
  access protected data

The spinlock release now ensures:

* Before writing 0: All critical section operations are visible
  to other threads


You may ask: why two DMBs in the atomic operations instead of one?
GCC's non-LSE path (LDAXR/STLXR) uses only one DMB because:
* LDAXR (Load-Acquire Exclusive) provides half-barrier acquire
  semantics [3]
* STLXR (Store-Release Exclusive) provides half-barrier release
  semantics [3]
* One final dmb sy upgrades to full sequential consistency

Since _InterlockedCompareExchange provides NO barrier semantics on
ARM64, we must provide both halves:

* First DMB acts as a release barrier (ensures prior memory ops
  complete before CAS)
* Second DMB acts as an acquire barrier (ensures subsequent memory
  ops wait for CAS)
* Together they provide sequential consistency matching GCC's
  semantics [3]


VERIFICATION

The fix has been verified by:

1. Spinlock fix resolves 027_stream_regress timeout: Test now passes
   consistently on MSVC ARM64 with /O2 optimization without hanging

2. Assembly code inspection: Confirmed that dmb sy instructions now
   appear in the optimized assembly for ARM64 builds

3. Platform compatibility: No regression on x86/x64 or ARM32 (macros
   expand to no-ops; original code path unchanged)


WHY CLANG/LLVM ON MACOS ARM64 DOESN'T HAVE THIS PROBLEM

PostgreSQL builds successfully on Apple Silicon Macs (ARM64) without
the memory ordering issues observed on MSVC Windows ARM64. The
difference comes down to how Clang/LLVM and MSVC handle atomic
operations.

CLANG/LLVM APPROACH (macOS, Linux, Android ARM64)

Clang/LLVM uses GCC-compatible atomic builtins
(__atomic_compare_exchange_n, etc.) even on platforms where it's not
GCC [125][134]. The LLVM backend has an AtomicExpand pass that
properly expands these operations to include appropriate memory
barriers for the target architecture [134].

On ARM64, Clang generates:

__aarch64_cas4_acq_rel library calls (or CASAL instruction with LSE)
Proper acquire-release semantics built into the instruction sequence
Automatic full dmb sy barriers where needed This means PostgreSQL's
use of __sync_lock_test_and_set and _atomic* builtins work correctly
on macOS ARM64 without additional patches.


Phew... I hope I read all those docs correctly and got that right.  Feel
free to let me know if I missed something.  Looking forward to your
feedback and review so I can get this new build animal up and running.

best.

-greg

[1] ARM Developer: CAS Instructions
https://developer.arm.com/documentation/dui0801/latest/A64-Data-Transfer-Instructions/CASAB--CASALB-...-

[2] ARM Developer: Load-Acquire and Store-Release Instructions
https://developer.arm.com/documentation/102336/0100/Load-Acquire-and-Store-Release-instructions

[3] ARM Developer: Data Memory Barrier (DMB)
https://developer.arm.com/documentation/100069/0610/A64-General-Instructions/DMB?lang=en

[4] Microsoft Learn: _InterlockedCompareExchange Intrinsic Functions
https://learn.microsoft.com/en-us/cpp/intrinsics/interlockedcompareexchange-intrinsic-functions?view...

[5] Microsoft Learn: ARM Intrinsics - Memory Barriers
https://learn.microsoft.com/en-us/cpp/intrinsics/arm-intrinsics?view=msvc-170

[6] Microsoft Learn: _ReadWriteBarrier is a Compiler Barrier
https://learn.microsoft.com/en-us/cpp/intrinsics/compiler-intrinsics?view=msvc-170

[7] PostgreSQL: 027_stream_regress WAL replication testing
https://www.postgresql.org/message-id/[email protected]

[8] Intel Volume 3A: Memory Ordering
https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software...

[9] Microsoft Developer Blog: The AArch64 processor - Barriers
https://devblogs.microsoft.com/oldnewthing/20220812-00/?p=106968

Attachments:

  [application/octet-stream] v1-0001-Address-build-issues-for-ARM64-using-MSVC.patch (5.0K, ../../[email protected]/2-v1-0001-Address-build-issues-for-ARM64-using-MSVC.patch)
  download | inline diff:
From b245143d7c6afa23e341ac69d5377083ccaf0edd Mon Sep 17 00:00:00 2001
From: Dave Cramer <[email protected]>
Date: Sun, 13 Jul 2025 06:33:17 -0400
Subject: [PATCH v1 1/2] Address build issues for ARM64 using MSVC

This patch adds support for the ARM64 architecture on Windows 11
and includes work that enables building with MSVC.  This patch also
includes a new intrinsic for spin_delay that is platform specific.
---
 doc/src/sgml/installation.sgml |  2 +-
 meson.build                    | 11 +++++++++--
 src/include/storage/s_lock.h   | 20 ++++++++++++++++++--
 src/port/pg_crc32c_armv8.c     |  2 ++
 src/tools/msvc_gendef.pl       |  8 ++++----
 5 files changed, 34 insertions(+), 9 deletions(-)

diff --git a/doc/src/sgml/installation.sgml b/doc/src/sgml/installation.sgml
index 593202f4fb2..1cddb047a9f 100644
--- a/doc/src/sgml/installation.sgml
+++ b/doc/src/sgml/installation.sgml
@@ -3967,7 +3967,7 @@ 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 ARM64 architecture on 64-bit Windows.
     </para>
     <para>
      Mixing 32- and 64-bit versions in the same build tree is not supported.
diff --git a/meson.build b/meson.build
index c1e17aa3040..cb572927319 100644
--- a/meson.build
+++ b/meson.build
@@ -1663,7 +1663,7 @@ endif
 zlibopt = get_option('zlib')
 zlib = not_found_dep
 if not zlibopt.disabled()
-  zlib_t = dependency('zlib', required: zlibopt)
+  zlib_t = dependency('zlib', method : 'pkg-config', required: zlibopt)
 
   if zlib_t.type_name() == 'internal'
     # if fallback was used, we don't need to test if headers are present (they
@@ -2494,6 +2494,9 @@ int main(void)
 elif host_cpu == 'arm' or host_cpu == 'aarch64'
 
   prog = '''
+#ifdef _MSC_VER
+#include <intrin.h>
+#else
 #include <arm_acle.h>
 unsigned int crc;
 
@@ -2509,7 +2512,11 @@ int main(void)
 }
 '''
 
-  if cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd without -march=armv8-a+crc',
+  if cc.get_id() == 'msvc'
+    cdata.set('USE_ARMV8_CRC32C', false)
+    cdata.set('USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 1)
+    have_optimized_crc = true
+  elif 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)
diff --git a/src/include/storage/s_lock.h b/src/include/storage/s_lock.h
index 7f8f566bd40..be7aaf6b013 100644
--- a/src/include/storage/s_lock.h
+++ b/src/include/storage/s_lock.h
@@ -602,15 +602,31 @@ 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 using Visual C++ on Win64, inline assembly is unavailable.
+ * Use architecture specific intrinsics.
  */
 #if defined(_WIN64)
+/*
+ * For Arm64, use __isb intrinsic. See aarch64 inline assembly definition for details.
+ */
+#ifdef _M_ARM64
+static __forceinline void
+spin_delay(void)
+{
+	 /* Reference: https://learn.microsoft.com/en-us/cpp/intrinsics/arm64-intrinsics#BarrierRestrictions */
+	__isb(_ARM64_BARRIER_SY);
+}
+#else
+/*
+ * For x64, use _mm_pause intrinsic instead of rep nop.
+ */
 static __forceinline void
 spin_delay(void)
 {
 	_mm_pause();
 }
+#endif
 #else
 static __forceinline void
 spin_delay(void)
diff --git a/src/port/pg_crc32c_armv8.c b/src/port/pg_crc32c_armv8.c
index 5ba070bb99d..6a155ddde1e 100644
--- a/src/port/pg_crc32c_armv8.c
+++ b/src/port/pg_crc32c_armv8.c
@@ -14,7 +14,9 @@
  */
 #include "c.h"
 
+#ifndef _MSC_VER
 #include <arm_acle.h>
+#endif
 
 #include "port/pg_crc32c.h"
 
diff --git a/src/tools/msvc_gendef.pl b/src/tools/msvc_gendef.pl
index 868aad51b09..c92c94c4775 100644
--- a/src/tools/msvc_gendef.pl
+++ b/src/tools/msvc_gendef.pl
@@ -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;
 
-- 
2.52.0.windows.1



  [application/octet-stream] v1-0002-DMB-barries-fix-memory-ordering-on-MSVC-ARM64.patch (12.2K, ../../[email protected]/3-v1-0002-DMB-barries-fix-memory-ordering-on-MSVC-ARM64.patch)
  download | inline diff:
From 6f8245bbc9f737eb4f5be48df9e76702d2f511b5 Mon Sep 17 00:00:00 2001
From: Greg Burd <[email protected]>
Date: Thu, 20 Nov 2025 12:00:47 -0500
Subject: [PATCH v1 2/2] DMB barries fix memory ordering on MSVC/ARM64

MSVC ARM64 builds have been experiencing intermittent test failures
(particularly recovery/027_stream_regress) due to insufficient memory
barrier semantics in both atomic operations and spinlock
implementations. Unlike GCC, which generates explicit memory barriers
automatically, MSVC's _Interlocked* intrinsics on ARM64 lack full
sequential consistency guarantees.

This commit adds explicit Data Memory Barrier (DMB sy) instructions on
ARM64:

In src/include/port/atomics/generic-msvc.h:

* Add conditional DMB barriers before and after all atomic operations
  on ARM64/MSVC (CAS/exchange/fetch-add)
* Barriers expand to no-ops on non-ARM64/MSVC platforms
* Applies to all six atomic operations:
  compare-exchange, exchange, and fetch-add for both 32-bit and 64-bit
  values

In src/include/storage/s_lock.h:

Add ARM64-specific TAS() implementation with explicit barriers around
the InterlockedCompareExchange intrinsic Replace S_UNLOCK() to use
hardware DMB instead of just _ReadWriteBarrier() (compiler barrier is
insufficient on ARM64) Non-ARM64 MSVC code path remains unchanged

These changes ensure sequential consistency semantics matching what GCC
generates automatically via _atomic* builtins, resolving the WAL
replication synchronization issues that caused 027_stream_regress test
timeouts.

Performance impact is negligible: DMB instructions are already implicit
in x86/x64 memory model, and ARM32 already provided full barriers via
intrinsics.
---
 src/include/port/atomics/generic-msvc.h | 155 ++++++++++++++++++++++--
 src/include/storage/s_lock.h            |  80 +++++++++---
 2 files changed, 207 insertions(+), 28 deletions(-)

diff --git a/src/include/port/atomics/generic-msvc.h b/src/include/port/atomics/generic-msvc.h
index a6ea5f1c2e7..c16ccafa341 100644
--- a/src/include/port/atomics/generic-msvc.h
+++ b/src/include/port/atomics/generic-msvc.h
@@ -12,13 +12,19 @@
  * * Interlocked Variable Access
  *   http://msdn.microsoft.com/en-us/library/ms684122%28VS.85%29.aspx
  *
+ * On ARM64, the _Interlocked* intrinsics do not emit full memory barriers
+ * by default. This file adds explicit DMB (Data Memory Barrier) instructions
+ * for ARM64 to ensure sequential consistency semantics required by PostgreSQL,
+ * matching the behavior of GCC's __atomic_* builtins which generate appropriate
+ * barriers automatically via __aarch64_cas4_acq_rel or equivalent.
+ *
  * src/include/port/atomics/generic-msvc.h
  *
  *-------------------------------------------------------------------------
  */
 #include <intrin.h>
 
-/* intentionally no include guards, should only be included by atomics.h */
+ /* intentionally no include guards, should only be included by atomics.h */
 #ifndef INSIDE_ATOMICS_H
 #error "should be included via atomics.h"
 #endif
@@ -26,8 +32,23 @@
 #pragma intrinsic(_ReadWriteBarrier)
 #define pg_compiler_barrier_impl()	_ReadWriteBarrier()
 
+
 #ifndef pg_memory_barrier_impl
+#if defined(_M_ARM64)
+/*
+ * On ARM64, MemoryBarrier() may not generate explicit dmb sy instructions.
+ * Use explicit __dmb(_ARM64_BARRIER_SY) to ensure sequential consistency,
+ * matching GCC's __sync_synchronize() behavior which generates dmb sy.
+ */
+#define pg_memory_barrier_impl()	__dmb(_ARM64_BARRIER_SY)
+
+#else
+/*
+ * On x86/x64 and ARM32, MemoryBarrier() provides full memory barriers
+ */
 #define pg_memory_barrier_impl()	MemoryBarrier()
+
+#endif
 #endif
 
 #define PG_HAVE_ATOMIC_U32_SUPPORT
@@ -43,31 +64,93 @@ typedef struct pg_attribute_aligned(8) pg_atomic_uint64
 } pg_atomic_uint64;
 
 
+/*
+ * ARM64-specific memory barrier helper macros
+ *
+ * MSVC ARM64 _Interlocked* intrinsics do not emit full memory barriers.
+ * We use explicit __dmb(_ARM64_BARRIER_SY) to provide sequential
+ * consistency.
+ */
+#if defined(_M_ARM64)
+#define PG_ARM64_DMB_BEFORE() __dmb(_ARM64_BARRIER_SY)
+#define PG_ARM64_DMB_AFTER()  __dmb(_ARM64_BARRIER_SY)
+#else
+#define PG_ARM64_DMB_BEFORE() ((void)0)
+#define PG_ARM64_DMB_AFTER()  ((void)0)
+#endif
+
+
+ /*
+  * pg_atomic_compare_exchange_u32
+  *
+  * Compare and swap for 32-bit values with full memory barrier semantics
+  * (sequential consistency).
+  *
+  * Implementation notes:
+  * - ARM64: Explicit DMB barriers added before and after CAS
+  * - x86/x64, ARM32: _InterlockedCompareExchange provides full barriers
+  */
 #define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32
 static inline bool
-pg_atomic_compare_exchange_u32_impl(volatile pg_atomic_uint32 *ptr,
-									uint32 *expected, uint32 newval)
+pg_atomic_compare_exchange_u32_impl(volatile pg_atomic_uint32* ptr,
+	uint32* expected, uint32 newval)
 {
 	bool	ret;
 	uint32	current;
+
+	PG_ARM64_DMB_BEFORE();
 	current = InterlockedCompareExchange(&ptr->value, newval, *expected);
+	PG_ARM64_DMB_AFTER();
+
 	ret = current == *expected;
 	*expected = current;
 	return ret;
 }
 
+/*
+ * pg_atomic_exchange_u32
+ *
+ * Atomically exchange a new value for an old value with full memory barrier
+ * semantics (sequential consistency).
+ *
+ * Implementation notes:
+ * - ARM64: Explicit DMB barriers added before and after exchange
+ * - x86/x64, ARM32: _InterlockedExchange provides full barriers
+ */
 #define PG_HAVE_ATOMIC_EXCHANGE_U32
 static inline uint32
-pg_atomic_exchange_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 newval)
+pg_atomic_exchange_u32_impl(volatile pg_atomic_uint32* ptr, uint32 newval)
 {
-	return InterlockedExchange(&ptr->value, newval);
+	uint32	result;
+
+	PG_ARM64_DMB_BEFORE();
+	result = InterlockedExchange(&ptr->value, newval);
+	PG_ARM64_DMB_AFTER();
+
+	return result;
 }
 
+/*
+ * pg_atomic_fetch_add_u32
+ *
+ * Atomically add a value to an atomic variable with full memory barrier
+ * semantics (sequential consistency).
+ *
+ * Implementation notes:
+ * - ARM64: Explicit DMB barriers added before and after fetch-add
+ * - x86/x64, ARM32: _InterlockedExchangeAdd provides full barriers
+ */
 #define PG_HAVE_ATOMIC_FETCH_ADD_U32
 static inline uint32
-pg_atomic_fetch_add_u32_impl(volatile pg_atomic_uint32 *ptr, int32 add_)
+pg_atomic_fetch_add_u32_impl(volatile pg_atomic_uint32* ptr, int32 add_)
 {
-	return InterlockedExchangeAdd(&ptr->value, add_);
+	uint32	result;
+
+	PG_ARM64_DMB_BEFORE();
+	result = InterlockedExchangeAdd(&ptr->value, add_);
+	PG_ARM64_DMB_AFTER();
+
+	return result;
 }
 
 /*
@@ -78,14 +161,28 @@ pg_atomic_fetch_add_u32_impl(volatile pg_atomic_uint32 *ptr, int32 add_)
  */
 #pragma intrinsic(_InterlockedCompareExchange64)
 
+ /*
+  * pg_atomic_compare_exchange_u64
+  *
+  * Compare and swap for 64-bit values with full memory barrier semantics
+  * (sequential consistency).
+  *
+  * Implementation notes:
+  * - ARM64: Explicit DMB barriers added before and after CAS
+  * - x86/x64, ARM32: _InterlockedCompareExchange64 provides full barriers
+  */
 #define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64
 static inline bool
-pg_atomic_compare_exchange_u64_impl(volatile pg_atomic_uint64 *ptr,
-									uint64 *expected, uint64 newval)
+pg_atomic_compare_exchange_u64_impl(volatile pg_atomic_uint64* ptr,
+	uint64* expected, uint64 newval)
 {
 	bool	ret;
 	uint64	current;
+
+	PG_ARM64_DMB_BEFORE();
 	current = _InterlockedCompareExchange64(&ptr->value, newval, *expected);
+	PG_ARM64_DMB_AFTER();
+
 	ret = current == *expected;
 	*expected = current;
 	return ret;
@@ -96,20 +193,52 @@ pg_atomic_compare_exchange_u64_impl(volatile pg_atomic_uint64 *ptr,
 
 #pragma intrinsic(_InterlockedExchange64)
 
+/*
+ * pg_atomic_exchange_u64
+ *
+ * Atomically exchange a new 64-bit value for an old value with full memory
+ * barrier semantics (sequential consistency).
+ *
+ * Implementation notes:
+ * - ARM64: Explicit DMB barriers added before and after exchange
+ * - x86/x64: _InterlockedExchange64 provides full barriers
+ */
 #define PG_HAVE_ATOMIC_EXCHANGE_U64
 static inline uint64
-pg_atomic_exchange_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 newval)
+pg_atomic_exchange_u64_impl(volatile pg_atomic_uint64* ptr, uint64 newval)
 {
-	return _InterlockedExchange64(&ptr->value, newval);
+	uint64	result;
+
+	PG_ARM64_DMB_BEFORE();
+	result = _InterlockedExchange64(&ptr->value, newval);
+	PG_ARM64_DMB_AFTER();
+
+	return result;
 }
 
 #pragma intrinsic(_InterlockedExchangeAdd64)
 
+/*
+ * pg_atomic_fetch_add_u64
+ *
+ * Atomically add a value to a 64-bit atomic variable with full memory barrier
+ * semantics (sequential consistency).
+ *
+ * Implementation notes:
+ * - ARM64: Explicit DMB barriers added before and after fetch-add
+ * - x86/x64: _InterlockedExchangeAdd64 provides full barriers
+ */
 #define PG_HAVE_ATOMIC_FETCH_ADD_U64
 static inline uint64
-pg_atomic_fetch_add_u64_impl(volatile pg_atomic_uint64 *ptr, int64 add_)
+pg_atomic_fetch_add_u64_impl(volatile pg_atomic_uint64* ptr, int64 add_)
 {
-	return _InterlockedExchangeAdd64(&ptr->value, add_);
+	uint64	result;
+
+	PG_ARM64_DMB_BEFORE();
+	result = _InterlockedExchangeAdd64(&ptr->value, add_);
+	PG_ARM64_DMB_AFTER();
+
+	return result;
 }
 
 #endif /* _WIN64 */
diff --git a/src/include/storage/s_lock.h b/src/include/storage/s_lock.h
index be7aaf6b013..f226d2058de 100644
--- a/src/include/storage/s_lock.h
+++ b/src/include/storage/s_lock.h
@@ -598,29 +598,82 @@ tas(volatile slock_t *lock)
 typedef LONG slock_t;
 
 #define HAS_TEST_AND_SET
+
+/*
+ * MSVC spinlock implementation
+ *
+ * On ARM64, explicit DMB (Data Memory Barrier) instructions are required
+ * to provide sequential consistency semantics. InterlockedCompareExchange
+ * alone does not emit full barriers on ARM64 [1]. _ReadWriteBarrier() is
+ * a compiler barrier only and does not prevent CPU reordering [2].
+ *
+ * [1] - Microsoft Learn: _InterlockedCompareExchange Intrinsic Functions - ARM intrinsics
+ * https://learn.microsoft.com/en-us/cpp/intrinsics/interlockedcompareexchange-intrinsic-functions?view=msvc-170
+ * [2] - Microsoft Learn: _ReadWriteBarrier is a Compiler Barrier
+ * https://learn.microsoft.com/en-us/cpp/intrinsics/compiler-intrinsics?view=msvc-170
+ */
+#if defined(_M_ARM64)
+ /* ARM64 requires explicit memory barriers for spinlock acquire/release */
+#define TAS(lock) tas_msvc_arm64(lock)
+
+static __forceinline int
+tas_msvc_arm64(volatile slock_t* lock)
+{
+	int result;
+
+	/* Full barrier before atomic operation */
+	__dmb(_ARM64_BARRIER_SY);
+
+	/* Atomic compare-and-swap */
+	result = InterlockedCompareExchange(lock, 1, 0);
+
+	/* Full barrier after atomic operation */
+	__dmb(_ARM64_BARRIER_SY);
+
+	return result;
+}
+
+#define S_UNLOCK(lock) \
+	do { \
+		__dmb(_ARM64_BARRIER_SY);  /* Full barrier before release */ \
+		(*(lock)) = 0; \
+	} while (0)
+
+#else
+ /*
+  * Non-ARM64 MSVC (x86/x64): InterlockedCompareExchange provides full barriers
+  *
+  * Microsoft Learn: InterlockedCompareExchange generates full memory barrier on x64
+  * https://learn.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-interlockedcompareexchange
+  */
 #define TAS(lock) (InterlockedCompareExchange(lock, 1, 0))
 
+#define S_UNLOCK(lock)	\
+	do { _ReadWriteBarrier(); (*(lock)) = 0; } while (0)
+
+#endif /* _M_ARM64 */
+
 #define SPIN_DELAY() spin_delay()
 
-/*
- * If using Visual C++ on Win64, inline assembly is unavailable.
- * Use architecture specific intrinsics.
- */
+  /*
+   * If using Visual C++ on Win64, inline assembly is unavailable.
+   * Use architecture specific intrinsics.
+   */
 #if defined(_WIN64)
-/*
- * For Arm64, use __isb intrinsic. See aarch64 inline assembly definition for details.
- */
+   /*
+	* For Arm64, use __isb intrinsic. See aarch64 inline assembly definition for details.
+	*/
 #ifdef _M_ARM64
 static __forceinline void
 spin_delay(void)
 {
-	 /* Reference: https://learn.microsoft.com/en-us/cpp/intrinsics/arm64-intrinsics#BarrierRestrictions */
+	/* Reference: https://learn.microsoft.com/en-us/cpp/intrinsics/arm64-intrinsics#BarrierRestrictions */
 	__isb(_ARM64_BARRIER_SY);
 }
 #else
-/*
- * For x64, use _mm_pause intrinsic instead of rep nop.
- */
+	/*
+	 * For x64, use _mm_pause intrinsic instead of rep nop.
+	 */
 static __forceinline void
 spin_delay(void)
 {
@@ -639,10 +692,7 @@ spin_delay(void)
 #include <intrin.h>
 #pragma intrinsic(_ReadWriteBarrier)
 
-#define S_UNLOCK(lock)	\
-	do { _ReadWriteBarrier(); (*(lock)) = 0; } while (0)
-
-#endif
+#endif /* _MSC_VER */
 
 
 #endif	/* !defined(HAS_TEST_AND_SET) */
-- 
2.52.0.windows.1



^ permalink  raw  reply  [nested|flat] 42+ messages in thread

* Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB barriers
@ 2025-11-20 22:00  Peter Eisentraut <[email protected]>
  parent: Greg Burd <[email protected]>
  2 siblings, 1 reply; 42+ messages in thread

From: Peter Eisentraut @ 2025-11-20 22:00 UTC (permalink / raw)
  To: Greg Burd <[email protected]>; PostgreSQL Hackers <[email protected]>; +Cc: Dave Cramer <[email protected]>

On 20.11.25 21:45, Greg Burd wrote:
> Dave and I have been working together to get ARM64 with MSVC functional.
>   The attached patches accomplish that. Dave is the author of the first
> which addresses some build issues and fixes the spin_delay() semantics,
> I did the second which fixes some atomics in this combination.

 > -  zlib_t = dependency('zlib', required: zlibopt)
 > +  zlib_t = dependency('zlib', method : 'pkg-config', required: zlibopt)

This appears to be a change unrelated to your patch description.

Also, the second patch contains a number of random whitespace changes. 
It would be good to clean that up so the patch is easier to analyze.






^ permalink  raw  reply  [nested|flat] 42+ messages in thread

* Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB barriers
@ 2025-11-20 22:08  Greg Burd <[email protected]>
  parent: Peter Eisentraut <[email protected]>
  0 siblings, 1 reply; 42+ messages in thread

From: Greg Burd @ 2025-11-20 22:08 UTC (permalink / raw)
  To: Peter Eisentraut <[email protected]>; +Cc: PostgreSQL Hackers <[email protected]>; Dave Cramer <[email protected]>


On Nov 20 2025, at 5:00 pm, Peter Eisentraut <[email protected]> wrote:

> On 20.11.25 21:45, Greg Burd wrote:
>> Dave and I have been working together to get ARM64 with MSVC functional.
>>   The attached patches accomplish that. Dave is the author of the first
>> which addresses some build issues and fixes the spin_delay() semantics,
>> I did the second which fixes some atomics in this combination.
> 

Hi Peter,

Thanks for taking a second to review.

> > -  zlib_t = dependency('zlib', required: zlibopt)
> > +  zlib_t = dependency('zlib', method : 'pkg-config', required: zlibopt)
> 
> This appears to be a change unrelated to your patch description.

Hmmm, these are changes that Dave added to get things to compile.  They
worked for me but I'll review them again in the morning and update the description.

> Also, the second patch contains a number of random whitespace changes. 
> It would be good to clean that up so the patch is easier to analyze.

Certainly, apologies.  I'll clean that up first thing in the morning.

-greg





^ permalink  raw  reply  [nested|flat] 42+ messages in thread

* Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB barriers
@ 2025-11-20 22:36  Nathan Bossart <[email protected]>
  parent: Greg Burd <[email protected]>
  0 siblings, 2 replies; 42+ messages in thread

From: Nathan Bossart @ 2025-11-20 22:36 UTC (permalink / raw)
  To: Greg Burd <[email protected]>; +Cc: Peter Eisentraut <[email protected]>; PostgreSQL Hackers <[email protected]>; Dave Cramer <[email protected]>

I took a quick look at 0001.

+#ifdef _MSC_VER
+#include <intrin.h>
+#else
 #include <arm_acle.h>
 unsigned int crc;

I think you can remove this since we unconditionally do the runtime check
for MSVC.  In any case, the missing #endif seems likely to cause
problems.

--- a/src/port/pg_crc32c_armv8.c
+++ b/src/port/pg_crc32c_armv8.c
@@ -14,7 +14,9 @@
  */
 #include "c.h"
 
+#ifndef _MSC_VER
 #include <arm_acle.h>
+#endif

Hm.  Doesn't MSVC require intrin.h?

-- 
nathan





^ permalink  raw  reply  [nested|flat] 42+ messages in thread

* Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ​barriers
@ 2025-11-21 00:03  Andres Freund <[email protected]>
  parent: Greg Burd <[email protected]>
  2 siblings, 2 replies; 42+ messages in thread

From: Andres Freund @ 2025-11-21 00:03 UTC (permalink / raw)
  To: Greg Burd <[email protected]>; +Cc: PostgreSQL Hackers <[email protected]>; Dave Cramer <[email protected]>

Hi,

On 2025-11-20 15:45:22 -0500, Greg Burd wrote:
> Dave and I have been working together to get ARM64 with MSVC functional.
>  The attached patches accomplish that. Dave is the author of the first
> which addresses some build issues and fixes the spin_delay() semantics,
> I did the second which fixes some atomics in this combination.

Thanks for working on this!


> This pointed a finger at the atomics, so I started there.  We used a few
> tools, but worth noting is https://godbolt.org/ where we were able to
> quickly see that the MSVC assembly was missing the "dmb" barriers on
> this platform.  I'm not sure how long this link will be valid, but in
> the short term here's our investigation: https://godbolt.org/z/PPqfxe1bn
> 
> 
> PROBLEM DESCRIPTION
> 
> PostgreSQL test failures occur intermittently on MSVC ARM64 builds,
> manifesting as timing-dependent failures in critical sections
> protected by spinlocks and atomic variables. The failures are
> reproducible when the test suite is compiled with optimization flags
> (/O2), particularly in the recovery/027_stream_regress test which
> involves WAL replication and standby recovery.
> 
> The root cause has two components:
> 
> 1. Atomic operations lack memory barriers on ARM64
> 2. MSVC spinlock implementation lacks memory barriers on ARM64
> 
> TECHNICAL ANALYSIS
> 
> PART 1: ATOMIC OPERATIONS MEMORY BARRIERS
> 
> GCC's __atomic_compare_exchange_n() with __ATOMIC_SEQ_CST semantics
> generates a call to __aarch64_cas4_acq_rel(), which is a library
> function that provides explicit acquire-release memory ordering
> semantics through either:
> 
> * LSE path (modern ARM64): Using CASAL instruction with built-in
>   memory ordering [1][2]
> 
> * Legacy path (older ARM64): Using LDAXR/STLXR instructions with
>   explicit dmb sy instruction [3]
> 
> MSVC's _InterlockedCompareExchange() intrinsic on ARM64 performs the
> atomic operation but does NOT emit the necessary Data Memory Barrier
> (DMB) instructions [4][5].

I couldn't reproduce this result when playing around on godbolt. By specifying
/arch:armv9.4 msvc can be convinced to emit the code for the intrinsics inline
(at least for most of them).  And that makes it visible that
_InterlockedCompareExchange() results in a "casal" instruction. Looking that
up shows:
  https://developer.arm.com/documentation/dui0801/l/A64-Data-Transfer-Instructions/CASA--CASAL--CAS--C...-
which includes these two statements:
"CASA and CASAL load from memory with acquire semantics."
"CASL and CASAL store to memory with release semantics."


> Issue 2: S_UNLOCK() uses only a compiler barrier
> 
> _ReadWriteBarrier() is a compiler barrier, NOT a hardware memory
> barrier [6].  It prevents the compiler from reordering operations, but
> the CPU can still reorder memory operations. This is fundamentally
> insufficient for ARM64's weaker memory model.

Yea, that seems broken on a non-TSO architecture.  Is the problem fixed if you
change just this to include a proper barrier?

Greetings,

Andres Freund





^ permalink  raw  reply  [nested|flat] 42+ messages in thread

* Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ​barriers
@ 2025-11-21 00:07  Andres Freund <[email protected]>
  parent: Andres Freund <[email protected]>
  1 sibling, 1 reply; 42+ messages in thread

From: Andres Freund @ 2025-11-21 00:07 UTC (permalink / raw)
  To: Greg Burd <[email protected]>; +Cc: PostgreSQL Hackers <[email protected]>; Dave Cramer <[email protected]>

Hi,

On 2025-11-20 19:03:47 -0500, Andres Freund wrote:
> > MSVC's _InterlockedCompareExchange() intrinsic on ARM64 performs the
> > atomic operation but does NOT emit the necessary Data Memory Barrier
> > (DMB) instructions [4][5].
> 
> I couldn't reproduce this result when playing around on godbolt. By specifying
> /arch:armv9.4 msvc can be convinced to emit the code for the intrinsics inline
> (at least for most of them).  And that makes it visible that
> _InterlockedCompareExchange() results in a "casal" instruction. Looking that
> up shows:
>   https://developer.arm.com/documentation/dui0801/l/A64-Data-Transfer-Instructions/CASA--CASAL--CAS--C...-
> which includes these two statements:
> "CASA and CASAL load from memory with acquire semantics."
> "CASL and CASAL store to memory with release semantics."

Further evidence for that is that
https://learn.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-interlockedcompareexchange
states:
"This function generates a full memory barrier (or fence) to ensure that memory operations are completed in order."

(note that we are using the function, not the intrinsic for TAS())

Greetings,

Andres





^ permalink  raw  reply  [nested|flat] 42+ messages in thread

*  Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ​barriers
@ 2025-11-21 00:08  Thomas Munro <[email protected]>
  parent: Greg Burd <[email protected]>
  2 siblings, 2 replies; 42+ messages in thread

From: Thomas Munro @ 2025-11-21 00:08 UTC (permalink / raw)
  To: Greg Burd <[email protected]>; +Cc: PostgreSQL Hackers <[email protected]>; Dave Cramer <[email protected]>

On Fri, Nov 21, 2025 at 9:45 AM Greg Burd <[email protected]> wrote:
> Dave and I have been working together to get ARM64 with MSVC functional.
>  The attached patches accomplish that. Dave is the author of the first
> which addresses some build issues and fixes the spin_delay() semantics,
> I did the second which fixes some atomics in this combination.

A couple of immediate thoughts:

https://learn.microsoft.com/en-us/cpp/intrinsics/interlockedexchangeadd-intrinsic-functions?view=msv...

Doesn't seem to match your conclusion.

+  if cc.get_id() == 'msvc'
+    cdata.set('USE_ARMV8_CRC32C', false)
+    cdata.set('USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 1)

USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK (pg_crc32c_armv8_choose.c) won't
actually work on Windows, but I don't think we should waste time
implementing it: vendor-supported versions of Windows 11 require
ARMv8.1A to boot[1][2], and that has it, so I think we should probably
just define USE_ARMV8_CRC32C.

+static __forceinline void
+spin_delay(void)
+{
+     /* Reference:
https://learn.microsoft.com/en-us/cpp/intrinsics/arm64-intrinsics#BarrierRestrictions
*/
+    __isb(_ARM64_BARRIER_SY);
+}

I don't doubt that barriers are missing in a few places, but how can
this be the right place?

If you have an environment set up so it's easy to test, I would also
be very interested to know if my patch set[3] that nukes all this
stuff and includes <stdatomic.h> instead, which is green on
Windows/x86 CI, will just work™ there too.

[1] https://en.wikipedia.org/wiki/Windows_11_version_history
[2] https://learn.microsoft.com/en-us/lifecycle/products/windows-11-home-and-pro
[3] https://www.postgresql.org/message-id/flat/CA%2BhUKGKFvu3zyvv3aaj5hHs9VtWcjFAmisOwOc7aOZNc5AF3NA%40m...





^ permalink  raw  reply  [nested|flat] 42+ messages in thread

* Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB barriers
@ 2025-11-21 09:46  Dave Cramer <[email protected]>
  parent: Nathan Bossart <[email protected]>
  1 sibling, 0 replies; 42+ messages in thread

From: Dave Cramer @ 2025-11-21 09:46 UTC (permalink / raw)
  To: Nathan Bossart <[email protected]>; +Cc: Greg Burd <[email protected]>; Peter Eisentraut <[email protected]>; PostgreSQL Hackers <[email protected]>

On Thu, 20 Nov 2025 at 17:36, Nathan Bossart <[email protected]>
wrote:

> I took a quick look at 0001.
>
> +#ifdef _MSC_VER
> +#include <intrin.h>
> +#else
>  #include <arm_acle.h>
>  unsigned int crc;
>
> I think you can remove this since we unconditionally do the runtime check
> for MSVC.  In any case, the missing #endif seems likely to cause
> problems.
>
> --- a/src/port/pg_crc32c_armv8.c
> +++ b/src/port/pg_crc32c_armv8.c
> @@ -14,7 +14,9 @@
>   */
>  #include "c.h"
>
> +#ifndef _MSC_VER
>  #include <arm_acle.h>
> +#endif
>
> Hm.  Doesn't MSVC require intrin.h?
>
> --
> nathan
>

I  posted this as a bug with Microsoft
https://developercommunity.visualstudio.com/t/MSVCs-_InterlockedCompareExchange-doe/11004239

Dave


^ permalink  raw  reply  [nested|flat] 42+ messages in thread

* Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ​barriers
@ 2025-11-21 19:36  Greg Burd <[email protected]>
  parent: Andres Freund <[email protected]>
  1 sibling, 0 replies; 42+ messages in thread

From: Greg Burd @ 2025-11-21 19:36 UTC (permalink / raw)
  To: Andres Freund <[email protected]>; +Cc: PostgreSQL Hackers <[email protected]>; Dave Cramer <[email protected]>


On Nov 20 2025, at 7:03 pm, Andres Freund <[email protected]> wrote:

> Hi,
> 
> On 2025-11-20 15:45:22 -0500, Greg Burd wrote:
>> Dave and I have been working together to get ARM64 with MSVC functional.
>>  The attached patches accomplish that. Dave is the author of the first
>> which addresses some build issues and fixes the spin_delay() semantics,
>> I did the second which fixes some atomics in this combination.
> 
> Thanks for working on this!

You're welcome, thanks for reviewing it. :)

>> 
>> MSVC's _InterlockedCompareExchange() intrinsic on ARM64 performs the
>> atomic operation but does NOT emit the necessary Data Memory Barrier
>> (DMB) instructions [4][5].
> 
> I couldn't reproduce this result when playing around on godbolt. By specifying
> /arch:armv9.4 msvc can be convinced to emit the code for the
> intrinsics inline
> (at least for most of them).  And that makes it visible that
> _InterlockedCompareExchange() results in a "casal" instruction.
> Looking that
> up shows:
>  https://developer.arm.com/documentation/dui0801/l/A64-Data-Transfer-Instructions/CASA--CASAL--CAS--C...-
> which includes these two statements:
> "CASA and CASAL load from memory with acquire semantics."
> "CASL and CASAL store to memory with release semantics."

I didn't even think to check for a compiler flag for the architecture,
nice call!  If this emits the correct instructions it is a much better
approach.  I'll give it a try, thanks for the nudge.

>> Issue 2: S_UNLOCK() uses only a compiler barrier
>> 
>> _ReadWriteBarrier() is a compiler barrier, NOT a hardware memory
>> barrier [6].  It prevents the compiler from reordering operations, but
>> the CPU can still reorder memory operations. This is fundamentally
>> insufficient for ARM64's weaker memory model.
> 
> Yea, that seems broken on a non-TSO architecture.  Is the problem
> fixed if you change just this to include a proper barrier?

Using the flag from above the _ReadWriteBarrier() does (in godbolt) turn
into a casal which (AFAIK) is going to do the trick.  I'll see if I can
update meson.build and get this work as intended.

> Greetings,
> 
> Andres Freund

best.

-greg





^ permalink  raw  reply  [nested|flat] 42+ messages in thread

* Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ​barriers
@ 2025-11-21 19:37  Greg Burd <[email protected]>
  parent: Andres Freund <[email protected]>
  0 siblings, 0 replies; 42+ messages in thread

From: Greg Burd @ 2025-11-21 19:37 UTC (permalink / raw)
  To: Andres Freund <[email protected]>; +Cc: PostgreSQL Hackers <[email protected]>; Dave Cramer <[email protected]>


On Nov 20 2025, at 7:07 pm, Andres Freund <[email protected]> wrote:

> Hi,
> 
> On 2025-11-20 19:03:47 -0500, Andres Freund wrote:
>> > MSVC's _InterlockedCompareExchange() intrinsic on ARM64 performs the
>> > atomic operation but does NOT emit the necessary Data Memory Barrier
>> > (DMB) instructions [4][5].
>> 
>> I couldn't reproduce this result when playing around on godbolt. By specifying
>> /arch:armv9.4 msvc can be convinced to emit the code for the
>> intrinsics inline
>> (at least for most of them).  And that makes it visible that
>> _InterlockedCompareExchange() results in a "casal" instruction.
>> Looking that
>> up shows:
>>   https://developer.arm.com/documentation/dui0801/l/A64-Data-Transfer-Instructions/CASA--CASAL--CAS--C...-
>> which includes these two statements:
>> "CASA and CASAL load from memory with acquire semantics."
>> "CASL and CASAL store to memory with release semantics."
> 
> Further evidence for that is that
> https://learn.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-interlockedcompareexchange
> states:
> "This function generates a full memory barrier (or fence) to ensure
> that memory operations are completed in order."
> 
> (note that we are using the function, not the intrinsic for TAS())

Got it, thanks.

> Greetings,
> 
> Andres

best.

-greg





^ permalink  raw  reply  [nested|flat] 42+ messages in thread

* Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB barriers
@ 2025-11-21 19:40  Greg Burd <[email protected]>
  parent: Nathan Bossart <[email protected]>
  1 sibling, 0 replies; 42+ messages in thread

From: Greg Burd @ 2025-11-21 19:40 UTC (permalink / raw)
  To: Nathan Bossart <[email protected]>; +Cc: Peter Eisentraut <[email protected]>; PostgreSQL Hackers <[email protected]>; Dave Cramer <[email protected]>


On Nov 20 2025, at 5:36 pm, Nathan Bossart <[email protected]> wrote:

> I took a quick look at 0001.

Thanks for taking a second to review!

> +#ifdef _MSC_VER
> +#include <intrin.h>
> +#else
> #include <arm_acle.h>
> unsigned int crc;
> 
> I think you can remove this since we unconditionally do the runtime check
> for MSVC.  In any case, the missing #endif seems likely to cause
> problems.
> 
> --- a/src/port/pg_crc32c_armv8.c
> +++ b/src/port/pg_crc32c_armv8.c
> @@ -14,7 +14,9 @@
>  */
> #include "c.h"
> 
> +#ifndef _MSC_VER
> #include <arm_acle.h>
> +#endif
> 
> Hm.  Doesn't MSVC require intrin.h?

It does in fact fail to compile without this part of the patch, I think
Dave posted a bug about this.  I added the missing endif, thanks!

> -- 
> nathan

best.

-greg





^ permalink  raw  reply  [nested|flat] 42+ messages in thread

* Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ​barriers
@ 2025-11-21 19:52  Greg Burd <[email protected]>
  parent: Thomas Munro <[email protected]>
  1 sibling, 1 reply; 42+ messages in thread

From: Greg Burd @ 2025-11-21 19:52 UTC (permalink / raw)
  To: Thomas Munro <[email protected]>; +Cc: PostgreSQL Hackers <[email protected]>; Dave Cramer <[email protected]>


On Nov 20 2025, at 7:08 pm, Thomas Munro <[email protected]> wrote:

> On Fri, Nov 21, 2025 at 9:45 AM Greg Burd <[email protected]> wrote:
>> Dave and I have been working together to get ARM64 with MSVC functional.
>>  The attached patches accomplish that. Dave is the author of the first
>> which addresses some build issues and fixes the spin_delay() semantics,
>> I did the second which fixes some atomics in this combination.
>  
> A couple of immediate thoughts:

Hey Thomas, I'm always interested in your thoughts.  Thanks for taking a
look at this.

> https://learn.microsoft.com/en-us/cpp/intrinsics/interlockedexchangeadd-intrinsic-functions?view=msv...
>  
> Doesn't seem to match your conclusion.
>  
> +  if cc.get_id() == 'msvc'
> +    cdata.set('USE_ARMV8_CRC32C', false)
> +    cdata.set('USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 1)
>  
> USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK (pg_crc32c_armv8_choose.c) won't
> actually work on Windows, but I don't think we should waste time
> implementing it: vendor-supported versions of Windows 11 require
> ARMv8.1A to boot[1][2], and that has it, so I think we should probably
> just define USE_ARMV8_CRC32C.

I'll give that a go, I think your logic is sound.

> +static __forceinline void
> +spin_delay(void)
> +{
> +     /* Reference:
> https://learn.microsoft.com/en-us/cpp/intrinsics/arm64-intrinsics#BarrierRestrictions
> */
> +    __isb(_ARM64_BARRIER_SY);
> +}
>  
> I don't doubt that barriers are missing in a few places, but how can
> this be the right place?

Well, with the compiler flag that Andres mentioned I need to reconsider
this change.

> If you have an environment set up so it's easy to test, I would also
> be very interested to know if my patch set[3] that nukes all this
> stuff and includes <stdatomic.h> instead, which is green on
> Windows/x86 CI, will just work™ there too.

I do, and I will as soon as I get this sorted.
  
> [1] https://en.wikipedia.org/wiki/Windows_11_version_history
> [2] https://learn.microsoft.com/en-us/lifecycle/products/windows-11-home-and-pro
> [3] https://www.postgresql.org/message-id/flat/CA%2BhUKGKFvu3zyvv3aaj5hHs9VtWcjFAmisOwOc7aOZNc5AF3NA%40m...

best.

-greg





^ permalink  raw  reply  [nested|flat] 42+ messages in thread

* Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ​barriers
@ 2025-11-22 21:43  Greg Burd <[email protected]>
  parent: Greg Burd <[email protected]>
  0 siblings, 1 reply; 42+ messages in thread

From: Greg Burd @ 2025-11-22 21:43 UTC (permalink / raw)
  To: Thomas Munro <[email protected]>; Nathan Bossart <[email protected]>; Andres Freund <[email protected]>; Peter Eisentraut <[email protected]>; +Cc: PostgreSQL Hackers <[email protected]>; Dave Cramer <[email protected]>

Okay,

With the new MSVC compiler flag Andres mentioned (/arch:armv9.4) I only
had to update the S_UNLOCK() macro, the compiler did the rest correctly
AFAICT.  So, a much smaller patch (v2) attached. FWIW I'm using Visual
Studio 2026 (18) to build, other platform information below [1].

The white space/formatting issues seem to have been due to my ineptitude
on Windows running pgindent, or maybe I can blame Perl.  I'll try to dig
if I get a minute to figure out what was the cause and if I need to
patch something.

Also attached is a file with some notes on how I build. The build farm
section isn't finished yet, but there is value in the rest for anyone
doing similar work.  If you're wondering how I learned PowerShell, I
didn't.  I used AI, forgive me.  Eventually I'll have a build animal to
add to the "farm" and update a wiki page somewhere when this solidifies
a bit more. :)

best.

-greg

[1] OS Name	Microsoft Windows 11 Pro
Version	10.0.26100 Build 26100
Other OS Description 	Not Available
OS Manufacturer	Microsoft Corporation
System Name	SANTORINI
System Manufacturer	Microsoft Corporation
System Model	Windows Dev Kit 2023
System Type	ARM64-based PC
System SKU	2043
Processor	Snapdragon Compute Platform, 2995 Mhz, 8 Core(s), 8 Logical Processor(s)
BIOS Version/Date	Microsoft Corporation 13.42.235, 11/13/2024
My goal was to be able to:
  a) develop PostgreSQL on Win11/ARM64 using either GCC or MSVC/Visual Studio
  b) setup my host as a "build farm animal"

Why?  I'm not a "Windows super-fan", I just saw that the Win11/ARM64/MSVC combo
was not covered by the build farm as yet, so I wanted to address that.  If you
have a sick animal you should be able to diagnose and fix it.  Hence, my two
goals.

I started with Dave Cramer's work on a GitHub workflow for this combo, that was
very helpful.
https://github.com/davecramer/vcpkg/blob/main/.github/workflows/vcpkg_windows_arm.yml

NOTE: ... someday figure out how to run the workflow on the host.


Steps I took (YMMV) to accomplish (a) development/testing on Win11/ARM64/MSVC
================================================================================================

* I decided to create a directory c:\tools rather than litter things around,
  you can put the things I placed in that directory anywhere you'd like, but
  adjust your PATH accordingly.

* install Chocolatey (a package manager)
  https://docs.chocolatey.org/

* use Chocolatey to install some packages
  choco install make cmake flex bison openssl python3 diffutils gzip sed strawberryperl winflexbison

  NOTE: the only viable Perl is "strawberryperl" and it is only available as an
  x86_64 build.  This works for scripts used to build Postgres, but it you
  can't link it into your arm64 binary so there is no way to support plperl.

* install Git
  https://git-scm.com/install/windows

  NOTE: This gives you a nice bash shell and some coreutils too.

* use Git to install vcpkg (https://github.com/microsoft/vcpkg)
  cd c:\tools
  git clone --depth 1 --branch 2025.10.17 https://github.com/microsoft/vcpkg.git
  .\bootstrap-vcpkg.bat
  ensure that the path to "vcpkg.bat" is in your PATH

* use vcpkg to install some libraries
  cd c:\tools
  vcpkg install --triplet=arm64-windows --debug icu libiconv libxml2 libxslt lz4 openssl pkgconf readline vcpkg-cmake vcpkg-make vcpkg-tool-meson zlib zstd


* install meson/ninja
  python -m pip install --upgrade pip
  python -m pip install meson==1.9.1
  python -m pip install ninja==1.13.0

  NOTE: I'm not sure if I've now installed meson twice, once via vcpkg and once
  using python... oh well.

* install cURL
  https://curl.se/windows/

* install Visual Studio Community
  https://visualstudio.microsoft.com/downloads/

  ls "C:\Program Files\Microsoft Visual Studio\18\Community\"

* set some environment variables

  PATH=
    $env:PATH
    $env:VCPKG_ROOT
    c:\tools
    c:\tools\curl\bin
    c:\tools\vcpkg\installed\arm64-windows\bin
    "%AppData%\Python\Python314\Scripts"
    "%LocalAppData%\Programs\Microsoft VS Code\bin"
    "%ProgramData%\chocolatey\bin"
    "%ProgramFiles(x86)%\Windows Kits\10\Windows Performance Toolkit"
    "%ProgramFiles%\Git\cmd"
    "C:\Strawberry\c\bin"
    "C:\Strawberry\perl\site\bin"
    "C:\Strawberry\perl\bin"

PKG_CONFIG_PATH=
  c:\tools\vcpkg\installed\arm64-windows\lib\pkgconfig

VCPKG_ROOT=
  c:\tools\vcpkg

* until the fixes are in the tree, apply patches
  git am .\0001-patch-for-arm.patch
  git am .\0002-patch-meson.patch
  git am .\0003...patch

* configure environment
.\env_setup.ps1

* setup meson build
  .\setup.bat

  See below what I get when I run setup.bat

* build
  ninja -v -C build

* test
  meson test -q --print-errorlogs -C build

  NOTE: When builds fail frequently there are postgres.exe and/or cmd.exe
  processes lingering about that are holding "handles" on things and when you
  try to build again or test again or remove the build directory you'll run
  into issues.  Below is a script that finds and kills those processes.

Not required, but useful for sanity... YMMV
================================================================================================
* update PowerShell
  https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell-on-windows
  winget install --id Microsoft.PowerShell --source winget

* emacs or vi/vim/nvim
  choco install emacs nvim

* Zed Editor
  https://zed.dev/

* Sublime Merge/Text
  https://www.sublimetext.com/download
  https://www.sublimemerge.com/download

* sysinternals
 https://learn.microsoft.com/en-us/sysinternals/
 - https://live.sysinternals.com/handle.exe
 - https://live.sysinternals.com/ctrl2cap.exe

* Windows Subsystem for Linux (WSL)
  from an admin cmd.exe: wsl --install

* install Windows Terminal
  https://learn.microsoft.com/en-us/windows/terminal/install

* Docker Desktop
  https://apps.microsoft.com/detail/xp8cbj40xlbwkx
  https://learn.microsoft.com/en-us/windows/wsl/tutorials/wsl-containers


CloseFileHandles.ps1
================================================================================================
PS C:\> Unblock-File C:\tools\CloseFileHandles.ps1

<SNIP>
<#
.SYNOPSIS
    Finds and terminates processes holding open handles to files in a directory.

.DESCRIPTION
    Recursively identifies all files in a specified directory that have open handles,
    determines which processes hold those handles, and forcefully terminates those processes.

.PARAMETER Path
    The directory path to scan for files with open handles. Required.

.PARAMETER WhatIf
    If specified, shows what actions would be taken without actually performing them.

.EXAMPLE
    .\CloseFileHandles.ps1 -Path "C:\Temp"
    .\CloseFileHandles.ps1 -Path "C:\Temp" -Verbose
    .\CloseFileHandles.ps1 -Path "C:\Temp" -WhatIf
    .\CloseFileHandles.ps1 -Path "C:\Temp" -Verbose -WhatIf
.REQUIRES
    https://live.sysinternals.com/handle.exe
#>

[CmdletBinding(SupportsShouldProcess=$true)]
param(
    [Parameter(Mandatory=$true, HelpMessage="Path to scan for open file handles")]
    [string]$Path
)

# Set error action preference to stop on errors
$ErrorActionPreference = "Stop"

# Initialize variables
$processesKilled = @()
$processesFailed = @()

function Write-Error-Custom {
    param([string]$Message)
    Write-Host "[ERROR] $Message" -ForegroundColor Red
}

function Write-Success-Custom {
    param([string]$Message)
    Write-Host "[SUCCESS] $Message" -ForegroundColor Green
}

function Write-WhatIf-Custom {
    param([string]$Message)
    Write-Host "[WHATIF] $Message" -ForegroundColor Yellow
}

try {
    # Validate path exists
    Write-Verbose "Validating path: $Path"
    if (-not (Test-Path -Path $Path -PathType Container)) {
        Write-Error-Custom "Path does not exist or is not a directory: $Path"
        exit 1
    }

    # Check if handle.exe exists
    Write-Verbose "Checking for handle.exe availability"
    $handlePath = "handle.exe"

    try {
        $null = & $handlePath -? 2>&1
    }
    catch {
        Write-Error-Custom "handle.exe not found. Please ensure Sysinternals handle.exe is in PATH or current directory."
        Write-Host "Download from: https://live.sysinternals.com/handle.exe";
        exit 1
    }

    # Get all files recursively in the path
    Write-Verbose "Scanning directory recursively: $Path"
    $files = Get-ChildItem -Path $Path -File -Recurse -ErrorAction SilentlyContinue

    if ($files.Count -eq 0) {
        Write-Verbose "No files found in directory"
        Write-Host "No files found in the specified directory."
        exit 0
    }

    Write-Verbose "Found $($files.Count) files to check"

    # Track unique processes to avoid duplicate kills
    $uniqueProcesses = @{}

    # Process each file
    foreach ($file in $files) {
        Write-Verbose "Checking file: $($file.FullName)"

        try {
            # Run handle.exe to find processes with open handles to this file
            $handleOutput = & $handlePath -p * $file.FullName 2>&1

            if ($handleOutput -and $handleOutput -match '\w+\s+pid:\s+(\d+)') {
                # Parse process IDs from handle.exe output
                $pidMatches = [regex]::Matches($handleOutput, 'pid:\s+(\d+)')

                foreach ($match in $pidMatches) {
                    $pid = [int]$match.Groups[1].Value

                    # Store unique processes
                    if (-not $uniqueProcesses.ContainsKey($pid)) {
                        $uniqueProcesses[$pid] = $file.FullName
                        Write-Verbose "Found process with PID $pid holding handle to: $($file.FullName)"
                    }
                }
            }
        }
        catch {
            Write-Verbose "Could not check handles for file $($file.FullName): $_"
        }
    }

    if ($uniqueProcesses.Count -eq 0) {
        Write-Success-Custom "No processes with open handles found."
        exit 0
    }

    Write-Host "`nFound $($uniqueProcesses.Count) process(es) holding open handles:`n"

    # Kill each unique process
    foreach ($pid in $uniqueProcesses.Keys) {
        try {
            $process = Get-Process -Id $pid -ErrorAction SilentlyContinue

            if ($null -ne $process) {
                $processName = $process.Name
                $processFile = $uniqueProcesses[$pid]

                if ($PSCmdlet.ShouldProcess("Process $processName (PID: $pid)", "Terminate")) {
                    Write-Verbose "Attempting to kill process: $processName (PID: $pid)"
                    Stop-Process -Id $pid -Force -ErrorAction Stop
                    $processesKilled += @{ Name = $processName; PID = $pid; File = $processFile }
                    Write-Success-Custom "Killed process: $processName (PID: $pid)"
                }
            }
            else {
                Write-Verbose "Process with PID $pid no longer exists"
            }
        }
        catch {
            $processesFailed += @{ PID = $pid; Error = $_.Exception.Message }
            Write-Error-Custom "Failed to kill process with PID $pid : $_"
        }
    }

    # Summary
    Write-Host "`n--- Summary ---"
    Write-Host "Processes to be killed: $($uniqueProcesses.Count)"

    if (-not $PSCmdlet.ShouldProcess("dummy", "dummy")) {
        # WhatIf mode was active
        Write-WhatIf-Custom "No processes were actually terminated (WhatIf mode)"
        exit 0
    }
    else {
        Write-Success-Custom "Successfully killed: $($processesKilled.Count) process(es)"

        if ($processesFailed.Count -gt 0) {
            Write-Error-Custom "Failed to kill: $($processesFailed.Count) process(es)"
            foreach ($failed in $processesFailed) {
                Write-Host "  - PID $($failed.PID): $($failed.Error)"
            }
            exit 1
        }

        if ($processesKilled.Count -gt 0 -and $processesFailed.Count -eq 0) {
            exit 0
        }
    }
}
catch {
    Write-Error-Custom "Script error: $_"
    exit 1
}
</SNIP>


Build Farm Animal Setup
================================================================================================

emacs -nw .\build-farm.conf
perl -cw .\run_build.pl
emacs -nw .\build-farm.conf
perl .\run_build.pl --test --nosend --verbose
more .\CHANGEME-test.lastrun-logs\
more .\CHANGEME-test.lastrun-logs\ns-githead.log
more .\CHANGEME-test.lastrun-logs\SCM-checkout.log


NOTES
================================================================================================
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
Get-ExecutionPolicy -Scope CurrentUser
$env:PATH
# Core variables
$env:VCPKG_ROOT
$env:PATH | ForEach-Object { $_.Split(';') | Select-Object -First 20 }
# MSVC paths
$env:INCLUDE
$env:LIB
$env:LIBPATH
# Verify Python
python --version
python -c "import struct; print(f'Python is {struct.calcsize(\"P\") * 8}-bit')"
# Verify Perl location (should be empty or ARM64)
perl --version 2>&1 | Select-Object -First 5
# Meson/build configuration
$env:MESON_PREFIX_PATH
$env:CMAKE_PREFIX_PATH
$env:PKG_CONFIG_PATH
$env:LIB.Split(';') | ForEach-Object { Write-Host $_ }
cat (Get-PSReadlineOption).HistorySavePath


Last bit of output from setup.bat/meson reconfigure/setup
================================================================================================

postgresql 19devel

  Data layout
    data block size        : 8 kB
    WAL block size         : 8 kB
    segment size           : 1 GB

  System
    host system            : windows aarch64
    build system           : windows aarch64

  Compiler
    linker                 : link
    C compiler             : msvc 19.50.35718

  Compiler Flags
    CPP FLAGS              : /DWIN32 /DWINDOWS /D__WINDOWS__ /D__WIN32__ /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
    C FLAGS, functional    : /std:c11
    C FLAGS, warnings      : /wd4090 /wd4244 /wd4018 /wd4101 /wd4267 /w24062 /w24102 /w24777
    C FLAGS, modules       :
    C FLAGS, user specified:
    LD FLAGS               : /INCREMENTAL:NO /STACK:4194304 /NOEXP

  Programs
    bison                  : C:\ProgramData\chocolatey\bin\win_bison.EXE 2.7
    dtrace                 : NO
    flex                   : C:\ProgramData\chocolatey\bin\win_flex.EXE 2.6.3

  External libraries
    bonjour                : NO
    bsd_auth               : NO
    docs                   : NO
    docs_pdf               : NO
    gss                    : NO
    icu                    : YES 78.1
    ldap                   : YES
    libcurl                : NO
    libnuma                : NO
    liburing               : NO
    libxml                 : YES 2.15.0
    libxslt                : YES 1.1.43
    llvm                   : NO
    lz4                    : YES 1.10.0
    nls                    : NO
    openssl                : YES 3.6.0
    pam                    : NO
    plperl                 : NO
    plpython               : NO
    pltcl                  : NO
    readline               : NO
    selinux                : NO
    systemd                : NO
    uuid                   : NO
    zlib                   : YES 1.3.1
    zstd                   : YES 1.5.7

  User defined options
    backend                : ninja
    buildtype              : debugoptimized
    extra_include_dirs     :
    extra_lib_dirs         :
    pkg_config_path        : C:\tools\vcpkg\installed\arm64-windows\lib\pkgconfig
    prefix                 : C:\Program Files\postgresql

Found ninja-1.13.0.git.kitware.jobserver-pipe-1 at C:\Users\gregb\AppData\Roaming\Python\Python314\Scripts\ninja.EXE


ConfigMSVC.ps1
================================================================================================


# ARM64 Development Environment Setup with Auto-Detection
# Configures environment variables and runs Meson setup

# ============================================
# Visual Studio and MSVC Auto-Detection
# ============================================

function Find-VisualStudioPath {
    <#
    .SYNOPSIS
    Locates the Visual Studio installation directory using vswhere
    Works with Visual Studio 2022, 2026, and later
    #>

    # vswhere.exe is always in ProgramFiles(x86)
    $vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"

    if (Test-Path $vswhere) {
        try {
            # Get the latest version of Visual Studio
            $vsPath = & $vswhere -latest -property installationPath 2>$null

            if ($vsPath -and (Test-Path $vsPath)) {
                Write-Host "Found Visual Studio at: $vsPath" -ForegroundColor Green
                return $vsPath
            }
        }
        catch {
            Write-Warning "vswhere.exe found but failed to execute: $_"
        }
    }

    # Fallback: Scan the entire Visual Studio directory tree
    $vsRoot = "${env:ProgramFiles}\Microsoft Visual Studio"
    if (Test-Path $vsRoot) {
        Write-Host "Searching for Visual Studio installations in $vsRoot" -ForegroundColor Yellow

        # Get year directories sorted by newest first (17 = 2022, 18 = 2026, etc.)
        $yearDirs = Get-ChildItem -Path $vsRoot -Directory -ErrorAction SilentlyContinue | Sort-Object Name -Descending

        foreach ($yearDir in $yearDirs) {
            # Get edition directories (Community, Professional, Enterprise)
            $editions = Get-ChildItem -Path $yearDir.FullName -Directory -ErrorAction SilentlyContinue
            foreach ($edition in $editions) {
                # Check if it has the VC tools
                if (Test-Path (Join-Path $edition.FullName "VC\Tools\MSVC")) {
                    Write-Host "Found Visual Studio at: $($edition.FullName)" -ForegroundColor Green
                    return $edition.FullName
                }
            }
        }
    }

    Write-Error "Visual Studio installation not found."
    Write-Error "Checked: $vswhere (vswhere.exe)"
    Write-Error "Checked: ${env:ProgramFiles}\Microsoft Visual Studio\"
    exit 1
}

function Find-MSVCPath {
    <#
    .SYNOPSIS
    Locates the MSVC compiler toolset and returns the latest version path
    #>
    param([string]$VSPath)

    $msvRoot = Join-Path $VSPath "VC\Tools\MSVC"

    if (-not (Test-Path $msvRoot)) {
        Write-Error "MSVC toolset not found at $msvRoot"
        exit 1
    }

    # Get the latest MSVC version folder
    $msvVersions = Get-ChildItem -Path $msvRoot -Directory | Sort-Object Name -Descending

    if ($msvVersions.Count -eq 0) {
        Write-Error "No MSVC versions found in $msvRoot"
        exit 1
    }

    return Join-Path $msvRoot $msvVersions[0].Name
}

function Find-WindowsSDKVersion {
    <#
    .SYNOPSIS
    Detects the Windows SDK version from the registry
    #>
    $regPath = "HKLM:\SOFTWARE\Microsoft\Windows Kits\Installed Roots"

    if (Test-Path $regPath) {
        $sdkRoot = Get-ItemProperty -Path $regPath -Name KitsRoot10
        $sdkRoot = $sdkRoot.KitsRoot10

        if (Test-Path (Join-Path $sdkRoot "Include")) {
            # Get the latest SDK version folder
            $versions = Get-ChildItem -Path (Join-Path $sdkRoot "Include") -Directory |
                        Where-Object { $_.Name -match '^\d+\.\d+\.\d+\.\d+$' } |
                        Sort-Object Name -Descending

            if ($versions.Count -gt 0) {
                return @{
                    Version = $versions[0].Name
                    Path = $sdkRoot
                }
            }
        }
    }

    Write-Error "Windows SDK not found"
    exit 1
}

# ============================================
# Main Setup
# ============================================

Write-Host "=== Detecting Visual Studio Installation ===" -ForegroundColor Cyan
$vsPath = Find-VisualStudioPath
Write-Host "Found Visual Studio at: $vsPath" -ForegroundColor Green

Write-Host "`n=== Detecting MSVC Toolset ===" -ForegroundColor Cyan
$msvPath = Find-MSVCPath -VSPath $vsPath
Write-Host "Found MSVC at: $msvPath" -ForegroundColor Green

Write-Host "`n=== Detecting Windows SDK ===" -ForegroundColor Cyan
$sdkInfo = Find-WindowsSDKVersion
$winKitVersion = $sdkInfo.Version
$winKitPath = $sdkInfo.Path
Write-Host "Found Windows SDK $winKitVersion at: $winKitPath" -ForegroundColor Green

# ============================================
# Initialize MSVC Environment with vcvarsarm64.bat
# ============================================

Write-Host "`n=== Initializing MSVC Environment ===" -ForegroundColor Cyan

$vcvarsPath = Join-Path $vsPath "VC\Auxiliary\Build\vcvarsarm64.bat"

if (-not (Test-Path $vcvarsPath)) {
    Write-Error "vcvarsarm64.bat not found at $vcvarsPath"
    exit 1
}

# Detect Visual Studio version from path
$vsVersion = (Split-Path $vsPath -Parent | Split-Path -Leaf)
Write-Host "Detected Visual Studio version: $vsVersion" -ForegroundColor Yellow

# Map VS directory to version number (17=2022, 18=2026, etc.)
$versionMap = @{
    "17" = "17.0"
    "18" = "18.0"
    "19" = "19.0"
}
$visualStudioVersion = $versionMap[$vsVersion]
if (-not $visualStudioVersion) {
    $visualStudioVersion = "$vsVersion.0"
}

Write-Host "Executing: `"$vcvarsPath`"" -ForegroundColor Yellow
$output = cmd /c """$vcvarsPath"" && set"

# Parse and set all environment variables from vcvarsarm64.bat
foreach ($line in $output) {
    if ($line -match "^([^=]+)=(.*)$") {
        $varName = $matches[1].Trim()
        $varValue = $matches[2].Trim()

        if ($varName -and $varValue) {
            Set-Item -Force -Path "ENV:\$varName" -Value $varValue 2>$null
        }
    }
}

# Explicitly set required variables for Meson
$env:VSINSTALLDIR = $vsPath
$env:VisualStudioVersion = $visualStudioVersion
$env:VCINSTALLDIR = $msvPath

# Verify critical variables
$requiredVars = @{
    "VSINSTALLDIR" = $vsPath
    "VisualStudioVersion" = $visualStudioVersion
    "VCINSTALLDIR" = $msvPath
}

Write-Host "`nEnvironment variables set:" -ForegroundColor Green
foreach ($var in $requiredVars.GetEnumerator()) {
    $value = Get-Item -Path "ENV:\$($var.Key)" -ErrorAction SilentlyContinue
    if ($value) {
        Write-Host "  $($var.Key) = $($value.Value)" -ForegroundColor Green
    }
    else {
        Write-Warning "  $($var.Key) not set!"
    }
}

Write-Host "MSVC environment initialized" -ForegroundColor Green

# ============================================
# Configure Include Paths
# ============================================

Write-Host "`n=== Configuring Include Paths ===" -ForegroundColor Cyan

$includeList = @(
    "$msvPath\include",
    "$winKitPath\Include\$winKitVersion\ucrt",
    "$winKitPath\Include\$winKitVersion\um",
    "$winKitPath\Include\$winKitVersion\shared"
    "$vcpkgRoot\installed\arm64-windows\include"
)

$env:INCLUDE = $includeList -join ";"
Write-Host "INCLUDE path configured" -ForegroundColor Green

# Dump INCLUDE
#$env:INCLUDE | ForEach-Object { $_.Split(';') | Select-Object -First 20 }

# ============================================
# Configure Library Paths
# ============================================

Write-Host "`n=== Configuring Library Paths ===" -ForegroundColor Cyan

$libList = @(
    "$msvPath\lib\arm64",
    "$winKitPath\Lib\$winKitVersion\ucrt\arm64",
    "$winKitPath\Lib\$winKitVersion\um\arm64"
    "$vcpkgRoot\installed\arm64-windows\lib"
)

$env:LIB = $libList -join ";"
$env:LIBPATH = $env:LIB
Write-Host "LIB and LIBPATH configured" -ForegroundColor Green

# Dump LIB
#$env:LIB | ForEach-Object { $_.Split(';') | Select-Object -First 20 }

# ============================================
# Configure PATH
# ============================================

Write-Host "`n=== Configuring System PATH ===" -ForegroundColor Cyan

$pythonPath = "C:\Python314"
#$pythonPath = Join-Path $env:LocalAppData "Programs\Python\Python314"
$pythonScripts = Join-Path $pythonPath "Scripts"
$pythonUserScripts = Join-Path $env:AppData "Python\Python314\Scripts"

$vcpkgRoot = "C:\tools\vcpkg"
$codeInsiders = Join-Path $env:LocalAppData "Programs\Microsoft VS Code Insiders\bin"
$vsCode = Join-Path $env:LocalAppData "Programs\Microsoft VS Code\bin"

# Perl paths - try Strawberry Perl first, then ActivePerl
$perlPath = $null
$perlCandidates = @(
    "C:\Strawberry\perl\bin",
    "${env:ProgramFiles}\Strawberry\perl\bin",
    "${env:ProgramFiles(x86)}\Strawberry\perl\bin",
    "C:\Perl\bin",
    "${env:ProgramFiles}\ActivePerl\bin"
)

foreach ($candidate in $perlCandidates) {
    if (Test-Path $candidate) {
        $perlPath = $candidate
        Write-Host "Found Perl at: $perlPath" -ForegroundColor Green
        break
    }
}

if (-not $perlPath) {
    Write-Warning "Perl not found in standard locations. PostgreSQL build may fail."
    Write-Warning "Install Strawberry Perl from https://strawberryperl.com/";
}

$pathArray = @(
    # ARM64 MSVC compiler
    "$msvPath\bin\HostARM64\ARM64",

    # ARM64 Python (BEFORE system Python or other tools)
    $pythonPath,
    $pythonScripts,
    $pythonUserScripts,

    # Add Perl to PATH
    $perlPath,

    # ARM64 vcpkg
    "$vcpkgRoot\installed\arm64-windows\bin",
    
    # Windows Kits ARM64
    "$winKitPath\bin\$winKitVersion\arm64",

    # System paths
    "$env:SystemRoot\system32",
    "$env:SystemRoot",
    "$env:SystemRoot\System32\Wbem",
    "$env:SystemRoot\System32\WindowsPowerShell\v1.0",
    $codeInsiders,
    $vsCode,

    # Optional tools (but keep at end)
    "${env:ProgramFiles}\Git\cmd",
    "${env:ProgramFiles}\Neovim\bin",
    "${env:ProgramFiles(x86)}\Windows Kits\10\Windows Performance Toolkit",
    "${env:ProgramData}\chocolatey\bin",
    "${env:ProgramFiles}\CMake\bin",
    "C:\tools"
)

# Filter out null/empty entries and non-existent paths
$env:PATH = ($pathArray | Where-Object { $_ -and (Test-Path $_) }) -join ";"
Write-Host "PATH configured" -ForegroundColor Green

# Dump PATH
#$env:PATH | ForEach-Object { $_.Split(';') | Select-Object -First 20 }


# ============================================
# Configure vcpkg and CMake
# ============================================

Write-Host "`n=== Configuring vcpkg and CMake ===" -ForegroundColor Cyan

if (Test-Path $vcpkgRoot) {
    $env:VCPKG_ROOT = $vcpkgRoot
    $env:CMAKE_PREFIX_PATH = "$vcpkgRoot\installed\arm64-windows"

    # Set PKG_CONFIG_PATH for Meson to find vcpkg dependencies
    $env:PKG_CONFIG_PATH = "$vcpkgRoot\installed\arm64-windows\lib\pkgconfig"

    # Add vcpkg tools to PATH (includes pkg-config, ninja from vcpkg-tool-meson, etc.)
    $vcpkgBinPath = "$vcpkgRoot\installed\arm64-windows\bin"
    $vcpkgToolsPath = "$vcpkgRoot\tools"

    if ($vcpkgBinPath -notin $env:PATH.Split(";")) {
        $env:PATH = "$vcpkgBinPath;$env:PATH"
    }

    if ($vcpkgToolsPath -notin $env:PATH.Split(";")) {
        $env:PATH = "$vcpkgToolsPath;$env:PATH"
    }

    Write-Host "vcpkg configured:" -ForegroundColor Green
    Write-Host "  VCPKG_ROOT = $env:VCPKG_ROOT" -ForegroundColor Green
    Write-Host "  CMAKE_PREFIX_PATH = $env:CMAKE_PREFIX_PATH" -ForegroundColor Green
    Write-Host "  PKG_CONFIG_PATH = $env:PKG_CONFIG_PATH" -ForegroundColor Green
    Write-Host "  Added to PATH: $vcpkgBinPath" -ForegroundColor Green
}
else {
    Write-Warning "vcpkg not found at $vcpkgRoot - skipping vcpkg configuration"
}

# ============================================
# Run Meson Setup
# ============================================

Write-Host "`n=== Running Meson Setup ===" -ForegroundColor Cyan

$mesonBuildDir = "build"
$mesonPrefix = "${env:ProgramFiles}\postgresql"

# Use ninja backend instead of vs, which works better with newer MSVC
$mesonArgs = @(
    "setup"
    $mesonBuildDir
    "--reconfigure"
#    "--vsenv"
#    "--backend", "vs"
    "--backend", "ninja"
    "--prefix=$mesonPrefix"
    "--buildtype=debugoptimized"
    "-Dplperl=disabled"
    "-Dextra_lib_dirs=$extraLibDir"
    "-Dextra_include_dirs=$extraIncludeDir"
    "-Dpkg_config_path=$env:PKG_CONFIG_PATH"
)

Write-Host "Executing: meson $($mesonArgs -join ' ')" -ForegroundColor Yellow
meson @mesonArgs


Attachments:

  [application/octet-stream] v2-0001-Address-build-issues-for-ARM64-using-MSVC.patch (4.6K, ../../[email protected]/2-v2-0001-Address-build-issues-for-ARM64-using-MSVC.patch)
  download | inline diff:
From f95d929d4796fd10a274f08c46de02a936414ef0 Mon Sep 17 00:00:00 2001
From: Dave Cramer <[email protected]>
Date: Sun, 13 Jul 2025 06:33:17 -0400
Subject: [PATCH v2 1/2] Address build issues for ARM64 using MSVC

This patch adds support for the ARM64 architecture on Windows 11
and includes work that enables building with MSVC.  This patch also
includes a new intrinsic for spin_delay that is platform specific.
---
 doc/src/sgml/installation.sgml |  2 +-
 meson.build                    |  9 ++++++++-
 src/include/storage/s_lock.h   | 20 ++++++++++++++++++--
 src/port/pg_crc32c_armv8.c     |  2 ++
 src/tools/msvc_gendef.pl       |  8 ++++----
 5 files changed, 33 insertions(+), 8 deletions(-)

diff --git a/doc/src/sgml/installation.sgml b/doc/src/sgml/installation.sgml
index 593202f4fb2..f74dd9e21dd 100644
--- a/doc/src/sgml/installation.sgml
+++ b/doc/src/sgml/installation.sgml
@@ -3967,7 +3967,7 @@ 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 ARM64 architectures on 64-bit Windows.
     </para>
     <para>
      Mixing 32- and 64-bit versions in the same build tree is not supported.
diff --git a/meson.build b/meson.build
index c1e17aa3040..49412364669 100644
--- a/meson.build
+++ b/meson.build
@@ -2494,7 +2494,11 @@ int main(void)
 elif host_cpu == 'arm' or host_cpu == 'aarch64'
 
   prog = '''
+#ifdef _MSC_VER
+#include <intrin.h>
+#else
 #include <arm_acle.h>
+#endif
 unsigned int crc;
 
 int main(void)
@@ -2509,7 +2513,10 @@ int main(void)
 }
 '''
 
-  if cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd without -march=armv8-a+crc',
+  if cc.get_id() == 'msvc'
+    cdata.set('USE_ARMV8_CRC32C', 1)
+    have_optimized_crc = true
+  elif 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)
diff --git a/src/include/storage/s_lock.h b/src/include/storage/s_lock.h
index 7f8f566bd40..be7aaf6b013 100644
--- a/src/include/storage/s_lock.h
+++ b/src/include/storage/s_lock.h
@@ -602,15 +602,31 @@ 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 using Visual C++ on Win64, inline assembly is unavailable.
+ * Use architecture specific intrinsics.
  */
 #if defined(_WIN64)
+/*
+ * For Arm64, use __isb intrinsic. See aarch64 inline assembly definition for details.
+ */
+#ifdef _M_ARM64
+static __forceinline void
+spin_delay(void)
+{
+	 /* Reference: https://learn.microsoft.com/en-us/cpp/intrinsics/arm64-intrinsics#BarrierRestrictions */
+	__isb(_ARM64_BARRIER_SY);
+}
+#else
+/*
+ * For x64, use _mm_pause intrinsic instead of rep nop.
+ */
 static __forceinline void
 spin_delay(void)
 {
 	_mm_pause();
 }
+#endif
 #else
 static __forceinline void
 spin_delay(void)
diff --git a/src/port/pg_crc32c_armv8.c b/src/port/pg_crc32c_armv8.c
index 5ba070bb99d..6a155ddde1e 100644
--- a/src/port/pg_crc32c_armv8.c
+++ b/src/port/pg_crc32c_armv8.c
@@ -14,7 +14,9 @@
  */
 #include "c.h"
 
+#ifndef _MSC_VER
 #include <arm_acle.h>
+#endif
 
 #include "port/pg_crc32c.h"
 
diff --git a/src/tools/msvc_gendef.pl b/src/tools/msvc_gendef.pl
index 868aad51b09..c92c94c4775 100644
--- a/src/tools/msvc_gendef.pl
+++ b/src/tools/msvc_gendef.pl
@@ -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;
 
-- 
2.52.0.windows.1



  [application/octet-stream] v2-0002-Fix-Win11-MSVC-ARM64-atomic-intrinsics.patch (1.6K, ../../[email protected]/3-v2-0002-Fix-Win11-MSVC-ARM64-atomic-intrinsics.patch)
  download | inline diff:
From b274b92ece9d48f0c9f25cfdddd0a15ad95f2c2f Mon Sep 17 00:00:00 2001
From: Greg Burd <[email protected]>
Date: Sat, 22 Nov 2025 16:15:42 -0500
Subject: [PATCH v2 2/2] Fix Win11/MSVC/ARM64 atomic intrinsics

Add complier flags that ensure proper generation of atomic intrinsic
code for the ARM64 platform.  Also update the S_UNLOCK() macro to have
a CPU barrier rather than compiler barrier that prevents memory
reordering.
---
 meson.build                  | 5 +++++
 src/include/storage/s_lock.h | 3 ++-
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/meson.build b/meson.build
index 49412364669..b5d141853e0 100644
--- a/meson.build
+++ b/meson.build
@@ -2154,6 +2154,11 @@ endforeach
 
 
 if cc.get_id() == 'msvc'
+  # Add ARM64 architecture flag for Windows 11 ARM64 for correct intrensics
+  if host_machine.system() == 'windows' and host_machine.cpu_family() == 'aarch64'
+    add_project_arguments('/arch:armv9.4', language: ['c', 'cpp'])
+  endif
+
   cflags_warn += [
     # Warnings to disable:
     # from /W1:
diff --git a/src/include/storage/s_lock.h b/src/include/storage/s_lock.h
index be7aaf6b013..fd4ae992dce 100644
--- a/src/include/storage/s_lock.h
+++ b/src/include/storage/s_lock.h
@@ -611,6 +611,7 @@ typedef LONG slock_t;
  * For Arm64, use __isb intrinsic. See aarch64 inline assembly definition for details.
  */
 #ifdef _M_ARM64
+
 static __forceinline void
 spin_delay(void)
 {
@@ -640,7 +641,7 @@ spin_delay(void)
 #pragma intrinsic(_ReadWriteBarrier)
 
 #define S_UNLOCK(lock)	\
-	do { _ReadWriteBarrier(); (*(lock)) = 0; } while (0)
+	do { __dmb(_ARM64_BARRIER_SY); (*(lock)) = 0; } while (0)
 
 #endif
 
-- 
2.52.0.windows.1



  [text/plain] pg-arm64-notes.txt (26.7K, ../../[email protected]/4-pg-arm64-notes.txt)
  download | inline:
My goal was to be able to:
  a) develop PostgreSQL on Win11/ARM64 using either GCC or MSVC/Visual Studio
  b) setup my host as a "build farm animal"

Why?  I'm not a "Windows super-fan", I just saw that the Win11/ARM64/MSVC combo
was not covered by the build farm as yet, so I wanted to address that.  If you
have a sick animal you should be able to diagnose and fix it.  Hence, my two
goals.

I started with Dave Cramer's work on a GitHub workflow for this combo, that was
very helpful.
https://github.com/davecramer/vcpkg/blob/main/.github/workflows/vcpkg_windows_arm.yml

NOTE: ... someday figure out how to run the workflow on the host.


Steps I took (YMMV) to accomplish (a) development/testing on Win11/ARM64/MSVC
================================================================================================

* I decided to create a directory c:\tools rather than litter things around,
  you can put the things I placed in that directory anywhere you'd like, but
  adjust your PATH accordingly.

* install Chocolatey (a package manager)
  https://docs.chocolatey.org/

* use Chocolatey to install some packages
  choco install make cmake flex bison openssl python3 diffutils gzip sed strawberryperl winflexbison

  NOTE: the only viable Perl is "strawberryperl" and it is only available as an
  x86_64 build.  This works for scripts used to build Postgres, but it you
  can't link it into your arm64 binary so there is no way to support plperl.

* install Git
  https://git-scm.com/install/windows

  NOTE: This gives you a nice bash shell and some coreutils too.

* use Git to install vcpkg (https://github.com/microsoft/vcpkg)
  cd c:\tools
  git clone --depth 1 --branch 2025.10.17 https://github.com/microsoft/vcpkg.git
  .\bootstrap-vcpkg.bat
  ensure that the path to "vcpkg.bat" is in your PATH

* use vcpkg to install some libraries
  cd c:\tools
  vcpkg install --triplet=arm64-windows --debug icu libiconv libxml2 libxslt lz4 openssl pkgconf readline vcpkg-cmake vcpkg-make vcpkg-tool-meson zlib zstd


* install meson/ninja
  python -m pip install --upgrade pip
  python -m pip install meson==1.9.1
  python -m pip install ninja==1.13.0

  NOTE: I'm not sure if I've now installed meson twice, once via vcpkg and once
  using python... oh well.

* install cURL
  https://curl.se/windows/

* install Visual Studio Community
  https://visualstudio.microsoft.com/downloads/

  ls "C:\Program Files\Microsoft Visual Studio\18\Community\"

* set some environment variables

  PATH=
    $env:PATH
    $env:VCPKG_ROOT
    c:\tools
    c:\tools\curl\bin
    c:\tools\vcpkg\installed\arm64-windows\bin
    "%AppData%\Python\Python314\Scripts"
    "%LocalAppData%\Programs\Microsoft VS Code\bin"
    "%ProgramData%\chocolatey\bin"
    "%ProgramFiles(x86)%\Windows Kits\10\Windows Performance Toolkit"
    "%ProgramFiles%\Git\cmd"
    "C:\Strawberry\c\bin"
    "C:\Strawberry\perl\site\bin"
    "C:\Strawberry\perl\bin"

PKG_CONFIG_PATH=
  c:\tools\vcpkg\installed\arm64-windows\lib\pkgconfig

VCPKG_ROOT=
  c:\tools\vcpkg

* until the fixes are in the tree, apply patches
  git am .\0001-patch-for-arm.patch
  git am .\0002-patch-meson.patch
  git am .\0003...patch

* configure environment
.\env_setup.ps1

* setup meson build
  .\setup.bat

  See below what I get when I run setup.bat

* build
  ninja -v -C build

* test
  meson test -q --print-errorlogs -C build

  NOTE: When builds fail frequently there are postgres.exe and/or cmd.exe
  processes lingering about that are holding "handles" on things and when you
  try to build again or test again or remove the build directory you'll run
  into issues.  Below is a script that finds and kills those processes.

Not required, but useful for sanity... YMMV
================================================================================================
* update PowerShell
  https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell-on-windows
  winget install --id Microsoft.PowerShell --source winget

* emacs or vi/vim/nvim
  choco install emacs nvim

* Zed Editor
  https://zed.dev/

* Sublime Merge/Text
  https://www.sublimetext.com/download
  https://www.sublimemerge.com/download

* sysinternals
 https://learn.microsoft.com/en-us/sysinternals/
 - https://live.sysinternals.com/handle.exe
 - https://live.sysinternals.com/ctrl2cap.exe

* Windows Subsystem for Linux (WSL)
  from an admin cmd.exe: wsl --install

* install Windows Terminal
  https://learn.microsoft.com/en-us/windows/terminal/install

* Docker Desktop
  https://apps.microsoft.com/detail/xp8cbj40xlbwkx
  https://learn.microsoft.com/en-us/windows/wsl/tutorials/wsl-containers


CloseFileHandles.ps1
================================================================================================
PS C:\> Unblock-File C:\tools\CloseFileHandles.ps1

<SNIP>
<#
.SYNOPSIS
    Finds and terminates processes holding open handles to files in a directory.

.DESCRIPTION
    Recursively identifies all files in a specified directory that have open handles,
    determines which processes hold those handles, and forcefully terminates those processes.

.PARAMETER Path
    The directory path to scan for files with open handles. Required.

.PARAMETER WhatIf
    If specified, shows what actions would be taken without actually performing them.

.EXAMPLE
    .\CloseFileHandles.ps1 -Path "C:\Temp"
    .\CloseFileHandles.ps1 -Path "C:\Temp" -Verbose
    .\CloseFileHandles.ps1 -Path "C:\Temp" -WhatIf
    .\CloseFileHandles.ps1 -Path "C:\Temp" -Verbose -WhatIf
.REQUIRES
    https://live.sysinternals.com/handle.exe
#>

[CmdletBinding(SupportsShouldProcess=$true)]
param(
    [Parameter(Mandatory=$true, HelpMessage="Path to scan for open file handles")]
    [string]$Path
)

# Set error action preference to stop on errors
$ErrorActionPreference = "Stop"

# Initialize variables
$processesKilled = @()
$processesFailed = @()

function Write-Error-Custom {
    param([string]$Message)
    Write-Host "[ERROR] $Message" -ForegroundColor Red
}

function Write-Success-Custom {
    param([string]$Message)
    Write-Host "[SUCCESS] $Message" -ForegroundColor Green
}

function Write-WhatIf-Custom {
    param([string]$Message)
    Write-Host "[WHATIF] $Message" -ForegroundColor Yellow
}

try {
    # Validate path exists
    Write-Verbose "Validating path: $Path"
    if (-not (Test-Path -Path $Path -PathType Container)) {
        Write-Error-Custom "Path does not exist or is not a directory: $Path"
        exit 1
    }

    # Check if handle.exe exists
    Write-Verbose "Checking for handle.exe availability"
    $handlePath = "handle.exe"

    try {
        $null = & $handlePath -? 2>&1
    }
    catch {
        Write-Error-Custom "handle.exe not found. Please ensure Sysinternals handle.exe is in PATH or current directory."
        Write-Host "Download from: https://live.sysinternals.com/handle.exe"
        exit 1
    }

    # Get all files recursively in the path
    Write-Verbose "Scanning directory recursively: $Path"
    $files = Get-ChildItem -Path $Path -File -Recurse -ErrorAction SilentlyContinue

    if ($files.Count -eq 0) {
        Write-Verbose "No files found in directory"
        Write-Host "No files found in the specified directory."
        exit 0
    }

    Write-Verbose "Found $($files.Count) files to check"

    # Track unique processes to avoid duplicate kills
    $uniqueProcesses = @{}

    # Process each file
    foreach ($file in $files) {
        Write-Verbose "Checking file: $($file.FullName)"

        try {
            # Run handle.exe to find processes with open handles to this file
            $handleOutput = & $handlePath -p * $file.FullName 2>&1

            if ($handleOutput -and $handleOutput -match '\w+\s+pid:\s+(\d+)') {
                # Parse process IDs from handle.exe output
                $pidMatches = [regex]::Matches($handleOutput, 'pid:\s+(\d+)')

                foreach ($match in $pidMatches) {
                    $pid = [int]$match.Groups[1].Value

                    # Store unique processes
                    if (-not $uniqueProcesses.ContainsKey($pid)) {
                        $uniqueProcesses[$pid] = $file.FullName
                        Write-Verbose "Found process with PID $pid holding handle to: $($file.FullName)"
                    }
                }
            }
        }
        catch {
            Write-Verbose "Could not check handles for file $($file.FullName): $_"
        }
    }

    if ($uniqueProcesses.Count -eq 0) {
        Write-Success-Custom "No processes with open handles found."
        exit 0
    }

    Write-Host "`nFound $($uniqueProcesses.Count) process(es) holding open handles:`n"

    # Kill each unique process
    foreach ($pid in $uniqueProcesses.Keys) {
        try {
            $process = Get-Process -Id $pid -ErrorAction SilentlyContinue

            if ($null -ne $process) {
                $processName = $process.Name
                $processFile = $uniqueProcesses[$pid]

                if ($PSCmdlet.ShouldProcess("Process $processName (PID: $pid)", "Terminate")) {
                    Write-Verbose "Attempting to kill process: $processName (PID: $pid)"
                    Stop-Process -Id $pid -Force -ErrorAction Stop
                    $processesKilled += @{ Name = $processName; PID = $pid; File = $processFile }
                    Write-Success-Custom "Killed process: $processName (PID: $pid)"
                }
            }
            else {
                Write-Verbose "Process with PID $pid no longer exists"
            }
        }
        catch {
            $processesFailed += @{ PID = $pid; Error = $_.Exception.Message }
            Write-Error-Custom "Failed to kill process with PID $pid : $_"
        }
    }

    # Summary
    Write-Host "`n--- Summary ---"
    Write-Host "Processes to be killed: $($uniqueProcesses.Count)"

    if (-not $PSCmdlet.ShouldProcess("dummy", "dummy")) {
        # WhatIf mode was active
        Write-WhatIf-Custom "No processes were actually terminated (WhatIf mode)"
        exit 0
    }
    else {
        Write-Success-Custom "Successfully killed: $($processesKilled.Count) process(es)"

        if ($processesFailed.Count -gt 0) {
            Write-Error-Custom "Failed to kill: $($processesFailed.Count) process(es)"
            foreach ($failed in $processesFailed) {
                Write-Host "  - PID $($failed.PID): $($failed.Error)"
            }
            exit 1
        }

        if ($processesKilled.Count -gt 0 -and $processesFailed.Count -eq 0) {
            exit 0
        }
    }
}
catch {
    Write-Error-Custom "Script error: $_"
    exit 1
}
</SNIP>


Build Farm Animal Setup
================================================================================================

emacs -nw .\build-farm.conf
perl -cw .\run_build.pl
emacs -nw .\build-farm.conf
perl .\run_build.pl --test --nosend --verbose
more .\CHANGEME-test.lastrun-logs\
more .\CHANGEME-test.lastrun-logs\ns-githead.log
more .\CHANGEME-test.lastrun-logs\SCM-checkout.log


NOTES
================================================================================================
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
Get-ExecutionPolicy -Scope CurrentUser
$env:PATH
# Core variables
$env:VCPKG_ROOT
$env:PATH | ForEach-Object { $_.Split(';') | Select-Object -First 20 }
# MSVC paths
$env:INCLUDE
$env:LIB
$env:LIBPATH
# Verify Python
python --version
python -c "import struct; print(f'Python is {struct.calcsize(\"P\") * 8}-bit')"
# Verify Perl location (should be empty or ARM64)
perl --version 2>&1 | Select-Object -First 5
# Meson/build configuration
$env:MESON_PREFIX_PATH
$env:CMAKE_PREFIX_PATH
$env:PKG_CONFIG_PATH
$env:LIB.Split(';') | ForEach-Object { Write-Host $_ }
cat (Get-PSReadlineOption).HistorySavePath


Last bit of output from setup.bat/meson reconfigure/setup
================================================================================================

postgresql 19devel

  Data layout
    data block size        : 8 kB
    WAL block size         : 8 kB
    segment size           : 1 GB

  System
    host system            : windows aarch64
    build system           : windows aarch64

  Compiler
    linker                 : link
    C compiler             : msvc 19.50.35718

  Compiler Flags
    CPP FLAGS              : /DWIN32 /DWINDOWS /D__WINDOWS__ /D__WIN32__ /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
    C FLAGS, functional    : /std:c11
    C FLAGS, warnings      : /wd4090 /wd4244 /wd4018 /wd4101 /wd4267 /w24062 /w24102 /w24777
    C FLAGS, modules       :
    C FLAGS, user specified:
    LD FLAGS               : /INCREMENTAL:NO /STACK:4194304 /NOEXP

  Programs
    bison                  : C:\ProgramData\chocolatey\bin\win_bison.EXE 2.7
    dtrace                 : NO
    flex                   : C:\ProgramData\chocolatey\bin\win_flex.EXE 2.6.3

  External libraries
    bonjour                : NO
    bsd_auth               : NO
    docs                   : NO
    docs_pdf               : NO
    gss                    : NO
    icu                    : YES 78.1
    ldap                   : YES
    libcurl                : NO
    libnuma                : NO
    liburing               : NO
    libxml                 : YES 2.15.0
    libxslt                : YES 1.1.43
    llvm                   : NO
    lz4                    : YES 1.10.0
    nls                    : NO
    openssl                : YES 3.6.0
    pam                    : NO
    plperl                 : NO
    plpython               : NO
    pltcl                  : NO
    readline               : NO
    selinux                : NO
    systemd                : NO
    uuid                   : NO
    zlib                   : YES 1.3.1
    zstd                   : YES 1.5.7

  User defined options
    backend                : ninja
    buildtype              : debugoptimized
    extra_include_dirs     :
    extra_lib_dirs         :
    pkg_config_path        : C:\tools\vcpkg\installed\arm64-windows\lib\pkgconfig
    prefix                 : C:\Program Files\postgresql

Found ninja-1.13.0.git.kitware.jobserver-pipe-1 at C:\Users\gregb\AppData\Roaming\Python\Python314\Scripts\ninja.EXE


ConfigMSVC.ps1
================================================================================================


# ARM64 Development Environment Setup with Auto-Detection
# Configures environment variables and runs Meson setup

# ============================================
# Visual Studio and MSVC Auto-Detection
# ============================================

function Find-VisualStudioPath {
    <#
    .SYNOPSIS
    Locates the Visual Studio installation directory using vswhere
    Works with Visual Studio 2022, 2026, and later
    #>

    # vswhere.exe is always in ProgramFiles(x86)
    $vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"

    if (Test-Path $vswhere) {
        try {
            # Get the latest version of Visual Studio
            $vsPath = & $vswhere -latest -property installationPath 2>$null

            if ($vsPath -and (Test-Path $vsPath)) {
                Write-Host "Found Visual Studio at: $vsPath" -ForegroundColor Green
                return $vsPath
            }
        }
        catch {
            Write-Warning "vswhere.exe found but failed to execute: $_"
        }
    }

    # Fallback: Scan the entire Visual Studio directory tree
    $vsRoot = "${env:ProgramFiles}\Microsoft Visual Studio"
    if (Test-Path $vsRoot) {
        Write-Host "Searching for Visual Studio installations in $vsRoot" -ForegroundColor Yellow

        # Get year directories sorted by newest first (17 = 2022, 18 = 2026, etc.)
        $yearDirs = Get-ChildItem -Path $vsRoot -Directory -ErrorAction SilentlyContinue | Sort-Object Name -Descending

        foreach ($yearDir in $yearDirs) {
            # Get edition directories (Community, Professional, Enterprise)
            $editions = Get-ChildItem -Path $yearDir.FullName -Directory -ErrorAction SilentlyContinue
            foreach ($edition in $editions) {
                # Check if it has the VC tools
                if (Test-Path (Join-Path $edition.FullName "VC\Tools\MSVC")) {
                    Write-Host "Found Visual Studio at: $($edition.FullName)" -ForegroundColor Green
                    return $edition.FullName
                }
            }
        }
    }

    Write-Error "Visual Studio installation not found."
    Write-Error "Checked: $vswhere (vswhere.exe)"
    Write-Error "Checked: ${env:ProgramFiles}\Microsoft Visual Studio\"
    exit 1
}

function Find-MSVCPath {
    <#
    .SYNOPSIS
    Locates the MSVC compiler toolset and returns the latest version path
    #>
    param([string]$VSPath)

    $msvRoot = Join-Path $VSPath "VC\Tools\MSVC"

    if (-not (Test-Path $msvRoot)) {
        Write-Error "MSVC toolset not found at $msvRoot"
        exit 1
    }

    # Get the latest MSVC version folder
    $msvVersions = Get-ChildItem -Path $msvRoot -Directory | Sort-Object Name -Descending

    if ($msvVersions.Count -eq 0) {
        Write-Error "No MSVC versions found in $msvRoot"
        exit 1
    }

    return Join-Path $msvRoot $msvVersions[0].Name
}

function Find-WindowsSDKVersion {
    <#
    .SYNOPSIS
    Detects the Windows SDK version from the registry
    #>
    $regPath = "HKLM:\SOFTWARE\Microsoft\Windows Kits\Installed Roots"

    if (Test-Path $regPath) {
        $sdkRoot = Get-ItemProperty -Path $regPath -Name KitsRoot10
        $sdkRoot = $sdkRoot.KitsRoot10

        if (Test-Path (Join-Path $sdkRoot "Include")) {
            # Get the latest SDK version folder
            $versions = Get-ChildItem -Path (Join-Path $sdkRoot "Include") -Directory |
                        Where-Object { $_.Name -match '^\d+\.\d+\.\d+\.\d+$' } |
                        Sort-Object Name -Descending

            if ($versions.Count -gt 0) {
                return @{
                    Version = $versions[0].Name
                    Path = $sdkRoot
                }
            }
        }
    }

    Write-Error "Windows SDK not found"
    exit 1
}

# ============================================
# Main Setup
# ============================================

Write-Host "=== Detecting Visual Studio Installation ===" -ForegroundColor Cyan
$vsPath = Find-VisualStudioPath
Write-Host "Found Visual Studio at: $vsPath" -ForegroundColor Green

Write-Host "`n=== Detecting MSVC Toolset ===" -ForegroundColor Cyan
$msvPath = Find-MSVCPath -VSPath $vsPath
Write-Host "Found MSVC at: $msvPath" -ForegroundColor Green

Write-Host "`n=== Detecting Windows SDK ===" -ForegroundColor Cyan
$sdkInfo = Find-WindowsSDKVersion
$winKitVersion = $sdkInfo.Version
$winKitPath = $sdkInfo.Path
Write-Host "Found Windows SDK $winKitVersion at: $winKitPath" -ForegroundColor Green

# ============================================
# Initialize MSVC Environment with vcvarsarm64.bat
# ============================================

Write-Host "`n=== Initializing MSVC Environment ===" -ForegroundColor Cyan

$vcvarsPath = Join-Path $vsPath "VC\Auxiliary\Build\vcvarsarm64.bat"

if (-not (Test-Path $vcvarsPath)) {
    Write-Error "vcvarsarm64.bat not found at $vcvarsPath"
    exit 1
}

# Detect Visual Studio version from path
$vsVersion = (Split-Path $vsPath -Parent | Split-Path -Leaf)
Write-Host "Detected Visual Studio version: $vsVersion" -ForegroundColor Yellow

# Map VS directory to version number (17=2022, 18=2026, etc.)
$versionMap = @{
    "17" = "17.0"
    "18" = "18.0"
    "19" = "19.0"
}
$visualStudioVersion = $versionMap[$vsVersion]
if (-not $visualStudioVersion) {
    $visualStudioVersion = "$vsVersion.0"
}

Write-Host "Executing: `"$vcvarsPath`"" -ForegroundColor Yellow
$output = cmd /c """$vcvarsPath"" && set"

# Parse and set all environment variables from vcvarsarm64.bat
foreach ($line in $output) {
    if ($line -match "^([^=]+)=(.*)$") {
        $varName = $matches[1].Trim()
        $varValue = $matches[2].Trim()

        if ($varName -and $varValue) {
            Set-Item -Force -Path "ENV:\$varName" -Value $varValue 2>$null
        }
    }
}

# Explicitly set required variables for Meson
$env:VSINSTALLDIR = $vsPath
$env:VisualStudioVersion = $visualStudioVersion
$env:VCINSTALLDIR = $msvPath

# Verify critical variables
$requiredVars = @{
    "VSINSTALLDIR" = $vsPath
    "VisualStudioVersion" = $visualStudioVersion
    "VCINSTALLDIR" = $msvPath
}

Write-Host "`nEnvironment variables set:" -ForegroundColor Green
foreach ($var in $requiredVars.GetEnumerator()) {
    $value = Get-Item -Path "ENV:\$($var.Key)" -ErrorAction SilentlyContinue
    if ($value) {
        Write-Host "  $($var.Key) = $($value.Value)" -ForegroundColor Green
    }
    else {
        Write-Warning "  $($var.Key) not set!"
    }
}

Write-Host "MSVC environment initialized" -ForegroundColor Green

# ============================================
# Configure Include Paths
# ============================================

Write-Host "`n=== Configuring Include Paths ===" -ForegroundColor Cyan

$includeList = @(
    "$msvPath\include",
    "$winKitPath\Include\$winKitVersion\ucrt",
    "$winKitPath\Include\$winKitVersion\um",
    "$winKitPath\Include\$winKitVersion\shared"
    "$vcpkgRoot\installed\arm64-windows\include"
)

$env:INCLUDE = $includeList -join ";"
Write-Host "INCLUDE path configured" -ForegroundColor Green

# Dump INCLUDE
#$env:INCLUDE | ForEach-Object { $_.Split(';') | Select-Object -First 20 }

# ============================================
# Configure Library Paths
# ============================================

Write-Host "`n=== Configuring Library Paths ===" -ForegroundColor Cyan

$libList = @(
    "$msvPath\lib\arm64",
    "$winKitPath\Lib\$winKitVersion\ucrt\arm64",
    "$winKitPath\Lib\$winKitVersion\um\arm64"
    "$vcpkgRoot\installed\arm64-windows\lib"
)

$env:LIB = $libList -join ";"
$env:LIBPATH = $env:LIB
Write-Host "LIB and LIBPATH configured" -ForegroundColor Green

# Dump LIB
#$env:LIB | ForEach-Object { $_.Split(';') | Select-Object -First 20 }

# ============================================
# Configure PATH
# ============================================

Write-Host "`n=== Configuring System PATH ===" -ForegroundColor Cyan

$pythonPath = "C:\Python314"
#$pythonPath = Join-Path $env:LocalAppData "Programs\Python\Python314"
$pythonScripts = Join-Path $pythonPath "Scripts"
$pythonUserScripts = Join-Path $env:AppData "Python\Python314\Scripts"

$vcpkgRoot = "C:\tools\vcpkg"
$codeInsiders = Join-Path $env:LocalAppData "Programs\Microsoft VS Code Insiders\bin"
$vsCode = Join-Path $env:LocalAppData "Programs\Microsoft VS Code\bin"

# Perl paths - try Strawberry Perl first, then ActivePerl
$perlPath = $null
$perlCandidates = @(
    "C:\Strawberry\perl\bin",
    "${env:ProgramFiles}\Strawberry\perl\bin",
    "${env:ProgramFiles(x86)}\Strawberry\perl\bin",
    "C:\Perl\bin",
    "${env:ProgramFiles}\ActivePerl\bin"
)

foreach ($candidate in $perlCandidates) {
    if (Test-Path $candidate) {
        $perlPath = $candidate
        Write-Host "Found Perl at: $perlPath" -ForegroundColor Green
        break
    }
}

if (-not $perlPath) {
    Write-Warning "Perl not found in standard locations. PostgreSQL build may fail."
    Write-Warning "Install Strawberry Perl from https://strawberryperl.com/"
}

$pathArray = @(
    # ARM64 MSVC compiler
    "$msvPath\bin\HostARM64\ARM64",

    # ARM64 Python (BEFORE system Python or other tools)
    $pythonPath,
    $pythonScripts,
    $pythonUserScripts,

    # Add Perl to PATH
    $perlPath,

    # ARM64 vcpkg
    "$vcpkgRoot\installed\arm64-windows\bin",
    
    # Windows Kits ARM64
    "$winKitPath\bin\$winKitVersion\arm64",

    # System paths
    "$env:SystemRoot\system32",
    "$env:SystemRoot",
    "$env:SystemRoot\System32\Wbem",
    "$env:SystemRoot\System32\WindowsPowerShell\v1.0",
    $codeInsiders,
    $vsCode,

    # Optional tools (but keep at end)
    "${env:ProgramFiles}\Git\cmd",
    "${env:ProgramFiles}\Neovim\bin",
    "${env:ProgramFiles(x86)}\Windows Kits\10\Windows Performance Toolkit",
    "${env:ProgramData}\chocolatey\bin",
    "${env:ProgramFiles}\CMake\bin",
    "C:\tools"
)

# Filter out null/empty entries and non-existent paths
$env:PATH = ($pathArray | Where-Object { $_ -and (Test-Path $_) }) -join ";"
Write-Host "PATH configured" -ForegroundColor Green

# Dump PATH
#$env:PATH | ForEach-Object { $_.Split(';') | Select-Object -First 20 }


# ============================================
# Configure vcpkg and CMake
# ============================================

Write-Host "`n=== Configuring vcpkg and CMake ===" -ForegroundColor Cyan

if (Test-Path $vcpkgRoot) {
    $env:VCPKG_ROOT = $vcpkgRoot
    $env:CMAKE_PREFIX_PATH = "$vcpkgRoot\installed\arm64-windows"

    # Set PKG_CONFIG_PATH for Meson to find vcpkg dependencies
    $env:PKG_CONFIG_PATH = "$vcpkgRoot\installed\arm64-windows\lib\pkgconfig"

    # Add vcpkg tools to PATH (includes pkg-config, ninja from vcpkg-tool-meson, etc.)
    $vcpkgBinPath = "$vcpkgRoot\installed\arm64-windows\bin"
    $vcpkgToolsPath = "$vcpkgRoot\tools"

    if ($vcpkgBinPath -notin $env:PATH.Split(";")) {
        $env:PATH = "$vcpkgBinPath;$env:PATH"
    }

    if ($vcpkgToolsPath -notin $env:PATH.Split(";")) {
        $env:PATH = "$vcpkgToolsPath;$env:PATH"
    }

    Write-Host "vcpkg configured:" -ForegroundColor Green
    Write-Host "  VCPKG_ROOT = $env:VCPKG_ROOT" -ForegroundColor Green
    Write-Host "  CMAKE_PREFIX_PATH = $env:CMAKE_PREFIX_PATH" -ForegroundColor Green
    Write-Host "  PKG_CONFIG_PATH = $env:PKG_CONFIG_PATH" -ForegroundColor Green
    Write-Host "  Added to PATH: $vcpkgBinPath" -ForegroundColor Green
}
else {
    Write-Warning "vcpkg not found at $vcpkgRoot - skipping vcpkg configuration"
}

# ============================================
# Run Meson Setup
# ============================================

Write-Host "`n=== Running Meson Setup ===" -ForegroundColor Cyan

$mesonBuildDir = "build"
$mesonPrefix = "${env:ProgramFiles}\postgresql"

# Use ninja backend instead of vs, which works better with newer MSVC
$mesonArgs = @(
    "setup"
    $mesonBuildDir
    "--reconfigure"
#    "--vsenv"
#    "--backend", "vs"
    "--backend", "ninja"
    "--prefix=$mesonPrefix"
    "--buildtype=debugoptimized"
    "-Dplperl=disabled"
    "-Dextra_lib_dirs=$extraLibDir"
    "-Dextra_include_dirs=$extraIncludeDir"
    "-Dpkg_config_path=$env:PKG_CONFIG_PATH"
)

Write-Host "Executing: meson $($mesonArgs -join ' ')" -ForegroundColor Yellow
meson @mesonArgs

^ permalink  raw  reply  [nested|flat] 42+ messages in thread

*  Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ​barriers
@ 2025-11-23 13:07  Greg Burd <[email protected]>
  parent: Thomas Munro <[email protected]>
  1 sibling, 0 replies; 42+ messages in thread

From: Greg Burd @ 2025-11-23 13:07 UTC (permalink / raw)
  To: Thomas Munro <[email protected]>; +Cc: PostgreSQL Hackers <[email protected]>; Dave Cramer <[email protected]>


On Thu, Nov 20, 2025, at 7:08 PM, Thomas Munro wrote:
> If you have an environment set up so it's easy to test, I would also
> be very interested to know if my patch set[3] that nukes all this
> stuff and includes <stdatomic.h> instead, which is green on
> Windows/x86 CI, will just work™ there too.
>
> [3] 
> https://www.postgresql.org/message-id/flat/CA%2BhUKGKFvu3zyvv3aaj5hHs9VtWcjFAmisOwOc7aOZNc5AF3NA%40m...

Hello Thomas,

I gave your stdatomic patchs a try, here's where it fell apart linking.

[174/1996] Linking target src/interfaces/libpq/libpq.dll
   Creating library src/interfaces/libpq\libpq.lib
[981/1996] Linking target src/interfaces/ecpg/pgtypeslib/libpgtypes.dll
   Creating library src\interfaces\ecpg\pgtypeslib\libpgtypes.lib
[1235/1996] Linking target src/interfaces/ecpg/ecpglib/libecpg.dll
   Creating library src\interfaces\ecpg\ecpglib\libecpg.lib
[1401/1996] Linking target src/backend/postgres.exe
FAILED: [code=1120] src/backend/postgres.exe src/backend/postgres.pdb
"link" @src/backend/postgres.exe.rsp
   Creating library src\backend\postgres.lib
storage_lmgr_s_lock.c.obj : error LNK2019: unresolved external symbol _mm_pause referenced in function perform_spin_delay
src\backend\postgres.exe : fatal error LNK1120: 1 unresolved externals
[1410/1996] Compiling C object src/backend/snowball/dict_snowball.dll.p/libstemmer_stem_UTF_8_german.c.obj
ninja: build stopped: subcommand failed.

I used your v2 and the attached reduced set of Dave and my changes.  I'll work on this next week if I find a bit of time, shouldn't be all that hard.  I thought I'd update you before then.  Also attached is my config script, I sent out my notes on a separate email.

I forgot to provide the MSVC compiler/linker versions for posterity, they are:
  cl (msvc 19.50.35718 "Microsoft (R) C/C++ Optimizing Compiler Version 19.50.35718 for ARM64")
  link 14.50.35718.0

best.

-greg


Attachments:

  [application/octet-stream] v20251123-0001-WIP-ARM64-MSVC-stdatomic.patch (3.7K, ../../[email protected]/2-v20251123-0001-WIP-ARM64-MSVC-stdatomic.patch)
  download | inline diff:
From 7e6f5a23e7aecb7170a97f092e61f7d590ef5e3b Mon Sep 17 00:00:00 2001
From: Greg Burd <[email protected]>
Date: Sun, 23 Nov 2025 07:58:47 -0500
Subject: [PATCH v20251123] WIP ARM64/MSVC stdatomic

---
 doc/src/sgml/installation.sgml |  2 +-
 meson.build                    | 15 ++++++++++++++-
 src/port/pg_crc32c_armv8.c     |  2 ++
 src/tools/msvc_gendef.pl       |  8 ++++----
 4 files changed, 21 insertions(+), 6 deletions(-)

diff --git a/doc/src/sgml/installation.sgml b/doc/src/sgml/installation.sgml
index fe8d73e1f8c..3f8d512a906 100644
--- a/doc/src/sgml/installation.sgml
+++ b/doc/src/sgml/installation.sgml
@@ -3967,7 +3967,7 @@ 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 ARM64 architectures on 64-bit Windows.
     </para>
     <para>
      Mixing 32- and 64-bit versions in the same build tree is not supported.
diff --git a/meson.build b/meson.build
index 1a2005e75c4..18637180ab1 100644
--- a/meson.build
+++ b/meson.build
@@ -2158,6 +2158,11 @@ endforeach
 
 
 if cc.get_id() == 'msvc'
+  # Add ARM64 architecture flag for Windows 11 ARM64 for correct intrensics
+  if host_machine.system() == 'windows' and host_machine.cpu_family() == 'aarch64'
+    add_project_arguments('/arch:armv9.4', language: ['c', 'cpp'])
+  endif
+
   cflags_warn += [
     # Warnings to disable:
     # from /W1:
@@ -2367,6 +2372,11 @@ if host_cpu == 'x86' or host_cpu == 'x86_64'
   else
 
     prog = '''
+#ifdef _MSC_VER
+#include <intrin.h>
+#else
+#include <arm_acle.h>
+#endif
 #include <nmmintrin.h>
 unsigned int crc;
 
@@ -2450,7 +2460,10 @@ int main(void)
 }
 '''
 
-  if cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd without -march=armv8-a+crc',
+  if cc.get_id() == 'msvc'
+    cdata.set('USE_ARMV8_CRC32C', 1)
+    have_optimized_crc = true
+  elif 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)
diff --git a/src/port/pg_crc32c_armv8.c b/src/port/pg_crc32c_armv8.c
index 5ba070bb99d..6a155ddde1e 100644
--- a/src/port/pg_crc32c_armv8.c
+++ b/src/port/pg_crc32c_armv8.c
@@ -14,7 +14,9 @@
  */
 #include "c.h"
 
+#ifndef _MSC_VER
 #include <arm_acle.h>
+#endif
 
 #include "port/pg_crc32c.h"
 
diff --git a/src/tools/msvc_gendef.pl b/src/tools/msvc_gendef.pl
index 868aad51b09..c92c94c4775 100644
--- a/src/tools/msvc_gendef.pl
+++ b/src/tools/msvc_gendef.pl
@@ -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;
 
-- 
2.52.0.windows.1



  [application/octet-stream] ConfigMSVC.ps1 (12.3K, ../../[email protected]/3-ConfigMSVC.ps1)
  download

^ permalink  raw  reply  [nested|flat] 42+ messages in thread

* Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ​barriers
@ 2025-11-23 15:55  Andres Freund <[email protected]>
  parent: Greg Burd <[email protected]>
  0 siblings, 2 replies; 42+ messages in thread

From: Andres Freund @ 2025-11-23 15:55 UTC (permalink / raw)
  To: Greg Burd <[email protected]>; +Cc: Thomas Munro <[email protected]>; Nathan Bossart <[email protected]>; Peter Eisentraut <[email protected]>; PostgreSQL Hackers <[email protected]>; Dave Cramer <[email protected]>

Hi,

On 2025-11-22 16:43:30 -0500, Greg Burd wrote:
> With the new MSVC compiler flag Andres mentioned (/arch:armv9.4) I only
> had to update the S_UNLOCK() macro, the compiler did the rest correctly
> AFAICT.

Just to be clear - the flag shouldn't be necessary for things to work
correctly. I was only using it to have godbolt inline the intrinsics, rather
than have them generate an out-of-line function call that I couldn't easily
inspect. I'm fairly sure that the out-of-line functions also have the relevant
barriers.


> @@ -2509,7 +2513,10 @@ int main(void)
>  }
>  '''
>  
> -  if cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd without -march=armv8-a+crc',
> +  if cc.get_id() == 'msvc'
> +    cdata.set('USE_ARMV8_CRC32C', 1)
> +    have_optimized_crc = true

Should have a comment explaining why we can do this unconditionally...


Greetings,

Andres Freund





^ permalink  raw  reply  [nested|flat] 42+ messages in thread

*  Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ​barriers
@ 2025-11-23 20:32  Thomas Munro <[email protected]>
  parent: Andres Freund <[email protected]>
  1 sibling, 1 reply; 42+ messages in thread

From: Thomas Munro @ 2025-11-23 20:32 UTC (permalink / raw)
  To: Andres Freund <[email protected]>; +Cc: Greg Burd <[email protected]>; Nathan Bossart <[email protected]>; Peter Eisentraut <[email protected]>; PostgreSQL Hackers <[email protected]>; Dave Cramer <[email protected]>

On Mon, Nov 24, 2025 at 4:55 AM Andres Freund <[email protected]> wrote:
> > -  if cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd without -march=armv8-a+crc',
> > +  if cc.get_id() == 'msvc'
> > +    cdata.set('USE_ARMV8_CRC32C', 1)
> > +    have_optimized_crc = true
>
> Should have a comment explaining why we can do this unconditionally...

I was wondering about that in light of your revelation that it must be
using /arch:armv8.0 by default.  If we only support Windows/ARM on
armv8.1 hardware (like Windows 11 itself), then I think that means
that we'd want /arch:armv8.1 here:

+  # Add ARM64 architecture flag for Windows 11 ARM64 for correct intrensics
+  if host_machine.system() == 'windows' and host_machine.cpu_family()
== 'aarch64'
+    add_project_arguments('/arch:armv9.4', language: ['c', 'cpp'])
+  endif

We can't impose our own random high ISA requirement like that, or some
machines will choke on illegal instructions.

I wonder if the same applies to Visual Studio on x86.  The OS now
requires x86-64-v2 (like RHEL9, and many other Linux distros except
Debian?), but Visual Studio might not know that... but then we might
say that's an issue for the EDB packaging crew to think about, not us.

In that case we might want to say "OK you choose the ARM version, but
we're not going to write the runtime test for CRC on armv8, we'll do a
compile-time test only, because it would be stupid to waste time
writing code for armv8.0".





^ permalink  raw  reply  [nested|flat] 42+ messages in thread

* Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ​barriers
@ 2025-11-23 20:41  Greg Burd <[email protected]>
  parent: Andres Freund <[email protected]>
  1 sibling, 0 replies; 42+ messages in thread

From: Greg Burd @ 2025-11-23 20:41 UTC (permalink / raw)
  To: Andres Freund <[email protected]>; +Cc: Thomas Munro <[email protected]>; Nathan Bossart <[email protected]>; Peter Eisentraut <[email protected]>; PostgreSQL Hackers <[email protected]>; Dave Cramer <[email protected]>


On Nov 23 2025, at 10:55 am, Andres Freund <[email protected]> wrote:

> Hi,
> 
> On 2025-11-22 16:43:30 -0500, Greg Burd wrote:
>> With the new MSVC compiler flag Andres mentioned (/arch:armv9.4) I only
>> had to update the S_UNLOCK() macro, the compiler did the rest correctly
>> AFAICT.
> 
> Just to be clear - the flag shouldn't be necessary for things to work
> correctly. I was only using it to have godbolt inline the intrinsics, rather
> than have them generate an out-of-line function call that I couldn't easily
> inspect. I'm fairly sure that the out-of-line functions also have the relevant
> barriers.

Well, I learned something new about MSVC (again) today.  Thanks Andres
for pointing that out.  I fiddled with godbolt a bit and indeed on ARM64
systems the only thing that flag (/arch:armv9.4) does is to replace the
out-of-line function call for the intrinsic with the inlined version of it.

Without:
        bl          _InterlockedCompareExchange

With:
        mov         w10,#2
        str         w8,[sp]
        mov         x9,sp
        casal       w8,w10,[x9]

Good to know, and yes it does seem that the ASM includes the correct
instruction sequence.

I think, except for the build issues, the one thing I can put my finger
on as a "fix" is the change from _ReadWriteBarrier() to _dmb(_ARM64_BARRIER_SY).

The docs say:
The _ReadWriteBarrier intrinsic limits the compiler optimizations that
can remove or reorder memory accesses across the point of the call.

Note that it says "compiler optimization" not "system memory barrier". 
So, this macro change:

 #define S_UNLOCK(lock)	\
-	do { _ReadWriteBarrier(); (*(lock)) = 0; } while (0)
+	do { __dmb(_ARM64_BARRIER_SY); (*(lock)) = 0; } while (0)
 
Makes more sense.  This change replaces a compiler-only barrier with a
full system memory barrier, fundamentally strengthening memory ordering
guarantees for spinlock release on ARM64.

When I remove the compiler flag from the patch and keep the S_UNLOCK()
change the tests pass.  I think we've found the critical fix.  I'll
update the patch set.

>> @@ -2509,7 +2513,10 @@ int main(void)
>>  }
>>  '''
>>  
>> -  if cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and
>> __crc32cd without -march=armv8-a+crc',
>> +  if cc.get_id() == 'msvc'
>> +    cdata.set('USE_ARMV8_CRC32C', 1)
>> +    have_optimized_crc = true
> 
> Should have a comment explaining why we can do this unconditionally...

Sure, the more I look at this the more I want to clean it up a bit more.

> Greetings,
> 
> Andres Freund

Thanks again for the helpful nudge Andres, best.

-greg





^ permalink  raw  reply  [nested|flat] 42+ messages in thread

* Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ​barriers
@ 2025-11-23 20:41  Greg Burd <[email protected]>
  parent: Thomas Munro <[email protected]>
  0 siblings, 1 reply; 42+ messages in thread

From: Greg Burd @ 2025-11-23 20:41 UTC (permalink / raw)
  To: Thomas Munro <[email protected]>; +Cc: Andres Freund <[email protected]>; Nathan Bossart <[email protected]>; Peter Eisentraut <[email protected]>; PostgreSQL Hackers <[email protected]>; Dave Cramer <[email protected]>


On Nov 23 2025, at 3:32 pm, Thomas Munro <[email protected]> wrote:

> On Mon, Nov 24, 2025 at 4:55 AM Andres Freund <[email protected]> wrote:
>> > -  if cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and
>> __crc32cd without -march=armv8-a+crc',
>> > +  if cc.get_id() == 'msvc'
>> > +    cdata.set('USE_ARMV8_CRC32C', 1)
>> > +    have_optimized_crc = true
>>  
>> Should have a comment explaining why we can do this unconditionally...
>  
> I was wondering about that in light of your revelation that it must be
> using /arch:armv8.0 by default.  If we only support Windows/ARM on
> armv8.1 hardware (like Windows 11 itself), then I think that means
> that we'd want /arch:armv8.1 here:
>  
> +  # Add ARM64 architecture flag for Windows 11 ARM64 for correct intrensics
> +  if host_machine.system() == 'windows' and host_machine.cpu_family()
> == 'aarch64'
> +    add_project_arguments('/arch:armv9.4', language: ['c', 'cpp'])
> +  endif

Hey Thomas,

Turns out that flag isn't required at all, the issue was the S_UNLOCK()
implementation's use of a compiler barrier not a CPU memory barrier.

> We can't impose our own random high ISA requirement like that, or some
> machines will choke on illegal instructions.

New incoming patch drops this entirely, so no need to worry about it.

> I wonder if the same applies to Visual Studio on x86.  The OS now
> requires x86-64-v2 (like RHEL9, and many other Linux distros except
> Debian?), but Visual Studio might not know that... but then we might
> say that's an issue for the EDB packaging crew to think about, not us.
>  
> In that case we might want to say "OK you choose the ARM version, but
> we're not going to write the runtime test for CRC on armv8, we'll do a
> compile-time test only, because it would be stupid to waste time
> writing code for armv8.0".

best.

-greg





^ permalink  raw  reply  [nested|flat] 42+ messages in thread

*  Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ​barriers
@ 2025-11-24 15:04  Greg Burd <[email protected]>
  parent: Greg Burd <[email protected]>
  0 siblings, 1 reply; 42+ messages in thread

From: Greg Burd @ 2025-11-24 15:04 UTC (permalink / raw)
  To: Thomas Munro <[email protected]>; Andres Freund <[email protected]>; Nathan Bossart <[email protected]>; Peter Eisentraut <[email protected]>; PostgreSQL Hackers <[email protected]>; +Cc: Dave Cramer <[email protected]>

Hello,

v3 attached is a more concise single patch that adds support for MSVC on Win11 ARM64.  The issues fixed are mostly related to config, build, docs, an implementation of spin_delay() and a change to S_UNLOCK() macro.  I've squished the work we did into a single commit and improved the commit message.  Thomas, I think in another thread you mentioned that some of what Dave added came from you, correct?  We should add you as another author if so, right?

best.

-greg


Attachments:

  [application/octet-stream] v3-0001-Enable-PostgreSQL-build-on-Windows-11-ARM64-with-.patch (9.4K, ../../[email protected]/2-v3-0001-Enable-PostgreSQL-build-on-Windows-11-ARM64-with-.patch)
  download | inline diff:
From 7a599424e8762567215d85f4063b3b6e8593ed93 Mon Sep 17 00:00:00 2001
From: Dave Cramer <[email protected]>
Date: Sun, 13 Jul 2025 06:33:17 -0400
Subject: [PATCH v3] Enable PostgreSQL build on Windows 11 ARM64 with MSVC

Add support for the ARM64 architecture on Windows 11 using MSVC compiler,
addressing build issues and implementing proper memory synchronization
semantics for this platform.

Changes:

1. Spinlock delay implementation (spin_delay.h)
   - Implement pg_spin_delay() for ARM64 MSVC using __isb(_ARM64_BARRIER_SY)
   - ISB (Instruction Synchronization Barrier) provides an effective delay
     hint for spin-wait loops on ARM64, flushing the instruction pipeline
     to reduce power consumption on high-core-count systems

2. CRC32C hardware acceleration (meson.build, pg_crc32c_armv8.c)
   - Detect CRC32C capability at build time for MSVC ARM64
   - Falls back to software implementation if hardware acceleration
     unavailable

3. Spinlock release memory barrier (s_lock.h)
   - Replace compiler barrier (_ReadWriteBarrier) with hardware barrier
     (__dmb(_ARM64_BARRIER_SY)) in S_UNLOCK macro for ARM64 MSVC
   - Compiler barriers are insufficient on ARM64's weak memory model;
     __dmb ensures all prior memory operations complete before the lock
     is released
   - Prevents memory reordering across cores, ensuring data visibility
     to threads acquiring the released lock
   - Critical for correctness in concurrent operations (e.g., WAL
     synchronization)

This patch brings ARM64 MSVC support to parity with existing GCC/Clang
implementations on the same architecture.

Author: Greg Burd <[email protected]>
Author: Dave Cramer <[email protected]>
Discussion: https://postgr.es/m/3c576ad7-d2da-4137-b791-5821da7cc370%40app.fastmail.com
Reference: https://learn.microsoft.com/en-us/cpp/intrinsics/arm64-intrinsics#BarrierRestrictions
---
 doc/src/sgml/installation.sgml |  2 +-
 meson.build                    | 81 ++++++++++++++++++++++++++--------
 src/include/storage/s_lock.h   | 23 ++++++++--
 src/port/pg_crc32c_armv8.c     |  6 +++
 src/tools/msvc_gendef.pl       |  8 ++--
 5 files changed, 93 insertions(+), 27 deletions(-)

diff --git a/doc/src/sgml/installation.sgml b/doc/src/sgml/installation.sgml
index fe8d73e1f8c..3f8d512a906 100644
--- a/doc/src/sgml/installation.sgml
+++ b/doc/src/sgml/installation.sgml
@@ -3967,7 +3967,7 @@ 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 ARM64 architectures on 64-bit Windows.
     </para>
     <para>
      Mixing 32- and 64-bit versions in the same build tree is not supported.
diff --git a/meson.build b/meson.build
index 6e7ddd74683..f71be89da97 100644
--- a/meson.build
+++ b/meson.build
@@ -2494,7 +2494,11 @@ int main(void)
 elif host_cpu == 'arm' or host_cpu == 'aarch64'
 
   prog = '''
+#ifdef _MSC_VER
+#include <intrin.h>
+#else
 #include <arm_acle.h>
+#endif
 unsigned int crc;
 
 int main(void)
@@ -2509,25 +2513,64 @@ int main(void)
 }
 '''
 
-  if 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)
-    have_optimized_crc = true
-  elif cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd with -march=armv8-a+crc+simd',
-      args: test_c_args + ['-march=armv8-a+crc+simd'])
-    # Use ARM CRC Extension, with runtime check
-    cflags_crc += '-march=armv8-a+crc+simd'
-    cdata.set('USE_ARMV8_CRC32C', false)
-    cdata.set('USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 1)
-    have_optimized_crc = true
-  elif cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd with -march=armv8-a+crc',
-      args: test_c_args + ['-march=armv8-a+crc'])
-    # Use ARM CRC Extension, with runtime check
-    cflags_crc += '-march=armv8-a+crc'
-    cdata.set('USE_ARMV8_CRC32C', false)
-    cdata.set('USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 1)
-    have_optimized_crc = true
+  if cc.get_id() == 'msvc'
+    # MSVC: Intrinsic availability check for ARM64
+    if host_machine.cpu_family() == 'aarch64'
+      # Test if CRC32C intrinsics are available in intrin.h
+      crc32c_test_msvc = '''
+        #include <intrin.h>
+        int main(void) {
+          uint32_t crc = 0;
+          uint8_t data = 0;
+          crc = __crc32cb(crc, data);
+          return 0;
+        }
+      '''
+      if cc.links(crc32c_test_msvc, name: '__crc32cb intrinsic available')
+        cdata.set('USE_ARMV8_CRC32C', 1)
+        have_optimized_crc = true
+        message('Using ARM64 CRC32C hardware acceleration (MSVC)')
+      else
+        message('CRC32C intrinsics not available on this MSVC ARM64 build')
+      endif
+    endif
+
+  elif host_machine.cpu_family() == 'aarch64'
+    # GCC/Clang paths: Try progressively with weaker requirements
+
+    # First: Try without any special flags (built-in support)
+    if cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd without -march=armv8-a+crc',
+        args: test_c_args)
+      cdata.set('USE_ARMV8_CRC32C', 1)
+      have_optimized_crc = true
+      message('Using ARM64 CRC32C without flags (built-in support)')
+
+    # Second: Try with -march=armv8-a+crc+simd (newer toolchains)
+    elif cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd with -march=armv8-a+crc+simd',
+        args: test_c_args + ['-march=armv8-a+crc+simd'])
+      cflags_crc += '-march=armv8-a+crc+simd'
+      cdata.set('USE_ARMV8_CRC32C', false)
+      cdata.set('USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 1)
+      have_optimized_crc = true
+      message('Using ARM64 CRC32C with runtime check (-march=armv8-a+crc+simd)')
+
+    # Third: Try with -march=armv8-a+crc (basic flag)
+    elif cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd with -march=armv8-a+crc',
+        args: test_c_args + ['-march=armv8-a+crc'])
+      cflags_crc += '-march=armv8-a+crc'
+      cdata.set('USE_ARMV8_CRC32C', false)
+      cdata.set('USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 1)
+      have_optimized_crc = true
+      message('Using ARM64 CRC32C with runtime check (-march=armv8-a+crc)')
+
+    else
+      message('CRC32C optimization not available for this ARM64 GCC/Clang build')
+    endif
+  endif
+
+  # Fallback: Use software CRC if no hardware acceleration found
+  if not have_optimized_crc
+    message('CRC32C: Using software implementation')
   endif
 
 elif host_cpu == 'loongarch64'
diff --git a/src/include/storage/s_lock.h b/src/include/storage/s_lock.h
index 7f8f566bd40..fd4ae992dce 100644
--- a/src/include/storage/s_lock.h
+++ b/src/include/storage/s_lock.h
@@ -602,15 +602,32 @@ 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 using Visual C++ on Win64, inline assembly is unavailable.
+ * Use architecture specific intrinsics.
  */
 #if defined(_WIN64)
+/*
+ * For Arm64, use __isb intrinsic. See aarch64 inline assembly definition for details.
+ */
+#ifdef _M_ARM64
+
+static __forceinline void
+spin_delay(void)
+{
+	 /* Reference: https://learn.microsoft.com/en-us/cpp/intrinsics/arm64-intrinsics#BarrierRestrictions */
+	__isb(_ARM64_BARRIER_SY);
+}
+#else
+/*
+ * For x64, use _mm_pause intrinsic instead of rep nop.
+ */
 static __forceinline void
 spin_delay(void)
 {
 	_mm_pause();
 }
+#endif
 #else
 static __forceinline void
 spin_delay(void)
@@ -624,7 +641,7 @@ spin_delay(void)
 #pragma intrinsic(_ReadWriteBarrier)
 
 #define S_UNLOCK(lock)	\
-	do { _ReadWriteBarrier(); (*(lock)) = 0; } while (0)
+	do { __dmb(_ARM64_BARRIER_SY); (*(lock)) = 0; } while (0)
 
 #endif
 
diff --git a/src/port/pg_crc32c_armv8.c b/src/port/pg_crc32c_armv8.c
index 5ba070bb99d..29a91dca62f 100644
--- a/src/port/pg_crc32c_armv8.c
+++ b/src/port/pg_crc32c_armv8.c
@@ -14,7 +14,13 @@
  */
 #include "c.h"
 
+#ifdef _MSC_VER
+ /* MSVC ARM64 intrinsics */
+#include <intrin.h>
+#else
+ /* GCC/Clang: Use ACLE intrinsics from arm_acle.h */
 #include <arm_acle.h>
+#endif
 
 #include "port/pg_crc32c.h"
 
diff --git a/src/tools/msvc_gendef.pl b/src/tools/msvc_gendef.pl
index 868aad51b09..c92c94c4775 100644
--- a/src/tools/msvc_gendef.pl
+++ b/src/tools/msvc_gendef.pl
@@ -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;
 
-- 
2.52.0.windows.1



^ permalink  raw  reply  [nested|flat] 42+ messages in thread

*  Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ​barriers
@ 2025-11-24 16:28  Greg Burd <[email protected]>
  parent: Greg Burd <[email protected]>
  0 siblings, 1 reply; 42+ messages in thread

From: Greg Burd @ 2025-11-24 16:28 UTC (permalink / raw)
  To: Thomas Munro <[email protected]>; Andres Freund <[email protected]>; Nathan Bossart <[email protected]>; Peter Eisentraut <[email protected]>; PostgreSQL Hackers <[email protected]>; +Cc: Dave Cramer <[email protected]>


On Mon, Nov 24, 2025, at 10:04 AM, Greg Burd wrote:
> Hello,
>
> v3 attached is a more concise single patch that adds support for MSVC 
> on Win11 ARM64.  The issues fixed are mostly related to config, build, 
> docs, an implementation of spin_delay() and a change to S_UNLOCK() 
> macro.  I've squished the work we did into a single commit and improved 
> the commit message.  Thomas, I think in another thread you mentioned 
> that some of what Dave added came from you, correct?  We should add you 
> as another author if so, right?
>
> best.
>
> -greg
>
> Attachments:
> * v3-0001-Enable-PostgreSQL-build-on-Windows-11-ARM64-with-.patch

I forgot to account for the non-ARM64 implementation of S_UNLOCK(), thanks CI for pointing that out.

-greg

Attachments:

  [application/octet-stream] v4-0001-Enable-PostgreSQL-build-on-Windows-11-ARM64-with-.patch (9.5K, ../../[email protected]/2-v4-0001-Enable-PostgreSQL-build-on-Windows-11-ARM64-with-.patch)
  download | inline diff:
From fda615dc6260f91cb53c1c84b438dbb8251eb09b Mon Sep 17 00:00:00 2001
From: Dave Cramer <[email protected]>
Date: Sun, 13 Jul 2025 06:33:17 -0400
Subject: [PATCH v4] Enable PostgreSQL build on Windows 11 ARM64 with MSVC

Add support for the ARM64 architecture on Windows 11 using MSVC compiler,
addressing build issues and implementing proper memory synchronization
semantics for this platform.

Changes:

1. Spinlock delay implementation (spin_delay.h)
   - Implement pg_spin_delay() for ARM64 MSVC using __isb(_ARM64_BARRIER_SY)
   - ISB (Instruction Synchronization Barrier) provides an effective delay
     hint for spin-wait loops on ARM64, flushing the instruction pipeline
     to reduce power consumption on high-core-count systems

2. CRC32C hardware acceleration (meson.build, pg_crc32c_armv8.c)
   - Detect CRC32C capability at build time for MSVC ARM64
   - Falls back to software implementation if hardware acceleration
     unavailable

3. Spinlock release memory barrier (s_lock.h)
   - Replace compiler barrier (_ReadWriteBarrier) with hardware barrier
     (__dmb(_ARM64_BARRIER_SY)) in S_UNLOCK macro for ARM64 MSVC
   - Compiler barriers are insufficient on ARM64's weak memory model;
     __dmb ensures all prior memory operations complete before the lock
     is released
   - Prevents memory reordering across cores, ensuring data visibility
     to threads acquiring the released lock
   - Critical for correctness in concurrent operations (e.g., WAL
     synchronization)

This patch brings ARM64 MSVC support to parity with existing GCC/Clang
implementations on the same architecture.

Author: Greg Burd <[email protected]>
Author: Dave Cramer <[email protected]>
Discussion: https://postgr.es/m/3c576ad7-d2da-4137-b791-5821da7cc370%40app.fastmail.com
Reference: https://learn.microsoft.com/en-us/cpp/intrinsics/arm64-intrinsics#BarrierRestrictions
---
 doc/src/sgml/installation.sgml |  2 +-
 meson.build                    | 81 ++++++++++++++++++++++++++--------
 src/include/storage/s_lock.h   | 29 ++++++++++--
 src/port/pg_crc32c_armv8.c     |  6 +++
 src/tools/msvc_gendef.pl       |  8 ++--
 5 files changed, 98 insertions(+), 28 deletions(-)

diff --git a/doc/src/sgml/installation.sgml b/doc/src/sgml/installation.sgml
index fe8d73e1f8c..3f8d512a906 100644
--- a/doc/src/sgml/installation.sgml
+++ b/doc/src/sgml/installation.sgml
@@ -3967,7 +3967,7 @@ 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 ARM64 architectures on 64-bit Windows.
     </para>
     <para>
      Mixing 32- and 64-bit versions in the same build tree is not supported.
diff --git a/meson.build b/meson.build
index 6e7ddd74683..f71be89da97 100644
--- a/meson.build
+++ b/meson.build
@@ -2494,7 +2494,11 @@ int main(void)
 elif host_cpu == 'arm' or host_cpu == 'aarch64'
 
   prog = '''
+#ifdef _MSC_VER
+#include <intrin.h>
+#else
 #include <arm_acle.h>
+#endif
 unsigned int crc;
 
 int main(void)
@@ -2509,25 +2513,64 @@ int main(void)
 }
 '''
 
-  if 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)
-    have_optimized_crc = true
-  elif cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd with -march=armv8-a+crc+simd',
-      args: test_c_args + ['-march=armv8-a+crc+simd'])
-    # Use ARM CRC Extension, with runtime check
-    cflags_crc += '-march=armv8-a+crc+simd'
-    cdata.set('USE_ARMV8_CRC32C', false)
-    cdata.set('USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 1)
-    have_optimized_crc = true
-  elif cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd with -march=armv8-a+crc',
-      args: test_c_args + ['-march=armv8-a+crc'])
-    # Use ARM CRC Extension, with runtime check
-    cflags_crc += '-march=armv8-a+crc'
-    cdata.set('USE_ARMV8_CRC32C', false)
-    cdata.set('USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 1)
-    have_optimized_crc = true
+  if cc.get_id() == 'msvc'
+    # MSVC: Intrinsic availability check for ARM64
+    if host_machine.cpu_family() == 'aarch64'
+      # Test if CRC32C intrinsics are available in intrin.h
+      crc32c_test_msvc = '''
+        #include <intrin.h>
+        int main(void) {
+          uint32_t crc = 0;
+          uint8_t data = 0;
+          crc = __crc32cb(crc, data);
+          return 0;
+        }
+      '''
+      if cc.links(crc32c_test_msvc, name: '__crc32cb intrinsic available')
+        cdata.set('USE_ARMV8_CRC32C', 1)
+        have_optimized_crc = true
+        message('Using ARM64 CRC32C hardware acceleration (MSVC)')
+      else
+        message('CRC32C intrinsics not available on this MSVC ARM64 build')
+      endif
+    endif
+
+  elif host_machine.cpu_family() == 'aarch64'
+    # GCC/Clang paths: Try progressively with weaker requirements
+
+    # First: Try without any special flags (built-in support)
+    if cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd without -march=armv8-a+crc',
+        args: test_c_args)
+      cdata.set('USE_ARMV8_CRC32C', 1)
+      have_optimized_crc = true
+      message('Using ARM64 CRC32C without flags (built-in support)')
+
+    # Second: Try with -march=armv8-a+crc+simd (newer toolchains)
+    elif cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd with -march=armv8-a+crc+simd',
+        args: test_c_args + ['-march=armv8-a+crc+simd'])
+      cflags_crc += '-march=armv8-a+crc+simd'
+      cdata.set('USE_ARMV8_CRC32C', false)
+      cdata.set('USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 1)
+      have_optimized_crc = true
+      message('Using ARM64 CRC32C with runtime check (-march=armv8-a+crc+simd)')
+
+    # Third: Try with -march=armv8-a+crc (basic flag)
+    elif cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd with -march=armv8-a+crc',
+        args: test_c_args + ['-march=armv8-a+crc'])
+      cflags_crc += '-march=armv8-a+crc'
+      cdata.set('USE_ARMV8_CRC32C', false)
+      cdata.set('USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 1)
+      have_optimized_crc = true
+      message('Using ARM64 CRC32C with runtime check (-march=armv8-a+crc)')
+
+    else
+      message('CRC32C optimization not available for this ARM64 GCC/Clang build')
+    endif
+  endif
+
+  # Fallback: Use software CRC if no hardware acceleration found
+  if not have_optimized_crc
+    message('CRC32C: Using software implementation')
   endif
 
 elif host_cpu == 'loongarch64'
diff --git a/src/include/storage/s_lock.h b/src/include/storage/s_lock.h
index 7f8f566bd40..029f2fa9729 100644
--- a/src/include/storage/s_lock.h
+++ b/src/include/storage/s_lock.h
@@ -602,15 +602,32 @@ 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 using Visual C++ on Win64, inline assembly is unavailable.
+ * Use architecture specific intrinsics.
  */
 #if defined(_WIN64)
+/*
+ * For Arm64, use __isb intrinsic. See aarch64 inline assembly definition for details.
+ */
+#ifdef _M_ARM64
+
+static __forceinline void
+spin_delay(void)
+{
+	 /* Reference: https://learn.microsoft.com/en-us/cpp/intrinsics/arm64-intrinsics#BarrierRestrictions */
+	__isb(_ARM64_BARRIER_SY);
+}
+#else
+/*
+ * For x64, use _mm_pause intrinsic instead of rep nop.
+ */
 static __forceinline void
 spin_delay(void)
 {
 	_mm_pause();
 }
+#endif
 #else
 static __forceinline void
 spin_delay(void)
@@ -623,9 +640,13 @@ spin_delay(void)
 #include <intrin.h>
 #pragma intrinsic(_ReadWriteBarrier)
 
-#define S_UNLOCK(lock)	\
+#ifdef _M_ARM64
+#define S_UNLOCK(lock) \
+	do { __dmb(_ARM64_BARRIER_SY); (*(lock)) = 0; } while (0)
+#else
+#define S_UNLOCK(lock) \
 	do { _ReadWriteBarrier(); (*(lock)) = 0; } while (0)
-
+#endif
 #endif
 
 
diff --git a/src/port/pg_crc32c_armv8.c b/src/port/pg_crc32c_armv8.c
index 5ba070bb99d..29a91dca62f 100644
--- a/src/port/pg_crc32c_armv8.c
+++ b/src/port/pg_crc32c_armv8.c
@@ -14,7 +14,13 @@
  */
 #include "c.h"
 
+#ifdef _MSC_VER
+ /* MSVC ARM64 intrinsics */
+#include <intrin.h>
+#else
+ /* GCC/Clang: Use ACLE intrinsics from arm_acle.h */
 #include <arm_acle.h>
+#endif
 
 #include "port/pg_crc32c.h"
 
diff --git a/src/tools/msvc_gendef.pl b/src/tools/msvc_gendef.pl
index 868aad51b09..c92c94c4775 100644
--- a/src/tools/msvc_gendef.pl
+++ b/src/tools/msvc_gendef.pl
@@ -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;
 
-- 
2.52.0.windows.1



^ permalink  raw  reply  [nested|flat] 42+ messages in thread

* Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ​barriers
@ 2025-11-24 23:20  Andres Freund <[email protected]>
  parent: Greg Burd <[email protected]>
  0 siblings, 1 reply; 42+ messages in thread

From: Andres Freund @ 2025-11-24 23:20 UTC (permalink / raw)
  To: Greg Burd <[email protected]>; +Cc: Thomas Munro <[email protected]>; Nathan Bossart <[email protected]>; Peter Eisentraut <[email protected]>; PostgreSQL Hackers <[email protected]>; Dave Cramer <[email protected]>

Hi,

On 2025-11-24 11:28:28 -0500, Greg Burd wrote:
> @@ -2509,25 +2513,64 @@ int main(void)
>  }
>  '''
>  
> -  if 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)
> -    have_optimized_crc = true
> -  elif cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd with -march=armv8-a+crc+simd',
> -      args: test_c_args + ['-march=armv8-a+crc+simd'])
> -    # Use ARM CRC Extension, with runtime check
> -    cflags_crc += '-march=armv8-a+crc+simd'
> -    cdata.set('USE_ARMV8_CRC32C', false)
> -    cdata.set('USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 1)
> -    have_optimized_crc = true
> -  elif cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd with -march=armv8-a+crc',
> -      args: test_c_args + ['-march=armv8-a+crc'])
> -    # Use ARM CRC Extension, with runtime check
> -    cflags_crc += '-march=armv8-a+crc'
> -    cdata.set('USE_ARMV8_CRC32C', false)
> -    cdata.set('USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 1)
> -    have_optimized_crc = true
> +  if cc.get_id() == 'msvc'
> +    # MSVC: Intrinsic availability check for ARM64
> +    if host_machine.cpu_family() == 'aarch64'
> +      # Test if CRC32C intrinsics are available in intrin.h
> +      crc32c_test_msvc = '''
> +        #include <intrin.h>
> +        int main(void) {
> +          uint32_t crc = 0;
> +          uint8_t data = 0;
> +          crc = __crc32cb(crc, data);
> +          return 0;
> +        }
> +      '''
> +      if cc.links(crc32c_test_msvc, name: '__crc32cb intrinsic available')
> +        cdata.set('USE_ARMV8_CRC32C', 1)
> +        have_optimized_crc = true
> +        message('Using ARM64 CRC32C hardware acceleration (MSVC)')
> +      else
> +        message('CRC32C intrinsics not available on this MSVC ARM64 build')
> +      endif

Does this:
a) need to be conditional at all, given that it's msvc specific, it seems we
   don't need to run a test?
b) why is the msvc block outside of the general aarch64 block but then has
another nested aarch64 test inside? That seems unnecessarily complicated and
requires reindenting unnecessarily much code?


> +/*
> + * For Arm64, use __isb intrinsic. See aarch64 inline assembly definition for details.
> + */
> +#ifdef _M_ARM64
> +
> +static __forceinline void
> +spin_delay(void)
> +{
> +	 /* Reference: https://learn.microsoft.com/en-us/cpp/intrinsics/arm64-intrinsics#BarrierRestrictions */
> +	__isb(_ARM64_BARRIER_SY);
> +}
> +#else
> +/*
> + * For x64, use _mm_pause intrinsic instead of rep nop.
> + */
>  static __forceinline void
>  spin_delay(void)
>  {
>  	_mm_pause();
>  }

This continues to use a barrier, with a reference to a list of barrier
semantics that really don't seem to make a whole lot of sense in the context
of spin_delay(). If we want to emit this kind of barrier for now it's ok with
me, but it should be documented as just being a fairly random choice, rather
than a link that doesn't explain anything.


> +#endif
>  #else
>  static __forceinline void
>  spin_delay(void)
> @@ -623,9 +640,13 @@ spin_delay(void)
>  #include <intrin.h>
>  #pragma intrinsic(_ReadWriteBarrier)
>  
> -#define S_UNLOCK(lock)	\
> +#ifdef _M_ARM64
> +#define S_UNLOCK(lock) \
> +	do { __dmb(_ARM64_BARRIER_SY); (*(lock)) = 0; } while (0)
> +#else

This doesn't seem like the right way to implement this - why not use
InterlockedExchange(lock, 0)? That will do the write with barrier semantics.

Greetings,

Andres Freund





^ permalink  raw  reply  [nested|flat] 42+ messages in thread

*  Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ​barriers
@ 2025-11-25 16:37  Greg Burd <[email protected]>
  parent: Andres Freund <[email protected]>
  0 siblings, 1 reply; 42+ messages in thread

From: Greg Burd @ 2025-11-25 16:37 UTC (permalink / raw)
  To: Andres Freund <[email protected]>; +Cc: Thomas Munro <[email protected]>; Nathan Bossart <[email protected]>; Peter Eisentraut <[email protected]>; PostgreSQL Hackers <[email protected]>; Dave Cramer <[email protected]>


On Mon, Nov 24, 2025, at 6:20 PM, Andres Freund wrote:
> Hi,

Thanks again for taking a look at the patch, hopefully I got it right this time. :)

> On 2025-11-24 11:28:28 -0500, Greg Burd wrote:
>> @@ -2509,25 +2513,64 @@ int main(void)
>>  }
>>  '''
>>  
>> -  if 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)
>> -    have_optimized_crc = true
>> -  elif cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd with -march=armv8-a+crc+simd',
>> -      args: test_c_args + ['-march=armv8-a+crc+simd'])
>> -    # Use ARM CRC Extension, with runtime check
>> -    cflags_crc += '-march=armv8-a+crc+simd'
>> -    cdata.set('USE_ARMV8_CRC32C', false)
>> -    cdata.set('USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 1)
>> -    have_optimized_crc = true
>> -  elif cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd with -march=armv8-a+crc',
>> -      args: test_c_args + ['-march=armv8-a+crc'])
>> -    # Use ARM CRC Extension, with runtime check
>> -    cflags_crc += '-march=armv8-a+crc'
>> -    cdata.set('USE_ARMV8_CRC32C', false)
>> -    cdata.set('USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 1)
>> -    have_optimized_crc = true
>> +  if cc.get_id() == 'msvc'
>> +    # MSVC: Intrinsic availability check for ARM64
>> +    if host_machine.cpu_family() == 'aarch64'
>> +      # Test if CRC32C intrinsics are available in intrin.h
>> +      crc32c_test_msvc = '''
>> +        #include <intrin.h>
>> +        int main(void) {
>> +          uint32_t crc = 0;
>> +          uint8_t data = 0;
>> +          crc = __crc32cb(crc, data);
>> +          return 0;
>> +        }
>> +      '''
>> +      if cc.links(crc32c_test_msvc, name: '__crc32cb intrinsic available')
>> +        cdata.set('USE_ARMV8_CRC32C', 1)
>> +        have_optimized_crc = true
>> +        message('Using ARM64 CRC32C hardware acceleration (MSVC)')
>> +      else
>> +        message('CRC32C intrinsics not available on this MSVC ARM64 build')
>> +      endif
>
> Does this:
> a) need to be conditional at all, given that it's msvc specific, it seems we
>    don't need to run a test?
> b) why is the msvc block outside of the general aarch64 block but then has
> another nested aarch64 test inside? That seems unnecessarily complicated and
> requires reindenting unnecessarily much code?

Yep, I rushed this.  Apologies.  I've re-worked it with your suggestions.

>> +/*
>> + * For Arm64, use __isb intrinsic. See aarch64 inline assembly definition for details.
>> + */
>> +#ifdef _M_ARM64
>> +
>> +static __forceinline void
>> +spin_delay(void)
>> +{
>> +	 /* Reference: https://learn.microsoft.com/en-us/cpp/intrinsics/arm64-intrinsics#BarrierRestrictions */
>> +	__isb(_ARM64_BARRIER_SY);
>> +}
>> +#else
>> +/*
>> + * For x64, use _mm_pause intrinsic instead of rep nop.
>> + */
>>  static __forceinline void
>>  spin_delay(void)
>>  {
>>  	_mm_pause();
>>  }
>
> This continues to use a barrier, with a reference to a list of barrier
> semantics that really don't seem to make a whole lot of sense in the context
> of spin_delay(). If we want to emit this kind of barrier for now it's ok with
> me, but it should be documented as just being a fairly random choice, rather
> than a link that doesn't explain anything.

I did more digging and found that you were right about the use of ISB for spin_delay().  I think I was misled by earlier code in that file (lines 277-286) where there is an implementation of spin_delay() that uses ISB, I ran with that not doing enough research myself.  So I did more digging and found an article on this [1] and it seems that YIELD should be used, not ISB.  I checked into how others implement this feature, Java [2][3] uses YIELD, Linux [4][5] uses YIELD in cpu_relax() called by __delay().

>> +#endif
>>  #else
>>  static __forceinline void
>>  spin_delay(void)
>> @@ -623,9 +640,13 @@ spin_delay(void)
>>  #include <intrin.h>
>>  #pragma intrinsic(_ReadWriteBarrier)
>>  
>> -#define S_UNLOCK(lock)	\
>> +#ifdef _M_ARM64
>> +#define S_UNLOCK(lock) \
>> +	do { __dmb(_ARM64_BARRIER_SY); (*(lock)) = 0; } while (0)
>> +#else
>
> This doesn't seem like the right way to implement this - why not use
> InterlockedExchange(lock, 0)? That will do the write with barrier semantics.

Great idea, done.  Seems to work too.

> Greetings,
>
> Andres Freund

Given what I learned about YIELD vs ISB for spin delay it seems like a reasonable idea to submit a new patch for the non-MSVC path and switch it to YIELD, what do you think?

v5 attached, best.

-greg

[1] https://developer.arm.com/community/arm-community-blogs/b/architectures-and-processors-blog/posts/mu... 
[2] https://cr.openjdk.org/~dchuyko/8186670/yield/spinwait.html
[3] https://mail.openjdk.org/pipermail/aarch64-port-dev/2017-August/004880.html
[4] https://github.com/torvalds/linux/blob/ac3fd01e4c1efce8f2c054cdeb2ddd2fc0fb150d/arch/arm64/include/a...
[5] https://github.com/torvalds/linux/commit/f511e079177a9b97175a9a3b0ee2374d55682403

Attachments:

  [application/octet-stream] v5-0001-Enable-build-on-Windows-11-ARM64-with-MSVC.patch (9.4K, ../../[email protected]/2-v5-0001-Enable-build-on-Windows-11-ARM64-with-MSVC.patch)
  download | inline diff:
From e249d750a115b8fcfc3c1e16cbeae9b679546c49 Mon Sep 17 00:00:00 2001
From: Dave Cramer <[email protected]>
Date: Sun, 13 Jul 2025 06:33:17 -0400
Subject: [PATCH v5] Enable build on Windows 11 ARM64 with MSVC

Add support for the ARM64 architecture on Windows 11 using MSVC compiler,
addressing build issues and implementing proper memory synchronization
semantics for this platform.

Implement spin_delay() with __yield() intrinsic that emits the YIELD
instruction.  Use MSVC CRC32 implementation on ARM64.  Changes the
S_UNLOCK() macro to use the InterlockedExchange() intrinsic.

Author: Greg Burd <[email protected]>
Author: Dave Cramer <[email protected]>
Discussion: https://postgr.es/m/3c576ad7-d2da-4137-b791-5821da7cc370%40app.fastmail.com
---
 doc/src/sgml/installation.sgml |  2 +-
 meson.build                    | 69 ++++++++++++++++++++++++----------
 src/include/storage/s_lock.h   | 61 ++++++++++++++++++++++++------
 src/port/pg_crc32c_armv8.c     |  6 +++
 src/tools/msvc_gendef.pl       |  8 ++--
 5 files changed, 111 insertions(+), 35 deletions(-)

diff --git a/doc/src/sgml/installation.sgml b/doc/src/sgml/installation.sgml
index fe8d73e1f8c..3f8d512a906 100644
--- a/doc/src/sgml/installation.sgml
+++ b/doc/src/sgml/installation.sgml
@@ -3967,7 +3967,7 @@ 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 ARM64 architectures on 64-bit Windows.
     </para>
     <para>
      Mixing 32- and 64-bit versions in the same build tree is not supported.
diff --git a/meson.build b/meson.build
index 6e7ddd74683..80622a05310 100644
--- a/meson.build
+++ b/meson.build
@@ -2494,7 +2494,11 @@ int main(void)
 elif host_cpu == 'arm' or host_cpu == 'aarch64'
 
   prog = '''
+#ifdef _MSC_VER
+#include <intrin.h>
+#else
 #include <arm_acle.h>
+#endif
 unsigned int crc;
 
 int main(void)
@@ -2509,25 +2513,52 @@ int main(void)
 }
 '''
 
-  if 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)
-    have_optimized_crc = true
-  elif cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd with -march=armv8-a+crc+simd',
-      args: test_c_args + ['-march=armv8-a+crc+simd'])
-    # Use ARM CRC Extension, with runtime check
-    cflags_crc += '-march=armv8-a+crc+simd'
-    cdata.set('USE_ARMV8_CRC32C', false)
-    cdata.set('USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 1)
-    have_optimized_crc = true
-  elif cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd with -march=armv8-a+crc',
-      args: test_c_args + ['-march=armv8-a+crc'])
-    # Use ARM CRC Extension, with runtime check
-    cflags_crc += '-march=armv8-a+crc'
-    cdata.set('USE_ARMV8_CRC32C', false)
-    cdata.set('USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 1)
-    have_optimized_crc = true
+  if cc.get_id() == 'msvc'
+    # MSVC ARM64: Intrinsics are part of intrin.h, always available.
+    # No runtime test needed - assume availability on ARM64 targets.
+    if host_machine.cpu_family() == 'aarch64'
+      cdata.set('USE_ARMV8_CRC32C', 1)
+      have_optimized_crc = true
+      message('Using ARM64 CRC32C hardware acceleration (MSVC)')
+    endif
+
+  elif host_machine.cpu_family() == 'aarch64'
+    # GCC/Clang ARM64: Test with progressive flag requirements to maximize
+    # compatibility across toolchain versions.
+
+    # First: Try without any special flags (built-in support)
+    if cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd without -march=armv8-a+crc',
+        args: test_c_args)
+      cdata.set('USE_ARMV8_CRC32C', 1)
+      have_optimized_crc = true
+      message('Using ARM64 CRC32C without flags (built-in support)')
+
+    # Second: Try with -march=armv8-a+crc+simd (newer toolchains)
+    elif cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd with -march=armv8-a+crc+simd',
+        args: test_c_args + ['-march=armv8-a+crc+simd'])
+      cflags_crc += '-march=armv8-a+crc+simd'
+      cdata.set('USE_ARMV8_CRC32C', false)
+      cdata.set('USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 1)
+      have_optimized_crc = true
+      message('Using ARM64 CRC32C with runtime check (-march=armv8-a+crc+simd)')
+
+    # Third: Try with -march=armv8-a+crc (basic flag)
+    elif cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd with -march=armv8-a+crc',
+        args: test_c_args + ['-march=armv8-a+crc'])
+      cflags_crc += '-march=armv8-a+crc'
+      cdata.set('USE_ARMV8_CRC32C', false)
+      cdata.set('USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 1)
+      have_optimized_crc = true
+      message('Using ARM64 CRC32C with runtime check (-march=armv8-a+crc)')
+
+    else
+      message('CRC32C optimization not available for this ARM64 GCC/Clang build')
+    endif
+  endif
+
+  # Fallback: Use software CRC if no hardware acceleration found
+  if not have_optimized_crc
+    message('CRC32C: Using software implementation')
   endif
 
 elif host_cpu == 'loongarch64'
diff --git a/src/include/storage/s_lock.h b/src/include/storage/s_lock.h
index 7f8f566bd40..6d073787837 100644
--- a/src/include/storage/s_lock.h
+++ b/src/include/storage/s_lock.h
@@ -594,7 +594,8 @@ tas(volatile slock_t *lock)
 
 #if !defined(HAS_TEST_AND_SET)	/* We didn't trigger above, let's try here */
 
-#ifdef _MSC_VER
+/* When compiling for Microsoft Windows using MSVC */
+#if defined(_MSC_VER)
 typedef LONG slock_t;
 
 #define HAS_TEST_AND_SET
@@ -602,34 +603,72 @@ 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.
+/*
+ * _InterlockedExchange() generates a full memory barrier (or release
+ * semantics that ensures all prior memory operations are visible to
+ * other cores before the lock is released.
+ */
+#define S_UNLOCK(lock) (InterlockedExchange(lock, 0))
+
+#if defined(_WIN64) /* Microsoft Windows x64 */
+
+#if defined(_M_ARM64) /* aarch64 */
+
+/*
+ * Use __yield() intrinsic for ARM64. This emits the YIELD instruction,
+ * which is the ARM-recommended hint for spinlock delays. Unlike ISB
+ * (Instruction Synchronization Barrier), YIELD is explicitly designed to
+ * indicate spin-wait loops, reducing power and allowing thread scheduling.
+ *
+ * XXX: GCC/Clang emit the ISB instruction and there is a comment about
+ * efficiency on high core-count systems.  It's unclear if the pipeline
+ * flush triggered by ISB is more efficient than YIELD or not.
+ *
+ * Reference: https://learn.microsoft.com/en-us/cpp/intrinsics/arm64-intrinsics
+ */
+static __forceinline void
+spin_delay(void)
+{
+	__yield();
+}
+
+#elif defined(_M_X64) /* x86-64 */
+
+/*
+ * Use _mm_pause() intrinsic for x86-64. This emits the PAUSE instruction,
+ * which improves performance in spin-wait loops by preventing pipeline flush
+ * on Hyper-Threading systems.
  */
-#if defined(_WIN64)
 static __forceinline void
 spin_delay(void)
 {
 	_mm_pause();
 }
-#else
+
+#endif /* defined(_M_ARM64|_M_X64) */
+
+#else /* !defined(_WIN64) */
+
+#ifdef _M_IX86 /* x86-specific */
+
+/* Use no-op for MSVC 32bit x86 */
 static __forceinline void
 spin_delay(void)
 {
 	/* See comment for gcc code. Same code, MASM syntax */
 	__asm rep nop;
 }
-#endif
 
 #include <intrin.h>
 #pragma intrinsic(_ReadWriteBarrier)
 
-#define S_UNLOCK(lock)	\
+#define S_UNLOCK(lock) \
 	do { _ReadWriteBarrier(); (*(lock)) = 0; } while (0)
 
-#endif
-
-
-#endif	/* !defined(HAS_TEST_AND_SET) */
+#endif /* defined(_M_IX86) */
+#endif /* defined(_WIN64) */
+#endif /* defined(_MSC_VER) */
+#endif /* !defined(HAS_TEST_AND_SET) */
 
 
 /* Blow up if we didn't have any way to do spinlocks */
diff --git a/src/port/pg_crc32c_armv8.c b/src/port/pg_crc32c_armv8.c
index 5ba070bb99d..29a91dca62f 100644
--- a/src/port/pg_crc32c_armv8.c
+++ b/src/port/pg_crc32c_armv8.c
@@ -14,7 +14,13 @@
  */
 #include "c.h"
 
+#ifdef _MSC_VER
+ /* MSVC ARM64 intrinsics */
+#include <intrin.h>
+#else
+ /* GCC/Clang: Use ACLE intrinsics from arm_acle.h */
 #include <arm_acle.h>
+#endif
 
 #include "port/pg_crc32c.h"
 
diff --git a/src/tools/msvc_gendef.pl b/src/tools/msvc_gendef.pl
index 868aad51b09..c92c94c4775 100644
--- a/src/tools/msvc_gendef.pl
+++ b/src/tools/msvc_gendef.pl
@@ -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;
 
-- 
2.52.0.windows.1



^ permalink  raw  reply  [nested|flat] 42+ messages in thread

*  Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ​barriers
@ 2025-12-10 16:31  Greg Burd <[email protected]>
  parent: Greg Burd <[email protected]>
  0 siblings, 1 reply; 42+ messages in thread

From: Greg Burd @ 2025-12-10 16:31 UTC (permalink / raw)
  To: PostgreSQL Hackers <[email protected]>; +Cc: Thomas Munro <[email protected]>; Nathan Bossart <[email protected]>; Peter Eisentraut <[email protected]>; Dave Cramer <[email protected]>; Andres Freund <[email protected]>

Hello.

Rebased with only minor changes to meson.build this patch is ready for review/commit as it is passing tests on my aarch64 Win11 MSVC system.  Also note that this system I'm testing on is ready to become a member of the buildfarm (application submitted) and monitor this combo in perpetuity.

FWIW, Dave's bug report to Microsoft [1] seems to be a duplicate of [2] and the duplicate is about to be auto-closed.

best.

-greg

[1] https://developercommunity.visualstudio.com/t/MSVCs-_InterlockedCompareExchange-doe/11004239
[2] https://developercommunity.visualstudio.com/t/MSVC-compiler-optimization-in-PostgreSQL/10982137

Attachments:

  [application/octet-stream] v6-0001-Enable-build-on-Windows-11-ARM64-with-MSVC.patch (9.2K, ../../[email protected]/2-v6-0001-Enable-build-on-Windows-11-ARM64-with-MSVC.patch)
  download | inline diff:
From 595c110b3c5ff9e6df8c862131673339d88b4552 Mon Sep 17 00:00:00 2001
From: Dave Cramer <[email protected]>
Date: Sun, 13 Jul 2025 06:33:17 -0400
Subject: [PATCH v6] Enable build on Windows 11 ARM64 with MSVC

Add support for the ARM64 architecture on Windows 11 using MSVC compiler,
addressing build issues and implementing proper memory synchronization
semantics for this platform.

Implement spin_delay() with __yield() intrinsic that emits the YIELD
instruction.  Use MSVC CRC32 implementation on ARM64.  Changes the
S_UNLOCK() macro to use the InterlockedExchange() intrinsic.

Author: Greg Burd <[email protected]>
Author: Dave Cramer <[email protected]>
Discussion: https://postgr.es/m/3c576ad7-d2da-4137-b791-5821da7cc370%40app.fastmail.com
---
 doc/src/sgml/installation.sgml |  2 +-
 meson.build                    | 64 ++++++++++++++++++++++++----------
 src/include/storage/s_lock.h   | 61 ++++++++++++++++++++++++++------
 src/port/pg_crc32c_armv8.c     |  6 ++++
 src/tools/msvc_gendef.pl       |  8 ++---
 5 files changed, 106 insertions(+), 35 deletions(-)

diff --git a/doc/src/sgml/installation.sgml b/doc/src/sgml/installation.sgml
index fe8d73e1f8c..3f8d512a906 100644
--- a/doc/src/sgml/installation.sgml
+++ b/doc/src/sgml/installation.sgml
@@ -3967,7 +3967,7 @@ 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 ARM64 architectures on 64-bit Windows.
     </para>
     <para>
      Mixing 32- and 64-bit versions in the same build tree is not supported.
diff --git a/meson.build b/meson.build
index 718150e3ac0..1304478b33b 100644
--- a/meson.build
+++ b/meson.build
@@ -2512,25 +2512,51 @@ int main(void)
 }
 '''
 
-  if 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)
-    have_optimized_crc = true
-  elif cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd with -march=armv8-a+crc+simd',
-      args: test_c_args + ['-march=armv8-a+crc+simd'])
-    # Use ARM CRC Extension, with runtime check
-    cflags_crc += '-march=armv8-a+crc+simd'
-    cdata.set('USE_ARMV8_CRC32C', false)
-    cdata.set('USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 1)
-    have_optimized_crc = true
-  elif cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd with -march=armv8-a+crc',
-      args: test_c_args + ['-march=armv8-a+crc'])
-    # Use ARM CRC Extension, with runtime check
-    cflags_crc += '-march=armv8-a+crc'
-    cdata.set('USE_ARMV8_CRC32C', false)
-    cdata.set('USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 1)
-    have_optimized_crc = true
+  if host_machine.cpu_family() == 'aarch64'
+    # MSVC ARM64: Intrinsics are part of intrin.h, always available.
+    # No runtime test needed - assume availability on ARM64 targets.
+    if cc.get_id() == 'msvc'
+      cdata.set('USE_ARMV8_CRC32C', 1)
+      have_optimized_crc = true
+      message('Using ARM64 CRC32C hardware acceleration (MSVC)')
+    else
+      # GCC/Clang ARM64: Test with progressive flag requirements to maximize
+      # compatibility across toolchain versions.
+
+      # First: Try without any special flags (built-in support)
+      if cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd without -march=armv8-a+crc',
+          args: test_c_args)
+        cdata.set('USE_ARMV8_CRC32C', 1)
+        have_optimized_crc = true
+        message('Using ARM64 CRC32C without flags (built-in support)')
+
+      # Second: Try with -march=armv8-a+crc+simd (newer toolchains)
+      elif cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd with -march=armv8-a+crc+simd',
+          args: test_c_args + ['-march=armv8-a+crc+simd'])
+        cflags_crc += '-march=armv8-a+crc+simd'
+        cdata.set('USE_ARMV8_CRC32C', false)
+        cdata.set('USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 1)
+        have_optimized_crc = true
+        message('Using ARM64 CRC32C with runtime check (-march=armv8-a+crc+simd)')
+
+      # Third: Try with -march=armv8-a+crc (basic flag)
+      elif cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd with -march=armv8-a+crc',
+          args: test_c_args + ['-march=armv8-a+crc'])
+        cflags_crc += '-march=armv8-a+crc'
+        cdata.set('USE_ARMV8_CRC32C', false)
+        cdata.set('USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 1)
+        have_optimized_crc = true
+        message('Using ARM64 CRC32C with runtime check (-march=armv8-a+crc)')
+
+      else
+        message('CRC32C optimization not available for this ARM64 GCC/Clang build')
+      endif
+    endif
+  endif
+
+  # Fallback: Use software CRC if no hardware acceleration found
+  if not have_optimized_crc
+    message('CRC32C: Using software implementation')
   endif
 
 elif host_cpu == 'loongarch64'
diff --git a/src/include/storage/s_lock.h b/src/include/storage/s_lock.h
index 7f8f566bd40..6d073787837 100644
--- a/src/include/storage/s_lock.h
+++ b/src/include/storage/s_lock.h
@@ -594,7 +594,8 @@ tas(volatile slock_t *lock)
 
 #if !defined(HAS_TEST_AND_SET)	/* We didn't trigger above, let's try here */
 
-#ifdef _MSC_VER
+/* When compiling for Microsoft Windows using MSVC */
+#if defined(_MSC_VER)
 typedef LONG slock_t;
 
 #define HAS_TEST_AND_SET
@@ -602,34 +603,72 @@ 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.
+/*
+ * _InterlockedExchange() generates a full memory barrier (or release
+ * semantics that ensures all prior memory operations are visible to
+ * other cores before the lock is released.
+ */
+#define S_UNLOCK(lock) (InterlockedExchange(lock, 0))
+
+#if defined(_WIN64) /* Microsoft Windows x64 */
+
+#if defined(_M_ARM64) /* aarch64 */
+
+/*
+ * Use __yield() intrinsic for ARM64. This emits the YIELD instruction,
+ * which is the ARM-recommended hint for spinlock delays. Unlike ISB
+ * (Instruction Synchronization Barrier), YIELD is explicitly designed to
+ * indicate spin-wait loops, reducing power and allowing thread scheduling.
+ *
+ * XXX: GCC/Clang emit the ISB instruction and there is a comment about
+ * efficiency on high core-count systems.  It's unclear if the pipeline
+ * flush triggered by ISB is more efficient than YIELD or not.
+ *
+ * Reference: https://learn.microsoft.com/en-us/cpp/intrinsics/arm64-intrinsics
+ */
+static __forceinline void
+spin_delay(void)
+{
+	__yield();
+}
+
+#elif defined(_M_X64) /* x86-64 */
+
+/*
+ * Use _mm_pause() intrinsic for x86-64. This emits the PAUSE instruction,
+ * which improves performance in spin-wait loops by preventing pipeline flush
+ * on Hyper-Threading systems.
  */
-#if defined(_WIN64)
 static __forceinline void
 spin_delay(void)
 {
 	_mm_pause();
 }
-#else
+
+#endif /* defined(_M_ARM64|_M_X64) */
+
+#else /* !defined(_WIN64) */
+
+#ifdef _M_IX86 /* x86-specific */
+
+/* Use no-op for MSVC 32bit x86 */
 static __forceinline void
 spin_delay(void)
 {
 	/* See comment for gcc code. Same code, MASM syntax */
 	__asm rep nop;
 }
-#endif
 
 #include <intrin.h>
 #pragma intrinsic(_ReadWriteBarrier)
 
-#define S_UNLOCK(lock)	\
+#define S_UNLOCK(lock) \
 	do { _ReadWriteBarrier(); (*(lock)) = 0; } while (0)
 
-#endif
-
-
-#endif	/* !defined(HAS_TEST_AND_SET) */
+#endif /* defined(_M_IX86) */
+#endif /* defined(_WIN64) */
+#endif /* defined(_MSC_VER) */
+#endif /* !defined(HAS_TEST_AND_SET) */
 
 
 /* Blow up if we didn't have any way to do spinlocks */
diff --git a/src/port/pg_crc32c_armv8.c b/src/port/pg_crc32c_armv8.c
index 5ba070bb99d..29a91dca62f 100644
--- a/src/port/pg_crc32c_armv8.c
+++ b/src/port/pg_crc32c_armv8.c
@@ -14,7 +14,13 @@
  */
 #include "c.h"
 
+#ifdef _MSC_VER
+ /* MSVC ARM64 intrinsics */
+#include <intrin.h>
+#else
+ /* GCC/Clang: Use ACLE intrinsics from arm_acle.h */
 #include <arm_acle.h>
+#endif
 
 #include "port/pg_crc32c.h"
 
diff --git a/src/tools/msvc_gendef.pl b/src/tools/msvc_gendef.pl
index 868aad51b09..c92c94c4775 100644
--- a/src/tools/msvc_gendef.pl
+++ b/src/tools/msvc_gendef.pl
@@ -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;
 
-- 
2.52.0.windows.1



^ permalink  raw  reply  [nested|flat] 42+ messages in thread

*  Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ​barriers
@ 2025-12-10 21:31  Thomas Munro <[email protected]>
  parent: Greg Burd <[email protected]>
  0 siblings, 1 reply; 42+ messages in thread

From: Thomas Munro @ 2025-12-10 21:31 UTC (permalink / raw)
  To: Greg Burd <[email protected]>; +Cc: PostgreSQL Hackers <[email protected]>; Nathan Bossart <[email protected]>; Peter Eisentraut <[email protected]>; Dave Cramer <[email protected]>; Andres Freund <[email protected]>

On Thu, Dec 11, 2025 at 5:32 AM Greg Burd <[email protected]> wrote:
> Rebased with only minor changes to meson.build this patch is ready for review/commit as it is passing tests on my aarch64 Win11 MSVC system.  Also note that this system I'm testing on is ready to become a member of the buildfarm (application submitted) and monitor this combo in perpetuity.

-  if cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and
__crc32cd without -march=armv8-a+crc',
...
+  if host_machine.cpu_family() == 'aarch64'

I think this new nesting of the CRC32 feature tests breaks the test on
"armv7" distros (in our build farm, that's a bunch of RPis running
Debian/Raspbian, but at least FreeBSD and NetBSD also support
"armv7").  Any ARM chip made since around 2011 is really an ARMv8+
chip running Aarch32 code and can thus reach the ARMv8 instructions.
For example "grison" says:

checking build system type... (cached) armv7l-unknown-linux-gnueabihf
...
checking which CRC-32C implementation to use... ARMv8 CRC instructions
with runtime check

-#define S_UNLOCK(lock)    \
+#define S_UNLOCK(lock) \

Bogus whitespace change.





^ permalink  raw  reply  [nested|flat] 42+ messages in thread

*  Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ​barriers
@ 2025-12-11 16:16  Greg Burd <[email protected]>
  parent: Thomas Munro <[email protected]>
  0 siblings, 1 reply; 42+ messages in thread

From: Greg Burd @ 2025-12-11 16:16 UTC (permalink / raw)
  To: Thomas Munro <[email protected]>; +Cc: PostgreSQL Hackers <[email protected]>; Nathan Bossart <[email protected]>; Peter Eisentraut <[email protected]>; Dave Cramer <[email protected]>; Andres Freund <[email protected]>


On Wed, Dec 10, 2025, at 4:31 PM, Thomas Munro wrote:
> On Thu, Dec 11, 2025 at 5:32 AM Greg Burd <[email protected]> wrote:
>> Rebased with only minor changes to meson.build this patch is ready for review/commit as it is passing tests on my aarch64 Win11 MSVC system.  Also note that this system I'm testing on is ready to become a member of the buildfarm (application submitted) and monitor this combo in perpetuity.
>
> -  if cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and
> __crc32cd without -march=armv8-a+crc',
> ...
> +  if host_machine.cpu_family() == 'aarch64'

Thanks for taking the time to review.

> I think this new nesting of the CRC32 feature tests breaks the test on
> "armv7" distros (in our build farm, that's a bunch of RPis running
> Debian/Raspbian, but at least FreeBSD and NetBSD also support
> "armv7").  Any ARM chip made since around 2011 is really an ARMv8+
> chip running Aarch32 code and can thus reach the ARMv8 instructions.
> For example "grison" says:
>
> checking build system type... (cached) armv7l-unknown-linux-gnueabihf
> ...
> checking which CRC-32C implementation to use... ARMv8 CRC instructions
> with runtime check

That was rather silly of me to overlook, apologies.  I went back to the code that was there before written by Andres I believe and simply added a test for this one special case.  That reduces code churn and simplifies the logic while preserving the earlier behavior.

As I was re-reading I decided to review the YEILD vs ISB question for this platform combo again in light of a82a5ee [1].  What I found was a wealth of information and work on the topic and the thread mentioned MariaDB so I did some digging (because, why not?).  Go-lang[2] uses ISB but a comment there led me on to another resource, a blog post from ARM on the topic of spin locks for ARM64[3].  I found that like Go-lang, Rust[4] uses ISB (and if you read only one thread on the topic this is the one to dig into).  The developers on the thread wrote a number of benchmarks and tested a variety of approaches landing on "ISB SY" on aarch64.  I found that MySQL[5][6] also went with ISB, as has Cloudera[7], Impala[8], Aerospike[9], and WebAssembly[10] at which point I stopped looking around.  There were other resources out there for understanding ARM and relaxed memory models such as [11], [12], and [13] for those that care to learn.

All of this is to say that I swapped out the YEILD for "ISB SY" for the ARM64/MSVC because that seems to make the most sense from the evidence I found and for consistency in our code.

> -#define S_UNLOCK(lock)    \
> +#define S_UNLOCK(lock) \
>
> Bogus whitespace change.

Fixed, thanks.

best.

-greg

[1] https://postgr.es/m/[email protected]
[2] https://github.com/golang/go/issues/69232
[3] https://community.arm.com/arm-community-blogs/b/architectures-and-processors-blog/posts/multi-thread...
[4] https://github.com/rust-lang/rust/commit/c064b6560b7ce0adeb9bbf5d7dcf12b1acb0c807
[5] https://bugs.mysql.com/bug.php?id=100664
[6] https://github.com/mysql/mysql-server/pull/305/files
[7] https://gerrit.cloudera.org/#/c/19865/
[8] https://issues.apache.org/jira/browse/IMPALA-12122
[9] https://github.com/aerospike/aerospike-common/pull/17
[10] https://github.com/WebAssembly/threads/issues/15
[11] https://developer.arm.com/documentation/genc007826/latest "Barrier Litmus Tests and Cookbook"
[12] http://www.rdrop.com/users/paulmck/scalability/paper/whymb.2010.07.23a.pdf - Memory Barriers: a Hardware View for Software Hackers
[13] https://randomascii.wordpress.com/2020/11/29/arm-and-lock-free-programming/


Attachments:

  [application/octet-stream] v7-0001-Enable-the-Microsoft-Windows-ARM64-MSVC-platform.patch (7.4K, ../../[email protected]/2-v7-0001-Enable-the-Microsoft-Windows-ARM64-MSVC-platform.patch)
  download | inline diff:
From 85dc82d7ad53c1bd19725883125f5f19a506973e Mon Sep 17 00:00:00 2001
From: Dave Cramer <[email protected]>
Date: Sun, 13 Jul 2025 06:33:17 -0400
Subject: [PATCH v7] Enable the Microsoft Windows ARM64/MSVC platform

Add support for the ARM64 architecture on Windows 11 using MSVC compiler
addressing build issues and implementing proper memory synchronization
semantics for this platform.

* Implement spin_delay() with __isb(_ARM64_BARRIER_SY) intrinsic to emit
  the "ISB SY" instruction which matches the GCC/Clang approach to
  spinloop delay and emperical evidence that it out-scales the YIELD
  instruction in practice.

* Unconditionally choose to use the MSVC supplied intrinsic
  for CRC32 on ARM64.

* Implement the S_UNLOCK() macro using the InterlockedExchange()
  intrinsic.

Author: Greg Burd <[email protected]>
Author: Dave Cramer <[email protected]>
Discussion: https://postgr.es/m/3c576ad7-d2da-4137-b791-5821da7cc370%40app.fastmail.com
---
 doc/src/sgml/installation.sgml |  2 +-
 meson.build                    |  9 +++--
 src/include/storage/s_lock.h   | 60 +++++++++++++++++++++++++++-------
 src/port/pg_crc32c_armv8.c     |  6 ++++
 src/tools/msvc_gendef.pl       |  8 ++---
 5 files changed, 67 insertions(+), 18 deletions(-)

diff --git a/doc/src/sgml/installation.sgml b/doc/src/sgml/installation.sgml
index fe8d73e1f8c..3f8d512a906 100644
--- a/doc/src/sgml/installation.sgml
+++ b/doc/src/sgml/installation.sgml
@@ -3967,7 +3967,7 @@ 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 ARM64 architectures on 64-bit Windows.
     </para>
     <para>
      Mixing 32- and 64-bit versions in the same build tree is not supported.
diff --git a/meson.build b/meson.build
index 718150e3ac0..e57c233b124 100644
--- a/meson.build
+++ b/meson.build
@@ -2512,7 +2512,12 @@ int main(void)
 }
 '''
 
-  if cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd without -march=armv8-a+crc',
+  # Check first for a MSVC/ARM64 combo because the test prog above won't
+  # compile (as it doesn't '#ifdef _MSC_VER #include <intrin.h>'), which
+  # is okay as we know for a fact that this platform combo supports the
+  # intrinsic for ARM64 CRC the test performs, so use that unconditionally.
+  if (host_machine.cpu_family() == '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)
@@ -2531,7 +2536,7 @@ int main(void)
     cdata.set('USE_ARMV8_CRC32C', false)
     cdata.set('USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 1)
     have_optimized_crc = true
-  endif
+endif
 
 elif host_cpu == 'loongarch64'
 
diff --git a/src/include/storage/s_lock.h b/src/include/storage/s_lock.h
index 7f8f566bd40..50262cca887 100644
--- a/src/include/storage/s_lock.h
+++ b/src/include/storage/s_lock.h
@@ -594,7 +594,8 @@ tas(volatile slock_t *lock)
 
 #if !defined(HAS_TEST_AND_SET)	/* We didn't trigger above, let's try here */
 
-#ifdef _MSC_VER
+/* When compiling for Microsoft Windows using MSVC */
+#if defined(_MSC_VER)
 typedef LONG slock_t;
 
 #define HAS_TEST_AND_SET
@@ -602,34 +603,71 @@ 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.
+/*
+ * _InterlockedExchange() generates a full memory barrier (or release
+ * semantics that ensures all prior memory operations are visible to
+ * other cores before the lock is released.
+ */
+#define S_UNLOCK(lock) (InterlockedExchange(lock, 0))
+
+#if defined(_WIN64) /* Microsoft Windows x64 */
+
+#if defined(_M_ARM64) /* aarch64 */
+/*
+ * While there is support for a __yield() intrinsic for MSVC/ARM64[1], there
+ * is a wealth of real-world testing across databases and languages as well
+ * as a blog post by ARM[2] suggest that ISB is the most scalable and power
+ * friendly instruction to use for spinlock delay loops. So we use the only
+ * supported intrinsic/flag combination availble for this platform combo[3].
+ * This matches what we do above when compiling with either GCC or Clang.
+ *
+ * [1] https://learn.microsoft.com/en-us/cpp/intrinsics/arm64-intrinsics
+ * [2] https://developer.arm.com/community/arm-community-blogs/b/architectures-and-processors-blog/posts/multi-threaded-applications-arm
+ * [3] https://github.com/MicrosoftDocs/cpp-docs/blob/main/docs/intrinsics/arm64-intrinsics.md
+ */
+static __forceinline void
+spin_delay(void)
+{
+	__isb(_ARM64_BARRIER_SY);
+}
+
+#elif defined(_M_X64) /* x86-64 */
+
+/*
+ * Use _mm_pause() intrinsic for x86-64. This emits the PAUSE instruction,
+ * which improves performance in spin-wait loops by preventing pipeline flush
+ * on Hyper-Threading systems.
  */
-#if defined(_WIN64)
 static __forceinline void
 spin_delay(void)
 {
 	_mm_pause();
 }
-#else
+
+#endif /* defined(_M_ARM64|_M_X64) */
+
+#else /* !defined(_WIN64) */
+
+#ifdef _M_IX86 /* x86-specific */
+
+/* Use no-op for MSVC 32bit x86 */
 static __forceinline void
 spin_delay(void)
 {
 	/* See comment for gcc code. Same code, MASM syntax */
 	__asm rep nop;
 }
-#endif
 
 #include <intrin.h>
 #pragma intrinsic(_ReadWriteBarrier)
 
-#define S_UNLOCK(lock)	\
+#define S_UNLOCK(lock) \
 	do { _ReadWriteBarrier(); (*(lock)) = 0; } while (0)
 
-#endif
-
-
-#endif	/* !defined(HAS_TEST_AND_SET) */
+#endif /* defined(_M_IX86) */
+#endif /* defined(_WIN64) */
+#endif /* defined(_MSC_VER) */
+#endif /* !defined(HAS_TEST_AND_SET) */
 
 
 /* Blow up if we didn't have any way to do spinlocks */
diff --git a/src/port/pg_crc32c_armv8.c b/src/port/pg_crc32c_armv8.c
index 5ba070bb99d..29a91dca62f 100644
--- a/src/port/pg_crc32c_armv8.c
+++ b/src/port/pg_crc32c_armv8.c
@@ -14,7 +14,13 @@
  */
 #include "c.h"
 
+#ifdef _MSC_VER
+ /* MSVC ARM64 intrinsics */
+#include <intrin.h>
+#else
+ /* GCC/Clang: Use ACLE intrinsics from arm_acle.h */
 #include <arm_acle.h>
+#endif
 
 #include "port/pg_crc32c.h"
 
diff --git a/src/tools/msvc_gendef.pl b/src/tools/msvc_gendef.pl
index 868aad51b09..c92c94c4775 100644
--- a/src/tools/msvc_gendef.pl
+++ b/src/tools/msvc_gendef.pl
@@ -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;
 
-- 
2.52.0.windows.1



^ permalink  raw  reply  [nested|flat] 42+ messages in thread

*  Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ​barriers
@ 2025-12-11 17:18  Greg Burd <[email protected]>
  parent: Greg Burd <[email protected]>
  0 siblings, 1 reply; 42+ messages in thread

From: Greg Burd @ 2025-12-11 17:18 UTC (permalink / raw)
  To: Thomas Munro <[email protected]>; +Cc: PostgreSQL Hackers <[email protected]>; Nathan Bossart <[email protected]>; Peter Eisentraut <[email protected]>; Dave Cramer <[email protected]>; Andres Freund <[email protected]>

Well, TIL something about Meson; you must escape multi-line statements with a backslash.  Apologies for the oversight/noise.

best.

-greg


Attachments:

  [application/octet-stream] v8-0001-Enable-the-Microsoft-Windows-ARM64-MSVC-platform.patch (7.4K, ../../[email protected]/2-v8-0001-Enable-the-Microsoft-Windows-ARM64-MSVC-platform.patch)
  download | inline diff:
From cfdfea317cd3a0ae53f0dfaa439ada8ded3bebf7 Mon Sep 17 00:00:00 2001
From: Dave Cramer <[email protected]>
Date: Sun, 13 Jul 2025 06:33:17 -0400
Subject: [PATCH v8] Enable the Microsoft Windows ARM64/MSVC platform

Add support for the ARM64 architecture on Windows 11 using MSVC compiler
addressing build issues and implementing proper memory synchronization
semantics for this platform.

* Implement spin_delay() with __isb(_ARM64_BARRIER_SY) intrinsic to emit
  the "ISB SY" instruction which matches the GCC/Clang approach to
  spinloop delay and emperical evidence that it out-scales the YIELD
  instruction in practice.

* Unconditionally choose to use the MSVC supplied intrinsic
  for CRC32 on ARM64.

* Implement the S_UNLOCK() macro using the InterlockedExchange()
  intrinsic.

Author: Greg Burd <[email protected]>
Author: Dave Cramer <[email protected]>
Discussion: https://postgr.es/m/3c576ad7-d2da-4137-b791-5821da7cc370%40app.fastmail.com
---
 doc/src/sgml/installation.sgml |  2 +-
 meson.build                    |  9 +++--
 src/include/storage/s_lock.h   | 60 +++++++++++++++++++++++++++-------
 src/port/pg_crc32c_armv8.c     |  6 ++++
 src/tools/msvc_gendef.pl       |  8 ++---
 5 files changed, 67 insertions(+), 18 deletions(-)

diff --git a/doc/src/sgml/installation.sgml b/doc/src/sgml/installation.sgml
index fe8d73e1f8c..3f8d512a906 100644
--- a/doc/src/sgml/installation.sgml
+++ b/doc/src/sgml/installation.sgml
@@ -3967,7 +3967,7 @@ 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 ARM64 architectures on 64-bit Windows.
     </para>
     <para>
      Mixing 32- and 64-bit versions in the same build tree is not supported.
diff --git a/meson.build b/meson.build
index 1256094fa57..6c463d14749 100644
--- a/meson.build
+++ b/meson.build
@@ -2527,7 +2527,12 @@ int main(void)
 }
 '''
 
-  if cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd without -march=armv8-a+crc',
+  # Check first for a MSVC/ARM64 combo because the test prog above won't
+  # compile (as it doesn't '#ifdef _MSC_VER #include <intrin.h>'), which
+  # is okay as we know for a fact that this platform combo supports the
+  # intrinsic for ARM64 CRC the test performs, so use that unconditionally.
+  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)
@@ -2546,7 +2551,7 @@ int main(void)
     cdata.set('USE_ARMV8_CRC32C', false)
     cdata.set('USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 1)
     have_optimized_crc = true
-  endif
+endif
 
 elif host_cpu == 'loongarch64'
 
diff --git a/src/include/storage/s_lock.h b/src/include/storage/s_lock.h
index 7f8f566bd40..50262cca887 100644
--- a/src/include/storage/s_lock.h
+++ b/src/include/storage/s_lock.h
@@ -594,7 +594,8 @@ tas(volatile slock_t *lock)
 
 #if !defined(HAS_TEST_AND_SET)	/* We didn't trigger above, let's try here */
 
-#ifdef _MSC_VER
+/* When compiling for Microsoft Windows using MSVC */
+#if defined(_MSC_VER)
 typedef LONG slock_t;
 
 #define HAS_TEST_AND_SET
@@ -602,34 +603,71 @@ 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.
+/*
+ * _InterlockedExchange() generates a full memory barrier (or release
+ * semantics that ensures all prior memory operations are visible to
+ * other cores before the lock is released.
+ */
+#define S_UNLOCK(lock) (InterlockedExchange(lock, 0))
+
+#if defined(_WIN64) /* Microsoft Windows x64 */
+
+#if defined(_M_ARM64) /* aarch64 */
+/*
+ * While there is support for a __yield() intrinsic for MSVC/ARM64[1], there
+ * is a wealth of real-world testing across databases and languages as well
+ * as a blog post by ARM[2] suggest that ISB is the most scalable and power
+ * friendly instruction to use for spinlock delay loops. So we use the only
+ * supported intrinsic/flag combination availble for this platform combo[3].
+ * This matches what we do above when compiling with either GCC or Clang.
+ *
+ * [1] https://learn.microsoft.com/en-us/cpp/intrinsics/arm64-intrinsics
+ * [2] https://developer.arm.com/community/arm-community-blogs/b/architectures-and-processors-blog/posts/multi-threaded-applications-arm
+ * [3] https://github.com/MicrosoftDocs/cpp-docs/blob/main/docs/intrinsics/arm64-intrinsics.md
+ */
+static __forceinline void
+spin_delay(void)
+{
+	__isb(_ARM64_BARRIER_SY);
+}
+
+#elif defined(_M_X64) /* x86-64 */
+
+/*
+ * Use _mm_pause() intrinsic for x86-64. This emits the PAUSE instruction,
+ * which improves performance in spin-wait loops by preventing pipeline flush
+ * on Hyper-Threading systems.
  */
-#if defined(_WIN64)
 static __forceinline void
 spin_delay(void)
 {
 	_mm_pause();
 }
-#else
+
+#endif /* defined(_M_ARM64|_M_X64) */
+
+#else /* !defined(_WIN64) */
+
+#ifdef _M_IX86 /* x86-specific */
+
+/* Use no-op for MSVC 32bit x86 */
 static __forceinline void
 spin_delay(void)
 {
 	/* See comment for gcc code. Same code, MASM syntax */
 	__asm rep nop;
 }
-#endif
 
 #include <intrin.h>
 #pragma intrinsic(_ReadWriteBarrier)
 
-#define S_UNLOCK(lock)	\
+#define S_UNLOCK(lock) \
 	do { _ReadWriteBarrier(); (*(lock)) = 0; } while (0)
 
-#endif
-
-
-#endif	/* !defined(HAS_TEST_AND_SET) */
+#endif /* defined(_M_IX86) */
+#endif /* defined(_WIN64) */
+#endif /* defined(_MSC_VER) */
+#endif /* !defined(HAS_TEST_AND_SET) */
 
 
 /* Blow up if we didn't have any way to do spinlocks */
diff --git a/src/port/pg_crc32c_armv8.c b/src/port/pg_crc32c_armv8.c
index 5ba070bb99d..29a91dca62f 100644
--- a/src/port/pg_crc32c_armv8.c
+++ b/src/port/pg_crc32c_armv8.c
@@ -14,7 +14,13 @@
  */
 #include "c.h"
 
+#ifdef _MSC_VER
+ /* MSVC ARM64 intrinsics */
+#include <intrin.h>
+#else
+ /* GCC/Clang: Use ACLE intrinsics from arm_acle.h */
 #include <arm_acle.h>
+#endif
 
 #include "port/pg_crc32c.h"
 
diff --git a/src/tools/msvc_gendef.pl b/src/tools/msvc_gendef.pl
index 868aad51b09..c92c94c4775 100644
--- a/src/tools/msvc_gendef.pl
+++ b/src/tools/msvc_gendef.pl
@@ -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;
 
-- 
2.52.0.windows.1



^ permalink  raw  reply  [nested|flat] 42+ messages in thread

* Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ?barriers
@ 2025-12-12 16:03  Nathan Bossart <[email protected]>
  parent: Greg Burd <[email protected]>
  0 siblings, 1 reply; 42+ messages in thread

From: Nathan Bossart @ 2025-12-12 16:03 UTC (permalink / raw)
  To: Greg Burd <[email protected]>; +Cc: Thomas Munro <[email protected]>; PostgreSQL Hackers <[email protected]>; Peter Eisentraut <[email protected]>; Dave Cramer <[email protected]>; Andres Freund <[email protected]>

+/*
+ * _InterlockedExchange() generates a full memory barrier (or release
+ * semantics that ensures all prior memory operations are visible to
+ * other cores before the lock is released.
+ */
+#define S_UNLOCK(lock) (InterlockedExchange(lock, 0))

This seems to change the implementation from

	#define S_UNLOCK(lock)	\
		do { _ReadWriteBarrier(); (*(lock)) = 0; } while (0)

in some cases, but I am insufficiently caffeinated to figure out what
platforms use which implementation.  In any case, it looks like we are
changing it for some currently-supported platforms, and I'm curious why.
Perhaps there's some way to make the #ifdefs a bit more readable, too
(e.g., a prerequisite patch that rearranges things).

The rest looks generally reasonable to me.

-- 
nathan





^ permalink  raw  reply  [nested|flat] 42+ messages in thread

* Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ?barriers
@ 2025-12-12 19:21  Greg Burd <[email protected]>
  parent: Nathan Bossart <[email protected]>
  0 siblings, 1 reply; 42+ messages in thread

From: Greg Burd @ 2025-12-12 19:21 UTC (permalink / raw)
  To: Nathan Bossart <[email protected]>; +Cc: Thomas Munro <[email protected]>; PostgreSQL Hackers <[email protected]>; Peter Eisentraut <[email protected]>; Dave Cramer <[email protected]>; Andres Freund <[email protected]>


On Fri, Dec 12, 2025, at 11:03 AM, Nathan Bossart wrote:
> +/*
> + * _InterlockedExchange() generates a full memory barrier (or release
> + * semantics that ensures all prior memory operations are visible to
> + * other cores before the lock is released.
> + */
> +#define S_UNLOCK(lock) (InterlockedExchange(lock, 0))

Nathan, thanks for looking at the patch!

> This seems to change the implementation from
>
> 	#define S_UNLOCK(lock)	\
> 		do { _ReadWriteBarrier(); (*(lock)) = 0; } while (0)
>
> in some cases, but I am insufficiently caffeinated to figure out what
> platforms use which implementation.  In any case, it looks like we are
> changing it for some currently-supported platforms, and I'm curious why.

This change is within _MSC_VER, but AFAICT this intrinsic is available across their supported platforms.  The previous implementation of S_UNLOCK() boils down to a no-op because the _ReadWriteBarrier()[1] is a hint to the compiler and does not emit any instruction on any platform and it's also deprecated.  So, on MSVC S_UNLOCK is an unguarded assignment and then a loop that will be optimized out, not really what we wanted I'd imagine.  My tests with godbolt showed this to be true, no instruction barriers emitted.  I think it was Andres[2] who suggested replacing it with _InterlockedExchange()[3].  So, given that _ReadWriteBarrier() is deprecated I decided not to specialize this change to only the ARM64 platform, sorry for not making that clear in the commit or email.

My buildfarm animal for this platform was just approved and is named "unicorn", I'm not making that up. :)

best.

-greg

> Perhaps there's some way to make the #ifdefs a bit more readable, too
> (e.g., a prerequisite patch that rearranges things).
>
> The rest looks generally reasonable to me.
>
> -- 
> nathan

[1] https://learn.microsoft.com/en-us/cpp/intrinsics/readwritebarrier
[2] https://www.postgresql.org/message-id/beirrgqo5n5e73dwa4dsdnlbtef3bsdv5sgarm6przdzxvifk5%40whyuhyemm...
[3] https://learn.microsoft.com/en-us/cpp/intrinsics/interlockedexchange-intrinsic-functions





^ permalink  raw  reply  [nested|flat] 42+ messages in thread

* Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ?barriers
@ 2025-12-12 19:32  Andres Freund <[email protected]>
  parent: Greg Burd <[email protected]>
  0 siblings, 1 reply; 42+ messages in thread

From: Andres Freund @ 2025-12-12 19:32 UTC (permalink / raw)
  To: Greg Burd <[email protected]>; +Cc: Nathan Bossart <[email protected]>; Thomas Munro <[email protected]>; PostgreSQL Hackers <[email protected]>; Peter Eisentraut <[email protected]>; Dave Cramer <[email protected]>

Hi,

On 2025-12-12 14:21:47 -0500, Greg Burd wrote:
> 
> On Fri, Dec 12, 2025, at 11:03 AM, Nathan Bossart wrote:
> > +/*
> > + * _InterlockedExchange() generates a full memory barrier (or release
> > + * semantics that ensures all prior memory operations are visible to
> > + * other cores before the lock is released.
> > + */
> > +#define S_UNLOCK(lock) (InterlockedExchange(lock, 0))
> 
> Nathan, thanks for looking at the patch!
> 
> > This seems to change the implementation from
> >
> > 	#define S_UNLOCK(lock)	\
> > 		do { _ReadWriteBarrier(); (*(lock)) = 0; } while (0)
> >
> > in some cases, but I am insufficiently caffeinated to figure out what
> > platforms use which implementation.  In any case, it looks like we are
> > changing it for some currently-supported platforms, and I'm curious why.
> 
> This change is within _MSC_VER, but AFAICT this intrinsic is available
> across their supported platforms.  The previous implementation of S_UNLOCK()
> boils down to a no-op because the _ReadWriteBarrier()[1] is a hint to the
> compiler and does not emit any instruction on any platform and it's also
> deprecated.  So, on MSVC S_UNLOCK is an unguarded assignment and then a loop
> that will be optimized out, not really what we wanted I'd imagine.

I don't think it can be optimized out, that should be prevented by
_ReadWriteBarrier() being a compiler barrier.


> My tests with godbolt showed this to be true, no instruction barriers
> emitted.  I think it was Andres[2] who suggested replacing it with
> _InterlockedExchange()[3].  So, given that _ReadWriteBarrier() is deprecated
> I decided not to specialize this change to only the ARM64 platform, sorry
> for not making that clear in the commit or email.

I don't think that's a good idea - the _ReadWriteBarrier() is sufficient on
x86 to implement a spinlock release (due to x86 being a total store order
architecture, once the lock is observed as being released, all the effects
protected by the lock are also guaranteed to be visible).  Making the
spinlocks use an atomic op for both acquire and release does cause measurable
slowdowns on x86 with gcc, so I'd expect the same to be true on windows.

Greetings,

Andres Freund





^ permalink  raw  reply  [nested|flat] 42+ messages in thread

* Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ?barriers
@ 2025-12-15 17:27  Greg Burd <[email protected]>
  parent: Andres Freund <[email protected]>
  0 siblings, 1 reply; 42+ messages in thread

From: Greg Burd @ 2025-12-15 17:27 UTC (permalink / raw)
  To: Andres Freund <[email protected]>; +Cc: Nathan Bossart <[email protected]>; Thomas Munro <[email protected]>; PostgreSQL Hackers <[email protected]>; Peter Eisentraut <[email protected]>; Dave Cramer <[email protected]>


On Fri, Dec 12, 2025, at 2:32 PM, Andres Freund wrote:
> Hi,
>
> On 2025-12-12 14:21:47 -0500, Greg Burd wrote:
>> 
>> On Fri, Dec 12, 2025, at 11:03 AM, Nathan Bossart wrote:
>> > +/*
>> > + * _InterlockedExchange() generates a full memory barrier (or release
>> > + * semantics that ensures all prior memory operations are visible to
>> > + * other cores before the lock is released.
>> > + */
>> > +#define S_UNLOCK(lock) (InterlockedExchange(lock, 0))
>> 
>> Nathan, thanks for looking at the patch!
>> 
>> > This seems to change the implementation from
>> >
>> > 	#define S_UNLOCK(lock)	\
>> > 		do { _ReadWriteBarrier(); (*(lock)) = 0; } while (0)
>> >
>> > in some cases, but I am insufficiently caffeinated to figure out what
>> > platforms use which implementation.  In any case, it looks like we are
>> > changing it for some currently-supported platforms, and I'm curious why.
>> 
>> This change is within _MSC_VER, but AFAICT this intrinsic is available
>> across their supported platforms.  The previous implementation of S_UNLOCK()
>> boils down to a no-op because the _ReadWriteBarrier()[1] is a hint to the
>> compiler and does not emit any instruction on any platform and it's also
>> deprecated.  So, on MSVC S_UNLOCK is an unguarded assignment and then a loop
>> that will be optimized out, not really what we wanted I'd imagine.

Thanks Andres for the comments.

> I don't think it can be optimized out, that should be prevented by
> _ReadWriteBarrier() being a compiler barrier.

While the documentation does mention that this has been deprecated, I tend to agree with you.  This has been in place for a while, no need to change what works at this time.  A new thread might be a better forum if there is some evidence that we should revisit this in the future.  I'd like to land the ARM64/MSVC changes and enable that platform in this thread.

>> My tests with godbolt showed this to be true, no instruction barriers
>> emitted.  I think it was Andres[2] who suggested replacing it with
>> _InterlockedExchange()[3].  So, given that _ReadWriteBarrier() is deprecated
>> I decided not to specialize this change to only the ARM64 platform, sorry
>> for not making that clear in the commit or email.
>
> I don't think that's a good idea - the _ReadWriteBarrier() is sufficient on
> x86 to implement a spinlock release (due to x86 being a total store order
> architecture, once the lock is observed as being released, all the effects
> protected by the lock are also guaranteed to be visible).  Making the
> spinlocks use an atomic op for both acquire and release does cause measurable
> slowdowns on x86 with gcc, so I'd expect the same to be true on windows.

Got it, fixed in v9.

best.

-greg

> Greetings,
>
> Andres Freund

Attachments:

  [application/octet-stream] v9-0001-Enable-the-Microsoft-Windows-ARM64-MSVC-platform.patch (7.6K, ../../[email protected]/2-v9-0001-Enable-the-Microsoft-Windows-ARM64-MSVC-platform.patch)
  download | inline diff:
From 396e5e5ab644aae261f852d616fe644f25238c37 Mon Sep 17 00:00:00 2001
From: Dave Cramer <[email protected]>
Date: Sun, 13 Jul 2025 06:33:17 -0400
Subject: [PATCH v9] Enable the Microsoft Windows ARM64/MSVC platform

Add support for the ARM64 architecture on Windows 11 using MSVC compiler
addressing build issues and implementing proper memory synchronization
semantics for this platform.

* Implement spin_delay() with __isb(_ARM64_BARRIER_SY) intrinsic to emit
  the "ISB SY" instruction which matches the GCC/Clang approach to
  spinloop delay and emperical evidence that it out-scales the YIELD
  instruction in practice.

* Unconditionally choose to use the MSVC supplied intrinsic
  for CRC32 on ARM64.

* Implement the S_UNLOCK() macro using the InterlockedExchange()
  intrinsic on ARM64.

Author: Greg Burd <[email protected]>
Author: Dave Cramer <[email protected]>
Discussion: https://postgr.es/m/3c576ad7-d2da-4137-b791-5821da7cc370%40app.fastmail.com
---
 doc/src/sgml/installation.sgml |  2 +-
 meson.build                    |  9 ++++-
 src/include/storage/s_lock.h   | 72 +++++++++++++++++++++++++++-------
 src/port/pg_crc32c_armv8.c     |  6 +++
 src/tools/msvc_gendef.pl       |  8 ++--
 5 files changed, 75 insertions(+), 22 deletions(-)

diff --git a/doc/src/sgml/installation.sgml b/doc/src/sgml/installation.sgml
index fe8d73e1f8c..3f8d512a906 100644
--- a/doc/src/sgml/installation.sgml
+++ b/doc/src/sgml/installation.sgml
@@ -3967,7 +3967,7 @@ 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 ARM64 architectures on 64-bit Windows.
     </para>
     <para>
      Mixing 32- and 64-bit versions in the same build tree is not supported.
diff --git a/meson.build b/meson.build
index d7c5193d4ce..57679e28443 100644
--- a/meson.build
+++ b/meson.build
@@ -2523,7 +2523,12 @@ int main(void)
 }
 '''
 
-  if cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd without -march=armv8-a+crc',
+  # Check first for a MSVC/ARM64 combo because the test prog above won't
+  # compile (as it doesn't '#ifdef _MSC_VER #include <intrin.h>'), which
+  # is okay as we know for a fact that this platform combo supports the
+  # intrinsic for ARM64 CRC the test performs, so use that unconditionally.
+  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)
@@ -2542,7 +2547,7 @@ int main(void)
     cdata.set('USE_ARMV8_CRC32C', false)
     cdata.set('USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 1)
     have_optimized_crc = true
-  endif
+endif
 
 elif host_cpu == 'loongarch64'
 
diff --git a/src/include/storage/s_lock.h b/src/include/storage/s_lock.h
index 7f8f566bd40..870010c67fd 100644
--- a/src/include/storage/s_lock.h
+++ b/src/include/storage/s_lock.h
@@ -594,7 +594,8 @@ tas(volatile slock_t *lock)
 
 #if !defined(HAS_TEST_AND_SET)	/* We didn't trigger above, let's try here */
 
-#ifdef _MSC_VER
+/* When compiling for Microsoft Windows using MSVC */
+#if defined(_MSC_VER)
 typedef LONG slock_t;
 
 #define HAS_TEST_AND_SET
@@ -602,34 +603,75 @@ 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.
+/*
+ * When using MSVC on any non-ARM64 (aarch64) platforms (x86-64 and x86)
+ * _ReadWriteBarrier is used to prevent the compiler from reordering
+ * memory operations across the lock operation.
  */
+#if !defined(_M_ARM64)
+
+#include <intrin.h>
+#pragma intrinsic(_ReadWriteBarrier)
+
+#define S_UNLOCK(lock) \
+	do { _ReadWriteBarrier(); (*(lock)) = 0; } while (0)
+
+#endif /* !defined(_M_ARM64) */
+
 #if defined(_WIN64)
+#if defined(_M_ARM64)
+
+/*
+ * _InterlockedExchange() generates a full memory barrier (or release
+ * semantics that ensures all prior memory operations are visible to
+ * other cores before the lock is released.
+ */
+#define S_UNLOCK(lock) (InterlockedExchange(lock, 0))
+
+/*
+ * While there is support for a __yield() intrinsic for MSVC/ARM64[1], there
+ * is a wealth of real-world testing across databases and languages as well
+ * as a blog post by ARM[2] suggest that ISB is the most scalable and power
+ * friendly instruction to use for spinlock delay loops. So we use the only
+ * supported intrinsic/flag combination availble for this platform combo[3].
+ * This matches what we do above when compiling with either GCC or Clang.
+ *
+ * [1] https://learn.microsoft.com/en-us/cpp/intrinsics/arm64-intrinsics
+ * [2] https://developer.arm.com/community/arm-community-blogs/b/architectures-and-processors-blog/posts/multi-threaded-applications-arm
+ * [3] https://github.com/MicrosoftDocs/cpp-docs/blob/main/docs/intrinsics/arm64-intrinsics.md
+ */
+static __forceinline void
+spin_delay(void)
+{
+	__isb(_ARM64_BARRIER_SY);
+}
+
+#else /* !defined(_M_ARM64) */
+
+/*
+ * If using Visual C++ on Win64, inline assembly is unavailable. Use the
+ * _mm_pause intrinsic instead of rep nop.
+ */
 static __forceinline void
 spin_delay(void)
 {
 	_mm_pause();
 }
-#else
+
+#endif /* defined(_M_ARM64) */
+#else /* !defined(_WIN64) */
+
+/* On 32bit systems (x86) use a no-op instruction */
 static __forceinline void
 spin_delay(void)
 {
 	/* See comment for gcc code. Same code, MASM syntax */
 	__asm rep nop;
 }
-#endif
-
-#include <intrin.h>
-#pragma intrinsic(_ReadWriteBarrier)
-
-#define S_UNLOCK(lock)	\
-	do { _ReadWriteBarrier(); (*(lock)) = 0; } while (0)
 
-#endif
-
-
-#endif	/* !defined(HAS_TEST_AND_SET) */
+#endif /* !defined(_WIN64) */
+#endif /* defined(_MSC_VER) */
+#endif /* !defined(HAS_TEST_AND_SET) */
 
 
 /* Blow up if we didn't have any way to do spinlocks */
diff --git a/src/port/pg_crc32c_armv8.c b/src/port/pg_crc32c_armv8.c
index 5ba070bb99d..29a91dca62f 100644
--- a/src/port/pg_crc32c_armv8.c
+++ b/src/port/pg_crc32c_armv8.c
@@ -14,7 +14,13 @@
  */
 #include "c.h"
 
+#ifdef _MSC_VER
+ /* MSVC ARM64 intrinsics */
+#include <intrin.h>
+#else
+ /* GCC/Clang: Use ACLE intrinsics from arm_acle.h */
 #include <arm_acle.h>
+#endif
 
 #include "port/pg_crc32c.h"
 
diff --git a/src/tools/msvc_gendef.pl b/src/tools/msvc_gendef.pl
index 868aad51b09..c92c94c4775 100644
--- a/src/tools/msvc_gendef.pl
+++ b/src/tools/msvc_gendef.pl
@@ -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;
 
-- 
2.52.0.windows.1



^ permalink  raw  reply  [nested|flat] 42+ messages in thread

* Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ?barriers
@ 2025-12-15 21:38  Nathan Bossart <[email protected]>
  parent: Greg Burd <[email protected]>
  0 siblings, 2 replies; 42+ messages in thread

From: Nathan Bossart @ 2025-12-15 21:38 UTC (permalink / raw)
  To: Greg Burd <[email protected]>; +Cc: Andres Freund <[email protected]>; Thomas Munro <[email protected]>; PostgreSQL Hackers <[email protected]>; Peter Eisentraut <[email protected]>; Dave Cramer <[email protected]>

On Mon, Dec 15, 2025 at 12:27:25PM -0500, Greg Burd wrote:
> Got it, fixed in v9.

I tried to rearrange the s_lock.h changes to make it more obvious what is
specific to AArch64.  WDYT?

-- 
nathan


^ permalink  raw  reply  [nested|flat] 42+ messages in thread

* Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ?barriers
@ 2025-12-15 22:32  Andres Freund <[email protected]>
  parent: Nathan Bossart <[email protected]>
  1 sibling, 2 replies; 42+ messages in thread

From: Andres Freund @ 2025-12-15 22:32 UTC (permalink / raw)
  To: Nathan Bossart <[email protected]>; +Cc: Greg Burd <[email protected]>; Thomas Munro <[email protected]>; PostgreSQL Hackers <[email protected]>; Peter Eisentraut <[email protected]>; Dave Cramer <[email protected]>

Hi,

On 2025-12-15 15:38:49 -0600, Nathan Bossart wrote:
> +++ b/meson.build
> @@ -2523,7 +2523,8 @@ int main(void)
>  }
>  '''
>  
> -  if cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd without -march=armv8-a+crc',
> +  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)

I still think this should have a comment explaining that we can
unconditionally rely on crc32 support due to window's baseline requirements.


> diff --git a/src/include/storage/s_lock.h b/src/include/storage/s_lock.h
> index 7f8f566bd40..e62141abf0a 100644
> --- a/src/include/storage/s_lock.h
> +++ b/src/include/storage/s_lock.h
> @@ -602,13 +602,21 @@ 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. */
> +	__isb(_ARM64_BARRIER_SY);

It'd be good to link the research in some form or another. Otherwise it's
harder to evolve the code in the future, because we don't know if the research
was "I liked the color better" or "one is catastrophically slower than the
other".

> +}
> +#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 +629,19 @@ spin_delay(void)
>  #endif
>  
>  #include <intrin.h>
> +#ifdef _M_ARM64
> +#pragma intrinsic(_InterlockedExchange)
> +
> +/* _ReadWriteBarrier() is insufficient on non-TSO architectures. */
> +#define S_UNLOCK(lock) _InterlockedExchange(lock, 0)
> +#else
>  #pragma intrinsic(_ReadWriteBarrier)
>  
>  #define S_UNLOCK(lock)	\
>  	do { _ReadWriteBarrier(); (*(lock)) = 0; } while (0)
>  
>  #endif
> +#endif

The newline placement looks odd here. I'd add newlines around the #else.



Greetings,

Andres Freund





^ permalink  raw  reply  [nested|flat] 42+ messages in thread

* Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ?barriers
@ 2025-12-15 23:00  Nathan Bossart <[email protected]>
  parent: Andres Freund <[email protected]>
  1 sibling, 1 reply; 42+ messages in thread

From: Nathan Bossart @ 2025-12-15 23:00 UTC (permalink / raw)
  To: Andres Freund <[email protected]>; +Cc: Greg Burd <[email protected]>; Thomas Munro <[email protected]>; PostgreSQL Hackers <[email protected]>; Peter Eisentraut <[email protected]>; Dave Cramer <[email protected]>

On Mon, Dec 15, 2025 at 05:32:36PM -0500, Andres Freund wrote:
> On 2025-12-15 15:38:49 -0600, Nathan Bossart wrote:
>> -  if cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd without -march=armv8-a+crc',
>> +  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)
> 
> I still think this should have a comment explaining that we can
> unconditionally rely on crc32 support due to window's baseline requirements.

Done.

>> +#ifdef _M_ARM64
>> +static __forceinline void
>> +spin_delay(void)
>> +{
>> +	/* Research indicates ISB is better than __yield() on AArch64. */
>> +	__isb(_ARM64_BARRIER_SY);
> 
> It'd be good to link the research in some form or another. Otherwise it's
> harder to evolve the code in the future, because we don't know if the research
> was "I liked the color better" or "one is catastrophically slower than the
> other".

Done.

>>  #include <intrin.h>
>> +#ifdef _M_ARM64
>> +#pragma intrinsic(_InterlockedExchange)
>> +
>> +/* _ReadWriteBarrier() is insufficient on non-TSO architectures. */
>> +#define S_UNLOCK(lock) _InterlockedExchange(lock, 0)
>> +#else
>>  #pragma intrinsic(_ReadWriteBarrier)
>>  
>>  #define S_UNLOCK(lock)	\
>>  	do { _ReadWriteBarrier(); (*(lock)) = 0; } while (0)
>>  
>>  #endif
>> +#endif
> 
> The newline placement looks odd here. I'd add newlines around the #else.

Done.

-- 
nathan


^ permalink  raw  reply  [nested|flat] 42+ messages in thread

*  Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ?barriers
@ 2025-12-15 23:08  Andres Freund <[email protected]>
  parent: Nathan Bossart <[email protected]>
  0 siblings, 1 reply; 42+ messages in thread

From: Andres Freund @ 2025-12-15 23:08 UTC (permalink / raw)
  To: Nathan Bossart <[email protected]>; +Cc: Greg Burd <[email protected]>; Thomas Munro <[email protected]>; PostgreSQL Hackers <[email protected]>; Peter Eisentraut <[email protected]>; Dave Cramer <[email protected]>



On December 15, 2025 6:00:47 PM EST, Nathan Bossart <[email protected]> wrote:
>Done.

LGTM
-- 
Sent from my Android device with K-9 Mail. Please excuse my brevity.





^ permalink  raw  reply  [nested|flat] 42+ messages in thread

* Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ?barriers
@ 2025-12-16 12:37  Greg Burd <[email protected]>
  parent: Nathan Bossart <[email protected]>
  1 sibling, 0 replies; 42+ messages in thread

From: Greg Burd @ 2025-12-16 12:37 UTC (permalink / raw)
  To: Nathan Bossart <[email protected]>; +Cc: Andres Freund <[email protected]>; Thomas Munro <[email protected]>; PostgreSQL Hackers <[email protected]>; Peter Eisentraut <[email protected]>; Dave Cramer <[email protected]>


On Mon, Dec 15, 2025, at 4:38 PM, Nathan Bossart wrote:
> On Mon, Dec 15, 2025 at 12:27:25PM -0500, Greg Burd wrote:
>> Got it, fixed in v9.
>
> I tried to rearrange the s_lock.h changes to make it more obvious what is
> specific to AArch64.  WDYT?

Hey Nathan, thanks for taking another look and editing the patch!  Your version is much more concise, I like it.  Testing it now.

best.

-greg

> -- 
> nathan
>
> Attachments:
> * v10-0001-Enable-the-Microsoft-Windows-ARM64-MSVC-platform.patch





^ permalink  raw  reply  [nested|flat] 42+ messages in thread

* Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ?barriers
@ 2025-12-16 12:40  Greg Burd <[email protected]>
  parent: Andres Freund <[email protected]>
  1 sibling, 0 replies; 42+ messages in thread

From: Greg Burd @ 2025-12-16 12:40 UTC (permalink / raw)
  To: Andres Freund <[email protected]>; Nathan Bossart <[email protected]>; +Cc: Thomas Munro <[email protected]>; PostgreSQL Hackers <[email protected]>; Peter Eisentraut <[email protected]>; Dave Cramer <[email protected]>


On Mon, Dec 15, 2025, at 5:32 PM, Andres Freund wrote:
> Hi,
>
> On 2025-12-15 15:38:49 -0600, Nathan Bossart wrote:
>> +++ b/meson.build
>> @@ -2523,7 +2523,8 @@ int main(void)
>>  }
>>  '''
>>  
>> -  if cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd without -march=armv8-a+crc',
>> +  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)
>
> I still think this should have a comment explaining that we can
> unconditionally rely on crc32 support due to window's baseline requirements.
>
>
>> diff --git a/src/include/storage/s_lock.h b/src/include/storage/s_lock.h
>> index 7f8f566bd40..e62141abf0a 100644
>> --- a/src/include/storage/s_lock.h
>> +++ b/src/include/storage/s_lock.h
>> @@ -602,13 +602,21 @@ 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. */
>> +	__isb(_ARM64_BARRIER_SY);
>
> It'd be good to link the research in some form or another. Otherwise it's
> harder to evolve the code in the future, because we don't know if the research
> was "I liked the color better" or "one is catastrophically slower than the
> other".
>
>> +}
>> +#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 +629,19 @@ spin_delay(void)
>>  #endif
>>  
>>  #include <intrin.h>
>> +#ifdef _M_ARM64
>> +#pragma intrinsic(_InterlockedExchange)
>> +
>> +/* _ReadWriteBarrier() is insufficient on non-TSO architectures. */
>> +#define S_UNLOCK(lock) _InterlockedExchange(lock, 0)
>> +#else
>>  #pragma intrinsic(_ReadWriteBarrier)
>>  
>>  #define S_UNLOCK(lock)	\
>>  	do { _ReadWriteBarrier(); (*(lock)) = 0; } while (0)
>>  
>>  #endif
>> +#endif
>
> The newline placement looks odd here. I'd add newlines around the #else.

Hey Andres, thanks for chiming in!  I agree with your suggestions and it looks like Nathan has already addressed them to your satisfaction.  I've applied v11 on my "unicorn" Win11 ARM64 MSVC system and it's testing now.

best.

-greg

> Greetings,
>
> Andres Freund





^ permalink  raw  reply  [nested|flat] 42+ messages in thread

* Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ?barriers
@ 2025-12-16 13:23  Greg Burd <[email protected]>
  parent: Andres Freund <[email protected]>
  0 siblings, 1 reply; 42+ messages in thread

From: Greg Burd @ 2025-12-16 13:23 UTC (permalink / raw)
  To: Andres Freund <[email protected]>; Nathan Bossart <[email protected]>; +Cc: Thomas Munro <[email protected]>; PostgreSQL Hackers <[email protected]>; Peter Eisentraut <[email protected]>; Dave Cramer <[email protected]>


On Mon, Dec 15, 2025, at 6:08 PM, Andres Freund wrote:
> On December 15, 2025 6:00:47 PM EST, Nathan Bossart 
> <[email protected]> wrote:
>>Done.
>
> LGTM
> -- 

Good morning Nathan, Andres,

Thanks again to both of you for your help with this work.  With the v11 patch on HEAD (b39013b7b1b) I was able to configure, compile, and test without errors on my build-farm animal "unicorn" (aarch64).

Just for the record:
C compiler for the host machine: cl (msvc 19.50.35720 "Microsoft (R) C/C++ Optimizing Compiler Version 19.50.35720 for ARM64")
C linker for the host machine: link link 14.50.35720.0

I'll add to my TODO list a task to update the wiki with things I've learned.

LGTM, thanks everyone.

-greg





^ permalink  raw  reply  [nested|flat] 42+ messages in thread

* Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ?barriers
@ 2025-12-16 18:07  Nathan Bossart <[email protected]>
  parent: Greg Burd <[email protected]>
  0 siblings, 1 reply; 42+ messages in thread

From: Nathan Bossart @ 2025-12-16 18:07 UTC (permalink / raw)
  To: Greg Burd <[email protected]>; +Cc: Andres Freund <[email protected]>; Thomas Munro <[email protected]>; PostgreSQL Hackers <[email protected]>; Peter Eisentraut <[email protected]>; Dave Cramer <[email protected]>

On Tue, Dec 16, 2025 at 08:23:19AM -0500, Greg Burd wrote:
> On Mon, Dec 15, 2025, at 6:08 PM, Andres Freund wrote:
>> LGTM
> 
> LGTM, thanks everyone.

Here's what I have staged for commit.  I searched around for anything else
that might be missing, and I only found a couple of small things.  First,
there are some optional AArch64 optimizations (simd.h and popcount) that
likely need more work, but those can wait for now.  Also, while the patch
is targeting Windows 11 (IIUC), there are some notes in the docs that give
the impression Windows 10 is supported, too [0].  I could easily change it
to say that AArch64 requires Windows 11, but I don't know what to do with
the references to specific versions of Visual Studio and the Windows SDK.
Thoughts?  Maybe that can wait, too.

[0] https://www.postgresql.org/docs/devel/installation-platform-notes.html#INSTALLATION-NOTES-VISUAL-STU...

-- 
nathan


^ permalink  raw  reply  [nested|flat] 42+ messages in thread

* Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ?barriers
@ 2025-12-16 21:40  Nathan Bossart <[email protected]>
  parent: Nathan Bossart <[email protected]>
  0 siblings, 2 replies; 42+ messages in thread

From: Nathan Bossart @ 2025-12-16 21:40 UTC (permalink / raw)
  To: Greg Burd <[email protected]>; +Cc: Andres Freund <[email protected]>; Thomas Munro <[email protected]>; PostgreSQL Hackers <[email protected]>; Peter Eisentraut <[email protected]>; Dave Cramer <[email protected]>

Sorry for the noise.

I discovered that this patch originated in another thread [0], so I spent
some time updating the attributions.  Please let me know if there are any
inaccuracies.

On Tue, Dec 16, 2025 at 12:07:34PM -0600, Nathan Bossart wrote:
> Here's what I have staged for commit.  I searched around for anything else
> that might be missing, and I only found a couple of small things.  First,
> there are some optional AArch64 optimizations (simd.h and popcount) that
> likely need more work, but those can wait for now.

Hm.  I think the USE_LLVM_BACKPORT_SECTION_MEMORY_MANAGER thing might need
work, too.  We don't have any Windows buildfarm machines with LLVM enabled,
but IIUC it should be possible.  Perhaps we can add that to unicorn.

> Also, while the patch
> is targeting Windows 11 (IIUC), there are some notes in the docs that give
> the impression Windows 10 is supported, too [0].  I could easily change it
> to say that AArch64 requires Windows 11, but I don't know what to do with
> the references to specific versions of Visual Studio and the Windows SDK.

Actually, I'm not sure there's anything specific to Windows 11 in this
patch, besides perhaps the choice to set USE_ARMV8_CRC32C unconditionally.
I don't know how likely it is that someone will try to run Postgres on
Windows on an AArch64 machine without CRC extension support, though.

[0] https://postgr.es/m/CAFPTBD-74%2BAEuN9n7caJ0YUnW5A0r-KBX8rYoEJWqFPgLKpzdg%40mail.gmail.com

-- 
nathan


^ permalink  raw  reply  [nested|flat] 42+ messages in thread

* Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ?barriers
@ 2025-12-16 22:36  Andres Freund <[email protected]>
  parent: Nathan Bossart <[email protected]>
  1 sibling, 0 replies; 42+ messages in thread

From: Andres Freund @ 2025-12-16 22:36 UTC (permalink / raw)
  To: Nathan Bossart <[email protected]>; +Cc: Greg Burd <[email protected]>; Thomas Munro <[email protected]>; PostgreSQL Hackers <[email protected]>; Peter Eisentraut <[email protected]>; Dave Cramer <[email protected]>

Hi,

On 2025-12-16 15:40:45 -0600, Nathan Bossart wrote:
> On Tue, Dec 16, 2025 at 12:07:34PM -0600, Nathan Bossart wrote:
> > Here's what I have staged for commit.  I searched around for anything else
> > that might be missing, and I only found a couple of small things.  First,
> > there are some optional AArch64 optimizations (simd.h and popcount) that
> > likely need more work, but those can wait for now.
> 
> Hm.  I think the USE_LLVM_BACKPORT_SECTION_MEMORY_MANAGER thing might need
> work, too.  We don't have any Windows buildfarm machines with LLVM enabled,
> but IIUC it should be possible.  Perhaps we can add that to unicorn.

I don't think LLVM ever was in use on windows. With the old src/tools/msvc
stuff it wasn't supported, and I don't know if anybody tested it with meson.

I don't think this patch/thread needs to worry about that.


> > Also, while the patch
> > is targeting Windows 11 (IIUC), there are some notes in the docs that give
> > the impression Windows 10 is supported, too [0].  I could easily change it
> > to say that AArch64 requires Windows 11, but I don't know what to do with
> > the references to specific versions of Visual Studio and the Windows SDK.
> 
> Actually, I'm not sure there's anything specific to Windows 11 in this
> patch, besides perhaps the choice to set USE_ARMV8_CRC32C unconditionally.
> I don't know how likely it is that someone will try to run Postgres on
> Windows on an AArch64 machine without CRC extension support, though.

I think it's vanishingly unlikely. Windows 10 is out of support and windows
ARM support is pretty new. I doubt there's any windows capable armv8 hardware
without the relevant extension.


Greetings,

Andres Freund





^ permalink  raw  reply  [nested|flat] 42+ messages in thread

* Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ?barriers
@ 2025-12-17 01:57  Thomas Munro <[email protected]>
  parent: Nathan Bossart <[email protected]>
  1 sibling, 1 reply; 42+ messages in thread

From: Thomas Munro @ 2025-12-17 01:57 UTC (permalink / raw)
  To: Nathan Bossart <[email protected]>; +Cc: Greg Burd <[email protected]>; Andres Freund <[email protected]>; PostgreSQL Hackers <[email protected]>; Peter Eisentraut <[email protected]>; Dave Cramer <[email protected]>

On Wed, Dec 17, 2025 at 10:40 AM Nathan Bossart
<[email protected]> wrote:
> Hm.  I think the USE_LLVM_BACKPORT_SECTION_MEMORY_MANAGER thing might need
> work, too.  We don't have any Windows buildfarm machines with LLVM enabled,
> but IIUC it should be possible.  Perhaps we can add that to unicorn.

The LLVM code has never run on Windows and will likely need
patching... I know of at least one change required and will write
about that.

> > Also, while the patch
> > is targeting Windows 11 (IIUC), there are some notes in the docs that give
> > the impression Windows 10 is supported, too [0].  I could easily change it
> > to say that AArch64 requires Windows 11, but I don't know what to do with
> > the references to specific versions of Visual Studio and the Windows SDK.
>
> Actually, I'm not sure there's anything specific to Windows 11 in this
> patch, besides perhaps the choice to set USE_ARMV8_CRC32C unconditionally.
> I don't know how likely it is that someone will try to run Postgres on
> Windows on an AArch64 machine without CRC extension support, though.

Assuming you haven't blocked OS updates, Windows stopped booting on
pre-ARMv8.1 hardware a while back.  RPi4's Broadcom chip and the
Snapdragon 835 (found in the oldest Windows laptops, according to a
quick Google search) are ARMv8-A only, but did actually have the CRC32
instructions, so it would actually work anyway.  They also have the
optional NEON SIMD stuff, which we use unconditionally:

/*
 * We use the Neon instructions if the compiler provides access to them (as
 * indicated by __ARM_NEON) and we are on aarch64.  While Neon support is
 * technically optional for aarch64, it appears that all available 64-bit
 * hardware does have it.  Neon exists in some 32-bit hardware too, but we
 * could not realistically use it there without a run-time check, which seems
 * not worth the trouble for now.
 */

A single chip in this report lacked FEAT_CRC32, the X-Gene 1 from 2012:

https://gpages.juszkiewicz.com.pl/arm-socs-table/arm-socs.html

So I don't think it's worth worrying about, I was just mentioning the
"Windows 11 requires CRC32, Windows 10 is dead" thing to avoid Greg
being forced to waste time researching the missing feature test code
:-)  The reason Windows can't boot on old ARM chips probably has more
to do with the modern atomics needed for decent lock performance,
which every kernel wants.





^ permalink  raw  reply  [nested|flat] 42+ messages in thread

* Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ?barriers
@ 2025-12-17 18:34  Greg Burd <[email protected]>
  parent: Thomas Munro <[email protected]>
  0 siblings, 0 replies; 42+ messages in thread

From: Greg Burd @ 2025-12-17 18:34 UTC (permalink / raw)
  To: Thomas Munro <[email protected]>; Nathan Bossart <[email protected]>; +Cc: Andres Freund <[email protected]>; PostgreSQL Hackers <[email protected]>; Peter Eisentraut <[email protected]>; Dave Cramer <[email protected]>


On Tue, Dec 16, 2025, at 8:57 PM, Thomas Munro wrote:
> On Wed, Dec 17, 2025 at 10:40 AM Nathan Bossart
> <[email protected]> wrote:

Hey Nathan, Thomas, thanks for your continued investment of time in this patch.  More thoughts below, but I wonder if the thing to do is to commit this and then for me to follow-on with a few more targeted changes to round out this platform combo?

>> Hm.  I think the USE_LLVM_BACKPORT_SECTION_MEMORY_MANAGER thing might need
>> work, too.  We don't have any Windows buildfarm machines with LLVM enabled,
>> but IIUC it should be possible.  Perhaps we can add that to unicorn.
>
> The LLVM code has never run on Windows and will likely need
> patching... I know of at least one change required and will write
> about that.

I think it would be amazing to support this eventually, but as I'm not a MSVC or Win11 guru this feels like a longer term patch.  I'm still struggling with simpler things at the moment.  The platform is not well established so some libraries are missing or out of date.  There's no ARM64-native Perl either.

>> > Also, while the patch
>> > is targeting Windows 11 (IIUC), there are some notes in the docs that give
>> > the impression Windows 10 is supported, too [0].  I could easily change it
>> > to say that AArch64 requires Windows 11, but I don't know what to do with
>> > the references to specific versions of Visual Studio and the Windows SDK.

When I get a chance I'll post a docs patch for debate/review.

>> Actually, I'm not sure there's anything specific to Windows 11 in this
>> patch, besides perhaps the choice to set USE_ARMV8_CRC32C unconditionally.
>> I don't know how likely it is that someone will try to run Postgres on
>> Windows on an AArch64 machine without CRC extension support, though.
>
> Assuming you haven't blocked OS updates, Windows stopped booting on
> pre-ARMv8.1 hardware a while back.  RPi4's Broadcom chip and the
> Snapdragon 835 (found in the oldest Windows laptops, according to a
> quick Google search) are ARMv8-A only, but did actually have the CRC32
> instructions, so it would actually work anyway.  They also have the
> optional NEON SIMD stuff, which we use unconditionally:
>
> /*
>  * We use the Neon instructions if the compiler provides access to them (as
>  * indicated by __ARM_NEON) and we are on aarch64.  While Neon support is
>  * technically optional for aarch64, it appears that all available 64-bit
>  * hardware does have it.  Neon exists in some 32-bit hardware too, but we
>  * could not realistically use it there without a run-time check, which seems
>  * not worth the trouble for now.
>  */
>
> A single chip in this report lacked FEAT_CRC32, the X-Gene 1 from 2012:
>
> https://gpages.juszkiewicz.com.pl/arm-socs-table/arm-socs.html
>
> So I don't think it's worth worrying about, I was just mentioning the
> "Windows 11 requires CRC32, Windows 10 is dead" thing to avoid Greg
> being forced to waste time researching the missing feature test code
> :-)  The reason Windows can't boot on old ARM chips probably has more
> to do with the modern atomics needed for decent lock performance,
> which every kernel wants.

I think there are a few things to offer up in the next few weeks:
* docs
* popcnt
* SIMD
* wiki page with HOWTO info for the next "brave" soul to give this a go
* what else?

What this patch does is get "unicorn" off the dead list, which would be nice.

-greg





^ permalink  raw  reply  [nested|flat] 42+ messages in thread


end of thread, other threads:[~2025-12-17 18:34 UTC | newest]

Thread overview: 42+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2025-11-20 20:45 [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ​barriers Greg Burd <[email protected]>
2025-11-20 22:00 ` Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB barriers Peter Eisentraut <[email protected]>
2025-11-20 22:08   ` Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB barriers Greg Burd <[email protected]>
2025-11-20 22:36     ` Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB barriers Nathan Bossart <[email protected]>
2025-11-21 09:46       ` Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB barriers Dave Cramer <[email protected]>
2025-11-21 19:40       ` Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB barriers Greg Burd <[email protected]>
2025-11-21 00:03 ` Andres Freund <[email protected]>
2025-11-21 00:07   ` Andres Freund <[email protected]>
2025-11-21 19:37     ` Greg Burd <[email protected]>
2025-11-21 19:36   ` Greg Burd <[email protected]>
2025-11-21 00:08 ` Thomas Munro <[email protected]>
2025-11-21 19:52   ` Greg Burd <[email protected]>
2025-11-22 21:43     ` Greg Burd <[email protected]>
2025-11-23 15:55       ` Andres Freund <[email protected]>
2025-11-23 20:32         ` Thomas Munro <[email protected]>
2025-11-23 20:41           ` Greg Burd <[email protected]>
2025-11-24 15:04             ` Greg Burd <[email protected]>
2025-11-24 16:28               ` Greg Burd <[email protected]>
2025-11-24 23:20                 ` Andres Freund <[email protected]>
2025-11-25 16:37                   ` Greg Burd <[email protected]>
2025-12-10 16:31                     ` Greg Burd <[email protected]>
2025-12-10 21:31                       ` Thomas Munro <[email protected]>
2025-12-11 16:16                         ` Greg Burd <[email protected]>
2025-12-11 17:18                           ` Greg Burd <[email protected]>
2025-12-12 16:03                             ` Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ?barriers Nathan Bossart <[email protected]>
2025-12-12 19:21                               ` Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ?barriers Greg Burd <[email protected]>
2025-12-12 19:32                                 ` Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ?barriers Andres Freund <[email protected]>
2025-12-15 17:27                                   ` Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ?barriers Greg Burd <[email protected]>
2025-12-15 21:38                                     ` Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ?barriers Nathan Bossart <[email protected]>
2025-12-15 22:32                                       ` Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ?barriers Andres Freund <[email protected]>
2025-12-15 23:00                                         ` Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ?barriers Nathan Bossart <[email protected]>
2025-12-15 23:08                                           `  Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ?barriers Andres Freund <[email protected]>
2025-12-16 13:23                                             ` Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ?barriers Greg Burd <[email protected]>
2025-12-16 18:07                                               ` Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ?barriers Nathan Bossart <[email protected]>
2025-12-16 21:40                                                 ` Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ?barriers Nathan Bossart <[email protected]>
2025-12-16 22:36                                                   ` Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ?barriers Andres Freund <[email protected]>
2025-12-17 01:57                                                   ` Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ?barriers Thomas Munro <[email protected]>
2025-12-17 18:34                                                     ` Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ?barriers Greg Burd <[email protected]>
2025-12-16 12:40                                         ` Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ?barriers Greg Burd <[email protected]>
2025-12-16 12:37                                       ` Re: [PATCH] Fix ARM64/MSVC atomic memory ordering issues on Win11 by adding explicit DMB ?barriers Greg Burd <[email protected]>
2025-11-23 20:41         ` Greg Burd <[email protected]>
2025-11-23 13:07   ` Greg Burd <[email protected]>

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox