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