Admin message

Due to a large amount of spam we do not allow new users to create repositories, they are "external" users. If you are a new user and want to create a repository, for example for forking GHC, open a new issue on ghc/ghc using the "get-verified" issue template

Stack alignment on x86(-64) with AVX/AVX-512
## Summary On x86-64 with AVX enabled, we make LLVM assume the stack is 32-byte aligned by the `override-stack-alignment` attribute in order to suppress stack realignment (if we fail to do so, problems like #26595 occur). The actual stack is only 16-byte aligned, so we transform `vmovapd` instructions emitted by LLVM into `vmovupd` using the LLVM Mangler (see #11138). This strategy has one caveat: The actual stack is not 32/64-byte aligned, so if we call a C function from Haskell, the arguments on the stack are not properly aligned. It leads to a segfault if the C function loads the argument with `vmovapd`. This problem is demonstrated by the attached program. I propose to make the stack 64-byte aligned when entering STG. If we do so, there would be one less task for the LLVM Mangler. ## Steps to reproduce ```haskell {-# LANGUAGE MagicHash, UnboxedTuples, UnliftedFFITypes #-} module StackAlignment32 where import GHC.Exts foreign import ccall unsafe add10 :: DoubleX4# -> DoubleX4# -> DoubleX4# -> DoubleX4# -> DoubleX4# -> DoubleX4# -> DoubleX4# -> DoubleX4# -> DoubleX4# -> DoubleX4# -> DoubleX4# foo :: Double -> IO () foo (D# x) = do let a = broadcastDoubleX4# x b = packDoubleX4# (# 1.0##, 2.0##, 3.0##, 4.0## #) c = add10 a a a a a a a a a b (# c0, c1, c2, c3 #) = unpackDoubleX4# c print (D# c0, D# c1, D# c2, D# c3) foreign export ccall foo :: Double -> IO () ``` ```c #include "HsFFI.h" #include <immintrin.h> // #if defined(__GLASGOW_HASKELL__) // #include "StackAlignment_stub.h" // #endif extern void foo(double x); __m256d add10(__m256d a0, __m256d a1, __m256d a2, __m256d a3, __m256d a4, __m256d a5, __m256d a6, __m256d a7, __m256d a8, __m256d a9) { // Test whether the stack is 32-byte aligned. // Under the System V ABI, the first eight parameters are passed in registers. // Here, `a8` and `a9` are passed on the stack. // We want the compiler to emit `vmovapd` so we can verify 32-byte stack alignment. // We cannot use `_mm256_add_pd(a0, a9)` because the compiler may fuse the load and // the addition and emit a `vaddpd m256` form, which permits an unaligned load of `a9`. // Therefore, we ensure that both operands are read from the stack, // so that at least one operand is loaded using `vmovapd`. return _mm256_add_pd(a8, a9); } __attribute__((noinline)) void baz(void) { // Make the stack pointer shift by 16 bytes on x86-64 foo(2.2); } __attribute__((noinline)) void bar(void) { // Make the stack pointer shift by 16 bytes on x86-64 foo(1.1); baz(); } int main(int argc, char *argv[]) { hs_init(&argc, &argv); foo(0.1); bar(); hs_exit(); } ``` ```console $ ghc -fforce-recomp -o stackalignment32 -mavx -optc -mavx -fllvm -no-hs-main -g StackAlignment32.hs stackalignment32_main.c $ ./stackalignment32 zsh: segmentation fault ./stackalignment32 $ lldb ./stackalignment32 (lldb) target create "./stackalignment32" Current executable set to '.../ghc/stackalignment32' (x86_64). (lldb) run Process 69537 launched: '../ghc/stackalignment32' (x86_64) Process 69537 stopped * thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT) frame #0: 0x00000001000091fc stackalignment32`add10 + 12 stackalignment32`add10: -> 0x1000091fc <+12>: vmovapd 0x10(%rbp), %ymm0 0x100009201 <+17>: vaddpd 0x30(%rbp), %ymm0, %ymm0 0x100009206 <+22>: movq %rbp, %rsp 0x100009209 <+25>: popq %rbp Target 0: (stackalignment32) stopped. ``` It is possible to create the AVX-512 variant of the program, and it results in a more obscure crash (similar to #26595). ## Expected behavior The program should print: ``` (1.1,2.1,3.1,4.1) (2.1,3.1,4.1,5.1) (3.2,4.2,5.2,6.2) ``` ## Environment * GHC version used: 9.15.20260123 (3f5e8d80b32063d265aeead6b62604c9ad4a34da) * Operating System: Linux, macOS * System Architecture: x86-64
issue