Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

wangpc-pp
Copy link
Contributor

@wangpc-pp wangpc-pp commented Jul 11, 2025

This adds the simplest implementation of PreserveMost calling
convention and we preserve x5-x31 (except x6/x7/x28) registers.

Fixes #148147.

@wangpc-pp wangpc-pp requested a review from topperc July 11, 2025 11:06
@wangpc-pp wangpc-pp requested review from preames, asb and topperc and removed request for topperc July 11, 2025 11:06
@llvmbot
Copy link
Member

llvmbot commented Jul 11, 2025

@llvm/pr-subscribers-llvm-ir

@llvm/pr-subscribers-backend-risc-v

Author: Pengcheng Wang (wangpc-pp)

Changes

This adds the simplest implementation of PreserveMost calling
convention and we preserve x5-x31 registers.

Fixes #148147.


Full diff: https://github.com/llvm/llvm-project/pull/148214.diff

4 Files Affected:

  • (modified) llvm/lib/Target/RISCV/RISCVCallingConv.td (+2)
  • (modified) llvm/lib/Target/RISCV/RISCVISelLowering.cpp (+1)
  • (modified) llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp (+2)
  • (added) llvm/test/CodeGen/RISCV/calling-conv-preserve-most.ll (+165)
diff --git a/llvm/lib/Target/RISCV/RISCVCallingConv.td b/llvm/lib/Target/RISCV/RISCVCallingConv.td
index cbf039edec273..90e5019019bed 100644
--- a/llvm/lib/Target/RISCV/RISCVCallingConv.td
+++ b/llvm/lib/Target/RISCV/RISCVCallingConv.td
@@ -93,3 +93,5 @@ def CSR_XLEN_F32_V_Interrupt_RVE: CalleeSavedRegs<(sub CSR_XLEN_F32_V_Interrupt,
 // Same as CSR_XLEN_F64_V_Interrupt, but excluding X16-X31.
 def CSR_XLEN_F64_V_Interrupt_RVE: CalleeSavedRegs<(sub CSR_XLEN_F64_V_Interrupt,
                                                    (sequence "X%u", 16, 31))>;
+
+def CSR_RT_MostRegs : CalleeSavedRegs<(add (sequence "X%u", 5, 31))>;
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 456f3aedbf034..6feb53202b7f2 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -22205,6 +22205,7 @@ SDValue RISCVTargetLowering::LowerFormalArguments(
   case CallingConv::C:
   case CallingConv::Fast:
   case CallingConv::SPIR_KERNEL:
+  case CallingConv::PreserveMost:
   case CallingConv::GRAAL:
   case CallingConv::RISCV_VectorCall:
 #define CC_VLS_CASE(ABI_VLEN) case CallingConv::RISCV_VLSCall_##ABI_VLEN:
diff --git a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
index 540412366026b..44c7ca3587cc1 100644
--- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
@@ -68,6 +68,8 @@ RISCVRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
   auto &Subtarget = MF->getSubtarget<RISCVSubtarget>();
   if (MF->getFunction().getCallingConv() == CallingConv::GHC)
     return CSR_NoRegs_SaveList;
+  if (MF->getFunction().getCallingConv() == CallingConv::PreserveMost)
+    return CSR_RT_MostRegs_SaveList;
   if (MF->getFunction().hasFnAttribute("interrupt")) {
     if (Subtarget.hasVInstructions()) {
       if (Subtarget.hasStdExtD())
diff --git a/llvm/test/CodeGen/RISCV/calling-conv-preserve-most.ll b/llvm/test/CodeGen/RISCV/calling-conv-preserve-most.ll
new file mode 100644
index 0000000000000..a0345363601a5
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/calling-conv-preserve-most.ll
@@ -0,0 +1,165 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv32 < %s | FileCheck %s -check-prefix=RV32
+; RUN: llc -mtriple=riscv64 < %s | FileCheck %s -check-prefix=RV64
+
+; Check the PreserveMost calling convention works.
+
+declare void @standard_cc_func()
+declare preserve_mostcc void @preserve_mostcc_func()
+
+define preserve_mostcc void @preserve_mostcc1() nounwind {
+; RV32-LABEL: preserve_mostcc1:
+; RV32:       # %bb.0: # %entry
+; RV32-NEXT:    addi sp, sp, -64
+; RV32-NEXT:    sw t0, 60(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw t1, 56(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw t2, 52(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a0, 48(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a1, 44(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a2, 40(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a3, 36(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a4, 32(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a5, 28(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a6, 24(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a7, 20(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw t3, 16(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw t4, 12(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw t5, 8(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw t6, 4(sp) # 4-byte Folded Spill
+; RV32-NEXT:    call standard_cc_func
+; RV32-NEXT:    lw t0, 60(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw t1, 56(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw t2, 52(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a0, 48(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a1, 44(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a2, 40(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a3, 36(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a4, 32(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a5, 28(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a6, 24(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a7, 20(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw t3, 16(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw t4, 12(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw t5, 8(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw t6, 4(sp) # 4-byte Folded Reload
+; RV32-NEXT:    addi sp, sp, 64
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: preserve_mostcc1:
+; RV64:       # %bb.0: # %entry
+; RV64-NEXT:    addi sp, sp, -128
+; RV64-NEXT:    sd t0, 120(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd t1, 112(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd t2, 104(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a0, 96(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a1, 88(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a2, 80(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a3, 72(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a4, 64(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a5, 56(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a6, 48(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a7, 40(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd t3, 32(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd t4, 24(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd t5, 16(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd t6, 8(sp) # 8-byte Folded Spill
+; RV64-NEXT:    call standard_cc_func
+; RV64-NEXT:    ld t0, 120(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld t1, 112(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld t2, 104(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a0, 96(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a1, 88(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a2, 80(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a3, 72(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a4, 64(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a5, 56(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a6, 48(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a7, 40(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld t3, 32(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld t4, 24(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld t5, 16(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld t6, 8(sp) # 8-byte Folded Reload
+; RV64-NEXT:    addi sp, sp, 128
+; RV64-NEXT:    ret
+entry:
+  call void @standard_cc_func()
+  ret void
+}
+
+define preserve_mostcc void @preserve_mostcc2() nounwind {
+; RV32-LABEL: preserve_mostcc2:
+; RV32:       # %bb.0:
+; RV32-NEXT:    addi sp, sp, -64
+; RV32-NEXT:    sw t0, 60(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw t1, 56(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw t2, 52(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a0, 48(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a1, 44(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a2, 40(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a3, 36(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a4, 32(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a5, 28(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a6, 24(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a7, 20(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw t3, 16(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw t4, 12(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw t5, 8(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw t6, 4(sp) # 4-byte Folded Spill
+; RV32-NEXT:    call preserve_mostcc_func
+; RV32-NEXT:    lw t0, 60(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw t1, 56(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw t2, 52(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a0, 48(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a1, 44(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a2, 40(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a3, 36(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a4, 32(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a5, 28(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a6, 24(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a7, 20(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw t3, 16(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw t4, 12(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw t5, 8(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw t6, 4(sp) # 4-byte Folded Reload
+; RV32-NEXT:    addi sp, sp, 64
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: preserve_mostcc2:
+; RV64:       # %bb.0:
+; RV64-NEXT:    addi sp, sp, -128
+; RV64-NEXT:    sd t0, 120(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd t1, 112(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd t2, 104(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a0, 96(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a1, 88(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a2, 80(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a3, 72(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a4, 64(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a5, 56(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a6, 48(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a7, 40(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd t3, 32(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd t4, 24(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd t5, 16(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd t6, 8(sp) # 8-byte Folded Spill
+; RV64-NEXT:    call preserve_mostcc_func
+; RV64-NEXT:    ld t0, 120(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld t1, 112(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld t2, 104(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a0, 96(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a1, 88(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a2, 80(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a3, 72(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a4, 64(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a5, 56(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a6, 48(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a7, 40(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld t3, 32(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld t4, 24(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld t5, 16(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld t6, 8(sp) # 8-byte Folded Reload
+; RV64-NEXT:    addi sp, sp, 128
+; RV64-NEXT:    ret
+  call preserve_mostcc void @preserve_mostcc_func()
+  ret void
+}

@wangpc-pp
Copy link
Contributor Author

It is appreciated if you can test its functionality @CaiWeiran @folkertdev.

@dtcxzyw dtcxzyw changed the title [RISCV] SUpport PreserveMost calling convention [RISCV] Support PreserveMost calling convention Jul 11, 2025
Copy link
Contributor

@lukel97 lukel97 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should probably update the LangRef to document that RISC-V supports it?

@wangpc-pp wangpc-pp force-pushed the main-riscv-preserve-most branch from 1fff14f to e3a2e57 Compare July 11, 2025 11:41
@wangpc-pp wangpc-pp force-pushed the main-riscv-preserve-most branch from c8e4770 to 3c4864d Compare July 29, 2025 04:20
Copy link
Member

@lenary lenary left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Thanks

@wangpc-pp wangpc-pp force-pushed the main-riscv-preserve-most branch from 3edb095 to 2900358 Compare July 30, 2025 04:02
@wangpc-pp wangpc-pp force-pushed the main-riscv-preserve-most branch from d734932 to 237d6cc Compare July 30, 2025 04:14
@wangpc-pp wangpc-pp merged commit 058d96f into llvm:main Jul 30, 2025
10 checks passed
@wangpc-pp wangpc-pp deleted the main-riscv-preserve-most branch July 30, 2025 08:31
wzssyqa pushed a commit to wzssyqa/llvm-project that referenced this pull request Sep 10, 2025
This adds the simplest implementation of `PreserveMost` calling
convention and we preserve `x5-x31` (except x6/x7/x28) registers.

Fixes llvm#148147.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

RISC-V backend does not support PreserveMost calling convention
7 participants