Add complete ARM64 Windows (AArch64 WoA) support to SBCL. This
enables building and running SBCL natively on Windows 11 ARM devices.
Key design decisions:
- x18 register reserved as TEB pointer (Windows ARM64 ABI requirement),
matching the existing Darwin reservation
- Safepoint GC with fake_foreign_function_call to save register context
for precise stack scanning (ARM64 uses separate C and control stacks)
- VEH (Vectored Exception Handling) for ARM64, decoding BRK instructions
which Windows reports as EXCEPTION_ILLEGAL_INSTRUCTION
- sb_udivmodti4 takes hi/lo split arguments to avoid __uint128_t ABI
issues on LLP64 where unsigned long is 32 bits
- FP exception traps disabled (ARM64 Windows does not deliver FP
exceptions even with FPCR trap bits set)
- Dynamic space pages committed on demand (Windows reserves but does
not commit the full dynamic space upfront)
New files:
- src/runtime/Config.arm64-win32: Build configuration
- src/runtime/arm64-win32-os.c: OS layer (VEH, context access, FP)
- src/runtime/arm64-win32-os.h: Platform header
- .github/workflows/windows-arm64.yml: CI workflow
Modified files grouped by subsystem:
Runtime (ARM64-specific):
- arm64-arch.c: Windows memory APIs, LLP64-safe pointer storage,
sb_udivmodti4 split-argument ABI, static space NIL header guard
- arm64-assem.S: Windows calling conventions for call_into_lisp and
call_into_c, TlsGetValue for thread pointer, x18 reservation
Runtime (Windows general):
- win32-os.c: ARM64 safepoint page handling, BRK exception decode,
ARM64 VEH, dynamic space page commit, ARM64 debug printing
Compiler:
- vm.lisp: Reserve x18 on Windows (matching Darwin)
- c-call.lisp: Don't zero control-stack-pointer on Windows (not FFCA)
- parms.lisp: Address space layout for Windows ARM64
- tramps.lisp: Save CSP to thread for GC, don't zero CSP on Windows
- genesis.lisp: GC_SAFEPOINT_PAGE_ADDR for non-x86-64 platforms
- parms.lisp (generic): Update safepoint space comment
- debug-int.lisp: NFP handling for ARM64 Windows
- float-trap.lisp: Disable FP traps on ARM64 Windows
- coreparse.c: ARM64 guard for TEXT_SPACE_START assignment
Build system:
- make-config.sh: ARM64 Windows detection and feature flags
- make-windows-installer.sh: ARM64 architecture in installer
CI:
- linux-arm64.yml, mac.yml: Robustness fixes for repo naming
- windows-arm64.yml: New workflow for ARM64 Windows builds
Tests:
- subr.sh: Auto-detect sbcl.exe on Windows
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
I'm not sure which test to blame: sb-posix.impure for being too sensitive
or run-sbcl.test.sh for changing the source tree.
I kinda feel that affecting the tree is the greater sin but I could also
see an argument that the DIRECTORY test needs better isolation.
Anything that invokes 'use_test_subdirectory' should go to /tmp, not just
a few scripts that overrode TEST_BASEDIR. After this there are approximately
6 files that will fail if pwd isn't writable. Most involve run-compiler.sh
and also filesys tests. Plus there's a hack in run-sbcl.sh without which
it would already fail when writing into /tmp.
Solaris' /bin/sh does not grok $(...), so use `...` instead.
Note that all recent versions of Solaris have included /bin/bash, but
I'm not sure the impact of using #!/bin/bash instead of #!/bin/sh on
some of our other platforms.
Allow override of SBCL location via TEST_SBCL_HOME,
TEST_SBCL_RUNTIME, and TEST_SBCL_CORE.
Allow override of temporary file location via TEST_DIRECTORY. (Some
tests still write to /tmp, though -- so user beware!)
Small unrelated whitespace / style-warning fixes.
MERGE-PATHNAMES to get an absolute pathname. (Using TRUENAME would be wrong,
since then we would delete files pointed to by symbolic links, and not the
symbolic links themselves -- a nasty regression that would be!)
Also remove the "for error checking" TRUENAME call from there: unlink will
give us an errno that tells what we need to know -- and lo! there is one
race condition less in the system.
Previously using relative pathnames it was possible to accidentally delete
the wrong file.
Fixes lp#882877.
NB: currently DELETE-DIRECTORY and RENAME-FILE use TRUENAME with just the
aforementioned unfortunate consequence, but I'm hesitant to change them
during the freeze -- so dealing with this issue in them will have to
wait a bit.
* Patch by Josh Elsasser, lp#615497.
* Fixes for run-sbcl.sh and tests/subr.sh on Solaris, some of which I
believe were also necessary on FreeBSD.
* A missing #include needed on Solaris is also added.
* Tests written in shell modified to use shell functions, rather than
variables, so that tests written in shell can run when the build
directory's absolute pathname contains whitespace (as home
directories might tend to on Windows).
* tests/subr.sh: new file, with some shell functions, variables, and
settings to support the above. Files in the test suite written in
shell should source this file.
* Factored code for creating and cleaning up temporary directories for
tests written in shell that touch the file system. Test scripts
written in shell should now call "use_test_subdirectory" to create
and chdir to a test directory, and the shell should clean out the
test directory at exit time.
* Most tests written in shell now quote filenames that derive from the
truename of the current working directory or from an environment
variable, as such names may contain whitespace. (Variables set to
non-offending constant strings in the script itself need not be
quoted this way.)
* tests/filesys.test.sh was not prepared to deal with a TRUENAME that
resolves all symbolic links in a pathname, as a soon-to-be-committed
TRUENAME will; "/tmp" on MacOSX is a symbolic link to
"/private/tmp". POSIX pwd(1) takes a -P option to resolve symbolic
links in the working directory's path, so we'll try that.
* Tests now supply --no-userinit, --no-sysinit arguments, so that we
don't need to conditionalize these for win32.
* Some tests written in shell changed from using --eval <string> to
heredocs, which allows the Lisp code the be formatted nicer and
avoids some shell quotation headaches (not all, of course).
* Minor shell errors corrected in some tests. Notable example:
program; if [ $? != $value ]; then echo failed $?; fi
Because "[" is a child process, after the test $? is set to the exit
status of the "["; the exit status of "program" is lost.