From fb889828b99d11f020a643267258aee6f050b370 Mon Sep 17 00:00:00 2001 From: Taimuraz Kaitmazov Date: Mon, 20 Jul 2026 02:00:03 +0300 Subject: [PATCH] [AIE] Handle large stack frames in adjustSPReg 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). --- llvm/lib/Target/AIE/AIE2FrameLowering.cpp | 28 +++++++++++-- .../Target/AIE/aie2p/AIE2PFrameLowering.cpp | 16 ++++++-- .../Target/AIE/aie2ps/AIE2PSFrameLowering.cpp | 16 ++++++-- .../CodeGen/AIE/aie2/large-stack-frame.ll | 41 +++++++++++++++++++ .../CodeGen/AIE/aie2p/large-stack-frame.ll | 41 +++++++++++++++++++ .../CodeGen/AIE/aie2ps/large-stack-frame.ll | 41 +++++++++++++++++++ 6 files changed, 174 insertions(+), 9 deletions(-) create mode 100644 llvm/test/CodeGen/AIE/aie2/large-stack-frame.ll create mode 100644 llvm/test/CodeGen/AIE/aie2p/large-stack-frame.ll create mode 100644 llvm/test/CodeGen/AIE/aie2ps/large-stack-frame.ll diff --git a/llvm/lib/Target/AIE/AIE2FrameLowering.cpp b/llvm/lib/Target/AIE/AIE2FrameLowering.cpp index 65ec21a3374d..83de50d8f435 100644 --- a/llvm/lib/Target/AIE/AIE2FrameLowering.cpp +++ b/llvm/lib/Target/AIE/AIE2FrameLowering.cpp @@ -54,9 +54,31 @@ void AIE2FrameLowering::adjustSPReg(MachineBasicBlock &MBB, .addImm(StackPtrIncr) .setMIFlag(Flag); } else { - LLVM_DEBUG(dbgs() << "Adjust Stack by " << StackPtrIncr << " bytes\n."); - report_fatal_error( - "adjustSPReg cannot yet handle adjustments > +-2^17 bytes"); + // AIE2 has no register-form SP pointer add (only the sp_imm forms), and SP + // is reserved, so it cannot be an explicit operand of the general pointer + // add. Copy SP into a scratch pointer register, add the materialized offset + // there, and copy the result back to SP. This is the same sequence the + // backend already uses to update SP for a dynamic stack allocation. The + // scratch registers are resolved by the register scavenger. + MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo(); + auto *RI = static_cast(STI.getRegisterInfo()); + Register SPReg = RI->getStackPointerRegister(); + Register ScratchP = MRI.createVirtualRegister(&AIE2::ePRegClass); + Register ModReg = MRI.createVirtualRegister(&AIE2::eMRegClass); + BuildMI(MBB, MBBI, DL, TII->get(TII->getMvSclOpcode()), ScratchP) + .addReg(SPReg) + .setMIFlag(Flag); + BuildMI(MBB, MBBI, DL, TII->get(AIE2::MOVXM_lng_cg), ModReg) + .addImm(StackPtrIncr) + .setMIFlag(Flag); + BuildMI(MBB, MBBI, DL, TII->get(AIE2::PADDA_lda_ptr_inc_idx)) + .addDef(ScratchP) + .addUse(ScratchP) + .addUse(ModReg) + .setMIFlag(Flag); + BuildMI(MBB, MBBI, DL, TII->get(TII->getMvSclOpcode()), SPReg) + .addReg(ScratchP, RegState::Kill) + .setMIFlag(Flag); } } diff --git a/llvm/lib/Target/AIE/aie2p/AIE2PFrameLowering.cpp b/llvm/lib/Target/AIE/aie2p/AIE2PFrameLowering.cpp index 940c497dffa9..cf611d064c14 100644 --- a/llvm/lib/Target/AIE/aie2p/AIE2PFrameLowering.cpp +++ b/llvm/lib/Target/AIE/aie2p/AIE2PFrameLowering.cpp @@ -76,9 +76,19 @@ void AIE2PFrameLowering::adjustSPReg(MachineBasicBlock &MBB, .addImm(StackPtrIncr) .setMIFlag(Flag); } else { - LLVM_DEBUG(dbgs() << "Adjust Stack by " << StackPtrIncr << " bytes\n."); - report_fatal_error( - "adjustSPReg cannot yet handle adjustments > +-2^18 bytes"); + // The sp_imm form cannot encode an offset this large. Materialize it in a + // modifier register and use the register form of the SP pointer add, which + // is the sibling of the sp_imm instruction used above. The register + // scavenger resolves the virtual register using the emergency slots that + // processFunctionBeforeFrameFinalized() reserves for large stack frames. + MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo(); + Register ModReg = MRI.createVirtualRegister(&AIE2P::eMRegClass); + BuildMI(MBB, MBBI, DL, TII->get(AIE2P::MOVXM), ModReg) + .addImm(StackPtrIncr) + .setMIFlag(Flag); + BuildMI(MBB, MBBI, DL, TII->get(AIE2P::PADDXM_pstm_sp)) + .addReg(ModReg) + .setMIFlag(Flag); } } void AIE2PFrameLowering::determineCalleeSaves(MachineFunction &MF, diff --git a/llvm/lib/Target/AIE/aie2ps/AIE2PSFrameLowering.cpp b/llvm/lib/Target/AIE/aie2ps/AIE2PSFrameLowering.cpp index 048fab42aa09..2bdef763e95c 100644 --- a/llvm/lib/Target/AIE/aie2ps/AIE2PSFrameLowering.cpp +++ b/llvm/lib/Target/AIE/aie2ps/AIE2PSFrameLowering.cpp @@ -75,9 +75,19 @@ void AIE2PSFrameLowering::adjustSPReg(MachineBasicBlock &MBB, .addImm(StackPtrIncr) .setMIFlag(Flag); } else { - LLVM_DEBUG(dbgs() << "Adjust Stack by " << StackPtrIncr << " bytes\n."); - report_fatal_error( - "adjustSPReg cannot yet handle adjustments > +-2^18 bytes"); + // The sp_imm form cannot encode an offset this large. Materialize it in a + // modifier register and use the register form of the SP pointer add, which + // is the sibling of the sp_imm instruction used above. The register + // scavenger resolves the virtual register using the emergency slots that + // processFunctionBeforeFrameFinalized() reserves for large stack frames. + MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo(); + Register ModReg = MRI.createVirtualRegister(&AIE2PS::eMRegClass); + BuildMI(MBB, MBBI, DL, TII->get(AIE2PS::MOVXM_lng_cg), ModReg) + .addImm(StackPtrIncr) + .setMIFlag(Flag); + BuildMI(MBB, MBBI, DL, TII->get(AIE2PS::PADDXM_pstm_sp)) + .addReg(ModReg) + .setMIFlag(Flag); } } diff --git a/llvm/test/CodeGen/AIE/aie2/large-stack-frame.ll b/llvm/test/CodeGen/AIE/aie2/large-stack-frame.ll new file mode 100644 index 000000000000..3c44b7662eb6 --- /dev/null +++ b/llvm/test/CodeGen/AIE/aie2/large-stack-frame.ll @@ -0,0 +1,41 @@ +; +; This file is licensed under the Apache License v2.0 with LLVM Exceptions. +; See https://llvm.org/LICENSE.txt for license information. +; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +; +; (c) Copyright 2025 Advanced Micro Devices, Inc. or its affiliates +; +; RUN: llc -O0 -verify-machineinstrs -mtriple=aie2 %s -o - | FileCheck %s + +; AIE2 has no register-form SP pointer add (only the sp_imm forms) and SP is +; reserved, so a stack frame larger than the sp_imm range (+-2^17 bytes) is +; adjusted by copying SP into a scratch pointer register, adding the materialized +; offset there, and copying back, rather than triggering the "adjustSPReg cannot +; yet handle adjustments > +-2^17 bytes" fatal error. +define void @big_frame(ptr %out) { +; CHECK-LABEL: big_frame: +; CHECK: mov [[P:p[0-9]+]], sp +; CHECK: movxm [[M:m[0-9]+]], #200000 +; CHECK: padda {{\[}}[[P]]{{\]}}, [[M]] +; CHECK: mov sp, [[P]] + %buf = alloca [200000 x i8], align 32 + %p = getelementptr [200000 x i8], ptr %buf, i64 0, i64 0 + store volatile i8 42, ptr %p + %v = load volatile i8, ptr %p + store i8 %v, ptr %out + ret void +} + +; A frame within range still uses the compact sp_imm form (no regression, and the +; scratch-register sequence is only used for large frames). +define void @small_frame(ptr %out) { +; CHECK-LABEL: small_frame: +; CHECK-NOT: mov sp, p +; CHECK: paddb [sp], #-32 + %buf = alloca [32 x i8], align 32 + %p = getelementptr [32 x i8], ptr %buf, i64 0, i64 0 + store volatile i8 42, ptr %p + %v = load volatile i8, ptr %p + store i8 %v, ptr %out + ret void +} diff --git a/llvm/test/CodeGen/AIE/aie2p/large-stack-frame.ll b/llvm/test/CodeGen/AIE/aie2p/large-stack-frame.ll new file mode 100644 index 000000000000..3651682ad254 --- /dev/null +++ b/llvm/test/CodeGen/AIE/aie2p/large-stack-frame.ll @@ -0,0 +1,41 @@ +; +; This file is licensed under the Apache License v2.0 with LLVM Exceptions. +; See https://llvm.org/LICENSE.txt for license information. +; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +; +; (c) Copyright 2025 Advanced Micro Devices, Inc. or its affiliates +; +; RUN: llc -O0 -verify-machineinstrs -mtriple=aie2p %s -o - | FileCheck %s + +; A stack frame larger than the sp_imm encodable range (+-2^18 bytes) must be +; materialized in a modifier register and applied with the register form of the +; SP pointer add, rather than triggering the "adjustSPReg cannot yet handle +; adjustments > +-2^18 bytes" fatal error. +define void @big_frame(ptr %out) { +; CHECK-LABEL: big_frame: +; CHECK: movxm [[M:m[0-9]+]], #300032 +; CHECK: paddxm [sp], [[M]] +; CHECK: movxm [[M2:m[0-9]+]], #-300032 +; CHECK: paddxm [sp], [[M2]] + %buf = alloca [300000 x i8], align 64 + %p = getelementptr [300000 x i8], ptr %buf, i64 0, i64 0 + store volatile i8 42, ptr %p + %v = load volatile i8, ptr %p + store i8 %v, ptr %out + ret void +} + +; A frame within range still uses the compact sp_imm form (no regression, and the +; register fallback is only taken for large frames). +define void @small_frame(ptr %out) { +; CHECK-LABEL: small_frame: +; CHECK: paddxm [sp], #64 +; CHECK-NOT: paddxm [sp], m +; CHECK: paddxm [sp], #-64 + %buf = alloca [64 x i8], align 64 + %p = getelementptr [64 x i8], ptr %buf, i64 0, i64 0 + store volatile i8 42, ptr %p + %v = load volatile i8, ptr %p + store i8 %v, ptr %out + ret void +} diff --git a/llvm/test/CodeGen/AIE/aie2ps/large-stack-frame.ll b/llvm/test/CodeGen/AIE/aie2ps/large-stack-frame.ll new file mode 100644 index 000000000000..9a36ba5503c0 --- /dev/null +++ b/llvm/test/CodeGen/AIE/aie2ps/large-stack-frame.ll @@ -0,0 +1,41 @@ +; +; This file is licensed under the Apache License v2.0 with LLVM Exceptions. +; See https://llvm.org/LICENSE.txt for license information. +; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +; +; (c) Copyright 2025 Advanced Micro Devices, Inc. or its affiliates +; +; RUN: llc -O0 -verify-machineinstrs -mtriple=aie2ps %s -o - | FileCheck %s + +; A stack frame larger than the sp_imm encodable range (+-2^18 bytes) must be +; materialized in a modifier register and applied with the register form of the +; SP pointer add, rather than triggering the "adjustSPReg cannot yet handle +; adjustments > +-2^18 bytes" fatal error. +define void @big_frame(ptr %out) { +; CHECK-LABEL: big_frame: +; CHECK: movxm [[M:m[0-9]+]], #300032 +; CHECK: paddxm [sp], [[M]] +; CHECK: movxm [[M2:m[0-9]+]], #-300032 +; CHECK: paddxm [sp], [[M2]] + %buf = alloca [300000 x i8], align 64 + %p = getelementptr [300000 x i8], ptr %buf, i64 0, i64 0 + store volatile i8 42, ptr %p + %v = load volatile i8, ptr %p + store i8 %v, ptr %out + ret void +} + +; A frame within range still uses the compact sp_imm form (no regression, and the +; register fallback is only taken for large frames). +define void @small_frame(ptr %out) { +; CHECK-LABEL: small_frame: +; CHECK: paddxm [sp], #64 +; CHECK-NOT: paddxm [sp], m +; CHECK: paddxm [sp], #-64 + %buf = alloca [64 x i8], align 64 + %p = getelementptr [64 x i8], ptr %buf, i64 0, i64 0 + store volatile i8 42, ptr %p + %v = load volatile i8, ptr %p + store i8 %v, ptr %out + ret void +}