-
Notifications
You must be signed in to change notification settings - Fork 15.4k
[RISCV] Implement getIPRACSRegs hook #125586
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
This patch implements the getIPRACSRegs hook for riscv, similar to how it's done for x86 in 14b567d. Differently from the x86 hook, in this patch we only save ra (x1) and not the frame pointer. I'm still working on a test case that shows the need to save the fp. The fixed test case was extracted from the gcc torture suite, but the same issue is found in SPEC's xz.
Signed-off-by: Mikhail R. Gadelha <[email protected]>
|
@llvm/pr-subscribers-backend-risc-v Author: Mikhail R. Gadelha (mikhailramalho) ChangesFixes #124932. This patch implements the getIPRACSRegs hook for RISC-V, similar to its introduction for x86 in commit 14b567d. This hook is necessary for correct code generation when Interprocedural Register Allocation (IPRA) is enabled, ensuring that the return address register (ra / x1) is correctly saved and restored when needed. Unlike the x86 implementation, this patch only saves ra and does not yet include the frame pointer (fp). Further investigation is required to determine whether fp should also be preserved in all cases. The test case is representative of a miscompile observed in the GCC torture suite (20090113-3.c), though similar failures occur in SPEC’s xz benchmark. Full diff: https://github.com/llvm/llvm-project/pull/125586.diff 4 Files Affected:
diff --git a/llvm/lib/Target/RISCV/RISCVCallingConv.td b/llvm/lib/Target/RISCV/RISCVCallingConv.td
index ad06f477437702..98e05b7f8eca7c 100644
--- a/llvm/lib/Target/RISCV/RISCVCallingConv.td
+++ b/llvm/lib/Target/RISCV/RISCVCallingConv.td
@@ -42,6 +42,8 @@ def CSR_ILP32D_LP64D_V
// Needed for implementation of RISCVRegisterInfo::getNoPreservedMask()
def CSR_NoRegs : CalleeSavedRegs<(add)>;
+def CSR_IPRA : CalleeSavedRegs<(add X1)>;
+
// Interrupt handler needs to save/restore all registers that are used,
// both Caller and Callee saved registers.
def CSR_Interrupt : CalleeSavedRegs<(add X1, (sequence "X%u", 5, 31))>;
diff --git a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
index b0a52698c1e9f1..7a99bfd1b25122 100644
--- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
@@ -55,6 +55,11 @@ RISCVRegisterInfo::RISCVRegisterInfo(unsigned HwMode)
: RISCVGenRegisterInfo(RISCV::X1, /*DwarfFlavour*/0, /*EHFlavor*/0,
/*PC*/0, HwMode) {}
+const MCPhysReg *
+RISCVRegisterInfo::getIPRACSRegs(const MachineFunction *MF) const {
+ return CSR_IPRA_SaveList;
+}
+
const MCPhysReg *
RISCVRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
auto &Subtarget = MF->getSubtarget<RISCVSubtarget>();
diff --git a/llvm/lib/Target/RISCV/RISCVRegisterInfo.h b/llvm/lib/Target/RISCV/RISCVRegisterInfo.h
index 3ab79694e175c8..6c4e9c7b1bdc7f 100644
--- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.h
+++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.h
@@ -62,6 +62,8 @@ struct RISCVRegisterInfo : public RISCVGenRegisterInfo {
const MCPhysReg *getCalleeSavedRegs(const MachineFunction *MF) const override;
+ const MCPhysReg *getIPRACSRegs(const MachineFunction *MF) const override;
+
BitVector getReservedRegs(const MachineFunction &MF) const override;
bool isAsmClobberable(const MachineFunction &MF,
MCRegister PhysReg) const override;
diff --git a/llvm/test/CodeGen/RISCV/ipra.ll b/llvm/test/CodeGen/RISCV/ipra.ll
index 717b778bcde375..761d4772283367 100644
--- a/llvm/test/CodeGen/RISCV/ipra.ll
+++ b/llvm/test/CodeGen/RISCV/ipra.ll
@@ -68,21 +68,25 @@ define internal void @foobar(ptr %live_throughout.0.val) norecurse nounwind {
; RV64-LABEL: foobar:
; RV64: # %bb.0: # %entry
; RV64-NEXT: addi sp, sp, -48
+; RV64-NEXT: sd ra, 40(sp) # 8-byte Folded Spill
; RV64-NEXT: mv a1, a0
-; RV64-NEXT: addi a0, sp, 16
-; RV64-NEXT: addi a2, sp, 12
+; RV64-NEXT: addi a0, sp, 8
+; RV64-NEXT: addi a2, sp, 4
; RV64-NEXT: call bmp_iter_set_init
+; RV64-NEXT: ld ra, 40(sp) # 8-byte Folded Reload
; RV64-NEXT: addi sp, sp, 48
; RV64-NEXT: ret
;
; RV32-LABEL: foobar:
; RV32: # %bb.0: # %entry
-; RV32-NEXT: addi sp, sp, -32
+; RV32-NEXT: addi sp, sp, -48
+; RV32-NEXT: sw ra, 44(sp) # 4-byte Folded Spill
; RV32-NEXT: mv a1, a0
-; RV32-NEXT: addi a0, sp, 8
-; RV32-NEXT: addi a2, sp, 4
+; RV32-NEXT: addi a0, sp, 16
+; RV32-NEXT: addi a2, sp, 12
; RV32-NEXT: call bmp_iter_set_init
-; RV32-NEXT: addi sp, sp, 32
+; RV32-NEXT: lw ra, 44(sp) # 4-byte Folded Reload
+; RV32-NEXT: addi sp, sp, 48
; RV32-NEXT: ret
;
; RV64-WITHFP-LABEL: foobar:
|
topperc
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Should we backport to LLVM 20?
Especially this early in the cycle, no opposition to it. I will note that due to #119556 there's at least one other issue with using IPRA in practice - you can get crashes unless you use |
Fixes llvm#124932. This patch implements the getIPRACSRegs hook for RISC-V, similar to its introduction for x86 in commit 14b567d. This hook is necessary for correct code generation when Interprocedural Register Allocation (IPRA) is enabled, ensuring that the return address register (ra / x1) is correctly saved and restored when needed. Unlike the x86 implementation, this patch only saves ra and does not yet include the frame pointer (fp). Further investigation is required to determine whether fp should also be preserved in all cases. The test case is representative of a miscompile observed in the GCC torture suite (20090113-3.c), though similar failures occur in SPEC’s xz benchmark.
Fixes #124932.
This patch implements the getIPRACSRegs hook for RISC-V, similar to its introduction for x86 in commit 14b567d. This hook is necessary for correct code generation when Interprocedural Register Allocation (IPRA) is enabled, ensuring that the return address register (ra / x1) is correctly saved and restored when needed.
Unlike the x86 implementation, this patch only saves ra and does not yet include the frame pointer (fp). Further investigation is required to determine whether fp should also be preserved in all cases.
The test case is representative of a miscompile observed in the GCC torture suite (20090113-3.c), though similar failures occur in SPEC’s xz benchmark.