[clang] [llvm] [RISCV] Support frame pointers in SiFive CLIC preemptible handlers (PR #221318)

Zeyi Xu via cfe-commits cfe-commits at lists.llvm.org
Sat Sep 19 03:29:04 PDT 2026


https://github.com/zeyi2 updated https://github.com/llvm/llvm-project/pull/221318

>From 3d68c396cb421db24087426ad7cbb3934d284ddf Mon Sep 17 00:00:00 2001
From: Zeyi Xu <mitchell.xu2 at gmail.com>
Date: Sat, 5 Sep 2026 02:48:58 +0800
Subject: [PATCH 1/5] [RISCV] Support frame pointers in SiFive CLIC preemptible
 handlers

---
 llvm/lib/Target/RISCV/RISCVFrameLowering.cpp  | 184 ++++++++++++------
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp   |   6 -
 .../RISCV/sifive-interrupt-attr-err.ll        |  12 --
 .../RISCV/sifive-interrupt-frame-pointer.ll   | 155 +++++++++++++++
 4 files changed, 280 insertions(+), 77 deletions(-)
 delete mode 100644 llvm/test/CodeGen/RISCV/sifive-interrupt-attr-err.ll
 create mode 100644 llvm/test/CodeGen/RISCV/sifive-interrupt-frame-pointer.ll

diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
index 458cf32bf8c1bd..3ba4ef969c4ed1 100644
--- a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
@@ -265,9 +265,8 @@ createSiFivePreemptibleInterruptFrameEntries(MachineFunction &MF,
       *MF.getSubtarget<RISCVSubtarget>().getRegisterInfo();
   MachineFrameInfo &MFI = MF.getFrameInfo();
 
-  // Create two frame objects for spilling X8 and X9, which will be done in
-  // `emitSiFiveCLICPreemptibleSaves`. This is in addition to any other stack
-  // objects we might have for X8 and X9, as they might be saved twice.
+  // Create two frame objects for preserving X8 and X9 or saving mcause and
+  // mepc, depending on whether the function uses a frame pointer.
   for (int I = 0; I < 2; ++I) {
     int FI = MFI.CreateStackObject(TRI.getSpillSize(RC), TRI.getSpillAlign(RC),
                                    true);
@@ -289,35 +288,60 @@ static void emitSiFiveCLICPreemptibleSaves(MachineFunction &MF,
 
   // FIXME: CFI Information here is nonexistent/wrong.
 
-  // X8 and X9 might be stored into the stack twice, initially into the
-  // `interruptCSRFrameIndex` here, and then maybe again into their CSI frame
-  // index.
-  //
-  // This is done instead of telling the register allocator that we need two
-  // VRegs to store the value of `mcause` and `mepc` through the instruction,
-  // which affects other passes.
-  TII->storeRegToStackSlot(MBB, MBBI, RISCV::X8, /* IsKill=*/true,
-                           RVFI->getInterruptCSRFrameIndex(0),
-                           &RISCV::GPRRegClass, Register(),
-                           MachineInstr::FrameSetup);
-  TII->storeRegToStackSlot(MBB, MBBI, RISCV::X9, /* IsKill=*/true,
-                           RVFI->getInterruptCSRFrameIndex(1),
-                           &RISCV::GPRRegClass, Register(),
-                           MachineInstr::FrameSetup);
-
-  // Put `mcause` into X8 (s0), and `mepc` into X9 (s1). If either of these are
-  // used in the function, then they will appear in `getUnmanagedCSI` and will
-  // be saved again.
-  BuildMI(MBB, MBBI, DL, TII->get(RISCV::CSRRS))
-      .addReg(RISCV::X8, RegState::Define)
-      .addImm(RISCVSysReg::mcause)
-      .addReg(RISCV::X0)
-      .setMIFlag(MachineInstr::FrameSetup);
-  BuildMI(MBB, MBBI, DL, TII->get(RISCV::CSRRS))
-      .addReg(RISCV::X9, RegState::Define)
-      .addImm(RISCVSysReg::mepc)
-      .addReg(RISCV::X0)
-      .setMIFlag(MachineInstr::FrameSetup);
+  if (STI.getFrameLowering()->hasFP(MF)) {
+    // With a frame pointer, use X5 as a temporary to save mcause and mepc to
+    // the stack. `determineCalleeSaves` adds X5 to the callee-saved set, so
+    // X5's original value has already been preserved.
+    BuildMI(MBB, MBBI, DL, TII->get(RISCV::CSRRS))
+        .addReg(RISCV::X5, RegState::Define)
+        .addImm(RISCVSysReg::mcause)
+        .addReg(RISCV::X0)
+        .setMIFlag(MachineInstr::FrameSetup);
+    TII->storeRegToStackSlot(MBB, MBBI, RISCV::X5, /* IsKill=*/true,
+                             RVFI->getInterruptCSRFrameIndex(0),
+                             &RISCV::GPRRegClass, Register(),
+                             MachineInstr::FrameSetup);
+
+    BuildMI(MBB, MBBI, DL, TII->get(RISCV::CSRRS))
+        .addReg(RISCV::X5, RegState::Define)
+        .addImm(RISCVSysReg::mepc)
+        .addReg(RISCV::X0)
+        .setMIFlag(MachineInstr::FrameSetup);
+    TII->storeRegToStackSlot(MBB, MBBI, RISCV::X5, /* IsKill=*/true,
+                             RVFI->getInterruptCSRFrameIndex(1),
+                             &RISCV::GPRRegClass, Register(),
+                             MachineInstr::FrameSetup);
+  } else {
+    // X8 and X9 might be stored into the stack twice, initially into the
+    // `interruptCSRFrameIndex` here, and then maybe again into their CSI frame
+    // index.
+    //
+    // This is done instead of telling the register allocator that we need two
+    // VRegs to store the value of `mcause` and `mepc` through the instruction,
+    // which affects other passes.
+    TII->storeRegToStackSlot(MBB, MBBI, RISCV::X8, /* IsKill=*/true,
+                             RVFI->getInterruptCSRFrameIndex(0),
+                             &RISCV::GPRRegClass, Register(),
+                             MachineInstr::FrameSetup);
+    TII->storeRegToStackSlot(MBB, MBBI, RISCV::X9, /* IsKill=*/true,
+                             RVFI->getInterruptCSRFrameIndex(1),
+                             &RISCV::GPRRegClass, Register(),
+                             MachineInstr::FrameSetup);
+
+    // Put `mcause` into X8 (s0), and `mepc` into X9 (s1). If either of these
+    // are used in the function, then they will appear in `getUnmanagedCSI` and
+    // will be saved again.
+    BuildMI(MBB, MBBI, DL, TII->get(RISCV::CSRRS))
+        .addReg(RISCV::X8, RegState::Define)
+        .addImm(RISCVSysReg::mcause)
+        .addReg(RISCV::X0)
+        .setMIFlag(MachineInstr::FrameSetup);
+    BuildMI(MBB, MBBI, DL, TII->get(RISCV::CSRRS))
+        .addReg(RISCV::X9, RegState::Define)
+        .addImm(RISCVSysReg::mepc)
+        .addReg(RISCV::X0)
+        .setMIFlag(MachineInstr::FrameSetup);
+  }
 
   // Enable interrupts.
   BuildMI(MBB, MBBI, DL, TII->get(RISCV::CSRRSI))
@@ -348,30 +372,54 @@ static void emitSiFiveCLICPreemptibleRestores(MachineFunction &MF,
       .addImm(8)
       .setMIFlag(MachineInstr::FrameDestroy);
 
-  // Restore `mepc` from x9 (s1), and `mcause` from x8 (s0). If either were used
-  // in the function, they have already been restored once, so now have the
-  // value stored in `emitSiFiveCLICPreemptibleSaves`.
-  BuildMI(MBB, MBBI, DL, TII->get(RISCV::CSRRW))
-      .addReg(RISCV::X0, RegState::Define)
-      .addImm(RISCVSysReg::mepc)
-      .addReg(RISCV::X9, RegState::Kill)
-      .setMIFlag(MachineInstr::FrameDestroy);
-  BuildMI(MBB, MBBI, DL, TII->get(RISCV::CSRRW))
-      .addReg(RISCV::X0, RegState::Define)
-      .addImm(RISCVSysReg::mcause)
-      .addReg(RISCV::X8, RegState::Kill)
-      .setMIFlag(MachineInstr::FrameDestroy);
+  if (STI.getFrameLowering()->hasFP(MF)) {
+    // Restore `mepc` and `mcause` through X5. The normal callee-saved register
+    // handling will restore the value X5 held on entry to the handler later.
+    TII->loadRegFromStackSlot(MBB, MBBI, RISCV::X5,
+                              RVFI->getInterruptCSRFrameIndex(1),
+                              &RISCV::GPRRegClass, Register(),
+                              RISCV::NoSubRegister, MachineInstr::FrameDestroy);
+    BuildMI(MBB, MBBI, DL, TII->get(RISCV::CSRRW))
+        .addReg(RISCV::X0, RegState::Define)
+        .addImm(RISCVSysReg::mepc)
+        .addReg(RISCV::X5, RegState::Kill)
+        .setMIFlag(MachineInstr::FrameDestroy);
 
-  // X8 and X9 need to be restored to their values on function entry, which we
-  // saved onto the stack in `emitSiFiveCLICPreemptibleSaves`.
-  TII->loadRegFromStackSlot(MBB, MBBI, RISCV::X9,
-                            RVFI->getInterruptCSRFrameIndex(1),
-                            &RISCV::GPRRegClass, Register(),
-                            RISCV::NoSubRegister, MachineInstr::FrameDestroy);
-  TII->loadRegFromStackSlot(MBB, MBBI, RISCV::X8,
-                            RVFI->getInterruptCSRFrameIndex(0),
-                            &RISCV::GPRRegClass, Register(),
-                            RISCV::NoSubRegister, MachineInstr::FrameDestroy);
+    TII->loadRegFromStackSlot(MBB, MBBI, RISCV::X5,
+                              RVFI->getInterruptCSRFrameIndex(0),
+                              &RISCV::GPRRegClass, Register(),
+                              RISCV::NoSubRegister, MachineInstr::FrameDestroy);
+    BuildMI(MBB, MBBI, DL, TII->get(RISCV::CSRRW))
+        .addReg(RISCV::X0, RegState::Define)
+        .addImm(RISCVSysReg::mcause)
+        .addReg(RISCV::X5, RegState::Kill)
+        .setMIFlag(MachineInstr::FrameDestroy);
+  } else {
+    // Restore `mepc` from x9 (s1), and `mcause` from x8 (s0). If either were
+    // used in the function, they have already been restored once, so now have
+    // the value stored in `emitSiFiveCLICPreemptibleSaves`.
+    BuildMI(MBB, MBBI, DL, TII->get(RISCV::CSRRW))
+        .addReg(RISCV::X0, RegState::Define)
+        .addImm(RISCVSysReg::mepc)
+        .addReg(RISCV::X9, RegState::Kill)
+        .setMIFlag(MachineInstr::FrameDestroy);
+    BuildMI(MBB, MBBI, DL, TII->get(RISCV::CSRRW))
+        .addReg(RISCV::X0, RegState::Define)
+        .addImm(RISCVSysReg::mcause)
+        .addReg(RISCV::X8, RegState::Kill)
+        .setMIFlag(MachineInstr::FrameDestroy);
+
+    // X8 and X9 need to be restored to their values on function entry, which we
+    // saved onto the stack in `emitSiFiveCLICPreemptibleSaves`.
+    TII->loadRegFromStackSlot(MBB, MBBI, RISCV::X9,
+                              RVFI->getInterruptCSRFrameIndex(1),
+                              &RISCV::GPRRegClass, Register(),
+                              RISCV::NoSubRegister, MachineInstr::FrameDestroy);
+    TII->loadRegFromStackSlot(MBB, MBBI, RISCV::X8,
+                              RVFI->getInterruptCSRFrameIndex(0),
+                              &RISCV::GPRRegClass, Register(),
+                              RISCV::NoSubRegister, MachineInstr::FrameDestroy);
+  }
 }
 
 // Get the ID of the libcall used for spilling and restoring callee saved
@@ -1138,8 +1186,10 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
                   NeedProbe, ProbeSize, DynAllocation,
                   MachineInstr::FrameSetup);
 
-  // Save SiFive CLIC CSRs into Stack
-  emitSiFiveCLICPreemptibleSaves(MF, MBB, MBBI, DL);
+  // Without a frame pointer, `mcause` and `mepc` remain in X8 and X9 across
+  // the handler.
+  if (!hasFP(MF))
+    emitSiFiveCLICPreemptibleSaves(MF, MBB, MBBI, DL);
 
   // The frame pointer is callee-saved, and code has been generated for us to
   // save it to the stack. We need to skip over the storing of callee-saved
@@ -1191,6 +1241,11 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
       CFIBuilder.buildDefCFA(FPReg, RVFI->getVarArgsSaveSize());
   }
 
+  // With a frame pointer, X5 is used as a temporary, so save the CSRs after
+  // the normal callee-saved spill has preserved X5's original value.
+  if (hasFP(MF))
+    emitSiFiveCLICPreemptibleSaves(MF, MBB, MBBI, DL);
+
   uint64_t SecondSPAdjustAmount = 0;
   // Emit the second SP adjustment after saving callee saved registers.
   if (FirstSPAdjustAmount) {
@@ -1401,6 +1456,10 @@ void RISCVFrameLowering::emitEpilogue(MachineFunction &MF,
   if (NeedsDwarfCFI && hasFP(MF))
     CFIBuilder.buildDefCFA(SPReg, RealStackSize);
 
+  // With a frame pointer, restore the SiFive CLIC CSRs through X5.
+  if (hasFP(MF))
+    emitSiFiveCLICPreemptibleRestores(MF, MBB, FirstScalarCSRRestoreInsn, DL);
+
   // Skip to after the restores of scalar callee-saved registers
   // FIXME: assumes exactly one instruction is used to restore each
   // callee-saved register.
@@ -1469,7 +1528,9 @@ void RISCVFrameLowering::emitEpilogue(MachineFunction &MF,
     }
   }
 
-  emitSiFiveCLICPreemptibleRestores(MF, MBB, MBBI, DL);
+  // Without a frame pointer, X8 and X9 hold mcause and mepc here.
+  if (!hasFP(MF))
+    emitSiFiveCLICPreemptibleRestores(MF, MBB, MBBI, DL);
 
   // Deallocate stack if StackSize isn't a zero yet. If this is a QCI interrupt
   // function, there will be a leftover offset which is deallocated by
@@ -1869,8 +1930,13 @@ void RISCVFrameLowering::determineCalleeSaves(MachineFunction &MF,
   if (hasBP(MF))
     SavedRegs.set(RISCVABI::getBPReg());
 
-  // When using cm.push/pop we must save X27 if we save X26.
   auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>();
+  // X5 is used as a temporary for saving and restoring mcause and mepc when
+  // X8 is occupied by the frame pointer.
+  if (RVFI->isSiFivePreemptibleInterrupt(MF) && hasFP(MF))
+    SavedRegs.set(RISCV::X5);
+
+  // When using cm.push/pop we must save X27 if we save X26.
   if (RVFI->isPushable(MF) && SavedRegs.test(RISCV::X26))
     SavedRegs.set(RISCV::X27);
 
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index b2f684952dd904..bec9f87ff2a197 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -27073,12 +27073,6 @@ SDValue RISCVTargetLowering::LowerFormalArguments(
 
     if (Kind == "rnmi" && !Subtarget.hasStdExtSmrnmi())
       reportFatalUsageError("'rnmi' interrupt kind requires Srnmi extension");
-    const TargetFrameLowering *TFI = Subtarget.getFrameLowering();
-    if (Kind.starts_with("SiFive-CLIC-preemptible") && TFI->hasFP(MF))
-      Func.getContext().diagnose(DiagnosticInfoUnsupported{
-          Func,
-          "'SiFive-CLIC-preemptible' interrupt functions cannot have a frame "
-          "pointer"});
   }
 
   EVT PtrVT = getPointerTy(DAG.getDataLayout());
diff --git a/llvm/test/CodeGen/RISCV/sifive-interrupt-attr-err.ll b/llvm/test/CodeGen/RISCV/sifive-interrupt-attr-err.ll
deleted file mode 100644
index f0e1f16cf6e54b..00000000000000
--- a/llvm/test/CodeGen/RISCV/sifive-interrupt-attr-err.ll
+++ /dev/null
@@ -1,12 +0,0 @@
-; RUN: not llc -mtriple riscv32-unknown-elf -mattr=+experimental-xsfmclic -o - %s 2>&1 \
-; RUN:   | FileCheck %s
-; RUN: not llc -mtriple riscv64-unknown-elf -mattr=+experimental-xsfmclic -o - %s 2>&1 \
-; RUN:   | FileCheck %s
-
-;; Test that these report regular errors.
-
-; CHECK: error: <unknown>:0:0: in function preemptible void (): 'SiFive-CLIC-preemptible' interrupt functions cannot have a frame pointer
-
-define void @preemptible() "interrupt"="SiFive-CLIC-preemptible" "frame-pointer"="all" {
-  ret void
-}
diff --git a/llvm/test/CodeGen/RISCV/sifive-interrupt-frame-pointer.ll b/llvm/test/CodeGen/RISCV/sifive-interrupt-frame-pointer.ll
new file mode 100644
index 00000000000000..da025cf86e65e3
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/sifive-interrupt-frame-pointer.ll
@@ -0,0 +1,155 @@
+; RUN: llc -mtriple riscv32-unknown-elf -mattr=+experimental-xsfmclic \
+; RUN:   -verify-machineinstrs < %s | FileCheck %s --check-prefix=RV32
+; RUN: llc -mtriple riscv64-unknown-elf -mattr=+experimental-xsfmclic \
+; RUN:   -verify-machineinstrs < %s | FileCheck %s --check-prefix=RV64
+
+ at size = external global i32
+
+declare void @use(ptr)
+
+define void @preemptible() "interrupt"="SiFive-CLIC-preemptible" "frame-pointer"="all" {
+; RV32-LABEL: preemptible:
+; RV32:         sw t0, 16(sp)
+; RV32:         sw s0, 12(sp)
+; RV32:         addi s0, sp, 32
+; RV32:         csrr t0, mcause
+; RV32-NEXT:    sw t0, 28(sp)
+; RV32-NEXT:    csrr t0, mepc
+; RV32-NEXT:    sw t0, 24(sp)
+; RV32-NEXT:    csrsi mstatus, 8
+; RV32:         csrci mstatus, 8
+; RV32-NEXT:    lw t0, 24(sp)
+; RV32-NEXT:    csrw mepc, t0
+; RV32-NEXT:    lw t0, 28(sp)
+; RV32-NEXT:    csrw mcause, t0
+; RV32:         lw t0, 16(sp)
+; RV32:         lw s0, 12(sp)
+; RV32:         mret
+;
+; RV64-LABEL: preemptible:
+; RV64:         sd t0, 16(sp)
+; RV64:         sd s0, 8(sp)
+; RV64:         addi s0, sp, 48
+; RV64:         csrr t0, mcause
+; RV64-NEXT:    sd t0, 40(sp)
+; RV64-NEXT:    csrr t0, mepc
+; RV64-NEXT:    sd t0, 32(sp)
+; RV64-NEXT:    csrsi mstatus, 8
+; RV64:         csrci mstatus, 8
+; RV64-NEXT:    ld t0, 32(sp)
+; RV64-NEXT:    csrw mepc, t0
+; RV64-NEXT:    ld t0, 40(sp)
+; RV64-NEXT:    csrw mcause, t0
+; RV64:         ld t0, 16(sp)
+; RV64:         ld s0, 8(sp)
+; RV64:         mret
+  ret void
+}
+
+define void @preemptible_stack_swap() "interrupt"="SiFive-CLIC-preemptible-stack-swap" "frame-pointer"="all" {
+; RV32-LABEL: preemptible_stack_swap:
+; RV32:         csrrw sp, sf.mscratchcsw, sp
+; RV32:         addi s0, sp, 32
+; RV32:         csrr t0, mcause
+; RV32:         csrsi mstatus, 8
+; RV32:         csrci mstatus, 8
+; RV32:         csrw mepc, t0
+; RV32:         csrw mcause, t0
+; RV32:         lw s0, 12(sp)
+; RV32:         csrrw sp, sf.mscratchcsw, sp
+; RV32-NEXT:    mret
+;
+; RV64-LABEL: preemptible_stack_swap:
+; RV64:         csrrw sp, sf.mscratchcsw, sp
+; RV64:         addi s0, sp, 48
+; RV64:         csrr t0, mcause
+; RV64:         csrsi mstatus, 8
+; RV64:         csrci mstatus, 8
+; RV64:         csrw mepc, t0
+; RV64:         csrw mcause, t0
+; RV64:         ld s0, 8(sp)
+; RV64:         csrrw sp, sf.mscratchcsw, sp
+; RV64-NEXT:    mret
+  ret void
+}
+
+define void @preemptible_var_alloca() "interrupt"="SiFive-CLIC-preemptible" "frame-pointer"="none" {
+; RV32-LABEL: preemptible_var_alloca:
+; RV32:         addi s0, sp, 80
+; RV32:         csrr t0, mcause
+; RV32-NEXT:    sw t0, -4(s0)
+; RV32-NEXT:    csrr t0, mepc
+; RV32-NEXT:    sw t0, -8(s0)
+; RV32-NEXT:    csrsi mstatus, 8
+; RV32:         sub a0, sp, a0
+; RV32:         mv sp, a0
+; RV32:         call use
+; RV32:         addi sp, s0, -80
+; RV32:         csrci mstatus, 8
+; RV32-NEXT:    lw t0, -8(s0)
+; RV32-NEXT:    csrw mepc, t0
+; RV32-NEXT:    lw t0, -4(s0)
+; RV32-NEXT:    csrw mcause, t0
+; RV32:         mret
+;
+; RV64-LABEL: preemptible_var_alloca:
+; RV64:         addi s0, sp, 160
+; RV64:         csrr t0, mcause
+; RV64-NEXT:    sd t0, -8(s0)
+; RV64-NEXT:    csrr t0, mepc
+; RV64-NEXT:    sd t0, -16(s0)
+; RV64-NEXT:    csrsi mstatus, 8
+; RV64:         sub a0, sp, a0
+; RV64:         mv sp, a0
+; RV64:         call use
+; RV64:         addi sp, s0, -160
+; RV64:         csrci mstatus, 8
+; RV64-NEXT:    ld t0, -16(s0)
+; RV64-NEXT:    csrw mepc, t0
+; RV64-NEXT:    ld t0, -8(s0)
+; RV64-NEXT:    csrw mcause, t0
+; RV64:         mret
+  %count = load volatile i32, ptr @size
+  %object = alloca i8, i32 %count, align 16
+  call void @use(ptr %object)
+  ret void
+}
+
+define void @preemptible_realign() "interrupt"="SiFive-CLIC-preemptible" "frame-pointer"="none" {
+; RV32-LABEL: preemptible_realign:
+; RV32:         addi s0, sp,
+; RV32:         csrr t0, mcause
+; RV32-NEXT:    sw t0,
+; RV32-NEXT:    csrr t0, mepc
+; RV32-NEXT:    sw t0,
+; RV32-NEXT:    csrsi mstatus, 8
+; RV32:         andi sp, sp, -64
+; RV32:         call use
+; RV32:         addi sp, s0,
+; RV32:         csrci mstatus, 8
+; RV32-NEXT:    lw t0, 184(sp)
+; RV32-NEXT:    csrw mepc, t0
+; RV32-NEXT:    lw t0, 188(sp)
+; RV32-NEXT:    csrw mcause, t0
+; RV32:         mret
+;
+; RV64-LABEL: preemptible_realign:
+; RV64:         addi s0, sp,
+; RV64:         csrr t0, mcause
+; RV64-NEXT:    sd t0,
+; RV64-NEXT:    csrr t0, mepc
+; RV64-NEXT:    sd t0,
+; RV64-NEXT:    csrsi mstatus, 8
+; RV64:         andi sp, sp, -64
+; RV64:         call use
+; RV64:         addi sp, s0,
+; RV64:         csrci mstatus, 8
+; RV64-NEXT:    ld t0, 240(sp)
+; RV64-NEXT:    csrw mepc, t0
+; RV64-NEXT:    ld t0, 248(sp)
+; RV64-NEXT:    csrw mcause, t0
+; RV64:         mret
+  %object = alloca [64 x i8], align 64
+  call void @use(ptr %object)
+  ret void
+}

>From 440de9e8c904a0664b9742db118b831f3bfdbc55 Mon Sep 17 00:00:00 2001
From: Zeyi Xu <mitchell.xu2 at gmail.com>
Date: Sat, 5 Sep 2026 02:50:00 +0800
Subject: [PATCH 2/5] forgot to add release notes, oops

---
 clang/docs/ReleaseNotes.md | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index edf74404c49257..fd84d4b28ec66d 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -722,8 +722,7 @@ features cannot lower the translation-unit ABI level;
 - Added a new warning when the same interrupt type is specified more than
   once in a RISC-V `interrupt` attribute.
 
-- SiFive CLIC preemptible interrupt handlers now diagnose unsupported frame
-  pointers instead of producing a backend fatal error.
+- SiFive CLIC preemptible interrupt handlers now support frame pointers.
 
 - Added `-march=native` for better compatibility with ARM, AArch64, and X86. This
   option will be treated like `-mcpu=native` if `-mcpu` is not present. If

>From 9560437627966650e1cf374ce91c82c932f2b453 Mon Sep 17 00:00:00 2001
From: Zeyi Xu <mitchell.xu2 at gmail.com>
Date: Wed, 9 Sep 2026 23:54:13 +0800
Subject: [PATCH 3/5] rework codegen, fix issues

---
 llvm/lib/Target/RISCV/RISCVFrameLowering.cpp  | 244 ++++----
 .../CodeGen/RISCV/sifive-interrupt-attr.ll    | 545 ++++++++++++------
 .../RISCV/sifive-interrupt-frame-flags.ll     |  29 +-
 .../RISCV/sifive-interrupt-frame-pointer.ll   | 175 ++++--
 4 files changed, 646 insertions(+), 347 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
index 3ba4ef969c4ed1..0e2d17301f2eed 100644
--- a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
@@ -265,8 +265,7 @@ createSiFivePreemptibleInterruptFrameEntries(MachineFunction &MF,
       *MF.getSubtarget<RISCVSubtarget>().getRegisterInfo();
   MachineFrameInfo &MFI = MF.getFrameInfo();
 
-  // Create two frame objects for preserving X8 and X9 or saving mcause and
-  // mepc, depending on whether the function uses a frame pointer.
+  // Create two frame objects for saving `mcause` and `mepc`.
   for (int I = 0; I < 2; ++I) {
     int FI = MFI.CreateStackObject(TRI.getSpillSize(RC), TRI.getSpillAlign(RC),
                                    true);
@@ -274,6 +273,16 @@ createSiFivePreemptibleInterruptFrameEntries(MachineFunction &MF,
   }
 }
 
+// The scratch register retains an ordinary CSI slot, but its save and restore
+// are emitted explicitly as part of the SiFive CLIC interrupt sequence.
+static int getSiFiveCLICScratchFrameIndex(const MachineFunction &MF) {
+  const auto &CSI = MF.getFrameInfo().getCalleeSavedInfo();
+  auto ScratchCS = llvm::find_if(
+      CSI, [](const CalleeSavedInfo &CS) { return CS.getReg() == RISCV::X5; });
+  assert(ScratchCS != CSI.end() && "Missing SiFive CLIC scratch spill slot");
+  return ScratchCS->getFrameIdx();
+}
+
 static void emitSiFiveCLICPreemptibleSaves(MachineFunction &MF,
                                            MachineBasicBlock &MBB,
                                            MachineBasicBlock::iterator MBBI,
@@ -286,62 +295,33 @@ static void emitSiFiveCLICPreemptibleSaves(MachineFunction &MF,
   const auto &STI = MF.getSubtarget<RISCVSubtarget>();
   const RISCVInstrInfo *TII = STI.getInstrInfo();
 
-  // FIXME: CFI Information here is nonexistent/wrong.
+  // FIXME: CFI information for `mcause` and `mepc` is missing.
 
-  if (STI.getFrameLowering()->hasFP(MF)) {
-    // With a frame pointer, use X5 as a temporary to save mcause and mepc to
-    // the stack. `determineCalleeSaves` adds X5 to the callee-saved set, so
-    // X5's original value has already been preserved.
-    BuildMI(MBB, MBBI, DL, TII->get(RISCV::CSRRS))
-        .addReg(RISCV::X5, RegState::Define)
-        .addImm(RISCVSysReg::mcause)
-        .addReg(RISCV::X0)
-        .setMIFlag(MachineInstr::FrameSetup);
-    TII->storeRegToStackSlot(MBB, MBBI, RISCV::X5, /* IsKill=*/true,
-                             RVFI->getInterruptCSRFrameIndex(0),
-                             &RISCV::GPRRegClass, Register(),
-                             MachineInstr::FrameSetup);
-
-    BuildMI(MBB, MBBI, DL, TII->get(RISCV::CSRRS))
-        .addReg(RISCV::X5, RegState::Define)
-        .addImm(RISCVSysReg::mepc)
-        .addReg(RISCV::X0)
-        .setMIFlag(MachineInstr::FrameSetup);
-    TII->storeRegToStackSlot(MBB, MBBI, RISCV::X5, /* IsKill=*/true,
-                             RVFI->getInterruptCSRFrameIndex(1),
-                             &RISCV::GPRRegClass, Register(),
-                             MachineInstr::FrameSetup);
-  } else {
-    // X8 and X9 might be stored into the stack twice, initially into the
-    // `interruptCSRFrameIndex` here, and then maybe again into their CSI frame
-    // index.
-    //
-    // This is done instead of telling the register allocator that we need two
-    // VRegs to store the value of `mcause` and `mepc` through the instruction,
-    // which affects other passes.
-    TII->storeRegToStackSlot(MBB, MBBI, RISCV::X8, /* IsKill=*/true,
-                             RVFI->getInterruptCSRFrameIndex(0),
-                             &RISCV::GPRRegClass, Register(),
-                             MachineInstr::FrameSetup);
-    TII->storeRegToStackSlot(MBB, MBBI, RISCV::X9, /* IsKill=*/true,
-                             RVFI->getInterruptCSRFrameIndex(1),
-                             &RISCV::GPRRegClass, Register(),
-                             MachineInstr::FrameSetup);
-
-    // Put `mcause` into X8 (s0), and `mepc` into X9 (s1). If either of these
-    // are used in the function, then they will appear in `getUnmanagedCSI` and
-    // will be saved again.
-    BuildMI(MBB, MBBI, DL, TII->get(RISCV::CSRRS))
-        .addReg(RISCV::X8, RegState::Define)
-        .addImm(RISCVSysReg::mcause)
-        .addReg(RISCV::X0)
-        .setMIFlag(MachineInstr::FrameSetup);
-    BuildMI(MBB, MBBI, DL, TII->get(RISCV::CSRRS))
-        .addReg(RISCV::X9, RegState::Define)
-        .addImm(RISCVSysReg::mepc)
-        .addReg(RISCV::X0)
-        .setMIFlag(MachineInstr::FrameSetup);
-  }
+  // Preserve X5 before using it to save the interrupt CSRs. Other GPRs
+  // are saved by the ordinary spill sequence after preemption is enabled.
+  int ScratchFI = getSiFiveCLICScratchFrameIndex(MF);
+  TII->storeRegToStackSlot(MBB, MBBI, RISCV::X5, /*IsKill=*/true, ScratchFI,
+                           &RISCV::GPRRegClass, Register(),
+                           MachineInstr::FrameSetup);
+  if (needsDwarfCFI(MF))
+    CFIInstBuilder(MBB, MBBI, MachineInstr::FrameSetup)
+        .buildOffset(RISCV::X5, MF.getFrameInfo().getObjectOffset(ScratchFI));
+
+  BuildMI(MBB, MBBI, DL, TII->get(RISCV::CSRRS))
+      .addReg(RISCV::X5, RegState::Define)
+      .addImm(RISCVSysReg::mcause)
+      .addReg(RISCV::X0)
+      .setMIFlag(MachineInstr::FrameSetup);
+  TII->storeRegToStackSlot(MBB, MBBI, RISCV::X5, /* IsKill=*/true,
+                           RVFI->getInterruptCSRFrameIndex(0),
+                           &RISCV::GPRRegClass, Register(),
+                           MachineInstr::FrameSetup);
+
+  BuildMI(MBB, MBBI, DL, TII->get(RISCV::CSRRS))
+      .addReg(RISCV::X5, RegState::Define)
+      .addImm(RISCVSysReg::mepc)
+      .addReg(RISCV::X0)
+      .setMIFlag(MachineInstr::FrameSetup);
 
   // Enable interrupts.
   BuildMI(MBB, MBBI, DL, TII->get(RISCV::CSRRSI))
@@ -349,6 +329,10 @@ static void emitSiFiveCLICPreemptibleSaves(MachineFunction &MF,
       .addImm(RISCVSysReg::mstatus)
       .addImm(8)
       .setMIFlag(MachineInstr::FrameSetup);
+  TII->storeRegToStackSlot(MBB, MBBI, RISCV::X5, /* IsKill=*/true,
+                           RVFI->getInterruptCSRFrameIndex(1),
+                           &RISCV::GPRRegClass, Register(),
+                           MachineInstr::FrameSetup);
 }
 
 static void emitSiFiveCLICPreemptibleRestores(MachineFunction &MF,
@@ -363,7 +347,14 @@ static void emitSiFiveCLICPreemptibleRestores(MachineFunction &MF,
   const auto &STI = MF.getSubtarget<RISCVSubtarget>();
   const RISCVInstrInfo *TII = STI.getInstrInfo();
 
-  // FIXME: CFI Information here is nonexistent/wrong.
+  // FIXME: CFI information for `mcause` and `mepc` is missing.
+
+  // Load mepc while preemption is still enabled. A nested handler preserves
+  // X5. Interrupts only need to be disabled before writing the CSRs back.
+  TII->loadRegFromStackSlot(MBB, MBBI, RISCV::X5,
+                            RVFI->getInterruptCSRFrameIndex(1),
+                            &RISCV::GPRRegClass, Register(),
+                            RISCV::NoSubRegister, MachineInstr::FrameDestroy);
 
   // Disable interrupts.
   BuildMI(MBB, MBBI, DL, TII->get(RISCV::CSRRCI))
@@ -372,54 +363,33 @@ static void emitSiFiveCLICPreemptibleRestores(MachineFunction &MF,
       .addImm(8)
       .setMIFlag(MachineInstr::FrameDestroy);
 
-  if (STI.getFrameLowering()->hasFP(MF)) {
-    // Restore `mepc` and `mcause` through X5. The normal callee-saved register
-    // handling will restore the value X5 held on entry to the handler later.
-    TII->loadRegFromStackSlot(MBB, MBBI, RISCV::X5,
-                              RVFI->getInterruptCSRFrameIndex(1),
-                              &RISCV::GPRRegClass, Register(),
-                              RISCV::NoSubRegister, MachineInstr::FrameDestroy);
-    BuildMI(MBB, MBBI, DL, TII->get(RISCV::CSRRW))
-        .addReg(RISCV::X0, RegState::Define)
-        .addImm(RISCVSysReg::mepc)
-        .addReg(RISCV::X5, RegState::Kill)
-        .setMIFlag(MachineInstr::FrameDestroy);
+  // Restore `mepc` and `mcause` through X5, then restore the value X5 held
+  // on entry to the handler.
+  BuildMI(MBB, MBBI, DL, TII->get(RISCV::CSRRW))
+      .addReg(RISCV::X0, RegState::Define)
+      .addImm(RISCVSysReg::mepc)
+      .addReg(RISCV::X5, RegState::Kill)
+      .setMIFlag(MachineInstr::FrameDestroy);
 
-    TII->loadRegFromStackSlot(MBB, MBBI, RISCV::X5,
-                              RVFI->getInterruptCSRFrameIndex(0),
-                              &RISCV::GPRRegClass, Register(),
-                              RISCV::NoSubRegister, MachineInstr::FrameDestroy);
-    BuildMI(MBB, MBBI, DL, TII->get(RISCV::CSRRW))
-        .addReg(RISCV::X0, RegState::Define)
-        .addImm(RISCVSysReg::mcause)
-        .addReg(RISCV::X5, RegState::Kill)
-        .setMIFlag(MachineInstr::FrameDestroy);
-  } else {
-    // Restore `mepc` from x9 (s1), and `mcause` from x8 (s0). If either were
-    // used in the function, they have already been restored once, so now have
-    // the value stored in `emitSiFiveCLICPreemptibleSaves`.
-    BuildMI(MBB, MBBI, DL, TII->get(RISCV::CSRRW))
-        .addReg(RISCV::X0, RegState::Define)
-        .addImm(RISCVSysReg::mepc)
-        .addReg(RISCV::X9, RegState::Kill)
-        .setMIFlag(MachineInstr::FrameDestroy);
-    BuildMI(MBB, MBBI, DL, TII->get(RISCV::CSRRW))
-        .addReg(RISCV::X0, RegState::Define)
-        .addImm(RISCVSysReg::mcause)
-        .addReg(RISCV::X8, RegState::Kill)
-        .setMIFlag(MachineInstr::FrameDestroy);
+  TII->loadRegFromStackSlot(MBB, MBBI, RISCV::X5,
+                            RVFI->getInterruptCSRFrameIndex(0),
+                            &RISCV::GPRRegClass, Register(),
+                            RISCV::NoSubRegister, MachineInstr::FrameDestroy);
+  BuildMI(MBB, MBBI, DL, TII->get(RISCV::CSRRW))
+      .addReg(RISCV::X0, RegState::Define)
+      .addImm(RISCVSysReg::mcause)
+      .addReg(RISCV::X5, RegState::Kill)
+      .setMIFlag(MachineInstr::FrameDestroy);
 
-    // X8 and X9 need to be restored to their values on function entry, which we
-    // saved onto the stack in `emitSiFiveCLICPreemptibleSaves`.
-    TII->loadRegFromStackSlot(MBB, MBBI, RISCV::X9,
-                              RVFI->getInterruptCSRFrameIndex(1),
-                              &RISCV::GPRRegClass, Register(),
-                              RISCV::NoSubRegister, MachineInstr::FrameDestroy);
-    TII->loadRegFromStackSlot(MBB, MBBI, RISCV::X8,
-                              RVFI->getInterruptCSRFrameIndex(0),
-                              &RISCV::GPRRegClass, Register(),
-                              RISCV::NoSubRegister, MachineInstr::FrameDestroy);
-  }
+  // The ordinary reloads have finished. Recover the interrupted value of X5
+  // only after it has restored both CSRs.
+  TII->loadRegFromStackSlot(MBB, MBBI, RISCV::X5,
+                            getSiFiveCLICScratchFrameIndex(MF),
+                            &RISCV::GPRRegClass, Register(),
+                            RISCV::NoSubRegister, MachineInstr::FrameDestroy);
+  if (needsDwarfCFI(MF))
+    CFIInstBuilder(MBB, MBBI, MachineInstr::FrameDestroy)
+        .buildRestore(RISCV::X5);
 }
 
 // Get the ID of the libcall used for spilling and restoring callee saved
@@ -642,6 +612,20 @@ getUnmanagedCSI(const MachineFunction &MF,
   return NonLibcallCSI;
 }
 
+// Exclude X5 from ordinary spills and restores for SiFive CLIC preemptible
+// handlers, which save and restore it explicitly.
+static SmallVector<CalleeSavedInfo, 8>
+getScalarSpillCSI(const MachineFunction &MF,
+                  const std::vector<CalleeSavedInfo> &CSI,
+                  bool ReverseOrder = false) {
+  auto ScalarCSI = getUnmanagedCSI(MF, CSI, ReverseOrder);
+  if (MF.getInfo<RISCVMachineFunctionInfo>()->isSiFivePreemptibleInterrupt(MF))
+    llvm::erase_if(ScalarCSI, [](const CalleeSavedInfo &CS) {
+      return CS.getReg() == RISCV::X5;
+    });
+  return ScalarCSI;
+}
+
 static SmallVector<CalleeSavedInfo, 8>
 getRVVCalleeSavedInfo(const MachineFunction &MF,
                       const std::vector<CalleeSavedInfo> &CSI) {
@@ -1076,7 +1060,7 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
   // callee-saved register.
   MBBI =
       std::prev(MBBI, getRVVCalleeSavedInfo(MF, CSI).size() +
-                          getUnmanagedCSI(MF, CSI, PreferAscendingLS).size());
+                          getScalarSpillCSI(MF, CSI, PreferAscendingLS).size());
   CFIInstBuilder CFIBuilder(MBB, MBBI, MachineInstr::FrameSetup);
   bool NeedsDwarfCFI = needsDwarfCFI(MF);
 
@@ -1186,10 +1170,8 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
                   NeedProbe, ProbeSize, DynAllocation,
                   MachineInstr::FrameSetup);
 
-  // Without a frame pointer, `mcause` and `mepc` remain in X8 and X9 across
-  // the handler.
-  if (!hasFP(MF))
-    emitSiFiveCLICPreemptibleSaves(MF, MBB, MBBI, DL);
+  // Save SiFive CLIC CSRs into Stack
+  emitSiFiveCLICPreemptibleSaves(MF, MBB, MBBI, DL);
 
   // The frame pointer is callee-saved, and code has been generated for us to
   // save it to the stack. We need to skip over the storing of callee-saved
@@ -1197,14 +1179,14 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
   // to the stack, not before.
   // FIXME: assumes exactly one instruction is used to save each callee-saved
   // register.
-  std::advance(MBBI, getUnmanagedCSI(MF, CSI, PreferAscendingLS).size());
+  std::advance(MBBI, getScalarSpillCSI(MF, CSI, PreferAscendingLS).size());
   CFIBuilder.setInsertPoint(MBBI);
 
   // Iterate over list of callee-saved registers and emit .cfi_offset
   // directives.
   if (NeedsDwarfCFI) {
     for (const CalleeSavedInfo &CS :
-         getUnmanagedCSI(MF, CSI, PreferAscendingLS)) {
+         getScalarSpillCSI(MF, CSI, PreferAscendingLS)) {
       MCRegister Reg = CS.getReg();
       int64_t Offset = MFI.getObjectOffset(CS.getFrameIdx());
       // Emit CFI for both sub-registers. The even register is at the base
@@ -1241,11 +1223,6 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
       CFIBuilder.buildDefCFA(FPReg, RVFI->getVarArgsSaveSize());
   }
 
-  // With a frame pointer, X5 is used as a temporary, so save the CSRs after
-  // the normal callee-saved spill has preserved X5's original value.
-  if (hasFP(MF))
-    emitSiFiveCLICPreemptibleSaves(MF, MBB, MBBI, DL);
-
   uint64_t SecondSPAdjustAmount = 0;
   // Emit the second SP adjustment after saving callee saved registers.
   if (FirstSPAdjustAmount) {
@@ -1456,15 +1433,12 @@ void RISCVFrameLowering::emitEpilogue(MachineFunction &MF,
   if (NeedsDwarfCFI && hasFP(MF))
     CFIBuilder.buildDefCFA(SPReg, RealStackSize);
 
-  // With a frame pointer, restore the SiFive CLIC CSRs through X5.
-  if (hasFP(MF))
-    emitSiFiveCLICPreemptibleRestores(MF, MBB, FirstScalarCSRRestoreInsn, DL);
-
   // Skip to after the restores of scalar callee-saved registers
   // FIXME: assumes exactly one instruction is used to restore each
   // callee-saved register.
   MBBI = std::next(FirstScalarCSRRestoreInsn,
-                   getUnmanagedCSI(MF, CSI, PreferAscendingLS).size());
+                   getScalarSpillCSI(MF, CSI, PreferAscendingLS).size());
+  emitSiFiveCLICPreemptibleRestores(MF, MBB, MBBI, DL);
   CFIBuilder.setInsertPoint(MBBI);
 
   if (getLibCallID(MF, CSI) != -1) {
@@ -1483,7 +1457,7 @@ void RISCVFrameLowering::emitEpilogue(MachineFunction &MF,
   // Recover callee-saved registers.
   if (NeedsDwarfCFI) {
     for (const CalleeSavedInfo &CS :
-         getUnmanagedCSI(MF, CSI, PreferAscendingLS)) {
+         getScalarSpillCSI(MF, CSI, PreferAscendingLS)) {
       MCRegister Reg = CS.getReg();
       // Emit CFI for both sub-registers.
       if (RISCV::GPRPairRegClass.contains(Reg)) {
@@ -1528,10 +1502,6 @@ void RISCVFrameLowering::emitEpilogue(MachineFunction &MF,
     }
   }
 
-  // Without a frame pointer, X8 and X9 hold mcause and mepc here.
-  if (!hasFP(MF))
-    emitSiFiveCLICPreemptibleRestores(MF, MBB, MBBI, DL);
-
   // Deallocate stack if StackSize isn't a zero yet. If this is a QCI interrupt
   // function, there will be a leftover offset which is deallocated by
   // `QC.C.MILEAVERET`, otherwise getQCIInterruptStackSize() will be 0.
@@ -1712,7 +1682,10 @@ RISCVFrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI,
     MaxCSFI = std::max(CSI.front().getFrameIdx(), CSI.back().getFrameIdx());
   }
 
-  if (FI >= MinCSFI && FI <= MaxCSFI) {
+  bool IsInterruptCSR = RVFI->isSiFivePreemptibleInterrupt(MF) &&
+                        (FI == RVFI->getInterruptCSRFrameIndex(0) ||
+                         FI == RVFI->getInterruptCSRFrameIndex(1));
+  if ((FI >= MinCSFI && FI <= MaxCSFI) || IsInterruptCSR) {
     FrameReg = SPReg;
 
     if (FirstSPAdjustAmount)
@@ -1931,9 +1904,8 @@ void RISCVFrameLowering::determineCalleeSaves(MachineFunction &MF,
     SavedRegs.set(RISCVABI::getBPReg());
 
   auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>();
-  // X5 is used as a temporary for saving and restoring mcause and mepc when
-  // X8 is occupied by the frame pointer.
-  if (RVFI->isSiFivePreemptibleInterrupt(MF) && hasFP(MF))
+  // X5 is used as a temporary for saving and restoring `mcause` and `mepc`.
+  if (RVFI->isSiFivePreemptibleInterrupt(MF))
     SavedRegs.set(RISCV::X5);
 
   // When using cm.push/pop we must save X27 if we save X26.
@@ -2381,8 +2353,8 @@ bool RISCVFrameLowering::assignCalleeSavedSpillSlots(
   MachineFrameInfo &MFI = MF.getFrameInfo();
   const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
 
-  // Preemptible Interrupts have two additional Callee-save Frame Indexes,
-  // not tracked by `CSI`.
+  // Treat the two `mcause` and `mepc` frame indexes as callee-saved objects for
+  // frame layout purposes. They are not tracked by `CSI`.
   if (RVFI->isSiFivePreemptibleInterrupt(MF)) {
     for (int I = 0; I < 2; ++I) {
       int FI = RVFI->getInterruptCSRFrameIndex(I);
@@ -2558,10 +2530,10 @@ bool RISCVFrameLowering::spillCalleeSavedRegisters(
 
   // Manually spill values not spilled by libcall & Push/Pop.
   const auto &UnmanagedCSI =
-      getUnmanagedCSI(*MF, CSI, STI.preferAscendingLoadStore());
+      getScalarSpillCSI(*MF, CSI, STI.preferAscendingLoadStore());
   const auto &RVVCSI = getRVVCalleeSavedInfo(*MF, CSI);
 
-  auto storeRegsToStackSlots = [&](decltype(UnmanagedCSI) CSInfo) {
+  auto storeRegsToStackSlots = [&](ArrayRef<CalleeSavedInfo> CSInfo) {
     for (auto &CS : CSInfo) {
       // Insert the spill to the stack frame.
       MCRegister Reg = CS.getReg();
@@ -2652,10 +2624,10 @@ bool RISCVFrameLowering::restoreCalleeSavedRegisters(
   // loading RA and return by RA.  loadRegFromStackSlot can insert
   // multiple instructions.
   const auto &UnmanagedCSI =
-      getUnmanagedCSI(*MF, CSI, STI.preferAscendingLoadStore());
+      getScalarSpillCSI(*MF, CSI, STI.preferAscendingLoadStore());
   const auto &RVVCSI = getRVVCalleeSavedInfo(*MF, CSI);
 
-  auto loadRegFromStackSlot = [&](decltype(UnmanagedCSI) CSInfo) {
+  auto loadRegFromStackSlot = [&](ArrayRef<CalleeSavedInfo> CSInfo) {
     for (auto &CS : CSInfo) {
       MCRegister Reg = CS.getReg();
       const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg);
diff --git a/llvm/test/CodeGen/RISCV/sifive-interrupt-attr.ll b/llvm/test/CodeGen/RISCV/sifive-interrupt-attr.ll
index a7dead74716777..7afcc28c1343d8 100644
--- a/llvm/test/CodeGen/RISCV/sifive-interrupt-attr.ll
+++ b/llvm/test/CodeGen/RISCV/sifive-interrupt-attr.ll
@@ -11,7 +11,7 @@
 ; "preemptible" means that `mcause` and `mepc` should be saved and interrupts
 ; should be re-enabled by setting a bit in `mstatus`.
 
-; FIXME: A lot of the CFI information here is wrong.
+; FIXME: CFI information for the stack swap and CSRs is still missing.
 
 define void @stack_swap_empty() "interrupt"="SiFive-CLIC-stack-swap" {
 ; RV32-LABEL: stack_swap_empty:
@@ -78,35 +78,43 @@ define void @preemptible_empty() "interrupt"="SiFive-CLIC-preemptible" {
 ; RV32:       # %bb.0:
 ; RV32-NEXT:    addi sp, sp, -16
 ; RV32-NEXT:    .cfi_def_cfa_offset 16
-; RV32-NEXT:    sw s0, 12(sp) # 4-byte Folded Spill
-; RV32-NEXT:    sw s1, 8(sp) # 4-byte Folded Spill
-; RV32-NEXT:    csrr s0, mcause
-; RV32-NEXT:    csrr s1, mepc
+; RV32-NEXT:    sw t0, 4(sp) # 4-byte Folded Spill
+; RV32-NEXT:    .cfi_offset t0, -12
+; RV32-NEXT:    csrr t0, mcause
+; RV32-NEXT:    sw t0, 12(sp) # 4-byte Folded Spill
+; RV32-NEXT:    csrr t0, mepc
 ; RV32-NEXT:    csrsi mstatus, 8
+; RV32-NEXT:    sw t0, 8(sp) # 4-byte Folded Spill
+; RV32-NEXT:    lw t0, 8(sp) # 4-byte Folded Reload
 ; RV32-NEXT:    csrci mstatus, 8
-; RV32-NEXT:    csrw mepc, s1
-; RV32-NEXT:    csrw mcause, s0
-; RV32-NEXT:    lw s1, 8(sp) # 4-byte Folded Reload
-; RV32-NEXT:    lw s0, 12(sp) # 4-byte Folded Reload
+; RV32-NEXT:    csrw mepc, t0
+; RV32-NEXT:    lw t0, 12(sp) # 4-byte Folded Reload
+; RV32-NEXT:    csrw mcause, t0
+; RV32-NEXT:    lw t0, 4(sp) # 4-byte Folded Reload
+; RV32-NEXT:    .cfi_restore t0
 ; RV32-NEXT:    addi sp, sp, 16
 ; RV32-NEXT:    .cfi_def_cfa_offset 0
 ; RV32-NEXT:    mret
 ;
 ; RV64-LABEL: preemptible_empty:
 ; RV64:       # %bb.0:
-; RV64-NEXT:    addi sp, sp, -16
-; RV64-NEXT:    .cfi_def_cfa_offset 16
-; RV64-NEXT:    sd s0, 8(sp) # 8-byte Folded Spill
-; RV64-NEXT:    sd s1, 0(sp) # 8-byte Folded Spill
-; RV64-NEXT:    csrr s0, mcause
-; RV64-NEXT:    csrr s1, mepc
+; RV64-NEXT:    addi sp, sp, -32
+; RV64-NEXT:    .cfi_def_cfa_offset 32
+; RV64-NEXT:    sd t0, 8(sp) # 8-byte Folded Spill
+; RV64-NEXT:    .cfi_offset t0, -24
+; RV64-NEXT:    csrr t0, mcause
+; RV64-NEXT:    sd t0, 24(sp) # 8-byte Folded Spill
+; RV64-NEXT:    csrr t0, mepc
 ; RV64-NEXT:    csrsi mstatus, 8
+; RV64-NEXT:    sd t0, 16(sp) # 8-byte Folded Spill
+; RV64-NEXT:    ld t0, 16(sp) # 8-byte Folded Reload
 ; RV64-NEXT:    csrci mstatus, 8
-; RV64-NEXT:    csrw mepc, s1
-; RV64-NEXT:    csrw mcause, s0
-; RV64-NEXT:    ld s1, 0(sp) # 8-byte Folded Reload
-; RV64-NEXT:    ld s0, 8(sp) # 8-byte Folded Reload
-; RV64-NEXT:    addi sp, sp, 16
+; RV64-NEXT:    csrw mepc, t0
+; RV64-NEXT:    ld t0, 24(sp) # 8-byte Folded Reload
+; RV64-NEXT:    csrw mcause, t0
+; RV64-NEXT:    ld t0, 8(sp) # 8-byte Folded Reload
+; RV64-NEXT:    .cfi_restore t0
+; RV64-NEXT:    addi sp, sp, 32
 ; RV64-NEXT:    .cfi_def_cfa_offset 0
 ; RV64-NEXT:    mret
   ret void
@@ -118,16 +126,20 @@ define void @both_empty() "interrupt"="SiFive-CLIC-preemptible-stack-swap" {
 ; RV32-NEXT:    csrrw sp, sf.mscratchcsw, sp
 ; RV32-NEXT:    addi sp, sp, -16
 ; RV32-NEXT:    .cfi_def_cfa_offset 16
-; RV32-NEXT:    sw s0, 12(sp) # 4-byte Folded Spill
-; RV32-NEXT:    sw s1, 8(sp) # 4-byte Folded Spill
-; RV32-NEXT:    csrr s0, mcause
-; RV32-NEXT:    csrr s1, mepc
+; RV32-NEXT:    sw t0, 4(sp) # 4-byte Folded Spill
+; RV32-NEXT:    .cfi_offset t0, -12
+; RV32-NEXT:    csrr t0, mcause
+; RV32-NEXT:    sw t0, 12(sp) # 4-byte Folded Spill
+; RV32-NEXT:    csrr t0, mepc
 ; RV32-NEXT:    csrsi mstatus, 8
+; RV32-NEXT:    sw t0, 8(sp) # 4-byte Folded Spill
+; RV32-NEXT:    lw t0, 8(sp) # 4-byte Folded Reload
 ; RV32-NEXT:    csrci mstatus, 8
-; RV32-NEXT:    csrw mepc, s1
-; RV32-NEXT:    csrw mcause, s0
-; RV32-NEXT:    lw s1, 8(sp) # 4-byte Folded Reload
-; RV32-NEXT:    lw s0, 12(sp) # 4-byte Folded Reload
+; RV32-NEXT:    csrw mepc, t0
+; RV32-NEXT:    lw t0, 12(sp) # 4-byte Folded Reload
+; RV32-NEXT:    csrw mcause, t0
+; RV32-NEXT:    lw t0, 4(sp) # 4-byte Folded Reload
+; RV32-NEXT:    .cfi_restore t0
 ; RV32-NEXT:    addi sp, sp, 16
 ; RV32-NEXT:    .cfi_def_cfa_offset 0
 ; RV32-NEXT:    csrrw sp, sf.mscratchcsw, sp
@@ -136,19 +148,23 @@ define void @both_empty() "interrupt"="SiFive-CLIC-preemptible-stack-swap" {
 ; RV64-LABEL: both_empty:
 ; RV64:       # %bb.0:
 ; RV64-NEXT:    csrrw sp, sf.mscratchcsw, sp
-; RV64-NEXT:    addi sp, sp, -16
-; RV64-NEXT:    .cfi_def_cfa_offset 16
-; RV64-NEXT:    sd s0, 8(sp) # 8-byte Folded Spill
-; RV64-NEXT:    sd s1, 0(sp) # 8-byte Folded Spill
-; RV64-NEXT:    csrr s0, mcause
-; RV64-NEXT:    csrr s1, mepc
+; RV64-NEXT:    addi sp, sp, -32
+; RV64-NEXT:    .cfi_def_cfa_offset 32
+; RV64-NEXT:    sd t0, 8(sp) # 8-byte Folded Spill
+; RV64-NEXT:    .cfi_offset t0, -24
+; RV64-NEXT:    csrr t0, mcause
+; RV64-NEXT:    sd t0, 24(sp) # 8-byte Folded Spill
+; RV64-NEXT:    csrr t0, mepc
 ; RV64-NEXT:    csrsi mstatus, 8
+; RV64-NEXT:    sd t0, 16(sp) # 8-byte Folded Spill
+; RV64-NEXT:    ld t0, 16(sp) # 8-byte Folded Reload
 ; RV64-NEXT:    csrci mstatus, 8
-; RV64-NEXT:    csrw mepc, s1
-; RV64-NEXT:    csrw mcause, s0
-; RV64-NEXT:    ld s1, 0(sp) # 8-byte Folded Reload
-; RV64-NEXT:    ld s0, 8(sp) # 8-byte Folded Reload
-; RV64-NEXT:    addi sp, sp, 16
+; RV64-NEXT:    csrw mepc, t0
+; RV64-NEXT:    ld t0, 24(sp) # 8-byte Folded Reload
+; RV64-NEXT:    csrw mcause, t0
+; RV64-NEXT:    ld t0, 8(sp) # 8-byte Folded Reload
+; RV64-NEXT:    .cfi_restore t0
+; RV64-NEXT:    addi sp, sp, 32
 ; RV64-NEXT:    .cfi_def_cfa_offset 0
 ; RV64-NEXT:    csrrw sp, sf.mscratchcsw, sp
 ; RV64-NEXT:    mret
@@ -484,13 +500,14 @@ define void @preeemptible_caller() "interrupt"="SiFive-CLIC-preemptible" {
 ; RV32:       # %bb.0:
 ; RV32-NEXT:    addi sp, sp, -80
 ; RV32-NEXT:    .cfi_def_cfa_offset 80
-; RV32-NEXT:    sw s0, 76(sp) # 4-byte Folded Spill
-; RV32-NEXT:    sw s1, 72(sp) # 4-byte Folded Spill
-; RV32-NEXT:    csrr s0, mcause
-; RV32-NEXT:    csrr s1, mepc
+; RV32-NEXT:    sw t0, 64(sp) # 4-byte Folded Spill
+; RV32-NEXT:    .cfi_offset t0, -16
+; RV32-NEXT:    csrr t0, mcause
+; RV32-NEXT:    sw t0, 76(sp) # 4-byte Folded Spill
+; RV32-NEXT:    csrr t0, mepc
 ; RV32-NEXT:    csrsi mstatus, 8
+; RV32-NEXT:    sw t0, 72(sp) # 4-byte Folded Spill
 ; RV32-NEXT:    sw ra, 68(sp) # 4-byte Folded Spill
-; RV32-NEXT:    sw t0, 64(sp) # 4-byte Folded Spill
 ; RV32-NEXT:    sw t1, 60(sp) # 4-byte Folded Spill
 ; RV32-NEXT:    sw t2, 56(sp) # 4-byte Folded Spill
 ; RV32-NEXT:    sw a0, 52(sp) # 4-byte Folded Spill
@@ -506,7 +523,6 @@ define void @preeemptible_caller() "interrupt"="SiFive-CLIC-preemptible" {
 ; RV32-NEXT:    sw t5, 12(sp) # 4-byte Folded Spill
 ; RV32-NEXT:    sw t6, 8(sp) # 4-byte Folded Spill
 ; RV32-NEXT:    .cfi_offset ra, -12
-; RV32-NEXT:    .cfi_offset t0, -16
 ; RV32-NEXT:    .cfi_offset t1, -20
 ; RV32-NEXT:    .cfi_offset t2, -24
 ; RV32-NEXT:    .cfi_offset a0, -28
@@ -523,7 +539,6 @@ define void @preeemptible_caller() "interrupt"="SiFive-CLIC-preemptible" {
 ; RV32-NEXT:    .cfi_offset t6, -72
 ; RV32-NEXT:    call callee
 ; RV32-NEXT:    lw ra, 68(sp) # 4-byte Folded Reload
-; RV32-NEXT:    lw t0, 64(sp) # 4-byte Folded Reload
 ; RV32-NEXT:    lw t1, 60(sp) # 4-byte Folded Reload
 ; RV32-NEXT:    lw t2, 56(sp) # 4-byte Folded Reload
 ; RV32-NEXT:    lw a0, 52(sp) # 4-byte Folded Reload
@@ -538,8 +553,14 @@ define void @preeemptible_caller() "interrupt"="SiFive-CLIC-preemptible" {
 ; RV32-NEXT:    lw t4, 16(sp) # 4-byte Folded Reload
 ; RV32-NEXT:    lw t5, 12(sp) # 4-byte Folded Reload
 ; RV32-NEXT:    lw t6, 8(sp) # 4-byte Folded Reload
-; RV32-NEXT:    .cfi_restore ra
+; RV32-NEXT:    lw t0, 72(sp) # 4-byte Folded Reload
+; RV32-NEXT:    csrci mstatus, 8
+; RV32-NEXT:    csrw mepc, t0
+; RV32-NEXT:    lw t0, 76(sp) # 4-byte Folded Reload
+; RV32-NEXT:    csrw mcause, t0
+; RV32-NEXT:    lw t0, 64(sp) # 4-byte Folded Reload
 ; RV32-NEXT:    .cfi_restore t0
+; RV32-NEXT:    .cfi_restore ra
 ; RV32-NEXT:    .cfi_restore t1
 ; RV32-NEXT:    .cfi_restore t2
 ; RV32-NEXT:    .cfi_restore a0
@@ -554,11 +575,6 @@ define void @preeemptible_caller() "interrupt"="SiFive-CLIC-preemptible" {
 ; RV32-NEXT:    .cfi_restore t4
 ; RV32-NEXT:    .cfi_restore t5
 ; RV32-NEXT:    .cfi_restore t6
-; RV32-NEXT:    csrci mstatus, 8
-; RV32-NEXT:    csrw mepc, s1
-; RV32-NEXT:    csrw mcause, s0
-; RV32-NEXT:    lw s1, 72(sp) # 4-byte Folded Reload
-; RV32-NEXT:    lw s0, 76(sp) # 4-byte Folded Reload
 ; RV32-NEXT:    addi sp, sp, 80
 ; RV32-NEXT:    .cfi_def_cfa_offset 0
 ; RV32-NEXT:    mret
@@ -567,13 +583,14 @@ define void @preeemptible_caller() "interrupt"="SiFive-CLIC-preemptible" {
 ; RV64:       # %bb.0:
 ; RV64-NEXT:    addi sp, sp, -144
 ; RV64-NEXT:    .cfi_def_cfa_offset 144
-; RV64-NEXT:    sd s0, 136(sp) # 8-byte Folded Spill
-; RV64-NEXT:    sd s1, 128(sp) # 8-byte Folded Spill
-; RV64-NEXT:    csrr s0, mcause
-; RV64-NEXT:    csrr s1, mepc
+; RV64-NEXT:    sd t0, 112(sp) # 8-byte Folded Spill
+; RV64-NEXT:    .cfi_offset t0, -32
+; RV64-NEXT:    csrr t0, mcause
+; RV64-NEXT:    sd t0, 136(sp) # 8-byte Folded Spill
+; RV64-NEXT:    csrr t0, mepc
 ; RV64-NEXT:    csrsi mstatus, 8
+; RV64-NEXT:    sd t0, 128(sp) # 8-byte Folded Spill
 ; RV64-NEXT:    sd ra, 120(sp) # 8-byte Folded Spill
-; RV64-NEXT:    sd t0, 112(sp) # 8-byte Folded Spill
 ; RV64-NEXT:    sd t1, 104(sp) # 8-byte Folded Spill
 ; RV64-NEXT:    sd t2, 96(sp) # 8-byte Folded Spill
 ; RV64-NEXT:    sd a0, 88(sp) # 8-byte Folded Spill
@@ -589,7 +606,6 @@ define void @preeemptible_caller() "interrupt"="SiFive-CLIC-preemptible" {
 ; RV64-NEXT:    sd t5, 8(sp) # 8-byte Folded Spill
 ; RV64-NEXT:    sd t6, 0(sp) # 8-byte Folded Spill
 ; RV64-NEXT:    .cfi_offset ra, -24
-; RV64-NEXT:    .cfi_offset t0, -32
 ; RV64-NEXT:    .cfi_offset t1, -40
 ; RV64-NEXT:    .cfi_offset t2, -48
 ; RV64-NEXT:    .cfi_offset a0, -56
@@ -606,7 +622,6 @@ define void @preeemptible_caller() "interrupt"="SiFive-CLIC-preemptible" {
 ; RV64-NEXT:    .cfi_offset t6, -144
 ; RV64-NEXT:    call callee
 ; RV64-NEXT:    ld ra, 120(sp) # 8-byte Folded Reload
-; RV64-NEXT:    ld t0, 112(sp) # 8-byte Folded Reload
 ; RV64-NEXT:    ld t1, 104(sp) # 8-byte Folded Reload
 ; RV64-NEXT:    ld t2, 96(sp) # 8-byte Folded Reload
 ; RV64-NEXT:    ld a0, 88(sp) # 8-byte Folded Reload
@@ -621,8 +636,14 @@ define void @preeemptible_caller() "interrupt"="SiFive-CLIC-preemptible" {
 ; RV64-NEXT:    ld t4, 16(sp) # 8-byte Folded Reload
 ; RV64-NEXT:    ld t5, 8(sp) # 8-byte Folded Reload
 ; RV64-NEXT:    ld t6, 0(sp) # 8-byte Folded Reload
-; RV64-NEXT:    .cfi_restore ra
+; RV64-NEXT:    ld t0, 128(sp) # 8-byte Folded Reload
+; RV64-NEXT:    csrci mstatus, 8
+; RV64-NEXT:    csrw mepc, t0
+; RV64-NEXT:    ld t0, 136(sp) # 8-byte Folded Reload
+; RV64-NEXT:    csrw mcause, t0
+; RV64-NEXT:    ld t0, 112(sp) # 8-byte Folded Reload
 ; RV64-NEXT:    .cfi_restore t0
+; RV64-NEXT:    .cfi_restore ra
 ; RV64-NEXT:    .cfi_restore t1
 ; RV64-NEXT:    .cfi_restore t2
 ; RV64-NEXT:    .cfi_restore a0
@@ -637,11 +658,6 @@ define void @preeemptible_caller() "interrupt"="SiFive-CLIC-preemptible" {
 ; RV64-NEXT:    .cfi_restore t4
 ; RV64-NEXT:    .cfi_restore t5
 ; RV64-NEXT:    .cfi_restore t6
-; RV64-NEXT:    csrci mstatus, 8
-; RV64-NEXT:    csrw mepc, s1
-; RV64-NEXT:    csrw mcause, s0
-; RV64-NEXT:    ld s1, 128(sp) # 8-byte Folded Reload
-; RV64-NEXT:    ld s0, 136(sp) # 8-byte Folded Reload
 ; RV64-NEXT:    addi sp, sp, 144
 ; RV64-NEXT:    .cfi_def_cfa_offset 0
 ; RV64-NEXT:    mret
@@ -655,13 +671,14 @@ define void @both_caller() "interrupt"="SiFive-CLIC-preemptible-stack-swap" {
 ; RV32-NEXT:    csrrw sp, sf.mscratchcsw, sp
 ; RV32-NEXT:    addi sp, sp, -80
 ; RV32-NEXT:    .cfi_def_cfa_offset 80
-; RV32-NEXT:    sw s0, 76(sp) # 4-byte Folded Spill
-; RV32-NEXT:    sw s1, 72(sp) # 4-byte Folded Spill
-; RV32-NEXT:    csrr s0, mcause
-; RV32-NEXT:    csrr s1, mepc
+; RV32-NEXT:    sw t0, 64(sp) # 4-byte Folded Spill
+; RV32-NEXT:    .cfi_offset t0, -16
+; RV32-NEXT:    csrr t0, mcause
+; RV32-NEXT:    sw t0, 76(sp) # 4-byte Folded Spill
+; RV32-NEXT:    csrr t0, mepc
 ; RV32-NEXT:    csrsi mstatus, 8
+; RV32-NEXT:    sw t0, 72(sp) # 4-byte Folded Spill
 ; RV32-NEXT:    sw ra, 68(sp) # 4-byte Folded Spill
-; RV32-NEXT:    sw t0, 64(sp) # 4-byte Folded Spill
 ; RV32-NEXT:    sw t1, 60(sp) # 4-byte Folded Spill
 ; RV32-NEXT:    sw t2, 56(sp) # 4-byte Folded Spill
 ; RV32-NEXT:    sw a0, 52(sp) # 4-byte Folded Spill
@@ -677,7 +694,6 @@ define void @both_caller() "interrupt"="SiFive-CLIC-preemptible-stack-swap" {
 ; RV32-NEXT:    sw t5, 12(sp) # 4-byte Folded Spill
 ; RV32-NEXT:    sw t6, 8(sp) # 4-byte Folded Spill
 ; RV32-NEXT:    .cfi_offset ra, -12
-; RV32-NEXT:    .cfi_offset t0, -16
 ; RV32-NEXT:    .cfi_offset t1, -20
 ; RV32-NEXT:    .cfi_offset t2, -24
 ; RV32-NEXT:    .cfi_offset a0, -28
@@ -694,7 +710,6 @@ define void @both_caller() "interrupt"="SiFive-CLIC-preemptible-stack-swap" {
 ; RV32-NEXT:    .cfi_offset t6, -72
 ; RV32-NEXT:    call callee
 ; RV32-NEXT:    lw ra, 68(sp) # 4-byte Folded Reload
-; RV32-NEXT:    lw t0, 64(sp) # 4-byte Folded Reload
 ; RV32-NEXT:    lw t1, 60(sp) # 4-byte Folded Reload
 ; RV32-NEXT:    lw t2, 56(sp) # 4-byte Folded Reload
 ; RV32-NEXT:    lw a0, 52(sp) # 4-byte Folded Reload
@@ -709,8 +724,14 @@ define void @both_caller() "interrupt"="SiFive-CLIC-preemptible-stack-swap" {
 ; RV32-NEXT:    lw t4, 16(sp) # 4-byte Folded Reload
 ; RV32-NEXT:    lw t5, 12(sp) # 4-byte Folded Reload
 ; RV32-NEXT:    lw t6, 8(sp) # 4-byte Folded Reload
-; RV32-NEXT:    .cfi_restore ra
+; RV32-NEXT:    lw t0, 72(sp) # 4-byte Folded Reload
+; RV32-NEXT:    csrci mstatus, 8
+; RV32-NEXT:    csrw mepc, t0
+; RV32-NEXT:    lw t0, 76(sp) # 4-byte Folded Reload
+; RV32-NEXT:    csrw mcause, t0
+; RV32-NEXT:    lw t0, 64(sp) # 4-byte Folded Reload
 ; RV32-NEXT:    .cfi_restore t0
+; RV32-NEXT:    .cfi_restore ra
 ; RV32-NEXT:    .cfi_restore t1
 ; RV32-NEXT:    .cfi_restore t2
 ; RV32-NEXT:    .cfi_restore a0
@@ -725,11 +746,6 @@ define void @both_caller() "interrupt"="SiFive-CLIC-preemptible-stack-swap" {
 ; RV32-NEXT:    .cfi_restore t4
 ; RV32-NEXT:    .cfi_restore t5
 ; RV32-NEXT:    .cfi_restore t6
-; RV32-NEXT:    csrci mstatus, 8
-; RV32-NEXT:    csrw mepc, s1
-; RV32-NEXT:    csrw mcause, s0
-; RV32-NEXT:    lw s1, 72(sp) # 4-byte Folded Reload
-; RV32-NEXT:    lw s0, 76(sp) # 4-byte Folded Reload
 ; RV32-NEXT:    addi sp, sp, 80
 ; RV32-NEXT:    .cfi_def_cfa_offset 0
 ; RV32-NEXT:    csrrw sp, sf.mscratchcsw, sp
@@ -740,13 +756,14 @@ define void @both_caller() "interrupt"="SiFive-CLIC-preemptible-stack-swap" {
 ; RV64-NEXT:    csrrw sp, sf.mscratchcsw, sp
 ; RV64-NEXT:    addi sp, sp, -144
 ; RV64-NEXT:    .cfi_def_cfa_offset 144
-; RV64-NEXT:    sd s0, 136(sp) # 8-byte Folded Spill
-; RV64-NEXT:    sd s1, 128(sp) # 8-byte Folded Spill
-; RV64-NEXT:    csrr s0, mcause
-; RV64-NEXT:    csrr s1, mepc
+; RV64-NEXT:    sd t0, 112(sp) # 8-byte Folded Spill
+; RV64-NEXT:    .cfi_offset t0, -32
+; RV64-NEXT:    csrr t0, mcause
+; RV64-NEXT:    sd t0, 136(sp) # 8-byte Folded Spill
+; RV64-NEXT:    csrr t0, mepc
 ; RV64-NEXT:    csrsi mstatus, 8
+; RV64-NEXT:    sd t0, 128(sp) # 8-byte Folded Spill
 ; RV64-NEXT:    sd ra, 120(sp) # 8-byte Folded Spill
-; RV64-NEXT:    sd t0, 112(sp) # 8-byte Folded Spill
 ; RV64-NEXT:    sd t1, 104(sp) # 8-byte Folded Spill
 ; RV64-NEXT:    sd t2, 96(sp) # 8-byte Folded Spill
 ; RV64-NEXT:    sd a0, 88(sp) # 8-byte Folded Spill
@@ -762,7 +779,6 @@ define void @both_caller() "interrupt"="SiFive-CLIC-preemptible-stack-swap" {
 ; RV64-NEXT:    sd t5, 8(sp) # 8-byte Folded Spill
 ; RV64-NEXT:    sd t6, 0(sp) # 8-byte Folded Spill
 ; RV64-NEXT:    .cfi_offset ra, -24
-; RV64-NEXT:    .cfi_offset t0, -32
 ; RV64-NEXT:    .cfi_offset t1, -40
 ; RV64-NEXT:    .cfi_offset t2, -48
 ; RV64-NEXT:    .cfi_offset a0, -56
@@ -779,7 +795,6 @@ define void @both_caller() "interrupt"="SiFive-CLIC-preemptible-stack-swap" {
 ; RV64-NEXT:    .cfi_offset t6, -144
 ; RV64-NEXT:    call callee
 ; RV64-NEXT:    ld ra, 120(sp) # 8-byte Folded Reload
-; RV64-NEXT:    ld t0, 112(sp) # 8-byte Folded Reload
 ; RV64-NEXT:    ld t1, 104(sp) # 8-byte Folded Reload
 ; RV64-NEXT:    ld t2, 96(sp) # 8-byte Folded Reload
 ; RV64-NEXT:    ld a0, 88(sp) # 8-byte Folded Reload
@@ -794,8 +809,14 @@ define void @both_caller() "interrupt"="SiFive-CLIC-preemptible-stack-swap" {
 ; RV64-NEXT:    ld t4, 16(sp) # 8-byte Folded Reload
 ; RV64-NEXT:    ld t5, 8(sp) # 8-byte Folded Reload
 ; RV64-NEXT:    ld t6, 0(sp) # 8-byte Folded Reload
-; RV64-NEXT:    .cfi_restore ra
+; RV64-NEXT:    ld t0, 128(sp) # 8-byte Folded Reload
+; RV64-NEXT:    csrci mstatus, 8
+; RV64-NEXT:    csrw mepc, t0
+; RV64-NEXT:    ld t0, 136(sp) # 8-byte Folded Reload
+; RV64-NEXT:    csrw mcause, t0
+; RV64-NEXT:    ld t0, 112(sp) # 8-byte Folded Reload
 ; RV64-NEXT:    .cfi_restore t0
+; RV64-NEXT:    .cfi_restore ra
 ; RV64-NEXT:    .cfi_restore t1
 ; RV64-NEXT:    .cfi_restore t2
 ; RV64-NEXT:    .cfi_restore a0
@@ -810,11 +831,6 @@ define void @both_caller() "interrupt"="SiFive-CLIC-preemptible-stack-swap" {
 ; RV64-NEXT:    .cfi_restore t4
 ; RV64-NEXT:    .cfi_restore t5
 ; RV64-NEXT:    .cfi_restore t6
-; RV64-NEXT:    csrci mstatus, 8
-; RV64-NEXT:    csrw mepc, s1
-; RV64-NEXT:    csrw mcause, s0
-; RV64-NEXT:    ld s1, 128(sp) # 8-byte Folded Reload
-; RV64-NEXT:    ld s0, 136(sp) # 8-byte Folded Reload
 ; RV64-NEXT:    addi sp, sp, 144
 ; RV64-NEXT:    .cfi_def_cfa_offset 0
 ; RV64-NEXT:    csrrw sp, sf.mscratchcsw, sp
@@ -928,57 +944,65 @@ define void @stack_swap_clobber_fp() "interrupt"="SiFive-CLIC-stack-swap" "frame
 define void @preemptible_clobber() "interrupt"="SiFive-CLIC-preemptible" {
 ; RV32-LABEL: preemptible_clobber:
 ; RV32:       # %bb.0:
-; RV32-NEXT:    addi sp, sp, -16
-; RV32-NEXT:    .cfi_def_cfa_offset 16
-; RV32-NEXT:    sw s0, 12(sp) # 4-byte Folded Spill
-; RV32-NEXT:    sw s1, 8(sp) # 4-byte Folded Spill
-; RV32-NEXT:    csrr s0, mcause
-; RV32-NEXT:    csrr s1, mepc
+; RV32-NEXT:    addi sp, sp, -32
+; RV32-NEXT:    .cfi_def_cfa_offset 32
+; RV32-NEXT:    sw t0, 20(sp) # 4-byte Folded Spill
+; RV32-NEXT:    .cfi_offset t0, -12
+; RV32-NEXT:    csrr t0, mcause
+; RV32-NEXT:    sw t0, 28(sp) # 4-byte Folded Spill
+; RV32-NEXT:    csrr t0, mepc
 ; RV32-NEXT:    csrsi mstatus, 8
-; RV32-NEXT:    sw s0, 4(sp) # 4-byte Folded Spill
-; RV32-NEXT:    sw s1, 0(sp) # 4-byte Folded Spill
-; RV32-NEXT:    .cfi_offset s0, -12
-; RV32-NEXT:    .cfi_offset s1, -16
+; RV32-NEXT:    sw t0, 24(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw s0, 16(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw s1, 12(sp) # 4-byte Folded Spill
+; RV32-NEXT:    .cfi_offset s0, -16
+; RV32-NEXT:    .cfi_offset s1, -20
 ; RV32-NEXT:    #APP
 ; RV32-NEXT:    #NO_APP
-; RV32-NEXT:    lw s0, 4(sp) # 4-byte Folded Reload
-; RV32-NEXT:    lw s1, 0(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw s0, 16(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw s1, 12(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw t0, 24(sp) # 4-byte Folded Reload
+; RV32-NEXT:    csrci mstatus, 8
+; RV32-NEXT:    csrw mepc, t0
+; RV32-NEXT:    lw t0, 28(sp) # 4-byte Folded Reload
+; RV32-NEXT:    csrw mcause, t0
+; RV32-NEXT:    lw t0, 20(sp) # 4-byte Folded Reload
+; RV32-NEXT:    .cfi_restore t0
 ; RV32-NEXT:    .cfi_restore s0
 ; RV32-NEXT:    .cfi_restore s1
-; RV32-NEXT:    csrci mstatus, 8
-; RV32-NEXT:    csrw mepc, s1
-; RV32-NEXT:    csrw mcause, s0
-; RV32-NEXT:    lw s1, 8(sp) # 4-byte Folded Reload
-; RV32-NEXT:    lw s0, 12(sp) # 4-byte Folded Reload
-; RV32-NEXT:    addi sp, sp, 16
+; RV32-NEXT:    addi sp, sp, 32
 ; RV32-NEXT:    .cfi_def_cfa_offset 0
 ; RV32-NEXT:    mret
 ;
 ; RV64-LABEL: preemptible_clobber:
 ; RV64:       # %bb.0:
-; RV64-NEXT:    addi sp, sp, -32
-; RV64-NEXT:    .cfi_def_cfa_offset 32
-; RV64-NEXT:    sd s0, 24(sp) # 8-byte Folded Spill
-; RV64-NEXT:    sd s1, 16(sp) # 8-byte Folded Spill
-; RV64-NEXT:    csrr s0, mcause
-; RV64-NEXT:    csrr s1, mepc
+; RV64-NEXT:    addi sp, sp, -48
+; RV64-NEXT:    .cfi_def_cfa_offset 48
+; RV64-NEXT:    sd t0, 24(sp) # 8-byte Folded Spill
+; RV64-NEXT:    .cfi_offset t0, -24
+; RV64-NEXT:    csrr t0, mcause
+; RV64-NEXT:    sd t0, 40(sp) # 8-byte Folded Spill
+; RV64-NEXT:    csrr t0, mepc
 ; RV64-NEXT:    csrsi mstatus, 8
-; RV64-NEXT:    sd s0, 8(sp) # 8-byte Folded Spill
-; RV64-NEXT:    sd s1, 0(sp) # 8-byte Folded Spill
-; RV64-NEXT:    .cfi_offset s0, -24
-; RV64-NEXT:    .cfi_offset s1, -32
+; RV64-NEXT:    sd t0, 32(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd s0, 16(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd s1, 8(sp) # 8-byte Folded Spill
+; RV64-NEXT:    .cfi_offset s0, -32
+; RV64-NEXT:    .cfi_offset s1, -40
 ; RV64-NEXT:    #APP
 ; RV64-NEXT:    #NO_APP
-; RV64-NEXT:    ld s0, 8(sp) # 8-byte Folded Reload
-; RV64-NEXT:    ld s1, 0(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld s0, 16(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld s1, 8(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld t0, 32(sp) # 8-byte Folded Reload
+; RV64-NEXT:    csrci mstatus, 8
+; RV64-NEXT:    csrw mepc, t0
+; RV64-NEXT:    ld t0, 40(sp) # 8-byte Folded Reload
+; RV64-NEXT:    csrw mcause, t0
+; RV64-NEXT:    ld t0, 24(sp) # 8-byte Folded Reload
+; RV64-NEXT:    .cfi_restore t0
 ; RV64-NEXT:    .cfi_restore s0
 ; RV64-NEXT:    .cfi_restore s1
-; RV64-NEXT:    csrci mstatus, 8
-; RV64-NEXT:    csrw mepc, s1
-; RV64-NEXT:    csrw mcause, s0
-; RV64-NEXT:    ld s1, 16(sp) # 8-byte Folded Reload
-; RV64-NEXT:    ld s0, 24(sp) # 8-byte Folded Reload
-; RV64-NEXT:    addi sp, sp, 32
+; RV64-NEXT:    addi sp, sp, 48
 ; RV64-NEXT:    .cfi_def_cfa_offset 0
 ; RV64-NEXT:    mret
   call void asm sideeffect "", "~{x8},~{x9}"() #4
@@ -989,29 +1013,33 @@ define void @both_clobber() "interrupt"="SiFive-CLIC-preemptible-stack-swap" {
 ; RV32-LABEL: both_clobber:
 ; RV32:       # %bb.0:
 ; RV32-NEXT:    csrrw sp, sf.mscratchcsw, sp
-; RV32-NEXT:    addi sp, sp, -16
-; RV32-NEXT:    .cfi_def_cfa_offset 16
-; RV32-NEXT:    sw s0, 12(sp) # 4-byte Folded Spill
-; RV32-NEXT:    sw s1, 8(sp) # 4-byte Folded Spill
-; RV32-NEXT:    csrr s0, mcause
-; RV32-NEXT:    csrr s1, mepc
+; RV32-NEXT:    addi sp, sp, -32
+; RV32-NEXT:    .cfi_def_cfa_offset 32
+; RV32-NEXT:    sw t0, 20(sp) # 4-byte Folded Spill
+; RV32-NEXT:    .cfi_offset t0, -12
+; RV32-NEXT:    csrr t0, mcause
+; RV32-NEXT:    sw t0, 28(sp) # 4-byte Folded Spill
+; RV32-NEXT:    csrr t0, mepc
 ; RV32-NEXT:    csrsi mstatus, 8
-; RV32-NEXT:    sw s0, 4(sp) # 4-byte Folded Spill
-; RV32-NEXT:    sw s1, 0(sp) # 4-byte Folded Spill
-; RV32-NEXT:    .cfi_offset s0, -12
-; RV32-NEXT:    .cfi_offset s1, -16
+; RV32-NEXT:    sw t0, 24(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw s0, 16(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw s1, 12(sp) # 4-byte Folded Spill
+; RV32-NEXT:    .cfi_offset s0, -16
+; RV32-NEXT:    .cfi_offset s1, -20
 ; RV32-NEXT:    #APP
 ; RV32-NEXT:    #NO_APP
-; RV32-NEXT:    lw s0, 4(sp) # 4-byte Folded Reload
-; RV32-NEXT:    lw s1, 0(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw s0, 16(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw s1, 12(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw t0, 24(sp) # 4-byte Folded Reload
+; RV32-NEXT:    csrci mstatus, 8
+; RV32-NEXT:    csrw mepc, t0
+; RV32-NEXT:    lw t0, 28(sp) # 4-byte Folded Reload
+; RV32-NEXT:    csrw mcause, t0
+; RV32-NEXT:    lw t0, 20(sp) # 4-byte Folded Reload
+; RV32-NEXT:    .cfi_restore t0
 ; RV32-NEXT:    .cfi_restore s0
 ; RV32-NEXT:    .cfi_restore s1
-; RV32-NEXT:    csrci mstatus, 8
-; RV32-NEXT:    csrw mepc, s1
-; RV32-NEXT:    csrw mcause, s0
-; RV32-NEXT:    lw s1, 8(sp) # 4-byte Folded Reload
-; RV32-NEXT:    lw s0, 12(sp) # 4-byte Folded Reload
-; RV32-NEXT:    addi sp, sp, 16
+; RV32-NEXT:    addi sp, sp, 32
 ; RV32-NEXT:    .cfi_def_cfa_offset 0
 ; RV32-NEXT:    csrrw sp, sf.mscratchcsw, sp
 ; RV32-NEXT:    mret
@@ -1019,32 +1047,223 @@ define void @both_clobber() "interrupt"="SiFive-CLIC-preemptible-stack-swap" {
 ; RV64-LABEL: both_clobber:
 ; RV64:       # %bb.0:
 ; RV64-NEXT:    csrrw sp, sf.mscratchcsw, sp
-; RV64-NEXT:    addi sp, sp, -32
-; RV64-NEXT:    .cfi_def_cfa_offset 32
-; RV64-NEXT:    sd s0, 24(sp) # 8-byte Folded Spill
-; RV64-NEXT:    sd s1, 16(sp) # 8-byte Folded Spill
-; RV64-NEXT:    csrr s0, mcause
-; RV64-NEXT:    csrr s1, mepc
+; RV64-NEXT:    addi sp, sp, -48
+; RV64-NEXT:    .cfi_def_cfa_offset 48
+; RV64-NEXT:    sd t0, 24(sp) # 8-byte Folded Spill
+; RV64-NEXT:    .cfi_offset t0, -24
+; RV64-NEXT:    csrr t0, mcause
+; RV64-NEXT:    sd t0, 40(sp) # 8-byte Folded Spill
+; RV64-NEXT:    csrr t0, mepc
 ; RV64-NEXT:    csrsi mstatus, 8
-; RV64-NEXT:    sd s0, 8(sp) # 8-byte Folded Spill
-; RV64-NEXT:    sd s1, 0(sp) # 8-byte Folded Spill
-; RV64-NEXT:    .cfi_offset s0, -24
-; RV64-NEXT:    .cfi_offset s1, -32
+; RV64-NEXT:    sd t0, 32(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd s0, 16(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd s1, 8(sp) # 8-byte Folded Spill
+; RV64-NEXT:    .cfi_offset s0, -32
+; RV64-NEXT:    .cfi_offset s1, -40
 ; RV64-NEXT:    #APP
 ; RV64-NEXT:    #NO_APP
-; RV64-NEXT:    ld s0, 8(sp) # 8-byte Folded Reload
-; RV64-NEXT:    ld s1, 0(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld s0, 16(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld s1, 8(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld t0, 32(sp) # 8-byte Folded Reload
+; RV64-NEXT:    csrci mstatus, 8
+; RV64-NEXT:    csrw mepc, t0
+; RV64-NEXT:    ld t0, 40(sp) # 8-byte Folded Reload
+; RV64-NEXT:    csrw mcause, t0
+; RV64-NEXT:    ld t0, 24(sp) # 8-byte Folded Reload
+; RV64-NEXT:    .cfi_restore t0
 ; RV64-NEXT:    .cfi_restore s0
 ; RV64-NEXT:    .cfi_restore s1
-; RV64-NEXT:    csrci mstatus, 8
-; RV64-NEXT:    csrw mepc, s1
-; RV64-NEXT:    csrw mcause, s0
-; RV64-NEXT:    ld s1, 16(sp) # 8-byte Folded Reload
-; RV64-NEXT:    ld s0, 24(sp) # 8-byte Folded Reload
-; RV64-NEXT:    addi sp, sp, 32
+; RV64-NEXT:    addi sp, sp, 48
 ; RV64-NEXT:    .cfi_def_cfa_offset 0
 ; RV64-NEXT:    csrrw sp, sf.mscratchcsw, sp
 ; RV64-NEXT:    mret
   call void asm sideeffect "", "~{x8},~{x9}"() #4
   ret void
 }
+
+declare void @use(ptr)
+
+define void @large_frame() "interrupt"="SiFive-CLIC-preemptible" "frame-pointer"="none" {
+; RV32-LABEL: large_frame:
+; RV32:       # %bb.0:
+; RV32-NEXT:    addi sp, sp, -2032
+; RV32-NEXT:    .cfi_def_cfa_offset 2032
+; RV32-NEXT:    sw t0, 2016(sp) # 4-byte Folded Spill
+; RV32-NEXT:    .cfi_offset t0, -16
+; RV32-NEXT:    csrr t0, mcause
+; RV32-NEXT:    sw t0, 2028(sp) # 4-byte Folded Spill
+; RV32-NEXT:    csrr t0, mepc
+; RV32-NEXT:    csrsi mstatus, 8
+; RV32-NEXT:    sw t0, 2024(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw ra, 2020(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw t1, 2012(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw t2, 2008(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a0, 2004(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a1, 2000(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a2, 1996(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a3, 1992(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a4, 1988(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a5, 1984(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a6, 1980(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a7, 1976(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw t3, 1972(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw t4, 1968(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw t5, 1964(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw t6, 1960(sp) # 4-byte Folded Spill
+; RV32-NEXT:    .cfi_offset ra, -12
+; RV32-NEXT:    .cfi_offset t1, -20
+; RV32-NEXT:    .cfi_offset t2, -24
+; RV32-NEXT:    .cfi_offset a0, -28
+; RV32-NEXT:    .cfi_offset a1, -32
+; RV32-NEXT:    .cfi_offset a2, -36
+; RV32-NEXT:    .cfi_offset a3, -40
+; RV32-NEXT:    .cfi_offset a4, -44
+; RV32-NEXT:    .cfi_offset a5, -48
+; RV32-NEXT:    .cfi_offset a6, -52
+; RV32-NEXT:    .cfi_offset a7, -56
+; RV32-NEXT:    .cfi_offset t3, -60
+; RV32-NEXT:    .cfi_offset t4, -64
+; RV32-NEXT:    .cfi_offset t5, -68
+; RV32-NEXT:    .cfi_offset t6, -72
+; RV32-NEXT:    addi sp, sp, -2048
+; RV32-NEXT:    addi sp, sp, -112
+; RV32-NEXT:    .cfi_def_cfa_offset 4192
+; RV32-NEXT:    addi a0, sp, 16
+; RV32-NEXT:    call use
+; RV32-NEXT:    addi sp, sp, 2032
+; RV32-NEXT:    addi sp, sp, 128
+; RV32-NEXT:    .cfi_def_cfa_offset 2032
+; RV32-NEXT:    lw ra, 2020(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw t1, 2012(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw t2, 2008(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a0, 2004(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a1, 2000(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a2, 1996(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a3, 1992(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a4, 1988(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a5, 1984(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a6, 1980(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a7, 1976(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw t3, 1972(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw t4, 1968(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw t5, 1964(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw t6, 1960(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw t0, 2024(sp) # 4-byte Folded Reload
+; RV32-NEXT:    csrci mstatus, 8
+; RV32-NEXT:    csrw mepc, t0
+; RV32-NEXT:    lw t0, 2028(sp) # 4-byte Folded Reload
+; RV32-NEXT:    csrw mcause, t0
+; RV32-NEXT:    lw t0, 2016(sp) # 4-byte Folded Reload
+; RV32-NEXT:    .cfi_restore t0
+; RV32-NEXT:    .cfi_restore ra
+; RV32-NEXT:    .cfi_restore t1
+; RV32-NEXT:    .cfi_restore t2
+; RV32-NEXT:    .cfi_restore a0
+; RV32-NEXT:    .cfi_restore a1
+; RV32-NEXT:    .cfi_restore a2
+; RV32-NEXT:    .cfi_restore a3
+; RV32-NEXT:    .cfi_restore a4
+; RV32-NEXT:    .cfi_restore a5
+; RV32-NEXT:    .cfi_restore a6
+; RV32-NEXT:    .cfi_restore a7
+; RV32-NEXT:    .cfi_restore t3
+; RV32-NEXT:    .cfi_restore t4
+; RV32-NEXT:    .cfi_restore t5
+; RV32-NEXT:    .cfi_restore t6
+; RV32-NEXT:    addi sp, sp, 2032
+; RV32-NEXT:    .cfi_def_cfa_offset 0
+; RV32-NEXT:    mret
+;
+; RV64-LABEL: large_frame:
+; RV64:       # %bb.0:
+; RV64-NEXT:    addi sp, sp, -2032
+; RV64-NEXT:    .cfi_def_cfa_offset 2032
+; RV64-NEXT:    sd t0, 2000(sp) # 8-byte Folded Spill
+; RV64-NEXT:    .cfi_offset t0, -32
+; RV64-NEXT:    csrr t0, mcause
+; RV64-NEXT:    sd t0, 2024(sp) # 8-byte Folded Spill
+; RV64-NEXT:    csrr t0, mepc
+; RV64-NEXT:    csrsi mstatus, 8
+; RV64-NEXT:    sd t0, 2016(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd ra, 2008(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd t1, 1992(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd t2, 1984(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a0, 1976(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a1, 1968(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a2, 1960(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a3, 1952(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a4, 1944(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a5, 1936(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a6, 1928(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a7, 1920(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd t3, 1912(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd t4, 1904(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd t5, 1896(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd t6, 1888(sp) # 8-byte Folded Spill
+; RV64-NEXT:    .cfi_offset ra, -24
+; RV64-NEXT:    .cfi_offset t1, -40
+; RV64-NEXT:    .cfi_offset t2, -48
+; RV64-NEXT:    .cfi_offset a0, -56
+; RV64-NEXT:    .cfi_offset a1, -64
+; RV64-NEXT:    .cfi_offset a2, -72
+; RV64-NEXT:    .cfi_offset a3, -80
+; RV64-NEXT:    .cfi_offset a4, -88
+; RV64-NEXT:    .cfi_offset a5, -96
+; RV64-NEXT:    .cfi_offset a6, -104
+; RV64-NEXT:    .cfi_offset a7, -112
+; RV64-NEXT:    .cfi_offset t3, -120
+; RV64-NEXT:    .cfi_offset t4, -128
+; RV64-NEXT:    .cfi_offset t5, -136
+; RV64-NEXT:    .cfi_offset t6, -144
+; RV64-NEXT:    addi sp, sp, -2048
+; RV64-NEXT:    addi sp, sp, -176
+; RV64-NEXT:    .cfi_def_cfa_offset 4256
+; RV64-NEXT:    addi a0, sp, 16
+; RV64-NEXT:    call use
+; RV64-NEXT:    addi sp, sp, 2032
+; RV64-NEXT:    addi sp, sp, 192
+; RV64-NEXT:    .cfi_def_cfa_offset 2032
+; RV64-NEXT:    ld ra, 2008(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld t1, 1992(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld t2, 1984(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a0, 1976(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a1, 1968(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a2, 1960(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a3, 1952(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a4, 1944(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a5, 1936(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a6, 1928(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a7, 1920(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld t3, 1912(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld t4, 1904(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld t5, 1896(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld t6, 1888(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld t0, 2016(sp) # 8-byte Folded Reload
+; RV64-NEXT:    csrci mstatus, 8
+; RV64-NEXT:    csrw mepc, t0
+; RV64-NEXT:    ld t0, 2024(sp) # 8-byte Folded Reload
+; RV64-NEXT:    csrw mcause, t0
+; RV64-NEXT:    ld t0, 2000(sp) # 8-byte Folded Reload
+; RV64-NEXT:    .cfi_restore t0
+; RV64-NEXT:    .cfi_restore ra
+; RV64-NEXT:    .cfi_restore t1
+; RV64-NEXT:    .cfi_restore t2
+; RV64-NEXT:    .cfi_restore a0
+; RV64-NEXT:    .cfi_restore a1
+; RV64-NEXT:    .cfi_restore a2
+; RV64-NEXT:    .cfi_restore a3
+; RV64-NEXT:    .cfi_restore a4
+; RV64-NEXT:    .cfi_restore a5
+; RV64-NEXT:    .cfi_restore a6
+; RV64-NEXT:    .cfi_restore a7
+; RV64-NEXT:    .cfi_restore t3
+; RV64-NEXT:    .cfi_restore t4
+; RV64-NEXT:    .cfi_restore t5
+; RV64-NEXT:    .cfi_restore t6
+; RV64-NEXT:    addi sp, sp, 2032
+; RV64-NEXT:    .cfi_def_cfa_offset 0
+; RV64-NEXT:    mret
+  %object = alloca [4096 x i8], align 16
+  call void @use(ptr %object)
+  ret void
+}
diff --git a/llvm/test/CodeGen/RISCV/sifive-interrupt-frame-flags.ll b/llvm/test/CodeGen/RISCV/sifive-interrupt-frame-flags.ll
index e014c20febfb81..3c10e87fe861f0 100644
--- a/llvm/test/CodeGen/RISCV/sifive-interrupt-frame-flags.ll
+++ b/llvm/test/CodeGen/RISCV/sifive-interrupt-frame-flags.ll
@@ -9,20 +9,25 @@ define void @preemptible_stack_swap() "interrupt"="SiFive-CLIC-preemptible-stack
 ; CHECK-LABEL: name: preemptible_stack_swap
 ; CHECK: body:             |
 ; CHECK-NEXT:   bb.0
-; CHECK-NEXT:     $x2 = frame-setup CSRRW 840, killed $x2
-; CHECK-NEXT:     $x2 = frame-setup ADDI $x2, -16
-; CHECK-NEXT:     frame-setup CFI_INSTRUCTION def_cfa_offset 16
-; CHECK-NEXT:     frame-setup {{SW|SD}} killed $x8
-; CHECK-NEXT:     frame-setup {{SW|SD}} killed $x9
-; CHECK-NEXT:     $x8 = frame-setup CSRRS 834, $x0
-; CHECK-NEXT:     $x9 = frame-setup CSRRS 833, $x0
+; CHECK-NEXT:     liveins: $x5
+; CHECK:          $x2 = frame-setup CSRRW 840, killed $x2
+; CHECK-NEXT:     $x2 = frame-setup ADDI $x2, -{{16|32}}
+; CHECK-NEXT:     frame-setup CFI_INSTRUCTION def_cfa_offset {{16|32}}
+; CHECK-NEXT:     frame-setup {{SW|SD}} killed $x5
+; CHECK-NEXT:     frame-setup CFI_INSTRUCTION offset $x5, -{{12|24}}
+; CHECK-NEXT:     $x5 = frame-setup CSRRS 834, $x0
+; CHECK-NEXT:     frame-setup {{SW|SD}} killed $x5
+; CHECK-NEXT:     $x5 = frame-setup CSRRS 833, $x0
 ; CHECK-NEXT:     $x0 = frame-setup CSRRSI 768, 8
+; CHECK-NEXT:     frame-setup {{SW|SD}} killed $x5
+; CHECK-NEXT:     $x5 = frame-destroy {{LW|LD}}
 ; CHECK-NEXT:     $x0 = frame-destroy CSRRCI 768, 8
-; CHECK-NEXT:     $x0 = frame-destroy CSRRW 833, killed $x9
-; CHECK-NEXT:     $x0 = frame-destroy CSRRW 834, killed $x8
-; CHECK-NEXT:     $x9 = frame-destroy {{LW|LD}}
-; CHECK-NEXT:     $x8 = frame-destroy {{LW|LD}}
-; CHECK-NEXT:     $x2 = frame-destroy ADDI $x2, 16
+; CHECK-NEXT:     $x0 = frame-destroy CSRRW 833, killed $x5
+; CHECK-NEXT:     $x5 = frame-destroy {{LW|LD}}
+; CHECK-NEXT:     $x0 = frame-destroy CSRRW 834, killed $x5
+; CHECK-NEXT:     $x5 = frame-destroy {{LW|LD}}
+; CHECK-NEXT:     frame-destroy CFI_INSTRUCTION restore $x5
+; CHECK-NEXT:     $x2 = frame-destroy ADDI $x2, {{16|32}}
 ; CHECK-NEXT:     frame-destroy CFI_INSTRUCTION def_cfa_offset 0
 ; CHECK-NEXT:     $x2 = frame-destroy CSRRW 840, killed $x2
 ; CHECK-NEXT:     MRET
diff --git a/llvm/test/CodeGen/RISCV/sifive-interrupt-frame-pointer.ll b/llvm/test/CodeGen/RISCV/sifive-interrupt-frame-pointer.ll
index da025cf86e65e3..70f5c38fd9ec63 100644
--- a/llvm/test/CodeGen/RISCV/sifive-interrupt-frame-pointer.ll
+++ b/llvm/test/CodeGen/RISCV/sifive-interrupt-frame-pointer.ll
@@ -10,38 +10,46 @@ declare void @use(ptr)
 define void @preemptible() "interrupt"="SiFive-CLIC-preemptible" "frame-pointer"="all" {
 ; RV32-LABEL: preemptible:
 ; RV32:         sw t0, 16(sp)
-; RV32:         sw s0, 12(sp)
-; RV32:         addi s0, sp, 32
+; RV32:         .cfi_offset t0, -16
 ; RV32:         csrr t0, mcause
 ; RV32-NEXT:    sw t0, 28(sp)
 ; RV32-NEXT:    csrr t0, mepc
-; RV32-NEXT:    sw t0, 24(sp)
 ; RV32-NEXT:    csrsi mstatus, 8
-; RV32:         csrci mstatus, 8
-; RV32-NEXT:    lw t0, 24(sp)
+; RV32-NEXT:    sw t0, 24(sp)
+; RV32:         sw s0, 12(sp)
+; RV32:         .cfi_offset s0, -20
+; RV32:         addi s0, sp, 32
+; RV32:         lw s0, 12(sp)
+; RV32:         lw t0, 24(sp)
+; RV32-NEXT:    csrci mstatus, 8
 ; RV32-NEXT:    csrw mepc, t0
 ; RV32-NEXT:    lw t0, 28(sp)
 ; RV32-NEXT:    csrw mcause, t0
 ; RV32:         lw t0, 16(sp)
-; RV32:         lw s0, 12(sp)
+; RV32:         .cfi_restore t0
+; RV32:         .cfi_restore s0
 ; RV32:         mret
 ;
 ; RV64-LABEL: preemptible:
 ; RV64:         sd t0, 16(sp)
-; RV64:         sd s0, 8(sp)
-; RV64:         addi s0, sp, 48
+; RV64:         .cfi_offset t0, -32
 ; RV64:         csrr t0, mcause
 ; RV64-NEXT:    sd t0, 40(sp)
 ; RV64-NEXT:    csrr t0, mepc
-; RV64-NEXT:    sd t0, 32(sp)
 ; RV64-NEXT:    csrsi mstatus, 8
-; RV64:         csrci mstatus, 8
-; RV64-NEXT:    ld t0, 32(sp)
+; RV64-NEXT:    sd t0, 32(sp)
+; RV64:         sd s0, 8(sp)
+; RV64:         .cfi_offset s0, -40
+; RV64:         addi s0, sp, 48
+; RV64:         ld s0, 8(sp)
+; RV64:         ld t0, 32(sp)
+; RV64-NEXT:    csrci mstatus, 8
 ; RV64-NEXT:    csrw mepc, t0
 ; RV64-NEXT:    ld t0, 40(sp)
 ; RV64-NEXT:    csrw mcause, t0
 ; RV64:         ld t0, 16(sp)
-; RV64:         ld s0, 8(sp)
+; RV64:         .cfi_restore t0
+; RV64:         .cfi_restore s0
 ; RV64:         mret
   ret void
 }
@@ -49,25 +57,25 @@ define void @preemptible() "interrupt"="SiFive-CLIC-preemptible" "frame-pointer"
 define void @preemptible_stack_swap() "interrupt"="SiFive-CLIC-preemptible-stack-swap" "frame-pointer"="all" {
 ; RV32-LABEL: preemptible_stack_swap:
 ; RV32:         csrrw sp, sf.mscratchcsw, sp
-; RV32:         addi s0, sp, 32
 ; RV32:         csrr t0, mcause
 ; RV32:         csrsi mstatus, 8
+; RV32:         addi s0, sp, 32
+; RV32:         lw s0, 12(sp)
 ; RV32:         csrci mstatus, 8
 ; RV32:         csrw mepc, t0
 ; RV32:         csrw mcause, t0
-; RV32:         lw s0, 12(sp)
 ; RV32:         csrrw sp, sf.mscratchcsw, sp
 ; RV32-NEXT:    mret
 ;
 ; RV64-LABEL: preemptible_stack_swap:
 ; RV64:         csrrw sp, sf.mscratchcsw, sp
-; RV64:         addi s0, sp, 48
 ; RV64:         csrr t0, mcause
 ; RV64:         csrsi mstatus, 8
+; RV64:         addi s0, sp, 48
+; RV64:         ld s0, 8(sp)
 ; RV64:         csrci mstatus, 8
 ; RV64:         csrw mepc, t0
 ; RV64:         csrw mcause, t0
-; RV64:         ld s0, 8(sp)
 ; RV64:         csrrw sp, sf.mscratchcsw, sp
 ; RV64-NEXT:    mret
   ret void
@@ -75,38 +83,38 @@ define void @preemptible_stack_swap() "interrupt"="SiFive-CLIC-preemptible-stack
 
 define void @preemptible_var_alloca() "interrupt"="SiFive-CLIC-preemptible" "frame-pointer"="none" {
 ; RV32-LABEL: preemptible_var_alloca:
-; RV32:         addi s0, sp, 80
 ; RV32:         csrr t0, mcause
-; RV32-NEXT:    sw t0, -4(s0)
+; RV32-NEXT:    sw t0, 76(sp)
 ; RV32-NEXT:    csrr t0, mepc
-; RV32-NEXT:    sw t0, -8(s0)
 ; RV32-NEXT:    csrsi mstatus, 8
+; RV32-NEXT:    sw t0, 72(sp)
+; RV32:         addi s0, sp, 80
 ; RV32:         sub a0, sp, a0
 ; RV32:         mv sp, a0
 ; RV32:         call use
 ; RV32:         addi sp, s0, -80
-; RV32:         csrci mstatus, 8
-; RV32-NEXT:    lw t0, -8(s0)
+; RV32:         lw t0, 72(sp)
+; RV32-NEXT:    csrci mstatus, 8
 ; RV32-NEXT:    csrw mepc, t0
-; RV32-NEXT:    lw t0, -4(s0)
+; RV32-NEXT:    lw t0, 76(sp)
 ; RV32-NEXT:    csrw mcause, t0
 ; RV32:         mret
 ;
 ; RV64-LABEL: preemptible_var_alloca:
-; RV64:         addi s0, sp, 160
 ; RV64:         csrr t0, mcause
-; RV64-NEXT:    sd t0, -8(s0)
+; RV64-NEXT:    sd t0, 152(sp)
 ; RV64-NEXT:    csrr t0, mepc
-; RV64-NEXT:    sd t0, -16(s0)
 ; RV64-NEXT:    csrsi mstatus, 8
+; RV64-NEXT:    sd t0, 144(sp)
+; RV64:         addi s0, sp, 160
 ; RV64:         sub a0, sp, a0
 ; RV64:         mv sp, a0
 ; RV64:         call use
 ; RV64:         addi sp, s0, -160
-; RV64:         csrci mstatus, 8
-; RV64-NEXT:    ld t0, -16(s0)
+; RV64:         ld t0, 144(sp)
+; RV64-NEXT:    csrci mstatus, 8
 ; RV64-NEXT:    csrw mepc, t0
-; RV64-NEXT:    ld t0, -8(s0)
+; RV64-NEXT:    ld t0, 152(sp)
 ; RV64-NEXT:    csrw mcause, t0
 ; RV64:         mret
   %count = load volatile i32, ptr @size
@@ -117,34 +125,34 @@ define void @preemptible_var_alloca() "interrupt"="SiFive-CLIC-preemptible" "fra
 
 define void @preemptible_realign() "interrupt"="SiFive-CLIC-preemptible" "frame-pointer"="none" {
 ; RV32-LABEL: preemptible_realign:
-; RV32:         addi s0, sp,
 ; RV32:         csrr t0, mcause
 ; RV32-NEXT:    sw t0,
 ; RV32-NEXT:    csrr t0, mepc
-; RV32-NEXT:    sw t0,
 ; RV32-NEXT:    csrsi mstatus, 8
+; RV32-NEXT:    sw t0,
+; RV32:         addi s0, sp,
 ; RV32:         andi sp, sp, -64
 ; RV32:         call use
 ; RV32:         addi sp, s0,
-; RV32:         csrci mstatus, 8
-; RV32-NEXT:    lw t0, 184(sp)
+; RV32:         lw t0, 184(sp)
+; RV32-NEXT:    csrci mstatus, 8
 ; RV32-NEXT:    csrw mepc, t0
 ; RV32-NEXT:    lw t0, 188(sp)
 ; RV32-NEXT:    csrw mcause, t0
 ; RV32:         mret
 ;
 ; RV64-LABEL: preemptible_realign:
-; RV64:         addi s0, sp,
 ; RV64:         csrr t0, mcause
 ; RV64-NEXT:    sd t0,
 ; RV64-NEXT:    csrr t0, mepc
-; RV64-NEXT:    sd t0,
 ; RV64-NEXT:    csrsi mstatus, 8
+; RV64-NEXT:    sd t0,
+; RV64:         addi s0, sp,
 ; RV64:         andi sp, sp, -64
 ; RV64:         call use
 ; RV64:         addi sp, s0,
-; RV64:         csrci mstatus, 8
-; RV64-NEXT:    ld t0, 240(sp)
+; RV64:         ld t0, 240(sp)
+; RV64-NEXT:    csrci mstatus, 8
 ; RV64-NEXT:    csrw mepc, t0
 ; RV64-NEXT:    ld t0, 248(sp)
 ; RV64-NEXT:    csrw mcause, t0
@@ -153,3 +161,98 @@ define void @preemptible_realign() "interrupt"="SiFive-CLIC-preemptible" "frame-
   call void @use(ptr %object)
   ret void
 }
+
+define void @large_frame_fp() "interrupt"="SiFive-CLIC-preemptible" "frame-pointer"="all" {
+; RV32-LABEL: large_frame_fp:
+; RV32:         addi sp, sp, -2032
+; RV32-NEXT:    .cfi_def_cfa_offset 2032
+; RV32-NEXT:    sw t0, 2016(sp)
+; RV32-NEXT:    .cfi_offset t0, -16
+; RV32-NEXT:    csrr t0, mcause
+; RV32-NEXT:    sw t0, 2028(sp)
+; RV32-NEXT:    csrr t0, mepc
+; RV32-NEXT:    csrsi mstatus, 8
+; RV32-NEXT:    sw t0, 2024(sp)
+; RV32:         call use
+; RV32:         lw ra, 2020(sp)
+; RV32:         lw t0, 2024(sp)
+; RV32-NEXT:    csrci mstatus, 8
+; RV32-NEXT:    csrw mepc, t0
+; RV32-NEXT:    lw t0, 2028(sp)
+; RV32-NEXT:    csrw mcause, t0
+; RV32-NEXT:    lw t0, 2016(sp)
+; RV32:         .cfi_restore t0
+; RV32:         mret
+;
+; RV64-LABEL: large_frame_fp:
+; RV64:         addi sp, sp, -2032
+; RV64-NEXT:    .cfi_def_cfa_offset 2032
+; RV64-NEXT:    sd t0, 2000(sp)
+; RV64-NEXT:    .cfi_offset t0, -32
+; RV64-NEXT:    csrr t0, mcause
+; RV64-NEXT:    sd t0, 2024(sp)
+; RV64-NEXT:    csrr t0, mepc
+; RV64-NEXT:    csrsi mstatus, 8
+; RV64-NEXT:    sd t0, 2016(sp)
+; RV64:         call use
+; RV64:         ld ra, 2008(sp)
+; RV64:         ld t0, 2016(sp)
+; RV64-NEXT:    csrci mstatus, 8
+; RV64-NEXT:    csrw mepc, t0
+; RV64-NEXT:    ld t0, 2024(sp)
+; RV64-NEXT:    csrw mcause, t0
+; RV64-NEXT:    ld t0, 2000(sp)
+; RV64:         .cfi_restore t0
+; RV64:         mret
+  %object = alloca [4096 x i8], align 16
+  call void @use(ptr %object)
+  ret void
+}
+
+define void @realign_var_alloca() "interrupt"="SiFive-CLIC-preemptible" "frame-pointer"="none" {
+; RV32-LABEL: realign_var_alloca:
+; RV32:         addi sp, sp, -128
+; RV32-NEXT:    .cfi_def_cfa_offset 128
+; RV32-NEXT:    sw t0, 112(sp)
+; RV32-NEXT:    .cfi_offset t0, -16
+; RV32-NEXT:    csrr t0, mcause
+; RV32-NEXT:    sw t0, 124(sp)
+; RV32-NEXT:    csrr t0, mepc
+; RV32-NEXT:    csrsi mstatus, 8
+; RV32-NEXT:    sw t0, 120(sp)
+; RV32:         call use
+; RV32:         lw ra, 116(sp)
+; RV32:         lw t0, 120(sp)
+; RV32-NEXT:    csrci mstatus, 8
+; RV32-NEXT:    csrw mepc, t0
+; RV32-NEXT:    lw t0, 124(sp)
+; RV32-NEXT:    csrw mcause, t0
+; RV32-NEXT:    lw t0, 112(sp)
+; RV32:         .cfi_restore t0
+; RV32:         mret
+;
+; RV64-LABEL: realign_var_alloca:
+; RV64:         addi sp, sp, -192
+; RV64-NEXT:    .cfi_def_cfa_offset 192
+; RV64-NEXT:    sd t0, 160(sp)
+; RV64-NEXT:    .cfi_offset t0, -32
+; RV64-NEXT:    csrr t0, mcause
+; RV64-NEXT:    sd t0, 184(sp)
+; RV64-NEXT:    csrr t0, mepc
+; RV64-NEXT:    csrsi mstatus, 8
+; RV64-NEXT:    sd t0, 176(sp)
+; RV64:         call use
+; RV64:         ld ra, 168(sp)
+; RV64:         ld t0, 176(sp)
+; RV64-NEXT:    csrci mstatus, 8
+; RV64-NEXT:    csrw mepc, t0
+; RV64-NEXT:    ld t0, 184(sp)
+; RV64-NEXT:    csrw mcause, t0
+; RV64-NEXT:    ld t0, 160(sp)
+; RV64:         .cfi_restore t0
+; RV64:         mret
+  %count = load volatile i32, ptr @size
+  %object = alloca i8, i32 %count, align 64
+  call void @use(ptr %object)
+  ret void
+}

>From 0e3b162cfacbac3cd323aaed9206a01a2c7b4462 Mon Sep 17 00:00:00 2001
From: Zeyi Xu <mitchell.xu2 at gmail.com>
Date: Wed, 9 Sep 2026 23:57:15 +0800
Subject: [PATCH 4/5] small cleanup

---
 llvm/lib/Target/RISCV/RISCVFrameLowering.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
index 0e2d17301f2eed..661556dca0a956 100644
--- a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
@@ -2353,8 +2353,8 @@ bool RISCVFrameLowering::assignCalleeSavedSpillSlots(
   MachineFrameInfo &MFI = MF.getFrameInfo();
   const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
 
-  // Treat the two `mcause` and `mepc` frame indexes as callee-saved objects for
-  // frame layout purposes. They are not tracked by `CSI`.
+  // Preemptible Interrupts have two additional Callee-save Frame Indexes,
+  // not tracked by `CSI`.
   if (RVFI->isSiFivePreemptibleInterrupt(MF)) {
     for (int I = 0; I < 2; ++I) {
       int FI = RVFI->getInterruptCSRFrameIndex(I);
@@ -2533,7 +2533,7 @@ bool RISCVFrameLowering::spillCalleeSavedRegisters(
       getScalarSpillCSI(*MF, CSI, STI.preferAscendingLoadStore());
   const auto &RVVCSI = getRVVCalleeSavedInfo(*MF, CSI);
 
-  auto storeRegsToStackSlots = [&](ArrayRef<CalleeSavedInfo> CSInfo) {
+  auto storeRegsToStackSlots = [&](decltype(UnmanagedCSI) CSInfo) {
     for (auto &CS : CSInfo) {
       // Insert the spill to the stack frame.
       MCRegister Reg = CS.getReg();
@@ -2627,7 +2627,7 @@ bool RISCVFrameLowering::restoreCalleeSavedRegisters(
       getScalarSpillCSI(*MF, CSI, STI.preferAscendingLoadStore());
   const auto &RVVCSI = getRVVCalleeSavedInfo(*MF, CSI);
 
-  auto loadRegFromStackSlot = [&](ArrayRef<CalleeSavedInfo> CSInfo) {
+  auto loadRegFromStackSlot = [&](decltype(UnmanagedCSI) CSInfo) {
     for (auto &CS : CSInfo) {
       MCRegister Reg = CS.getReg();
       const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg);

>From 49fbd0d4fd70140ddfae2cd792df47e77bddd7a3 Mon Sep 17 00:00:00 2001
From: Zeyi Xu <mitchell.xu2 at gmail.com>
Date: Sat, 19 Sep 2026 18:28:23 +0800
Subject: [PATCH 5/5] address feedback

---
 llvm/lib/Target/RISCV/RISCVFrameLowering.cpp  |  41 +-
 .../RISCV/sifive-interrupt-frame-pointer.ll   | 961 +++++++++++++++---
 2 files changed, 848 insertions(+), 154 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
index 661556dca0a956..7a62049462e878 100644
--- a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
@@ -338,6 +338,7 @@ static void emitSiFiveCLICPreemptibleSaves(MachineFunction &MF,
 static void emitSiFiveCLICPreemptibleRestores(MachineFunction &MF,
                                               MachineBasicBlock &MBB,
                                               MachineBasicBlock::iterator MBBI,
+                                              CFIInstBuilder &CFIBuilder,
                                               const DebugLoc &DL) {
   auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>();
 
@@ -388,8 +389,7 @@ static void emitSiFiveCLICPreemptibleRestores(MachineFunction &MF,
                             &RISCV::GPRRegClass, Register(),
                             RISCV::NoSubRegister, MachineInstr::FrameDestroy);
   if (needsDwarfCFI(MF))
-    CFIInstBuilder(MBB, MBBI, MachineInstr::FrameDestroy)
-        .buildRestore(RISCV::X5);
+    CFIBuilder.buildRestore(RISCV::X5);
 }
 
 // Get the ID of the libcall used for spilling and restoring callee saved
@@ -615,15 +615,15 @@ getUnmanagedCSI(const MachineFunction &MF,
 // Exclude X5 from ordinary spills and restores for SiFive CLIC preemptible
 // handlers, which save and restore it explicitly.
 static SmallVector<CalleeSavedInfo, 8>
-getScalarSpillCSI(const MachineFunction &MF,
-                  const std::vector<CalleeSavedInfo> &CSI,
-                  bool ReverseOrder = false) {
-  auto ScalarCSI = getUnmanagedCSI(MF, CSI, ReverseOrder);
+getUnmanagedInterruptCSI(const MachineFunction &MF,
+                         const std::vector<CalleeSavedInfo> &CSI,
+                         bool ReverseOrder = false) {
+  auto InterruptCSI = getUnmanagedCSI(MF, CSI, ReverseOrder);
   if (MF.getInfo<RISCVMachineFunctionInfo>()->isSiFivePreemptibleInterrupt(MF))
-    llvm::erase_if(ScalarCSI, [](const CalleeSavedInfo &CS) {
+    llvm::erase_if(InterruptCSI, [](const CalleeSavedInfo &CS) {
       return CS.getReg() == RISCV::X5;
     });
-  return ScalarCSI;
+  return InterruptCSI;
 }
 
 static SmallVector<CalleeSavedInfo, 8>
@@ -1058,9 +1058,9 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
   // Skip to before the spills of scalar callee-saved registers
   // FIXME: assumes exactly one instruction is used to restore each
   // callee-saved register.
-  MBBI =
-      std::prev(MBBI, getRVVCalleeSavedInfo(MF, CSI).size() +
-                          getScalarSpillCSI(MF, CSI, PreferAscendingLS).size());
+  MBBI = std::prev(
+      MBBI, getRVVCalleeSavedInfo(MF, CSI).size() +
+                getUnmanagedInterruptCSI(MF, CSI, PreferAscendingLS).size());
   CFIInstBuilder CFIBuilder(MBB, MBBI, MachineInstr::FrameSetup);
   bool NeedsDwarfCFI = needsDwarfCFI(MF);
 
@@ -1179,14 +1179,15 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
   // to the stack, not before.
   // FIXME: assumes exactly one instruction is used to save each callee-saved
   // register.
-  std::advance(MBBI, getScalarSpillCSI(MF, CSI, PreferAscendingLS).size());
+  std::advance(MBBI,
+               getUnmanagedInterruptCSI(MF, CSI, PreferAscendingLS).size());
   CFIBuilder.setInsertPoint(MBBI);
 
   // Iterate over list of callee-saved registers and emit .cfi_offset
   // directives.
   if (NeedsDwarfCFI) {
     for (const CalleeSavedInfo &CS :
-         getScalarSpillCSI(MF, CSI, PreferAscendingLS)) {
+         getUnmanagedInterruptCSI(MF, CSI, PreferAscendingLS)) {
       MCRegister Reg = CS.getReg();
       int64_t Offset = MFI.getObjectOffset(CS.getFrameIdx());
       // Emit CFI for both sub-registers. The even register is at the base
@@ -1437,9 +1438,9 @@ void RISCVFrameLowering::emitEpilogue(MachineFunction &MF,
   // FIXME: assumes exactly one instruction is used to restore each
   // callee-saved register.
   MBBI = std::next(FirstScalarCSRRestoreInsn,
-                   getScalarSpillCSI(MF, CSI, PreferAscendingLS).size());
-  emitSiFiveCLICPreemptibleRestores(MF, MBB, MBBI, DL);
+                   getUnmanagedInterruptCSI(MF, CSI, PreferAscendingLS).size());
   CFIBuilder.setInsertPoint(MBBI);
+  emitSiFiveCLICPreemptibleRestores(MF, MBB, MBBI, CFIBuilder, DL);
 
   if (getLibCallID(MF, CSI) != -1) {
     // tail __riscv_restore_[0-12] instruction is considered as a terminator,
@@ -1457,7 +1458,7 @@ void RISCVFrameLowering::emitEpilogue(MachineFunction &MF,
   // Recover callee-saved registers.
   if (NeedsDwarfCFI) {
     for (const CalleeSavedInfo &CS :
-         getScalarSpillCSI(MF, CSI, PreferAscendingLS)) {
+         getUnmanagedInterruptCSI(MF, CSI, PreferAscendingLS)) {
       MCRegister Reg = CS.getReg();
       // Emit CFI for both sub-registers.
       if (RISCV::GPRPairRegClass.contains(Reg)) {
@@ -2530,10 +2531,10 @@ bool RISCVFrameLowering::spillCalleeSavedRegisters(
 
   // Manually spill values not spilled by libcall & Push/Pop.
   const auto &UnmanagedCSI =
-      getScalarSpillCSI(*MF, CSI, STI.preferAscendingLoadStore());
+      getUnmanagedInterruptCSI(*MF, CSI, STI.preferAscendingLoadStore());
   const auto &RVVCSI = getRVVCalleeSavedInfo(*MF, CSI);
 
-  auto storeRegsToStackSlots = [&](decltype(UnmanagedCSI) CSInfo) {
+  auto storeRegsToStackSlots = [&](ArrayRef<CalleeSavedInfo> CSInfo) {
     for (auto &CS : CSInfo) {
       // Insert the spill to the stack frame.
       MCRegister Reg = CS.getReg();
@@ -2624,10 +2625,10 @@ bool RISCVFrameLowering::restoreCalleeSavedRegisters(
   // loading RA and return by RA.  loadRegFromStackSlot can insert
   // multiple instructions.
   const auto &UnmanagedCSI =
-      getScalarSpillCSI(*MF, CSI, STI.preferAscendingLoadStore());
+      getUnmanagedInterruptCSI(*MF, CSI, STI.preferAscendingLoadStore());
   const auto &RVVCSI = getRVVCalleeSavedInfo(*MF, CSI);
 
-  auto loadRegFromStackSlot = [&](decltype(UnmanagedCSI) CSInfo) {
+  auto loadRegFromStackSlot = [&](ArrayRef<CalleeSavedInfo> CSInfo) {
     for (auto &CS : CSInfo) {
       MCRegister Reg = CS.getReg();
       const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg);
diff --git a/llvm/test/CodeGen/RISCV/sifive-interrupt-frame-pointer.ll b/llvm/test/CodeGen/RISCV/sifive-interrupt-frame-pointer.ll
index 70f5c38fd9ec63..0145c6de8924f9 100644
--- a/llvm/test/CodeGen/RISCV/sifive-interrupt-frame-pointer.ll
+++ b/llvm/test/CodeGen/RISCV/sifive-interrupt-frame-pointer.ll
@@ -1,3 +1,4 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
 ; RUN: llc -mtriple riscv32-unknown-elf -mattr=+experimental-xsfmclic \
 ; RUN:   -verify-machineinstrs < %s | FileCheck %s --check-prefix=RV32
 ; RUN: llc -mtriple riscv64-unknown-elf -mattr=+experimental-xsfmclic \
@@ -9,114 +10,340 @@ declare void @use(ptr)
 
 define void @preemptible() "interrupt"="SiFive-CLIC-preemptible" "frame-pointer"="all" {
 ; RV32-LABEL: preemptible:
-; RV32:         sw t0, 16(sp)
-; RV32:         .cfi_offset t0, -16
-; RV32:         csrr t0, mcause
-; RV32-NEXT:    sw t0, 28(sp)
+; RV32:       # %bb.0:
+; RV32-NEXT:    addi sp, sp, -32
+; RV32-NEXT:    .cfi_def_cfa_offset 32
+; RV32-NEXT:    sw t0, 16(sp) # 4-byte Folded Spill
+; RV32-NEXT:    .cfi_offset t0, -16
+; RV32-NEXT:    csrr t0, mcause
+; RV32-NEXT:    sw t0, 28(sp) # 4-byte Folded Spill
 ; RV32-NEXT:    csrr t0, mepc
 ; RV32-NEXT:    csrsi mstatus, 8
-; RV32-NEXT:    sw t0, 24(sp)
-; RV32:         sw s0, 12(sp)
-; RV32:         .cfi_offset s0, -20
-; RV32:         addi s0, sp, 32
-; RV32:         lw s0, 12(sp)
-; RV32:         lw t0, 24(sp)
+; RV32-NEXT:    sw t0, 24(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw ra, 20(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw s0, 12(sp) # 4-byte Folded Spill
+; RV32-NEXT:    .cfi_offset ra, -12
+; RV32-NEXT:    .cfi_offset s0, -20
+; RV32-NEXT:    addi s0, sp, 32
+; RV32-NEXT:    .cfi_def_cfa s0, 0
+; RV32-NEXT:    .cfi_def_cfa sp, 32
+; RV32-NEXT:    lw ra, 20(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw s0, 12(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw t0, 24(sp) # 4-byte Folded Reload
 ; RV32-NEXT:    csrci mstatus, 8
 ; RV32-NEXT:    csrw mepc, t0
-; RV32-NEXT:    lw t0, 28(sp)
+; RV32-NEXT:    lw t0, 28(sp) # 4-byte Folded Reload
 ; RV32-NEXT:    csrw mcause, t0
-; RV32:         lw t0, 16(sp)
-; RV32:         .cfi_restore t0
-; RV32:         .cfi_restore s0
-; RV32:         mret
+; RV32-NEXT:    lw t0, 16(sp) # 4-byte Folded Reload
+; RV32-NEXT:    .cfi_restore t0
+; RV32-NEXT:    .cfi_restore ra
+; RV32-NEXT:    .cfi_restore s0
+; RV32-NEXT:    addi sp, sp, 32
+; RV32-NEXT:    .cfi_def_cfa_offset 0
+; RV32-NEXT:    mret
 ;
 ; RV64-LABEL: preemptible:
-; RV64:         sd t0, 16(sp)
-; RV64:         .cfi_offset t0, -32
-; RV64:         csrr t0, mcause
-; RV64-NEXT:    sd t0, 40(sp)
+; RV64:       # %bb.0:
+; RV64-NEXT:    addi sp, sp, -48
+; RV64-NEXT:    .cfi_def_cfa_offset 48
+; RV64-NEXT:    sd t0, 16(sp) # 8-byte Folded Spill
+; RV64-NEXT:    .cfi_offset t0, -32
+; RV64-NEXT:    csrr t0, mcause
+; RV64-NEXT:    sd t0, 40(sp) # 8-byte Folded Spill
 ; RV64-NEXT:    csrr t0, mepc
 ; RV64-NEXT:    csrsi mstatus, 8
-; RV64-NEXT:    sd t0, 32(sp)
-; RV64:         sd s0, 8(sp)
-; RV64:         .cfi_offset s0, -40
-; RV64:         addi s0, sp, 48
-; RV64:         ld s0, 8(sp)
-; RV64:         ld t0, 32(sp)
+; RV64-NEXT:    sd t0, 32(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd ra, 24(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd s0, 8(sp) # 8-byte Folded Spill
+; RV64-NEXT:    .cfi_offset ra, -24
+; RV64-NEXT:    .cfi_offset s0, -40
+; RV64-NEXT:    addi s0, sp, 48
+; RV64-NEXT:    .cfi_def_cfa s0, 0
+; RV64-NEXT:    .cfi_def_cfa sp, 48
+; RV64-NEXT:    ld ra, 24(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld s0, 8(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld t0, 32(sp) # 8-byte Folded Reload
 ; RV64-NEXT:    csrci mstatus, 8
 ; RV64-NEXT:    csrw mepc, t0
-; RV64-NEXT:    ld t0, 40(sp)
+; RV64-NEXT:    ld t0, 40(sp) # 8-byte Folded Reload
 ; RV64-NEXT:    csrw mcause, t0
-; RV64:         ld t0, 16(sp)
-; RV64:         .cfi_restore t0
-; RV64:         .cfi_restore s0
-; RV64:         mret
+; RV64-NEXT:    ld t0, 16(sp) # 8-byte Folded Reload
+; RV64-NEXT:    .cfi_restore t0
+; RV64-NEXT:    .cfi_restore ra
+; RV64-NEXT:    .cfi_restore s0
+; RV64-NEXT:    addi sp, sp, 48
+; RV64-NEXT:    .cfi_def_cfa_offset 0
+; RV64-NEXT:    mret
   ret void
 }
 
 define void @preemptible_stack_swap() "interrupt"="SiFive-CLIC-preemptible-stack-swap" "frame-pointer"="all" {
 ; RV32-LABEL: preemptible_stack_swap:
-; RV32:         csrrw sp, sf.mscratchcsw, sp
-; RV32:         csrr t0, mcause
-; RV32:         csrsi mstatus, 8
-; RV32:         addi s0, sp, 32
-; RV32:         lw s0, 12(sp)
-; RV32:         csrci mstatus, 8
-; RV32:         csrw mepc, t0
-; RV32:         csrw mcause, t0
-; RV32:         csrrw sp, sf.mscratchcsw, sp
+; RV32:       # %bb.0:
+; RV32-NEXT:    csrrw sp, sf.mscratchcsw, sp
+; RV32-NEXT:    addi sp, sp, -32
+; RV32-NEXT:    .cfi_def_cfa_offset 32
+; RV32-NEXT:    sw t0, 16(sp) # 4-byte Folded Spill
+; RV32-NEXT:    .cfi_offset t0, -16
+; RV32-NEXT:    csrr t0, mcause
+; RV32-NEXT:    sw t0, 28(sp) # 4-byte Folded Spill
+; RV32-NEXT:    csrr t0, mepc
+; RV32-NEXT:    csrsi mstatus, 8
+; RV32-NEXT:    sw t0, 24(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw ra, 20(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw s0, 12(sp) # 4-byte Folded Spill
+; RV32-NEXT:    .cfi_offset ra, -12
+; RV32-NEXT:    .cfi_offset s0, -20
+; RV32-NEXT:    addi s0, sp, 32
+; RV32-NEXT:    .cfi_def_cfa s0, 0
+; RV32-NEXT:    .cfi_def_cfa sp, 32
+; RV32-NEXT:    lw ra, 20(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw s0, 12(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw t0, 24(sp) # 4-byte Folded Reload
+; RV32-NEXT:    csrci mstatus, 8
+; RV32-NEXT:    csrw mepc, t0
+; RV32-NEXT:    lw t0, 28(sp) # 4-byte Folded Reload
+; RV32-NEXT:    csrw mcause, t0
+; RV32-NEXT:    lw t0, 16(sp) # 4-byte Folded Reload
+; RV32-NEXT:    .cfi_restore t0
+; RV32-NEXT:    .cfi_restore ra
+; RV32-NEXT:    .cfi_restore s0
+; RV32-NEXT:    addi sp, sp, 32
+; RV32-NEXT:    .cfi_def_cfa_offset 0
+; RV32-NEXT:    csrrw sp, sf.mscratchcsw, sp
 ; RV32-NEXT:    mret
 ;
 ; RV64-LABEL: preemptible_stack_swap:
-; RV64:         csrrw sp, sf.mscratchcsw, sp
-; RV64:         csrr t0, mcause
-; RV64:         csrsi mstatus, 8
-; RV64:         addi s0, sp, 48
-; RV64:         ld s0, 8(sp)
-; RV64:         csrci mstatus, 8
-; RV64:         csrw mepc, t0
-; RV64:         csrw mcause, t0
-; RV64:         csrrw sp, sf.mscratchcsw, sp
+; RV64:       # %bb.0:
+; RV64-NEXT:    csrrw sp, sf.mscratchcsw, sp
+; RV64-NEXT:    addi sp, sp, -48
+; RV64-NEXT:    .cfi_def_cfa_offset 48
+; RV64-NEXT:    sd t0, 16(sp) # 8-byte Folded Spill
+; RV64-NEXT:    .cfi_offset t0, -32
+; RV64-NEXT:    csrr t0, mcause
+; RV64-NEXT:    sd t0, 40(sp) # 8-byte Folded Spill
+; RV64-NEXT:    csrr t0, mepc
+; RV64-NEXT:    csrsi mstatus, 8
+; RV64-NEXT:    sd t0, 32(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd ra, 24(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd s0, 8(sp) # 8-byte Folded Spill
+; RV64-NEXT:    .cfi_offset ra, -24
+; RV64-NEXT:    .cfi_offset s0, -40
+; RV64-NEXT:    addi s0, sp, 48
+; RV64-NEXT:    .cfi_def_cfa s0, 0
+; RV64-NEXT:    .cfi_def_cfa sp, 48
+; RV64-NEXT:    ld ra, 24(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld s0, 8(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld t0, 32(sp) # 8-byte Folded Reload
+; RV64-NEXT:    csrci mstatus, 8
+; RV64-NEXT:    csrw mepc, t0
+; RV64-NEXT:    ld t0, 40(sp) # 8-byte Folded Reload
+; RV64-NEXT:    csrw mcause, t0
+; RV64-NEXT:    ld t0, 16(sp) # 8-byte Folded Reload
+; RV64-NEXT:    .cfi_restore t0
+; RV64-NEXT:    .cfi_restore ra
+; RV64-NEXT:    .cfi_restore s0
+; RV64-NEXT:    addi sp, sp, 48
+; RV64-NEXT:    .cfi_def_cfa_offset 0
+; RV64-NEXT:    csrrw sp, sf.mscratchcsw, sp
 ; RV64-NEXT:    mret
   ret void
 }
 
 define void @preemptible_var_alloca() "interrupt"="SiFive-CLIC-preemptible" "frame-pointer"="none" {
 ; RV32-LABEL: preemptible_var_alloca:
-; RV32:         csrr t0, mcause
-; RV32-NEXT:    sw t0, 76(sp)
+; RV32:       # %bb.0:
+; RV32-NEXT:    addi sp, sp, -80
+; RV32-NEXT:    .cfi_def_cfa_offset 80
+; RV32-NEXT:    sw t0, 64(sp) # 4-byte Folded Spill
+; RV32-NEXT:    .cfi_offset t0, -16
+; RV32-NEXT:    csrr t0, mcause
+; RV32-NEXT:    sw t0, 76(sp) # 4-byte Folded Spill
 ; RV32-NEXT:    csrr t0, mepc
 ; RV32-NEXT:    csrsi mstatus, 8
-; RV32-NEXT:    sw t0, 72(sp)
-; RV32:         addi s0, sp, 80
-; RV32:         sub a0, sp, a0
-; RV32:         mv sp, a0
-; RV32:         call use
-; RV32:         addi sp, s0, -80
-; RV32:         lw t0, 72(sp)
+; RV32-NEXT:    sw t0, 72(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw ra, 68(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw t1, 60(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw t2, 56(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw s0, 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:    .cfi_offset ra, -12
+; RV32-NEXT:    .cfi_offset t1, -20
+; RV32-NEXT:    .cfi_offset t2, -24
+; RV32-NEXT:    .cfi_offset s0, -28
+; RV32-NEXT:    .cfi_offset a0, -32
+; RV32-NEXT:    .cfi_offset a1, -36
+; RV32-NEXT:    .cfi_offset a2, -40
+; RV32-NEXT:    .cfi_offset a3, -44
+; RV32-NEXT:    .cfi_offset a4, -48
+; RV32-NEXT:    .cfi_offset a5, -52
+; RV32-NEXT:    .cfi_offset a6, -56
+; RV32-NEXT:    .cfi_offset a7, -60
+; RV32-NEXT:    .cfi_offset t3, -64
+; RV32-NEXT:    .cfi_offset t4, -68
+; RV32-NEXT:    .cfi_offset t5, -72
+; RV32-NEXT:    .cfi_offset t6, -76
+; RV32-NEXT:    addi s0, sp, 80
+; RV32-NEXT:    .cfi_def_cfa s0, 0
+; RV32-NEXT:    lui a0, %hi(size)
+; RV32-NEXT:    lw a0, %lo(size)(a0)
+; RV32-NEXT:    addi a0, a0, 15
+; RV32-NEXT:    andi a0, a0, -16
+; RV32-NEXT:    sub a0, sp, a0
+; RV32-NEXT:    mv sp, a0
+; RV32-NEXT:    call use
+; RV32-NEXT:    addi sp, s0, -80
+; RV32-NEXT:    .cfi_def_cfa sp, 80
+; RV32-NEXT:    lw ra, 68(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw t1, 60(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw t2, 56(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw s0, 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:    lw t0, 72(sp) # 4-byte Folded Reload
 ; RV32-NEXT:    csrci mstatus, 8
 ; RV32-NEXT:    csrw mepc, t0
-; RV32-NEXT:    lw t0, 76(sp)
+; RV32-NEXT:    lw t0, 76(sp) # 4-byte Folded Reload
 ; RV32-NEXT:    csrw mcause, t0
-; RV32:         mret
+; RV32-NEXT:    lw t0, 64(sp) # 4-byte Folded Reload
+; RV32-NEXT:    .cfi_restore t0
+; RV32-NEXT:    .cfi_restore ra
+; RV32-NEXT:    .cfi_restore t1
+; RV32-NEXT:    .cfi_restore t2
+; RV32-NEXT:    .cfi_restore s0
+; RV32-NEXT:    .cfi_restore a0
+; RV32-NEXT:    .cfi_restore a1
+; RV32-NEXT:    .cfi_restore a2
+; RV32-NEXT:    .cfi_restore a3
+; RV32-NEXT:    .cfi_restore a4
+; RV32-NEXT:    .cfi_restore a5
+; RV32-NEXT:    .cfi_restore a6
+; RV32-NEXT:    .cfi_restore a7
+; RV32-NEXT:    .cfi_restore t3
+; RV32-NEXT:    .cfi_restore t4
+; RV32-NEXT:    .cfi_restore t5
+; RV32-NEXT:    .cfi_restore t6
+; RV32-NEXT:    addi sp, sp, 80
+; RV32-NEXT:    .cfi_def_cfa_offset 0
+; RV32-NEXT:    mret
 ;
 ; RV64-LABEL: preemptible_var_alloca:
-; RV64:         csrr t0, mcause
-; RV64-NEXT:    sd t0, 152(sp)
+; RV64:       # %bb.0:
+; RV64-NEXT:    addi sp, sp, -160
+; RV64-NEXT:    .cfi_def_cfa_offset 160
+; RV64-NEXT:    sd t0, 128(sp) # 8-byte Folded Spill
+; RV64-NEXT:    .cfi_offset t0, -32
+; RV64-NEXT:    csrr t0, mcause
+; RV64-NEXT:    sd t0, 152(sp) # 8-byte Folded Spill
 ; RV64-NEXT:    csrr t0, mepc
 ; RV64-NEXT:    csrsi mstatus, 8
-; RV64-NEXT:    sd t0, 144(sp)
-; RV64:         addi s0, sp, 160
-; RV64:         sub a0, sp, a0
-; RV64:         mv sp, a0
-; RV64:         call use
-; RV64:         addi sp, s0, -160
-; RV64:         ld t0, 144(sp)
+; RV64-NEXT:    sd t0, 144(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd ra, 136(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd t1, 120(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd t2, 112(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd s0, 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:    .cfi_offset ra, -24
+; RV64-NEXT:    .cfi_offset t1, -40
+; RV64-NEXT:    .cfi_offset t2, -48
+; RV64-NEXT:    .cfi_offset s0, -56
+; RV64-NEXT:    .cfi_offset a0, -64
+; RV64-NEXT:    .cfi_offset a1, -72
+; RV64-NEXT:    .cfi_offset a2, -80
+; RV64-NEXT:    .cfi_offset a3, -88
+; RV64-NEXT:    .cfi_offset a4, -96
+; RV64-NEXT:    .cfi_offset a5, -104
+; RV64-NEXT:    .cfi_offset a6, -112
+; RV64-NEXT:    .cfi_offset a7, -120
+; RV64-NEXT:    .cfi_offset t3, -128
+; RV64-NEXT:    .cfi_offset t4, -136
+; RV64-NEXT:    .cfi_offset t5, -144
+; RV64-NEXT:    .cfi_offset t6, -152
+; RV64-NEXT:    addi s0, sp, 160
+; RV64-NEXT:    .cfi_def_cfa s0, 0
+; RV64-NEXT:    lui a0, %hi(size)
+; RV64-NEXT:    lwu a0, %lo(size)(a0)
+; RV64-NEXT:    addi a0, a0, 15
+; RV64-NEXT:    andi a0, a0, -16
+; RV64-NEXT:    sub a0, sp, a0
+; RV64-NEXT:    mv sp, a0
+; RV64-NEXT:    call use
+; RV64-NEXT:    addi sp, s0, -160
+; RV64-NEXT:    .cfi_def_cfa sp, 160
+; RV64-NEXT:    ld ra, 136(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld t1, 120(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld t2, 112(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld s0, 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:    ld t0, 144(sp) # 8-byte Folded Reload
 ; RV64-NEXT:    csrci mstatus, 8
 ; RV64-NEXT:    csrw mepc, t0
-; RV64-NEXT:    ld t0, 152(sp)
+; RV64-NEXT:    ld t0, 152(sp) # 8-byte Folded Reload
 ; RV64-NEXT:    csrw mcause, t0
-; RV64:         mret
+; RV64-NEXT:    ld t0, 128(sp) # 8-byte Folded Reload
+; RV64-NEXT:    .cfi_restore t0
+; RV64-NEXT:    .cfi_restore ra
+; RV64-NEXT:    .cfi_restore t1
+; RV64-NEXT:    .cfi_restore t2
+; RV64-NEXT:    .cfi_restore s0
+; RV64-NEXT:    .cfi_restore a0
+; RV64-NEXT:    .cfi_restore a1
+; RV64-NEXT:    .cfi_restore a2
+; RV64-NEXT:    .cfi_restore a3
+; RV64-NEXT:    .cfi_restore a4
+; RV64-NEXT:    .cfi_restore a5
+; RV64-NEXT:    .cfi_restore a6
+; RV64-NEXT:    .cfi_restore a7
+; RV64-NEXT:    .cfi_restore t3
+; RV64-NEXT:    .cfi_restore t4
+; RV64-NEXT:    .cfi_restore t5
+; RV64-NEXT:    .cfi_restore t6
+; RV64-NEXT:    addi sp, sp, 160
+; RV64-NEXT:    .cfi_def_cfa_offset 0
+; RV64-NEXT:    mret
   %count = load volatile i32, ptr @size
   %object = alloca i8, i32 %count, align 16
   call void @use(ptr %object)
@@ -125,38 +352,190 @@ define void @preemptible_var_alloca() "interrupt"="SiFive-CLIC-preemptible" "fra
 
 define void @preemptible_realign() "interrupt"="SiFive-CLIC-preemptible" "frame-pointer"="none" {
 ; RV32-LABEL: preemptible_realign:
-; RV32:         csrr t0, mcause
-; RV32-NEXT:    sw t0,
+; RV32:       # %bb.0:
+; RV32-NEXT:    addi sp, sp, -192
+; RV32-NEXT:    .cfi_def_cfa_offset 192
+; RV32-NEXT:    sw t0, 176(sp) # 4-byte Folded Spill
+; RV32-NEXT:    .cfi_offset t0, -16
+; RV32-NEXT:    csrr t0, mcause
+; RV32-NEXT:    sw t0, 188(sp) # 4-byte Folded Spill
 ; RV32-NEXT:    csrr t0, mepc
 ; RV32-NEXT:    csrsi mstatus, 8
-; RV32-NEXT:    sw t0,
-; RV32:         addi s0, sp,
-; RV32:         andi sp, sp, -64
-; RV32:         call use
-; RV32:         addi sp, s0,
-; RV32:         lw t0, 184(sp)
+; RV32-NEXT:    sw t0, 184(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw ra, 180(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw t1, 172(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw t2, 168(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw s0, 164(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a0, 160(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a1, 156(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a2, 152(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a3, 148(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a4, 144(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a5, 140(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a6, 136(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a7, 132(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw t3, 128(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw t4, 124(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw t5, 120(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw t6, 116(sp) # 4-byte Folded Spill
+; RV32-NEXT:    .cfi_offset ra, -12
+; RV32-NEXT:    .cfi_offset t1, -20
+; RV32-NEXT:    .cfi_offset t2, -24
+; RV32-NEXT:    .cfi_offset s0, -28
+; RV32-NEXT:    .cfi_offset a0, -32
+; RV32-NEXT:    .cfi_offset a1, -36
+; RV32-NEXT:    .cfi_offset a2, -40
+; RV32-NEXT:    .cfi_offset a3, -44
+; RV32-NEXT:    .cfi_offset a4, -48
+; RV32-NEXT:    .cfi_offset a5, -52
+; RV32-NEXT:    .cfi_offset a6, -56
+; RV32-NEXT:    .cfi_offset a7, -60
+; RV32-NEXT:    .cfi_offset t3, -64
+; RV32-NEXT:    .cfi_offset t4, -68
+; RV32-NEXT:    .cfi_offset t5, -72
+; RV32-NEXT:    .cfi_offset t6, -76
+; RV32-NEXT:    addi s0, sp, 192
+; RV32-NEXT:    .cfi_def_cfa s0, 0
+; RV32-NEXT:    andi sp, sp, -64
+; RV32-NEXT:    mv a0, sp
+; RV32-NEXT:    call use
+; RV32-NEXT:    addi sp, s0, -192
+; RV32-NEXT:    .cfi_def_cfa sp, 192
+; RV32-NEXT:    lw ra, 180(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw t1, 172(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw t2, 168(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw s0, 164(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a0, 160(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a1, 156(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a2, 152(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a3, 148(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a4, 144(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a5, 140(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a6, 136(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a7, 132(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw t3, 128(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw t4, 124(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw t5, 120(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw t6, 116(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw t0, 184(sp) # 4-byte Folded Reload
 ; RV32-NEXT:    csrci mstatus, 8
 ; RV32-NEXT:    csrw mepc, t0
-; RV32-NEXT:    lw t0, 188(sp)
+; RV32-NEXT:    lw t0, 188(sp) # 4-byte Folded Reload
 ; RV32-NEXT:    csrw mcause, t0
-; RV32:         mret
+; RV32-NEXT:    lw t0, 176(sp) # 4-byte Folded Reload
+; RV32-NEXT:    .cfi_restore t0
+; RV32-NEXT:    .cfi_restore ra
+; RV32-NEXT:    .cfi_restore t1
+; RV32-NEXT:    .cfi_restore t2
+; RV32-NEXT:    .cfi_restore s0
+; RV32-NEXT:    .cfi_restore a0
+; RV32-NEXT:    .cfi_restore a1
+; RV32-NEXT:    .cfi_restore a2
+; RV32-NEXT:    .cfi_restore a3
+; RV32-NEXT:    .cfi_restore a4
+; RV32-NEXT:    .cfi_restore a5
+; RV32-NEXT:    .cfi_restore a6
+; RV32-NEXT:    .cfi_restore a7
+; RV32-NEXT:    .cfi_restore t3
+; RV32-NEXT:    .cfi_restore t4
+; RV32-NEXT:    .cfi_restore t5
+; RV32-NEXT:    .cfi_restore t6
+; RV32-NEXT:    addi sp, sp, 192
+; RV32-NEXT:    .cfi_def_cfa_offset 0
+; RV32-NEXT:    mret
 ;
 ; RV64-LABEL: preemptible_realign:
-; RV64:         csrr t0, mcause
-; RV64-NEXT:    sd t0,
+; RV64:       # %bb.0:
+; RV64-NEXT:    addi sp, sp, -256
+; RV64-NEXT:    .cfi_def_cfa_offset 256
+; RV64-NEXT:    sd t0, 224(sp) # 8-byte Folded Spill
+; RV64-NEXT:    .cfi_offset t0, -32
+; RV64-NEXT:    csrr t0, mcause
+; RV64-NEXT:    sd t0, 248(sp) # 8-byte Folded Spill
 ; RV64-NEXT:    csrr t0, mepc
 ; RV64-NEXT:    csrsi mstatus, 8
-; RV64-NEXT:    sd t0,
-; RV64:         addi s0, sp,
-; RV64:         andi sp, sp, -64
-; RV64:         call use
-; RV64:         addi sp, s0,
-; RV64:         ld t0, 240(sp)
+; RV64-NEXT:    sd t0, 240(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd ra, 232(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd t1, 216(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd t2, 208(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd s0, 200(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a0, 192(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a1, 184(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a2, 176(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a3, 168(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a4, 160(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a5, 152(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a6, 144(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a7, 136(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd t3, 128(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd t4, 120(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd t5, 112(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd t6, 104(sp) # 8-byte Folded Spill
+; RV64-NEXT:    .cfi_offset ra, -24
+; RV64-NEXT:    .cfi_offset t1, -40
+; RV64-NEXT:    .cfi_offset t2, -48
+; RV64-NEXT:    .cfi_offset s0, -56
+; RV64-NEXT:    .cfi_offset a0, -64
+; RV64-NEXT:    .cfi_offset a1, -72
+; RV64-NEXT:    .cfi_offset a2, -80
+; RV64-NEXT:    .cfi_offset a3, -88
+; RV64-NEXT:    .cfi_offset a4, -96
+; RV64-NEXT:    .cfi_offset a5, -104
+; RV64-NEXT:    .cfi_offset a6, -112
+; RV64-NEXT:    .cfi_offset a7, -120
+; RV64-NEXT:    .cfi_offset t3, -128
+; RV64-NEXT:    .cfi_offset t4, -136
+; RV64-NEXT:    .cfi_offset t5, -144
+; RV64-NEXT:    .cfi_offset t6, -152
+; RV64-NEXT:    addi s0, sp, 256
+; RV64-NEXT:    .cfi_def_cfa s0, 0
+; RV64-NEXT:    andi sp, sp, -64
+; RV64-NEXT:    mv a0, sp
+; RV64-NEXT:    call use
+; RV64-NEXT:    addi sp, s0, -256
+; RV64-NEXT:    .cfi_def_cfa sp, 256
+; RV64-NEXT:    ld ra, 232(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld t1, 216(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld t2, 208(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld s0, 200(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a0, 192(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a1, 184(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a2, 176(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a3, 168(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a4, 160(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a5, 152(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a6, 144(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a7, 136(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld t3, 128(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld t4, 120(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld t5, 112(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld t6, 104(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld t0, 240(sp) # 8-byte Folded Reload
 ; RV64-NEXT:    csrci mstatus, 8
 ; RV64-NEXT:    csrw mepc, t0
-; RV64-NEXT:    ld t0, 248(sp)
+; RV64-NEXT:    ld t0, 248(sp) # 8-byte Folded Reload
 ; RV64-NEXT:    csrw mcause, t0
-; RV64:         mret
+; RV64-NEXT:    ld t0, 224(sp) # 8-byte Folded Reload
+; RV64-NEXT:    .cfi_restore t0
+; RV64-NEXT:    .cfi_restore ra
+; RV64-NEXT:    .cfi_restore t1
+; RV64-NEXT:    .cfi_restore t2
+; RV64-NEXT:    .cfi_restore s0
+; RV64-NEXT:    .cfi_restore a0
+; RV64-NEXT:    .cfi_restore a1
+; RV64-NEXT:    .cfi_restore a2
+; RV64-NEXT:    .cfi_restore a3
+; RV64-NEXT:    .cfi_restore a4
+; RV64-NEXT:    .cfi_restore a5
+; RV64-NEXT:    .cfi_restore a6
+; RV64-NEXT:    .cfi_restore a7
+; RV64-NEXT:    .cfi_restore t3
+; RV64-NEXT:    .cfi_restore t4
+; RV64-NEXT:    .cfi_restore t5
+; RV64-NEXT:    .cfi_restore t6
+; RV64-NEXT:    addi sp, sp, 256
+; RV64-NEXT:    .cfi_def_cfa_offset 0
+; RV64-NEXT:    mret
   %object = alloca [64 x i8], align 64
   call void @use(ptr %object)
   ret void
@@ -164,46 +543,194 @@ define void @preemptible_realign() "interrupt"="SiFive-CLIC-preemptible" "frame-
 
 define void @large_frame_fp() "interrupt"="SiFive-CLIC-preemptible" "frame-pointer"="all" {
 ; RV32-LABEL: large_frame_fp:
-; RV32:         addi sp, sp, -2032
+; RV32:       # %bb.0:
+; RV32-NEXT:    addi sp, sp, -2032
 ; RV32-NEXT:    .cfi_def_cfa_offset 2032
-; RV32-NEXT:    sw t0, 2016(sp)
+; RV32-NEXT:    sw t0, 2016(sp) # 4-byte Folded Spill
 ; RV32-NEXT:    .cfi_offset t0, -16
 ; RV32-NEXT:    csrr t0, mcause
-; RV32-NEXT:    sw t0, 2028(sp)
+; RV32-NEXT:    sw t0, 2028(sp) # 4-byte Folded Spill
 ; RV32-NEXT:    csrr t0, mepc
 ; RV32-NEXT:    csrsi mstatus, 8
-; RV32-NEXT:    sw t0, 2024(sp)
-; RV32:         call use
-; RV32:         lw ra, 2020(sp)
-; RV32:         lw t0, 2024(sp)
+; RV32-NEXT:    sw t0, 2024(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw ra, 2020(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw t1, 2012(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw t2, 2008(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw s0, 2004(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a0, 2000(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a1, 1996(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a2, 1992(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a3, 1988(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a4, 1984(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a5, 1980(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a6, 1976(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a7, 1972(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw t3, 1968(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw t4, 1964(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw t5, 1960(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw t6, 1956(sp) # 4-byte Folded Spill
+; RV32-NEXT:    .cfi_offset ra, -12
+; RV32-NEXT:    .cfi_offset t1, -20
+; RV32-NEXT:    .cfi_offset t2, -24
+; RV32-NEXT:    .cfi_offset s0, -28
+; RV32-NEXT:    .cfi_offset a0, -32
+; RV32-NEXT:    .cfi_offset a1, -36
+; RV32-NEXT:    .cfi_offset a2, -40
+; RV32-NEXT:    .cfi_offset a3, -44
+; RV32-NEXT:    .cfi_offset a4, -48
+; RV32-NEXT:    .cfi_offset a5, -52
+; RV32-NEXT:    .cfi_offset a6, -56
+; RV32-NEXT:    .cfi_offset a7, -60
+; RV32-NEXT:    .cfi_offset t3, -64
+; RV32-NEXT:    .cfi_offset t4, -68
+; RV32-NEXT:    .cfi_offset t5, -72
+; RV32-NEXT:    .cfi_offset t6, -76
+; RV32-NEXT:    addi s0, sp, 2032
+; RV32-NEXT:    .cfi_def_cfa s0, 0
+; RV32-NEXT:    addi sp, sp, -2048
+; RV32-NEXT:    addi sp, sp, -96
+; RV32-NEXT:    mv a0, sp
+; RV32-NEXT:    call use
+; RV32-NEXT:    addi sp, sp, 2032
+; RV32-NEXT:    addi sp, sp, 112
+; RV32-NEXT:    .cfi_def_cfa sp, 2032
+; RV32-NEXT:    lw ra, 2020(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw t1, 2012(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw t2, 2008(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw s0, 2004(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a0, 2000(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a1, 1996(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a2, 1992(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a3, 1988(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a4, 1984(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a5, 1980(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a6, 1976(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a7, 1972(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw t3, 1968(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw t4, 1964(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw t5, 1960(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw t6, 1956(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw t0, 2024(sp) # 4-byte Folded Reload
 ; RV32-NEXT:    csrci mstatus, 8
 ; RV32-NEXT:    csrw mepc, t0
-; RV32-NEXT:    lw t0, 2028(sp)
+; RV32-NEXT:    lw t0, 2028(sp) # 4-byte Folded Reload
 ; RV32-NEXT:    csrw mcause, t0
-; RV32-NEXT:    lw t0, 2016(sp)
-; RV32:         .cfi_restore t0
-; RV32:         mret
+; RV32-NEXT:    lw t0, 2016(sp) # 4-byte Folded Reload
+; RV32-NEXT:    .cfi_restore t0
+; RV32-NEXT:    .cfi_restore ra
+; RV32-NEXT:    .cfi_restore t1
+; RV32-NEXT:    .cfi_restore t2
+; RV32-NEXT:    .cfi_restore s0
+; RV32-NEXT:    .cfi_restore a0
+; RV32-NEXT:    .cfi_restore a1
+; RV32-NEXT:    .cfi_restore a2
+; RV32-NEXT:    .cfi_restore a3
+; RV32-NEXT:    .cfi_restore a4
+; RV32-NEXT:    .cfi_restore a5
+; RV32-NEXT:    .cfi_restore a6
+; RV32-NEXT:    .cfi_restore a7
+; RV32-NEXT:    .cfi_restore t3
+; RV32-NEXT:    .cfi_restore t4
+; RV32-NEXT:    .cfi_restore t5
+; RV32-NEXT:    .cfi_restore t6
+; RV32-NEXT:    addi sp, sp, 2032
+; RV32-NEXT:    .cfi_def_cfa_offset 0
+; RV32-NEXT:    mret
 ;
 ; RV64-LABEL: large_frame_fp:
-; RV64:         addi sp, sp, -2032
+; RV64:       # %bb.0:
+; RV64-NEXT:    addi sp, sp, -2032
 ; RV64-NEXT:    .cfi_def_cfa_offset 2032
-; RV64-NEXT:    sd t0, 2000(sp)
+; RV64-NEXT:    sd t0, 2000(sp) # 8-byte Folded Spill
 ; RV64-NEXT:    .cfi_offset t0, -32
 ; RV64-NEXT:    csrr t0, mcause
-; RV64-NEXT:    sd t0, 2024(sp)
+; RV64-NEXT:    sd t0, 2024(sp) # 8-byte Folded Spill
 ; RV64-NEXT:    csrr t0, mepc
 ; RV64-NEXT:    csrsi mstatus, 8
-; RV64-NEXT:    sd t0, 2016(sp)
-; RV64:         call use
-; RV64:         ld ra, 2008(sp)
-; RV64:         ld t0, 2016(sp)
+; RV64-NEXT:    sd t0, 2016(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd ra, 2008(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd t1, 1992(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd t2, 1984(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd s0, 1976(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a0, 1968(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a1, 1960(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a2, 1952(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a3, 1944(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a4, 1936(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a5, 1928(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a6, 1920(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a7, 1912(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd t3, 1904(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd t4, 1896(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd t5, 1888(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd t6, 1880(sp) # 8-byte Folded Spill
+; RV64-NEXT:    .cfi_offset ra, -24
+; RV64-NEXT:    .cfi_offset t1, -40
+; RV64-NEXT:    .cfi_offset t2, -48
+; RV64-NEXT:    .cfi_offset s0, -56
+; RV64-NEXT:    .cfi_offset a0, -64
+; RV64-NEXT:    .cfi_offset a1, -72
+; RV64-NEXT:    .cfi_offset a2, -80
+; RV64-NEXT:    .cfi_offset a3, -88
+; RV64-NEXT:    .cfi_offset a4, -96
+; RV64-NEXT:    .cfi_offset a5, -104
+; RV64-NEXT:    .cfi_offset a6, -112
+; RV64-NEXT:    .cfi_offset a7, -120
+; RV64-NEXT:    .cfi_offset t3, -128
+; RV64-NEXT:    .cfi_offset t4, -136
+; RV64-NEXT:    .cfi_offset t5, -144
+; RV64-NEXT:    .cfi_offset t6, -152
+; RV64-NEXT:    addi s0, sp, 2032
+; RV64-NEXT:    .cfi_def_cfa s0, 0
+; RV64-NEXT:    addi sp, sp, -2048
+; RV64-NEXT:    addi sp, sp, -176
+; RV64-NEXT:    mv a0, sp
+; RV64-NEXT:    call use
+; RV64-NEXT:    addi sp, sp, 2032
+; RV64-NEXT:    addi sp, sp, 192
+; RV64-NEXT:    .cfi_def_cfa sp, 2032
+; RV64-NEXT:    ld ra, 2008(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld t1, 1992(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld t2, 1984(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld s0, 1976(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a0, 1968(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a1, 1960(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a2, 1952(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a3, 1944(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a4, 1936(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a5, 1928(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a6, 1920(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a7, 1912(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld t3, 1904(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld t4, 1896(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld t5, 1888(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld t6, 1880(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld t0, 2016(sp) # 8-byte Folded Reload
 ; RV64-NEXT:    csrci mstatus, 8
 ; RV64-NEXT:    csrw mepc, t0
-; RV64-NEXT:    ld t0, 2024(sp)
+; RV64-NEXT:    ld t0, 2024(sp) # 8-byte Folded Reload
 ; RV64-NEXT:    csrw mcause, t0
-; RV64-NEXT:    ld t0, 2000(sp)
-; RV64:         .cfi_restore t0
-; RV64:         mret
+; RV64-NEXT:    ld t0, 2000(sp) # 8-byte Folded Reload
+; RV64-NEXT:    .cfi_restore t0
+; RV64-NEXT:    .cfi_restore ra
+; RV64-NEXT:    .cfi_restore t1
+; RV64-NEXT:    .cfi_restore t2
+; RV64-NEXT:    .cfi_restore s0
+; RV64-NEXT:    .cfi_restore a0
+; RV64-NEXT:    .cfi_restore a1
+; RV64-NEXT:    .cfi_restore a2
+; RV64-NEXT:    .cfi_restore a3
+; RV64-NEXT:    .cfi_restore a4
+; RV64-NEXT:    .cfi_restore a5
+; RV64-NEXT:    .cfi_restore a6
+; RV64-NEXT:    .cfi_restore a7
+; RV64-NEXT:    .cfi_restore t3
+; RV64-NEXT:    .cfi_restore t4
+; RV64-NEXT:    .cfi_restore t5
+; RV64-NEXT:    .cfi_restore t6
+; RV64-NEXT:    addi sp, sp, 2032
+; RV64-NEXT:    .cfi_def_cfa_offset 0
+; RV64-NEXT:    mret
   %object = alloca [4096 x i8], align 16
   call void @use(ptr %object)
   ret void
@@ -211,46 +738,212 @@ define void @large_frame_fp() "interrupt"="SiFive-CLIC-preemptible" "frame-point
 
 define void @realign_var_alloca() "interrupt"="SiFive-CLIC-preemptible" "frame-pointer"="none" {
 ; RV32-LABEL: realign_var_alloca:
-; RV32:         addi sp, sp, -128
+; RV32:       # %bb.0:
+; RV32-NEXT:    addi sp, sp, -128
 ; RV32-NEXT:    .cfi_def_cfa_offset 128
-; RV32-NEXT:    sw t0, 112(sp)
+; RV32-NEXT:    sw t0, 112(sp) # 4-byte Folded Spill
 ; RV32-NEXT:    .cfi_offset t0, -16
 ; RV32-NEXT:    csrr t0, mcause
-; RV32-NEXT:    sw t0, 124(sp)
+; RV32-NEXT:    sw t0, 124(sp) # 4-byte Folded Spill
 ; RV32-NEXT:    csrr t0, mepc
 ; RV32-NEXT:    csrsi mstatus, 8
-; RV32-NEXT:    sw t0, 120(sp)
-; RV32:         call use
-; RV32:         lw ra, 116(sp)
-; RV32:         lw t0, 120(sp)
+; RV32-NEXT:    sw t0, 120(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw ra, 116(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw t1, 108(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw t2, 104(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw s0, 100(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw s1, 96(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a0, 92(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a1, 88(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a2, 84(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a3, 80(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a4, 76(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a5, 72(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a6, 68(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw a7, 64(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw t3, 60(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw t4, 56(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw t5, 52(sp) # 4-byte Folded Spill
+; RV32-NEXT:    sw t6, 48(sp) # 4-byte Folded Spill
+; RV32-NEXT:    .cfi_offset ra, -12
+; RV32-NEXT:    .cfi_offset t1, -20
+; RV32-NEXT:    .cfi_offset t2, -24
+; RV32-NEXT:    .cfi_offset s0, -28
+; RV32-NEXT:    .cfi_offset s1, -32
+; RV32-NEXT:    .cfi_offset a0, -36
+; RV32-NEXT:    .cfi_offset a1, -40
+; RV32-NEXT:    .cfi_offset a2, -44
+; RV32-NEXT:    .cfi_offset a3, -48
+; RV32-NEXT:    .cfi_offset a4, -52
+; RV32-NEXT:    .cfi_offset a5, -56
+; RV32-NEXT:    .cfi_offset a6, -60
+; RV32-NEXT:    .cfi_offset a7, -64
+; RV32-NEXT:    .cfi_offset t3, -68
+; RV32-NEXT:    .cfi_offset t4, -72
+; RV32-NEXT:    .cfi_offset t5, -76
+; RV32-NEXT:    .cfi_offset t6, -80
+; RV32-NEXT:    addi s0, sp, 128
+; RV32-NEXT:    .cfi_def_cfa s0, 0
+; RV32-NEXT:    andi sp, sp, -64
+; RV32-NEXT:    mv s1, sp
+; RV32-NEXT:    lui a0, %hi(size)
+; RV32-NEXT:    lw a0, %lo(size)(a0)
+; RV32-NEXT:    addi a0, a0, 15
+; RV32-NEXT:    andi a0, a0, -16
+; RV32-NEXT:    sub a0, sp, a0
+; RV32-NEXT:    andi a0, a0, -64
+; RV32-NEXT:    mv sp, a0
+; RV32-NEXT:    call use
+; RV32-NEXT:    addi sp, s0, -128
+; RV32-NEXT:    .cfi_def_cfa sp, 128
+; RV32-NEXT:    lw ra, 116(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw t1, 108(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw t2, 104(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw s0, 100(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw s1, 96(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a0, 92(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a1, 88(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a2, 84(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a3, 80(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a4, 76(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a5, 72(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a6, 68(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw a7, 64(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw t3, 60(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw t4, 56(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw t5, 52(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw t6, 48(sp) # 4-byte Folded Reload
+; RV32-NEXT:    lw t0, 120(sp) # 4-byte Folded Reload
 ; RV32-NEXT:    csrci mstatus, 8
 ; RV32-NEXT:    csrw mepc, t0
-; RV32-NEXT:    lw t0, 124(sp)
+; RV32-NEXT:    lw t0, 124(sp) # 4-byte Folded Reload
 ; RV32-NEXT:    csrw mcause, t0
-; RV32-NEXT:    lw t0, 112(sp)
-; RV32:         .cfi_restore t0
-; RV32:         mret
+; RV32-NEXT:    lw t0, 112(sp) # 4-byte Folded Reload
+; RV32-NEXT:    .cfi_restore t0
+; RV32-NEXT:    .cfi_restore ra
+; RV32-NEXT:    .cfi_restore t1
+; RV32-NEXT:    .cfi_restore t2
+; RV32-NEXT:    .cfi_restore s0
+; RV32-NEXT:    .cfi_restore s1
+; RV32-NEXT:    .cfi_restore a0
+; RV32-NEXT:    .cfi_restore a1
+; RV32-NEXT:    .cfi_restore a2
+; RV32-NEXT:    .cfi_restore a3
+; RV32-NEXT:    .cfi_restore a4
+; RV32-NEXT:    .cfi_restore a5
+; RV32-NEXT:    .cfi_restore a6
+; RV32-NEXT:    .cfi_restore a7
+; RV32-NEXT:    .cfi_restore t3
+; RV32-NEXT:    .cfi_restore t4
+; RV32-NEXT:    .cfi_restore t5
+; RV32-NEXT:    .cfi_restore t6
+; RV32-NEXT:    addi sp, sp, 128
+; RV32-NEXT:    .cfi_def_cfa_offset 0
+; RV32-NEXT:    mret
 ;
 ; RV64-LABEL: realign_var_alloca:
-; RV64:         addi sp, sp, -192
+; RV64:       # %bb.0:
+; RV64-NEXT:    addi sp, sp, -192
 ; RV64-NEXT:    .cfi_def_cfa_offset 192
-; RV64-NEXT:    sd t0, 160(sp)
+; RV64-NEXT:    sd t0, 160(sp) # 8-byte Folded Spill
 ; RV64-NEXT:    .cfi_offset t0, -32
 ; RV64-NEXT:    csrr t0, mcause
-; RV64-NEXT:    sd t0, 184(sp)
+; RV64-NEXT:    sd t0, 184(sp) # 8-byte Folded Spill
 ; RV64-NEXT:    csrr t0, mepc
 ; RV64-NEXT:    csrsi mstatus, 8
-; RV64-NEXT:    sd t0, 176(sp)
-; RV64:         call use
-; RV64:         ld ra, 168(sp)
-; RV64:         ld t0, 176(sp)
+; RV64-NEXT:    sd t0, 176(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd ra, 168(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd t1, 152(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd t2, 144(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd s0, 136(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd s1, 128(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a0, 120(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a1, 112(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a2, 104(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a3, 96(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a4, 88(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a5, 80(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a6, 72(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd a7, 64(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd t3, 56(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd t4, 48(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd t5, 40(sp) # 8-byte Folded Spill
+; RV64-NEXT:    sd t6, 32(sp) # 8-byte Folded Spill
+; RV64-NEXT:    .cfi_offset ra, -24
+; RV64-NEXT:    .cfi_offset t1, -40
+; RV64-NEXT:    .cfi_offset t2, -48
+; RV64-NEXT:    .cfi_offset s0, -56
+; RV64-NEXT:    .cfi_offset s1, -64
+; RV64-NEXT:    .cfi_offset a0, -72
+; RV64-NEXT:    .cfi_offset a1, -80
+; RV64-NEXT:    .cfi_offset a2, -88
+; RV64-NEXT:    .cfi_offset a3, -96
+; RV64-NEXT:    .cfi_offset a4, -104
+; RV64-NEXT:    .cfi_offset a5, -112
+; RV64-NEXT:    .cfi_offset a6, -120
+; RV64-NEXT:    .cfi_offset a7, -128
+; RV64-NEXT:    .cfi_offset t3, -136
+; RV64-NEXT:    .cfi_offset t4, -144
+; RV64-NEXT:    .cfi_offset t5, -152
+; RV64-NEXT:    .cfi_offset t6, -160
+; RV64-NEXT:    addi s0, sp, 192
+; RV64-NEXT:    .cfi_def_cfa s0, 0
+; RV64-NEXT:    andi sp, sp, -64
+; RV64-NEXT:    mv s1, sp
+; RV64-NEXT:    lui a0, %hi(size)
+; RV64-NEXT:    lwu a0, %lo(size)(a0)
+; RV64-NEXT:    addi a0, a0, 15
+; RV64-NEXT:    andi a0, a0, -16
+; RV64-NEXT:    sub a0, sp, a0
+; RV64-NEXT:    andi a0, a0, -64
+; RV64-NEXT:    mv sp, a0
+; RV64-NEXT:    call use
+; RV64-NEXT:    addi sp, s0, -192
+; RV64-NEXT:    .cfi_def_cfa sp, 192
+; RV64-NEXT:    ld ra, 168(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld t1, 152(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld t2, 144(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld s0, 136(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld s1, 128(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a0, 120(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a1, 112(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a2, 104(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a3, 96(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a4, 88(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a5, 80(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a6, 72(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld a7, 64(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld t3, 56(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld t4, 48(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld t5, 40(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld t6, 32(sp) # 8-byte Folded Reload
+; RV64-NEXT:    ld t0, 176(sp) # 8-byte Folded Reload
 ; RV64-NEXT:    csrci mstatus, 8
 ; RV64-NEXT:    csrw mepc, t0
-; RV64-NEXT:    ld t0, 184(sp)
+; RV64-NEXT:    ld t0, 184(sp) # 8-byte Folded Reload
 ; RV64-NEXT:    csrw mcause, t0
-; RV64-NEXT:    ld t0, 160(sp)
-; RV64:         .cfi_restore t0
-; RV64:         mret
+; RV64-NEXT:    ld t0, 160(sp) # 8-byte Folded Reload
+; RV64-NEXT:    .cfi_restore t0
+; RV64-NEXT:    .cfi_restore ra
+; RV64-NEXT:    .cfi_restore t1
+; RV64-NEXT:    .cfi_restore t2
+; RV64-NEXT:    .cfi_restore s0
+; RV64-NEXT:    .cfi_restore s1
+; RV64-NEXT:    .cfi_restore a0
+; RV64-NEXT:    .cfi_restore a1
+; RV64-NEXT:    .cfi_restore a2
+; RV64-NEXT:    .cfi_restore a3
+; RV64-NEXT:    .cfi_restore a4
+; RV64-NEXT:    .cfi_restore a5
+; RV64-NEXT:    .cfi_restore a6
+; RV64-NEXT:    .cfi_restore a7
+; RV64-NEXT:    .cfi_restore t3
+; RV64-NEXT:    .cfi_restore t4
+; RV64-NEXT:    .cfi_restore t5
+; RV64-NEXT:    .cfi_restore t6
+; RV64-NEXT:    addi sp, sp, 192
+; RV64-NEXT:    .cfi_def_cfa_offset 0
+; RV64-NEXT:    mret
   %count = load volatile i32, ptr @size
   %object = alloca i8, i32 %count, align 64
   call void @use(ptr %object)



More information about the cfe-commits mailing list