[llvm] [llvm][RISCV] Use zilsd for callee-saved register spill/restore on RV32 (PR #184794)

Brandon Wu via llvm-commits llvm-commits at lists.llvm.org
Fri Mar 6 07:34:37 PST 2026


================
@@ -1633,6 +1651,59 @@ void RISCVFrameLowering::determineCalleeSaves(MachineFunction &MF,
   if (RVFI->isPushable(MF) && SavedRegs.test(RISCV::X26))
     SavedRegs.set(RISCV::X27);
 
+  // For Zilsd on RV32, append GPRPair registers to the CSR list. This prevents
+  // the need to create register sets for each abi which is a lot more complex.
+  // Don't use Zilsd for callee-saved coalescing if the required alignment
+  // exceeds the stack alignment.
+  bool UseZilsd = !STI.is64Bit() && STI.hasStdExtZilsd() &&
+                  STI.getZilsdAlign() <= getStackAlign();
+  if (UseZilsd) {
+    SmallVector<MCPhysReg, 32> NewCSRs;
+    SmallSet<MCPhysReg, 16> CSRSet;
+    for (unsigned i = 0; CSRegs[i]; ++i) {
+      NewCSRs.push_back(CSRegs[i]);
+      CSRSet.insert(CSRegs[i]);
+    }
+
+    // Append GPRPair registers for pairs where both sub-registers are in CSR
+    // list. Iterate through all GPRPairs and check if both sub-regs are CSRs.
+    for (MCPhysReg Pair : RISCV::GPRPairRegClass) {
+      MCPhysReg EvenReg = TRI.getSubReg(Pair, RISCV::sub_gpr_even);
+      MCPhysReg OddReg = TRI.getSubReg(Pair, RISCV::sub_gpr_odd);
+      if (CSRSet.contains(EvenReg) && CSRSet.contains(OddReg))
+        NewCSRs.push_back(Pair);
+    }
+
+    MRI.setCalleeSavedRegs(NewCSRs);
+    CSRegs = MRI.getCalleeSavedRegs();
+  }
+
+  // Check if all subregisters are marked for saving. If so, set the super
+  // register bit. For GPRPair, only check sub_gpr_even and sub_gpr_odd, not
+  // aliases like X8_W or X8_H which are not set in SavedRegs.
+  for (unsigned i = 0; CSRegs[i]; ++i) {
+    unsigned CSReg = CSRegs[i];
+    bool CombineToSuperReg;
+    if (RISCV::GPRPairRegClass.contains(CSReg)) {
+      MCPhysReg EvenReg = TRI.getSubReg(CSReg, RISCV::sub_gpr_even);
+      MCPhysReg OddReg = TRI.getSubReg(CSReg, RISCV::sub_gpr_odd);
+      CombineToSuperReg = SavedRegs.test(EvenReg) && SavedRegs.test(OddReg);
+      // If s0(x8) is used as FP we can't generate load/store pair because it
+      // breaks the frame chain.
+      if (hasFP(MF) && CSReg == RISCV::X8_X9)
+        CombineToSuperReg = false;
+    } else {
+      auto SubRegs = TRI.subregs(CSReg);
+      CombineToSuperReg =
+          !SubRegs.empty() && llvm::all_of(SubRegs, [&](unsigned Reg) {
+            return SavedRegs.test(Reg);
+          });
+    }
+
+    if (CombineToSuperReg)
+      SavedRegs.set(CSReg);
----------------
4vtomat wrote:

I think later in `assignCalleeSavedSpillSlots` it will check if its super register is set to prevent double savings

https://github.com/llvm/llvm-project/pull/184794


More information about the llvm-commits mailing list