[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