Skip to content

[AIE] Handle large stack frames in adjustSPReg#1148

Open
atassis wants to merge 1 commit into
Xilinx:aie-publicfrom
atassis:adjustspreg-large-stack-frame
Open

[AIE] Handle large stack frames in adjustSPReg#1148
atassis wants to merge 1 commit into
Xilinx:aie-publicfrom
atassis:adjustspreg-large-stack-frame

Conversation

@atassis

@atassis atassis commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Problem

adjustSPReg emits the SP adjustment via the sp_imm pointer-add form, which encodes a limited immediate (+-2^18 bytes on AIE2P/AIE2PS, +-2^17 on AIE2). For a larger frame it took a report_fatal_error(...) path, crashing the backend instead of generating code. This is reachable whenever a function needs a frame that large, e.g. at -O0 where large vector temporaries spill to the stack. Minimal repro (aie2p):

define void @big_frame(ptr %out) {
  %buf = alloca [300000 x i8], align 64
  %p = getelementptr [300000 x i8], ptr %buf, i64 0, i64 0
  store volatile i8 42, ptr %p
  ret void
}

llc -O0 -mtriple=aie2p on that hits the fatal error.

Fix

Materialize the offset in an eM modifier register with MOVXM, then apply it with a register-form pointer add:

  • AIE2P / AIE2PS: PADDXM_pstm_sp (paddxm [sp], $mod), the register-operand sibling of the PADDXM_pstm_sp_imm used for small frames. It defs/uses SP implicitly, so the reserved SP register is not an explicit operand.
  • AIE2: no register-form SP add exists and SP is reserved, so copy SP into a scratch pointer register (MOV_mv_scl), add the offset there (PADDA_lda_ptr_inc_idx), and copy back to SP. This is the same sequence the backend already emits to update SP for a dynamic stack allocation.

The virtual scratch registers are resolved by the register scavenger (requiresRegisterScavenging is true on all three targets); adjustReg and the dynamic-alloca lowering already rely on the identical patterns.

Testing

New tests llvm/test/CodeGen/AIE/{aie2p,aie2ps,aie2}/large-stack-frame.ll (run with -verify-machineinstrs). Each checks that a larger-than-range frame emits the register-form SP adjust and that an in-range frame still uses the compact sp_imm form (no regression). Verified for all three: the minimal repro that crashed now compiles, passes -verify-machineinstrs, and assembles to a valid object; the existing prolog/epilog and dyn-stackalloc tests still pass.

Notes

  • AIE1 is out of scope: its own adjustReg also report_fatal_errors on large offsets (no register-materialization pattern to mirror), and it is the legacy target.
  • MOVXM encodes a 32-bit signed immediate, which covers any representable stack frame.

adjustSPReg reported a fatal error ("adjustSPReg cannot yet handle adjustments
> +-2^N bytes") when a function's stack frame exceeded the range encodable by the
sp_imm pointer-add form (2^18 on AIE2P/AIE2PS, 2^17 on AIE2), so the backend
crashed instead of generating code. This is reachable whenever a function needs a
frame that large, for example at -O0 where large vector temporaries are not
coalesced and spill to the stack.

Materialize the offset in a modifier register with MOVXM and apply it with a
register-form pointer add. AIE2P and AIE2PS have a dedicated SP register-modifier
instruction, PADDXM_pstm_sp, the sibling of the sp_imm form (it defs and uses SP
implicitly). AIE2 has no register-form SP add and SP is reserved, so it copies SP
into a scratch pointer register, adds the offset there, and copies back, the same
sequence the backend already uses to update SP for a dynamic stack allocation.
The virtual scratch registers are resolved by the register scavenger
(requiresRegisterScavenging is true).
@atassis
atassis force-pushed the adjustspreg-large-stack-frame branch from ba15f63 to fb88982 Compare July 24, 2026 22:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant