Does MSVC predefine __x86_64__ on 64-bit Intel?

First seen: 2026-06-03 16:17:10+00:00 · Messages: 5 · Participants: 3

Latest Update

2026-06-04 · claude-opus-4-6

Technical Analysis: MSVC Predefined Architecture Macros and x86_64

Core Problem

Tom Lane identified a latent portability and correctness issue in PostgreSQL's preprocessor-based architecture detection, specifically around how MSVC (Microsoft's C/C++ compiler) handles CPU architecture identification macros.

The Specific Issue

PostgreSQL's codebase uses GCC-style predefined macros (__x86_64__, __i386__, __aarch64__) to gate architecture-specific code paths — particularly for atomics, SIMD optimizations, and other low-level CPU features. The problem manifests in two ways:

  1. MSVC does NOT define __x86_64__ or __i386__ — it uses its own _M_X64 and _M_IX86 macros instead. This means conditional compilation guards that only check for GCC-style macros silently exclude MSVC builds from CPU-specific optimizations.

  2. _M_X64 is now semantically broken — Microsoft's ARM64EC (Emulation Compatible) mode defines _M_X64 even when compiling for ARM64 hardware. ARM64EC is a compatibility layer that allows x64 binaries to run on ARM Windows via emulation, but the code is actually compiled for ARM64. This means _M_X64 no longer reliably indicates Intel/AMD x86-64 hardware.

Why This Matters Architecturally

The architecture detection macros gate critical low-level code:

The current code in arch-x86.h demonstrates the bug clearly:

// The include guard checks:
#elif defined(__i386__) || defined(__i386) || defined(__x86_64__)
#include "port/atomics/arch-x86.h"

// But inside the file:
#if defined(__x86_64__) || defined(__x86_64) || defined(_M_X64)

The _M_X64 check inside the file is dead code because the file can never be reached via _M_X64 alone — the outer include guard doesn't test for it. This reveals that MSVC builds on x64 are potentially missing architecture-specific atomic implementations, falling back to generic (slower) versions.

Proposed Solution

Tom Lane proposes a centralized approach:

  1. Create a central header that, on MSVC builds, defines the GCC-style macros (__x86_64__, __i386__, __aarch64__, __arm__) based on MSVC's own _M_X64, _M_IX86, _M_ARM64, _M_ARM — but with proper ARM64EC awareness.

  2. Remove all direct references to _M_X64 and _M_AMD64 from architecture selection code (only ~3 references each).

  3. Standardize on GCC-style macros as the canonical architecture identifiers throughout the codebase, regardless of compiler.

  4. Clean up dead references to __i386 (double-underscore only on left), which were historically needed for Sun Studio but are now redundant after commit 25f36066d removed Sun Studio support.

This is analogous to the pattern PostgreSQL previously used for Sun Studio — defining GCC-compatible macros in a central location so that architecture-detection code doesn't need per-compiler conditionals scattered throughout.

Potential Risk

Defining __x86_64__ on MSVC might expose hidden compiler dependencies in code currently guarded by that macro. Some code paths might use GCC-specific intrinsics or inline assembly syntax that MSVC doesn't support. Tom acknowledges this and proposes using explicit _MSC_VER guards where compiler-specific (as opposed to architecture-specific) behavior is needed.

ARM64EC Complication

The ARM64EC issue is particularly insidious. Microsoft documents:

_M_X64: Defined as the integer literal value 100 for compilations that target x64 processors or ARM64EC.

This means any code using _M_X64 to select x86-64-specific instructions (e.g., _mm_crc32_u64, x86 atomics, SSE intrinsics) would miscompile in an ARM64EC build — attempting to use x86 intrinsics on ARM hardware. While PostgreSQL likely doesn't have ARM64EC builds today, the semantic breakage makes _M_X64 a ticking time bomb that shouldn't be relied upon for architecture detection.

Prior Art

Nathan Bossart pointed to related threads by John Naylor (Munro) that had already identified overlapping issues with architecture macro handling, suggesting this cleanup was already partially in flight or at least well-understood by the community.

Status

The thread is in early discussion/discovery phase. Tom Lane indicated intent to prepare a cleanup patch but discovered via Nathan's links that related work was already underway. The thread effectively concludes with Tom acknowledging the prior work.