[llvm] [RISC-V] Fix crash with late stack realignment requirement (PR #83496)

Nemanja Ivanovic via llvm-commits llvm-commits at lists.llvm.org
Thu Feb 29 14:36:02 PST 2024


https://github.com/nemanjai created https://github.com/llvm/llvm-project/pull/83496

In order to performa a stack re-alignment, the RISC-V back end requires the frame pointer. Of course, the frame pointer rquires a register to be reserved. The decision on which registers to reserve is made prior to any spilling introduced by RA. If the spill has to spill a register that of a class that requires greater alignment than the stack alignment, this will trigger a requirement to re-align the stack but the FP register hasn't been reserved.
This patch adds a check for any use of a register that could cause stack re-alignment if it were to be spilled.

Currently, the only situation that triggers this issue is when we have -Zdinx with the E extension (for which we align the stack to 4 bytes).

>From e9668e4558894b0b92b3d6798533864a3d6c254e Mon Sep 17 00:00:00 2001
From: Nemanja Ivanovic <nemanja at synopsys.com>
Date: Thu, 29 Feb 2024 23:32:50 +0100
Subject: [PATCH] [RISC-V] Fix crash with late stack realignment requirement

In order to performa a stack re-alignment, the RISC-V back end
requires the frame pointer. Of course, the frame pointer
rquires a register to be reserved. The decision on which
registers to reserve is made prior to any spilling introduced
by RA. If the spill has to spill a register that of a class
that requires greater alignment than the stack alignment,
this will trigger a requirement to re-align the stack but
the FP register hasn't been reserved.
This patch adds a check for any use of a register that
could cause stack re-alignment if it were to be spilled.

Currently, the only situation that triggers this issue
is when we have -Zdinx with the E extension (for which
we align the stack to 4 bytes).
---
 llvm/lib/Target/RISCV/RISCVFrameLowering.cpp  | 34 +++++++++-
 llvm/lib/Target/RISCV/RISCVFrameLowering.h    |  3 +
 .../CodeGen/RISCV/zdinx-realignment-with-e.ll | 64 +++++++++++++++++++
 3 files changed, 100 insertions(+), 1 deletion(-)
 create mode 100644 llvm/test/CodeGen/RISCV/zdinx-realignment-with-e.ll

diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
index 8bac41372b5a83..26cf6a24d15cca 100644
--- a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
@@ -306,9 +306,12 @@ static Register getMaxPushPopReg(const MachineFunction &MF,
 // variable sized allocas, or if the frame address is taken.
 bool RISCVFrameLowering::hasFP(const MachineFunction &MF) const {
   const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
-
+  bool HasExtE =
+      MF.getSubtarget<RISCVSubtarget>().getTargetABI() == RISCVABI::ABI_ILP32E;
   const MachineFrameInfo &MFI = MF.getFrameInfo();
+
   return MF.getTarget().Options.DisableFramePointerElim(MF) ||
+         (HasExtE && maxPossibleSpillAlign(MF) > Align(4)) ||
          RegInfo->hasStackRealignment(MF) || MFI.hasVarSizedObjects() ||
          MFI.isFrameAddressTaken();
 }
@@ -1175,6 +1178,35 @@ static unsigned estimateFunctionSizeInBytes(const MachineFunction &MF,
   return FnSize;
 }
 
+Align RISCVFrameLowering::maxPossibleSpillAlign(
+    const MachineFunction &MF) const {
+  if (MaxSpillAlign.contains(&MF))
+    return MaxSpillAlign.at(&MF);
+
+  const MachineRegisterInfo &MRI = MF.getRegInfo();
+  const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
+  Align CurrMaxAlign = Align(1);
+  // The maximum spill alignment has not yet been computed. Compute it.
+  for (const MachineBasicBlock &MBB : MF) {
+    for (const MachineInstr &MI : MBB) {
+      for (const MachineOperand &MO : MI.operands()) {
+        if (!MO.isReg())
+          continue;
+        Register Reg = MO.getReg();
+        const TargetRegisterClass *RC;
+        if (Reg.isPhysical())
+          RC = TRI->getMinimalPhysRegClass(Reg);
+        else
+          RC = MRI.getRegClassOrNull(MO.getReg());
+        if (RC && TRI->getSpillAlign(*RC) > CurrMaxAlign)
+          CurrMaxAlign = TRI->getSpillAlign(*RC);
+      }
+    }
+  }
+  MaxSpillAlign[&MF] = CurrMaxAlign;
+  return CurrMaxAlign;
+}
+
 void RISCVFrameLowering::processFunctionBeforeFrameFinalized(
     MachineFunction &MF, RegScavenger *RS) const {
   const RISCVRegisterInfo *RegInfo =
diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.h b/llvm/lib/Target/RISCV/RISCVFrameLowering.h
index 210f8c1064724a..cb5dbf82dc1b11 100644
--- a/llvm/lib/Target/RISCV/RISCVFrameLowering.h
+++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.h
@@ -13,6 +13,7 @@
 #ifndef LLVM_LIB_TARGET_RISCV_RISCVFRAMELOWERING_H
 #define LLVM_LIB_TARGET_RISCV_RISCVFRAMELOWERING_H
 
+#include "llvm/ADT/DenseMap.h"
 #include "llvm/CodeGen/TargetFrameLowering.h"
 #include "llvm/Support/TypeSize.h"
 
@@ -37,6 +38,7 @@ class RISCVFrameLowering : public TargetFrameLowering {
   void processFunctionBeforeFrameFinalized(MachineFunction &MF,
                                            RegScavenger *RS) const override;
 
+  Align maxPossibleSpillAlign(const MachineFunction &MF) const;
   bool hasFP(const MachineFunction &MF) const override;
 
   bool hasBP(const MachineFunction &MF) const;
@@ -82,6 +84,7 @@ class RISCVFrameLowering : public TargetFrameLowering {
 
 protected:
   const RISCVSubtarget &STI;
+  mutable llvm::DenseMap<const MachineFunction *, Align> MaxSpillAlign;
 
 private:
   void determineFrameLayout(MachineFunction &MF) const;
diff --git a/llvm/test/CodeGen/RISCV/zdinx-realignment-with-e.ll b/llvm/test/CodeGen/RISCV/zdinx-realignment-with-e.ll
new file mode 100644
index 00000000000000..1b0e6d1967ff92
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/zdinx-realignment-with-e.ll
@@ -0,0 +1,64 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 2
+; RUN: llc --mtriple=riscv32 --mattr=+e,+zdinx --target-abi ilp32e \
+; RUN:   --verify-machineinstrs < %s | FileCheck %s
+define void @func(ptr %__first, ptr %__start, ptr %add.ptr23) #0 {
+; CHECK-LABEL: func:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    addi sp, sp, -24
+; CHECK-NEXT:    .cfi_def_cfa_offset 24
+; CHECK-NEXT:    sw ra, 20(sp) # 4-byte Folded Spill
+; CHECK-NEXT:    sw s0, 16(sp) # 4-byte Folded Spill
+; CHECK-NEXT:    .cfi_offset ra, -4
+; CHECK-NEXT:    .cfi_offset s0, -8
+; CHECK-NEXT:    addi s0, sp, 24
+; CHECK-NEXT:    .cfi_def_cfa s0, 0
+; CHECK-NEXT:    andi sp, sp, -8
+; CHECK-NEXT:    lui a1, %hi(.LCPI0_0)
+; CHECK-NEXT:    lw a4, %lo(.LCPI0_0)(a1)
+; CHECK-NEXT:    lw a5, %lo(.LCPI0_0+4)(a1)
+; CHECK-NEXT:    sw a4, 8(sp)
+; CHECK-NEXT:    sw a5, 12(sp)
+; CHECK-NEXT:    lui a1, %hi(.LCPI0_1)
+; CHECK-NEXT:    lw a4, %lo(.LCPI0_1)(a1)
+; CHECK-NEXT:    lw a5, %lo(.LCPI0_1+4)(a1)
+; CHECK-NEXT:    sw a4, 0(sp)
+; CHECK-NEXT:    sw a5, 4(sp)
+; CHECK-NEXT:  .LBB0_1: # %do.body
+; CHECK-NEXT:    # =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    lw a4, 0(zero)
+; CHECK-NEXT:    lw a5, 4(zero)
+; CHECK-NEXT:    fcvt.d.w t1, zero
+; CHECK-NEXT:    sw t1, 0(a0)
+; CHECK-NEXT:    sw t2, 4(a0)
+; CHECK-NEXT:    lw t1, 8(sp)
+; CHECK-NEXT:    lw t2, 12(sp)
+; CHECK-NEXT:    flt.d a1, t1, a4
+; CHECK-NEXT:    neg a1, a1
+; CHECK-NEXT:    and a1, a1, a2
+; CHECK-NEXT:    lw a4, 0(a1)
+; CHECK-NEXT:    lw a5, 4(a1)
+; CHECK-NEXT:    lw t1, 0(sp)
+; CHECK-NEXT:    lw t2, 4(sp)
+; CHECK-NEXT:    flt.d a1, a4, t1
+; CHECK-NEXT:    beqz a1, .LBB0_1
+; CHECK-NEXT:  # %bb.2: # %do.end
+; CHECK-NEXT:    addi sp, s0, -24
+; CHECK-NEXT:    lw ra, 20(sp) # 4-byte Folded Reload
+; CHECK-NEXT:    lw s0, 16(sp) # 4-byte Folded Reload
+; CHECK-NEXT:    addi sp, sp, 24
+; CHECK-NEXT:    ret
+entry:
+  br label %do.body
+
+do.body:                                          ; preds = %do.body, %entry
+  store double 0.000000e+00, ptr %__first, align 8
+  %0 = load double, ptr null, align 8
+  %cmp.i51 = fcmp olt double 0x7FF8000000000000, %0
+  %__child_i.2 = select i1 %cmp.i51, ptr %add.ptr23, ptr null
+  %1 = load double, ptr %__child_i.2, align 8
+  %cmp.i52 = fcmp olt double %1, 1.000000e+00
+  br i1 %cmp.i52, label %do.end, label %do.body
+
+do.end:                                           ; preds = %do.body
+  ret void
+}



More information about the llvm-commits mailing list