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

aarch64 backend generates conditional jumps beyond 2MB of code (fixup value out of range)
## Summary The aarch64 backend currently generates conditional jumps to labels with relative addresses that do not fit in the 21 bit limit for conditional jumps. #23451 is an instance of this, and the [reproducer posted on that ticket](https://gitlab.haskell.org/ghc/ghc/-/issues/23451#note_501205) demonstrates that we are particularly at a risk of doing this when emitting unoptimized code that, e.g., contains unfoldings. ## Solutions ### Somehow selectively generate far jumps As the error in #23451 indicates, the `b.hi` conditional jump instruction is where the fixup value is out of range. If we instead generated a conditional jump to a non-conditional jump, we could avoid the issue. For example, a jump of the form: ``` cmp xi, xj b.hi Lbl1 ... code a ... Lbl1: ... code b ... ``` Could be equivalently (but less efficiently) represented as: ``` cmp xi, xj b.ls Lbl2 adrp xk, Lbl1@PAGE add xk, xk, Lbl1@PAGEOFF br xk Lbl2: ... code a ... Lbl1: ... code b ... ``` If we could somehow track whether `code a` was over 2MB of code, we could selectively generate far jumps like the latter. Alternatively, we could introduce a flag which causes the aarch64 backend to always generate jumps like the latter, just to give some sure way out of the fixup error. ### Generate smaller assembly Looking at the dumped asm for that reproducer, there is approximately 2105508 bytes of instructions between the jump and the destination (which is just beyond the 2^21=2097152 byte limit). A lot of those instructions look like this: ``` ... mov x5, #54888 movk x5, #65535, lsl #16 movk x5, #65535, lsl #32 movk x5, #65535, lsl #48 add x5, x21, x5 str x6, [ x5 ] mov x6, #54896 movk x6, #65535, lsl #16 movk x6, #65535, lsl #32 movk x6, #65535, lsl #48 add x6, x21, x6 str x8, [ x6 ] mov x8, #54904 movk x8, #65535, lsl #16 movk x8, #65535, lsl #32 movk x8, #65535, lsl #48 add x8, x21, x8 ... ``` Which is just inefficient subtractions. For example, the first 5 instructions there could instead be just two instructions: ``` mov x5, #10648 sub x5, x21, x5 ``` There are about 17550 groups of five instructions matching that pattern between the branch and the destination in the output assembly. That means that `17550 groups * 5 instructions/group * 4 bytes/instruction = 351000 bytes` is used by those groups of instructions. If all of those groups could be optimized to two instructions, they would instead use `17550 groups * 2 instructions/group * 4 bytes/instruction = 140400 bytes`, saving about `351000 - 140400 = 210600` and bringing the jump destination back within reach for this specific minimal example. This is obviously not a general fix for the issue, just something that could make this harder to bump into. I believe @andreask plans on addressing this specific aspect of the issue in his work on #23556. ## Environment * GHC version used: Should be able to reproduce on `HEAD`, I am specifically using `27a472d4a34e3c0d287c6079335abeb4df41530a` Optional: * Operating System: Darwin * System Architecture: aarch64
issue