[llvm] [RISCV] Do not generate QC.CM.PUSHFP when rlist has only RA (PR #200541)
via llvm-commits
llvm-commits at lists.llvm.org
Fri May 29 19:32:20 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-risc-v
Author: Sudharsan Veeravalli (svs-quic)
<details>
<summary>Changes</summary>
`QC.CM.PUSHFP` is only legal when the push `rlist` includes `{ra, s0}`. The current flow could assume implicit FP updates in cases where `QC.CM.PUSHFP` is not legal and generate the instruction incorrectly.
---
Full diff: https://github.com/llvm/llvm-project/pull/200541.diff
3 Files Affected:
- (modified) llvm/lib/Target/RISCV/RISCVFrameLowering.cpp (+6-2)
- (modified) llvm/lib/Target/RISCV/RISCVMachineFunctionInfo.cpp (+3-3)
- (modified) llvm/test/CodeGen/RISCV/zilsd-csr-duplicate.mir (+72-35)
``````````diff
diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
index 9306fe69ef427..46cd260b70bef 100644
--- a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
@@ -2274,8 +2274,12 @@ bool RISCVFrameLowering::spillCalleeSavedRegisters(
unsigned PushedRegNum = RVFI->getRVPushRegs();
if (PushedRegNum > 0) {
// Use encoded number to represent registers to spill.
- unsigned Opcode = getPushOpcode(
- RVFI->getPushPopKind(*MF), hasFP(*MF) && !RVFI->useQCIInterrupt(*MF));
+ // `QC.CM.PUSHFP` requires the rlist to include at least `{ra, s0}`.
+ // If only that is not the case, fall back to `QC.CM.PUSH` and let
+ // generic FP setup logic materialize FP explicitly.
+ bool CanUsePushFP =
+ hasFP(*MF) && !RVFI->useQCIInterrupt(*MF) && PushedRegNum >= 2;
+ unsigned Opcode = getPushOpcode(RVFI->getPushPopKind(*MF), CanUsePushFP);
unsigned RegEnc = RISCVZC::encodeRegListNumRegs(PushedRegNum);
MachineInstrBuilder PushBuilder =
BuildMI(MBB, MI, DL, TII.get(Opcode))
diff --git a/llvm/lib/Target/RISCV/RISCVMachineFunctionInfo.cpp b/llvm/lib/Target/RISCV/RISCVMachineFunctionInfo.cpp
index 4944df1e731a8..638461396df2a 100644
--- a/llvm/lib/Target/RISCV/RISCVMachineFunctionInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVMachineFunctionInfo.cpp
@@ -125,9 +125,9 @@ bool RISCVMachineFunctionInfo::hasImplicitFPUpdates(
switch (getPushPopKind(MF)) {
case PushPopKind::VendorXqccmp:
- // When using Xqccmp, we will use `QC.CM.PUSHFP` when Frame Pointers are
- // enabled, which will update FP.
- return true;
+ // `QC.CM.PUSHFP` updates FP implicitly, but it is only encodable when the
+ // push rlist includes `{ra, s0}`.
+ return RVPushRegs >= 2;
default:
break;
}
diff --git a/llvm/test/CodeGen/RISCV/zilsd-csr-duplicate.mir b/llvm/test/CodeGen/RISCV/zilsd-csr-duplicate.mir
index 5fda434cab827..4079d76a70e14 100644
--- a/llvm/test/CodeGen/RISCV/zilsd-csr-duplicate.mir
+++ b/llvm/test/CodeGen/RISCV/zilsd-csr-duplicate.mir
@@ -1,6 +1,8 @@
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
# RUN: llc -mtriple riscv32 -mattr=+zcmp,+zilsd --run-pass=prologepilog %s -verify-machineinstrs -o - \
-# RUN: | FileCheck %s
+# RUN: | FileCheck --check-prefix=ZCMP-ZILSD %s
+# RUN: llc -mtriple riscv32 -mattr=+xqccmp,+zilsd --run-pass=prologepilog %s -verify-machineinstrs -o - \
+# RUN: | FileCheck --check-prefix=XQCCMP-ZILSD %s
--- |
declare i32 @foo()
@@ -85,40 +87,75 @@ body: |
bb.0.entry:
liveins: $x10, $x11
- ; CHECK-LABEL: name: zilsd_dup_csr
- ; CHECK: liveins: $x10, $x11, $x1, $x18_x19
- ; CHECK-NEXT: {{ $}}
- ; CHECK-NEXT: frame-setup CM_PUSH 4, 16, implicit-def $x2, implicit $x2, implicit $x1
- ; CHECK-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 32
- ; CHECK-NEXT: frame-setup CFI_INSTRUCTION offset $x1, -4
- ; CHECK-NEXT: frame-setup SD_RV32 killed $x8_x9, $x2, 8 :: (store (s64) into %stack.1)
- ; CHECK-NEXT: frame-setup SD_RV32 killed $x18_x19, $x2, 0 :: (store (s64) into %stack.2)
- ; CHECK-NEXT: frame-setup CFI_INSTRUCTION offset $x8, -24
- ; CHECK-NEXT: frame-setup CFI_INSTRUCTION offset $x9, -20
- ; CHECK-NEXT: frame-setup CFI_INSTRUCTION offset $x18, -32
- ; CHECK-NEXT: frame-setup CFI_INSTRUCTION offset $x19, -28
- ; CHECK-NEXT: $x8 = frame-setup ADDI $x2, 32
- ; CHECK-NEXT: frame-setup CFI_INSTRUCTION def_cfa $x8, 0
- ; CHECK-NEXT: renamable $x9 = COPY $x11
- ; CHECK-NEXT: renamable $x18 = COPY $x10
- ; CHECK-NEXT: PseudoCALL target-flags(riscv-call) @foo, csr_ilp32_lp64, implicit-def dead $x1, implicit-def $x2, implicit-def dead $x10
- ; CHECK-NEXT: renamable $x9 = nuw ADDI killed renamable $x9, 15
- ; CHECK-NEXT: renamable $x9 = ANDI killed renamable $x9, -16
- ; CHECK-NEXT: renamable $x10 = SUB $x2, killed renamable $x9
- ; CHECK-NEXT: $x2 = COPY renamable $x10
- ; CHECK-NEXT: SW killed renamable $x10, killed renamable $x18, 0 :: (store (s32) into %ir.p, align 8)
- ; CHECK-NEXT: $x2 = frame-destroy ADDI $x8, -32
- ; CHECK-NEXT: frame-destroy CFI_INSTRUCTION def_cfa $x2, 32
- ; CHECK-NEXT: $x8_x9 = frame-destroy LD_RV32 $x2, 8 :: (load (s64) from %stack.1)
- ; CHECK-NEXT: $x18_x19 = frame-destroy LD_RV32 $x2, 0 :: (load (s64) from %stack.2)
- ; CHECK-NEXT: frame-destroy CFI_INSTRUCTION restore $x8
- ; CHECK-NEXT: frame-destroy CFI_INSTRUCTION restore $x9
- ; CHECK-NEXT: frame-destroy CFI_INSTRUCTION restore $x18
- ; CHECK-NEXT: frame-destroy CFI_INSTRUCTION restore $x19
- ; CHECK-NEXT: frame-destroy CM_POP 4, 16, implicit-def $x2, implicit $x2, implicit-def $x1
- ; CHECK-NEXT: frame-destroy CFI_INSTRUCTION restore $x1
- ; CHECK-NEXT: frame-destroy CFI_INSTRUCTION def_cfa_offset 0
- ; CHECK-NEXT: PseudoTAIL target-flags(riscv-call) @bar, csr_ilp32_lp64, implicit $x2
+ ; ZCMP-ZILSD-LABEL: name: zilsd_dup_csr
+ ; ZCMP-ZILSD: liveins: $x10, $x11, $x1, $x18_x19
+ ; ZCMP-ZILSD-NEXT: {{ $}}
+ ; ZCMP-ZILSD-NEXT: frame-setup CM_PUSH 4, 16, implicit-def $x2, implicit $x2, implicit $x1
+ ; ZCMP-ZILSD-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 32
+ ; ZCMP-ZILSD-NEXT: frame-setup CFI_INSTRUCTION offset $x1, -4
+ ; ZCMP-ZILSD-NEXT: frame-setup SD_RV32 killed $x8_x9, $x2, 8 :: (store (s64) into %stack.1)
+ ; ZCMP-ZILSD-NEXT: frame-setup SD_RV32 killed $x18_x19, $x2, 0 :: (store (s64) into %stack.2)
+ ; ZCMP-ZILSD-NEXT: frame-setup CFI_INSTRUCTION offset $x8, -24
+ ; ZCMP-ZILSD-NEXT: frame-setup CFI_INSTRUCTION offset $x9, -20
+ ; ZCMP-ZILSD-NEXT: frame-setup CFI_INSTRUCTION offset $x18, -32
+ ; ZCMP-ZILSD-NEXT: frame-setup CFI_INSTRUCTION offset $x19, -28
+ ; ZCMP-ZILSD-NEXT: $x8 = frame-setup ADDI $x2, 32
+ ; ZCMP-ZILSD-NEXT: frame-setup CFI_INSTRUCTION def_cfa $x8, 0
+ ; ZCMP-ZILSD-NEXT: renamable $x9 = COPY $x11
+ ; ZCMP-ZILSD-NEXT: renamable $x18 = COPY $x10
+ ; ZCMP-ZILSD-NEXT: PseudoCALL target-flags(riscv-call) @foo, csr_ilp32_lp64, implicit-def dead $x1, implicit-def $x2, implicit-def dead $x10
+ ; ZCMP-ZILSD-NEXT: renamable $x9 = nuw ADDI killed renamable $x9, 15
+ ; ZCMP-ZILSD-NEXT: renamable $x9 = ANDI killed renamable $x9, -16
+ ; ZCMP-ZILSD-NEXT: renamable $x10 = SUB $x2, killed renamable $x9
+ ; ZCMP-ZILSD-NEXT: $x2 = COPY renamable $x10
+ ; ZCMP-ZILSD-NEXT: SW killed renamable $x10, killed renamable $x18, 0 :: (store (s32) into %ir.p, align 8)
+ ; ZCMP-ZILSD-NEXT: $x2 = frame-destroy ADDI $x8, -32
+ ; ZCMP-ZILSD-NEXT: frame-destroy CFI_INSTRUCTION def_cfa $x2, 32
+ ; ZCMP-ZILSD-NEXT: $x8_x9 = frame-destroy LD_RV32 $x2, 8 :: (load (s64) from %stack.1)
+ ; ZCMP-ZILSD-NEXT: $x18_x19 = frame-destroy LD_RV32 $x2, 0 :: (load (s64) from %stack.2)
+ ; ZCMP-ZILSD-NEXT: frame-destroy CFI_INSTRUCTION restore $x8
+ ; ZCMP-ZILSD-NEXT: frame-destroy CFI_INSTRUCTION restore $x9
+ ; ZCMP-ZILSD-NEXT: frame-destroy CFI_INSTRUCTION restore $x18
+ ; ZCMP-ZILSD-NEXT: frame-destroy CFI_INSTRUCTION restore $x19
+ ; ZCMP-ZILSD-NEXT: frame-destroy CM_POP 4, 16, implicit-def $x2, implicit $x2, implicit-def $x1
+ ; ZCMP-ZILSD-NEXT: frame-destroy CFI_INSTRUCTION restore $x1
+ ; ZCMP-ZILSD-NEXT: frame-destroy CFI_INSTRUCTION def_cfa_offset 0
+ ; ZCMP-ZILSD-NEXT: PseudoTAIL target-flags(riscv-call) @bar, csr_ilp32_lp64, implicit $x2
+ ;
+ ; XQCCMP-ZILSD-LABEL: name: zilsd_dup_csr
+ ; XQCCMP-ZILSD: liveins: $x10, $x11, $x1, $x18_x19
+ ; XQCCMP-ZILSD-NEXT: {{ $}}
+ ; XQCCMP-ZILSD-NEXT: frame-setup QC_CM_PUSH 4, 16, implicit-def $x2, implicit $x2, implicit $x1
+ ; XQCCMP-ZILSD-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 32
+ ; XQCCMP-ZILSD-NEXT: frame-setup CFI_INSTRUCTION offset $x1, -4
+ ; XQCCMP-ZILSD-NEXT: frame-setup SD_RV32 killed $x8_x9, $x2, 8 :: (store (s64) into %stack.1)
+ ; XQCCMP-ZILSD-NEXT: frame-setup SD_RV32 killed $x18_x19, $x2, 0 :: (store (s64) into %stack.2)
+ ; XQCCMP-ZILSD-NEXT: frame-setup CFI_INSTRUCTION offset $x8, -24
+ ; XQCCMP-ZILSD-NEXT: frame-setup CFI_INSTRUCTION offset $x9, -20
+ ; XQCCMP-ZILSD-NEXT: frame-setup CFI_INSTRUCTION offset $x18, -32
+ ; XQCCMP-ZILSD-NEXT: frame-setup CFI_INSTRUCTION offset $x19, -28
+ ; XQCCMP-ZILSD-NEXT: $x8 = frame-setup ADDI $x2, 32
+ ; XQCCMP-ZILSD-NEXT: frame-setup CFI_INSTRUCTION def_cfa $x8, 0
+ ; XQCCMP-ZILSD-NEXT: renamable $x9 = COPY $x11
+ ; XQCCMP-ZILSD-NEXT: renamable $x18 = COPY $x10
+ ; XQCCMP-ZILSD-NEXT: PseudoCALL target-flags(riscv-call) @foo, csr_ilp32_lp64, implicit-def dead $x1, implicit-def $x2, implicit-def dead $x10
+ ; XQCCMP-ZILSD-NEXT: renamable $x9 = nuw ADDI killed renamable $x9, 15
+ ; XQCCMP-ZILSD-NEXT: renamable $x9 = ANDI killed renamable $x9, -16
+ ; XQCCMP-ZILSD-NEXT: renamable $x10 = SUB $x2, killed renamable $x9
+ ; XQCCMP-ZILSD-NEXT: $x2 = COPY renamable $x10
+ ; XQCCMP-ZILSD-NEXT: SW killed renamable $x10, killed renamable $x18, 0 :: (store (s32) into %ir.p, align 8)
+ ; XQCCMP-ZILSD-NEXT: $x2 = frame-destroy ADDI $x8, -32
+ ; XQCCMP-ZILSD-NEXT: frame-destroy CFI_INSTRUCTION def_cfa $x2, 32
+ ; XQCCMP-ZILSD-NEXT: $x8_x9 = frame-destroy LD_RV32 $x2, 8 :: (load (s64) from %stack.1)
+ ; XQCCMP-ZILSD-NEXT: $x18_x19 = frame-destroy LD_RV32 $x2, 0 :: (load (s64) from %stack.2)
+ ; XQCCMP-ZILSD-NEXT: frame-destroy CFI_INSTRUCTION restore $x8
+ ; XQCCMP-ZILSD-NEXT: frame-destroy CFI_INSTRUCTION restore $x9
+ ; XQCCMP-ZILSD-NEXT: frame-destroy CFI_INSTRUCTION restore $x18
+ ; XQCCMP-ZILSD-NEXT: frame-destroy CFI_INSTRUCTION restore $x19
+ ; XQCCMP-ZILSD-NEXT: frame-destroy QC_CM_POP 4, 16, implicit-def $x2, implicit $x2, implicit-def $x1
+ ; XQCCMP-ZILSD-NEXT: frame-destroy CFI_INSTRUCTION restore $x1
+ ; XQCCMP-ZILSD-NEXT: frame-destroy CFI_INSTRUCTION def_cfa_offset 0
+ ; XQCCMP-ZILSD-NEXT: PseudoTAIL target-flags(riscv-call) @bar, csr_ilp32_lp64, implicit $x2
renamable $x9 = COPY $x11
renamable $x18 = COPY $x10
ADJCALLSTACKDOWN 0, 0, implicit-def dead $x2, implicit $x2
``````````
</details>
https://github.com/llvm/llvm-project/pull/200541
More information about the llvm-commits
mailing list