From 9995c2b70f1e94ca4a97c7c585c7472cd5b2b456 Mon Sep 17 00:00:00 2001
From: "Serge S. Gulin" <gulin.serge@gmail.com>
Date: Sat, 25 Jan 2025 03:55:30 +0300
Subject: [PATCH] Support for ARM64 Windows (LLVM-enabled) (fixes #24603)

1. Add Windows AArch64 cross-compilation support via CI jobs
Introduce new CI configurations for cross-compiling to Windows ARM64 using Debian12Wine, FEX, and MSYS2.
Configure toolchain variables for LLVM MinGW and Wine emulation in CI pipelines.

2. Adjust compiler and RTS for AArch64 Windows compatibility
Reserve register `x18` on Windows and Darwin platforms in AArch64 codegen.
Handle Windows-specific relocations and data sections in AArch64 assembler.
Update PEi386 linker to recognize ARM64 binaries and support exception handling.
Adjust LLVM target definitions and data layouts for new architectures.
Update `ghc-toolchain` and build scripts to handle `TablesNextToCode` on Windows ARM64.

3. Enhance CI scripts and stability
Modify `ci.sh` to handle mingw cross-targets, fixing GHC executable paths and test execution.
Use `diff -w` in tests to ignore whitespace differences, improving cross-platform consistency.

4. Refactor and clean up code
Remove redundant imports in hello.hs test.
Improve error messages and checks for unsupported configurations in the driver.
Add `EXDEV` error code to `errno.js`.
Add async/sync flags to IO logs at `base.js`.
Improve POSIX compatibility for file close at `base.js`: decrease indeterminism for mixed cases of async and sync code.

5. Update dependencies: `Cabal`, `Win32`, `directory`, `process`, `haskeline`, and `unix`.

submodule

Co-authored-by: Cheng Shao <terrorjack@type.dance>
Co-authored-by: Dmitrii Egorov <egorov.d.i@icloud.com>
Co-authored-by: Andrei Borzenkov <root@sandwitch.dev>
---
 .gitlab-ci.yml                                |   2 +-
 .gitlab/ci.sh                                 |  31 +-
 .gitlab/generate-ci/gen_ci.hs                 |  55 +++
 .gitlab/hello.hs                              |   1 -
 .gitlab/jobs.yaml                             | 326 ++++++++++++++++++
 compiler/CodeGen.Platform.h                   |   6 +-
 compiler/GHC/CmmToAsm/AArch64/CodeGen.hs      |   7 +-
 compiler/GHC/CmmToAsm/AArch64/Instr.hs        |   2 +-
 compiler/GHC/CmmToAsm/AArch64/Ppr.hs          | 100 +++---
 compiler/GHC/CmmToAsm/Reg/Linear/AArch64.hs   |   1 +
 compiler/GHC/Driver/Session.hs                |   8 +
 compiler/GHC/Platform/Regs.hs                 |  13 +-
 hadrian/src/Oracles/Setting.hs                |   4 +
 hadrian/src/Rules/BinaryDist.hs               |   3 +-
 libraries/Cabal                               |   2 +-
 libraries/Win32                               |   2 +-
 libraries/base/src/System/CPUTime/Windows.hsc |   2 +-
 .../base/tests/perf/encodingAllocations.hs    |  10 +-
 libraries/directory                           |   2 +-
 libraries/ghc-internal/jsbits/base.js         |  83 +++--
 libraries/ghc-internal/jsbits/errno.js        |   2 +
 .../GHC/Internal/System/Posix/Internals.hs    |   2 +
 libraries/haskeline                           |   2 +-
 libraries/process                             |   2 +-
 libraries/unix                                |   2 +-
 llvm-targets                                  |   1 +
 m4/fp_cc_supports_target.m4                   |   2 +-
 m4/fptools_set_platform_vars.m4               |   2 +-
 m4/ghc_tables_next_to_code.m4                 |   9 +-
 rts/StgCRun.c                                 |   6 +-
 rts/linker/PEi386.c                           |  19 +
 rts/win32/veh_excn.c                          |  10 +
 testsuite/tests/ghc-api/fixed-nodes/all.T     |   1 -
 ...se-exports.stdout-javascript-unknown-ghcjs |   1 +
 utils/ghc-toolchain/exe/Main.hs               |   1 +
 utils/hsc2hs                                  |   2 +-
 utils/llvm-targets/gen-data-layout.sh         |   1 +
 37 files changed, 620 insertions(+), 105 deletions(-)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 168fe4b760f..107469465fa 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -2,7 +2,7 @@ variables:
   GIT_SSL_NO_VERIFY: "1"
 
   # Commit of ghc/ci-images repository from which to pull Docker images
-  DOCKER_REV: 59da90988f9f3caa36572bf47d5f78704a969dea
+  DOCKER_REV: 6e9f8f17086e56e83adae4a8a9d63e2fec3cb6c7
 
   # Sequential version number of all cached things.
   # Bump to invalidate GitLab CI cache.
diff --git a/.gitlab/ci.sh b/.gitlab/ci.sh
index 33574ac7f11..59b8d09104b 100755
--- a/.gitlab/ci.sh
+++ b/.gitlab/ci.sh
@@ -561,9 +561,17 @@ function install_bindist() {
     *)
       read -r -a args <<< "${INSTALL_CONFIGURE_ARGS:-}"
 
+      if [[ "${CROSS_TARGET:-no_cross_target}" =~ "mingw" ]]; then
+          # We suppose that host target = build target.
+          # By the fact above it is clearly turning out which host value is
+          # for currently built compiler.
+          # The fix for #21970 will probably remove this if-branch.
+          local -r CROSS_HOST_GUESS=$($SHELL ./config.guess)
+          args+=( "--target=$CROSS_TARGET" "--host=$CROSS_HOST_GUESS" )
+
       # FIXME: The bindist configure script shouldn't need to be reminded of
       # the target platform. See #21970.
-      if [ -n "${CROSS_TARGET:-}" ]; then
+      elif [ -n "${CROSS_TARGET:-}" ]; then
           args+=( "--target=$CROSS_TARGET" "--host=$CROSS_TARGET" )
       fi
 
@@ -572,7 +580,7 @@ function install_bindist() {
           "${args[@]+"${args[@]}"}" || fail "bindist configure failed"
       make_install_destdir "$TOP"/destdir "$instdir"
       # And check the `--info` of the installed compiler, sometimes useful in CI log.
-      "$instdir"/bin/ghc --info
+      "$instdir/bin/${cross_prefix}ghc$exe" --info
       ;;
   esac
   popd
@@ -629,8 +637,23 @@ function test_hadrian() {
     install_bindist _build/bindist/ghc-*/ "$instdir"
     echo 'main = putStrLn "hello world"' > expected
     run "$test_compiler" -package ghc "$TOP/.gitlab/hello.hs" -o hello
-    ${CROSS_EMULATOR:-} ./hello > actual
-    run diff expected actual
+
+    if [[ "${CROSS_TARGET:-no_cross_target}" =~ "mingw" ]]; then
+      ${CROSS_EMULATOR:-} ./hello.exe > actual
+    else
+      ${CROSS_EMULATOR:-} ./hello > actual
+    fi
+
+    # We have to use `-w` to make the test more stable across supported
+    # platforms, i.e. Windows:
+    # $ cmp expected actual
+    # differ: byte 30, line 1
+    # $ diff expected actual
+    # 1c1
+    # < main = putStrLn "hello world"
+    # ---
+    # > main = putStrLn "hello world"
+    run diff -w expected actual
   elif [[ -n "${REINSTALL_GHC:-}" ]]; then
     run_hadrian \
       test \
diff --git a/.gitlab/generate-ci/gen_ci.hs b/.gitlab/generate-ci/gen_ci.hs
index ed285ca703a..de041435e7b 100644
--- a/.gitlab/generate-ci/gen_ci.hs
+++ b/.gitlab/generate-ci/gen_ci.hs
@@ -112,6 +112,7 @@ data Opsys
 
 data LinuxDistro
   = Debian12
+  | Debian12Wine
   | Debian12Riscv
   | Debian11
   | Debian11Js
@@ -315,6 +316,7 @@ distroName Debian12      = "deb12"
 distroName Debian11      = "deb11"
 distroName Debian11Js    = "deb11-emsdk-closure"
 distroName Debian12Riscv = "deb12-riscv"
+distroName Debian12Wine  = "deb12-wine"
 distroName Debian10      = "deb10"
 distroName Debian9       = "deb9"
 distroName Fedora33      = "fedora33"
@@ -724,6 +726,8 @@ data ValidateRule
   | IpeData      -- ^ Run this job when the "IPE" label is set
   | TestPrimops  -- ^ Run this job when "test-primops" label is set
   | I386Backend  -- ^ Run this job when the "i386" label is set
+  | WinArm64     -- ^ Run this job when the "aarch64" and "Windows" labels are set together without "LLVM backend"
+  | WinArm64LLVM -- ^ Run this job when the "aarch64" and "Windows" labels are set together with "LLVM backend"
   deriving (Show, Ord, Eq)
 
 -- | Convert the state of the rule into a string that gitlab understand.
@@ -768,6 +772,15 @@ validateRuleString NonmovingGc  = labelString "non-moving GC"
 validateRuleString IpeData      = labelString "IPE"
 validateRuleString TestPrimops  = labelString "test-primops"
 validateRuleString I386Backend  = labelString "i386"
+validateRuleString WinArm64     = and_all
+                                    [ labelString "aarch64"
+                                    , labelString "Windows"
+                                    ]
+validateRuleString WinArm64LLVM = and_all
+                                    [ labelString "aarch64"
+                                    , labelString "Windows"
+                                    , validateRuleString LLVMBackend
+                                    ]
 
 ---------------------------------------------------------------------
 -- The Job type
@@ -1260,11 +1273,51 @@ cross_jobs = [
       make_wasm_jobs wasm_build_config {bignumBackend = Native}
   , modifyValidateJobs manual $
       make_wasm_jobs wasm_build_config {unregisterised = True}
+
+    -- Linux Aarch64 (Wine + FEX + MSYS64) => Windows Aarch64
+  , makeWinArmJobs
+      $ addValidateRule WinArm64
+        (validateBuilds AArch64 (Linux Debian12Wine) winAarch64Config)
+  , makeWinArmJobs
+      $ addValidateRule WinArm64LLVM
+        (validateBuilds AArch64 (Linux Debian12Wine) (winAarch64Config {llvmBootstrap = True}))
   ]
   where
     javascriptConfig = (crossConfig "javascript-unknown-ghcjs" (Emulator "js-emulator") (Just "emconfigure"))
                          { bignumBackend = Native }
 
+    makeWinArmJobs = modifyJobs
+        ( -- Cross compiler validate does not need any docs
+          setVariable "HADRIAN_ARGS" "--docs=none"
+        . setVariable "AR" (llvm_prefix ++ "llvm-ar")
+        . setVariable "CC" (llvm_prefix ++ "clang")
+        . setVariable "CXX" (llvm_prefix ++ "clang++")
+        . setVariable "NM" (llvm_prefix ++ "nm")
+        . setVariable "OBJCOPY" (llvm_prefix ++ "objcopy")
+        . setVariable "OBJDUMP" (llvm_prefix ++ "objdump")
+        . setVariable "RANLIB" (llvm_prefix ++ "llvm-ranlib")
+        . setVariable "SIZE" (llvm_prefix ++ "size")
+        . setVariable "STRINGS" (llvm_prefix ++ "strings")
+        . setVariable "STRIP" (llvm_prefix ++ "strip")
+        . setVariable "WindresCmd" (llvm_prefix ++ "windres")
+        . setVariable "LLVMAS" (llvm_prefix ++ "clang")
+        . setVariable "LD" (llvm_prefix ++ "ld")
+          -- Windows target require to make linker merge feature check disabled.
+        . setVariable "MergeObjsCmd" ""
+          -- LLVM MinGW Linux Toolchain expects to recieve "aarch64-w64-mingw32"
+          -- as a triple but we use more common "aarch64-unknown-mingw32".
+          -- Due of this we need configure ld manually for clang beacause
+          -- it will use system's ld otherwise when --target will be specified to
+          -- unexpected triple.
+        . setVariable "CFLAGS" cflags
+        . setVariable "CONF_CC_OPTS_STAGE2" cflags
+        ) where
+            llvm_prefix = "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-"
+            cflags = "-fuse-ld=" ++ llvm_prefix ++ "ld --rtlib=compiler-rt"
+
+    winAarch64Config = (crossConfig "aarch64-unknown-mingw32" (Emulator "/opt/wine-arm64ec-msys2-deb12/bin/wine") Nothing)
+                         { bignumBackend = Native }
+
     make_wasm_jobs cfg =
       modifyJobs
         ( -- See Note [Testing wasm ghci browser mode]
@@ -1323,6 +1376,7 @@ platform_mapping = Map.map go combined_result
                 , "x86_64-linux-deb11-cross_aarch64-linux-gnu-validate"
                 , "x86_64-windows-validate"
                 , "aarch64-linux-deb12-validate"
+                , "aarch64-linux-deb12-wine-int_native-cross_aarch64-unknown-mingw32-validate"
                 , "nightly-x86_64-linux-alpine3_20-wasm-cross_wasm32-wasi-release+host_fully_static+text_simdutf"
                 , "nightly-x86_64-linux-deb11-validate"
                 , "nightly-x86_64-linux-deb12-validate"
@@ -1330,6 +1384,7 @@ platform_mapping = Map.map go combined_result
                 , "x86_64-linux-deb12-validate+thread_sanitizer_cmm"
                 , "nightly-aarch64-linux-deb10-validate"
                 , "nightly-aarch64-linux-deb12-validate"
+                , "nightly-aarch64-linux-deb12-wine-int_native-cross_aarch64-unknown-mingw32-validate"
                 , "nightly-x86_64-linux-alpine3_12-validate"
                 , "nightly-x86_64-linux-deb10-validate"
                 , "nightly-x86_64-linux-fedora33-release"
diff --git a/.gitlab/hello.hs b/.gitlab/hello.hs
index 4b1c65932cc..486778c3a41 100644
--- a/.gitlab/hello.hs
+++ b/.gitlab/hello.hs
@@ -1,6 +1,5 @@
 {-# OPTIONS_GHC -Wall -Wno-missing-fields #-}
 
-import GHC.Unit.Types (stringToUnitId)
 import GHC hiding (parseModule)
 import GHC.Data.StringBuffer
 import GHC.Driver.Config.Parser
diff --git a/.gitlab/jobs.yaml b/.gitlab/jobs.yaml
index 961d10794d3..c26705a754e 100644
--- a/.gitlab/jobs.yaml
+++ b/.gitlab/jobs.yaml
@@ -315,6 +315,168 @@
       "TEST_ENV": "aarch64-linux-deb12-validate+llvm"
     }
   },
+  "aarch64-linux-deb12-wine-int_native-cross_aarch64-unknown-mingw32-validate": {
+    "after_script": [
+      ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
+      ".gitlab/ci.sh clean",
+      "cat ci_timings"
+    ],
+    "allow_failure": false,
+    "artifacts": {
+      "expire_in": "2 weeks",
+      "paths": [
+        "ghc-aarch64-linux-deb12-wine-int_native-cross_aarch64-unknown-mingw32-validate.tar.xz",
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
+      ],
+      "reports": {
+        "junit": "junit.xml"
+      },
+      "when": "always"
+    },
+    "cache": {
+      "key": "aarch64-linux-deb12-wine-$CACHE_REV",
+      "paths": [
+        "cabal-cache",
+        "toolchain"
+      ]
+    },
+    "dependencies": [],
+    "image": "registry.gitlab.haskell.org/ghc/ci-images/aarch64-linux-deb12-wine:$DOCKER_REV",
+    "needs": [
+      {
+        "artifacts": false,
+        "job": "hadrian-ghc-in-ghci"
+      }
+    ],
+    "rules": [
+      {
+        "if": "((($ONLY_JOBS) && ($ONLY_JOBS =~ /.*\\baarch64-linux-deb12-wine-int_native-cross_aarch64-unknown-mingw32-validate(\\s|$).*/)) || (($ONLY_JOBS == null) && ((($CI_MERGE_REQUEST_LABELS =~ /.*full-ci.*/) || ($CI_MERGE_REQUEST_LABELS =~ /.*marge_bot_batch_merge_job.*/) || ($CI_COMMIT_BRANCH == \"master\") || ($CI_COMMIT_BRANCH =~ /ghc-[0-9]+\\.[0-9]+/)) || (($CI_MERGE_REQUEST_LABELS =~ /.*aarch64.*/) && ($CI_MERGE_REQUEST_LABELS =~ /.*Windows.*/))))) && ($RELEASE_JOB != \"yes\") && ($NIGHTLY == null)",
+        "when": "on_success"
+      }
+    ],
+    "script": [
+      "sudo chown ghc:ghc -R .",
+      ".gitlab/ci.sh setup",
+      ".gitlab/ci.sh configure",
+      ".gitlab/ci.sh build_hadrian",
+      ".gitlab/ci.sh test_hadrian"
+    ],
+    "stage": "full-build",
+    "tags": [
+      "aarch64-linux"
+    ],
+    "variables": {
+      "AR": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-llvm-ar",
+      "BIGNUM_BACKEND": "native",
+      "BIN_DIST_NAME": "ghc-aarch64-linux-deb12-wine-int_native-cross_aarch64-unknown-mingw32-validate",
+      "BUILD_FLAVOUR": "validate",
+      "CC": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-clang",
+      "CFLAGS": "-fuse-ld=/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-ld --rtlib=compiler-rt",
+      "CONFIGURE_ARGS": "--with-intree-gmp --enable-strict-ghc-toolchain-check",
+      "CONF_CC_OPTS_STAGE2": "-fuse-ld=/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-ld --rtlib=compiler-rt",
+      "CROSS_EMULATOR": "/opt/wine-arm64ec-msys2-deb12/bin/wine",
+      "CROSS_TARGET": "aarch64-unknown-mingw32",
+      "CXX": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-clang++",
+      "HADRIAN_ARGS": "--docs=none",
+      "INSTALL_CONFIGURE_ARGS": "--enable-strict-ghc-toolchain-check",
+      "LD": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-ld",
+      "LLVMAS": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-clang",
+      "MergeObjsCmd": "",
+      "NM": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-nm",
+      "OBJCOPY": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-objcopy",
+      "OBJDUMP": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-objdump",
+      "RANLIB": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-llvm-ranlib",
+      "RUNTEST_ARGS": "",
+      "SIZE": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-size",
+      "STRINGS": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-strings",
+      "STRIP": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-strip",
+      "TEST_ENV": "aarch64-linux-deb12-wine-int_native-cross_aarch64-unknown-mingw32-validate",
+      "WindresCmd": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-windres"
+    }
+  },
+  "aarch64-linux-deb12-wine-int_native-cross_aarch64-unknown-mingw32-validate+llvm": {
+    "after_script": [
+      ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
+      ".gitlab/ci.sh clean",
+      "cat ci_timings"
+    ],
+    "allow_failure": false,
+    "artifacts": {
+      "expire_in": "2 weeks",
+      "paths": [
+        "ghc-aarch64-linux-deb12-wine-int_native-cross_aarch64-unknown-mingw32-validate+llvm.tar.xz",
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
+      ],
+      "reports": {
+        "junit": "junit.xml"
+      },
+      "when": "always"
+    },
+    "cache": {
+      "key": "aarch64-linux-deb12-wine-$CACHE_REV",
+      "paths": [
+        "cabal-cache",
+        "toolchain"
+      ]
+    },
+    "dependencies": [],
+    "image": "registry.gitlab.haskell.org/ghc/ci-images/aarch64-linux-deb12-wine:$DOCKER_REV",
+    "needs": [
+      {
+        "artifacts": false,
+        "job": "hadrian-ghc-in-ghci"
+      }
+    ],
+    "rules": [
+      {
+        "if": "((($ONLY_JOBS) && ($ONLY_JOBS =~ /.*\\baarch64-linux-deb12-wine-int_native-cross_aarch64-unknown-mingw32-validate\\+llvm(\\s|$).*/)) || (($ONLY_JOBS == null) && ((($CI_MERGE_REQUEST_LABELS =~ /.*full-ci.*/) || ($CI_MERGE_REQUEST_LABELS =~ /.*marge_bot_batch_merge_job.*/) || ($CI_COMMIT_BRANCH == \"master\") || ($CI_COMMIT_BRANCH =~ /ghc-[0-9]+\\.[0-9]+/)) || (($CI_MERGE_REQUEST_LABELS =~ /.*aarch64.*/) && ($CI_MERGE_REQUEST_LABELS =~ /.*Windows.*/) && ($CI_MERGE_REQUEST_LABELS =~ /.*LLVM backend.*/))))) && ($RELEASE_JOB != \"yes\") && ($NIGHTLY == null)",
+        "when": "on_success"
+      }
+    ],
+    "script": [
+      "sudo chown ghc:ghc -R .",
+      ".gitlab/ci.sh setup",
+      ".gitlab/ci.sh configure",
+      ".gitlab/ci.sh build_hadrian",
+      ".gitlab/ci.sh test_hadrian"
+    ],
+    "stage": "full-build",
+    "tags": [
+      "aarch64-linux"
+    ],
+    "variables": {
+      "AR": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-llvm-ar",
+      "BIGNUM_BACKEND": "native",
+      "BIN_DIST_NAME": "ghc-aarch64-linux-deb12-wine-int_native-cross_aarch64-unknown-mingw32-validate+llvm",
+      "BUILD_FLAVOUR": "validate+llvm",
+      "CC": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-clang",
+      "CFLAGS": "-fuse-ld=/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-ld --rtlib=compiler-rt",
+      "CONFIGURE_ARGS": "--with-intree-gmp --enable-strict-ghc-toolchain-check",
+      "CONF_CC_OPTS_STAGE2": "-fuse-ld=/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-ld --rtlib=compiler-rt",
+      "CROSS_EMULATOR": "/opt/wine-arm64ec-msys2-deb12/bin/wine",
+      "CROSS_TARGET": "aarch64-unknown-mingw32",
+      "CXX": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-clang++",
+      "HADRIAN_ARGS": "--docs=none",
+      "INSTALL_CONFIGURE_ARGS": "--enable-strict-ghc-toolchain-check",
+      "LD": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-ld",
+      "LLVMAS": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-clang",
+      "MergeObjsCmd": "",
+      "NM": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-nm",
+      "OBJCOPY": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-objcopy",
+      "OBJDUMP": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-objdump",
+      "RANLIB": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-llvm-ranlib",
+      "RUNTEST_ARGS": "",
+      "SIZE": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-size",
+      "STRINGS": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-strings",
+      "STRIP": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-strip",
+      "TEST_ENV": "aarch64-linux-deb12-wine-int_native-cross_aarch64-unknown-mingw32-validate+llvm",
+      "WindresCmd": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-windres"
+    }
+  },
   "i386-linux-alpine3_20-validate": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
@@ -822,6 +984,170 @@
       "XZ_OPT": "-9"
     }
   },
+  "nightly-aarch64-linux-deb12-wine-int_native-cross_aarch64-unknown-mingw32-validate": {
+    "after_script": [
+      ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
+      ".gitlab/ci.sh clean",
+      "cat ci_timings"
+    ],
+    "allow_failure": false,
+    "artifacts": {
+      "expire_in": "8 weeks",
+      "paths": [
+        "ghc-aarch64-linux-deb12-wine-int_native-cross_aarch64-unknown-mingw32-validate.tar.xz",
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
+      ],
+      "reports": {
+        "junit": "junit.xml"
+      },
+      "when": "always"
+    },
+    "cache": {
+      "key": "aarch64-linux-deb12-wine-$CACHE_REV",
+      "paths": [
+        "cabal-cache",
+        "toolchain"
+      ]
+    },
+    "dependencies": [],
+    "image": "registry.gitlab.haskell.org/ghc/ci-images/aarch64-linux-deb12-wine:$DOCKER_REV",
+    "needs": [
+      {
+        "artifacts": false,
+        "job": "hadrian-ghc-in-ghci"
+      }
+    ],
+    "rules": [
+      {
+        "if": "(\"true\" == \"true\") && ($RELEASE_JOB != \"yes\") && ($NIGHTLY)",
+        "when": "on_success"
+      }
+    ],
+    "script": [
+      "sudo chown ghc:ghc -R .",
+      ".gitlab/ci.sh setup",
+      ".gitlab/ci.sh configure",
+      ".gitlab/ci.sh build_hadrian",
+      ".gitlab/ci.sh test_hadrian"
+    ],
+    "stage": "full-build",
+    "tags": [
+      "aarch64-linux"
+    ],
+    "variables": {
+      "AR": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-llvm-ar",
+      "BIGNUM_BACKEND": "native",
+      "BIN_DIST_NAME": "ghc-aarch64-linux-deb12-wine-int_native-cross_aarch64-unknown-mingw32-validate",
+      "BUILD_FLAVOUR": "validate",
+      "CC": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-clang",
+      "CFLAGS": "-fuse-ld=/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-ld --rtlib=compiler-rt",
+      "CONFIGURE_ARGS": "--with-intree-gmp --enable-strict-ghc-toolchain-check",
+      "CONF_CC_OPTS_STAGE2": "-fuse-ld=/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-ld --rtlib=compiler-rt",
+      "CROSS_EMULATOR": "/opt/wine-arm64ec-msys2-deb12/bin/wine",
+      "CROSS_TARGET": "aarch64-unknown-mingw32",
+      "CXX": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-clang++",
+      "HADRIAN_ARGS": "--docs=none",
+      "INSTALL_CONFIGURE_ARGS": "--enable-strict-ghc-toolchain-check",
+      "LD": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-ld",
+      "LLVMAS": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-clang",
+      "MergeObjsCmd": "",
+      "NM": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-nm",
+      "OBJCOPY": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-objcopy",
+      "OBJDUMP": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-objdump",
+      "RANLIB": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-llvm-ranlib",
+      "RUNTEST_ARGS": "",
+      "SIZE": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-size",
+      "STRINGS": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-strings",
+      "STRIP": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-strip",
+      "TEST_ENV": "aarch64-linux-deb12-wine-int_native-cross_aarch64-unknown-mingw32-validate",
+      "WindresCmd": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-windres",
+      "XZ_OPT": "-9"
+    }
+  },
+  "nightly-aarch64-linux-deb12-wine-int_native-cross_aarch64-unknown-mingw32-validate+llvm": {
+    "after_script": [
+      ".gitlab/ci.sh save_cache",
+      ".gitlab/ci.sh save_test_output",
+      ".gitlab/ci.sh clean",
+      "cat ci_timings"
+    ],
+    "allow_failure": false,
+    "artifacts": {
+      "expire_in": "8 weeks",
+      "paths": [
+        "ghc-aarch64-linux-deb12-wine-int_native-cross_aarch64-unknown-mingw32-validate+llvm.tar.xz",
+        "junit.xml",
+        "unexpected-test-output.tar.gz"
+      ],
+      "reports": {
+        "junit": "junit.xml"
+      },
+      "when": "always"
+    },
+    "cache": {
+      "key": "aarch64-linux-deb12-wine-$CACHE_REV",
+      "paths": [
+        "cabal-cache",
+        "toolchain"
+      ]
+    },
+    "dependencies": [],
+    "image": "registry.gitlab.haskell.org/ghc/ci-images/aarch64-linux-deb12-wine:$DOCKER_REV",
+    "needs": [
+      {
+        "artifacts": false,
+        "job": "hadrian-ghc-in-ghci"
+      }
+    ],
+    "rules": [
+      {
+        "if": "(\"true\" == \"true\") && ($RELEASE_JOB != \"yes\") && ($NIGHTLY)",
+        "when": "on_success"
+      }
+    ],
+    "script": [
+      "sudo chown ghc:ghc -R .",
+      ".gitlab/ci.sh setup",
+      ".gitlab/ci.sh configure",
+      ".gitlab/ci.sh build_hadrian",
+      ".gitlab/ci.sh test_hadrian"
+    ],
+    "stage": "full-build",
+    "tags": [
+      "aarch64-linux"
+    ],
+    "variables": {
+      "AR": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-llvm-ar",
+      "BIGNUM_BACKEND": "native",
+      "BIN_DIST_NAME": "ghc-aarch64-linux-deb12-wine-int_native-cross_aarch64-unknown-mingw32-validate+llvm",
+      "BUILD_FLAVOUR": "validate+llvm",
+      "CC": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-clang",
+      "CFLAGS": "-fuse-ld=/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-ld --rtlib=compiler-rt",
+      "CONFIGURE_ARGS": "--with-intree-gmp --enable-strict-ghc-toolchain-check",
+      "CONF_CC_OPTS_STAGE2": "-fuse-ld=/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-ld --rtlib=compiler-rt",
+      "CROSS_EMULATOR": "/opt/wine-arm64ec-msys2-deb12/bin/wine",
+      "CROSS_TARGET": "aarch64-unknown-mingw32",
+      "CXX": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-clang++",
+      "HADRIAN_ARGS": "--docs=none",
+      "INSTALL_CONFIGURE_ARGS": "--enable-strict-ghc-toolchain-check",
+      "LD": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-ld",
+      "LLVMAS": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-clang",
+      "MergeObjsCmd": "",
+      "NM": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-nm",
+      "OBJCOPY": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-objcopy",
+      "OBJDUMP": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-objdump",
+      "RANLIB": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-llvm-ranlib",
+      "RUNTEST_ARGS": "",
+      "SIZE": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-size",
+      "STRINGS": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-strings",
+      "STRIP": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-strip",
+      "TEST_ENV": "aarch64-linux-deb12-wine-int_native-cross_aarch64-unknown-mingw32-validate+llvm",
+      "WindresCmd": "/opt/llvm-mingw-linux/bin/aarch64-w64-mingw32-windres",
+      "XZ_OPT": "-9"
+    }
+  },
   "nightly-i386-linux-alpine3_20-validate": {
     "after_script": [
       ".gitlab/ci.sh save_cache",
diff --git a/compiler/CodeGen.Platform.h b/compiler/CodeGen.Platform.h
index 78a712072d5..989528526a3 100644
--- a/compiler/CodeGen.Platform.h
+++ b/compiler/CodeGen.Platform.h
@@ -1032,11 +1032,15 @@ freeReg 29 = False
 -- ip0 -- used for spill offset computations
 freeReg 16 = False
 
-#if defined(darwin_HOST_OS) || defined(ios_HOST_OS)
+-- Note [Aarch64 Register x18 at Darwin and Windows]
+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 -- x18 is reserved by the platform on Darwin/iOS, and can not be used
 -- More about ARM64 ABI that Apple platforms support:
 -- https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms
 -- https://github.com/Siguza/ios-resources/blob/master/bits/arm64.md
+-- It is a reserved at Windows as well. Acts like TEB register in user mode at Windows.
+-- https://learn.microsoft.com/en-us/cpp/build/arm64-windows-abi-conventions
+#if defined(darwin_HOST_OS) || defined(ios_HOST_OS) || defined(mingw32_HOST_OS)
 freeReg 18 = False
 #endif
 
diff --git a/compiler/GHC/CmmToAsm/AArch64/CodeGen.hs b/compiler/GHC/CmmToAsm/AArch64/CodeGen.hs
index 300f46c2984..780af270d7c 100644
--- a/compiler/GHC/CmmToAsm/AArch64/CodeGen.hs
+++ b/compiler/GHC/CmmToAsm/AArch64/CodeGen.hs
@@ -1,5 +1,6 @@
 {-# language GADTs, LambdaCase #-}
 {-# LANGUAGE OverloadedStrings #-}
+
 module GHC.CmmToAsm.AArch64.CodeGen (
       cmmTopCodeGen
     , generateJumpTableForInstr
@@ -281,7 +282,11 @@ generateJumpTableForInstr config (J_TBL ids (Just lbl) _) =
               )
             where
               blockLabel = blockLbl blockid
-   in Just (CmmData (Section ReadOnlyData lbl) (CmmStaticsRaw lbl jumpTable))
+      sectionType = case platformOS (ncgPlatform config) of
+        -- Aarch64 Windows platform requires LLVM 20 to support .rodata
+        OSMinGW32 -> Text
+        _         -> ReadOnlyData
+   in Just (CmmData (Section sectionType lbl) (CmmStaticsRaw lbl jumpTable))
 generateJumpTableForInstr _ _ = Nothing
 
 -- -----------------------------------------------------------------------------
diff --git a/compiler/GHC/CmmToAsm/AArch64/Instr.hs b/compiler/GHC/CmmToAsm/AArch64/Instr.hs
index 968ff50063e..39182be09f6 100644
--- a/compiler/GHC/CmmToAsm/AArch64/Instr.hs
+++ b/compiler/GHC/CmmToAsm/AArch64/Instr.hs
@@ -211,7 +211,7 @@ regUsageOfInstr platform instr = case instr of
 -- | <---- argument passing -------------> | <-- callee saved (lower 64 bits) ---> | <--------------------------------------- caller saved ----------------------> |
 -- | <------ free registers -------------> | F1 | F2 | F3 | F4 | D1 | D2 | D3 | D4 | <------ free registers -----------------------------------------------------> |
 -- '---------------------------------------------------------------------------------------------------------------------------------------------------------------'
--- IR: Indirect result location register, IP: Intra-procedure register, PL: Platform register, FP: Frame pointer, LR: Link register, SP: Stack pointer
+-- IR: Indirect result location register, IP: Intra-procedure register, PL: Platform register (See Note [Aarch64 Register x18 at Darwin and Windows]), FP: Frame pointer, LR: Link register, SP: Stack pointer
 -- BR: Base, SL: SpLim
 --
 -- TODO: The zero register is currently mapped to -1 but should get it's own separate number.
diff --git a/compiler/GHC/CmmToAsm/AArch64/Ppr.hs b/compiler/GHC/CmmToAsm/AArch64/Ppr.hs
index 80fe6f02cce..25c448feaf3 100644
--- a/compiler/GHC/CmmToAsm/AArch64/Ppr.hs
+++ b/compiler/GHC/CmmToAsm/AArch64/Ppr.hs
@@ -1,5 +1,4 @@
 {-# OPTIONS_GHC -fno-warn-orphans #-}
-{-# LANGUAGE CPP #-}
 
 module GHC.CmmToAsm.AArch64.Ppr (pprNatCmmDecl, pprInstr, pprBasicBlock) where
 
@@ -43,7 +42,9 @@ pprNatCmmDecl config proc@(CmmProc top_info lbl _ (ListGraph blocks)) =
         pprSectionAlign config (Section Text lbl) $$
         -- do not
         -- pprProcAlignment config $$
-        pprLabel platform lbl $$ -- blocks guaranteed not null, so label needed
+        (if lbl /= blockLbl (blockId (head blocks)) -- blocks can have clashed names
+          then pprLabel platform lbl -- blocks guaranteed not null, so label needed
+          else empty) $$
         vcat (map (pprBasicBlock platform with_dwarf top_info) blocks) $$
         (if ncgDwarfEnabled config
          then line (pprAsmLabel platform (mkAsmTempEndLabel lbl) <> char ':') else empty) $$
@@ -461,63 +462,51 @@ pprInstr platform instr = case instr of
   STR _f o1 o2 -> op2 (text "\tstr") o1 o2
   STLR _f o1 o2 -> op2 (text "\tstlr") o1 o2
 
-#if defined(darwin_HOST_OS)
   LDR _f o1 (OpImm (ImmIndex lbl' off)) | Just (_info, lbl) <- dynamicLinkerLabelInfo lbl' ->
-    op_adrp o1 (pprAsmLabel platform lbl <> text "@gotpage") $$
-    op_ldr o1 (pprAsmLabel platform lbl <> text "@gotpageoff") $$
-    op_add o1 (char '#' <> int off) -- TODO: check that off is in 12bits.
+    let (adrp', ldr') = op_adrp_reloc_dynamic $ pprAsmLabel platform lbl in
+    op_adrp o1 (adrp') $$
+    op_ldr o1 (ldr') $$
+    op_add o1 (check_off off)
 
   LDR _f o1 (OpImm (ImmIndex lbl off)) | isForeignLabel lbl ->
-    op_adrp o1 (pprAsmLabel platform lbl <> text "@gotpage") $$
-    op_ldr o1 (pprAsmLabel platform lbl <> text "@gotpageoff") $$
-    op_add o1 (char '#' <> int off) -- TODO: check that off is in 12bits.
+    case platformOS platform of
+      OSMinGW32 ->
+        let (adrp', add') = op_adrp_reloc_local $ pprAsmLabel platform lbl in
+        op_adrp o1 (adrp') $$
+        op_add o1 add' $$
+        op_add o1 (check_off off)
+      _ ->
+        let (adrp', ldr') = op_adrp_reloc_dynamic $ pprAsmLabel platform lbl in
+        op_adrp o1 (adrp') $$
+        op_ldr o1 (ldr') $$
+        op_add o1 (check_off off)
 
   LDR _f o1 (OpImm (ImmIndex lbl off)) ->
-    op_adrp o1 (pprAsmLabel platform lbl <> text "@page") $$
-    op_add o1 (pprAsmLabel platform lbl <> text "@pageoff") $$
-    op_add o1 (char '#' <> int off) -- TODO: check that off is in 12bits.
+    let (adrp', add') = op_adrp_reloc_local $ pprAsmLabel platform lbl in
+    op_adrp o1 (adrp') $$
+    op_add o1 (add') $$
+    op_add o1 (check_off off)
 
   LDR _f o1 (OpImm (ImmCLbl lbl')) | Just (_info, lbl) <- dynamicLinkerLabelInfo lbl' ->
-    op_adrp o1 (pprAsmLabel platform lbl <> text "@gotpage") $$
-    op_ldr o1 (pprAsmLabel platform lbl <> text "@gotpageoff")
+    let (adrp', ldr') = op_adrp_reloc_dynamic $ pprAsmLabel platform lbl in
+    op_adrp o1 (adrp') $$
+    op_ldr o1 (ldr')
 
   LDR _f o1 (OpImm (ImmCLbl lbl)) | isForeignLabel lbl ->
-    op_adrp o1 (pprAsmLabel platform lbl <> text "@gotpage") $$
-    op_ldr o1 (pprAsmLabel platform lbl <> text "@gotpageoff")
+    case platformOS platform of
+      OSMinGW32 ->
+        let (adrp', add') = op_adrp_reloc_local $ pprAsmLabel platform lbl in
+        op_adrp o1 (adrp') $$
+        op_add o1 add'
+      _ ->
+        let (adrp', ldr') = op_adrp_reloc_dynamic $ pprAsmLabel platform lbl in
+        op_adrp o1 (adrp') $$
+        op_ldr o1 (ldr')
 
   LDR _f o1 (OpImm (ImmCLbl lbl)) ->
-    op_adrp o1 (pprAsmLabel platform lbl <> text "@page") $$
-    op_add o1 (pprAsmLabel platform lbl <> text "@pageoff")
-
-#else
-  LDR _f o1 (OpImm (ImmIndex lbl' off)) | Just (_info, lbl) <- dynamicLinkerLabelInfo lbl' ->
-    op_adrp o1 (text ":got:" <> pprAsmLabel platform lbl) $$
-    op_ldr o1 (text ":got_lo12:" <> pprAsmLabel platform lbl) $$
-    op_add o1 (char '#' <> int off) -- TODO: check that off is in 12bits.
-
-  LDR _f o1 (OpImm (ImmIndex lbl off)) | isForeignLabel lbl ->
-    op_adrp o1 (text ":got:" <> pprAsmLabel platform lbl) $$
-    op_ldr o1 (text ":got_lo12:" <> pprAsmLabel platform lbl) $$
-    op_add o1 (char '#' <> int off) -- TODO: check that off is in 12bits.
-
-  LDR _f o1 (OpImm (ImmIndex lbl off)) ->
-    op_adrp o1 (pprAsmLabel platform lbl) $$
-    op_add o1 (text ":lo12:" <> pprAsmLabel platform lbl) $$
-    op_add o1 (char '#' <> int off) -- TODO: check that off is in 12bits.
-
-  LDR _f o1 (OpImm (ImmCLbl lbl')) | Just (_info, lbl) <- dynamicLinkerLabelInfo lbl' ->
-    op_adrp o1 (text ":got:" <> pprAsmLabel platform lbl) $$
-    op_ldr o1 (text ":got_lo12:" <> pprAsmLabel platform lbl)
-
-  LDR _f o1 (OpImm (ImmCLbl lbl)) | isForeignLabel lbl ->
-    op_adrp o1 (text ":got:" <> pprAsmLabel platform lbl) $$
-    op_ldr o1 (text ":got_lo12:" <> pprAsmLabel platform lbl)
-
-  LDR _f o1 (OpImm (ImmCLbl lbl)) ->
-    op_adrp o1 (pprAsmLabel platform lbl) $$
-    op_add o1 (text ":lo12:" <> pprAsmLabel platform lbl)
-
-#endif
+    let (adrp', ldr') = op_adrp_reloc_local $ pprAsmLabel platform lbl in
+    op_adrp o1 adrp' $$
+    op_add o1 ldr'
 
   LDR _f o1@(OpReg W8 (RegReal (RealRegSingle i))) o2 | i < 32 ->
     op2 (text "\tldrb") o1 o2
@@ -553,6 +542,21 @@ pprInstr platform instr = case instr of
        op_adrp o1 rest     = line $ text "\tadrp" <+> pprOp platform o1 <> comma <+> rest
        op_add o1 rest      = line $ text "\tadd" <+> pprOp platform o1 <> comma <+> pprOp platform o1 <> comma <+> rest
 
+       op_adrp_reloc_dynamic asm_lbl = case platformOS platform of
+          OSDarwin -> (asm_lbl <> text "@gotpage", asm_lbl <> text "@gotpageoff")
+          OSLinux -> (text ":got:" <> asm_lbl, text ":got_lo12:" <> asm_lbl)
+          OSMinGW32 -> (text "__imp_" <> asm_lbl, text ":lo12:__imp_" <> asm_lbl)
+          os' -> pgmError $ "GHC.CmmToAsm.AArch64.Ppr.op_adrp_reloc_dynamic : " ++ show os' ++ " is unsuppported by relocations"
+
+       op_adrp_reloc_local asm_lbl = case platformOS platform of
+          OSDarwin -> (asm_lbl <> text "@page", asm_lbl <> text "@pageoff")
+          OSLinux -> (asm_lbl, text ":lo12:" <> asm_lbl)
+          OSMinGW32 -> (asm_lbl, text ":lo12:" <> asm_lbl)
+          os' -> pgmError $ "GHC.CmmToAsm.AArch64.Ppr.op_adrp_reloc_local : " ++ show os' ++ " is unsuppported by relocations"
+
+       check_off off = if off >= 0 && off <= 4095 then char '#' <> int off else
+         pgmError $ "GHC.CmmToAsm.AArch64.Ppr.check_off : " ++ show off ++ " is out of 12 bit"
+
 pprBcond :: IsLine doc => Cond -> doc
 pprBcond c = text "b." <> pprCond c
 
diff --git a/compiler/GHC/CmmToAsm/Reg/Linear/AArch64.hs b/compiler/GHC/CmmToAsm/Reg/Linear/AArch64.hs
index 64ed25e92dd..95fbe77fbb9 100644
--- a/compiler/GHC/CmmToAsm/Reg/Linear/AArch64.hs
+++ b/compiler/GHC/CmmToAsm/Reg/Linear/AArch64.hs
@@ -118,6 +118,7 @@ getFreeRegs :: RegClass -> FreeRegs -> [RealReg]
 getFreeRegs cls (FreeRegs g f) =
   case cls of
     RcFloatOrVector -> go 32 f 31
+    -- x18 is a platform-reserved register for Win/Mac and free for Linux (See Note [Aarch64 Register x18 at Darwin and Windows])
     RcInteger       -> go  0 g 18
     where
         go _   _ i | i < 0 = []
diff --git a/compiler/GHC/Driver/Session.hs b/compiler/GHC/Driver/Session.hs
index aeed58acaaf..cfdd08fd9e6 100644
--- a/compiler/GHC/Driver/Session.hs
+++ b/compiler/GHC/Driver/Session.hs
@@ -3652,6 +3652,14 @@ makeDynFlagsConsistent dflags
  , Nothing <- outputFile dflags
     = pgmError "--output must be specified when using --merge-objs"
 
+ | platformTablesNextToCode platform
+   && os == OSMinGW32
+   && arch == ArchAArch64
+    = case backendCodeOutput (backend dflags) of
+        LlvmCodeOutput -> pgmError "-fllvm is incompatible with enabled TablesNextToCode at Windows Aarch64"
+        NcgCodeOutput -> pgmError "-fasm is incompatible with enabled TablesNextToCode at Windows Aarch64"
+        _ -> (dflags, mempty, mempty)
+
   -- When we do ghci, force using dyn ways if the target RTS linker
   -- only supports dynamic code
  | LinkInMemory <- ghcLink dflags
diff --git a/compiler/GHC/Platform/Regs.hs b/compiler/GHC/Platform/Regs.hs
index 429f977a99c..bdb3a589755 100644
--- a/compiler/GHC/Platform/Regs.hs
+++ b/compiler/GHC/Platform/Regs.hs
@@ -112,7 +112,18 @@ freeReg platform
    ArchX86_64  -> X86_64.freeReg
    ArchS390X   -> S390X.freeReg
    ArchARM {}  -> ARM.freeReg
-   ArchAArch64 -> AArch64.freeReg
+   ArchAArch64 ->
+    -- See Note [Aarch64 Register x18 at Darwin and Windows].
+    -- It already has `freeReg 18 = False` but that line does not work for cross-compile when
+    -- we use host not from the list (darwin_HOST_OS, ios_HOST_OS, mingw32_HOST_OS) i.e. Linux
+    if platformOS platform == OSMinGW32 || platformOS platform == OSDarwin
+        then
+            let
+                x18Check :: RegNo -> Bool
+                x18Check 18 = False
+                x18Check a = AArch64.freeReg a
+            in x18Check
+        else AArch64.freeReg
    ArchRISCV64 -> RISCV64.freeReg
    ArchWasm32  -> Wasm32.freeReg
    ArchLoongArch64 -> LoongArch64.freeReg
diff --git a/hadrian/src/Oracles/Setting.hs b/hadrian/src/Oracles/Setting.hs
index 807fab63bfc..b6a8943abf1 100644
--- a/hadrian/src/Oracles/Setting.hs
+++ b/hadrian/src/Oracles/Setting.hs
@@ -11,6 +11,7 @@ module Oracles.Setting (
     -- ** Target platform things
     anyTargetOs, anyTargetArch, anyHostOs,
     isElfTarget, isOsxTarget, isWinTarget, isJsTarget, isArmTarget,
+    isWinHost,
     targetArmVersion
     ) where
 
@@ -156,6 +157,9 @@ getSetting = expr . setting
 bashPath :: Action FilePath
 bashPath = setting BourneShell
 
+isWinHost :: Action Bool
+isWinHost = anyHostOs [OSMinGW32]
+
 isWinTarget :: Action Bool
 isWinTarget = anyTargetOs [OSMinGW32]
 
diff --git a/hadrian/src/Rules/BinaryDist.hs b/hadrian/src/Rules/BinaryDist.hs
index 187ae211344..af8fa5c7d36 100644
--- a/hadrian/src/Rules/BinaryDist.hs
+++ b/hadrian/src/Rules/BinaryDist.hs
@@ -301,7 +301,8 @@ bindistRules = do
 
     let buildBinDist compressor = do
           win_target <- isWinTarget
-          when win_target (error "normal binary-dist does not work for Windows targets, use `reloc-binary-dist-*` target instead.")
+          win_host <- isWinHost
+          when (win_target && win_host) (error "normal binary-dist does not work at Windows, use `reloc-binary-dist-*` target instead.")
           buildBinDistX "binary-dist-dir" "bindist" compressor
         buildBinDistReloc = buildBinDistX "reloc-binary-dist-dir" "reloc-bindist"
 
diff --git a/libraries/Cabal b/libraries/Cabal
index 269fd808e5d..703582f80f6 160000
--- a/libraries/Cabal
+++ b/libraries/Cabal
@@ -1 +1 @@
-Subproject commit 269fd808e5d80223a229b6b19edfe6f5b109007a
+Subproject commit 703582f80f6d7f0c914ef4b885affcfc7b7b6ec8
diff --git a/libraries/Win32 b/libraries/Win32
index 027cbcf0de2..f340d2c3d84 160000
--- a/libraries/Win32
+++ b/libraries/Win32
@@ -1 +1 @@
-Subproject commit 027cbcf0de25d681823ea92fb545a2604c3a6a8b
+Subproject commit f340d2c3d846fce73117dd2548ad1bf0c56ceb9d
diff --git a/libraries/base/src/System/CPUTime/Windows.hsc b/libraries/base/src/System/CPUTime/Windows.hsc
index 547e7fa4805..4bae075d464 100644
--- a/libraries/base/src/System/CPUTime/Windows.hsc
+++ b/libraries/base/src/System/CPUTime/Windows.hsc
@@ -60,7 +60,7 @@ type HANDLE = ()
 #if defined(i386_HOST_ARCH)
 foreign import stdcall unsafe "GetCurrentProcess" getCurrentProcess :: IO (Ptr HANDLE)
 foreign import stdcall unsafe "GetProcessTimes" getProcessTimes :: Ptr HANDLE -> Ptr FILETIME -> Ptr FILETIME -> Ptr FILETIME -> Ptr FILETIME -> IO CInt
-#elif defined(x86_64_HOST_ARCH)
+#elif defined(x86_64_HOST_ARCH) || defined(aarch64_HOST_ARCH)
 foreign import ccall unsafe "GetCurrentProcess" getCurrentProcess :: IO (Ptr HANDLE)
 foreign import ccall unsafe "GetProcessTimes" getProcessTimes :: Ptr HANDLE -> Ptr FILETIME -> Ptr FILETIME -> Ptr FILETIME -> Ptr FILETIME -> IO CInt
 #else
diff --git a/libraries/base/tests/perf/encodingAllocations.hs b/libraries/base/tests/perf/encodingAllocations.hs
index cd136963cb9..58b31b08533 100755
--- a/libraries/base/tests/perf/encodingAllocations.hs
+++ b/libraries/base/tests/perf/encodingAllocations.hs
@@ -13,13 +13,13 @@ import Distribution.Simple.Utils
 
 
 main :: IO ()
-main = withTempFile "." "encodingAllocations.tmp" (const $ loop 1000000)
+main = withTempFile "encodingAllocations.tmp" (loop 1000000)
 
-loop :: Int -> Handle -> IO ()
-loop 0  !_ = pure ()
-loop !n !h = do
+loop :: Int -> FilePath -> Handle -> IO ()
+loop 0  !_ !_ = pure ()
+loop !n !fp !h = do
   hPutChar h $! dummy_char n
-  loop (n-1) h
+  loop (n-1) fp h
 
 -- unsafe efficient version of `chr`
 my_chr :: Int -> Char
diff --git a/libraries/directory b/libraries/directory
index 005fa061171..eb40bbebcaf 160000
--- a/libraries/directory
+++ b/libraries/directory
@@ -1 +1 @@
-Subproject commit 005fa061171a55d35ce8dfe936cf3703525a8616
+Subproject commit eb40bbebcaf86153bbc60772fb2e0466d35c95c4
diff --git a/libraries/ghc-internal/jsbits/base.js b/libraries/ghc-internal/jsbits/base.js
index 9150799d130..d7a78a46379 100644
--- a/libraries/ghc-internal/jsbits/base.js
+++ b/libraries/ghc-internal/jsbits/base.js
@@ -44,30 +44,45 @@ function h$base_close(fd, c) {
 }
 
 function h$close(fd,c) {
-  if (c) {
-    //asynchronous
-    var fdo = h$base_fds[fd];
-    if(fdo) {
+  var fdo = h$base_fds[fd];
+
+  // File descriptor was closed already?
+  // It may happen only if its reference count reached <1 and actual closing is processed at underlying fd
+  if (!fdo) {
+    h$setErrno('EINVAL');
+
+    if (c) {
+      TRACE_IO("base_close: file descriptor not found, already closed?")
+      c(-1);
+      return;
+    }
+
+    TRACE_IO("base_close sync: file descriptor not found, already closed?")
+    return (-1);
+  }
+
+  fdo.refs--;
+
+  if (fdo.refs < 1) {
+    // Process closing at underlying fd
+
+    if (c) {
+      TRACE_IO("base_close: closing underlying fd")
+      if (fdo.close) {
+        fdo.close(fd, fdo, c);
+      } else {
+        TRACE_IO("base_close: no actual underlying fd close, dummy implementation")
         delete h$base_fds[fd];
-        if(--fdo.refs < 1) {
-          TRACE_IO("base_close: closing underlying fd")
-          if(fdo.close) {
-            fdo.close(fd, fdo, c);
-          } else {
-            c(0);
-          }
-        } else {
-          TRACE_IO("base_close: remaining references, not closing underlying fd")
-          c(0);
-        }
-    } else {
-        TRACE_IO("base_close: file descriptor not found, already closed?")
-        h$errno = CONST_EINVAL;
-        c(-1);
+        c(0);
+      }
+      return;
     }
-  } else {
-    //synchronous
+
+    TRACE_IO("base_close sync: closing underlying fd")
     try {
+      // See: https://nodejs.org/api/fs.html#fsclosesyncfd
+      // Calling fs.closeSync() on any file descriptor (fd) that is currently in use through any other fs operation may lead to undefined behavior.
+      delete h$base_fds[fd];
       h$fs.closeSync(fd);
       return 0;
     } catch(err) {
@@ -75,6 +90,16 @@ function h$close(fd,c) {
       return (-1);
     }
   }
+
+  // Dummy process closing due of remaining references
+  if (c) {
+    TRACE_IO("base_close: remaining references, not closing underlying fd")
+    c(0);
+    return;
+  }
+
+  TRACE_IO("base_close sync: remaining references, not closing underlying fd")
+  return 0;
 }
 
 function h$base_dup(fd, c) {
@@ -122,7 +147,7 @@ function h$base_dup2(fd, new_fd, c) {
 }
 
 function h$base_fstat(fd, stat, stat_off, c) {
-    TRACE_IO("base_stat")
+    TRACE_IO("base_fstat")
 #ifndef GHCJS_BROWSER
     if(h$isNode()) {
         h$fs.fstat(fd, function(err, fs) {
@@ -384,11 +409,13 @@ function h$rmdir(file, file_off) {
 }
 
 function h$rename(old_path, old_path_off, new_path, new_path_off) {
-  TRACE_IO("rename")
+  var old_path_str = h$decodeUtf8z(old_path, old_path_off);
+  var new_path_str = h$decodeUtf8z(new_path, new_path_off);
+  TRACE_IO("rename sync: " + old_path_str + " -> " + new_path_str)
 #ifndef GHCJS_BROWSER
   if (h$isNode()) {
     try {
-      h$fs.renameSync(h$decodeUtf8z(old_path, old_path_off), h$decodeUtf8z(new_path, new_path_off));
+      h$fs.renameSync(old_path_str, new_path_str);
       return 0;
     } catch(e) {
       h$setErrno(e);
@@ -473,11 +500,13 @@ function h$calculate_at(dirfd, file, file_off) {
 
 function h$openat(dirfd, file, file_off, how, mode, c) {
   var path = h$calculate_at(dirfd, file, file_off);
+  TRACE_IO("openat" + (!!c ? ": " : " sync: ") + path)
   return h$base_open(path, how, mode, c);
 }
 
 function h$open(file, file_off, how, mode, c) {
   var path = h$decodeUtf8z(file, file_off);
+  TRACE_IO("open" + (!!c ? ": " : " sync: ") + path)
   return h$base_open(path, how, mode, c);
 }
 
@@ -485,7 +514,7 @@ function h$base_open(fp, how, mode, c) {
 #ifndef GHCJS_BROWSER
     if(h$isNode()) {
         var flags, off;
-        TRACE_IO("open: " + fp)
+        TRACE_IO("base_open" + (!!c ? ": " : " sync: ") + fp)
         var acc  = how & h$base_o_accmode;
         // passing a number lets node.js use it directly as the flags (undocumented)
         if(acc === h$base_o_rdonly) {
@@ -539,7 +568,7 @@ function h$base_open(fp, how, mode, c) {
                                        , pos:   p
                                        , refs:  1
                                        };
-                      TRACE_IO("open: " + fp + " -> " + fd)
+                      TRACE_IO("base_open sync: " + fp + " -> " + fd)
                   }
             if(off === -1) {
               var fs = h$fs.statSync(fp);
@@ -944,8 +973,8 @@ if(h$isNode()) {
     h$base_closeFile = function(fd, fdo, c) {
         TRACE_IO("base_closeFile: " + fd + " (" + fdo.fd + ")")
         var real_fd = typeof fdo.fd === 'number' ? fdo.fd : fd;
+        delete h$base_fds[fd];
         h$fs.close(real_fd, function(err) {
-            delete h$base_fds[fd];
             h$handleErrnoC(err, -1, 0, c);
         });
     }
diff --git a/libraries/ghc-internal/jsbits/errno.js b/libraries/ghc-internal/jsbits/errno.js
index ff31029baaa..7bfd3dae838 100644
--- a/libraries/ghc-internal/jsbits/errno.js
+++ b/libraries/ghc-internal/jsbits/errno.js
@@ -52,6 +52,7 @@ function h$setErrno(e) {
       if(es.indexOf('EBADF') !== -1)        return CONST_EBADF;
       if(es.indexOf('ENOSPC') !== -1)       return CONST_ENOSPC;
       if(es.indexOf('EACCES') !== -1)       return CONST_EACCES;
+      if(es.indexOf('EXDEV') !== -1)        return CONST_EXDEV;
       if(es.indexOf('Bad argument') !== -1) return CONST_ENOENT; // fixme?
       throw ("setErrno not yet implemented for: " + e);
 
@@ -72,6 +73,7 @@ var h$errorStrs =  { CONST_E2BIG:   "Argument list too long"
                    , CONST_EPIPE:   "Broken pipe"
                    , CONST_EAGAIN:  "Resource temporarily unavailable"
                    , CONST_ESPIPE:  "Illegal seek"
+                   , CONST_EXDEV:   "Cross-device link" // See https://en.cppreference.com/w/cpp/error/errno_macros
                    }
 
 function h$handleErrno(r_err, f) {
diff --git a/libraries/ghc-internal/src/GHC/Internal/System/Posix/Internals.hs b/libraries/ghc-internal/src/GHC/Internal/System/Posix/Internals.hs
index db100866e0a..7fd0fe75159 100644
--- a/libraries/ghc-internal/src/GHC/Internal/System/Posix/Internals.hs
+++ b/libraries/ghc-internal/src/GHC/Internal/System/Posix/Internals.hs
@@ -556,6 +556,8 @@ foreign import javascript interruptible "h$open"
    c_interruptible_open_ :: CFilePath -> CInt -> CMode -> IO CInt
 foreign import javascript interruptible "h$open"
    c_safe_open_ :: CFilePath -> CInt -> CMode -> IO CInt
+foreign import javascript interruptible "h$openat"
+   c_openat :: CInt -> CFilePath -> CInt -> CMode -> IO CInt
 foreign import javascript interruptible "h$base_read"
    c_read :: CInt -> Ptr Word8 -> CSize -> IO CSsize
 foreign import javascript interruptible "h$base_read"
diff --git a/libraries/haskeline b/libraries/haskeline
index 5f4bf62bf1f..5f1a790a5db 160000
--- a/libraries/haskeline
+++ b/libraries/haskeline
@@ -1 +1 @@
-Subproject commit 5f4bf62bf1f4846ad0b8d1fa9d45f902e3934511
+Subproject commit 5f1a790a5db1cb3708d105d4f532c32fcbeb4296
diff --git a/libraries/process b/libraries/process
index 9c3bfc214c7..fbbe6071873 160000
--- a/libraries/process
+++ b/libraries/process
@@ -1 +1 @@
-Subproject commit 9c3bfc214c72bbd0c8a30a1c41465deed0feaf47
+Subproject commit fbbe60718736999db701c12528c85cbc605ab4fb
diff --git a/libraries/unix b/libraries/unix
index 74ae1c0d9dd..47d5fc4a8f1 160000
--- a/libraries/unix
+++ b/libraries/unix
@@ -1 +1 @@
-Subproject commit 74ae1c0d9dd1518434f7d6cd3e63d7769599e0f9
+Subproject commit 47d5fc4a8f19207819030725e7de23c65fa61a04
diff --git a/llvm-targets b/llvm-targets
index c42f3e7d8b2..daafe8c18fc 100644
--- a/llvm-targets
+++ b/llvm-targets
@@ -1,4 +1,5 @@
 [("x86_64-unknown-windows-gnu", ("e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128", "x86-64", ""))
+,("aarch64-unknown-windows-gnu", ("e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128-Fn32", "generic", "+v8a +fp-armv8 +neon"))
 ,("arm-unknown-linux-gnueabi", ("e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64", "arm7tdmi", "+strict-align"))
 ,("arm-unknown-linux-gnueabihf", ("e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64", "arm1176jzf-s", "+strict-align"))
 ,("arm-unknown-linux-musleabihf", ("e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64", "arm1176jzf-s", "+strict-align"))
diff --git a/m4/fp_cc_supports_target.m4 b/m4/fp_cc_supports_target.m4
index a8b8bf90743..177c9824bd9 100644
--- a/m4/fp_cc_supports_target.m4
+++ b/m4/fp_cc_supports_target.m4
@@ -20,7 +20,7 @@ AC_DEFUN([FP_CC_SUPPORTS_TARGET],
        # See Note [Don't pass --target to emscripten toolchain] in GHC.Toolchain.Program
        CONF_CC_SUPPORTS_TARGET=NO
        AC_MSG_RESULT([no])
-   elif $1 --target=$LlvmTarget -Werror conftest.c > /dev/null 2>&1 ; then
+   elif $1 --target=$LlvmTarget -Werror -c conftest.c > /dev/null 2>&1 ; then
        CONF_CC_SUPPORTS_TARGET=YES
        AC_MSG_RESULT([yes])
    else
diff --git a/m4/fptools_set_platform_vars.m4 b/m4/fptools_set_platform_vars.m4
index 4c022da52b0..3f82257501e 100644
--- a/m4/fptools_set_platform_vars.m4
+++ b/m4/fptools_set_platform_vars.m4
@@ -93,7 +93,7 @@ AC_DEFUN([FPTOOLS_OVERRIDE_PLATFORM_FROM_BOOTSTRAP],
 
 # FPTOOLS_SET_PLATFORM_VARS(platform,Platform)
 # ----------------------------------
-# Set the platform variables for a single plaform (one of build, host,
+# Set the platform variables for a single platform (one of build, host,
 # or target). Assumes <platform>Arch, <platform>Vendor, and <platform>OS
 # are defined, and does everything else in terms of them.
 AC_DEFUN([FPTOOLS_SET_PLATFORM_VARS],
diff --git a/m4/ghc_tables_next_to_code.m4 b/m4/ghc_tables_next_to_code.m4
index 3e0ced2137d..9bf473a712c 100644
--- a/m4/ghc_tables_next_to_code.m4
+++ b/m4/ghc_tables_next_to_code.m4
@@ -22,8 +22,13 @@ AC_DEFUN([GHC_TABLES_NEXT_TO_CODE],
                   AC_MSG_RESULT([no])
                   ;;
               *)
-                  TablesNextToCodeDefault=YES
-                  AC_MSG_RESULT([yes])
+                  if test "$TargetOS" = "mingw32" && test "$TargetArch" = "aarch64"; then
+                    TablesNextToCodeDefault=NO
+                    AC_MSG_RESULT([no])
+                  else
+                    TablesNextToCodeDefault=YES
+                    AC_MSG_RESULT([yes])
+                  fi
                   ;;
           esac
           ;;
diff --git a/rts/StgCRun.c b/rts/StgCRun.c
index 2e283a73bfe..fe6cde6f999 100644
--- a/rts/StgCRun.c
+++ b/rts/StgCRun.c
@@ -863,8 +863,12 @@ StgRun(StgFunPtr f, StgRegTable *basereg) {
          */
         "br %1\n\t"
 
+#if defined(mingw32_HOST_OS)
+        ".globl " STG_RETURN "\n"
+#else
         ".globl " STG_RETURN "\n\t"
-#if !defined(ios_HOST_OS) && !defined(darwin_HOST_OS)
+#endif
+#if !defined(ios_HOST_OS) && !defined(darwin_HOST_OS) && !defined(mingw32_HOST_OS)
         ".type " STG_RETURN ", %%function\n"
 #endif
         STG_RETURN ":\n\t"
diff --git a/rts/linker/PEi386.c b/rts/linker/PEi386.c
index 5f22d74da87..8764c173274 100644
--- a/rts/linker/PEi386.c
+++ b/rts/linker/PEi386.c
@@ -1195,6 +1195,12 @@ verifyCOFFHeader ( uint16_t machine, IMAGE_FILE_HEADER *hdr,
       errorBelch("%" PATH_FMT ": Not a x86_64 PE+ file.", fileName);
       return false;
    }
+#elif defined(aarch64_HOST_ARCH)
+   if (machine != IMAGE_FILE_MACHINE_ARM64) {
+      errorBelch("%" PATH_FMT ": Not a ARM64 PE+ file.", fileName);
+      return false;
+   }
+   errorBelch("PE/PE+ not supported on ARM64.");
 #else
    errorBelch("PE/PE+ not supported on this arch.");
 #endif
@@ -2132,6 +2138,19 @@ ocResolve_PEi386 ( ObjectCode* oc )
                    *(uint32_t *)pP = (uint32_t)v;
                    break;
                }
+#elif defined(aarch64_HOST_ARCH)
+            case 1: // IMAGE_REL_ARM64_ADDR32, see https://llvm.org/doxygen/namespacellvm_1_1COFF.html, https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#arm64-processors
+               {
+                    // We have to put this stub due of errors like:
+                    // warning: variable 'A' set but not used.
+                    uint64_t v;
+                    v = S + A;
+
+                    debugBelch("%" PATH_FMT ": Catch ARM64 PEi386 relocation type %d, %llx\n",
+                        oc->fileName, reloc->Type, v);
+                    releaseOcInfo (oc);
+                    return false;
+               }
 #endif
             default:
                debugBelch("%" PATH_FMT ": unhandled PEi386 relocation type %d\n",
diff --git a/rts/win32/veh_excn.c b/rts/win32/veh_excn.c
index 999580c7ef3..183c4657e9a 100644
--- a/rts/win32/veh_excn.c
+++ b/rts/win32/veh_excn.c
@@ -287,6 +287,16 @@ void generateStack (EXCEPTION_POINTERS* pExceptionPointers)
 
     stackFrame.AddrStack.Offset = context->Rsp;
     stackFrame.AddrStack.Mode = AddrModeFlat;
+#elif defined(aarch64_HOST_ARCH)
+    machineType = IMAGE_FILE_MACHINE_ARM64;
+    stackFrame.AddrPC.Offset = context->Pc;
+    stackFrame.AddrPC.Mode = AddrModeFlat;
+
+    stackFrame.AddrFrame.Offset = context->Fp;
+    stackFrame.AddrFrame.Mode = AddrModeFlat;
+
+    stackFrame.AddrStack.Offset = context->Sp;
+    stackFrame.AddrStack.Mode = AddrModeFlat;
 #endif
     fprintf (stderr, "\n Attempting to reconstruct a stack trace...\n\n");
     if (!SymInitialize (GetCurrentProcess (), NULL, true))
diff --git a/testsuite/tests/ghc-api/fixed-nodes/all.T b/testsuite/tests/ghc-api/fixed-nodes/all.T
index 7d512269d25..961b3e66172 100644
--- a/testsuite/tests/ghc-api/fixed-nodes/all.T
+++ b/testsuite/tests/ghc-api/fixed-nodes/all.T
@@ -2,7 +2,6 @@ test('FixedNodes',
      [extra_run_opts(f'"{config.libdir}"'),
      extra_files(['T1A.hs', 'T1B.hs', 'T1C.hs']),
      wasm_broken(25953),
-     js_broken(25953)
      ],
      compile_and_run,
      ['-package ghc'])
diff --git a/testsuite/tests/interface-stability/base-exports.stdout-javascript-unknown-ghcjs b/testsuite/tests/interface-stability/base-exports.stdout-javascript-unknown-ghcjs
index 43f9b7bcb2c..d67be89fb65 100644
--- a/testsuite/tests/interface-stability/base-exports.stdout-javascript-unknown-ghcjs
+++ b/testsuite/tests/interface-stability/base-exports.stdout-javascript-unknown-ghcjs
@@ -13536,6 +13536,7 @@ module System.Posix.Internals where
   c_lseek :: GHC.Internal.Foreign.C.Types.CInt -> GHC.Internal.System.Posix.Types.COff -> GHC.Internal.Foreign.C.Types.CInt -> GHC.Internal.Types.IO GHC.Internal.System.Posix.Types.COff
   c_mkfifo :: GHC.Internal.Foreign.C.String.Encoding.CString -> GHC.Internal.System.Posix.Types.CMode -> GHC.Internal.Types.IO GHC.Internal.Foreign.C.Types.CInt
   c_open :: CFilePath -> GHC.Internal.Foreign.C.Types.CInt -> GHC.Internal.System.Posix.Types.CMode -> GHC.Internal.Types.IO GHC.Internal.Foreign.C.Types.CInt
+  c_openat :: GHC.Internal.Foreign.C.Types.CInt -> CFilePath -> GHC.Internal.Foreign.C.Types.CInt -> GHC.Internal.System.Posix.Types.CMode -> GHC.Internal.Types.IO GHC.Internal.Foreign.C.Types.CInt
   c_pipe :: GHC.Internal.Ptr.Ptr GHC.Internal.Foreign.C.Types.CInt -> GHC.Internal.Types.IO GHC.Internal.Foreign.C.Types.CInt
   c_read :: GHC.Internal.Foreign.C.Types.CInt -> GHC.Internal.Ptr.Ptr GHC.Internal.Word.Word8 -> GHC.Internal.Foreign.C.Types.CSize -> GHC.Internal.Types.IO GHC.Internal.System.Posix.Types.CSsize
   c_s_isblk :: GHC.Internal.System.Posix.Types.CMode -> GHC.Internal.Foreign.C.Types.CInt
diff --git a/utils/ghc-toolchain/exe/Main.hs b/utils/ghc-toolchain/exe/Main.hs
index 71faaf79a17..7e75e7b1bb3 100644
--- a/utils/ghc-toolchain/exe/Main.hs
+++ b/utils/ghc-toolchain/exe/Main.hs
@@ -348,6 +348,7 @@ tablesNextToCodeSupported archOs =
       ArchPPC      -> False
       ArchPPC_64 _ -> False
       ArchS390X    -> False
+      ArchAArch64  -> archOS_OS archOs /= OSMinGW32
       _            -> True
 
 determineTablesNextToCode
diff --git a/utils/hsc2hs b/utils/hsc2hs
index c3b21800a67..2fab2f4cdff 160000
--- a/utils/hsc2hs
+++ b/utils/hsc2hs
@@ -1 +1 @@
-Subproject commit c3b21800a67366c9591dc85a471d1dfdb1efcf29
+Subproject commit 2fab2f4cdffef12afe561ef03f5ebdace7dbae67
diff --git a/utils/llvm-targets/gen-data-layout.sh b/utils/llvm-targets/gen-data-layout.sh
index 2f50bf15de3..b594f141a93 100755
--- a/utils/llvm-targets/gen-data-layout.sh
+++ b/utils/llvm-targets/gen-data-layout.sh
@@ -27,6 +27,7 @@ TARGETS=(
 
     # Windows
     "x86_64-unknown-windows-gnu"
+    "aarch64-unknown-windows-gnu"
 
     #########################
     # Linux
-- 
GitLab