[llvm] [llvm] Support multiple save/restore points in mir (PR #119357)

Elizaveta Noskova via llvm-commits llvm-commits at lists.llvm.org
Wed Apr 2 05:27:17 PDT 2025


https://github.com/enoskova-sc updated https://github.com/llvm/llvm-project/pull/119357

>From baaea8d77a47f4de4716019af6d6854f9c4428f1 Mon Sep 17 00:00:00 2001
From: ens-sc <elizaveta.noskova at syntacore.com>
Date: Wed, 12 Feb 2025 12:11:01 +0300
Subject: [PATCH 1/6] [llvm] support multiple save/restore points in mir

Currently mir supports only one save and one restore point specification:

```
  savePoint:       '%bb.1'
  restorePoint:    '%bb.2'
```

This patch provide possibility to specify multiple save and multiple restore points in mir:

```
  savePoint:
    - point:           '%bb.1'
  restorePoint:
    - point:           '%bb.2'
```
while maintaining backward compatibility.
---
 llvm/include/llvm/CodeGen/MIRYamlMapping.h    | 76 +++++++++++++++++--
 llvm/lib/CodeGen/MIRParser/MIRParser.cpp      | 61 +++++++++++----
 llvm/lib/CodeGen/MIRPrinter.cpp               | 27 +++++--
 .../dont-shrink-wrap-stack-mayloadorstore.mir | 20 +++--
 .../CodeGen/ARM/invalidated-save-point.ll     |  4 +-
 llvm/test/CodeGen/MIR/Generic/frame-info.mir  |  4 +-
 .../X86/frame-info-save-restore-points.mir    |  6 +-
 .../CodeGen/X86/shrink_wrap_dbg_value.mir     |  6 +-
 .../llvm-reduce/mir/preserve-frame-info.mir   |  8 +-
 9 files changed, 165 insertions(+), 47 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/MIRYamlMapping.h b/llvm/include/llvm/CodeGen/MIRYamlMapping.h
index dbad3469d047d..33451b4ef2a26 100644
--- a/llvm/include/llvm/CodeGen/MIRYamlMapping.h
+++ b/llvm/include/llvm/CodeGen/MIRYamlMapping.h
@@ -631,6 +631,55 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::CalledGlobal)
 namespace llvm {
 namespace yaml {
 
+// Struct representing one save/restore point in the 'savePoint'/'restorePoint'
+// list
+struct SaveRestorePointEntry {
+  StringValue Point;
+
+  bool operator==(const SaveRestorePointEntry &Other) const {
+    return Point == Other.Point;
+  }
+};
+
+using SaveRestorePoints =
+    std::variant<std::vector<SaveRestorePointEntry>, StringValue>;
+
+template <> struct PolymorphicTraits<SaveRestorePoints> {
+
+  static NodeKind getKind(const SaveRestorePoints &SRPoints) {
+    if (std::holds_alternative<std::vector<SaveRestorePointEntry>>(SRPoints))
+      return NodeKind::Sequence;
+    if (std::holds_alternative<StringValue>(SRPoints))
+      return NodeKind::Scalar;
+    llvm_unreachable("Unsupported NodeKind of SaveRestorePoints");
+  }
+
+  static SaveRestorePointEntry &getAsMap(SaveRestorePoints &SRPoints) {
+    llvm_unreachable("SaveRestorePoints can't be represented as Map");
+  }
+
+  static std::vector<SaveRestorePointEntry> &
+  getAsSequence(SaveRestorePoints &SRPoints) {
+    if (!std::holds_alternative<std::vector<SaveRestorePointEntry>>(SRPoints))
+      SRPoints = std::vector<SaveRestorePointEntry>();
+
+    return std::get<std::vector<SaveRestorePointEntry>>(SRPoints);
+  }
+
+  static StringValue &getAsScalar(SaveRestorePoints &SRPoints) {
+    if (!std::holds_alternative<StringValue>(SRPoints))
+      SRPoints = StringValue();
+
+    return std::get<StringValue>(SRPoints);
+  }
+};
+
+template <> struct MappingTraits<SaveRestorePointEntry> {
+  static void mapping(IO &YamlIO, SaveRestorePointEntry &Entry) {
+    YamlIO.mapRequired("point", Entry.Point);
+  }
+};
+
 template <> struct MappingTraits<MachineJumpTable> {
   static void mapping(IO &YamlIO, MachineJumpTable &JT) {
     YamlIO.mapRequired("kind", JT.Kind);
@@ -639,6 +688,14 @@ template <> struct MappingTraits<MachineJumpTable> {
   }
 };
 
+} // namespace yaml
+} // namespace llvm
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::SaveRestorePointEntry)
+
+namespace llvm {
+namespace yaml {
+
 /// Serializable representation of MachineFrameInfo.
 ///
 /// Doesn't serialize attributes like 'StackAlignment', 'IsStackRealignable' and
@@ -666,8 +723,8 @@ struct MachineFrameInfo {
   bool HasTailCall = false;
   bool IsCalleeSavedInfoValid = false;
   unsigned LocalFrameSize = 0;
-  StringValue SavePoint;
-  StringValue RestorePoint;
+  SaveRestorePoints SavePoints;
+  SaveRestorePoints RestorePoints;
 
   bool operator==(const MachineFrameInfo &Other) const {
     return IsFrameAddressTaken == Other.IsFrameAddressTaken &&
@@ -688,7 +745,8 @@ struct MachineFrameInfo {
            HasMustTailInVarArgFunc == Other.HasMustTailInVarArgFunc &&
            HasTailCall == Other.HasTailCall &&
            LocalFrameSize == Other.LocalFrameSize &&
-           SavePoint == Other.SavePoint && RestorePoint == Other.RestorePoint &&
+           SavePoints == Other.SavePoints &&
+           RestorePoints == Other.RestorePoints &&
            IsCalleeSavedInfoValid == Other.IsCalleeSavedInfoValid;
   }
 };
@@ -720,10 +778,14 @@ template <> struct MappingTraits<MachineFrameInfo> {
     YamlIO.mapOptional("isCalleeSavedInfoValid", MFI.IsCalleeSavedInfoValid,
                        false);
     YamlIO.mapOptional("localFrameSize", MFI.LocalFrameSize, (unsigned)0);
-    YamlIO.mapOptional("savePoint", MFI.SavePoint,
-                       StringValue()); // Don't print it out when it's empty.
-    YamlIO.mapOptional("restorePoint", MFI.RestorePoint,
-                       StringValue()); // Don't print it out when it's empty.
+    YamlIO.mapOptional(
+        "savePoint", MFI.SavePoints,
+        SaveRestorePoints(
+            StringValue())); // Don't print it out when it's empty.
+    YamlIO.mapOptional(
+        "restorePoint", MFI.RestorePoints,
+        SaveRestorePoints(
+            StringValue())); // Don't print it out when it's empty.
   }
 };
 
diff --git a/llvm/lib/CodeGen/MIRParser/MIRParser.cpp b/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
index de2fe925c2d5c..9dee8674f2453 100644
--- a/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
+++ b/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
@@ -124,6 +124,10 @@ class MIRParserImpl {
   bool initializeFrameInfo(PerFunctionMIParsingState &PFS,
                            const yaml::MachineFunction &YamlMF);
 
+  bool initializeSaveRestorePoints(PerFunctionMIParsingState &PFS,
+                                   const yaml::SaveRestorePoints &YamlSRPoints,
+                                   bool IsSavePoints);
+
   bool initializeCallSiteInfo(PerFunctionMIParsingState &PFS,
                               const yaml::MachineFunction &YamlMF);
 
@@ -851,18 +855,12 @@ bool MIRParserImpl::initializeFrameInfo(PerFunctionMIParsingState &PFS,
   MFI.setHasTailCall(YamlMFI.HasTailCall);
   MFI.setCalleeSavedInfoValid(YamlMFI.IsCalleeSavedInfoValid);
   MFI.setLocalFrameSize(YamlMFI.LocalFrameSize);
-  if (!YamlMFI.SavePoint.Value.empty()) {
-    MachineBasicBlock *MBB = nullptr;
-    if (parseMBBReference(PFS, MBB, YamlMFI.SavePoint))
-      return true;
-    MFI.setSavePoint(MBB);
-  }
-  if (!YamlMFI.RestorePoint.Value.empty()) {
-    MachineBasicBlock *MBB = nullptr;
-    if (parseMBBReference(PFS, MBB, YamlMFI.RestorePoint))
-      return true;
-    MFI.setRestorePoint(MBB);
-  }
+  if (initializeSaveRestorePoints(PFS, YamlMFI.SavePoints,
+                                  true /*IsSavePoints*/))
+    return true;
+  if (initializeSaveRestorePoints(PFS, YamlMFI.RestorePoints,
+                                  false /*IsSavePoints*/))
+    return true;
 
   std::vector<CalleeSavedInfo> CSIInfo;
   // Initialize the fixed frame objects.
@@ -1077,8 +1075,43 @@ bool MIRParserImpl::initializeConstantPool(PerFunctionMIParsingState &PFS,
   return false;
 }
 
-bool MIRParserImpl::initializeJumpTableInfo(PerFunctionMIParsingState &PFS,
-    const yaml::MachineJumpTable &YamlJTI) {
+// Return true if basic block was incorrectly specified in MIR
+bool MIRParserImpl::initializeSaveRestorePoints(
+    PerFunctionMIParsingState &PFS, const yaml::SaveRestorePoints &YamlSRPoints,
+    bool IsSavePoints) {
+  MachineBasicBlock *MBB = nullptr;
+  if (std::holds_alternative<std::vector<yaml::SaveRestorePointEntry>>(
+          YamlSRPoints)) {
+    const auto &VectorRepr =
+        std::get<std::vector<yaml::SaveRestorePointEntry>>(YamlSRPoints);
+    if (VectorRepr.empty())
+      return false;
+
+    const auto &Entry = VectorRepr.front();
+    const auto &MBBSource = Entry.Point;
+    if (parseMBBReference(PFS, MBB, MBBSource.Value))
+      return true;
+  } else {
+    yaml::StringValue StringRepr = std::get<yaml::StringValue>(YamlSRPoints);
+    if (StringRepr.Value.empty())
+      return false;
+    if (parseMBBReference(PFS, MBB, StringRepr))
+      return true;
+  }
+
+  MachineFunction &MF = PFS.MF;
+  MachineFrameInfo &MFI = MF.getFrameInfo();
+
+  if (IsSavePoints)
+    MFI.setSavePoint(MBB);
+  else
+    MFI.setRestorePoint(MBB);
+
+  return false;
+}
+
+bool MIRParserImpl::initializeJumpTableInfo(
+    PerFunctionMIParsingState &PFS, const yaml::MachineJumpTable &YamlJTI) {
   MachineJumpTableInfo *JTI = PFS.MF.getOrCreateJumpTableInfo(YamlJTI.Kind);
   for (const auto &Entry : YamlJTI.Entries) {
     std::vector<MachineBasicBlock *> Blocks;
diff --git a/llvm/lib/CodeGen/MIRPrinter.cpp b/llvm/lib/CodeGen/MIRPrinter.cpp
index 0b41c90442a5d..a3ffb44fdd831 100644
--- a/llvm/lib/CodeGen/MIRPrinter.cpp
+++ b/llvm/lib/CodeGen/MIRPrinter.cpp
@@ -118,6 +118,8 @@ class MIRPrinter {
                const TargetRegisterInfo *TRI);
   void convert(ModuleSlotTracker &MST, yaml::MachineFrameInfo &YamlMFI,
                const MachineFrameInfo &MFI);
+  void convert(ModuleSlotTracker &MST, yaml::SaveRestorePoints &YamlSRPoints,
+               MachineBasicBlock *SaveRestorePoint);
   void convert(yaml::MachineFunction &MF,
                const MachineConstantPool &ConstantPool);
   void convert(ModuleSlotTracker &MST, yaml::MachineJumpTable &YamlJTI,
@@ -397,14 +399,10 @@ void MIRPrinter::convert(ModuleSlotTracker &MST,
   YamlMFI.HasTailCall = MFI.hasTailCall();
   YamlMFI.IsCalleeSavedInfoValid = MFI.isCalleeSavedInfoValid();
   YamlMFI.LocalFrameSize = MFI.getLocalFrameSize();
-  if (MFI.getSavePoint()) {
-    raw_string_ostream StrOS(YamlMFI.SavePoint.Value);
-    StrOS << printMBBReference(*MFI.getSavePoint());
-  }
-  if (MFI.getRestorePoint()) {
-    raw_string_ostream StrOS(YamlMFI.RestorePoint.Value);
-    StrOS << printMBBReference(*MFI.getRestorePoint());
-  }
+  if (MFI.getSavePoint())
+    convert(MST, YamlMFI.SavePoints, MFI.getSavePoint());
+  if (MFI.getRestorePoint())
+    convert(MST, YamlMFI.RestorePoints, MFI.getRestorePoint());
 }
 
 void MIRPrinter::convertEntryValueObjects(yaml::MachineFunction &YMF,
@@ -646,6 +644,19 @@ void MIRPrinter::convert(yaml::MachineFunction &MF,
   }
 }
 
+void MIRPrinter::convert(ModuleSlotTracker &MST,
+                         yaml::SaveRestorePoints &YamlSRPoints,
+                         MachineBasicBlock *SRPoint) {
+  SmallString<16> Str;
+  yaml::SaveRestorePointEntry Entry;
+  raw_svector_ostream StrOS(Str);
+  StrOS << printMBBReference(*SRPoint);
+  Entry.Point = StrOS.str().str();
+  auto &Points =
+      std::get<std::vector<yaml::SaveRestorePointEntry>>(YamlSRPoints);
+  Points.push_back(Entry);
+}
+
 void MIRPrinter::convert(ModuleSlotTracker &MST,
                          yaml::MachineJumpTable &YamlJTI,
                          const MachineJumpTableInfo &JTI) {
diff --git a/llvm/test/CodeGen/AArch64/dont-shrink-wrap-stack-mayloadorstore.mir b/llvm/test/CodeGen/AArch64/dont-shrink-wrap-stack-mayloadorstore.mir
index 1c4447bffd872..6122cf843c230 100644
--- a/llvm/test/CodeGen/AArch64/dont-shrink-wrap-stack-mayloadorstore.mir
+++ b/llvm/test/CodeGen/AArch64/dont-shrink-wrap-stack-mayloadorstore.mir
@@ -6,17 +6,23 @@
  ; RUN: llc -x=mir -simplify-mir -run-pass=shrink-wrap -o - %s | FileCheck %s
  ; CHECK:      name:            compiler_pop_stack
  ; CHECK:      frameInfo:
- ; CHECK:      savePoint:       '%bb.1'
- ; CHECK:      restorePoint:    '%bb.7'
+ ; CHECK:        savePoint:
+ ; CHECK-NEXT:     - point:           '%bb.1'
+ ; CHECK:        restorePoint:
+ ; CHECK-NEXT:     - point:           '%bb.7'
  ; CHECK:      name:            compiler_pop_stack_no_memoperands
  ; CHECK:      frameInfo:
- ; CHECK:      savePoint:       '%bb.1'
- ; CHECK:      restorePoint:    '%bb.7'
+ ; CHECK:        savePoint:
+ ; CHECK-NEXT:     - point:           '%bb.1'
+ ; CHECK:        restorePoint:
+ ; CHECK-NEXT:     - point:           '%bb.7'
  ; CHECK:      name:            f
  ; CHECK:      frameInfo:
- ; CHECK:      savePoint:       '%bb.2'
- ; CHECK-NEXT: restorePoint:    '%bb.4'
- ; CHECK-NEXT: stack:
+ ; CHECK:        savePoint:
+ ; CHECK-NEXT:     - point:           '%bb.2'
+ ; CHECK:        restorePoint:
+ ; CHECK-NEXT:     - point:           '%bb.4'
+ ; CHECK:      stack:
 
   target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
   target triple = "aarch64"
diff --git a/llvm/test/CodeGen/ARM/invalidated-save-point.ll b/llvm/test/CodeGen/ARM/invalidated-save-point.ll
index bb602308a1793..4179316572990 100644
--- a/llvm/test/CodeGen/ARM/invalidated-save-point.ll
+++ b/llvm/test/CodeGen/ARM/invalidated-save-point.ll
@@ -4,8 +4,8 @@
 ; this point. Notably, if it isn't is will be invalid and reference a
 ; deleted block (%bb.-1.if.end)
 
-; CHECK: savePoint: ''
-; CHECK: restorePoint: ''
+; CHECK: savePoint: []
+; CHECK: restorePoint: []
 
 target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
 target triple = "thumbv7"
diff --git a/llvm/test/CodeGen/MIR/Generic/frame-info.mir b/llvm/test/CodeGen/MIR/Generic/frame-info.mir
index d5e014cf62991..e8f3a83fcda89 100644
--- a/llvm/test/CodeGen/MIR/Generic/frame-info.mir
+++ b/llvm/test/CodeGen/MIR/Generic/frame-info.mir
@@ -46,8 +46,8 @@ tracksRegLiveness: true
 # CHECK-NEXT: hasTailCall: false
 # CHECK-NEXT: isCalleeSavedInfoValid: false
 # CHECK-NEXT: localFrameSize: 0
-# CHECK-NEXT: savePoint:       ''
-# CHECK-NEXT: restorePoint:    ''
+# CHECK-NEXT: savePoint:       []
+# CHECK-NEXT: restorePoint:    []
 # CHECK: body
 frameInfo:
   maxAlignment:    4
diff --git a/llvm/test/CodeGen/MIR/X86/frame-info-save-restore-points.mir b/llvm/test/CodeGen/MIR/X86/frame-info-save-restore-points.mir
index e26233f946606..bd2d45046123a 100644
--- a/llvm/test/CodeGen/MIR/X86/frame-info-save-restore-points.mir
+++ b/llvm/test/CodeGen/MIR/X86/frame-info-save-restore-points.mir
@@ -30,8 +30,10 @@ liveins:
   - { reg: '$edi' }
   - { reg: '$esi' }
 # CHECK: frameInfo:
-# CHECK:      savePoint: '%bb.2'
-# CHECK-NEXT: restorePoint: '%bb.2'
+# CHECK:      savePoint:
+# CHECK-NEXT:   - point:           '%bb.2'
+# CHECK:      restorePoint:
+# CHECK-NEXT:   - point:           '%bb.2'
 # CHECK: stack
 frameInfo:
   maxAlignment:  4
diff --git a/llvm/test/CodeGen/X86/shrink_wrap_dbg_value.mir b/llvm/test/CodeGen/X86/shrink_wrap_dbg_value.mir
index aa7befc18d4fe..66110c75be145 100644
--- a/llvm/test/CodeGen/X86/shrink_wrap_dbg_value.mir
+++ b/llvm/test/CodeGen/X86/shrink_wrap_dbg_value.mir
@@ -119,8 +119,10 @@ frameInfo:
   hasOpaqueSPAdjustment: false
   hasVAStart:      false
   hasMustTailInVarArgFunc: false
-  # CHECK: savePoint:       '%bb.1'
-  # CHECK: restorePoint:    '%bb.3'
+  # CHECK:      savePoint:
+  # CHECK-NEXT:   - point:           '%bb.1'
+  # CHECK:      restorePoint:
+  # CHECK-NEXT:   - point:           '%bb.3'
   savePoint:       ''
   restorePoint:    ''
 fixedStack:      
diff --git a/llvm/test/tools/llvm-reduce/mir/preserve-frame-info.mir b/llvm/test/tools/llvm-reduce/mir/preserve-frame-info.mir
index d7ad5f88874d7..957c90929d3fe 100644
--- a/llvm/test/tools/llvm-reduce/mir/preserve-frame-info.mir
+++ b/llvm/test/tools/llvm-reduce/mir/preserve-frame-info.mir
@@ -20,8 +20,10 @@
 # RESULT-NEXT: hasVAStart:      true
 # RESULT-NEXT: hasMustTailInVarArgFunc: true
 # RESULT-NEXT: hasTailCall:     true
-# RESULT-NEXT: savePoint:       '%bb.1'
-# RESULT-NEXT: restorePoint:    '%bb.2'
+# RESULT-NEXT: savePoint:
+# RESULT-NEXT:   - point:           '%bb.1'
+# RESULT-NEXT: restorePoint:
+# RESULT-NEXT:   - point:           '%bb.1'
 
 # RESULT-NEXT: fixedStack:
 # RESULT-NEXT:  - { id: 0, offset: 56, size: 4, alignment: 8, callee-saved-register: '$sgpr44',
@@ -117,7 +119,7 @@ frameInfo:
   hasTailCall:     true
   localFrameSize:  0
   savePoint:       '%bb.1'
-  restorePoint:    '%bb.2'
+  restorePoint:    '%bb.1'
 
 fixedStack:
   - { id: 0, offset: 0, size: 8, alignment: 4, isImmutable: true, isAliased: false }

>From bd3c367fba072f17dd3f45aeaf90545f08c9e08a Mon Sep 17 00:00:00 2001
From: ens-sc <elizaveta.noskova at syntacore.com>
Date: Wed, 12 Feb 2025 16:57:35 +0300
Subject: [PATCH 2/6] formatting issue

---
 llvm/lib/CodeGen/MIRParser/MIRParser.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/CodeGen/MIRParser/MIRParser.cpp b/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
index 9dee8674f2453..3b664d50c03ec 100644
--- a/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
+++ b/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
@@ -1110,8 +1110,8 @@ bool MIRParserImpl::initializeSaveRestorePoints(
   return false;
 }
 
-bool MIRParserImpl::initializeJumpTableInfo(
-    PerFunctionMIParsingState &PFS, const yaml::MachineJumpTable &YamlJTI) {
+bool MIRParserImpl::initializeJumpTableInfo(PerFunctionMIParsingState &PFS,
+    const yaml::MachineJumpTable &YamlJTI) {
   MachineJumpTableInfo *JTI = PFS.MF.getOrCreateJumpTableInfo(YamlJTI.Kind);
   for (const auto &Entry : YamlJTI.Entries) {
     std::vector<MachineBasicBlock *> Blocks;

>From fb9d9c3bbd0a090895ff549c034caaeab603147d Mon Sep 17 00:00:00 2001
From: ens-sc <elizaveta.noskova at syntacore.com>
Date: Mon, 3 Mar 2025 20:00:12 +0300
Subject: [PATCH 3/6] add support for multiple save/restore points in mfi

---
 llvm/include/llvm/CodeGen/MachineFrameInfo.h  | 19 +++--
 llvm/lib/CodeGen/MIRParser/MIRParser.cpp      | 17 ++--
 llvm/lib/CodeGen/MIRPrinter.cpp               | 27 ++++---
 llvm/lib/CodeGen/MachineFrameInfo.cpp         | 16 ++++
 llvm/lib/CodeGen/PrologEpilogInserter.cpp     | 39 +++++----
 llvm/lib/CodeGen/ShrinkWrap.cpp               | 10 ++-
 llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp  | 10 ++-
 llvm/lib/Target/PowerPC/PPCFrameLowering.cpp  |  5 +-
 ...nfo-multiple-save-restore-points-parse.mir | 81 +++++++++++++++++++
 .../llvm-reduce/mir/preserve-frame-info.mir   |  2 +-
 llvm/tools/llvm-reduce/ReducerWorkItem.cpp    | 18 ++++-
 11 files changed, 188 insertions(+), 56 deletions(-)
 create mode 100644 llvm/test/CodeGen/MIR/X86/frame-info-multiple-save-restore-points-parse.mir

diff --git a/llvm/include/llvm/CodeGen/MachineFrameInfo.h b/llvm/include/llvm/CodeGen/MachineFrameInfo.h
index 213b7ec6b3fbf..a9f68b75193fa 100644
--- a/llvm/include/llvm/CodeGen/MachineFrameInfo.h
+++ b/llvm/include/llvm/CodeGen/MachineFrameInfo.h
@@ -330,10 +330,10 @@ class MachineFrameInfo {
   /// stack objects like arguments so we can't treat them as immutable.
   bool HasTailCall = false;
 
-  /// Not null, if shrink-wrapping found a better place for the prologue.
-  MachineBasicBlock *Save = nullptr;
-  /// Not null, if shrink-wrapping found a better place for the epilogue.
-  MachineBasicBlock *Restore = nullptr;
+  /// Not empty, if shrink-wrapping found a better place for the prologue.
+  std::vector<MachineBasicBlock *> SavePoints;
+  /// Not empty, if shrink-wrapping found a better place for the epilogue.
+  std::vector<MachineBasicBlock *> RestorePoints;
 
   /// Size of the UnsafeStack Frame
   uint64_t UnsafeStackSize = 0;
@@ -820,10 +820,13 @@ class MachineFrameInfo {
 
   void setCalleeSavedInfoValid(bool v) { CSIValid = v; }
 
-  MachineBasicBlock *getSavePoint() const { return Save; }
-  void setSavePoint(MachineBasicBlock *NewSave) { Save = NewSave; }
-  MachineBasicBlock *getRestorePoint() const { return Restore; }
-  void setRestorePoint(MachineBasicBlock *NewRestore) { Restore = NewRestore; }
+  const std::vector<MachineBasicBlock *> &getSavePoints() const { return SavePoints; }
+  void setSavePoints(std::vector<MachineBasicBlock *> NewSavePoints) { SavePoints = std::move(NewSavePoints); }
+  const std::vector<MachineBasicBlock *> getRestorePoints() const { return RestorePoints; }
+  void setRestorePoints(std::vector<MachineBasicBlock *> NewRestorePoints) { RestorePoints = std::move(NewRestorePoints); }
+
+  void clearSavePoints() { SavePoints.clear(); }
+  void clearRestorePoints() { RestorePoints.clear(); }
 
   uint64_t getUnsafeStackSize() const { return UnsafeStackSize; }
   void setUnsafeStackSize(uint64_t Size) { UnsafeStackSize = Size; }
diff --git a/llvm/lib/CodeGen/MIRParser/MIRParser.cpp b/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
index 3b664d50c03ec..ea98a211a76b1 100644
--- a/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
+++ b/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
@@ -1080,32 +1080,35 @@ bool MIRParserImpl::initializeSaveRestorePoints(
     PerFunctionMIParsingState &PFS, const yaml::SaveRestorePoints &YamlSRPoints,
     bool IsSavePoints) {
   MachineBasicBlock *MBB = nullptr;
+  std::vector<MachineBasicBlock *> SaveRestorePoints;
   if (std::holds_alternative<std::vector<yaml::SaveRestorePointEntry>>(
           YamlSRPoints)) {
     const auto &VectorRepr =
         std::get<std::vector<yaml::SaveRestorePointEntry>>(YamlSRPoints);
     if (VectorRepr.empty())
       return false;
-
-    const auto &Entry = VectorRepr.front();
-    const auto &MBBSource = Entry.Point;
-    if (parseMBBReference(PFS, MBB, MBBSource.Value))
-      return true;
+    for (const auto &Entry : VectorRepr) {
+      const auto &MBBSource = Entry.Point;
+      if (parseMBBReference(PFS, MBB, MBBSource.Value))
+        return true;
+      SaveRestorePoints.push_back(MBB);
+    }
   } else {
     yaml::StringValue StringRepr = std::get<yaml::StringValue>(YamlSRPoints);
     if (StringRepr.Value.empty())
       return false;
     if (parseMBBReference(PFS, MBB, StringRepr))
       return true;
+    SaveRestorePoints.push_back(MBB);
   }
 
   MachineFunction &MF = PFS.MF;
   MachineFrameInfo &MFI = MF.getFrameInfo();
 
   if (IsSavePoints)
-    MFI.setSavePoint(MBB);
+    MFI.setSavePoints(SaveRestorePoints);
   else
-    MFI.setRestorePoint(MBB);
+    MFI.setRestorePoints(SaveRestorePoints);
 
   return false;
 }
diff --git a/llvm/lib/CodeGen/MIRPrinter.cpp b/llvm/lib/CodeGen/MIRPrinter.cpp
index a3ffb44fdd831..584d6c658e4dc 100644
--- a/llvm/lib/CodeGen/MIRPrinter.cpp
+++ b/llvm/lib/CodeGen/MIRPrinter.cpp
@@ -119,7 +119,7 @@ class MIRPrinter {
   void convert(ModuleSlotTracker &MST, yaml::MachineFrameInfo &YamlMFI,
                const MachineFrameInfo &MFI);
   void convert(ModuleSlotTracker &MST, yaml::SaveRestorePoints &YamlSRPoints,
-               MachineBasicBlock *SaveRestorePoint);
+               std::vector<MachineBasicBlock *> SaveRestorePoints);
   void convert(yaml::MachineFunction &MF,
                const MachineConstantPool &ConstantPool);
   void convert(ModuleSlotTracker &MST, yaml::MachineJumpTable &YamlJTI,
@@ -399,10 +399,10 @@ void MIRPrinter::convert(ModuleSlotTracker &MST,
   YamlMFI.HasTailCall = MFI.hasTailCall();
   YamlMFI.IsCalleeSavedInfoValid = MFI.isCalleeSavedInfoValid();
   YamlMFI.LocalFrameSize = MFI.getLocalFrameSize();
-  if (MFI.getSavePoint())
-    convert(MST, YamlMFI.SavePoints, MFI.getSavePoint());
-  if (MFI.getRestorePoint())
-    convert(MST, YamlMFI.RestorePoints, MFI.getRestorePoint());
+  if (!MFI.getSavePoints().empty())
+    convert(MST, YamlMFI.SavePoints, MFI.getSavePoints());
+  if (!MFI.getRestorePoints().empty())
+    convert(MST, YamlMFI.RestorePoints, MFI.getRestorePoints());
 }
 
 void MIRPrinter::convertEntryValueObjects(yaml::MachineFunction &YMF,
@@ -646,15 +646,18 @@ void MIRPrinter::convert(yaml::MachineFunction &MF,
 
 void MIRPrinter::convert(ModuleSlotTracker &MST,
                          yaml::SaveRestorePoints &YamlSRPoints,
-                         MachineBasicBlock *SRPoint) {
-  SmallString<16> Str;
-  yaml::SaveRestorePointEntry Entry;
-  raw_svector_ostream StrOS(Str);
-  StrOS << printMBBReference(*SRPoint);
-  Entry.Point = StrOS.str().str();
+                         std::vector<MachineBasicBlock *> SRPoints) {
   auto &Points =
       std::get<std::vector<yaml::SaveRestorePointEntry>>(YamlSRPoints);
-  Points.push_back(Entry);
+  for (const auto &MBB : SRPoints) {
+    SmallString<16> Str;
+    yaml::SaveRestorePointEntry Entry;
+    raw_svector_ostream StrOS(Str);
+    StrOS << printMBBReference(*MBB);
+    Entry.Point = StrOS.str().str();
+    Str.clear();
+    Points.push_back(Entry);
+  }
 }
 
 void MIRPrinter::convert(ModuleSlotTracker &MST,
diff --git a/llvm/lib/CodeGen/MachineFrameInfo.cpp b/llvm/lib/CodeGen/MachineFrameInfo.cpp
index e4b993850f73d..a8306b2ef2e5b 100644
--- a/llvm/lib/CodeGen/MachineFrameInfo.cpp
+++ b/llvm/lib/CodeGen/MachineFrameInfo.cpp
@@ -244,6 +244,22 @@ void MachineFrameInfo::print(const MachineFunction &MF, raw_ostream &OS) const{
     }
     OS << "\n";
   }
+  OS << "save/restore points:\n";
+
+  if (!SavePoints.empty()) {
+    OS << "save points:\n";
+
+    for (auto &item : SavePoints)
+      OS << printMBBReference(*item) << "\n";
+  } else
+    OS << "save points are empty\n";
+
+  if (!RestorePoints.empty()) {
+    OS << "restore points:\n";
+    for (auto &item : RestorePoints)
+      OS << printMBBReference(*item) << "\n";
+  } else
+    OS << "restore points are empty\n";
 }
 
 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
diff --git a/llvm/lib/CodeGen/PrologEpilogInserter.cpp b/llvm/lib/CodeGen/PrologEpilogInserter.cpp
index eb8929cae069e..dcd78be74f6f3 100644
--- a/llvm/lib/CodeGen/PrologEpilogInserter.cpp
+++ b/llvm/lib/CodeGen/PrologEpilogInserter.cpp
@@ -349,8 +349,8 @@ bool PEI::runOnMachineFunction(MachineFunction &MF) {
   delete RS;
   SaveBlocks.clear();
   RestoreBlocks.clear();
-  MFI.setSavePoint(nullptr);
-  MFI.setRestorePoint(nullptr);
+  MFI.clearSavePoints();
+  MFI.clearRestorePoints();
   return true;
 }
 
@@ -399,16 +399,17 @@ void PEI::calculateCallFrameInfo(MachineFunction &MF) {
 /// callee-saved registers, and placing prolog and epilog code.
 void PEI::calculateSaveRestoreBlocks(MachineFunction &MF) {
   const MachineFrameInfo &MFI = MF.getFrameInfo();
-
   // Even when we do not change any CSR, we still want to insert the
   // prologue and epilogue of the function.
   // So set the save points for those.
 
   // Use the points found by shrink-wrapping, if any.
-  if (MFI.getSavePoint()) {
-    SaveBlocks.push_back(MFI.getSavePoint());
-    assert(MFI.getRestorePoint() && "Both restore and save must be set");
-    MachineBasicBlock *RestoreBlock = MFI.getRestorePoint();
+  if (!MFI.getSavePoints().empty()) {
+    assert(MFI.getSavePoints().size() < 2 && "MFI can't contain multiple save points!");
+    SaveBlocks.push_back(MFI.getSavePoints().front());
+    assert(!MFI.getRestorePoints().empty() && "Both restore and save must be set");
+    assert(MFI.getRestorePoints().size() < 2 && "MFI can't contain multiple restore points!");
+    MachineBasicBlock *RestoreBlock = MFI.getRestorePoints().front();
     // If RestoreBlock does not have any successor and is not a return block
     // then the end point is unreachable and we do not need to insert any
     // epilogue.
@@ -417,13 +418,15 @@ void PEI::calculateSaveRestoreBlocks(MachineFunction &MF) {
     return;
   }
 
-  // Save refs to entry and return blocks.
-  SaveBlocks.push_back(&MF.front());
-  for (MachineBasicBlock &MBB : MF) {
-    if (MBB.isEHFuncletEntry())
-      SaveBlocks.push_back(&MBB);
-    if (MBB.isReturnBlock())
-      RestoreBlocks.push_back(&MBB);
+  if (MFI.getSavePoints().empty()) {
+    // Save refs to entry and return blocks.
+    SaveBlocks.push_back(&MF.front());
+    for (MachineBasicBlock &MBB : MF) {
+      if (MBB.isEHFuncletEntry())
+        SaveBlocks.push_back(&MBB);
+      if (MBB.isReturnBlock())
+        RestoreBlocks.push_back(&MBB);
+    }
   }
 }
 
@@ -534,7 +537,10 @@ static void updateLiveness(MachineFunction &MF) {
   SmallPtrSet<MachineBasicBlock *, 8> Visited;
   SmallVector<MachineBasicBlock *, 8> WorkList;
   MachineBasicBlock *Entry = &MF.front();
-  MachineBasicBlock *Save = MFI.getSavePoint();
+
+  assert(MFI.getSavePoints().size() < 2 && "MFI can't contain multiple save points!");
+  MachineBasicBlock *Save = MFI.getSavePoints().empty() ? nullptr : MFI.getSavePoints().front();
+ 
 
   if (!Save)
     Save = Entry;
@@ -545,7 +551,8 @@ static void updateLiveness(MachineFunction &MF) {
   }
   Visited.insert(Save);
 
-  MachineBasicBlock *Restore = MFI.getRestorePoint();
+  assert(MFI.getRestorePoints().size() < 2 && "MFI can't contain multiple restore points!");
+  MachineBasicBlock *Restore = MFI.getRestorePoints().empty() ? nullptr : MFI.getRestorePoints().front();
   if (Restore)
     // By construction Restore cannot be visited, otherwise it
     // means there exists a path to Restore that does not go
diff --git a/llvm/lib/CodeGen/ShrinkWrap.cpp b/llvm/lib/CodeGen/ShrinkWrap.cpp
index fa57eb30fac43..604c26c2db90c 100644
--- a/llvm/lib/CodeGen/ShrinkWrap.cpp
+++ b/llvm/lib/CodeGen/ShrinkWrap.cpp
@@ -959,8 +959,14 @@ bool ShrinkWrap::runOnMachineFunction(MachineFunction &MF) {
                     << "\nRestore: " << printMBBReference(*Restore) << '\n');
 
   MachineFrameInfo &MFI = MF.getFrameInfo();
-  MFI.setSavePoint(Save);
-  MFI.setRestorePoint(Restore);
+  std::vector<MachineBasicBlock *> SavePoints;
+  std::vector<MachineBasicBlock *> RestorePoints;
+  if (Save) {
+    SavePoints.push_back(Save);
+    RestorePoints.push_back(Restore);
+  }
+  MFI.setSavePoints(SavePoints);
+  MFI.setRestorePoints(RestorePoints);
   ++NumCandidates;
   return Changed;
 }
diff --git a/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp b/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp
index d27c523425feb..cd1d78c5d9163 100644
--- a/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp
+++ b/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp
@@ -193,10 +193,12 @@ void SILowerSGPRSpills::calculateSaveRestoreBlocks(MachineFunction &MF) {
   // So set the save points for those.
 
   // Use the points found by shrink-wrapping, if any.
-  if (MFI.getSavePoint()) {
-    SaveBlocks.push_back(MFI.getSavePoint());
-    assert(MFI.getRestorePoint() && "Both restore and save must be set");
-    MachineBasicBlock *RestoreBlock = MFI.getRestorePoint();
+  if (!MFI.getSavePoints().empty()) {
+    assert(MFI.getSavePoints().size() < 2 && "MFI can't contain multiple save points!");
+    SaveBlocks.push_back(MFI.getSavePoints().front());
+    assert(!MFI.getRestorePoints().empty() && "Both restore and save must be set");
+    assert(MFI.getRestorePoints().size() < 2 && "MFI can't contain multiple restore points!");
+    MachineBasicBlock *RestoreBlock = MFI.getRestorePoints().front();
     // If RestoreBlock does not have any successor and is not a return block
     // then the end point is unreachable and we do not need to insert any
     // epilogue.
diff --git a/llvm/lib/Target/PowerPC/PPCFrameLowering.cpp b/llvm/lib/Target/PowerPC/PPCFrameLowering.cpp
index ba775c4a679d0..4a09bee37636a 100644
--- a/llvm/lib/Target/PowerPC/PPCFrameLowering.cpp
+++ b/llvm/lib/Target/PowerPC/PPCFrameLowering.cpp
@@ -2078,8 +2078,9 @@ void PPCFrameLowering::processFunctionBeforeFrameFinalized(MachineFunction &MF,
   // tail call might not be in the new RestoreBlock, so real branch instruction
   // won't be generated by emitEpilogue(), because shrink-wrap has chosen new
   // RestoreBlock. So we handle this case here.
-  if (MFI.getSavePoint() && MFI.hasTailCall()) {
-    MachineBasicBlock *RestoreBlock = MFI.getRestorePoint();
+  if (!MFI.getSavePoints().empty() && MFI.hasTailCall()) {
+    assert(MFI.getRestorePoints().size() < 2 && "MFI can't contain multiple restore points!");
+    MachineBasicBlock *RestoreBlock = MFI.getRestorePoints().front();
     for (MachineBasicBlock &MBB : MF) {
       if (MBB.isReturnBlock() && (&MBB) != RestoreBlock)
         createTailCallBranchInstr(MBB);
diff --git a/llvm/test/CodeGen/MIR/X86/frame-info-multiple-save-restore-points-parse.mir b/llvm/test/CodeGen/MIR/X86/frame-info-multiple-save-restore-points-parse.mir
new file mode 100644
index 0000000000000..4c60ccd573595
--- /dev/null
+++ b/llvm/test/CodeGen/MIR/X86/frame-info-multiple-save-restore-points-parse.mir
@@ -0,0 +1,81 @@
+# RUN: llc -mtriple=x86_64 -run-pass none -o - %s | FileCheck %s
+# This test ensures that the MIR parser parses the save and restore points in
+# the machine frame info correctly.
+
+--- |
+
+  define i32 @foo(i32 %a, i32 %b) {
+  entry:
+    %tmp = alloca i32, align 4
+    %tmp2 = icmp slt i32 %a, %b
+    br i1 %tmp2, label %true, label %false
+
+  true:
+    store i32 %a, ptr %tmp, align 4
+    %tmp4 = call i32 @doSomething(i32 0, ptr %tmp)
+    br label %false
+
+  false:
+    %tmp.0 = phi i32 [ %tmp4, %true ], [ %a, %entry ]
+    ret i32 %tmp.0
+  }
+
+  declare i32 @doSomething(i32, ptr)
+
+...
+---
+name:            foo
+tracksRegLiveness: true
+liveins:
+  - { reg: '$edi' }
+  - { reg: '$esi' }
+# CHECK: frameInfo:
+# CHECK:      savePoint:
+# CHECK-NEXT:   - point:           '%bb.1'
+# CHECK-NEXT:   - point:           '%bb.2'
+# CHECK:      restorePoint:
+# CHECK-NEXT:   - point:           '%bb.2'
+# CHECK-NEXT:   - point:           '%bb.3'
+# CHECK: stack
+frameInfo:
+  maxAlignment:  4
+  hasCalls:      true
+  savePoint:
+    - point:     '%bb.1'
+    - point:     '%bb.2'
+  restorePoint:  
+    - point:     '%bb.2'
+    - point:     '%bb.3'
+stack:
+  - { id: 0, name: tmp, offset: 0, size: 4, alignment: 4 }
+body: |
+  bb.0:
+    successors: %bb.2, %bb.1
+    liveins: $edi, $esi
+
+    $eax = COPY $edi
+    CMP32rr $eax, killed $esi, implicit-def $eflags
+    JCC_1 %bb.2, 12, implicit killed $eflags
+
+  bb.1:
+    successors: %bb.3
+    liveins: $eax
+
+    JMP_1 %bb.3
+
+  bb.2.true:
+    successors: %bb.3
+    liveins: $eax
+
+    MOV32mr %stack.0.tmp, 1, _, 0, _, killed $eax
+    ADJCALLSTACKDOWN64 0, 0, 0, implicit-def $rsp, implicit-def $ssp, implicit-def dead $eflags, implicit $rsp, implicit $ssp
+    $rsi = LEA64r %stack.0.tmp, 1, _, 0, _
+    $edi = MOV32r0 implicit-def dead $eflags
+    CALL64pcrel32 @doSomething, csr_64, implicit $rsp, implicit $ssp, implicit $edi, implicit $rsi, implicit-def $rsp, implicit-def $ssp, implicit-def $eax
+    ADJCALLSTACKUP64 0, 0, implicit-def $rsp, implicit-def $ssp, implicit-def dead $eflags, implicit $rsp, implicit $ssp
+
+  bb.3.false:
+    liveins: $eax
+
+    RET64 $eax
+...
diff --git a/llvm/test/tools/llvm-reduce/mir/preserve-frame-info.mir b/llvm/test/tools/llvm-reduce/mir/preserve-frame-info.mir
index 957c90929d3fe..e47fd689912b1 100644
--- a/llvm/test/tools/llvm-reduce/mir/preserve-frame-info.mir
+++ b/llvm/test/tools/llvm-reduce/mir/preserve-frame-info.mir
@@ -119,7 +119,7 @@ frameInfo:
   hasTailCall:     true
   localFrameSize:  0
   savePoint:       '%bb.1'
-  restorePoint:    '%bb.1'
+  restorePoint:    '%bb.2'
 
 fixedStack:
   - { id: 0, offset: 0, size: 8, alignment: 4, isImmutable: true, isAliased: false }
diff --git a/llvm/tools/llvm-reduce/ReducerWorkItem.cpp b/llvm/tools/llvm-reduce/ReducerWorkItem.cpp
index 7cd974f0cf438..9d391f590e5bc 100644
--- a/llvm/tools/llvm-reduce/ReducerWorkItem.cpp
+++ b/llvm/tools/llvm-reduce/ReducerWorkItem.cpp
@@ -93,11 +93,21 @@ static void cloneFrameInfo(
   DstMFI.setCVBytesOfCalleeSavedRegisters(
       SrcMFI.getCVBytesOfCalleeSavedRegisters());
 
-  if (MachineBasicBlock *SavePt = SrcMFI.getSavePoint())
-    DstMFI.setSavePoint(Src2DstMBB.find(SavePt)->second);
-  if (MachineBasicBlock *RestorePt = SrcMFI.getRestorePoint())
-    DstMFI.setRestorePoint(Src2DstMBB.find(RestorePt)->second);
+  assert(SrcMFI.getSavePoints().size() < 2 && "MFI can't contain multiple save points!");
+  if (!SrcMFI.getSavePoints().empty()) {
+    MachineBasicBlock *SavePt = SrcMFI.getSavePoints().front();
+    std::vector<MachineBasicBlock *> SavePts;
+    SavePts.push_back(Src2DstMBB.find(SavePt)->second);
+    DstMFI.setSavePoints(SavePts);
+  }
 
+  assert(SrcMFI.getRestorePoints().size() < 2 && "MFI can't contain multiple restore points!");
+  if (!SrcMFI.getRestorePoints().empty()) {
+    MachineBasicBlock *RestorePt = SrcMFI.getRestorePoints().front();
+    std::vector<MachineBasicBlock *> RestorePts;
+    RestorePts.push_back(Src2DstMBB.find(RestorePt)->second);
+    DstMFI.setRestorePoints(RestorePts);
+  }
 
   auto CopyObjectProperties = [](MachineFrameInfo &DstMFI,
                                  const MachineFrameInfo &SrcMFI, int FI) {

>From 740901474a08d6179117757a49088920678581f4 Mon Sep 17 00:00:00 2001
From: ens-sc <elizaveta.noskova at syntacore.com>
Date: Mon, 3 Mar 2025 20:02:04 +0300
Subject: [PATCH 4/6] formatting

---
 llvm/include/llvm/CodeGen/MachineFrameInfo.h | 16 ++++++++++----
 llvm/lib/CodeGen/PrologEpilogInserter.cpp    | 22 +++++++++++++-------
 llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp |  9 +++++---
 llvm/lib/Target/PowerPC/PPCFrameLowering.cpp |  3 ++-
 llvm/tools/llvm-reduce/ReducerWorkItem.cpp   |  6 ++++--
 5 files changed, 38 insertions(+), 18 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/MachineFrameInfo.h b/llvm/include/llvm/CodeGen/MachineFrameInfo.h
index a9f68b75193fa..227eb826e5f08 100644
--- a/llvm/include/llvm/CodeGen/MachineFrameInfo.h
+++ b/llvm/include/llvm/CodeGen/MachineFrameInfo.h
@@ -820,10 +820,18 @@ class MachineFrameInfo {
 
   void setCalleeSavedInfoValid(bool v) { CSIValid = v; }
 
-  const std::vector<MachineBasicBlock *> &getSavePoints() const { return SavePoints; }
-  void setSavePoints(std::vector<MachineBasicBlock *> NewSavePoints) { SavePoints = std::move(NewSavePoints); }
-  const std::vector<MachineBasicBlock *> getRestorePoints() const { return RestorePoints; }
-  void setRestorePoints(std::vector<MachineBasicBlock *> NewRestorePoints) { RestorePoints = std::move(NewRestorePoints); }
+  const std::vector<MachineBasicBlock *> &getSavePoints() const {
+    return SavePoints;
+  }
+  void setSavePoints(std::vector<MachineBasicBlock *> NewSavePoints) {
+    SavePoints = std::move(NewSavePoints);
+  }
+  const std::vector<MachineBasicBlock *> getRestorePoints() const {
+    return RestorePoints;
+  }
+  void setRestorePoints(std::vector<MachineBasicBlock *> NewRestorePoints) {
+    RestorePoints = std::move(NewRestorePoints);
+  }
 
   void clearSavePoints() { SavePoints.clear(); }
   void clearRestorePoints() { RestorePoints.clear(); }
diff --git a/llvm/lib/CodeGen/PrologEpilogInserter.cpp b/llvm/lib/CodeGen/PrologEpilogInserter.cpp
index dcd78be74f6f3..0960be90fce2d 100644
--- a/llvm/lib/CodeGen/PrologEpilogInserter.cpp
+++ b/llvm/lib/CodeGen/PrologEpilogInserter.cpp
@@ -405,10 +405,13 @@ void PEI::calculateSaveRestoreBlocks(MachineFunction &MF) {
 
   // Use the points found by shrink-wrapping, if any.
   if (!MFI.getSavePoints().empty()) {
-    assert(MFI.getSavePoints().size() < 2 && "MFI can't contain multiple save points!");
+    assert(MFI.getSavePoints().size() < 2 &&
+           "MFI can't contain multiple save points!");
     SaveBlocks.push_back(MFI.getSavePoints().front());
-    assert(!MFI.getRestorePoints().empty() && "Both restore and save must be set");
-    assert(MFI.getRestorePoints().size() < 2 && "MFI can't contain multiple restore points!");
+    assert(!MFI.getRestorePoints().empty() &&
+           "Both restore and save must be set");
+    assert(MFI.getRestorePoints().size() < 2 &&
+           "MFI can't contain multiple restore points!");
     MachineBasicBlock *RestoreBlock = MFI.getRestorePoints().front();
     // If RestoreBlock does not have any successor and is not a return block
     // then the end point is unreachable and we do not need to insert any
@@ -538,9 +541,10 @@ static void updateLiveness(MachineFunction &MF) {
   SmallVector<MachineBasicBlock *, 8> WorkList;
   MachineBasicBlock *Entry = &MF.front();
 
-  assert(MFI.getSavePoints().size() < 2 && "MFI can't contain multiple save points!");
-  MachineBasicBlock *Save = MFI.getSavePoints().empty() ? nullptr : MFI.getSavePoints().front();
- 
+  assert(MFI.getSavePoints().size() < 2 &&
+         "MFI can't contain multiple save points!");
+  MachineBasicBlock *Save =
+      MFI.getSavePoints().empty() ? nullptr : MFI.getSavePoints().front();
 
   if (!Save)
     Save = Entry;
@@ -551,8 +555,10 @@ static void updateLiveness(MachineFunction &MF) {
   }
   Visited.insert(Save);
 
-  assert(MFI.getRestorePoints().size() < 2 && "MFI can't contain multiple restore points!");
-  MachineBasicBlock *Restore = MFI.getRestorePoints().empty() ? nullptr : MFI.getRestorePoints().front();
+  assert(MFI.getRestorePoints().size() < 2 &&
+         "MFI can't contain multiple restore points!");
+  MachineBasicBlock *Restore =
+      MFI.getRestorePoints().empty() ? nullptr : MFI.getRestorePoints().front();
   if (Restore)
     // By construction Restore cannot be visited, otherwise it
     // means there exists a path to Restore that does not go
diff --git a/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp b/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp
index cd1d78c5d9163..e76fb58b3be25 100644
--- a/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp
+++ b/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp
@@ -194,10 +194,13 @@ void SILowerSGPRSpills::calculateSaveRestoreBlocks(MachineFunction &MF) {
 
   // Use the points found by shrink-wrapping, if any.
   if (!MFI.getSavePoints().empty()) {
-    assert(MFI.getSavePoints().size() < 2 && "MFI can't contain multiple save points!");
+    assert(MFI.getSavePoints().size() < 2 &&
+           "MFI can't contain multiple save points!");
     SaveBlocks.push_back(MFI.getSavePoints().front());
-    assert(!MFI.getRestorePoints().empty() && "Both restore and save must be set");
-    assert(MFI.getRestorePoints().size() < 2 && "MFI can't contain multiple restore points!");
+    assert(!MFI.getRestorePoints().empty() &&
+           "Both restore and save must be set");
+    assert(MFI.getRestorePoints().size() < 2 &&
+           "MFI can't contain multiple restore points!");
     MachineBasicBlock *RestoreBlock = MFI.getRestorePoints().front();
     // If RestoreBlock does not have any successor and is not a return block
     // then the end point is unreachable and we do not need to insert any
diff --git a/llvm/lib/Target/PowerPC/PPCFrameLowering.cpp b/llvm/lib/Target/PowerPC/PPCFrameLowering.cpp
index 4a09bee37636a..b3bcc6448c162 100644
--- a/llvm/lib/Target/PowerPC/PPCFrameLowering.cpp
+++ b/llvm/lib/Target/PowerPC/PPCFrameLowering.cpp
@@ -2079,7 +2079,8 @@ void PPCFrameLowering::processFunctionBeforeFrameFinalized(MachineFunction &MF,
   // won't be generated by emitEpilogue(), because shrink-wrap has chosen new
   // RestoreBlock. So we handle this case here.
   if (!MFI.getSavePoints().empty() && MFI.hasTailCall()) {
-    assert(MFI.getRestorePoints().size() < 2 && "MFI can't contain multiple restore points!");
+    assert(MFI.getRestorePoints().size() < 2 &&
+           "MFI can't contain multiple restore points!");
     MachineBasicBlock *RestoreBlock = MFI.getRestorePoints().front();
     for (MachineBasicBlock &MBB : MF) {
       if (MBB.isReturnBlock() && (&MBB) != RestoreBlock)
diff --git a/llvm/tools/llvm-reduce/ReducerWorkItem.cpp b/llvm/tools/llvm-reduce/ReducerWorkItem.cpp
index 9d391f590e5bc..7b1f69a8671ef 100644
--- a/llvm/tools/llvm-reduce/ReducerWorkItem.cpp
+++ b/llvm/tools/llvm-reduce/ReducerWorkItem.cpp
@@ -93,7 +93,8 @@ static void cloneFrameInfo(
   DstMFI.setCVBytesOfCalleeSavedRegisters(
       SrcMFI.getCVBytesOfCalleeSavedRegisters());
 
-  assert(SrcMFI.getSavePoints().size() < 2 && "MFI can't contain multiple save points!");
+  assert(SrcMFI.getSavePoints().size() < 2 &&
+         "MFI can't contain multiple save points!");
   if (!SrcMFI.getSavePoints().empty()) {
     MachineBasicBlock *SavePt = SrcMFI.getSavePoints().front();
     std::vector<MachineBasicBlock *> SavePts;
@@ -101,7 +102,8 @@ static void cloneFrameInfo(
     DstMFI.setSavePoints(SavePts);
   }
 
-  assert(SrcMFI.getRestorePoints().size() < 2 && "MFI can't contain multiple restore points!");
+  assert(SrcMFI.getRestorePoints().size() < 2 &&
+         "MFI can't contain multiple restore points!");
   if (!SrcMFI.getRestorePoints().empty()) {
     MachineBasicBlock *RestorePt = SrcMFI.getRestorePoints().front();
     std::vector<MachineBasicBlock *> RestorePts;

>From a1ce745b0c3dba4ba03260ba38503f404f3f8dc3 Mon Sep 17 00:00:00 2001
From: ens-sc <elizaveta.noskova at syntacore.com>
Date: Mon, 16 Sep 2024 18:48:13 +0300
Subject: [PATCH 5/6] [llvm] support multiple save/restore points in
 prolog-epilog

With this patch the possibility to store multiple Save and Restore points in MachineFrameInfo appears.
As the logical consequnce of it, the notions "Save point" / "Restore point"
are no longer synonyms for "Prolog" / "Epilog". Currently, "Prolog" / "Epilog"
is the place for stack allocation / deallocation and
"Save point" / "Restore point" is the place for register spills and restores.
So, now we need to store in MachineFrameInfo not only vector of Save and vector of Restore blocks,
but Prolog and Epilog.

As we assume to have multiple Save and Restore points we need to know the list of registers,
we store / restore in each point. Threfore our SavePoint become a pair <MachineBasicBlock, std::vector<Register>>.

The full support for operating with multiple Save / Restore points is supported only in RISCV backend.
---
 llvm/include/llvm/CodeGen/MIRYamlMapping.h    |   4 +-
 llvm/include/llvm/CodeGen/MachineFrameInfo.h  | 139 +++++++++-
 llvm/lib/CodeGen/MIRParser/MIRParser.cpp      |  23 +-
 llvm/lib/CodeGen/MIRPrinter.cpp               |  29 +-
 llvm/lib/CodeGen/MachineFrameInfo.cpp         |   5 +-
 llvm/lib/CodeGen/PrologEpilogInserter.cpp     | 258 +++++++++++++-----
 llvm/lib/CodeGen/ShrinkWrap.cpp               |  15 +-
 llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp  |  40 +--
 llvm/lib/Target/PowerPC/PPCFrameLowering.cpp  |   5 +-
 llvm/lib/Target/RISCV/RISCVFrameLowering.cpp  |  87 ++++--
 llvm/lib/Target/RISCV/RISCVFrameLowering.h    |   4 +
 llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp   |  47 ++++
 .../CodeGen/AArch64/live-debugvalues-sve.mir  |  14 +-
 .../X86/frame-info-save-restore-points.mir    |  10 +-
 .../CodeGen/PowerPC/common-chain-aix32.ll     |   6 +-
 llvm/test/CodeGen/PowerPC/common-chain.ll     |   8 +-
 .../PowerPC/loop-instr-form-prepare.ll        |  28 +-
 .../CodeGen/PowerPC/lsr-profitable-chain.ll   |  32 +--
 .../CodeGen/PowerPC/more-dq-form-prepare.ll   | 128 ++++-----
 llvm/test/CodeGen/PowerPC/pr43527.ll          |   4 +-
 llvm/test/CodeGen/PowerPC/shrink-wrap.ll      | 204 +++++++-------
 .../CodeGen/X86/cfi-epilogue-with-return.mir  |  18 +-
 .../X86/cfi-epilogue-without-return.mir       |  18 +-
 llvm/tools/llvm-reduce/ReducerWorkItem.cpp    |  20 +-
 24 files changed, 773 insertions(+), 373 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/MIRYamlMapping.h b/llvm/include/llvm/CodeGen/MIRYamlMapping.h
index 33451b4ef2a26..67300524b2f60 100644
--- a/llvm/include/llvm/CodeGen/MIRYamlMapping.h
+++ b/llvm/include/llvm/CodeGen/MIRYamlMapping.h
@@ -635,9 +635,10 @@ namespace yaml {
 // list
 struct SaveRestorePointEntry {
   StringValue Point;
+  std::vector<StringValue> Registers;
 
   bool operator==(const SaveRestorePointEntry &Other) const {
-    return Point == Other.Point;
+    return Point == Other.Point && Registers == Other.Registers;
   }
 };
 
@@ -677,6 +678,7 @@ template <> struct PolymorphicTraits<SaveRestorePoints> {
 template <> struct MappingTraits<SaveRestorePointEntry> {
   static void mapping(IO &YamlIO, SaveRestorePointEntry &Entry) {
     YamlIO.mapRequired("point", Entry.Point);
+    YamlIO.mapRequired("registers", Entry.Registers);
   }
 };
 
diff --git a/llvm/include/llvm/CodeGen/MachineFrameInfo.h b/llvm/include/llvm/CodeGen/MachineFrameInfo.h
index 227eb826e5f08..d746466d41c3e 100644
--- a/llvm/include/llvm/CodeGen/MachineFrameInfo.h
+++ b/llvm/include/llvm/CodeGen/MachineFrameInfo.h
@@ -27,6 +27,21 @@ class MachineBasicBlock;
 class BitVector;
 class AllocaInst;
 
+using SaveRestorePoints = DenseMap<MachineBasicBlock *, std::vector<Register>>;
+
+class CalleeSavedInfoPerBB {
+  DenseMap<MachineBasicBlock *, std::vector<CalleeSavedInfo>> Map;
+
+public:
+  std::vector<CalleeSavedInfo> get(MachineBasicBlock *MBB) const {
+    return Map.lookup(MBB);
+  }
+
+  void set(DenseMap<MachineBasicBlock *, std::vector<CalleeSavedInfo>> CSI) {
+    Map = std::move(CSI);
+  }
+};
+
 /// The CalleeSavedInfo class tracks the information need to locate where a
 /// callee saved register is in the current frame.
 /// Callee saved reg can also be saved to a different register rather than
@@ -37,6 +52,8 @@ class CalleeSavedInfo {
     int FrameIdx;
     unsigned DstReg;
   };
+  std::vector<MachineBasicBlock *> SpilledIn;
+  std::vector<MachineBasicBlock *> RestoredIn;
   /// Flag indicating whether the register is actually restored in the epilog.
   /// In most cases, if a register is saved, it is also restored. There are
   /// some situations, though, when this is not the case. For example, the
@@ -58,9 +75,9 @@ class CalleeSavedInfo {
   explicit CalleeSavedInfo(unsigned R, int FI = 0) : Reg(R), FrameIdx(FI) {}
 
   // Accessors.
-  Register getReg()                        const { return Reg; }
-  int getFrameIdx()                        const { return FrameIdx; }
-  unsigned getDstReg()                     const { return DstReg; }
+  Register getReg() const { return Reg; }
+  int getFrameIdx() const { return FrameIdx; }
+  unsigned getDstReg() const { return DstReg; }
   void setFrameIdx(int FI) {
     FrameIdx = FI;
     SpilledToReg = false;
@@ -72,6 +89,16 @@ class CalleeSavedInfo {
   bool isRestored()                        const { return Restored; }
   void setRestored(bool R)                       { Restored = R; }
   bool isSpilledToReg()                    const { return SpilledToReg; }
+  ArrayRef<MachineBasicBlock *> spilledIn() const { return SpilledIn; }
+  ArrayRef<MachineBasicBlock *> restoredIn() const { return RestoredIn; }
+  void addSpilledIn(MachineBasicBlock *MBB) { SpilledIn.push_back(MBB); }
+  void addRestoredIn(MachineBasicBlock *MBB) { RestoredIn.push_back(MBB); }
+  void setSpilledIn(std::vector<MachineBasicBlock *> BBV) {
+    SpilledIn = std::move(BBV);
+  }
+  void setRestoredIn(std::vector<MachineBasicBlock *> BBV) {
+    RestoredIn = std::move(BBV);
+  }
 };
 
 /// The MachineFrameInfo class represents an abstract stack frame until
@@ -295,6 +322,10 @@ class MachineFrameInfo {
   /// Has CSInfo been set yet?
   bool CSIValid = false;
 
+  CalleeSavedInfoPerBB CSInfoPerSave;
+
+  CalleeSavedInfoPerBB CSInfoPerRestore;
+
   /// References to frame indices which are mapped
   /// into the local frame allocation block. <FrameIdx, LocalOffset>
   SmallVector<std::pair<int, int64_t>, 32> LocalFrameObjects;
@@ -330,10 +361,17 @@ class MachineFrameInfo {
   /// stack objects like arguments so we can't treat them as immutable.
   bool HasTailCall = false;
 
-  /// Not empty, if shrink-wrapping found a better place for the prologue.
-  std::vector<MachineBasicBlock *> SavePoints;
-  /// Not empty, if shrink-wrapping found a better place for the epilogue.
-  std::vector<MachineBasicBlock *> RestorePoints;
+  /// Not null, if shrink-wrapping found a better place for the prologue.
+  MachineBasicBlock *Prolog = nullptr;
+  /// Not null, if shrink-wrapping found a better place for the epilogue.
+  MachineBasicBlock *Epilog = nullptr;
+
+  /// Not empty, if shrink-wrapping found a better place for saving callee
+  /// saves.
+  SaveRestorePoints SavePoints;
+  /// Not empty, if shrink-wrapping found a better place for restoring callee
+  /// saves.
+  SaveRestorePoints RestorePoints;
 
   /// Size of the UnsafeStack Frame
   uint64_t UnsafeStackSize = 0;
@@ -809,30 +847,103 @@ class MachineFrameInfo {
   /// \copydoc getCalleeSavedInfo()
   std::vector<CalleeSavedInfo> &getCalleeSavedInfo() { return CSInfo; }
 
+  /// Returns callee saved info vector for provided save point in
+  /// the current function.
+  std::vector<CalleeSavedInfo> getCSInfoPerSave(MachineBasicBlock *MBB) const {
+    return CSInfoPerSave.get(MBB);
+  }
+
+  /// Returns callee saved info vector for provided restore point
+  /// in the current function.
+  std::vector<CalleeSavedInfo>
+  getCSInfoPerRestore(MachineBasicBlock *MBB) const {
+    return CSInfoPerRestore.get(MBB);
+  }
+
   /// Used by prolog/epilog inserter to set the function's callee saved
   /// information.
   void setCalleeSavedInfo(std::vector<CalleeSavedInfo> CSI) {
     CSInfo = std::move(CSI);
   }
 
+  /// Used by prolog/epilog inserter to set the function's callee saved
+  /// information for particular save point.
+  void setCSInfoPerSave(
+      DenseMap<MachineBasicBlock *, std::vector<CalleeSavedInfo>> CSI) {
+    CSInfoPerSave.set(CSI);
+  }
+
+  /// Used by prolog/epilog inserter to set the function's callee saved
+  /// information for particular restore point.
+  void setCSInfoPerRestore(
+      DenseMap<MachineBasicBlock *, std::vector<CalleeSavedInfo>> CSI) {
+    CSInfoPerRestore.set(CSI);
+  }
+
   /// Has the callee saved info been calculated yet?
   bool isCalleeSavedInfoValid() const { return CSIValid; }
 
   void setCalleeSavedInfoValid(bool v) { CSIValid = v; }
 
-  const std::vector<MachineBasicBlock *> &getSavePoints() const {
-    return SavePoints;
+  const SaveRestorePoints &getRestorePoints() const { return RestorePoints; }
+
+  const SaveRestorePoints &getSavePoints() const { return SavePoints; }
+
+  std::pair<MachineBasicBlock *, std::vector<Register>>
+  getRestorePoint(MachineBasicBlock *MBB) const {
+    if (auto It = RestorePoints.find(MBB); It != RestorePoints.end())
+      return *It;
+
+    std::vector<Register> Regs = {};
+    return std::make_pair(nullptr, Regs);
   }
-  void setSavePoints(std::vector<MachineBasicBlock *> NewSavePoints) {
-    SavePoints = std::move(NewSavePoints);
+
+  std::pair<MachineBasicBlock *, std::vector<Register>>
+  getSavePoint(MachineBasicBlock *MBB) const {
+    if (auto It = SavePoints.find(MBB); It != SavePoints.end())
+      return *It;
+
+    std::vector<Register> Regs = {};
+    return std::make_pair(nullptr, Regs);
   }
-  const std::vector<MachineBasicBlock *> getRestorePoints() const {
-    return RestorePoints;
+
+  void setSavePoints(SaveRestorePoints NewSavePoints) {
+    SavePoints = std::move(NewSavePoints);
   }
-  void setRestorePoints(std::vector<MachineBasicBlock *> NewRestorePoints) {
+
+  void setRestorePoints(SaveRestorePoints NewRestorePoints) {
     RestorePoints = std::move(NewRestorePoints);
   }
 
+  void setSavePoint(MachineBasicBlock *MBB, std::vector<Register> &Regs) {
+    if (SavePoints.contains(MBB))
+      SavePoints[MBB] = Regs;
+    else
+      SavePoints.insert(std::make_pair(MBB, Regs));
+  }
+
+  static const SaveRestorePoints constructSaveRestorePoints(
+      const SaveRestorePoints &SRP,
+      const DenseMap<MachineBasicBlock *, MachineBasicBlock *> &BBMap) {
+    SaveRestorePoints Pts{};
+    for (auto &Src : SRP) {
+      Pts.insert(std::make_pair(BBMap.find(Src.first)->second, Src.second));
+    }
+    return Pts;
+  }
+
+  void setRestorePoint(MachineBasicBlock *MBB, std::vector<Register> &Regs) {
+    if (RestorePoints.contains(MBB))
+      RestorePoints[MBB] = Regs;
+    else
+      RestorePoints.insert(std::make_pair(MBB, Regs));
+  }
+
+  MachineBasicBlock *getProlog() const { return Prolog; }
+  void setProlog(MachineBasicBlock *BB) { Prolog = BB; }
+  MachineBasicBlock *getEpilog() const { return Epilog; }
+  void setEpilog(MachineBasicBlock *BB) { Epilog = BB; }
+
   void clearSavePoints() { SavePoints.clear(); }
   void clearRestorePoints() { RestorePoints.clear(); }
 
diff --git a/llvm/lib/CodeGen/MIRParser/MIRParser.cpp b/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
index ea98a211a76b1..67a5fbe0665d0 100644
--- a/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
+++ b/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
@@ -1079,8 +1079,11 @@ bool MIRParserImpl::initializeConstantPool(PerFunctionMIParsingState &PFS,
 bool MIRParserImpl::initializeSaveRestorePoints(
     PerFunctionMIParsingState &PFS, const yaml::SaveRestorePoints &YamlSRPoints,
     bool IsSavePoints) {
+  SMDiagnostic Error;
   MachineBasicBlock *MBB = nullptr;
-  std::vector<MachineBasicBlock *> SaveRestorePoints;
+  llvm::SaveRestorePoints SRPoints;
+  std::vector<Register> Registers{};
+
   if (std::holds_alternative<std::vector<yaml::SaveRestorePointEntry>>(
           YamlSRPoints)) {
     const auto &VectorRepr =
@@ -1091,7 +1094,16 @@ bool MIRParserImpl::initializeSaveRestorePoints(
       const auto &MBBSource = Entry.Point;
       if (parseMBBReference(PFS, MBB, MBBSource.Value))
         return true;
-      SaveRestorePoints.push_back(MBB);
+
+      Registers.clear();
+      for (auto &RegStr : Entry.Registers) {
+        Register Reg;
+        if (parseNamedRegisterReference(PFS, Reg, RegStr.Value, Error))
+          return error(Error, RegStr.SourceRange);
+
+        Registers.push_back(Reg);
+      }
+      SRPoints.insert(std::make_pair(MBB, Registers));
     }
   } else {
     yaml::StringValue StringRepr = std::get<yaml::StringValue>(YamlSRPoints);
@@ -1099,17 +1111,16 @@ bool MIRParserImpl::initializeSaveRestorePoints(
       return false;
     if (parseMBBReference(PFS, MBB, StringRepr))
       return true;
-    SaveRestorePoints.push_back(MBB);
+    SRPoints.insert(std::make_pair(MBB, Registers));
   }
 
   MachineFunction &MF = PFS.MF;
   MachineFrameInfo &MFI = MF.getFrameInfo();
 
   if (IsSavePoints)
-    MFI.setSavePoints(SaveRestorePoints);
+    MFI.setSavePoints(SRPoints);
   else
-    MFI.setRestorePoints(SaveRestorePoints);
-
+    MFI.setRestorePoints(SRPoints);
   return false;
 }
 
diff --git a/llvm/lib/CodeGen/MIRPrinter.cpp b/llvm/lib/CodeGen/MIRPrinter.cpp
index 584d6c658e4dc..16788de5d01e3 100644
--- a/llvm/lib/CodeGen/MIRPrinter.cpp
+++ b/llvm/lib/CodeGen/MIRPrinter.cpp
@@ -117,9 +117,10 @@ class MIRPrinter {
                const MachineRegisterInfo &RegInfo,
                const TargetRegisterInfo *TRI);
   void convert(ModuleSlotTracker &MST, yaml::MachineFrameInfo &YamlMFI,
-               const MachineFrameInfo &MFI);
+               const MachineFrameInfo &MFI, const TargetRegisterInfo *TRI);
   void convert(ModuleSlotTracker &MST, yaml::SaveRestorePoints &YamlSRPoints,
-               std::vector<MachineBasicBlock *> SaveRestorePoints);
+               const DenseMap<MachineBasicBlock *, std::vector<Register>> &SRP,
+               const TargetRegisterInfo *TRI);
   void convert(yaml::MachineFunction &MF,
                const MachineConstantPool &ConstantPool);
   void convert(ModuleSlotTracker &MST, yaml::MachineJumpTable &YamlJTI,
@@ -240,7 +241,8 @@ void MIRPrinter::print(const MachineFunction &MF) {
   convert(YamlMF, MF, MF.getRegInfo(), MF.getSubtarget().getRegisterInfo());
   MachineModuleSlotTracker MST(MMI, &MF);
   MST.incorporateFunction(MF.getFunction());
-  convert(MST, YamlMF.FrameInfo, MF.getFrameInfo());
+  convert(MST, YamlMF.FrameInfo, MF.getFrameInfo(),
+          MF.getSubtarget().getRegisterInfo());
   convertStackObjects(YamlMF, MF, MST);
   convertEntryValueObjects(YamlMF, MF, MST);
   convertCallSiteObjects(YamlMF, MF, MST);
@@ -379,7 +381,8 @@ void MIRPrinter::convert(yaml::MachineFunction &YamlMF,
 
 void MIRPrinter::convert(ModuleSlotTracker &MST,
                          yaml::MachineFrameInfo &YamlMFI,
-                         const MachineFrameInfo &MFI) {
+                         const MachineFrameInfo &MFI,
+                         const TargetRegisterInfo *TRI) {
   YamlMFI.IsFrameAddressTaken = MFI.isFrameAddressTaken();
   YamlMFI.IsReturnAddressTaken = MFI.isReturnAddressTaken();
   YamlMFI.HasStackMap = MFI.hasStackMap();
@@ -400,9 +403,9 @@ void MIRPrinter::convert(ModuleSlotTracker &MST,
   YamlMFI.IsCalleeSavedInfoValid = MFI.isCalleeSavedInfoValid();
   YamlMFI.LocalFrameSize = MFI.getLocalFrameSize();
   if (!MFI.getSavePoints().empty())
-    convert(MST, YamlMFI.SavePoints, MFI.getSavePoints());
+    convert(MST, YamlMFI.SavePoints, MFI.getSavePoints(), TRI);
   if (!MFI.getRestorePoints().empty())
-    convert(MST, YamlMFI.RestorePoints, MFI.getRestorePoints());
+    convert(MST, YamlMFI.RestorePoints, MFI.getRestorePoints(), TRI);
 }
 
 void MIRPrinter::convertEntryValueObjects(yaml::MachineFunction &YMF,
@@ -646,16 +649,24 @@ void MIRPrinter::convert(yaml::MachineFunction &MF,
 
 void MIRPrinter::convert(ModuleSlotTracker &MST,
                          yaml::SaveRestorePoints &YamlSRPoints,
-                         std::vector<MachineBasicBlock *> SRPoints) {
+                         const SaveRestorePoints &SRPoints,
+                         const TargetRegisterInfo *TRI) {
   auto &Points =
       std::get<std::vector<yaml::SaveRestorePointEntry>>(YamlSRPoints);
-  for (const auto &MBB : SRPoints) {
+  for (const auto &MBBEntry : SRPoints) {
     SmallString<16> Str;
     yaml::SaveRestorePointEntry Entry;
     raw_svector_ostream StrOS(Str);
-    StrOS << printMBBReference(*MBB);
+    StrOS << printMBBReference(*MBBEntry.first);
     Entry.Point = StrOS.str().str();
     Str.clear();
+    for (auto &Reg : MBBEntry.second) {
+      if (Reg != MCRegister::NoRegister) {
+        StrOS << printReg(Reg, TRI);
+        Entry.Registers.push_back(StrOS.str());
+        Str.clear();
+      }
+    }
     Points.push_back(Entry);
   }
 }
diff --git a/llvm/lib/CodeGen/MachineFrameInfo.cpp b/llvm/lib/CodeGen/MachineFrameInfo.cpp
index a8306b2ef2e5b..c6658d2e9eba8 100644
--- a/llvm/lib/CodeGen/MachineFrameInfo.cpp
+++ b/llvm/lib/CodeGen/MachineFrameInfo.cpp
@@ -244,20 +244,21 @@ void MachineFrameInfo::print(const MachineFunction &MF, raw_ostream &OS) const{
     }
     OS << "\n";
   }
+
   OS << "save/restore points:\n";
 
   if (!SavePoints.empty()) {
     OS << "save points:\n";
 
     for (auto &item : SavePoints)
-      OS << printMBBReference(*item) << "\n";
+      OS << printMBBReference(*item.first) << "\n";
   } else
     OS << "save points are empty\n";
 
   if (!RestorePoints.empty()) {
     OS << "restore points:\n";
     for (auto &item : RestorePoints)
-      OS << printMBBReference(*item) << "\n";
+      OS << printMBBReference(*item.first) << "\n";
   } else
     OS << "restore points are empty\n";
 }
diff --git a/llvm/lib/CodeGen/PrologEpilogInserter.cpp b/llvm/lib/CodeGen/PrologEpilogInserter.cpp
index 0960be90fce2d..8f7aa11d229a5 100644
--- a/llvm/lib/CodeGen/PrologEpilogInserter.cpp
+++ b/llvm/lib/CodeGen/PrologEpilogInserter.cpp
@@ -99,8 +99,12 @@ class PEI : public MachineFunctionPass {
   unsigned MinCSFrameIndex = std::numeric_limits<unsigned>::max();
   unsigned MaxCSFrameIndex = 0;
 
-  // Save and Restore blocks of the current function. Typically there is a
-  // single save block, unless Windows EH funclets are involved.
+  // Prolog and Epilog blocks of the current function. Typically there is a
+  // single Prolog block, unless Windows EH funclets are involved.
+  MBBVector PrologBlocks;
+  MBBVector EpilogBlocks;
+
+  // Save and Restore blocks of the current function.
   MBBVector SaveBlocks;
   MBBVector RestoreBlocks;
 
@@ -118,6 +122,7 @@ class PEI : public MachineFunctionPass {
 
   void calculateCallFrameInfo(MachineFunction &MF);
   void calculateSaveRestoreBlocks(MachineFunction &MF);
+  void calculatePrologEpilogBlocks(MachineFunction &MF);
   void spillCalleeSavedRegs(MachineFunction &MF);
 
   void calculateFrameObjectOffsets(MachineFunction &MF);
@@ -234,14 +239,17 @@ bool PEI::runOnMachineFunction(MachineFunction &MF) {
   // information. Also eliminates call frame pseudo instructions.
   calculateCallFrameInfo(MF);
 
-  // Determine placement of CSR spill/restore code and prolog/epilog code:
+  // Determine placement of CSR spill/restore code:
   // place all spills in the entry block, all restores in return blocks.
   calculateSaveRestoreBlocks(MF);
 
+  // Determine placement of prolog/epilog code.
+  calculatePrologEpilogBlocks(MF);
+
   // Stash away DBG_VALUEs that should not be moved by insertion of prolog code.
   SavedDbgValuesMap EntryDbgValues;
-  for (MachineBasicBlock *SaveBlock : SaveBlocks)
-    stashEntryDbgValues(*SaveBlock, EntryDbgValues);
+  for (MachineBasicBlock *PrologBlock : PrologBlocks)
+    stashEntryDbgValues(*PrologBlock, EntryDbgValues);
 
   // Handle CSR spilling and restoring, for targets that need it.
   if (MF.getTarget().usesPhysRegsForValues())
@@ -349,6 +357,8 @@ bool PEI::runOnMachineFunction(MachineFunction &MF) {
   delete RS;
   SaveBlocks.clear();
   RestoreBlocks.clear();
+  PrologBlocks.clear();
+  EpilogBlocks.clear();
   MFI.clearSavePoints();
   MFI.clearRestorePoints();
   return true;
@@ -395,6 +405,25 @@ void PEI::calculateCallFrameInfo(MachineFunction &MF) {
   }
 }
 
+/// Compute two sets of blocks for placing prolog and epilog code respectively.
+void PEI::calculatePrologEpilogBlocks(MachineFunction &MF) {
+  const MachineFrameInfo &MFI = MF.getFrameInfo();
+  MachineBasicBlock *Prolog = MFI.getProlog();
+  MachineBasicBlock *Epilog = MFI.getEpilog();
+
+  if (Prolog)
+    PrologBlocks.push_back(Prolog);
+
+  if (Epilog)
+    EpilogBlocks.push_back(Epilog);
+
+  if (!Prolog && !SaveBlocks.empty())
+    PrologBlocks = SaveBlocks;
+
+  if (!Epilog && !RestoreBlocks.empty())
+    EpilogBlocks = RestoreBlocks;
+}
+
 /// Compute the sets of entry and return blocks for saving and restoring
 /// callee-saved registers, and placing prolog and epilog code.
 void PEI::calculateSaveRestoreBlocks(MachineFunction &MF) {
@@ -405,19 +434,19 @@ void PEI::calculateSaveRestoreBlocks(MachineFunction &MF) {
 
   // Use the points found by shrink-wrapping, if any.
   if (!MFI.getSavePoints().empty()) {
-    assert(MFI.getSavePoints().size() < 2 &&
-           "MFI can't contain multiple save points!");
-    SaveBlocks.push_back(MFI.getSavePoints().front());
     assert(!MFI.getRestorePoints().empty() &&
-           "Both restore and save must be set");
-    assert(MFI.getRestorePoints().size() < 2 &&
-           "MFI can't contain multiple restore points!");
-    MachineBasicBlock *RestoreBlock = MFI.getRestorePoints().front();
-    // If RestoreBlock does not have any successor and is not a return block
-    // then the end point is unreachable and we do not need to insert any
-    // epilogue.
-    if (!RestoreBlock->succ_empty() || RestoreBlock->isReturnBlock())
-      RestoreBlocks.push_back(RestoreBlock);
+           "Both restores and saves must be set");
+    for (auto &item : MFI.getSavePoints())
+      SaveBlocks.push_back(item.first);
+
+    for (auto &item : MFI.getRestorePoints()) {
+      MachineBasicBlock *RestoreBlock = item.first;
+      // If RestoreBlock does not have any successor and is not a return block
+      // then the end point is unreachable and we do not need to insert any
+      // epilogue.
+      if (!RestoreBlock->succ_empty() || RestoreBlock->isReturnBlock())
+        RestoreBlocks.push_back(RestoreBlock);
+    }
     return;
   }
 
@@ -528,8 +557,8 @@ static void assignCalleeSavedSpillSlots(MachineFunction &F,
 
 /// Helper function to update the liveness information for the callee-saved
 /// registers.
-static void updateLiveness(MachineFunction &MF) {
-  MachineFrameInfo &MFI = MF.getFrameInfo();
+static void updateLiveness(MachineFunction &MF, MachineBasicBlock *Save,
+                           MachineBasicBlock *Restore, CalleeSavedInfo &Info) {
   // Visited will contain all the basic blocks that are in the region
   // where the callee saved registers are alive:
   // - Anything that is not Save or Restore -> LiveThrough.
@@ -541,11 +570,6 @@ static void updateLiveness(MachineFunction &MF) {
   SmallVector<MachineBasicBlock *, 8> WorkList;
   MachineBasicBlock *Entry = &MF.front();
 
-  assert(MFI.getSavePoints().size() < 2 &&
-         "MFI can't contain multiple save points!");
-  MachineBasicBlock *Save =
-      MFI.getSavePoints().empty() ? nullptr : MFI.getSavePoints().front();
-
   if (!Save)
     Save = Entry;
 
@@ -555,10 +579,6 @@ static void updateLiveness(MachineFunction &MF) {
   }
   Visited.insert(Save);
 
-  assert(MFI.getRestorePoints().size() < 2 &&
-         "MFI can't contain multiple restore points!");
-  MachineBasicBlock *Restore =
-      MFI.getRestorePoints().empty() ? nullptr : MFI.getRestorePoints().front();
   if (Restore)
     // By construction Restore cannot be visited, otherwise it
     // means there exists a path to Restore that does not go
@@ -578,30 +598,27 @@ static void updateLiveness(MachineFunction &MF) {
         WorkList.push_back(SuccBB);
   }
 
-  const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
-
   MachineRegisterInfo &MRI = MF.getRegInfo();
-  for (const CalleeSavedInfo &I : CSI) {
-    for (MachineBasicBlock *MBB : Visited) {
-      MCPhysReg Reg = I.getReg();
-      // Add the callee-saved register as live-in.
-      // It's killed at the spill.
-      if (!MRI.isReserved(Reg) && !MBB->isLiveIn(Reg))
-        MBB->addLiveIn(Reg);
-    }
-    // If callee-saved register is spilled to another register rather than
-    // spilling to stack, the destination register has to be marked as live for
-    // each MBB between the prologue and epilogue so that it is not clobbered
-    // before it is reloaded in the epilogue. The Visited set contains all
-    // blocks outside of the region delimited by prologue/epilogue.
-    if (I.isSpilledToReg()) {
-      for (MachineBasicBlock &MBB : MF) {
-        if (Visited.count(&MBB))
-          continue;
-        MCPhysReg DstReg = I.getDstReg();
-        if (!MBB.isLiveIn(DstReg))
-          MBB.addLiveIn(DstReg);
-      }
+
+  for (MachineBasicBlock *MBB : Visited) {
+    MCPhysReg Reg = Info.getReg();
+    // Add the callee-saved register as live-in.
+    // It's killed at the spill.
+    if (!MRI.isReserved(Reg) && !MBB->isLiveIn(Reg))
+      MBB->addLiveIn(Reg);
+  }
+  // If callee-saved register is spilled to another register rather than
+  // spilling to stack, the destination register has to be marked as live for
+  // each MBB between the save and restore point so that it is not clobbered
+  // before it is reloaded in the restore point. The Visited set contains all
+  // blocks outside of the region delimited by save/restore.
+  if (Info.isSpilledToReg()) {
+    for (MachineBasicBlock &MBB : MF) {
+      if (Visited.count(&MBB))
+        continue;
+      MCPhysReg DstReg = Info.getDstReg();
+      if (!MBB.isLiveIn(DstReg))
+        MBB.addLiveIn(DstReg);
     }
   }
 }
@@ -664,6 +681,57 @@ static void insertCSRRestores(MachineBasicBlock &RestoreBlock,
   }
 }
 
+static void fillCSInfoPerBB(
+    SaveRestorePoints SRPoints,
+    DenseMap<Register, CalleeSavedInfo *> &RegToInfo,
+    DenseMap<MachineBasicBlock *, std::vector<CalleeSavedInfo>> &CSInfoPerBB,
+    bool isSave, MBBVector &PrologEpilogBlocks) {
+  std::vector<CalleeSavedInfo> CSIV = {};
+  std::vector<CalleeSavedInfo> GCSIV = {};
+  for (auto [BB, Regs] : SRPoints) {
+    CSIV.clear();
+    for (auto &Reg : Regs) {
+      auto It = RegToInfo.find(Reg);
+      if (It == RegToInfo.end())
+        continue;
+      CalleeSavedInfo *CSI = It->second;
+      if (isSave)
+        CSI->addSpilledIn(BB);
+      else
+        CSI->addRestoredIn(BB);
+      CSIV.push_back(*RegToInfo.at(Reg));
+      GCSIV.push_back(*RegToInfo.at(Reg));
+    }
+    std::sort(CSIV.begin(), CSIV.end(),
+              [](const CalleeSavedInfo &Lhs, const CalleeSavedInfo &Rhs) {
+                return Lhs.getFrameIdx() < Rhs.getFrameIdx();
+              });
+    CSInfoPerBB.insert(std::make_pair(BB, CSIV));
+  }
+
+  if (GCSIV.size() >= RegToInfo.size())
+    return;
+
+  for (auto &RTI : RegToInfo) {
+    if (find_if(GCSIV, [&RTI](const CalleeSavedInfo &CSI) {
+          return CSI.getReg() == RTI.first;
+        }) != std::end(GCSIV))
+      continue;
+    for (auto BB : PrologEpilogBlocks) {
+      if (CSInfoPerBB.contains(BB)) {
+        CSInfoPerBB[BB].push_back(*RTI.second);
+        std::sort(CSInfoPerBB[BB].begin(), CSInfoPerBB[BB].end(),
+                  [](const CalleeSavedInfo &Lhs, const CalleeSavedInfo &Rhs) {
+                    return Lhs.getFrameIdx() < Rhs.getFrameIdx();
+                  });
+      }
+      CSIV.clear();
+      CSIV.push_back(*RTI.second);
+      CSInfoPerBB.insert(std::make_pair(BB, CSIV));
+    }
+  }
+}
+
 void PEI::spillCalleeSavedRegs(MachineFunction &MF) {
   // We can't list this requirement in getRequiredProperties because some
   // targets (WebAssembly) use virtual registers past this point, and the pass
@@ -691,19 +759,79 @@ void PEI::spillCalleeSavedRegs(MachineFunction &MF) {
     MFI.setCalleeSavedInfoValid(true);
 
     std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
+    DenseMap<Register, CalleeSavedInfo *> RegToInfo;
+    for (auto &CS : CSI) {
+      RegToInfo.insert(std::make_pair(CS.getReg(), &CS));
+    }
+
+    DenseMap<MachineBasicBlock *, std::vector<CalleeSavedInfo>> CSInfoPerSave{};
+    DenseMap<MachineBasicBlock *, std::vector<CalleeSavedInfo>>
+        CSInfoPerRestore{};
+    if (!MFI.getSavePoints().empty()) {
+      fillCSInfoPerBB(MFI.getSavePoints(), RegToInfo, CSInfoPerSave,
+                      true /* isSave */, PrologBlocks);
+      fillCSInfoPerBB(MFI.getRestorePoints(), RegToInfo, CSInfoPerRestore,
+                      false /* isSave */, EpilogBlocks);
+    } else {
+      for (MachineBasicBlock *PrologBlock : PrologBlocks) {
+        CSInfoPerSave.insert(
+            std::make_pair(PrologBlock, MFI.getCalleeSavedInfo()));
+
+        for (auto &CS : CSI) {
+          CS.addSpilledIn(PrologBlock);
+        }
+      }
+    }
+
     if (!CSI.empty()) {
       if (!MFI.hasCalls())
         NumLeafFuncWithSpills++;
 
       for (MachineBasicBlock *SaveBlock : SaveBlocks)
-        insertCSRSaves(*SaveBlock, CSI);
+        insertCSRSaves(*SaveBlock,
+                       CSInfoPerSave.empty() ? CSI : CSInfoPerSave[SaveBlock]);
+
+      MachineBasicBlock *Save = nullptr;
+      MachineBasicBlock *Restore = nullptr;
+      for (auto &CS : CSI) {
+        if (!MFI.getSavePoints().empty()) {
+          auto &SavePoints = MFI.getSavePoints();
+          auto &RestorePoints = MFI.getRestorePoints();
+          auto CSRegFound =
+              [CS](const std::pair<MachineBasicBlock *, std::vector<Register>>
+                       &Point) { return count(Point.second, CS.getReg()); };
+
+          if (auto PointIt = find_if(SavePoints, CSRegFound);
+              PointIt != std::end(SavePoints))
+            Save = PointIt->first;
+
+          if (auto PointIt = find_if(RestorePoints, CSRegFound);
+              PointIt != std::end(RestorePoints))
+            Restore = PointIt->first;
+        }
+        // Update the live-in information of all the blocks up to the save
+        // point.
+        updateLiveness(MF, Save, Restore, CS);
+      }
 
-      // Update the live-in information of all the blocks up to the save point.
-      updateLiveness(MF);
+      if (MFI.getRestorePoints().empty()) {
+        for (MachineBasicBlock *EpilogBlock : EpilogBlocks) {
+          CSInfoPerRestore.insert(
+              std::make_pair(EpilogBlock, MFI.getCalleeSavedInfo()));
+
+          for (auto &CS : CSI)
+            CS.addRestoredIn(EpilogBlock);
+        }
+      }
 
       for (MachineBasicBlock *RestoreBlock : RestoreBlocks)
-        insertCSRRestores(*RestoreBlock, CSI);
+        insertCSRRestores(*RestoreBlock, CSInfoPerRestore.empty()
+                                             ? CSI
+                                             : CSInfoPerRestore[RestoreBlock]);
     }
+
+    MFI.setCSInfoPerSave(CSInfoPerSave);
+    MFI.setCSInfoPerRestore(CSInfoPerRestore);
   }
 }
 
@@ -1175,26 +1303,26 @@ void PEI::insertPrologEpilogCode(MachineFunction &MF) {
   const TargetFrameLowering &TFI = *MF.getSubtarget().getFrameLowering();
 
   // Add prologue to the function...
-  for (MachineBasicBlock *SaveBlock : SaveBlocks)
-    TFI.emitPrologue(MF, *SaveBlock);
+  for (MachineBasicBlock *PrologBlock : PrologBlocks)
+    TFI.emitPrologue(MF, *PrologBlock);
 
   // Add epilogue to restore the callee-save registers in each exiting block.
-  for (MachineBasicBlock *RestoreBlock : RestoreBlocks)
-    TFI.emitEpilogue(MF, *RestoreBlock);
+  for (MachineBasicBlock *EpilogBlock : EpilogBlocks)
+    TFI.emitEpilogue(MF, *EpilogBlock);
 
   // Zero call used registers before restoring callee-saved registers.
   insertZeroCallUsedRegs(MF);
 
-  for (MachineBasicBlock *SaveBlock : SaveBlocks)
-    TFI.inlineStackProbe(MF, *SaveBlock);
+  for (MachineBasicBlock *PrologBlock : PrologBlocks)
+    TFI.inlineStackProbe(MF, *PrologBlock);
 
   // Emit additional code that is required to support segmented stacks, if
   // we've been asked for it.  This, when linked with a runtime with support
   // for segmented stacks (libgcc is one), will result in allocating stack
   // space in small chunks instead of one large contiguous block.
   if (MF.shouldSplitStack()) {
-    for (MachineBasicBlock *SaveBlock : SaveBlocks)
-      TFI.adjustForSegmentedStacks(MF, *SaveBlock);
+    for (MachineBasicBlock *PrologBlock : PrologBlocks)
+      TFI.adjustForSegmentedStacks(MF, *PrologBlock);
   }
 
   // Emit additional code that is required to explicitly handle the stack in
@@ -1203,8 +1331,8 @@ void PEI::insertPrologEpilogCode(MachineFunction &MF) {
   // different conditional check and another BIF for allocating more stack
   // space.
   if (MF.getFunction().getCallingConv() == CallingConv::HiPE)
-    for (MachineBasicBlock *SaveBlock : SaveBlocks)
-      TFI.adjustForHiPEPrologue(MF, *SaveBlock);
+    for (MachineBasicBlock *PrologBlock : PrologBlocks)
+      TFI.adjustForHiPEPrologue(MF, *PrologBlock);
 }
 
 /// insertZeroCallUsedRegs - Zero out call used registers.
diff --git a/llvm/lib/CodeGen/ShrinkWrap.cpp b/llvm/lib/CodeGen/ShrinkWrap.cpp
index 604c26c2db90c..b1ac54fddbcc1 100644
--- a/llvm/lib/CodeGen/ShrinkWrap.cpp
+++ b/llvm/lib/CodeGen/ShrinkWrap.cpp
@@ -959,12 +959,15 @@ bool ShrinkWrap::runOnMachineFunction(MachineFunction &MF) {
                     << "\nRestore: " << printMBBReference(*Restore) << '\n');
 
   MachineFrameInfo &MFI = MF.getFrameInfo();
-  std::vector<MachineBasicBlock *> SavePoints;
-  std::vector<MachineBasicBlock *> RestorePoints;
-  if (Save) {
-    SavePoints.push_back(Save);
-    RestorePoints.push_back(Restore);
-  }
+
+  std::vector<Register> CSRVec;
+  SetOfRegs CSRSet = getCurrentCSRs(RS.get());
+  for (unsigned Reg : CSRSet)
+    CSRVec.push_back(Reg);
+
+  llvm::SaveRestorePoints SavePoints({{Save, CSRVec}});
+  llvm::SaveRestorePoints RestorePoints({{Restore, CSRVec}});
+
   MFI.setSavePoints(SavePoints);
   MFI.setRestorePoints(RestorePoints);
   ++NumCandidates;
diff --git a/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp b/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp
index e76fb58b3be25..729b4b7093eef 100644
--- a/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp
+++ b/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp
@@ -194,29 +194,31 @@ void SILowerSGPRSpills::calculateSaveRestoreBlocks(MachineFunction &MF) {
 
   // Use the points found by shrink-wrapping, if any.
   if (!MFI.getSavePoints().empty()) {
-    assert(MFI.getSavePoints().size() < 2 &&
-           "MFI can't contain multiple save points!");
-    SaveBlocks.push_back(MFI.getSavePoints().front());
     assert(!MFI.getRestorePoints().empty() &&
-           "Both restore and save must be set");
-    assert(MFI.getRestorePoints().size() < 2 &&
-           "MFI can't contain multiple restore points!");
-    MachineBasicBlock *RestoreBlock = MFI.getRestorePoints().front();
-    // If RestoreBlock does not have any successor and is not a return block
-    // then the end point is unreachable and we do not need to insert any
-    // epilogue.
-    if (!RestoreBlock->succ_empty() || RestoreBlock->isReturnBlock())
-      RestoreBlocks.push_back(RestoreBlock);
+           "Both restores and saves must be set");
+    for (auto &item : MFI.getSavePoints())
+      SaveBlocks.push_back(item.first);
+
+    for (auto &item : MFI.getRestorePoints()) {
+      MachineBasicBlock *RestoreBlock = item.first;
+      // If RestoreBlock does not have any successor and is not a return block
+      // then the end point is unreachable and we do not need to insert any
+      // epilogue.
+      if (!RestoreBlock->succ_empty() || RestoreBlock->isReturnBlock())
+        RestoreBlocks.push_back(RestoreBlock);
+    }
     return;
   }
 
-  // Save refs to entry and return blocks.
-  SaveBlocks.push_back(&MF.front());
-  for (MachineBasicBlock &MBB : MF) {
-    if (MBB.isEHFuncletEntry())
-      SaveBlocks.push_back(&MBB);
-    if (MBB.isReturnBlock())
-      RestoreBlocks.push_back(&MBB);
+  if (MFI.getSavePoints().empty()) {
+    // Save refs to entry and return blocks.
+    SaveBlocks.push_back(&MF.front());
+    for (MachineBasicBlock &MBB : MF) {
+      if (MBB.isEHFuncletEntry())
+        SaveBlocks.push_back(&MBB);
+      if (MBB.isReturnBlock())
+        RestoreBlocks.push_back(&MBB);
+    }
   }
 }
 
diff --git a/llvm/lib/Target/PowerPC/PPCFrameLowering.cpp b/llvm/lib/Target/PowerPC/PPCFrameLowering.cpp
index b3bcc6448c162..ade1b0dfb86a8 100644
--- a/llvm/lib/Target/PowerPC/PPCFrameLowering.cpp
+++ b/llvm/lib/Target/PowerPC/PPCFrameLowering.cpp
@@ -2079,11 +2079,8 @@ void PPCFrameLowering::processFunctionBeforeFrameFinalized(MachineFunction &MF,
   // won't be generated by emitEpilogue(), because shrink-wrap has chosen new
   // RestoreBlock. So we handle this case here.
   if (!MFI.getSavePoints().empty() && MFI.hasTailCall()) {
-    assert(MFI.getRestorePoints().size() < 2 &&
-           "MFI can't contain multiple restore points!");
-    MachineBasicBlock *RestoreBlock = MFI.getRestorePoints().front();
     for (MachineBasicBlock &MBB : MF) {
-      if (MBB.isReturnBlock() && (&MBB) != RestoreBlock)
+      if (MBB.isReturnBlock() && (!MFI.getRestorePoint(&MBB).first))
         createTailCallBranchInstr(MBB);
     }
   }
diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
index bb2e5781c34db..58b74c94090ea 100644
--- a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
@@ -30,6 +30,33 @@ using namespace llvm;
 
 namespace {
 
+static int64_t calculateCSRSpillOffsets(MachineFrameInfo &MFI,
+                                        const TargetFrameLowering *TFI,
+                                        int MinCSFI, int FrameIdx) {
+  int LocalAreaOffset = -TFI->getOffsetOfLocalArea();
+  Align MaxAlign = MFI.getMaxAlign();
+  Align Alignment = MFI.getObjectAlign(FrameIdx);
+  MaxAlign = std::max(MaxAlign, Alignment);
+  int64_t Offset = LocalAreaOffset;
+
+  for (int i = MFI.getObjectIndexBegin(); i != 0; ++i) {
+    // Only allocate objects on the default stack.
+    if (MFI.getStackID(i) != TargetStackID::Default)
+      continue;
+
+    int64_t FixedOff;
+    FixedOff = -MFI.getObjectOffset(i);
+    if (FixedOff > Offset)
+      Offset = FixedOff;
+  }
+
+  for (int i = MinCSFI; i <= FrameIdx; ++i)
+    Offset += MFI.getObjectSize(i);
+
+  Offset = alignTo(Offset, Alignment);
+  return -Offset;
+}
+
 class CFISaveRegisterEmitter {
   MachineFunction &MF;
   MachineFrameInfo &MFI;
@@ -42,7 +69,25 @@ class CFISaveRegisterEmitter {
             const RISCVRegisterInfo &RI, const RISCVInstrInfo &TII,
             const DebugLoc &DL, const CalleeSavedInfo &CS) const {
     int FrameIdx = CS.getFrameIdx();
-    int64_t Offset = MFI.getObjectOffset(FrameIdx);
+    if (FrameIdx >= 0 &&
+        MFI.getStackID(FrameIdx) == TargetStackID::ScalableVector)
+      return;
+
+    int64_t Offset = 0;
+
+    MachineFrameInfo &MFI = MF.getFrameInfo();
+    auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>();
+    std::vector<CalleeSavedInfo> GCSI = MFI.getCalleeSavedInfo();
+
+    if (FrameIdx < 0 &&
+        (RVFI->isPushable(MF) || RVFI->useSaveRestoreLibCalls(MF)))
+      Offset = MFI.getObjectOffset(FrameIdx);
+    else {
+      const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering();
+      Offset = calculateCSRSpillOffsets(
+          MFI, TFI, std::max(GCSI[0].getFrameIdx(), 0), FrameIdx);
+    }
+
     Register Reg = CS.getReg();
     unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
         nullptr, RI.getDwarfRegNum(Reg, true), Offset));
@@ -450,9 +495,8 @@ uint64_t RISCVFrameLowering::getStackSizeWithRVVPadding(
   return alignTo(MFI.getStackSize() + RVFI->getRVVPadding(), getStackAlign());
 }
 
-static SmallVector<CalleeSavedInfo, 8>
-getUnmanagedCSI(const MachineFunction &MF,
-                const std::vector<CalleeSavedInfo> &CSI) {
+SmallVector<CalleeSavedInfo, 8> RISCVFrameLowering::getUnmanagedCSI(
+    const MachineFunction &MF, const std::vector<CalleeSavedInfo> &CSI) const {
   const MachineFrameInfo &MFI = MF.getFrameInfo();
   SmallVector<CalleeSavedInfo, 8> NonLibcallCSI;
 
@@ -811,13 +855,13 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
   auto FirstFrameSetup = MBBI;
 
   // Skip past all callee-saved register spill instructions.
-  while (MBBI != MBB.end() && MBBI->getFlag(MachineInstr::FrameSetup))
+  while (MBBI != MBB.end() && MBBI->getFlag(MachineInstr::FrameSetup) && !MBBI->isCFIInstruction())
     ++MBBI;
 
   // Determine the correct frame layout
   determineFrameLayout(MF);
 
-  const auto &CSI = MFI.getCalleeSavedInfo();
+  const auto &CSI = MFI.getCSInfoPerSave(&MBB);
 
   // Skip to before the spills of scalar callee-saved registers
   // FIXME: assumes exactly one instruction is used to restore each
@@ -922,11 +966,10 @@ 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).size());
-
-  // Iterate over list of callee-saved registers and emit .cfi_offset
-  // directives.
-  emitCFIForCSI<CFISaveRegisterEmitter>(MBB, MBBI, getUnmanagedCSI(MF, CSI));
+  int Distance = getUnmanagedCSI(MF, CSI).size();
+  if (!RVFI->isPushable(MF) && !RVFI->useSaveRestoreLibCalls(MF))
+    Distance *= 2;
+  std::advance(MBBI, Distance);
 
   // Generate new FP.
   if (hasFP(MF)) {
@@ -1087,13 +1130,16 @@ void RISCVFrameLowering::emitEpilogue(MachineFunction &MF,
       --MBBI;
   }
 
-  const auto &CSI = MFI.getCalleeSavedInfo();
+  const auto &CSI = MFI.getCSInfoPerRestore(&MBB);
 
   // Skip to before the restores of scalar callee-saved registers
   // FIXME: assumes exactly one instruction is used to restore each
   // callee-saved register.
   auto FirstScalarCSRRestoreInsn =
       std::next(MBBI, getRVVCalleeSavedInfo(MF, CSI).size());
+  int Distance = getUnmanagedCSI(MF, CSI).size();
+  auto LastFrameDestroy = std::prev(MBBI, Distance);
+  std::advance(MBBI, Distance);
 
   uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF);
   uint64_t RealStackSize = FirstSPAdjustAmount ? FirstSPAdjustAmount
@@ -1193,9 +1239,6 @@ void RISCVFrameLowering::emitEpilogue(MachineFunction &MF,
     return;
   }
 
-  // Recover callee-saved registers.
-  emitCFIForCSI<CFIRestoreRegisterEmitter>(MBB, MBBI, getUnmanagedCSI(MF, CSI));
-
   bool ApplyPop = RVFI->isPushable(MF) && MBBI != MBB.end() &&
                   MBBI->getOpcode() == RISCV::CM_POP;
   if (ApplyPop) {
@@ -1867,13 +1910,13 @@ bool RISCVFrameLowering::spillCalleeSavedRegisters(
     return true;
 
   MachineFunction *MF = MBB.getParent();
+  auto *RVFI = MF->getInfo<RISCVMachineFunctionInfo>();
   const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo();
   DebugLoc DL;
   if (MI != MBB.end() && !MI->isDebugInstr())
     DL = MI->getDebugLoc();
 
   // Emit CM.PUSH with base SPimm & evaluate Push stack
-  RISCVMachineFunctionInfo *RVFI = MF->getInfo<RISCVMachineFunctionInfo>();
   if (RVFI->isPushable(*MF)) {
     unsigned PushedRegNum = RVFI->getRVPushRegs();
     if (PushedRegNum > 0) {
@@ -1913,8 +1956,13 @@ bool RISCVFrameLowering::spillCalleeSavedRegisters(
                               MachineInstr::FrameSetup);
     }
   };
-  storeRegsToStackSlots(UnmanagedCSI);
-  storeRegsToStackSlots(RVVCSI);
+  storeRegToStackSlot(UnmanagedCSI);
+
+  // Iterate over list of callee-saved registers and emit .cfi_offset
+  // directives.
+  emitCFIForCSI<CFISaveRegisterEmitter>(MBB, MI, UnmanagedCSI);
+
+  storeRegToStackSlot(RVVCSI);
 
   return true;
 }
@@ -2029,6 +2077,9 @@ bool RISCVFrameLowering::restoreCalleeSavedRegisters(
   loadRegFromStackSlot(RVVCSI);
   loadRegFromStackSlot(UnmanagedCSI);
 
+  // Recover callee-saved registers.
+  emitCFIForCSI<CFIRestoreRegisterEmitter>(MBB, MI, UnmanagedCSI);
+
   RISCVMachineFunctionInfo *RVFI = MF->getInfo<RISCVMachineFunctionInfo>();
   if (RVFI->isPushable(*MF)) {
     int RegEnc = RVFI->getRVPushRlist();
diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.h b/llvm/lib/Target/RISCV/RISCVFrameLowering.h
index d013755ce58a0..e618fe1615e1e 100644
--- a/llvm/lib/Target/RISCV/RISCVFrameLowering.h
+++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.h
@@ -28,6 +28,10 @@ class RISCVFrameLowering : public TargetFrameLowering {
 
   uint64_t getStackSizeWithRVVPadding(const MachineFunction &MF) const;
 
+  SmallVector<CalleeSavedInfo, 8>
+  getUnmanagedCSI(const MachineFunction &MF,
+                  const std::vector<CalleeSavedInfo> &CSI) const;
+
   StackOffset getFrameIndexReference(const MachineFunction &MF, int FI,
                                      Register &FrameReg) const override;
 
diff --git a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
index 7a99bfd1b2512..1091f2a29f0f9 100644
--- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
@@ -478,12 +478,59 @@ bool RISCVRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
   MachineInstr &MI = *II;
   MachineFunction &MF = *MI.getParent()->getParent();
   MachineRegisterInfo &MRI = MF.getRegInfo();
+  const MachineFrameInfo &MFI = MF.getFrameInfo();
   DebugLoc DL = MI.getDebugLoc();
 
   int FrameIndex = MI.getOperand(FIOperandNum).getIndex();
   Register FrameReg;
   StackOffset Offset =
       getFrameLowering(MF)->getFrameIndexReference(MF, FrameIndex, FrameReg);
+
+  const auto &CSI =
+      getFrameLowering(MF)->getUnmanagedCSI(MF, MFI.getCalleeSavedInfo());
+
+  if (!CSI.empty()) {
+    int MinCSFI = CSI.front().getFrameIdx();
+    int MaxCSFI = CSI.back().getFrameIdx();
+
+    // If our FrameIndex is CSI FrameIndex we in some cases need additional
+    // adjustment
+    if (FrameIndex >= MinCSFI && FrameIndex <= MaxCSFI) {
+      MachineBasicBlock *SpilledIn = nullptr;
+      MachineBasicBlock *RestoredIn = nullptr;
+      auto It = std::find_if(CSI.begin(), CSI.end(), [FrameIndex](auto &CS) {
+        return CS.getFrameIdx() == FrameIndex;
+      });
+
+      if (It != CSI.end()) {
+        if (MI.mayStore() && !It->spilledIn().empty())
+          SpilledIn = *It->spilledIn().begin();
+
+        else if (MI.mayLoad() && !It->restoredIn().empty())
+          RestoredIn = *It->restoredIn().begin();
+      }
+      bool SpilledRestoredInPrologEpilog = true;
+      if (MI.mayStore() && !MFI.getSavePoints().empty() && SpilledIn) {
+        SpilledRestoredInPrologEpilog =
+            MFI.getSavePoint(SpilledIn).first == MFI.getProlog();
+      } else if (MI.mayLoad() && !MFI.getRestorePoints().empty() &&
+                 RestoredIn) {
+        SpilledRestoredInPrologEpilog =
+            MFI.getRestorePoint(RestoredIn).first == MFI.getEpilog();
+      }
+
+      // For spills/restores performed not in Prolog/Epilog we need to add full
+      // SP offset, despite SPAdjusment optimization, because at the end of
+      // Prolog or at the start of Epilog SP has maximum offset
+      uint64_t FirstSPAdjustAmount =
+          getFrameLowering(MF)->getFirstSPAdjustAmount(MF);
+      if (FirstSPAdjustAmount && !SpilledRestoredInPrologEpilog)
+        Offset += StackOffset::getFixed(
+            getFrameLowering(MF)->getStackSizeWithRVVPadding(MF) -
+            FirstSPAdjustAmount);
+    }
+  }
+
   bool IsRVVSpill = RISCV::isRVVSpill(MI);
   if (!IsRVVSpill)
     Offset += StackOffset::getFixed(MI.getOperand(FIOperandNum + 1).getImm());
diff --git a/llvm/test/CodeGen/AArch64/live-debugvalues-sve.mir b/llvm/test/CodeGen/AArch64/live-debugvalues-sve.mir
index 612453ab53f43..89f4e8eb161ce 100644
--- a/llvm/test/CodeGen/AArch64/live-debugvalues-sve.mir
+++ b/llvm/test/CodeGen/AArch64/live-debugvalues-sve.mir
@@ -120,8 +120,18 @@ frameInfo:
   adjustsStack:    true
   hasCalls:        true
   maxCallFrameSize: 0
-  savePoint:       '%bb.1'
-  restorePoint:    '%bb.1'
+  savePoint:
+    - point:           '%bb.1'
+      registers:
+        - '$fp'
+        - '$lr'
+        - '$x28'
+  restorePoint:
+    - point:           '%bb.1'
+      registers:
+        - '$fp'
+        - '$lr'
+        - '$x28'
 stack:
   - { id: 0, size: 16, alignment: 16, stack-id: scalable-vector }
 machineFunctionInfo: {}
diff --git a/llvm/test/CodeGen/MIR/X86/frame-info-save-restore-points.mir b/llvm/test/CodeGen/MIR/X86/frame-info-save-restore-points.mir
index bd2d45046123a..2bd5cd853210b 100644
--- a/llvm/test/CodeGen/MIR/X86/frame-info-save-restore-points.mir
+++ b/llvm/test/CodeGen/MIR/X86/frame-info-save-restore-points.mir
@@ -32,14 +32,20 @@ liveins:
 # CHECK: frameInfo:
 # CHECK:      savePoint:
 # CHECK-NEXT:   - point:           '%bb.2'
+# CHECK-NEXT:     registers:       []
 # CHECK:      restorePoint:
 # CHECK-NEXT:   - point:           '%bb.2'
+# CHECK-NEXT:     registers:       []
 # CHECK: stack
 frameInfo:
   maxAlignment:  4
   hasCalls:      true
-  savePoint:     '%bb.2'
-  restorePoint:  '%bb.2'
+  savePoint:
+    - point:           '%bb.2'
+      registers:       []
+  restorePoint:
+    - point:           '%bb.2'
+      registers:       []
 stack:
   - { id: 0, name: tmp, offset: 0, size: 4, alignment: 4 }
 body: |
diff --git a/llvm/test/CodeGen/PowerPC/common-chain-aix32.ll b/llvm/test/CodeGen/PowerPC/common-chain-aix32.ll
index 35ddcfd9ba6d6..a61d669b014b5 100644
--- a/llvm/test/CodeGen/PowerPC/common-chain-aix32.ll
+++ b/llvm/test/CodeGen/PowerPC/common-chain-aix32.ll
@@ -49,9 +49,9 @@ define i64 @two_chain_same_offset_succ_i32(ptr %p, i32 %offset, i32 %base1, i64
 ; CHECK-NEXT:    slwi r8, r4, 1
 ; CHECK-NEXT:    li r10, 0
 ; CHECK-NEXT:    li r11, 0
-; CHECK-NEXT:    stw r30, -8(r1) # 4-byte Folded Spill
-; CHECK-NEXT:    add r8, r4, r8
 ; CHECK-NEXT:    stw r31, -4(r1) # 4-byte Folded Spill
+; CHECK-NEXT:    add r8, r4, r8
+; CHECK-NEXT:    stw r30, -8(r1) # 4-byte Folded Spill
 ; CHECK-NEXT:    add r9, r5, r8
 ; CHECK-NEXT:    add r5, r5, r4
 ; CHECK-NEXT:    add r8, r3, r5
@@ -84,8 +84,8 @@ define i64 @two_chain_same_offset_succ_i32(ptr %p, i32 %offset, i32 %base1, i64
 ; CHECK-NEXT:    crand 4*cr5+lt, eq, 4*cr1+lt
 ; CHECK-NEXT:    bc 12, 4*cr5+lt, L..BB0_3
 ; CHECK-NEXT:  # %bb.5:
-; CHECK-NEXT:    lwz r31, -4(r1) # 4-byte Folded Reload
 ; CHECK-NEXT:    lwz r30, -8(r1) # 4-byte Folded Reload
+; CHECK-NEXT:    lwz r31, -4(r1) # 4-byte Folded Reload
 ; CHECK-NEXT:    mr r4, r5
 ; CHECK-NEXT:    blr
 ; CHECK-NEXT:  L..BB0_6:
diff --git a/llvm/test/CodeGen/PowerPC/common-chain.ll b/llvm/test/CodeGen/PowerPC/common-chain.ll
index b71a360d1be12..bc6401d84cf25 100644
--- a/llvm/test/CodeGen/PowerPC/common-chain.ll
+++ b/llvm/test/CodeGen/PowerPC/common-chain.ll
@@ -426,11 +426,11 @@ define i64 @not_same_offset_fail(ptr %p, i64 %offset, i64 %base1, i64 %n) {
 ; CHECK-NEXT:    cmpdi r6, 0
 ; CHECK-NEXT:    ble cr0, .LBB4_4
 ; CHECK-NEXT:  # %bb.1: # %for.body.preheader
-; CHECK-NEXT:    std r28, -32(r1) # 8-byte Folded Spill
+; CHECK-NEXT:    std r30, -16(r1) # 8-byte Folded Spill
 ; CHECK-NEXT:    std r29, -24(r1) # 8-byte Folded Spill
 ; CHECK-NEXT:    add r5, r3, r5
 ; CHECK-NEXT:    li r3, 0
-; CHECK-NEXT:    std r30, -16(r1) # 8-byte Folded Spill
+; CHECK-NEXT:    std r28, -32(r1) # 8-byte Folded Spill
 ; CHECK-NEXT:    mtctr r6
 ; CHECK-NEXT:    mulli r11, r4, 10
 ; CHECK-NEXT:    sldi r8, r4, 2
@@ -455,9 +455,9 @@ define i64 @not_same_offset_fail(ptr %p, i64 %offset, i64 %base1, i64 %n) {
 ; CHECK-NEXT:    maddld r3, r6, r28, r3
 ; CHECK-NEXT:    bdnz .LBB4_2
 ; CHECK-NEXT:  # %bb.3:
-; CHECK-NEXT:    ld r30, -16(r1) # 8-byte Folded Reload
-; CHECK-NEXT:    ld r29, -24(r1) # 8-byte Folded Reload
 ; CHECK-NEXT:    ld r28, -32(r1) # 8-byte Folded Reload
+; CHECK-NEXT:    ld r29, -24(r1) # 8-byte Folded Reload
+; CHECK-NEXT:    ld r30, -16(r1) # 8-byte Folded Reload
 ; CHECK-NEXT:    blr
 ; CHECK-NEXT:  .LBB4_4:
 ; CHECK-NEXT:    li r3, 0
diff --git a/llvm/test/CodeGen/PowerPC/loop-instr-form-prepare.ll b/llvm/test/CodeGen/PowerPC/loop-instr-form-prepare.ll
index cc38e250f183f..00627b8434beb 100644
--- a/llvm/test/CodeGen/PowerPC/loop-instr-form-prepare.ll
+++ b/llvm/test/CodeGen/PowerPC/loop-instr-form-prepare.ll
@@ -189,8 +189,8 @@ define i64 @test_max_number_reminder(ptr %arg, i32 signext %arg1) {
 ; CHECK-NEXT:    cmplwi r4, 0
 ; CHECK-NEXT:    beq cr0, .LBB2_4
 ; CHECK-NEXT:  # %bb.1: # %bb3.preheader
-; CHECK-NEXT:    std r25, -56(r1) # 8-byte Folded Spill
-; CHECK-NEXT:    std r26, -48(r1) # 8-byte Folded Spill
+; CHECK-NEXT:    std r30, -16(r1) # 8-byte Folded Spill
+; CHECK-NEXT:    std r29, -24(r1) # 8-byte Folded Spill
 ; CHECK-NEXT:    addi r10, r3, 4002
 ; CHECK-NEXT:    li r3, 0
 ; CHECK-NEXT:    li r5, -1
@@ -198,10 +198,10 @@ define i64 @test_max_number_reminder(ptr %arg, i32 signext %arg1) {
 ; CHECK-NEXT:    li r7, 3
 ; CHECK-NEXT:    li r8, 5
 ; CHECK-NEXT:    li r9, 9
-; CHECK-NEXT:    std r27, -40(r1) # 8-byte Folded Spill
 ; CHECK-NEXT:    std r28, -32(r1) # 8-byte Folded Spill
-; CHECK-NEXT:    std r29, -24(r1) # 8-byte Folded Spill
-; CHECK-NEXT:    std r30, -16(r1) # 8-byte Folded Spill
+; CHECK-NEXT:    std r27, -40(r1) # 8-byte Folded Spill
+; CHECK-NEXT:    std r26, -48(r1) # 8-byte Folded Spill
+; CHECK-NEXT:    std r25, -56(r1) # 8-byte Folded Spill
 ; CHECK-NEXT:    mtctr r4
 ; CHECK-NEXT:    .p2align 4
 ; CHECK-NEXT:  .LBB2_2: # %bb3
@@ -226,13 +226,13 @@ define i64 @test_max_number_reminder(ptr %arg, i32 signext %arg1) {
 ; CHECK-NEXT:    maddld r3, r11, r25, r3
 ; CHECK-NEXT:    bdnz .LBB2_2
 ; CHECK-NEXT:  # %bb.3:
-; CHECK-NEXT:    ld r30, -16(r1) # 8-byte Folded Reload
-; CHECK-NEXT:    ld r29, -24(r1) # 8-byte Folded Reload
-; CHECK-NEXT:    ld r28, -32(r1) # 8-byte Folded Reload
+; CHECK-NEXT:    ld r25, -56(r1) # 8-byte Folded Reload
+; CHECK-NEXT:    ld r26, -48(r1) # 8-byte Folded Reload
 ; CHECK-NEXT:    ld r27, -40(r1) # 8-byte Folded Reload
+; CHECK-NEXT:    ld r28, -32(r1) # 8-byte Folded Reload
 ; CHECK-NEXT:    add r3, r3, r4
-; CHECK-NEXT:    ld r26, -48(r1) # 8-byte Folded Reload
-; CHECK-NEXT:    ld r25, -56(r1) # 8-byte Folded Reload
+; CHECK-NEXT:    ld r29, -24(r1) # 8-byte Folded Reload
+; CHECK-NEXT:    ld r30, -16(r1) # 8-byte Folded Reload
 ; CHECK-NEXT:    blr
 ; CHECK-NEXT:  .LBB2_4:
 ; CHECK-NEXT:    addi r3, r4, 0
@@ -583,10 +583,10 @@ define i64 @test_ds_cross_basic_blocks(ptr %arg, i32 signext %arg1) {
 ; CHECK-NEXT:    beq cr0, .LBB6_9
 ; CHECK-NEXT:  # %bb.1: # %bb3
 ; CHECK-NEXT:    addis r5, r2, .LC0 at toc@ha
-; CHECK-NEXT:    std r28, -32(r1) # 8-byte Folded Spill
+; CHECK-NEXT:    std r30, -16(r1) # 8-byte Folded Spill
 ; CHECK-NEXT:    std r29, -24(r1) # 8-byte Folded Spill
 ; CHECK-NEXT:    ld r5, .LC0 at toc@l(r5)
-; CHECK-NEXT:    std r30, -16(r1) # 8-byte Folded Spill
+; CHECK-NEXT:    std r28, -32(r1) # 8-byte Folded Spill
 ; CHECK-NEXT:    addi r6, r3, 4009
 ; CHECK-NEXT:    li r3, 0
 ; CHECK-NEXT:    li r7, -7
@@ -649,9 +649,9 @@ define i64 @test_ds_cross_basic_blocks(ptr %arg, i32 signext %arg1) {
 ; CHECK-NEXT:    add r4, r30, r4
 ; CHECK-NEXT:    b .LBB6_3
 ; CHECK-NEXT:  .LBB6_8:
-; CHECK-NEXT:    ld r30, -16(r1) # 8-byte Folded Reload
-; CHECK-NEXT:    ld r29, -24(r1) # 8-byte Folded Reload
 ; CHECK-NEXT:    ld r28, -32(r1) # 8-byte Folded Reload
+; CHECK-NEXT:    ld r29, -24(r1) # 8-byte Folded Reload
+; CHECK-NEXT:    ld r30, -16(r1) # 8-byte Folded Reload
 ; CHECK-NEXT:    blr
 ; CHECK-NEXT:  .LBB6_9:
 ; CHECK-NEXT:    li r3, 0
diff --git a/llvm/test/CodeGen/PowerPC/lsr-profitable-chain.ll b/llvm/test/CodeGen/PowerPC/lsr-profitable-chain.ll
index 79f2ef3e3746a..3de0fe239021c 100644
--- a/llvm/test/CodeGen/PowerPC/lsr-profitable-chain.ll
+++ b/llvm/test/CodeGen/PowerPC/lsr-profitable-chain.ll
@@ -8,22 +8,22 @@ define void @foo(ptr readonly %0, ptr %1, i64 %2, i64 %3, i64 %4, i64 %5, i64 %6
 ; CHECK-NEXT:    cmpd 5, 7
 ; CHECK-NEXT:    bgelr 0
 ; CHECK-NEXT:  # %bb.1: # %.preheader
-; CHECK-NEXT:    std 27, -40(1) # 8-byte Folded Spill
-; CHECK-NEXT:    addi 27, 5, 2
-; CHECK-NEXT:    std 28, -32(1) # 8-byte Folded Spill
-; CHECK-NEXT:    addi 28, 5, 3
 ; CHECK-NEXT:    std 30, -16(1) # 8-byte Folded Spill
 ; CHECK-NEXT:    addi 30, 5, 1
+; CHECK-NEXT:    std 28, -32(1) # 8-byte Folded Spill
+; CHECK-NEXT:    addi 28, 5, 3
+; CHECK-NEXT:    std 27, -40(1) # 8-byte Folded Spill
+; CHECK-NEXT:    addi 27, 5, 2
 ; CHECK-NEXT:    mulld 12, 8, 5
 ; CHECK-NEXT:    mulld 0, 9, 8
 ; CHECK-NEXT:    std 29, -24(1) # 8-byte Folded Spill
 ; CHECK-NEXT:    addi 29, 3, 16
 ; CHECK-NEXT:    sldi 11, 10, 3
-; CHECK-NEXT:    std 22, -80(1) # 8-byte Folded Spill
-; CHECK-NEXT:    std 23, -72(1) # 8-byte Folded Spill
-; CHECK-NEXT:    std 24, -64(1) # 8-byte Folded Spill
-; CHECK-NEXT:    std 25, -56(1) # 8-byte Folded Spill
 ; CHECK-NEXT:    std 26, -48(1) # 8-byte Folded Spill
+; CHECK-NEXT:    std 25, -56(1) # 8-byte Folded Spill
+; CHECK-NEXT:    std 24, -64(1) # 8-byte Folded Spill
+; CHECK-NEXT:    std 23, -72(1) # 8-byte Folded Spill
+; CHECK-NEXT:    std 22, -80(1) # 8-byte Folded Spill
 ; CHECK-NEXT:    mulld 30, 8, 30
 ; CHECK-NEXT:    mulld 28, 8, 28
 ; CHECK-NEXT:    mulld 8, 8, 27
@@ -104,15 +104,15 @@ define void @foo(ptr readonly %0, ptr %1, i64 %2, i64 %3, i64 %4, i64 %5, i64 %6
 ; CHECK-NEXT:    blt 0, .LBB0_5
 ; CHECK-NEXT:    b .LBB0_2
 ; CHECK-NEXT:  .LBB0_6:
-; CHECK-NEXT:    ld 30, -16(1) # 8-byte Folded Reload
-; CHECK-NEXT:    ld 29, -24(1) # 8-byte Folded Reload
-; CHECK-NEXT:    ld 28, -32(1) # 8-byte Folded Reload
-; CHECK-NEXT:    ld 27, -40(1) # 8-byte Folded Reload
-; CHECK-NEXT:    ld 26, -48(1) # 8-byte Folded Reload
-; CHECK-NEXT:    ld 25, -56(1) # 8-byte Folded Reload
-; CHECK-NEXT:    ld 24, -64(1) # 8-byte Folded Reload
-; CHECK-NEXT:    ld 23, -72(1) # 8-byte Folded Reload
 ; CHECK-NEXT:    ld 22, -80(1) # 8-byte Folded Reload
+; CHECK-NEXT:    ld 23, -72(1) # 8-byte Folded Reload
+; CHECK-NEXT:    ld 24, -64(1) # 8-byte Folded Reload
+; CHECK-NEXT:    ld 25, -56(1) # 8-byte Folded Reload
+; CHECK-NEXT:    ld 26, -48(1) # 8-byte Folded Reload
+; CHECK-NEXT:    ld 27, -40(1) # 8-byte Folded Reload
+; CHECK-NEXT:    ld 28, -32(1) # 8-byte Folded Reload
+; CHECK-NEXT:    ld 29, -24(1) # 8-byte Folded Reload
+; CHECK-NEXT:    ld 30, -16(1) # 8-byte Folded Reload
 ; CHECK-NEXT:    blr
   %9 = icmp slt i64 %2, %4
   br i1 %9, label %10, label %97
diff --git a/llvm/test/CodeGen/PowerPC/more-dq-form-prepare.ll b/llvm/test/CodeGen/PowerPC/more-dq-form-prepare.ll
index 9f62477ae01df..b6a10aaebdc82 100644
--- a/llvm/test/CodeGen/PowerPC/more-dq-form-prepare.ll
+++ b/llvm/test/CodeGen/PowerPC/more-dq-form-prepare.ll
@@ -56,39 +56,39 @@ define void @foo(ptr %.m, ptr %.n, ptr %.a, ptr %.x, ptr %.l, ptr %.vy01, ptr %.
 ; CHECK-NEXT:    .cfi_offset v29, -240
 ; CHECK-NEXT:    .cfi_offset v30, -224
 ; CHECK-NEXT:    .cfi_offset v31, -208
-; CHECK-NEXT:    std 22, 464(1) # 8-byte Folded Spill
 ; CHECK-NEXT:    std 23, 472(1) # 8-byte Folded Spill
+; CHECK-NEXT:    std 22, 464(1) # 8-byte Folded Spill
 ; CHECK-NEXT:    mr 22, 5
 ; CHECK-NEXT:    ld 5, 848(1)
 ; CHECK-NEXT:    addi 3, 3, 1
 ; CHECK-NEXT:    mr 11, 7
 ; CHECK-NEXT:    ld 23, 688(1)
 ; CHECK-NEXT:    ld 7, 728(1)
-; CHECK-NEXT:    std 18, 432(1) # 8-byte Folded Spill
 ; CHECK-NEXT:    std 19, 440(1) # 8-byte Folded Spill
+; CHECK-NEXT:    std 18, 432(1) # 8-byte Folded Spill
 ; CHECK-NEXT:    mr 18, 6
 ; CHECK-NEXT:    li 6, 9
 ; CHECK-NEXT:    ld 19, 768(1)
 ; CHECK-NEXT:    ld 2, 760(1)
-; CHECK-NEXT:    std 26, 496(1) # 8-byte Folded Spill
 ; CHECK-NEXT:    std 27, 504(1) # 8-byte Folded Spill
+; CHECK-NEXT:    std 26, 496(1) # 8-byte Folded Spill
 ; CHECK-NEXT:    cmpldi 3, 9
 ; CHECK-NEXT:    ld 27, 816(1)
 ; CHECK-NEXT:    ld 26, 808(1)
-; CHECK-NEXT:    std 14, 400(1) # 8-byte Folded Spill
 ; CHECK-NEXT:    std 15, 408(1) # 8-byte Folded Spill
+; CHECK-NEXT:    std 14, 400(1) # 8-byte Folded Spill
 ; CHECK-NEXT:    ld 15, 736(1)
 ; CHECK-NEXT:    lxv 39, 0(8)
-; CHECK-NEXT:    std 30, 528(1) # 8-byte Folded Spill
 ; CHECK-NEXT:    std 31, 536(1) # 8-byte Folded Spill
+; CHECK-NEXT:    std 30, 528(1) # 8-byte Folded Spill
 ; CHECK-NEXT:    ld 30, 704(1)
 ; CHECK-NEXT:    lxv 38, 0(9)
-; CHECK-NEXT:    std 20, 448(1) # 8-byte Folded Spill
 ; CHECK-NEXT:    std 21, 456(1) # 8-byte Folded Spill
+; CHECK-NEXT:    std 20, 448(1) # 8-byte Folded Spill
 ; CHECK-NEXT:    ld 21, 784(1)
 ; CHECK-NEXT:    ld 20, 776(1)
-; CHECK-NEXT:    std 24, 480(1) # 8-byte Folded Spill
 ; CHECK-NEXT:    std 25, 488(1) # 8-byte Folded Spill
+; CHECK-NEXT:    std 24, 480(1) # 8-byte Folded Spill
 ; CHECK-NEXT:    iselgt 3, 3, 6
 ; CHECK-NEXT:    ld 6, 720(1)
 ; CHECK-NEXT:    ld 24, 792(1)
@@ -112,14 +112,14 @@ define void @foo(ptr %.m, ptr %.n, ptr %.a, ptr %.x, ptr %.l, ptr %.vy01, ptr %.
 ; CHECK-NEXT:    lxv 33, 0(10)
 ; CHECK-NEXT:    lxv 32, 0(23)
 ; CHECK-NEXT:    lxv 36, 0(30)
-; CHECK-NEXT:    std 16, 416(1) # 8-byte Folded Spill
-; CHECK-NEXT:    std 17, 424(1) # 8-byte Folded Spill
-; CHECK-NEXT:    ld 17, 752(1)
-; CHECK-NEXT:    ld 16, 744(1)
-; CHECK-NEXT:    std 28, 512(1) # 8-byte Folded Spill
 ; CHECK-NEXT:    std 29, 520(1) # 8-byte Folded Spill
+; CHECK-NEXT:    std 28, 512(1) # 8-byte Folded Spill
 ; CHECK-NEXT:    ld 29, 712(1)
 ; CHECK-NEXT:    ld 28, 696(1)
+; CHECK-NEXT:    std 17, 424(1) # 8-byte Folded Spill
+; CHECK-NEXT:    std 16, 416(1) # 8-byte Folded Spill
+; CHECK-NEXT:    ld 17, 752(1)
+; CHECK-NEXT:    ld 16, 744(1)
 ; CHECK-NEXT:    std 8, 56(1) # 8-byte Folded Spill
 ; CHECK-NEXT:    std 9, 64(1) # 8-byte Folded Spill
 ; CHECK-NEXT:    lxv 37, 0(28)
@@ -132,33 +132,33 @@ define void @foo(ptr %.m, ptr %.n, ptr %.a, ptr %.x, ptr %.l, ptr %.vy01, ptr %.
 ; CHECK-NEXT:    lxv 10, 0(15)
 ; CHECK-NEXT:    lxv 9, 0(16)
 ; CHECK-NEXT:    li 28, 1
-; CHECK-NEXT:    stfd 26, 544(1) # 8-byte Folded Spill
-; CHECK-NEXT:    stfd 27, 552(1) # 8-byte Folded Spill
+; CHECK-NEXT:    stxv 63, 384(1) # 16-byte Folded Spill
+; CHECK-NEXT:    stxv 62, 368(1) # 16-byte Folded Spill
 ; CHECK-NEXT:    lxv 8, 0(17)
 ; CHECK-NEXT:    lxv 7, 0(2)
-; CHECK-NEXT:    stfd 28, 560(1) # 8-byte Folded Spill
-; CHECK-NEXT:    stfd 29, 568(1) # 8-byte Folded Spill
+; CHECK-NEXT:    stxv 61, 352(1) # 16-byte Folded Spill
+; CHECK-NEXT:    stxv 60, 336(1) # 16-byte Folded Spill
 ; CHECK-NEXT:    lxv 5, 0(20)
 ; CHECK-NEXT:    lxv 3, 0(24)
-; CHECK-NEXT:    stfd 30, 576(1) # 8-byte Folded Spill
-; CHECK-NEXT:    stfd 31, 584(1) # 8-byte Folded Spill
+; CHECK-NEXT:    stxv 59, 320(1) # 16-byte Folded Spill
+; CHECK-NEXT:    stxv 58, 304(1) # 16-byte Folded Spill
 ; CHECK-NEXT:    lxv 2, 0(25)
 ; CHECK-NEXT:    lxv 1, 0(26)
-; CHECK-NEXT:    stxv 52, 208(1) # 16-byte Folded Spill
-; CHECK-NEXT:    stxv 53, 224(1) # 16-byte Folded Spill
+; CHECK-NEXT:    stxv 57, 288(1) # 16-byte Folded Spill
+; CHECK-NEXT:    stxv 56, 272(1) # 16-byte Folded Spill
 ; CHECK-NEXT:    lxv 0, 0(27)
-; CHECK-NEXT:    stxv 54, 240(1) # 16-byte Folded Spill
 ; CHECK-NEXT:    stxv 55, 256(1) # 16-byte Folded Spill
-; CHECK-NEXT:    stxv 56, 272(1) # 16-byte Folded Spill
-; CHECK-NEXT:    stxv 57, 288(1) # 16-byte Folded Spill
-; CHECK-NEXT:    stxv 58, 304(1) # 16-byte Folded Spill
+; CHECK-NEXT:    stxv 54, 240(1) # 16-byte Folded Spill
+; CHECK-NEXT:    stxv 53, 224(1) # 16-byte Folded Spill
+; CHECK-NEXT:    stxv 52, 208(1) # 16-byte Folded Spill
+; CHECK-NEXT:    stfd 31, 584(1) # 8-byte Folded Spill
+; CHECK-NEXT:    stfd 30, 576(1) # 8-byte Folded Spill
 ; CHECK-NEXT:    std 5, 192(1) # 8-byte Folded Spill
 ; CHECK-NEXT:    ld 5, 832(1)
-; CHECK-NEXT:    stxv 59, 320(1) # 16-byte Folded Spill
-; CHECK-NEXT:    stxv 60, 336(1) # 16-byte Folded Spill
-; CHECK-NEXT:    stxv 61, 352(1) # 16-byte Folded Spill
-; CHECK-NEXT:    stxv 62, 368(1) # 16-byte Folded Spill
-; CHECK-NEXT:    stxv 63, 384(1) # 16-byte Folded Spill
+; CHECK-NEXT:    stfd 29, 568(1) # 8-byte Folded Spill
+; CHECK-NEXT:    stfd 28, 560(1) # 8-byte Folded Spill
+; CHECK-NEXT:    stfd 27, 552(1) # 8-byte Folded Spill
+; CHECK-NEXT:    stfd 26, 544(1) # 8-byte Folded Spill
 ; CHECK-NEXT:    std 15, 88(1) # 8-byte Folded Spill
 ; CHECK-NEXT:    std 16, 96(1) # 8-byte Folded Spill
 ; CHECK-NEXT:    std 17, 104(1) # 8-byte Folded Spill
@@ -270,53 +270,53 @@ define void @foo(ptr %.m, ptr %.n, ptr %.a, ptr %.x, ptr %.l, ptr %.vy01, ptr %.
 ; CHECK-NEXT:    ble 0, .LBB0_3
 ; CHECK-NEXT:  # %bb.6: # %_loop_1_loopHeader_._return_bb_crit_edge.loopexit
 ; CHECK-NEXT:    ld 3, 56(1) # 8-byte Folded Reload
-; CHECK-NEXT:    lxv 63, 384(1) # 16-byte Folded Reload
+; CHECK-NEXT:    ld 14, 400(1) # 8-byte Folded Reload
 ; CHECK-NEXT:    stxv 39, 0(3)
 ; CHECK-NEXT:    ld 3, 64(1) # 8-byte Folded Reload
-; CHECK-NEXT:    lxv 62, 368(1) # 16-byte Folded Reload
-; CHECK-NEXT:    lxv 61, 352(1) # 16-byte Folded Reload
-; CHECK-NEXT:    lxv 60, 336(1) # 16-byte Folded Reload
-; CHECK-NEXT:    lxv 59, 320(1) # 16-byte Folded Reload
-; CHECK-NEXT:    lxv 58, 304(1) # 16-byte Folded Reload
-; CHECK-NEXT:    lxv 57, 288(1) # 16-byte Folded Reload
-; CHECK-NEXT:    lxv 56, 272(1) # 16-byte Folded Reload
-; CHECK-NEXT:    lxv 55, 256(1) # 16-byte Folded Reload
-; CHECK-NEXT:    lxv 54, 240(1) # 16-byte Folded Reload
-; CHECK-NEXT:    lxv 53, 224(1) # 16-byte Folded Reload
-; CHECK-NEXT:    lxv 52, 208(1) # 16-byte Folded Reload
+; CHECK-NEXT:    ld 15, 408(1) # 8-byte Folded Reload
+; CHECK-NEXT:    ld 16, 416(1) # 8-byte Folded Reload
+; CHECK-NEXT:    ld 17, 424(1) # 8-byte Folded Reload
+; CHECK-NEXT:    ld 18, 432(1) # 8-byte Folded Reload
+; CHECK-NEXT:    ld 19, 440(1) # 8-byte Folded Reload
+; CHECK-NEXT:    ld 20, 448(1) # 8-byte Folded Reload
+; CHECK-NEXT:    ld 21, 456(1) # 8-byte Folded Reload
+; CHECK-NEXT:    ld 22, 464(1) # 8-byte Folded Reload
+; CHECK-NEXT:    ld 23, 472(1) # 8-byte Folded Reload
+; CHECK-NEXT:    ld 24, 480(1) # 8-byte Folded Reload
+; CHECK-NEXT:    ld 25, 488(1) # 8-byte Folded Reload
 ; CHECK-NEXT:    stxv 38, 0(3)
 ; CHECK-NEXT:    ld 3, 72(1) # 8-byte Folded Reload
-; CHECK-NEXT:    lfd 31, 584(1) # 8-byte Folded Reload
-; CHECK-NEXT:    lfd 30, 576(1) # 8-byte Folded Reload
-; CHECK-NEXT:    lfd 29, 568(1) # 8-byte Folded Reload
-; CHECK-NEXT:    lfd 28, 560(1) # 8-byte Folded Reload
-; CHECK-NEXT:    lfd 27, 552(1) # 8-byte Folded Reload
-; CHECK-NEXT:    lfd 26, 544(1) # 8-byte Folded Reload
-; CHECK-NEXT:    ld 31, 536(1) # 8-byte Folded Reload
-; CHECK-NEXT:    ld 30, 528(1) # 8-byte Folded Reload
-; CHECK-NEXT:    ld 29, 520(1) # 8-byte Folded Reload
-; CHECK-NEXT:    ld 28, 512(1) # 8-byte Folded Reload
+; CHECK-NEXT:    ld 26, 496(1) # 8-byte Folded Reload
 ; CHECK-NEXT:    ld 27, 504(1) # 8-byte Folded Reload
+; CHECK-NEXT:    ld 28, 512(1) # 8-byte Folded Reload
+; CHECK-NEXT:    ld 29, 520(1) # 8-byte Folded Reload
+; CHECK-NEXT:    ld 30, 528(1) # 8-byte Folded Reload
+; CHECK-NEXT:    ld 31, 536(1) # 8-byte Folded Reload
+; CHECK-NEXT:    lfd 26, 544(1) # 8-byte Folded Reload
+; CHECK-NEXT:    lfd 27, 552(1) # 8-byte Folded Reload
+; CHECK-NEXT:    lfd 28, 560(1) # 8-byte Folded Reload
+; CHECK-NEXT:    lfd 29, 568(1) # 8-byte Folded Reload
+; CHECK-NEXT:    lfd 30, 576(1) # 8-byte Folded Reload
 ; CHECK-NEXT:    stxv 33, 0(3)
 ; CHECK-NEXT:    ld 3, 40(1) # 8-byte Folded Reload
-; CHECK-NEXT:    ld 26, 496(1) # 8-byte Folded Reload
-; CHECK-NEXT:    ld 25, 488(1) # 8-byte Folded Reload
-; CHECK-NEXT:    ld 24, 480(1) # 8-byte Folded Reload
-; CHECK-NEXT:    ld 23, 472(1) # 8-byte Folded Reload
-; CHECK-NEXT:    ld 22, 464(1) # 8-byte Folded Reload
-; CHECK-NEXT:    ld 21, 456(1) # 8-byte Folded Reload
-; CHECK-NEXT:    ld 20, 448(1) # 8-byte Folded Reload
-; CHECK-NEXT:    ld 19, 440(1) # 8-byte Folded Reload
-; CHECK-NEXT:    ld 18, 432(1) # 8-byte Folded Reload
-; CHECK-NEXT:    ld 17, 424(1) # 8-byte Folded Reload
-; CHECK-NEXT:    ld 16, 416(1) # 8-byte Folded Reload
+; CHECK-NEXT:    lfd 31, 584(1) # 8-byte Folded Reload
+; CHECK-NEXT:    lxv 52, 208(1) # 16-byte Folded Reload
+; CHECK-NEXT:    lxv 53, 224(1) # 16-byte Folded Reload
+; CHECK-NEXT:    lxv 54, 240(1) # 16-byte Folded Reload
+; CHECK-NEXT:    lxv 55, 256(1) # 16-byte Folded Reload
+; CHECK-NEXT:    lxv 56, 272(1) # 16-byte Folded Reload
+; CHECK-NEXT:    lxv 57, 288(1) # 16-byte Folded Reload
+; CHECK-NEXT:    lxv 58, 304(1) # 16-byte Folded Reload
+; CHECK-NEXT:    lxv 59, 320(1) # 16-byte Folded Reload
+; CHECK-NEXT:    lxv 60, 336(1) # 16-byte Folded Reload
+; CHECK-NEXT:    lxv 61, 352(1) # 16-byte Folded Reload
 ; CHECK-NEXT:    stxv 32, 0(3)
 ; CHECK-NEXT:    ld 3, 48(1) # 8-byte Folded Reload
 ; CHECK-NEXT:    stxv 37, 0(10)
 ; CHECK-NEXT:    stxv 36, 0(9)
 ; CHECK-NEXT:    stxv 13, 0(8)
-; CHECK-NEXT:    ld 15, 408(1) # 8-byte Folded Reload
-; CHECK-NEXT:    ld 14, 400(1) # 8-byte Folded Reload
+; CHECK-NEXT:    lxv 62, 368(1) # 16-byte Folded Reload
+; CHECK-NEXT:    lxv 63, 384(1) # 16-byte Folded Reload
 ; CHECK-NEXT:    stxv 12, 0(3)
 ; CHECK-NEXT:    ld 3, 80(1) # 8-byte Folded Reload
 ; CHECK-NEXT:    stxv 11, 0(3)
diff --git a/llvm/test/CodeGen/PowerPC/pr43527.ll b/llvm/test/CodeGen/PowerPC/pr43527.ll
index 379bd6c070c77..e4b513272b9be 100644
--- a/llvm/test/CodeGen/PowerPC/pr43527.ll
+++ b/llvm/test/CodeGen/PowerPC/pr43527.ll
@@ -14,8 +14,8 @@ define dso_local void @test(i64 %arg, i64 %arg1) {
 ; CHECK-NEXT:    .cfi_offset lr, 16
 ; CHECK-NEXT:    .cfi_offset r29, -24
 ; CHECK-NEXT:    .cfi_offset r30, -16
-; CHECK-NEXT:    std r29, -24(r1) # 8-byte Folded Spill
 ; CHECK-NEXT:    std r30, -16(r1) # 8-byte Folded Spill
+; CHECK-NEXT:    std r29, -24(r1) # 8-byte Folded Spill
 ; CHECK-NEXT:    stdu r1, -64(r1)
 ; CHECK-NEXT:    sub r30, r4, r3
 ; CHECK-NEXT:    li r29, -4
@@ -33,8 +33,8 @@ define dso_local void @test(i64 %arg, i64 %arg1) {
 ; CHECK-NEXT:    stb r3, 0(r3)
 ; CHECK-NEXT:    addi r1, r1, 64
 ; CHECK-NEXT:    ld r0, 16(r1)
-; CHECK-NEXT:    ld r30, -16(r1) # 8-byte Folded Reload
 ; CHECK-NEXT:    ld r29, -24(r1) # 8-byte Folded Reload
+; CHECK-NEXT:    ld r30, -16(r1) # 8-byte Folded Reload
 ; CHECK-NEXT:    mtlr r0
 ; CHECK-NEXT:    blr
 ; CHECK-NEXT:  .LBB0_5: # %bb2
diff --git a/llvm/test/CodeGen/PowerPC/shrink-wrap.ll b/llvm/test/CodeGen/PowerPC/shrink-wrap.ll
index 12d0b056ca886..44215ce8c4dff 100644
--- a/llvm/test/CodeGen/PowerPC/shrink-wrap.ll
+++ b/llvm/test/CodeGen/PowerPC/shrink-wrap.ll
@@ -10,26 +10,26 @@ define signext i32 @shrinkwrapme(i32 signext %a, i32 signext %lim) {
 ; POWERPC64-NEXT:    ble 0, .LBB0_4
 ; POWERPC64-NEXT:  # %bb.1: # %for.body.preheader
 ; POWERPC64-NEXT:    addi 4, 4, -1
-; POWERPC64-NEXT:    std 14, -144(1) # 8-byte Folded Spill
-; POWERPC64-NEXT:    std 15, -136(1) # 8-byte Folded Spill
-; POWERPC64-NEXT:    std 16, -128(1) # 8-byte Folded Spill
-; POWERPC64-NEXT:    std 17, -120(1) # 8-byte Folded Spill
-; POWERPC64-NEXT:    std 18, -112(1) # 8-byte Folded Spill
-; POWERPC64-NEXT:    std 19, -104(1) # 8-byte Folded Spill
-; POWERPC64-NEXT:    std 20, -96(1) # 8-byte Folded Spill
-; POWERPC64-NEXT:    std 21, -88(1) # 8-byte Folded Spill
-; POWERPC64-NEXT:    std 22, -80(1) # 8-byte Folded Spill
-; POWERPC64-NEXT:    std 23, -72(1) # 8-byte Folded Spill
-; POWERPC64-NEXT:    std 24, -64(1) # 8-byte Folded Spill
-; POWERPC64-NEXT:    std 25, -56(1) # 8-byte Folded Spill
-; POWERPC64-NEXT:    std 26, -48(1) # 8-byte Folded Spill
-; POWERPC64-NEXT:    std 27, -40(1) # 8-byte Folded Spill
+; POWERPC64-NEXT:    std 31, -8(1) # 8-byte Folded Spill
+; POWERPC64-NEXT:    std 30, -16(1) # 8-byte Folded Spill
+; POWERPC64-NEXT:    std 29, -24(1) # 8-byte Folded Spill
 ; POWERPC64-NEXT:    std 28, -32(1) # 8-byte Folded Spill
+; POWERPC64-NEXT:    std 27, -40(1) # 8-byte Folded Spill
+; POWERPC64-NEXT:    std 26, -48(1) # 8-byte Folded Spill
+; POWERPC64-NEXT:    std 25, -56(1) # 8-byte Folded Spill
+; POWERPC64-NEXT:    std 24, -64(1) # 8-byte Folded Spill
+; POWERPC64-NEXT:    std 23, -72(1) # 8-byte Folded Spill
+; POWERPC64-NEXT:    std 22, -80(1) # 8-byte Folded Spill
+; POWERPC64-NEXT:    std 21, -88(1) # 8-byte Folded Spill
+; POWERPC64-NEXT:    std 20, -96(1) # 8-byte Folded Spill
+; POWERPC64-NEXT:    std 19, -104(1) # 8-byte Folded Spill
+; POWERPC64-NEXT:    std 18, -112(1) # 8-byte Folded Spill
+; POWERPC64-NEXT:    std 17, -120(1) # 8-byte Folded Spill
 ; POWERPC64-NEXT:    clrldi 4, 4, 32
 ; POWERPC64-NEXT:    addi 4, 4, 1
-; POWERPC64-NEXT:    std 29, -24(1) # 8-byte Folded Spill
-; POWERPC64-NEXT:    std 30, -16(1) # 8-byte Folded Spill
-; POWERPC64-NEXT:    std 31, -8(1) # 8-byte Folded Spill
+; POWERPC64-NEXT:    std 16, -128(1) # 8-byte Folded Spill
+; POWERPC64-NEXT:    std 15, -136(1) # 8-byte Folded Spill
+; POWERPC64-NEXT:    std 14, -144(1) # 8-byte Folded Spill
 ; POWERPC64-NEXT:    mtctr 4
 ; POWERPC64-NEXT:    li 4, 0
 ; POWERPC64-NEXT:    .p2align 4
@@ -40,25 +40,25 @@ define signext i32 @shrinkwrapme(i32 signext %a, i32 signext %lim) {
 ; POWERPC64-NEXT:    #NO_APP
 ; POWERPC64-NEXT:    bdnz .LBB0_2
 ; POWERPC64-NEXT:  # %bb.3:
-; POWERPC64-NEXT:    ld 31, -8(1) # 8-byte Folded Reload
-; POWERPC64-NEXT:    ld 30, -16(1) # 8-byte Folded Reload
-; POWERPC64-NEXT:    ld 29, -24(1) # 8-byte Folded Reload
-; POWERPC64-NEXT:    ld 28, -32(1) # 8-byte Folded Reload
+; POWERPC64-NEXT:    ld 14, -144(1) # 8-byte Folded Reload
+; POWERPC64-NEXT:    ld 15, -136(1) # 8-byte Folded Reload
+; POWERPC64-NEXT:    ld 16, -128(1) # 8-byte Folded Reload
+; POWERPC64-NEXT:    ld 17, -120(1) # 8-byte Folded Reload
 ; POWERPC64-NEXT:    extsw 3, 4
-; POWERPC64-NEXT:    ld 27, -40(1) # 8-byte Folded Reload
-; POWERPC64-NEXT:    ld 26, -48(1) # 8-byte Folded Reload
-; POWERPC64-NEXT:    ld 25, -56(1) # 8-byte Folded Reload
-; POWERPC64-NEXT:    ld 24, -64(1) # 8-byte Folded Reload
-; POWERPC64-NEXT:    ld 23, -72(1) # 8-byte Folded Reload
-; POWERPC64-NEXT:    ld 22, -80(1) # 8-byte Folded Reload
-; POWERPC64-NEXT:    ld 21, -88(1) # 8-byte Folded Reload
-; POWERPC64-NEXT:    ld 20, -96(1) # 8-byte Folded Reload
-; POWERPC64-NEXT:    ld 19, -104(1) # 8-byte Folded Reload
 ; POWERPC64-NEXT:    ld 18, -112(1) # 8-byte Folded Reload
-; POWERPC64-NEXT:    ld 17, -120(1) # 8-byte Folded Reload
-; POWERPC64-NEXT:    ld 16, -128(1) # 8-byte Folded Reload
-; POWERPC64-NEXT:    ld 15, -136(1) # 8-byte Folded Reload
-; POWERPC64-NEXT:    ld 14, -144(1) # 8-byte Folded Reload
+; POWERPC64-NEXT:    ld 19, -104(1) # 8-byte Folded Reload
+; POWERPC64-NEXT:    ld 20, -96(1) # 8-byte Folded Reload
+; POWERPC64-NEXT:    ld 21, -88(1) # 8-byte Folded Reload
+; POWERPC64-NEXT:    ld 22, -80(1) # 8-byte Folded Reload
+; POWERPC64-NEXT:    ld 23, -72(1) # 8-byte Folded Reload
+; POWERPC64-NEXT:    ld 24, -64(1) # 8-byte Folded Reload
+; POWERPC64-NEXT:    ld 25, -56(1) # 8-byte Folded Reload
+; POWERPC64-NEXT:    ld 26, -48(1) # 8-byte Folded Reload
+; POWERPC64-NEXT:    ld 27, -40(1) # 8-byte Folded Reload
+; POWERPC64-NEXT:    ld 28, -32(1) # 8-byte Folded Reload
+; POWERPC64-NEXT:    ld 29, -24(1) # 8-byte Folded Reload
+; POWERPC64-NEXT:    ld 30, -16(1) # 8-byte Folded Reload
+; POWERPC64-NEXT:    ld 31, -8(1) # 8-byte Folded Reload
 ; POWERPC64-NEXT:    blr
 ; POWERPC64-NEXT:  .LBB0_4:
 ; POWERPC64-NEXT:    li 4, 0
@@ -70,24 +70,24 @@ define signext i32 @shrinkwrapme(i32 signext %a, i32 signext %lim) {
 ; POWERPC32-AIX-NEXT:    cmpwi 4, 0
 ; POWERPC32-AIX-NEXT:    ble 0, L..BB0_4
 ; POWERPC32-AIX-NEXT:  # %bb.1: # %for.body.preheader
-; POWERPC32-AIX-NEXT:    stw 14, -72(1) # 4-byte Folded Spill
-; POWERPC32-AIX-NEXT:    stw 15, -68(1) # 4-byte Folded Spill
-; POWERPC32-AIX-NEXT:    stw 16, -64(1) # 4-byte Folded Spill
-; POWERPC32-AIX-NEXT:    stw 17, -60(1) # 4-byte Folded Spill
-; POWERPC32-AIX-NEXT:    stw 18, -56(1) # 4-byte Folded Spill
-; POWERPC32-AIX-NEXT:    stw 19, -52(1) # 4-byte Folded Spill
-; POWERPC32-AIX-NEXT:    stw 20, -48(1) # 4-byte Folded Spill
-; POWERPC32-AIX-NEXT:    stw 21, -44(1) # 4-byte Folded Spill
-; POWERPC32-AIX-NEXT:    stw 22, -40(1) # 4-byte Folded Spill
-; POWERPC32-AIX-NEXT:    stw 23, -36(1) # 4-byte Folded Spill
-; POWERPC32-AIX-NEXT:    stw 24, -32(1) # 4-byte Folded Spill
-; POWERPC32-AIX-NEXT:    stw 25, -28(1) # 4-byte Folded Spill
-; POWERPC32-AIX-NEXT:    stw 26, -24(1) # 4-byte Folded Spill
-; POWERPC32-AIX-NEXT:    stw 27, -20(1) # 4-byte Folded Spill
-; POWERPC32-AIX-NEXT:    stw 28, -16(1) # 4-byte Folded Spill
-; POWERPC32-AIX-NEXT:    stw 29, -12(1) # 4-byte Folded Spill
-; POWERPC32-AIX-NEXT:    stw 30, -8(1) # 4-byte Folded Spill
 ; POWERPC32-AIX-NEXT:    stw 31, -4(1) # 4-byte Folded Spill
+; POWERPC32-AIX-NEXT:    stw 30, -8(1) # 4-byte Folded Spill
+; POWERPC32-AIX-NEXT:    stw 29, -12(1) # 4-byte Folded Spill
+; POWERPC32-AIX-NEXT:    stw 28, -16(1) # 4-byte Folded Spill
+; POWERPC32-AIX-NEXT:    stw 27, -20(1) # 4-byte Folded Spill
+; POWERPC32-AIX-NEXT:    stw 26, -24(1) # 4-byte Folded Spill
+; POWERPC32-AIX-NEXT:    stw 25, -28(1) # 4-byte Folded Spill
+; POWERPC32-AIX-NEXT:    stw 24, -32(1) # 4-byte Folded Spill
+; POWERPC32-AIX-NEXT:    stw 23, -36(1) # 4-byte Folded Spill
+; POWERPC32-AIX-NEXT:    stw 22, -40(1) # 4-byte Folded Spill
+; POWERPC32-AIX-NEXT:    stw 21, -44(1) # 4-byte Folded Spill
+; POWERPC32-AIX-NEXT:    stw 20, -48(1) # 4-byte Folded Spill
+; POWERPC32-AIX-NEXT:    stw 19, -52(1) # 4-byte Folded Spill
+; POWERPC32-AIX-NEXT:    stw 18, -56(1) # 4-byte Folded Spill
+; POWERPC32-AIX-NEXT:    stw 17, -60(1) # 4-byte Folded Spill
+; POWERPC32-AIX-NEXT:    stw 16, -64(1) # 4-byte Folded Spill
+; POWERPC32-AIX-NEXT:    stw 15, -68(1) # 4-byte Folded Spill
+; POWERPC32-AIX-NEXT:    stw 14, -72(1) # 4-byte Folded Spill
 ; POWERPC32-AIX-NEXT:    mtctr 4
 ; POWERPC32-AIX-NEXT:    li 4, 0
 ; POWERPC32-AIX-NEXT:    .align 4
@@ -98,25 +98,25 @@ define signext i32 @shrinkwrapme(i32 signext %a, i32 signext %lim) {
 ; POWERPC32-AIX-NEXT:    #NO_APP
 ; POWERPC32-AIX-NEXT:    bdnz L..BB0_2
 ; POWERPC32-AIX-NEXT:  # %bb.3:
-; POWERPC32-AIX-NEXT:    lwz 31, -4(1) # 4-byte Folded Reload
-; POWERPC32-AIX-NEXT:    lwz 30, -8(1) # 4-byte Folded Reload
-; POWERPC32-AIX-NEXT:    lwz 29, -12(1) # 4-byte Folded Reload
-; POWERPC32-AIX-NEXT:    lwz 28, -16(1) # 4-byte Folded Reload
+; POWERPC32-AIX-NEXT:    lwz 14, -72(1) # 4-byte Folded Reload
+; POWERPC32-AIX-NEXT:    lwz 15, -68(1) # 4-byte Folded Reload
+; POWERPC32-AIX-NEXT:    lwz 16, -64(1) # 4-byte Folded Reload
+; POWERPC32-AIX-NEXT:    lwz 17, -60(1) # 4-byte Folded Reload
 ; POWERPC32-AIX-NEXT:    mr 3, 4
-; POWERPC32-AIX-NEXT:    lwz 27, -20(1) # 4-byte Folded Reload
-; POWERPC32-AIX-NEXT:    lwz 26, -24(1) # 4-byte Folded Reload
-; POWERPC32-AIX-NEXT:    lwz 25, -28(1) # 4-byte Folded Reload
-; POWERPC32-AIX-NEXT:    lwz 24, -32(1) # 4-byte Folded Reload
-; POWERPC32-AIX-NEXT:    lwz 23, -36(1) # 4-byte Folded Reload
-; POWERPC32-AIX-NEXT:    lwz 22, -40(1) # 4-byte Folded Reload
-; POWERPC32-AIX-NEXT:    lwz 21, -44(1) # 4-byte Folded Reload
-; POWERPC32-AIX-NEXT:    lwz 20, -48(1) # 4-byte Folded Reload
-; POWERPC32-AIX-NEXT:    lwz 19, -52(1) # 4-byte Folded Reload
 ; POWERPC32-AIX-NEXT:    lwz 18, -56(1) # 4-byte Folded Reload
-; POWERPC32-AIX-NEXT:    lwz 17, -60(1) # 4-byte Folded Reload
-; POWERPC32-AIX-NEXT:    lwz 16, -64(1) # 4-byte Folded Reload
-; POWERPC32-AIX-NEXT:    lwz 15, -68(1) # 4-byte Folded Reload
-; POWERPC32-AIX-NEXT:    lwz 14, -72(1) # 4-byte Folded Reload
+; POWERPC32-AIX-NEXT:    lwz 19, -52(1) # 4-byte Folded Reload
+; POWERPC32-AIX-NEXT:    lwz 20, -48(1) # 4-byte Folded Reload
+; POWERPC32-AIX-NEXT:    lwz 21, -44(1) # 4-byte Folded Reload
+; POWERPC32-AIX-NEXT:    lwz 22, -40(1) # 4-byte Folded Reload
+; POWERPC32-AIX-NEXT:    lwz 23, -36(1) # 4-byte Folded Reload
+; POWERPC32-AIX-NEXT:    lwz 24, -32(1) # 4-byte Folded Reload
+; POWERPC32-AIX-NEXT:    lwz 25, -28(1) # 4-byte Folded Reload
+; POWERPC32-AIX-NEXT:    lwz 26, -24(1) # 4-byte Folded Reload
+; POWERPC32-AIX-NEXT:    lwz 27, -20(1) # 4-byte Folded Reload
+; POWERPC32-AIX-NEXT:    lwz 28, -16(1) # 4-byte Folded Reload
+; POWERPC32-AIX-NEXT:    lwz 29, -12(1) # 4-byte Folded Reload
+; POWERPC32-AIX-NEXT:    lwz 30, -8(1) # 4-byte Folded Reload
+; POWERPC32-AIX-NEXT:    lwz 31, -4(1) # 4-byte Folded Reload
 ; POWERPC32-AIX-NEXT:    blr
 ; POWERPC32-AIX-NEXT:  L..BB0_4:
 ; POWERPC32-AIX-NEXT:    li 3, 0
@@ -128,26 +128,26 @@ define signext i32 @shrinkwrapme(i32 signext %a, i32 signext %lim) {
 ; POWERPC64-AIX-NEXT:    blt 0, L..BB0_4
 ; POWERPC64-AIX-NEXT:  # %bb.1: # %for.body.preheader
 ; POWERPC64-AIX-NEXT:    addi 4, 4, -1
-; POWERPC64-AIX-NEXT:    std 14, -144(1) # 8-byte Folded Spill
-; POWERPC64-AIX-NEXT:    std 15, -136(1) # 8-byte Folded Spill
-; POWERPC64-AIX-NEXT:    std 16, -128(1) # 8-byte Folded Spill
-; POWERPC64-AIX-NEXT:    std 17, -120(1) # 8-byte Folded Spill
-; POWERPC64-AIX-NEXT:    std 18, -112(1) # 8-byte Folded Spill
-; POWERPC64-AIX-NEXT:    std 19, -104(1) # 8-byte Folded Spill
-; POWERPC64-AIX-NEXT:    std 20, -96(1) # 8-byte Folded Spill
-; POWERPC64-AIX-NEXT:    std 21, -88(1) # 8-byte Folded Spill
-; POWERPC64-AIX-NEXT:    std 22, -80(1) # 8-byte Folded Spill
-; POWERPC64-AIX-NEXT:    std 23, -72(1) # 8-byte Folded Spill
-; POWERPC64-AIX-NEXT:    std 24, -64(1) # 8-byte Folded Spill
-; POWERPC64-AIX-NEXT:    std 25, -56(1) # 8-byte Folded Spill
-; POWERPC64-AIX-NEXT:    std 26, -48(1) # 8-byte Folded Spill
-; POWERPC64-AIX-NEXT:    std 27, -40(1) # 8-byte Folded Spill
+; POWERPC64-AIX-NEXT:    std 31, -8(1) # 8-byte Folded Spill
+; POWERPC64-AIX-NEXT:    std 30, -16(1) # 8-byte Folded Spill
+; POWERPC64-AIX-NEXT:    std 29, -24(1) # 8-byte Folded Spill
 ; POWERPC64-AIX-NEXT:    std 28, -32(1) # 8-byte Folded Spill
+; POWERPC64-AIX-NEXT:    std 27, -40(1) # 8-byte Folded Spill
+; POWERPC64-AIX-NEXT:    std 26, -48(1) # 8-byte Folded Spill
+; POWERPC64-AIX-NEXT:    std 25, -56(1) # 8-byte Folded Spill
+; POWERPC64-AIX-NEXT:    std 24, -64(1) # 8-byte Folded Spill
+; POWERPC64-AIX-NEXT:    std 23, -72(1) # 8-byte Folded Spill
+; POWERPC64-AIX-NEXT:    std 22, -80(1) # 8-byte Folded Spill
+; POWERPC64-AIX-NEXT:    std 21, -88(1) # 8-byte Folded Spill
+; POWERPC64-AIX-NEXT:    std 20, -96(1) # 8-byte Folded Spill
+; POWERPC64-AIX-NEXT:    std 19, -104(1) # 8-byte Folded Spill
+; POWERPC64-AIX-NEXT:    std 18, -112(1) # 8-byte Folded Spill
+; POWERPC64-AIX-NEXT:    std 17, -120(1) # 8-byte Folded Spill
 ; POWERPC64-AIX-NEXT:    clrldi 4, 4, 32
 ; POWERPC64-AIX-NEXT:    addi 4, 4, 1
-; POWERPC64-AIX-NEXT:    std 29, -24(1) # 8-byte Folded Spill
-; POWERPC64-AIX-NEXT:    std 30, -16(1) # 8-byte Folded Spill
-; POWERPC64-AIX-NEXT:    std 31, -8(1) # 8-byte Folded Spill
+; POWERPC64-AIX-NEXT:    std 16, -128(1) # 8-byte Folded Spill
+; POWERPC64-AIX-NEXT:    std 15, -136(1) # 8-byte Folded Spill
+; POWERPC64-AIX-NEXT:    std 14, -144(1) # 8-byte Folded Spill
 ; POWERPC64-AIX-NEXT:    mtctr 4
 ; POWERPC64-AIX-NEXT:    li 4, 0
 ; POWERPC64-AIX-NEXT:    .align 4
@@ -158,25 +158,25 @@ define signext i32 @shrinkwrapme(i32 signext %a, i32 signext %lim) {
 ; POWERPC64-AIX-NEXT:    #NO_APP
 ; POWERPC64-AIX-NEXT:    bdnz L..BB0_2
 ; POWERPC64-AIX-NEXT:  # %bb.3:
-; POWERPC64-AIX-NEXT:    ld 31, -8(1) # 8-byte Folded Reload
-; POWERPC64-AIX-NEXT:    ld 30, -16(1) # 8-byte Folded Reload
-; POWERPC64-AIX-NEXT:    ld 29, -24(1) # 8-byte Folded Reload
-; POWERPC64-AIX-NEXT:    ld 28, -32(1) # 8-byte Folded Reload
+; POWERPC64-AIX-NEXT:    ld 14, -144(1) # 8-byte Folded Reload
+; POWERPC64-AIX-NEXT:    ld 15, -136(1) # 8-byte Folded Reload
+; POWERPC64-AIX-NEXT:    ld 16, -128(1) # 8-byte Folded Reload
+; POWERPC64-AIX-NEXT:    ld 17, -120(1) # 8-byte Folded Reload
 ; POWERPC64-AIX-NEXT:    extsw 3, 4
-; POWERPC64-AIX-NEXT:    ld 27, -40(1) # 8-byte Folded Reload
-; POWERPC64-AIX-NEXT:    ld 26, -48(1) # 8-byte Folded Reload
-; POWERPC64-AIX-NEXT:    ld 25, -56(1) # 8-byte Folded Reload
-; POWERPC64-AIX-NEXT:    ld 24, -64(1) # 8-byte Folded Reload
-; POWERPC64-AIX-NEXT:    ld 23, -72(1) # 8-byte Folded Reload
-; POWERPC64-AIX-NEXT:    ld 22, -80(1) # 8-byte Folded Reload
-; POWERPC64-AIX-NEXT:    ld 21, -88(1) # 8-byte Folded Reload
-; POWERPC64-AIX-NEXT:    ld 20, -96(1) # 8-byte Folded Reload
-; POWERPC64-AIX-NEXT:    ld 19, -104(1) # 8-byte Folded Reload
 ; POWERPC64-AIX-NEXT:    ld 18, -112(1) # 8-byte Folded Reload
-; POWERPC64-AIX-NEXT:    ld 17, -120(1) # 8-byte Folded Reload
-; POWERPC64-AIX-NEXT:    ld 16, -128(1) # 8-byte Folded Reload
-; POWERPC64-AIX-NEXT:    ld 15, -136(1) # 8-byte Folded Reload
-; POWERPC64-AIX-NEXT:    ld 14, -144(1) # 8-byte Folded Reload
+; POWERPC64-AIX-NEXT:    ld 19, -104(1) # 8-byte Folded Reload
+; POWERPC64-AIX-NEXT:    ld 20, -96(1) # 8-byte Folded Reload
+; POWERPC64-AIX-NEXT:    ld 21, -88(1) # 8-byte Folded Reload
+; POWERPC64-AIX-NEXT:    ld 22, -80(1) # 8-byte Folded Reload
+; POWERPC64-AIX-NEXT:    ld 23, -72(1) # 8-byte Folded Reload
+; POWERPC64-AIX-NEXT:    ld 24, -64(1) # 8-byte Folded Reload
+; POWERPC64-AIX-NEXT:    ld 25, -56(1) # 8-byte Folded Reload
+; POWERPC64-AIX-NEXT:    ld 26, -48(1) # 8-byte Folded Reload
+; POWERPC64-AIX-NEXT:    ld 27, -40(1) # 8-byte Folded Reload
+; POWERPC64-AIX-NEXT:    ld 28, -32(1) # 8-byte Folded Reload
+; POWERPC64-AIX-NEXT:    ld 29, -24(1) # 8-byte Folded Reload
+; POWERPC64-AIX-NEXT:    ld 30, -16(1) # 8-byte Folded Reload
+; POWERPC64-AIX-NEXT:    ld 31, -8(1) # 8-byte Folded Reload
 ; POWERPC64-AIX-NEXT:    blr
 ; POWERPC64-AIX-NEXT:  L..BB0_4:
 ; POWERPC64-AIX-NEXT:    li 4, 0
diff --git a/llvm/test/CodeGen/X86/cfi-epilogue-with-return.mir b/llvm/test/CodeGen/X86/cfi-epilogue-with-return.mir
index 583e54b097faf..395a2c5ebf915 100644
--- a/llvm/test/CodeGen/X86/cfi-epilogue-with-return.mir
+++ b/llvm/test/CodeGen/X86/cfi-epilogue-with-return.mir
@@ -21,8 +21,22 @@ liveins:
 frameInfo:
   maxAlignment:    1
   hasCalls:        true
-  savePoint:       '%bb.1'
-  restorePoint:    '%bb.1'
+  savePoint:
+    - point:           '%bb.1'
+      registers:
+        - '$rbx'
+        - '$r12'
+        - '$r13'
+        - '$r14'
+        - '$r15'
+  restorePoint:
+    - point:           '%bb.1'
+      registers:
+        - '$rbx'
+        - '$r12'
+        - '$r13'
+        - '$r14'
+        - '$r15'
 machineFunctionInfo: {}
 body:             |
   bb.0:
diff --git a/llvm/test/CodeGen/X86/cfi-epilogue-without-return.mir b/llvm/test/CodeGen/X86/cfi-epilogue-without-return.mir
index 8f04721489608..b701569b8ad7d 100644
--- a/llvm/test/CodeGen/X86/cfi-epilogue-without-return.mir
+++ b/llvm/test/CodeGen/X86/cfi-epilogue-without-return.mir
@@ -28,8 +28,22 @@ liveins:
 frameInfo:
   maxAlignment:    1
   hasCalls:        true
-  savePoint:       '%bb.1'
-  restorePoint:    '%bb.1'
+  savePoints:
+    - point:           '%bb.1'
+      registers:
+        - '$rbx'
+        - '$r12'
+        - '$r13'
+        - '$r14'
+        - '$r15'
+  restorePoints:
+    - point:           '%bb.1'
+      registers:
+        - '$rbx'
+        - '$r12'
+        - '$r13'
+        - '$r14'
+        - '$r15'
 machineFunctionInfo: {}
 body:             |
   bb.0:
diff --git a/llvm/tools/llvm-reduce/ReducerWorkItem.cpp b/llvm/tools/llvm-reduce/ReducerWorkItem.cpp
index 7b1f69a8671ef..434f88ebd8940 100644
--- a/llvm/tools/llvm-reduce/ReducerWorkItem.cpp
+++ b/llvm/tools/llvm-reduce/ReducerWorkItem.cpp
@@ -93,23 +93,11 @@ static void cloneFrameInfo(
   DstMFI.setCVBytesOfCalleeSavedRegisters(
       SrcMFI.getCVBytesOfCalleeSavedRegisters());
 
-  assert(SrcMFI.getSavePoints().size() < 2 &&
-         "MFI can't contain multiple save points!");
-  if (!SrcMFI.getSavePoints().empty()) {
-    MachineBasicBlock *SavePt = SrcMFI.getSavePoints().front();
-    std::vector<MachineBasicBlock *> SavePts;
-    SavePts.push_back(Src2DstMBB.find(SavePt)->second);
-    DstMFI.setSavePoints(SavePts);
-  }
+  DstMFI.setSavePoints(MachineFrameInfo::constructSaveRestorePoints(
+      SrcMFI.getSavePoints(), Src2DstMBB));
 
-  assert(SrcMFI.getRestorePoints().size() < 2 &&
-         "MFI can't contain multiple restore points!");
-  if (!SrcMFI.getRestorePoints().empty()) {
-    MachineBasicBlock *RestorePt = SrcMFI.getRestorePoints().front();
-    std::vector<MachineBasicBlock *> RestorePts;
-    RestorePts.push_back(Src2DstMBB.find(RestorePt)->second);
-    DstMFI.setRestorePoints(RestorePts);
-  }
+  DstMFI.setRestorePoints(MachineFrameInfo::constructSaveRestorePoints(
+      SrcMFI.getRestorePoints(), Src2DstMBB));
 
   auto CopyObjectProperties = [](MachineFrameInfo &DstMFI,
                                  const MachineFrameInfo &SrcMFI, int FI) {

>From dbd589045c658c865690af9cd81bbb62afb1cbee Mon Sep 17 00:00:00 2001
From: ens-sc <elizaveta.noskova at syntacore.com>
Date: Wed, 11 Dec 2024 14:55:20 +0300
Subject: [PATCH 6/6] review

---
 llvm/include/llvm/CodeGen/MachineFrameInfo.h | 12 +++---------
 llvm/lib/CodeGen/MIRParser/MIRParser.cpp     |  3 +--
 2 files changed, 4 insertions(+), 11 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/MachineFrameInfo.h b/llvm/include/llvm/CodeGen/MachineFrameInfo.h
index d746466d41c3e..7c224cdb3fc01 100644
--- a/llvm/include/llvm/CodeGen/MachineFrameInfo.h
+++ b/llvm/include/llvm/CodeGen/MachineFrameInfo.h
@@ -915,11 +915,8 @@ class MachineFrameInfo {
     RestorePoints = std::move(NewRestorePoints);
   }
 
-  void setSavePoint(MachineBasicBlock *MBB, std::vector<Register> &Regs) {
-    if (SavePoints.contains(MBB))
-      SavePoints[MBB] = Regs;
-    else
-      SavePoints.insert(std::make_pair(MBB, Regs));
+  void setSavePoint(MachineBasicBlock *MBB, const std::vector<Register> &Regs) {
+    SavePoints[MBB] = Regs;
   }
 
   static const SaveRestorePoints constructSaveRestorePoints(
@@ -933,10 +930,7 @@ class MachineFrameInfo {
   }
 
   void setRestorePoint(MachineBasicBlock *MBB, std::vector<Register> &Regs) {
-    if (RestorePoints.contains(MBB))
-      RestorePoints[MBB] = Regs;
-    else
-      RestorePoints.insert(std::make_pair(MBB, Regs));
+    RestorePoints[MBB] = Regs;
   }
 
   MachineBasicBlock *getProlog() const { return Prolog; }
diff --git a/llvm/lib/CodeGen/MIRParser/MIRParser.cpp b/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
index 67a5fbe0665d0..b4ecae36ce60a 100644
--- a/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
+++ b/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
@@ -1082,7 +1082,7 @@ bool MIRParserImpl::initializeSaveRestorePoints(
   SMDiagnostic Error;
   MachineBasicBlock *MBB = nullptr;
   llvm::SaveRestorePoints SRPoints;
-  std::vector<Register> Registers{};
+  std::vector<Register> Registers;
 
   if (std::holds_alternative<std::vector<yaml::SaveRestorePointEntry>>(
           YamlSRPoints)) {
@@ -1100,7 +1100,6 @@ bool MIRParserImpl::initializeSaveRestorePoints(
         Register Reg;
         if (parseNamedRegisterReference(PFS, Reg, RegStr.Value, Error))
           return error(Error, RegStr.SourceRange);
-
         Registers.push_back(Reg);
       }
       SRPoints.insert(std::make_pair(MBB, Registers));



More information about the llvm-commits mailing list