[llvm] [llvm][RISCV] Support multiple save/restore points in prolog-epilog (PR #119358)

Elizaveta Noskova via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 6 05:41:20 PDT 2025


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

>From 474a1939756d5bc729ae14592bcc6101fc3195ea 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 01/13] [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 0f3f945905d3a..2fe5496235903 100644
--- a/llvm/include/llvm/CodeGen/MIRYamlMapping.h
+++ b/llvm/include/llvm/CodeGen/MIRYamlMapping.h
@@ -634,6 +634,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);
@@ -642,6 +691,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
@@ -669,8 +726,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 &&
@@ -691,7 +748,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;
   }
 };
@@ -723,10 +781,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 3e99e576fa364..0a7e56449e812 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);
 
@@ -867,18 +871,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.
@@ -1093,8 +1091,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 ce1834a90ca54..b51249c3f82b6 100644
--- a/llvm/lib/CodeGen/MIRPrinter.cpp
+++ b/llvm/lib/CodeGen/MIRPrinter.cpp
@@ -150,6 +150,8 @@ static void convertMJTI(ModuleSlotTracker &MST, yaml::MachineJumpTable &YamlJTI,
                         const MachineJumpTableInfo &JTI);
 static void convertMFI(ModuleSlotTracker &MST, yaml::MachineFrameInfo &YamlMFI,
                        const MachineFrameInfo &MFI);
+static void convertSRPoints(ModuleSlotTracker &MST, yaml::SaveRestorePoints &YamlSRPoints,
+                            MachineBasicBlock *SaveRestorePoint);
 static void convertStackObjects(yaml::MachineFunction &YMF,
                                 const MachineFunction &MF,
                                 ModuleSlotTracker &MST, MFPrintState &State);
@@ -355,14 +357,10 @@ static void convertMFI(ModuleSlotTracker &MST, yaml::MachineFrameInfo &YamlMFI,
   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())
+    convertSRPoints(MST, YamlMFI.SavePoints, MFI.getSavePoint());
+  if (MFI.getRestorePoint())
+    convertSRPoints(MST, YamlMFI.RestorePoints, MFI.getRestorePoint());
 }
 
 static void convertEntryValueObjects(yaml::MachineFunction &YMF,
@@ -616,6 +614,19 @@ static void convertMCP(yaml::MachineFunction &MF,
   }
 }
 
+static void convertSRPoints(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);
+}
+
 static void convertMJTI(ModuleSlotTracker &MST, yaml::MachineJumpTable &YamlJTI,
                         const MachineJumpTableInfo &JTI) {
   YamlJTI.Kind = JTI.getEntryKind();
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 b8fd76681c5eb..b912a346c1b66 100644
--- a/llvm/test/CodeGen/AArch64/dont-shrink-wrap-stack-mayloadorstore.mir
+++ b/llvm/test/CodeGen/AArch64/dont-shrink-wrap-stack-mayloadorstore.mir
@@ -7,17 +7,23 @@
  ; RUN: llc -x=mir -simplify-mir -passes='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 af2a18d92b34f..139a3c46c51c1 100644
--- a/llvm/test/CodeGen/X86/shrink_wrap_dbg_value.mir
+++ b/llvm/test/CodeGen/X86/shrink_wrap_dbg_value.mir
@@ -120,8 +120,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 07b8ded45124b862690020a3201485301d89820b 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 02/13] 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 0a7e56449e812..b42ebaab54ef2 100644
--- a/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
+++ b/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
@@ -1126,8 +1126,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 0b7a58b110942d317852dfe00ea152f29c19a684 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 03/13] 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 403e5eda949f1..63e28a1c9444a 100644
--- a/llvm/include/llvm/CodeGen/MachineFrameInfo.h
+++ b/llvm/include/llvm/CodeGen/MachineFrameInfo.h
@@ -332,10 +332,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;
@@ -825,10 +825,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 b42ebaab54ef2..2dc535abb3fcc 100644
--- a/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
+++ b/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
@@ -1096,32 +1096,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 b51249c3f82b6..de9e8a4a147ee 100644
--- a/llvm/lib/CodeGen/MIRPrinter.cpp
+++ b/llvm/lib/CodeGen/MIRPrinter.cpp
@@ -151,7 +151,7 @@ static void convertMJTI(ModuleSlotTracker &MST, yaml::MachineJumpTable &YamlJTI,
 static void convertMFI(ModuleSlotTracker &MST, yaml::MachineFrameInfo &YamlMFI,
                        const MachineFrameInfo &MFI);
 static void convertSRPoints(ModuleSlotTracker &MST, yaml::SaveRestorePoints &YamlSRPoints,
-                            MachineBasicBlock *SaveRestorePoint);
+                            std::vector<MachineBasicBlock *> SaveRestorePoints);
 static void convertStackObjects(yaml::MachineFunction &YMF,
                                 const MachineFunction &MF,
                                 ModuleSlotTracker &MST, MFPrintState &State);
@@ -357,10 +357,10 @@ static void convertMFI(ModuleSlotTracker &MST, yaml::MachineFrameInfo &YamlMFI,
   YamlMFI.HasTailCall = MFI.hasTailCall();
   YamlMFI.IsCalleeSavedInfoValid = MFI.isCalleeSavedInfoValid();
   YamlMFI.LocalFrameSize = MFI.getLocalFrameSize();
-  if (MFI.getSavePoint())
-    convertSRPoints(MST, YamlMFI.SavePoints, MFI.getSavePoint());
-  if (MFI.getRestorePoint())
-    convertSRPoints(MST, YamlMFI.RestorePoints, MFI.getRestorePoint());
+  if (!MFI.getSavePoints().empty())
+    convertSRPoints(MST, YamlMFI.SavePoints, MFI.getSavePoints());
+  if (!MFI.getRestorePoints().empty())
+    convertSRPoints(MST, YamlMFI.RestorePoints, MFI.getRestorePoints());
 }
 
 static void convertEntryValueObjects(yaml::MachineFunction &YMF,
@@ -616,15 +616,18 @@ static void convertMCP(yaml::MachineFunction &MF,
 
 static void convertSRPoints(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);
+  }
 }
 
 static void convertMJTI(ModuleSlotTracker &MST, yaml::MachineJumpTable &YamlJTI,
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 f66f54682c84c..4fe0a1893843c 100644
--- a/llvm/lib/CodeGen/PrologEpilogInserter.cpp
+++ b/llvm/lib/CodeGen/PrologEpilogInserter.cpp
@@ -351,8 +351,8 @@ bool PEIImpl::run(MachineFunction &MF) {
   delete RS;
   SaveBlocks.clear();
   RestoreBlocks.clear();
-  MFI.setSavePoint(nullptr);
-  MFI.setRestorePoint(nullptr);
+  MFI.clearSavePoints();
+  MFI.clearRestorePoints();
   return true;
 }
 
@@ -423,16 +423,17 @@ void PEIImpl::calculateCallFrameInfo(MachineFunction &MF) {
 /// callee-saved registers, and placing prolog and epilog code.
 void PEIImpl::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.
@@ -441,13 +442,15 @@ void PEIImpl::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);
+    }
   }
 }
 
@@ -558,7 +561,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;
@@ -569,7 +575,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 41e956caa7b34..6121f8b70d9ea 100644
--- a/llvm/lib/CodeGen/ShrinkWrap.cpp
+++ b/llvm/lib/CodeGen/ShrinkWrap.cpp
@@ -967,8 +967,14 @@ bool ShrinkWrapImpl::run(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 9509199a8d5ef..cc0ffb0f70f6d 100644
--- a/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp
+++ b/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp
@@ -209,10 +209,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 c0860fcdaa3b0..860b415484347 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 3f84e8f6c8d40..353e2aed9cd7a 100644
--- a/llvm/tools/llvm-reduce/ReducerWorkItem.cpp
+++ b/llvm/tools/llvm-reduce/ReducerWorkItem.cpp
@@ -92,11 +92,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 b66688f4c3d974d8298703ca4197eb3a1a4650fb 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 04/13] 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 63e28a1c9444a..b413d3f2424fd 100644
--- a/llvm/include/llvm/CodeGen/MachineFrameInfo.h
+++ b/llvm/include/llvm/CodeGen/MachineFrameInfo.h
@@ -825,10 +825,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 4fe0a1893843c..3582a101deaaa 100644
--- a/llvm/lib/CodeGen/PrologEpilogInserter.cpp
+++ b/llvm/lib/CodeGen/PrologEpilogInserter.cpp
@@ -429,10 +429,13 @@ void PEIImpl::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
@@ -562,9 +565,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;
@@ -575,8 +579,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 cc0ffb0f70f6d..b3de4fe45ebb6 100644
--- a/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp
+++ b/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp
@@ -210,10 +210,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 860b415484347..2ad3ed21732ed 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 353e2aed9cd7a..6178e7cb79a2d 100644
--- a/llvm/tools/llvm-reduce/ReducerWorkItem.cpp
+++ b/llvm/tools/llvm-reduce/ReducerWorkItem.cpp
@@ -92,7 +92,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;
@@ -100,7 +101,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 102119c2eecb1486abf78774cd215a7772e5c728 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 05/13] [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  | 133 ++++++++-
 llvm/lib/CodeGen/MIRParser/MIRParser.cpp      |  23 +-
 llvm/lib/CodeGen/MIRPrinter.cpp               |  26 +-
 llvm/lib/CodeGen/MachineFrameInfo.cpp         |   5 +-
 llvm/lib/CodeGen/PrologEpilogInserter.cpp     | 257 +++++++++++++-----
 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  | 103 +++++--
 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   |  81 +++++-
 llvm/test/CodeGen/PowerPC/pr43527.ll          |   2 +-
 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, 784 insertions(+), 319 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/MIRYamlMapping.h b/llvm/include/llvm/CodeGen/MIRYamlMapping.h
index 2fe5496235903..fa9202b83f1a8 100644
--- a/llvm/include/llvm/CodeGen/MIRYamlMapping.h
+++ b/llvm/include/llvm/CodeGen/MIRYamlMapping.h
@@ -638,9 +638,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;
   }
 };
 
@@ -680,6 +681,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 b413d3f2424fd..56e9ad9d4ec70 100644
--- a/llvm/include/llvm/CodeGen/MachineFrameInfo.h
+++ b/llvm/include/llvm/CodeGen/MachineFrameInfo.h
@@ -28,6 +28,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
@@ -38,6 +53,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
@@ -74,6 +91,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
@@ -297,6 +324,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;
@@ -332,10 +363,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;
@@ -814,30 +852,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 2dc535abb3fcc..273cb65295cca 100644
--- a/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
+++ b/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
@@ -1095,8 +1095,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 =
@@ -1107,7 +1110,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);
@@ -1115,17 +1127,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 de9e8a4a147ee..280178059b1af 100644
--- a/llvm/lib/CodeGen/MIRPrinter.cpp
+++ b/llvm/lib/CodeGen/MIRPrinter.cpp
@@ -149,9 +149,9 @@ static void convertMCP(yaml::MachineFunction &MF,
 static void convertMJTI(ModuleSlotTracker &MST, yaml::MachineJumpTable &YamlJTI,
                         const MachineJumpTableInfo &JTI);
 static void convertMFI(ModuleSlotTracker &MST, yaml::MachineFrameInfo &YamlMFI,
-                       const MachineFrameInfo &MFI);
+                       const MachineFrameInfo &MFI, const TargetRegisterInfo *TRI);
 static void convertSRPoints(ModuleSlotTracker &MST, yaml::SaveRestorePoints &YamlSRPoints,
-                            std::vector<MachineBasicBlock *> SaveRestorePoints);
+                            const DenseMap<MachineBasicBlock *, std::vector<Register>> &SRP, const TargetRegisterInfo *TRI);
 static void convertStackObjects(yaml::MachineFunction &YMF,
                                 const MachineFunction &MF,
                                 ModuleSlotTracker &MST, MFPrintState &State);
@@ -202,7 +202,7 @@ static void printMF(raw_ostream &OS, const MachineModuleInfo &MMI,
   convertMRI(YamlMF, MF, MF.getRegInfo(), MF.getSubtarget().getRegisterInfo());
   MachineModuleSlotTracker &MST = State.MST;
   MST.incorporateFunction(MF.getFunction());
-  convertMFI(MST, YamlMF.FrameInfo, MF.getFrameInfo());
+  convertMFI(MST, YamlMF.FrameInfo, MF.getFrameInfo(), MF.getSubtarget().getRegisterInfo());
   convertStackObjects(YamlMF, MF, MST, State);
   convertEntryValueObjects(YamlMF, MF, MST);
   convertCallSiteObjects(YamlMF, MF, MST);
@@ -337,7 +337,7 @@ static void convertMRI(yaml::MachineFunction &YamlMF, const MachineFunction &MF,
 }
 
 static void convertMFI(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();
@@ -358,9 +358,9 @@ static void convertMFI(ModuleSlotTracker &MST, yaml::MachineFrameInfo &YamlMFI,
   YamlMFI.IsCalleeSavedInfoValid = MFI.isCalleeSavedInfoValid();
   YamlMFI.LocalFrameSize = MFI.getLocalFrameSize();
   if (!MFI.getSavePoints().empty())
-    convertSRPoints(MST, YamlMFI.SavePoints, MFI.getSavePoints());
+    convertSRPoints(MST, YamlMFI.SavePoints, MFI.getSavePoints(), TRI);
   if (!MFI.getRestorePoints().empty())
-    convertSRPoints(MST, YamlMFI.RestorePoints, MFI.getRestorePoints());
+    convertSRPoints(MST, YamlMFI.RestorePoints, MFI.getRestorePoints(), TRI);
 }
 
 static void convertEntryValueObjects(yaml::MachineFunction &YMF,
@@ -616,16 +616,24 @@ static void convertMCP(yaml::MachineFunction &MF,
 
 static void convertSRPoints(ModuleSlotTracker &MST,
                             yaml::SaveRestorePoints &YamlSRPoints,
-                            std::vector<MachineBasicBlock *> SRPoints) {
+                            const DenseMap<MachineBasicBlock *, std::vector<Register>> &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());
+        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 3582a101deaaa..ae6a603ae9876 100644
--- a/llvm/lib/CodeGen/PrologEpilogInserter.cpp
+++ b/llvm/lib/CodeGen/PrologEpilogInserter.cpp
@@ -85,8 +85,12 @@ class PEIImpl {
   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;
 
@@ -104,6 +108,7 @@ class PEIImpl {
 
   void calculateCallFrameInfo(MachineFunction &MF);
   void calculateSaveRestoreBlocks(MachineFunction &MF);
+  void calculatePrologEpilogBlocks(MachineFunction &MF);
   void spillCalleeSavedRegs(MachineFunction &MF);
 
   void calculateFrameObjectOffsets(MachineFunction &MF);
@@ -236,14 +241,17 @@ bool PEIImpl::run(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())
@@ -351,6 +359,8 @@ bool PEIImpl::run(MachineFunction &MF) {
   delete RS;
   SaveBlocks.clear();
   RestoreBlocks.clear();
+  PrologBlocks.clear();
+  EpilogBlocks.clear();
   MFI.clearSavePoints();
   MFI.clearRestorePoints();
   return true;
@@ -419,6 +429,25 @@ void PEIImpl::calculateCallFrameInfo(MachineFunction &MF) {
   }
 }
 
+/// Compute two sets of blocks for placing prolog and epilog code respectively.
+void PEIImpl::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 PEIImpl::calculateSaveRestoreBlocks(MachineFunction &MF) {
@@ -429,19 +458,19 @@ void PEIImpl::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;
   }
 
@@ -552,8 +581,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.
@@ -565,11 +594,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;
 
@@ -579,10 +603,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
@@ -602,30 +622,26 @@ 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) {
-      MCRegister 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;
-        MCRegister 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);
     }
   }
 }
@@ -665,6 +681,57 @@ static void insertCSRRestores(MachineBasicBlock &RestoreBlock,
   }
 }
 
+static void fillCSInfoPerBB(
+    SaveRestorePoints SRPoints,
+    DenseMap<MCRegister, 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 PEIImpl::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 +758,79 @@ void PEIImpl::spillCalleeSavedRegs(MachineFunction &MF) {
     MFI.setCalleeSavedInfoValid(true);
 
     std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
+    DenseMap<MCRegister, 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 +1302,26 @@ void PEIImpl::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 +1330,8 @@ void PEIImpl::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 6121f8b70d9ea..725489f5fbf99 100644
--- a/llvm/lib/CodeGen/ShrinkWrap.cpp
+++ b/llvm/lib/CodeGen/ShrinkWrap.cpp
@@ -967,12 +967,15 @@ bool ShrinkWrapImpl::run(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 b3de4fe45ebb6..fd682fda3ebd7 100644
--- a/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp
+++ b/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp
@@ -210,29 +210,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 2ad3ed21732ed..d9be6823dc3d7 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 9fc0d815ceee3..0c1d1da0a91f2 100644
--- a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
@@ -538,9 +538,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;
 
@@ -931,13 +930,13 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
   auto PossiblePush = 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
@@ -1062,15 +1061,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());
-  CFIBuilder.setInsertPoint(MBBI);
-
-  // Iterate over list of callee-saved registers and emit .cfi_offset
-  // directives.
-  if (NeedsDwarfCFI)
-    for (const CalleeSavedInfo &CS : getUnmanagedCSI(MF, CSI))
-      CFIBuilder.buildOffset(CS.getReg(),
-                             MFI.getObjectOffset(CS.getFrameIdx()));
+  int Distance = getUnmanagedCSI(MF, CSI).size();
+  if (!RVFI->isPushable(MF) && !RVFI->useSaveRestoreLibCalls(MF) && NeedsDwarfCFI)
+    Distance *= 2;
+  std::advance(MBBI, Distance);
 
   // Generate new FP.
   if (hasFP(MF)) {
@@ -1227,7 +1221,7 @@ 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
@@ -1238,6 +1232,11 @@ void RISCVFrameLowering::emitEpilogue(MachineFunction &MF,
                             MachineInstr::FrameDestroy);
   bool NeedsDwarfCFI = needsDwarfCFI(MF);
 
+  if (NeedsDwarfCFI) {
+    int Distance = getUnmanagedCSI(MF, CSI).size();
+    std::advance(MBBI, Distance);
+  }
+
   uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF);
   uint64_t RealStackSize = FirstSPAdjustAmount ? FirstSPAdjustAmount
                                                : getStackSizeWithRVVPadding(MF);
@@ -1320,11 +1319,6 @@ void RISCVFrameLowering::emitEpilogue(MachineFunction &MF,
     return;
   }
 
-  // Recover callee-saved registers.
-  if (NeedsDwarfCFI)
-    for (const CalleeSavedInfo &CS : getUnmanagedCSI(MF, CSI))
-      CFIBuilder.buildRestore(CS.getReg());
-
   if (RVFI->isPushable(MF) && MBBI != MBB.end() && isPop(MBBI->getOpcode())) {
     // Use available stack adjustment in pop instruction to deallocate stack
     // space. Align the stack size down to a multiple of 16. This is needed for
@@ -2099,6 +2093,33 @@ bool RISCVFrameLowering::assignCalleeSavedSpillSlots(
   return true;
 }
 
+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;
+}
+
 bool RISCVFrameLowering::spillCalleeSavedRegisters(
     MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
     ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
@@ -2106,12 +2127,12 @@ 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();
 
-  RISCVMachineFunctionInfo *RVFI = MF->getInfo<RISCVMachineFunctionInfo>();
   if (RVFI->useQCIInterrupt(*MF)) {
     // Emit QC.C.MIENTER(.NEST)
     BuildMI(
@@ -2169,6 +2190,36 @@ bool RISCVFrameLowering::spillCalleeSavedRegisters(
     }
   };
   storeRegsToStackSlots(UnmanagedCSI);
+
+  bool NeedsDwarfCFI = needsDwarfCFI(*MF);
+  // Iterate over list of callee-saved registers and emit .cfi_offset
+  // directives.
+  if (NeedsDwarfCFI) {
+    CFIInstBuilder CFIBuilder(MBB, MI, MachineInstr::FrameSetup);
+    MachineFrameInfo &MFI = MF->getFrameInfo();
+
+    for (const CalleeSavedInfo &CS : UnmanagedCSI) {
+      int FrameIdx = CS.getFrameIdx();
+      if (FrameIdx < 0 ||
+          MFI.getStackID(FrameIdx) != TargetStackID::ScalableVector) {
+        int64_t Offset = 0;
+
+        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);
+        }
+        CFIBuilder.buildOffset(CS.getReg(), Offset);
+      }
+    }
+  }
+
   storeRegsToStackSlots(RVVCSI);
 
   return true;
@@ -2263,6 +2314,16 @@ bool RISCVFrameLowering::restoreCalleeSavedRegisters(
   loadRegFromStackSlot(RVVCSI);
   loadRegFromStackSlot(UnmanagedCSI);
 
+  bool NeedsDwarfCFI = needsDwarfCFI(*MF);
+  // Recover callee-saved registers.
+  if (NeedsDwarfCFI) {
+    CFIInstBuilder CFIBuilder(MBB, MI,
+                              MachineInstr::FrameDestroy);
+    for (const CalleeSavedInfo &CS : UnmanagedCSI)
+      CFIBuilder.buildRestore(CS.getReg());
+  }
+  //emitCFIForCSI<CFIRestoreRegisterEmitter>(MBB, MI, UnmanagedCSI);
+
   RISCVMachineFunctionInfo *RVFI = MF->getInfo<RISCVMachineFunctionInfo>();
   if (RVFI->useQCIInterrupt(*MF)) {
     // Don't emit anything here because restoration is handled by
diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.h b/llvm/lib/Target/RISCV/RISCVFrameLowering.h
index 6af63a4885f35..466f33daa54bc 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 7e58b6f342689..be7b930b74026 100644
--- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
@@ -557,12 +557,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 af0942e99182d..6a6c24fdfbeee 100644
--- a/llvm/test/CodeGen/PowerPC/more-dq-form-prepare.ll
+++ b/llvm/test/CodeGen/PowerPC/more-dq-form-prepare.ll
@@ -93,7 +93,6 @@ define void @foo(ptr %.m, ptr %.n, ptr %.a, ptr %.x, ptr %.l, ptr %.vy01, ptr %.
 ; CHECK-NEXT:    std 17, 424(1) # 8-byte Folded Spill
 ; CHECK-NEXT:    ld 23, 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:    ld 25, 800(1)
 ; CHECK-NEXT:    ld 24, 792(1)
@@ -267,6 +266,7 @@ define void @foo(ptr %.m, ptr %.n, ptr %.a, ptr %.x, ptr %.l, ptr %.vy01, ptr %.
 ; CHECK-NEXT:    cmpld 28, 4
 ; CHECK-NEXT:    ble 0, .LBB0_3
 ; CHECK-NEXT:  # %bb.6: # %_loop_1_loopHeader_._return_bb_crit_edge.loopexit
+<<<<<<< HEAD
 ; CHECK-NEXT:    ld 3, 48(1) # 8-byte Folded Reload
 ; CHECK-NEXT:    lxv 63, 384(1) # 16-byte Folded Reload
 ; CHECK-NEXT:    stxv 1, 0(3)
@@ -283,18 +283,28 @@ define void @foo(ptr %.m, ptr %.n, ptr %.a, ptr %.x, ptr %.l, ptr %.vy01, ptr %.
 ; CHECK-NEXT:    lxv 53, 224(1) # 16-byte Folded Reload
 ; CHECK-NEXT:    lxv 52, 208(1) # 16-byte Folded Reload
 ; CHECK-NEXT:    stxv 0, 0(3)
+=======
+; CHECK-NEXT:    ld 3, 56(1) # 8-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:    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)
+>>>>>>> a1ce745b0c3d ([llvm] support multiple save/restore points in prolog-epilog)
 ; 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
+<<<<<<< HEAD
 ; CHECK-NEXT:    stxv 5, 0(3)
 ; CHECK-NEXT:    ld 3, 32(1) # 8-byte Folded Reload
 ; CHECK-NEXT:    ld 26, 496(1) # 8-byte Folded Reload
@@ -312,6 +322,55 @@ define void @foo(ptr %.m, ptr %.n, ptr %.a, ptr %.x, ptr %.l, ptr %.vy01, ptr %.
 ; CHECK-NEXT:    ld 3, 40(1) # 8-byte Folded Reload
 ; CHECK-NEXT:    ld 15, 408(1) # 8-byte Folded Reload
 ; CHECK-NEXT:    ld 14, 400(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:    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:    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)
+; CHECK-NEXT:    ld 3, 88(1) # 8-byte Folded Reload
+; CHECK-NEXT:    stxv 10, 0(3)
+; CHECK-NEXT:    ld 3, 96(1) # 8-byte Folded Reload
+; CHECK-NEXT:    stxv 9, 0(3)
+; CHECK-NEXT:    ld 3, 104(1) # 8-byte Folded Reload
+; CHECK-NEXT:    stxv 8, 0(3)
+; CHECK-NEXT:    ld 3, 112(1) # 8-byte Folded Reload
+; CHECK-NEXT:    stxv 7, 0(3)
+; CHECK-NEXT:    ld 3, 120(1) # 8-byte Folded Reload
+; CHECK-NEXT:    stxv 6, 0(3)
+; CHECK-NEXT:    ld 3, 128(1) # 8-byte Folded Reload
+; CHECK-NEXT:    stxv 5, 0(3)
+; CHECK-NEXT:    ld 3, 136(1) # 8-byte Folded Reload
+; CHECK-NEXT:    stxv 4, 0(3)
+; CHECK-NEXT:    ld 3, 144(1) # 8-byte Folded Reload
+>>>>>>> a1ce745b0c3d ([llvm] support multiple save/restore points in prolog-epilog)
 ; CHECK-NEXT:    stxv 3, 0(3)
 ; CHECK-NEXT:    ld 3, 56(1) # 8-byte Folded Reload
 ; CHECK-NEXT:    stxv 2, 0(8)
diff --git a/llvm/test/CodeGen/PowerPC/pr43527.ll b/llvm/test/CodeGen/PowerPC/pr43527.ll
index adfea51077a0b..e175ea63d059c 100644
--- a/llvm/test/CodeGen/PowerPC/pr43527.ll
+++ b/llvm/test/CodeGen/PowerPC/pr43527.ll
@@ -18,6 +18,7 @@ define dso_local void @test(i64 %arg, i64 %arg1, ptr %arg2) {
 ; 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 r29, -24(r1) # 8-byte Folded Spill
 ; CHECK-NEXT:    stdu r1, -64(r1)
 ; CHECK-NEXT:    mr r30, r5
 ; CHECK-NEXT:    sub r29, r4, r3
@@ -36,7 +37,6 @@ define dso_local void @test(i64 %arg, i64 %arg1, ptr %arg2) {
 ; CHECK-NEXT:  # %bb.4: # %bb15
 ; 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 r28, -32(r1) # 8-byte Folded Reload
 ; CHECK-NEXT:    mtlr r0
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 6178e7cb79a2d..478a565c7f39d 100644
--- a/llvm/tools/llvm-reduce/ReducerWorkItem.cpp
+++ b/llvm/tools/llvm-reduce/ReducerWorkItem.cpp
@@ -92,23 +92,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 5cb467467efb741fb260d1e56fb2edd9afba5029 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 06/13] 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 56e9ad9d4ec70..49debf8f0717f 100644
--- a/llvm/include/llvm/CodeGen/MachineFrameInfo.h
+++ b/llvm/include/llvm/CodeGen/MachineFrameInfo.h
@@ -920,11 +920,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(
@@ -938,10 +935,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 273cb65295cca..52f309d999779 100644
--- a/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
+++ b/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
@@ -1098,7 +1098,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)) {
@@ -1116,7 +1116,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));

>From ec431e2aa4c4bc2c1f858441995c43d7128d0d5e Mon Sep 17 00:00:00 2001
From: ens-sc <elizaveta.noskova at syntacore.com>
Date: Fri, 18 Apr 2025 21:38:32 +0300
Subject: [PATCH 07/13] Review

---
 llvm/include/llvm/CodeGen/MIRYamlMapping.h    |  10 +-
 llvm/include/llvm/CodeGen/MachineFrameInfo.h  | 135 ++++++---------
 llvm/lib/CodeGen/MIRParser/MIRParser.cpp      |  14 +-
 llvm/lib/CodeGen/MIRPrinter.cpp               |   8 +-
 llvm/lib/CodeGen/MachineFrameInfo.cpp         |   4 +-
 llvm/lib/CodeGen/PrologEpilogInserter.cpp     | 155 ++++++++----------
 llvm/lib/CodeGen/ShrinkWrap.cpp               |   9 +-
 llvm/lib/Target/PowerPC/PPCFrameLowering.cpp  |   2 +-
 llvm/lib/Target/RISCV/RISCVFrameLowering.cpp  |  32 ++--
 llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp   |  28 ++--
 ...nfo-multiple-save-restore-points-parse.mir |  81 ---------
 .../X86/frame-info-save-restore-points.mir    |  10 +-
 .../X86/cfi-epilogue-without-return.mir       |   4 +-
 .../llvm-reduce/mir/preserve-frame-info.mir   |   6 +-
 14 files changed, 184 insertions(+), 314 deletions(-)
 delete mode 100644 llvm/test/CodeGen/MIR/X86/frame-info-multiple-save-restore-points-parse.mir

diff --git a/llvm/include/llvm/CodeGen/MIRYamlMapping.h b/llvm/include/llvm/CodeGen/MIRYamlMapping.h
index fa9202b83f1a8..ff8a177ac2a86 100644
--- a/llvm/include/llvm/CodeGen/MIRYamlMapping.h
+++ b/llvm/include/llvm/CodeGen/MIRYamlMapping.h
@@ -634,8 +634,12 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::CalledGlobal)
 namespace llvm {
 namespace yaml {
 
-// Struct representing one save/restore point in the 'savePoint'/'restorePoint'
-// list
+// Struct representing one save/restore point in the
+// 'savePoint' / 'restorePoint' list. One point consist of machine basic block
+// name and list of saved/restored in this basic block registers. Generally
+// 'registers' is not obligatory field, if this field is not specified, it is
+// assumed to be equal to the list of all CalleeSavedRegisters, calculated
+// during PEI
 struct SaveRestorePointEntry {
   StringValue Point;
   std::vector<StringValue> Registers;
@@ -681,7 +685,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);
+    YamlIO.mapOptional("registers", Entry.Registers);
   }
 };
 
diff --git a/llvm/include/llvm/CodeGen/MachineFrameInfo.h b/llvm/include/llvm/CodeGen/MachineFrameInfo.h
index 49debf8f0717f..0d6d1011a771f 100644
--- a/llvm/include/llvm/CodeGen/MachineFrameInfo.h
+++ b/llvm/include/llvm/CodeGen/MachineFrameInfo.h
@@ -28,21 +28,6 @@ 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
@@ -53,8 +38,6 @@ 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
@@ -91,16 +74,34 @@ 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);
+};
+
+class SaveRestorePoints {
+public:
+  using PointsMap = DenseMap<MachineBasicBlock *, std::vector<CalleeSavedInfo>>;
+
+private:
+  PointsMap Map;
+
+public:
+  const PointsMap &get() const { return Map; }
+
+  const std::vector<CalleeSavedInfo> getCSInfo(MachineBasicBlock *MBB) const {
+    return Map.lookup(MBB);
   }
-  void setRestoredIn(std::vector<MachineBasicBlock *> BBV) {
-    RestoredIn = std::move(BBV);
+
+  void set(PointsMap CSI) { Map = std::move(CSI); }
+
+  MachineBasicBlock *findAny(const CalleeSavedInfo &Match) const {
+    for (auto [BB, CSIV] : Map)
+      for (auto &CSI : CSIV)
+        if (CSI.getReg() == Match.getReg())
+          return BB;
+    return nullptr;
   }
+
+  void clear() { Map.clear(); }
+  bool empty() const { return Map.empty(); }
 };
 
 /// The MachineFrameInfo class represents an abstract stack frame until
@@ -324,10 +325,6 @@ 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;
@@ -854,35 +851,30 @@ class MachineFrameInfo {
 
   /// Returns callee saved info vector for provided save point in
   /// the current function.
-  std::vector<CalleeSavedInfo> getCSInfoPerSave(MachineBasicBlock *MBB) const {
-    return CSInfoPerSave.get(MBB);
+  const std::vector<CalleeSavedInfo>
+  getSaveCSInfo(MachineBasicBlock *MBB) const {
+    return SavePoints.getCSInfo(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);
+  const std::vector<CalleeSavedInfo>
+  getRestoreCSInfo(MachineBasicBlock *MBB) const {
+    return RestorePoints.getCSInfo(MBB);
   }
 
-  /// Used by prolog/epilog inserter to set the function's callee saved
-  /// information.
-  void setCalleeSavedInfo(std::vector<CalleeSavedInfo> CSI) {
-    CSInfo = std::move(CSI);
+  MachineBasicBlock *findSpilledIn(const CalleeSavedInfo &CSI) const {
+    return SavePoints.findAny(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);
+  MachineBasicBlock *findRestoredIn(const CalleeSavedInfo &CSI) const {
+    return RestorePoints.findAny(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);
+  /// information.
+  void setCalleeSavedInfo(std::vector<CalleeSavedInfo> CSI) {
+    CSInfo = std::move(CSI);
   }
 
   /// Has the callee saved info been calculated yet?
@@ -890,54 +882,31 @@ class MachineFrameInfo {
 
   void setCalleeSavedInfoValid(bool v) { CSIValid = v; }
 
-  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);
+  const SaveRestorePoints::PointsMap &getRestorePoints() const {
+    return RestorePoints.get();
   }
 
-  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 SaveRestorePoints::PointsMap &getSavePoints() const {
+    return SavePoints.get();
   }
 
-  void setSavePoints(SaveRestorePoints NewSavePoints) {
-    SavePoints = std::move(NewSavePoints);
+  void setSavePoints(SaveRestorePoints::PointsMap NewSavePoints) {
+    SavePoints.set(NewSavePoints);
   }
 
-  void setRestorePoints(SaveRestorePoints NewRestorePoints) {
-    RestorePoints = std::move(NewRestorePoints);
+  void setRestorePoints(SaveRestorePoints::PointsMap NewRestorePoints) {
+    RestorePoints.set(NewRestorePoints);
   }
 
-  void setSavePoint(MachineBasicBlock *MBB, const std::vector<Register> &Regs) {
-    SavePoints[MBB] = Regs;
-  }
-
-  static const SaveRestorePoints constructSaveRestorePoints(
-      const SaveRestorePoints &SRP,
+  static const SaveRestorePoints::PointsMap constructSaveRestorePoints(
+      const SaveRestorePoints::PointsMap &SRPoints,
       const DenseMap<MachineBasicBlock *, MachineBasicBlock *> &BBMap) {
-    SaveRestorePoints Pts{};
-    for (auto &Src : SRP) {
-      Pts.insert(std::make_pair(BBMap.find(Src.first)->second, Src.second));
-    }
+    SaveRestorePoints::PointsMap Pts{};
+    for (auto &Src : SRPoints)
+      Pts.insert({BBMap.find(Src.first)->second, Src.second});
     return Pts;
   }
 
-  void setRestorePoint(MachineBasicBlock *MBB, std::vector<Register> &Regs) {
-    RestorePoints[MBB] = Regs;
-  }
-
   MachineBasicBlock *getProlog() const { return Prolog; }
   void setProlog(MachineBasicBlock *BB) { Prolog = BB; }
   MachineBasicBlock *getEpilog() const { return Epilog; }
diff --git a/llvm/lib/CodeGen/MIRParser/MIRParser.cpp b/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
index 52f309d999779..9e7846c846921 100644
--- a/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
+++ b/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
@@ -1097,8 +1097,9 @@ bool MIRParserImpl::initializeSaveRestorePoints(
     bool IsSavePoints) {
   SMDiagnostic Error;
   MachineBasicBlock *MBB = nullptr;
-  llvm::SaveRestorePoints SRPoints;
-  std::vector<Register> Registers;
+  llvm::SaveRestorePoints::PointsMap SRPoints;
+  MachineFunction &MF = PFS.MF;
+  MachineFrameInfo &MFI = MF.getFrameInfo();
 
   if (std::holds_alternative<std::vector<yaml::SaveRestorePointEntry>>(
           YamlSRPoints)) {
@@ -1106,17 +1107,17 @@ bool MIRParserImpl::initializeSaveRestorePoints(
         std::get<std::vector<yaml::SaveRestorePointEntry>>(YamlSRPoints);
     if (VectorRepr.empty())
       return false;
+    std::vector<CalleeSavedInfo> Registers;
     for (const auto &Entry : VectorRepr) {
       const auto &MBBSource = Entry.Point;
       if (parseMBBReference(PFS, MBB, MBBSource.Value))
         return true;
-
       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);
+        Registers.push_back(CalleeSavedInfo(Reg));
       }
       SRPoints.insert(std::make_pair(MBB, Registers));
     }
@@ -1126,12 +1127,9 @@ bool MIRParserImpl::initializeSaveRestorePoints(
       return false;
     if (parseMBBReference(PFS, MBB, StringRepr))
       return true;
-    SRPoints.insert(std::make_pair(MBB, Registers));
+    SRPoints.insert(std::make_pair(MBB, MFI.getCalleeSavedInfo()));
   }
 
-  MachineFunction &MF = PFS.MF;
-  MachineFrameInfo &MFI = MF.getFrameInfo();
-
   if (IsSavePoints)
     MFI.setSavePoints(SRPoints);
   else
diff --git a/llvm/lib/CodeGen/MIRPrinter.cpp b/llvm/lib/CodeGen/MIRPrinter.cpp
index 280178059b1af..064751341260c 100644
--- a/llvm/lib/CodeGen/MIRPrinter.cpp
+++ b/llvm/lib/CodeGen/MIRPrinter.cpp
@@ -151,7 +151,7 @@ static void convertMJTI(ModuleSlotTracker &MST, yaml::MachineJumpTable &YamlJTI,
 static void convertMFI(ModuleSlotTracker &MST, yaml::MachineFrameInfo &YamlMFI,
                        const MachineFrameInfo &MFI, const TargetRegisterInfo *TRI);
 static void convertSRPoints(ModuleSlotTracker &MST, yaml::SaveRestorePoints &YamlSRPoints,
-                            const DenseMap<MachineBasicBlock *, std::vector<Register>> &SRP, const TargetRegisterInfo *TRI);
+                            const llvm::SaveRestorePoints::PointsMap &SRP, const TargetRegisterInfo *TRI);
 static void convertStackObjects(yaml::MachineFunction &YMF,
                                 const MachineFunction &MF,
                                 ModuleSlotTracker &MST, MFPrintState &State);
@@ -616,7 +616,7 @@ static void convertMCP(yaml::MachineFunction &MF,
 
 static void convertSRPoints(ModuleSlotTracker &MST,
                             yaml::SaveRestorePoints &YamlSRPoints,
-                            const DenseMap<MachineBasicBlock *, std::vector<Register>> &SRPoints, 
+                            const llvm::SaveRestorePoints::PointsMap &SRPoints, 
                             const TargetRegisterInfo *TRI) {
   auto &Points =
       std::get<std::vector<yaml::SaveRestorePointEntry>>(YamlSRPoints);
@@ -628,8 +628,8 @@ static void convertSRPoints(ModuleSlotTracker &MST,
     Entry.Point = StrOS.str().str();
     Str.clear();
     for (auto &Reg : MBBEntry.second) {
-      if (Reg != MCRegister::NoRegister) {
-        StrOS << printReg(Reg, TRI);
+      if (Reg.getReg()) {
+        StrOS << printReg(Reg.getReg(), TRI);
         Entry.Registers.push_back(StrOS.str().str());
         Str.clear();
       }
diff --git a/llvm/lib/CodeGen/MachineFrameInfo.cpp b/llvm/lib/CodeGen/MachineFrameInfo.cpp
index c6658d2e9eba8..4c98e8a2dd52d 100644
--- a/llvm/lib/CodeGen/MachineFrameInfo.cpp
+++ b/llvm/lib/CodeGen/MachineFrameInfo.cpp
@@ -250,14 +250,14 @@ void MachineFrameInfo::print(const MachineFunction &MF, raw_ostream &OS) const{
   if (!SavePoints.empty()) {
     OS << "save points:\n";
 
-    for (auto &item : SavePoints)
+    for (auto &item : SavePoints.get())
       OS << printMBBReference(*item.first) << "\n";
   } else
     OS << "save points are empty\n";
 
   if (!RestorePoints.empty()) {
     OS << "restore points:\n";
-    for (auto &item : RestorePoints)
+    for (auto &item : RestorePoints.get())
       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 ae6a603ae9876..0a5c5f3423aca 100644
--- a/llvm/lib/CodeGen/PrologEpilogInserter.cpp
+++ b/llvm/lib/CodeGen/PrologEpilogInserter.cpp
@@ -474,15 +474,13 @@ void PEIImpl::calculateSaveRestoreBlocks(MachineFunction &MF) {
     return;
   }
 
-  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);
-    }
+  // 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);
   }
 }
 
@@ -664,7 +662,7 @@ static void insertCSRSaves(MachineBasicBlock &SaveBlock,
 
 /// Insert restore code for the callee-saved registers used in the function.
 static void insertCSRRestores(MachineBasicBlock &RestoreBlock,
-                              std::vector<CalleeSavedInfo> &CSI) {
+                              std::vector<CalleeSavedInfo> CSI) {
   MachineFunction &MF = *RestoreBlock.getParent();
   const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
   const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering();
@@ -681,55 +679,55 @@ static void insertCSRRestores(MachineBasicBlock &RestoreBlock,
   }
 }
 
-static void fillCSInfoPerBB(
-    SaveRestorePoints SRPoints,
-    DenseMap<MCRegister, CalleeSavedInfo *> &RegToInfo,
-    DenseMap<MachineBasicBlock *, std::vector<CalleeSavedInfo>> &CSInfoPerBB,
-    bool isSave, MBBVector &PrologEpilogBlocks) {
+static void fillCSInfoPerBB(MachineFrameInfo &MFI,
+                            DenseMap<MCRegister, CalleeSavedInfo *> &RegToInfo,
+                            MBBVector &PrologEpilogBlocks, bool isSave) {
   std::vector<CalleeSavedInfo> CSIV = {};
   std::vector<CalleeSavedInfo> GCSIV = {};
+  const SaveRestorePoints::PointsMap &SRPoints =
+      isSave ? MFI.getSavePoints() : MFI.getRestorePoints();
+  SaveRestorePoints::PointsMap Inner;
   for (auto [BB, Regs] : SRPoints) {
     CSIV.clear();
     for (auto &Reg : Regs) {
-      auto It = RegToInfo.find(Reg);
+      auto It = RegToInfo.find(Reg.getReg());
       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));
+      CSIV.push_back(*RegToInfo.at(Reg.getReg()));
+      GCSIV.push_back(*RegToInfo.at(Reg.getReg()));
     }
     std::sort(CSIV.begin(), CSIV.end(),
               [](const CalleeSavedInfo &Lhs, const CalleeSavedInfo &Rhs) {
                 return Lhs.getFrameIdx() < Rhs.getFrameIdx();
               });
-    CSInfoPerBB.insert(std::make_pair(BB, CSIV));
+    Inner.insert({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();
-                  });
+  if (GCSIV.size() < RegToInfo.size()) {
+    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 (Inner.contains(BB)) {
+          Inner[BB].push_back(*RTI.second);
+          std::sort(Inner[BB].begin(), Inner[BB].end(),
+                    [](const CalleeSavedInfo &Lhs, const CalleeSavedInfo &Rhs) {
+                      return Lhs.getFrameIdx() < Rhs.getFrameIdx();
+                    });
+        }
+        CSIV.clear();
+        CSIV.push_back(*RTI.second);
+        Inner.insert(std::make_pair(BB, CSIV));
       }
-      CSIV.clear();
-      CSIV.push_back(*RTI.second);
-      CSInfoPerBB.insert(std::make_pair(BB, CSIV));
     }
   }
+
+  if (isSave)
+    MFI.setSavePoints(Inner);
+  else
+    MFI.setRestorePoints(Inner);
 }
 
 void PEIImpl::spillCalleeSavedRegs(MachineFunction &MF) {
@@ -759,27 +757,17 @@ void PEIImpl::spillCalleeSavedRegs(MachineFunction &MF) {
 
     std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
     DenseMap<MCRegister, CalleeSavedInfo *> RegToInfo;
-    for (auto &CS : CSI) {
-      RegToInfo.insert(std::make_pair(CS.getReg(), &CS));
-    }
+    for (auto &CS : CSI)
+      RegToInfo.insert({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);
+      fillCSInfoPerBB(MFI, RegToInfo, PrologBlocks, true /* isSave */);
+      fillCSInfoPerBB(MFI, RegToInfo, EpilogBlocks, false /* isSave */);
     } else {
-      for (MachineBasicBlock *PrologBlock : PrologBlocks) {
-        CSInfoPerSave.insert(
-            std::make_pair(PrologBlock, MFI.getCalleeSavedInfo()));
-
-        for (auto &CS : CSI) {
-          CS.addSpilledIn(PrologBlock);
-        }
-      }
+      SaveRestorePoints::PointsMap SavePts;
+      for (MachineBasicBlock *PrologBlock : PrologBlocks)
+        SavePts.insert({PrologBlock, MFI.getCalleeSavedInfo()});
+      MFI.setSavePoints(SavePts);
     }
 
     if (!CSI.empty()) {
@@ -787,26 +775,19 @@ void PEIImpl::spillCalleeSavedRegs(MachineFunction &MF) {
         NumLeafFuncWithSpills++;
 
       for (MachineBasicBlock *SaveBlock : SaveBlocks)
-        insertCSRSaves(*SaveBlock,
-                       CSInfoPerSave.empty() ? CSI : CSInfoPerSave[SaveBlock]);
+        insertCSRSaves(*SaveBlock, MFI.getSavePoints().empty()
+                                       ? CSI
+                                       : MFI.getSaveCSInfo(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;
+          if (auto BB = MFI.findSpilledIn(CS))
+            Save = BB;
+
+          if (auto BB = MFI.findRestoredIn(CS))
+            Restore = BB;
         }
         // Update the live-in information of all the blocks up to the save
         // point.
@@ -814,23 +795,19 @@ void PEIImpl::spillCalleeSavedRegs(MachineFunction &MF) {
       }
 
       if (MFI.getRestorePoints().empty()) {
-        for (MachineBasicBlock *EpilogBlock : EpilogBlocks) {
-          CSInfoPerRestore.insert(
-              std::make_pair(EpilogBlock, MFI.getCalleeSavedInfo()));
-
-          for (auto &CS : CSI)
-            CS.addRestoredIn(EpilogBlock);
-        }
+        SaveRestorePoints::PointsMap RestorePts;
+        for (MachineBasicBlock *EpilogBlock : EpilogBlocks)
+          RestorePts.insert({EpilogBlock, MFI.getCalleeSavedInfo()});
+        MFI.setRestorePoints(RestorePts);
       }
 
-      for (MachineBasicBlock *RestoreBlock : RestoreBlocks)
-        insertCSRRestores(*RestoreBlock, CSInfoPerRestore.empty()
-                                             ? CSI
-                                             : CSInfoPerRestore[RestoreBlock]);
+      for (MachineBasicBlock *RestoreBlock : RestoreBlocks) {
+        insertCSRRestores(*RestoreBlock,
+                          MFI.getRestorePoints().empty()
+                              ? CSI
+                              : MFI.getRestoreCSInfo(RestoreBlock));
+      }
     }
-
-    MFI.setCSInfoPerSave(CSInfoPerSave);
-    MFI.setCSInfoPerRestore(CSInfoPerRestore);
   }
 }
 
diff --git a/llvm/lib/CodeGen/ShrinkWrap.cpp b/llvm/lib/CodeGen/ShrinkWrap.cpp
index 725489f5fbf99..b2592e177ee1d 100644
--- a/llvm/lib/CodeGen/ShrinkWrap.cpp
+++ b/llvm/lib/CodeGen/ShrinkWrap.cpp
@@ -957,6 +957,7 @@ bool ShrinkWrapImpl::run(MachineFunction &MF) {
   bool HasCandidate = performShrinkWrapping(RPOT, RS.get());
   StackAddressUsedBlockInfo.clear();
   Changed = postShrinkWrapping(HasCandidate, MF, RS.get());
+
   if (!HasCandidate && !Changed)
     return false;
   if (!ArePointsInteresting())
@@ -968,13 +969,13 @@ bool ShrinkWrapImpl::run(MachineFunction &MF) {
 
   MachineFrameInfo &MFI = MF.getFrameInfo();
 
-  std::vector<Register> CSRVec;
+  std::vector<CalleeSavedInfo> CSIVec;
   SetOfRegs CSRSet = getCurrentCSRs(RS.get());
   for (unsigned Reg : CSRSet)
-    CSRVec.push_back(Reg);
+    CSIVec.push_back(CalleeSavedInfo(Reg));
 
-  llvm::SaveRestorePoints SavePoints({{Save, CSRVec}});
-  llvm::SaveRestorePoints RestorePoints({{Restore, CSRVec}});
+  SaveRestorePoints::PointsMap SavePoints({{Save, CSIVec}});
+  SaveRestorePoints::PointsMap RestorePoints({{Restore, CSIVec}});
 
   MFI.setSavePoints(SavePoints);
   MFI.setRestorePoints(RestorePoints);
diff --git a/llvm/lib/Target/PowerPC/PPCFrameLowering.cpp b/llvm/lib/Target/PowerPC/PPCFrameLowering.cpp
index d9be6823dc3d7..4cd6dd2f8d789 100644
--- a/llvm/lib/Target/PowerPC/PPCFrameLowering.cpp
+++ b/llvm/lib/Target/PowerPC/PPCFrameLowering.cpp
@@ -2080,7 +2080,7 @@ void PPCFrameLowering::processFunctionBeforeFrameFinalized(MachineFunction &MF,
   // RestoreBlock. So we handle this case here.
   if (!MFI.getSavePoints().empty() && MFI.hasTailCall()) {
     for (MachineBasicBlock &MBB : MF) {
-      if (MBB.isReturnBlock() && (!MFI.getRestorePoint(&MBB).first))
+      if (MBB.isReturnBlock() && (!MFI.getRestorePoints().contains(&MBB)))
         createTailCallBranchInstr(MBB);
     }
   }
diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
index 0c1d1da0a91f2..648ddc022ee5c 100644
--- a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
@@ -930,21 +930,28 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
   auto PossiblePush = MBBI;
 
   // Skip past all callee-saved register spill instructions.
-  while (MBBI != MBB.end() && MBBI->getFlag(MachineInstr::FrameSetup) && !MBBI->isCFIInstruction())
+  while (MBBI != MBB.end() && MBBI->getFlag(MachineInstr::FrameSetup))
     ++MBBI;
 
   // Determine the correct frame layout
   determineFrameLayout(MF);
 
-  const auto &CSI = MFI.getCSInfoPerSave(&MBB);
+  const auto &CSI = MFI.getSaveCSInfo(&MBB);
 
   // Skip to before the spills of scalar callee-saved registers
   // FIXME: assumes exactly one instruction is used to restore each
   // callee-saved register.
-  MBBI = std::prev(MBBI, getRVVCalleeSavedInfo(MF, CSI).size() +
-                             getUnmanagedCSI(MF, CSI).size());
   CFIInstBuilder CFIBuilder(MBB, MBBI, MachineInstr::FrameSetup);
   bool NeedsDwarfCFI = needsDwarfCFI(MF);
+  // For scalar spills we skip 2 instrs at once, because right after
+  // spills there are cfi instructions. At the moment of prolog emission they
+  // are already inserted for scalar instructions, but not for vector
+  // instructions.
+  int ScalarDistance = getUnmanagedCSI(MF, CSI).size();
+  if (NeedsDwarfCFI)
+    ScalarDistance *= 2;
+  int VectorDistance = getRVVCalleeSavedInfo(MF, CSI).size();
+  MBBI = std::prev(MBBI, VectorDistance + ScalarDistance);
 
   // If libcalls are used to spill and restore callee-saved registers, the frame
   // has two sections; the opaque section managed by the libcalls, and the
@@ -1062,6 +1069,7 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
   // FIXME: assumes exactly one instruction is used to save each callee-saved
   // register.
   int Distance = getUnmanagedCSI(MF, CSI).size();
+  // Skip scalar CSR spills and corresponding cfi instrs
   if (!RVFI->isPushable(MF) && !RVFI->useSaveRestoreLibCalls(MF) && NeedsDwarfCFI)
     Distance *= 2;
   std::advance(MBBI, Distance);
@@ -1221,7 +1229,7 @@ void RISCVFrameLowering::emitEpilogue(MachineFunction &MF,
       --MBBI;
   }
 
-  const auto &CSI = MFI.getCSInfoPerRestore(&MBB);
+  const auto &CSI = MFI.getRestoreCSInfo(&MBB);
 
   // Skip to before the restores of scalar callee-saved registers
   // FIXME: assumes exactly one instruction is used to restore each
@@ -1232,10 +1240,6 @@ void RISCVFrameLowering::emitEpilogue(MachineFunction &MF,
                             MachineInstr::FrameDestroy);
   bool NeedsDwarfCFI = needsDwarfCFI(MF);
 
-  if (NeedsDwarfCFI) {
-    int Distance = getUnmanagedCSI(MF, CSI).size();
-    std::advance(MBBI, Distance);
-  }
 
   uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF);
   uint64_t RealStackSize = FirstSPAdjustAmount ? FirstSPAdjustAmount
@@ -1303,8 +1307,11 @@ void RISCVFrameLowering::emitEpilogue(MachineFunction &MF,
   // Skip to after the restores of scalar callee-saved registers
   // FIXME: assumes exactly one instruction is used to restore each
   // callee-saved register.
-  MBBI = std::next(FirstScalarCSRRestoreInsn, getUnmanagedCSI(MF, CSI).size());
-  CFIBuilder.setInsertPoint(MBBI);
+  // Skip CSR restore + corresponding cfi restore instruction
+  int ScalarDistance = getUnmanagedCSI(MF, CSI).size();
+  if (NeedsDwarfCFI)
+    ScalarDistance *= 2;
+  MBBI = std::next(FirstScalarCSRRestoreInsn, ScalarDistance);
 
   if (getLibCallID(MF, CSI) != -1) {
     // tail __riscv_restore_[0-12] instruction is considered as a terminator,
@@ -2127,12 +2134,12 @@ 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();
 
+  RISCVMachineFunctionInfo *RVFI = MF->getInfo<RISCVMachineFunctionInfo>();
   if (RVFI->useQCIInterrupt(*MF)) {
     // Emit QC.C.MIENTER(.NEST)
     BuildMI(
@@ -2147,6 +2154,7 @@ bool RISCVFrameLowering::spillCalleeSavedRegisters(
       MBB.addLiveIn(Reg);
   }
 
+  // Emit CM.PUSH with base SPimm & evaluate Push stack
   if (RVFI->isPushable(*MF)) {
     // Emit CM.PUSH with base StackAdj & evaluate Push stack
     unsigned PushedRegNum = RVFI->getRVPushRegs();
diff --git a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
index be7b930b74026..926452bd67f21 100644
--- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
@@ -581,22 +581,22 @@ bool RISCVRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
         return CS.getFrameIdx() == FrameIndex;
       });
 
-      if (It != CSI.end()) {
-        if (MI.mayStore() && !It->spilledIn().empty())
-          SpilledIn = *It->spilledIn().begin();
+      assert(It != CSI.end() &&
+             "Did't find CalleeSavedInfo for CalleeSaved FrameIndex");
+
+      if (MI.mayStore())
+        SpilledIn = MFI.findSpilledIn(*It);
+
+      else if (MI.mayLoad())
+        RestoredIn = MFI.findRestoredIn(*It);
 
-        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();
-      }
+      // If we didn't managed to find NCD (NCPD) for the list of Save (Restore)
+      // blocks, spill (restore) will be unconditionally in Prolog (Epilog)
+      if (MI.mayStore() && MFI.getProlog())
+        SpilledRestoredInPrologEpilog = SpilledIn == MFI.getProlog();
+      else if (MI.mayLoad() && MFI.getEpilog())
+        SpilledRestoredInPrologEpilog = RestoredIn == 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
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
deleted file mode 100644
index 4c60ccd573595..0000000000000
--- a/llvm/test/CodeGen/MIR/X86/frame-info-multiple-save-restore-points-parse.mir
+++ /dev/null
@@ -1,81 +0,0 @@
-# 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/CodeGen/MIR/X86/frame-info-save-restore-points.mir b/llvm/test/CodeGen/MIR/X86/frame-info-save-restore-points.mir
index 2bd5cd853210b..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
@@ -32,20 +32,14 @@ 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:
-    - point:           '%bb.2'
-      registers:       []
-  restorePoint:
-    - point:           '%bb.2'
-      registers:       []
+  savePoint:     '%bb.2'
+  restorePoint:  '%bb.2'
 stack:
   - { id: 0, name: tmp, offset: 0, size: 4, alignment: 4 }
 body: |
diff --git a/llvm/test/CodeGen/X86/cfi-epilogue-without-return.mir b/llvm/test/CodeGen/X86/cfi-epilogue-without-return.mir
index b701569b8ad7d..73e07d0c28335 100644
--- a/llvm/test/CodeGen/X86/cfi-epilogue-without-return.mir
+++ b/llvm/test/CodeGen/X86/cfi-epilogue-without-return.mir
@@ -28,7 +28,7 @@ liveins:
 frameInfo:
   maxAlignment:    1
   hasCalls:        true
-  savePoints:
+  savePoint:
     - point:           '%bb.1'
       registers:
         - '$rbx'
@@ -36,7 +36,7 @@ frameInfo:
         - '$r13'
         - '$r14'
         - '$r15'
-  restorePoints:
+  restorePoint:
     - point:           '%bb.1'
       registers:
         - '$rbx'
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 e47fd689912b1..17e042bf2df8c 100644
--- a/llvm/test/tools/llvm-reduce/mir/preserve-frame-info.mir
+++ b/llvm/test/tools/llvm-reduce/mir/preserve-frame-info.mir
@@ -22,10 +22,10 @@
 # RESULT-NEXT: hasTailCall:     true
 # RESULT-NEXT: savePoint:
 # RESULT-NEXT:   - point:           '%bb.1'
-# RESULT-NEXT: restorePoint:
-# RESULT-NEXT:   - point:           '%bb.1'
+# RESULT: restorePoint:
+# RESULT-NEXT:   - point:           '%bb.2'
 
-# RESULT-NEXT: fixedStack:
+# RESULT: fixedStack:
 # RESULT-NEXT:  - { id: 0, offset: 56, size: 4, alignment: 8, callee-saved-register: '$sgpr44',
 # RESULT-NEXT:      callee-saved-restored: false }
 # RESULT-NEXT:  - { id: 1, offset: 52, size: 4, alignment: 4, callee-saved-register: '$sgpr43' }

>From c64a2d9f1786418cd5fb2894f355e00784e491ca Mon Sep 17 00:00:00 2001
From: ens-sc <elizaveta.noskova at syntacore.com>
Date: Wed, 23 Apr 2025 18:31:21 +0300
Subject: [PATCH 08/13] Review

---
 llvm/include/llvm/CodeGen/MIRYamlMapping.h    | 28 +++++-
 llvm/include/llvm/CodeGen/MachineFrameInfo.h  | 12 ++-
 llvm/lib/CodeGen/MIRParser/MIRParser.cpp      |  4 +-
 llvm/lib/CodeGen/MIRPrinter.cpp               | 11 +++
 llvm/lib/CodeGen/MachineFrameInfo.cpp         |  4 +-
 llvm/lib/CodeGen/PrologEpilogInserter.cpp     | 28 ++++--
 llvm/lib/Target/RISCV/RISCVFrameLowering.cpp  | 12 +--
 .../dont-shrink-wrap-stack-mayloadorstore.mir |  6 ++
 ...nfo-multiple-save-restore-points-parse.mir | 91 +++++++++++++++++++
 .../X86/frame-info-save-restore-points.mir    |  2 +
 .../CodeGen/X86/shrink_wrap_dbg_value.mir     |  8 ++
 .../llvm-reduce/mir/preserve-frame-info.mir   |  6 +-
 12 files changed, 180 insertions(+), 32 deletions(-)
 create mode 100644 llvm/test/CodeGen/MIR/X86/frame-info-multiple-save-restore-points-parse.mir

diff --git a/llvm/include/llvm/CodeGen/MIRYamlMapping.h b/llvm/include/llvm/CodeGen/MIRYamlMapping.h
index ff8a177ac2a86..412c45a6396ea 100644
--- a/llvm/include/llvm/CodeGen/MIRYamlMapping.h
+++ b/llvm/include/llvm/CodeGen/MIRYamlMapping.h
@@ -636,10 +636,28 @@ namespace yaml {
 
 // Struct representing one save/restore point in the
 // 'savePoint' / 'restorePoint' list. One point consist of machine basic block
-// name and list of saved/restored in this basic block registers. Generally
-// 'registers' is not obligatory field, if this field is not specified, it is
-// assumed to be equal to the list of all CalleeSavedRegisters, calculated
-// during PEI
+// name and list of saved/restored in this basic block registers. There are
+// two forms of Save/Restore point representation:
+// 1. Without explicit register enumeration:
+//      savePoint:       '%bb.n'
+//      restorePoint:    '%bb.n'
+// supported for backward compatibility (in this case we assume that all
+// CalleeSavedRegisters are splilled/restored in these points)
+// 2. With explicit register:
+//  savePoint:
+//    - point:           '%bb.1'
+//      registers:
+//        - '$rbx'
+//        - '$r12'
+//        ...
+//  restorePoint:
+//    - point:           '%bb.1'
+//      registers:
+//        - '$rbx'
+//        - '$r12'
+// If this representation form is used and no register is saved/restored in the
+// selected BB, the empty list of register should be specified ( i.e. registers:
+// [])
 struct SaveRestorePointEntry {
   StringValue Point;
   std::vector<StringValue> Registers;
@@ -685,7 +703,7 @@ template <> struct PolymorphicTraits<SaveRestorePoints> {
 template <> struct MappingTraits<SaveRestorePointEntry> {
   static void mapping(IO &YamlIO, SaveRestorePointEntry &Entry) {
     YamlIO.mapRequired("point", Entry.Point);
-    YamlIO.mapOptional("registers", Entry.Registers);
+    YamlIO.mapRequired("registers", Entry.Registers);
   }
 };
 
diff --git a/llvm/include/llvm/CodeGen/MachineFrameInfo.h b/llvm/include/llvm/CodeGen/MachineFrameInfo.h
index 0d6d1011a771f..8765f7cbc4f4b 100644
--- a/llvm/include/llvm/CodeGen/MachineFrameInfo.h
+++ b/llvm/include/llvm/CodeGen/MachineFrameInfo.h
@@ -90,13 +90,15 @@ class SaveRestorePoints {
     return Map.lookup(MBB);
   }
 
-  void set(PointsMap CSI) { Map = std::move(CSI); }
+  void set(PointsMap &&CSI) { Map = std::move(CSI); }
 
   MachineBasicBlock *findAny(const CalleeSavedInfo &Match) const {
-    for (auto [BB, CSIV] : Map)
-      for (auto &CSI : CSIV)
+    for (auto [BB, CSIV] : Map) {
+      for (auto &CSI : CSIV) {
         if (CSI.getReg() == Match.getReg())
           return BB;
+      }
+    }
     return nullptr;
   }
 
@@ -891,11 +893,11 @@ class MachineFrameInfo {
   }
 
   void setSavePoints(SaveRestorePoints::PointsMap NewSavePoints) {
-    SavePoints.set(NewSavePoints);
+    SavePoints.set(std::move(NewSavePoints));
   }
 
   void setRestorePoints(SaveRestorePoints::PointsMap NewRestorePoints) {
-    RestorePoints.set(NewRestorePoints);
+    RestorePoints.set(std::move(NewRestorePoints));
   }
 
   static const SaveRestorePoints::PointsMap constructSaveRestorePoints(
diff --git a/llvm/lib/CodeGen/MIRParser/MIRParser.cpp b/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
index 9e7846c846921..f64f7f7e42df7 100644
--- a/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
+++ b/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
@@ -872,10 +872,10 @@ bool MIRParserImpl::initializeFrameInfo(PerFunctionMIParsingState &PFS,
   MFI.setCalleeSavedInfoValid(YamlMFI.IsCalleeSavedInfoValid);
   MFI.setLocalFrameSize(YamlMFI.LocalFrameSize);
   if (initializeSaveRestorePoints(PFS, YamlMFI.SavePoints,
-                                  true /*IsSavePoints*/))
+                                  /*IsSavePoints=*/true))
     return true;
   if (initializeSaveRestorePoints(PFS, YamlMFI.RestorePoints,
-                                  false /*IsSavePoints*/))
+                                  /*IsSavePoints=*/false))
     return true;
 
   std::vector<CalleeSavedInfo> CSIInfo;
diff --git a/llvm/lib/CodeGen/MIRPrinter.cpp b/llvm/lib/CodeGen/MIRPrinter.cpp
index 064751341260c..a6e5f1b23d620 100644
--- a/llvm/lib/CodeGen/MIRPrinter.cpp
+++ b/llvm/lib/CodeGen/MIRPrinter.cpp
@@ -634,8 +634,19 @@ static void convertSRPoints(ModuleSlotTracker &MST,
         Str.clear();
       }
     }
+    // Sort here needed for stable output for lit tests
+    std::sort(Entry.Registers.begin(), Entry.Registers.end(),
+              [](const yaml::StringValue &Lhs, const yaml::StringValue &Rhs) {
+                return Lhs.Value < Rhs.Value;
+              });
     Points.push_back(Entry);
   }
+  // Sort here needed for stable output for lit tests
+  std::sort(Points.begin(), Points.end(),
+            [](const yaml::SaveRestorePointEntry &Lhs,
+               const yaml::SaveRestorePointEntry &Rhs) {
+              return Lhs.Point.Value < Rhs.Point.Value;
+            });
 }
 
 static void convertMJTI(ModuleSlotTracker &MST, yaml::MachineJumpTable &YamlJTI,
diff --git a/llvm/lib/CodeGen/MachineFrameInfo.cpp b/llvm/lib/CodeGen/MachineFrameInfo.cpp
index 4c98e8a2dd52d..e2c44a45e6c77 100644
--- a/llvm/lib/CodeGen/MachineFrameInfo.cpp
+++ b/llvm/lib/CodeGen/MachineFrameInfo.cpp
@@ -251,14 +251,14 @@ void MachineFrameInfo::print(const MachineFunction &MF, raw_ostream &OS) const{
     OS << "save points:\n";
 
     for (auto &item : SavePoints.get())
-      OS << printMBBReference(*item.first) << "\n";
+      OS << printMBBReference(*item.first) << '\n';
   } else
     OS << "save points are empty\n";
 
   if (!RestorePoints.empty()) {
     OS << "restore points:\n";
     for (auto &item : RestorePoints.get())
-      OS << printMBBReference(*item.first) << "\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 0a5c5f3423aca..cb83eb25658e9 100644
--- a/llvm/lib/CodeGen/PrologEpilogInserter.cpp
+++ b/llvm/lib/CodeGen/PrologEpilogInserter.cpp
@@ -682,8 +682,10 @@ static void insertCSRRestores(MachineBasicBlock &RestoreBlock,
 static void fillCSInfoPerBB(MachineFrameInfo &MFI,
                             DenseMap<MCRegister, CalleeSavedInfo *> &RegToInfo,
                             MBBVector &PrologEpilogBlocks, bool isSave) {
-  std::vector<CalleeSavedInfo> CSIV = {};
-  std::vector<CalleeSavedInfo> GCSIV = {};
+  // CaleeSavedInfo list for each point
+  std::vector<CalleeSavedInfo> CSIV;
+  // Global CalleeSavedInfo list aggregating CSIVs for all points
+  std::vector<CalleeSavedInfo> GCSIV;
   const SaveRestorePoints::PointsMap &SRPoints =
       isSave ? MFI.getSavePoints() : MFI.getRestorePoints();
   SaveRestorePoints::PointsMap Inner;
@@ -696,6 +698,8 @@ static void fillCSInfoPerBB(MachineFrameInfo &MFI,
       CSIV.push_back(*RegToInfo.at(Reg.getReg()));
       GCSIV.push_back(*RegToInfo.at(Reg.getReg()));
     }
+    // We need to sort CSIV, because Aarch64 expect CSI list to come sorted by
+    // frame index
     std::sort(CSIV.begin(), CSIV.end(),
               [](const CalleeSavedInfo &Lhs, const CalleeSavedInfo &Rhs) {
                 return Lhs.getFrameIdx() < Rhs.getFrameIdx();
@@ -703,6 +707,10 @@ static void fillCSInfoPerBB(MachineFrameInfo &MFI,
     Inner.insert({BB, CSIV});
   }
 
+  // If in any case not all CSRs listed in MFI.getCalleeSavedInfo are in the
+  // list of spilled/restored registers (for example AArch64 backend add VG
+  // registers in the list of CalleeSavedRegs during spill slot assignment), we
+  // should add them to this list and spill/restore them in Prolog/Epilog.
   if (GCSIV.size() < RegToInfo.size()) {
     for (auto &RTI : RegToInfo) {
       if (find_if(GCSIV, [&RTI](const CalleeSavedInfo &CSI) {
@@ -710,12 +718,14 @@ static void fillCSInfoPerBB(MachineFrameInfo &MFI,
           }) != std::end(GCSIV))
         continue;
       for (auto BB : PrologEpilogBlocks) {
-        if (Inner.contains(BB)) {
-          Inner[BB].push_back(*RTI.second);
-          std::sort(Inner[BB].begin(), Inner[BB].end(),
+        if (auto Entry = Inner.find(BB); Entry != Inner.end()) {
+          auto &CSI = Entry->second;
+          CSI.push_back(*RTI.second);
+          std::sort(CSI.begin(), CSI.end(),
                     [](const CalleeSavedInfo &Lhs, const CalleeSavedInfo &Rhs) {
                       return Lhs.getFrameIdx() < Rhs.getFrameIdx();
                     });
+          continue;
         }
         CSIV.clear();
         CSIV.push_back(*RTI.second);
@@ -761,13 +771,13 @@ void PEIImpl::spillCalleeSavedRegs(MachineFunction &MF) {
       RegToInfo.insert({CS.getReg(), &CS});
 
     if (!MFI.getSavePoints().empty()) {
-      fillCSInfoPerBB(MFI, RegToInfo, PrologBlocks, true /* isSave */);
-      fillCSInfoPerBB(MFI, RegToInfo, EpilogBlocks, false /* isSave */);
+      fillCSInfoPerBB(MFI, RegToInfo, PrologBlocks, /*isSave=*/true);
+      fillCSInfoPerBB(MFI, RegToInfo, EpilogBlocks, /*isSave=*/false);
     } else {
       SaveRestorePoints::PointsMap SavePts;
       for (MachineBasicBlock *PrologBlock : PrologBlocks)
         SavePts.insert({PrologBlock, MFI.getCalleeSavedInfo()});
-      MFI.setSavePoints(SavePts);
+      MFI.setSavePoints(std::move(SavePts));
     }
 
     if (!CSI.empty()) {
@@ -798,7 +808,7 @@ void PEIImpl::spillCalleeSavedRegs(MachineFunction &MF) {
         SaveRestorePoints::PointsMap RestorePts;
         for (MachineBasicBlock *EpilogBlock : EpilogBlocks)
           RestorePts.insert({EpilogBlock, MFI.getCalleeSavedInfo()});
-        MFI.setRestorePoints(RestorePts);
+        MFI.setRestorePoints(std::move(RestorePts));
       }
 
       for (MachineBasicBlock *RestoreBlock : RestoreBlocks) {
diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
index 648ddc022ee5c..6c5b53d69a8d4 100644
--- a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
@@ -943,7 +943,7 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
   // callee-saved register.
   CFIInstBuilder CFIBuilder(MBB, MBBI, MachineInstr::FrameSetup);
   bool NeedsDwarfCFI = needsDwarfCFI(MF);
-  // For scalar spills we skip 2 instrs at once, because right after
+  // For scalar register spills we skip 2 instrs at once, because right after
   // spills there are cfi instructions. At the moment of prolog emission they
   // are already inserted for scalar instructions, but not for vector
   // instructions.
@@ -1068,11 +1068,7 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
   // to the stack, not before.
   // FIXME: assumes exactly one instruction is used to save each callee-saved
   // register.
-  int Distance = getUnmanagedCSI(MF, CSI).size();
-  // Skip scalar CSR spills and corresponding cfi instrs
-  if (!RVFI->isPushable(MF) && !RVFI->useSaveRestoreLibCalls(MF) && NeedsDwarfCFI)
-    Distance *= 2;
-  std::advance(MBBI, Distance);
+  std::advance(MBBI, ScalarDistance);
 
   // Generate new FP.
   if (hasFP(MF)) {
@@ -1307,7 +1303,7 @@ void RISCVFrameLowering::emitEpilogue(MachineFunction &MF,
   // Skip to after the restores of scalar callee-saved registers
   // FIXME: assumes exactly one instruction is used to restore each
   // callee-saved register.
-  // Skip CSR restore + corresponding cfi restore instruction
+  // Skip CSR restore instructions + corresponding cfi restore instructions
   int ScalarDistance = getUnmanagedCSI(MF, CSI).size();
   if (NeedsDwarfCFI)
     ScalarDistance *= 2;
@@ -2197,6 +2193,7 @@ bool RISCVFrameLowering::spillCalleeSavedRegisters(
                               MachineInstr::FrameSetup);
     }
   };
+
   storeRegsToStackSlots(UnmanagedCSI);
 
   bool NeedsDwarfCFI = needsDwarfCFI(*MF);
@@ -2320,6 +2317,7 @@ bool RISCVFrameLowering::restoreCalleeSavedRegisters(
     }
   };
   loadRegFromStackSlot(RVVCSI);
+
   loadRegFromStackSlot(UnmanagedCSI);
 
   bool NeedsDwarfCFI = needsDwarfCFI(*MF);
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 b912a346c1b66..76ee613b09a23 100644
--- a/llvm/test/CodeGen/AArch64/dont-shrink-wrap-stack-mayloadorstore.mir
+++ b/llvm/test/CodeGen/AArch64/dont-shrink-wrap-stack-mayloadorstore.mir
@@ -9,20 +9,26 @@
  ; CHECK:      frameInfo:
  ; CHECK:        savePoint:
  ; CHECK-NEXT:     - point:           '%bb.1'
+ ; CHECK-NEXT:       registers:       []
  ; CHECK:        restorePoint:
  ; CHECK-NEXT:     - point:           '%bb.7'
+ ; CHECK-NEXT:       registers:       []
  ; CHECK:      name:            compiler_pop_stack_no_memoperands
  ; CHECK:      frameInfo:
  ; CHECK:        savePoint:
  ; CHECK-NEXT:     - point:           '%bb.1'
+ ; CHECK-NEXT:       registers:       []
  ; CHECK:        restorePoint:
  ; CHECK-NEXT:     - point:           '%bb.7'
+ ; CHECK-NEXT:       registers:       []
  ; CHECK:      name:            f
  ; CHECK:      frameInfo:
  ; CHECK:        savePoint:
  ; CHECK-NEXT:     - point:           '%bb.2'
+ ; CHECK-NEXT:       registers:       []
  ; CHECK:        restorePoint:
  ; CHECK-NEXT:     - point:           '%bb.4'
+ ; CHECK-NEXT:       registers:       []
  ; CHECK:      stack:
 
   target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
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..55965f8f4cfc1
--- /dev/null
+++ b/llvm/test/CodeGen/MIR/X86/frame-info-multiple-save-restore-points-parse.mir
@@ -0,0 +1,91 @@
+# 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:     registers:
+# CHECK-NEXT:       - '$eax'
+# CHECK-NEXT:   - point:           '%bb.2'
+# CHECK-NEXT:     registers:
+# CHECK-NEXT:       - '$edi'
+# CHECK-NEXT: restorePoint:
+# CHECK-NEXT:   - point:           '%bb.2'
+# CHECK-NEXT:     registers:
+# CHECK-NEXT:       - '$edi'
+# CHECK-NEXT:   - point:           '%bb.3'
+# CHECK-NEXT:     registers:
+# CHECK-NEXT:       - '$eax'
+
+# CHECK: stack
+frameInfo:
+  maxAlignment:  4
+  hasCalls:      true
+  savePoint:
+    - point:     '%bb.1'
+      registers:
+        - '$eax'
+    - point:     '%bb.2'
+      registers:
+        - '$edi'
+  restorePoint:  
+    - point:     '%bb.2'
+      registers:
+        - '$edi'
+    - point:     '%bb.3'
+      registers:
+        - '$eax'
+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/CodeGen/MIR/X86/frame-info-save-restore-points.mir b/llvm/test/CodeGen/MIR/X86/frame-info-save-restore-points.mir
index bd2d45046123a..400177f7eee32 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,8 +32,10 @@ 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
diff --git a/llvm/test/CodeGen/X86/shrink_wrap_dbg_value.mir b/llvm/test/CodeGen/X86/shrink_wrap_dbg_value.mir
index 139a3c46c51c1..da07926bb33b2 100644
--- a/llvm/test/CodeGen/X86/shrink_wrap_dbg_value.mir
+++ b/llvm/test/CodeGen/X86/shrink_wrap_dbg_value.mir
@@ -122,8 +122,16 @@ frameInfo:
   hasMustTailInVarArgFunc: false
   # CHECK:      savePoint:
   # CHECK-NEXT:   - point:           '%bb.1'
+  # CHECK-NEXT:     registers:
+  # CHECK-NEXT:       - '$ebx'
+  # CHECK-NEXT:       - '$edi'
+  # CHECK-NEXT:       - '$esi'
   # CHECK:      restorePoint:
   # CHECK-NEXT:   - point:           '%bb.3'
+  # CHECK-NEXT:     registers:
+  # CHECK-NEXT:       - '$ebx'
+  # CHECK-NEXT:       - '$edi'
+  # CHECK-NEXT:       - '$esi'
   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 17e042bf2df8c..13c4b0ce86ee8 100644
--- a/llvm/test/tools/llvm-reduce/mir/preserve-frame-info.mir
+++ b/llvm/test/tools/llvm-reduce/mir/preserve-frame-info.mir
@@ -22,10 +22,12 @@
 # RESULT-NEXT: hasTailCall:     true
 # RESULT-NEXT: savePoint:
 # RESULT-NEXT:   - point:           '%bb.1'
-# RESULT: restorePoint:
+# RESULT-NEXT:     registers:       []
+# RESULT-NEXT: restorePoint:
 # RESULT-NEXT:   - point:           '%bb.2'
+# RESULT-NEXT:     registers:       []
 
-# RESULT: fixedStack:
+# RESULT-NEXT: fixedStack:
 # RESULT-NEXT:  - { id: 0, offset: 56, size: 4, alignment: 8, callee-saved-register: '$sgpr44',
 # RESULT-NEXT:      callee-saved-restored: false }
 # RESULT-NEXT:  - { id: 1, offset: 52, size: 4, alignment: 4, callee-saved-register: '$sgpr43' }

>From e1d70e59f2ad00060524ba4d0b10fe8d7da1f55f Mon Sep 17 00:00:00 2001
From: ens-sc <elizaveta.noskova at syntacore.com>
Date: Mon, 12 May 2025 12:10:49 +0300
Subject: [PATCH 09/13] Review

---
 llvm/include/llvm/CodeGen/MIRYamlMapping.h  | 6 +++---
 llvm/lib/CodeGen/MIRPrinter.cpp             | 6 +++---
 llvm/lib/CodeGen/PrologEpilogInserter.cpp   | 2 +-
 llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp | 5 ++++-
 4 files changed, 11 insertions(+), 8 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/MIRYamlMapping.h b/llvm/include/llvm/CodeGen/MIRYamlMapping.h
index 412c45a6396ea..86a78b7f38569 100644
--- a/llvm/include/llvm/CodeGen/MIRYamlMapping.h
+++ b/llvm/include/llvm/CodeGen/MIRYamlMapping.h
@@ -635,14 +635,14 @@ namespace llvm {
 namespace yaml {
 
 // Struct representing one save/restore point in the
-// 'savePoint' / 'restorePoint' list. One point consist of machine basic block
+// 'savePoint' / 'restorePoint' list. One point consists of machine basic block
 // name and list of saved/restored in this basic block registers. There are
 // two forms of Save/Restore point representation:
 // 1. Without explicit register enumeration:
 //      savePoint:       '%bb.n'
 //      restorePoint:    '%bb.n'
-// supported for backward compatibility (in this case we assume that all
-// CalleeSavedRegisters are splilled/restored in these points)
+// in this case we assume that all CalleeSavedRegisters
+// are splilled/restored in these points
 // 2. With explicit register:
 //  savePoint:
 //    - point:           '%bb.1'
diff --git a/llvm/lib/CodeGen/MIRPrinter.cpp b/llvm/lib/CodeGen/MIRPrinter.cpp
index a6e5f1b23d620..c65f2a341b7b3 100644
--- a/llvm/lib/CodeGen/MIRPrinter.cpp
+++ b/llvm/lib/CodeGen/MIRPrinter.cpp
@@ -627,9 +627,9 @@ static void convertSRPoints(ModuleSlotTracker &MST,
     StrOS << printMBBReference(*MBBEntry.first);
     Entry.Point = StrOS.str().str();
     Str.clear();
-    for (auto &Reg : MBBEntry.second) {
-      if (Reg.getReg()) {
-        StrOS << printReg(Reg.getReg(), TRI);
+    for (const CalleeSavedInfo &Info : MBBEntry.second) {
+      if (Info.getReg()) {
+        StrOS << printReg(Info.getReg(), TRI);
         Entry.Registers.push_back(StrOS.str().str());
         Str.clear();
       }
diff --git a/llvm/lib/CodeGen/PrologEpilogInserter.cpp b/llvm/lib/CodeGen/PrologEpilogInserter.cpp
index cb83eb25658e9..3b4734c372bf0 100644
--- a/llvm/lib/CodeGen/PrologEpilogInserter.cpp
+++ b/llvm/lib/CodeGen/PrologEpilogInserter.cpp
@@ -717,7 +717,7 @@ static void fillCSInfoPerBB(MachineFrameInfo &MFI,
             return CSI.getReg() == RTI.first;
           }) != std::end(GCSIV))
         continue;
-      for (auto BB : PrologEpilogBlocks) {
+      for (MachineBasicBlock *BB : PrologEpilogBlocks) {
         if (auto Entry = Inner.find(BB); Entry != Inner.end()) {
           auto &CSI = Entry->second;
           CSI.push_back(*RTI.second);
diff --git a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
index 926452bd67f21..65343d2be86d2 100644
--- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
@@ -584,11 +584,14 @@ bool RISCVRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
       assert(It != CSI.end() &&
              "Did't find CalleeSavedInfo for CalleeSaved FrameIndex");
 
+      assert(!(MI.mayLoad() && MI.mayStore()) && "Instruction with frame index operand may load and store simultaneously!");
+
       if (MI.mayStore())
         SpilledIn = MFI.findSpilledIn(*It);
-
       else if (MI.mayLoad())
         RestoredIn = MFI.findRestoredIn(*It);
+      else
+        llvm_unreachable("Instruction with frame index operand neither loads nor stores!");
 
       bool SpilledRestoredInPrologEpilog = true;
       // If we didn't managed to find NCD (NCPD) for the list of Save (Restore)

>From faa70e2b0452d1cc759842f5bbe379beaca96734 Mon Sep 17 00:00:00 2001
From: ens-sc <elizaveta.noskova at syntacore.com>
Date: Mon, 12 May 2025 12:11:48 +0300
Subject: [PATCH 10/13] Formatting

---
 llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
index 65343d2be86d2..baa65a0d6b122 100644
--- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
@@ -584,14 +584,17 @@ bool RISCVRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
       assert(It != CSI.end() &&
              "Did't find CalleeSavedInfo for CalleeSaved FrameIndex");
 
-      assert(!(MI.mayLoad() && MI.mayStore()) && "Instruction with frame index operand may load and store simultaneously!");
+      assert(!(MI.mayLoad() && MI.mayStore()) &&
+             "Instruction with frame index operand may load and store "
+             "simultaneously!");
 
       if (MI.mayStore())
         SpilledIn = MFI.findSpilledIn(*It);
       else if (MI.mayLoad())
         RestoredIn = MFI.findRestoredIn(*It);
       else
-        llvm_unreachable("Instruction with frame index operand neither loads nor stores!");
+        llvm_unreachable(
+            "Instruction with frame index operand neither loads nor stores!");
 
       bool SpilledRestoredInPrologEpilog = true;
       // If we didn't managed to find NCD (NCPD) for the list of Save (Restore)

>From c9be7985696348521bc6101049bce78cebf0c038 Mon Sep 17 00:00:00 2001
From: ens-sc <elizaveta.noskova at syntacore.com>
Date: Thu, 17 Jul 2025 16:51:33 +0300
Subject: [PATCH 11/13] Review

---
 llvm/include/llvm/CodeGen/MIRYamlMapping.h   |  2 +-
 llvm/include/llvm/CodeGen/MachineFrameInfo.h |  7 +++----
 llvm/lib/CodeGen/MIRParser/MIRParser.cpp     |  9 +++++----
 llvm/lib/CodeGen/PrologEpilogInserter.cpp    | 12 ++++++------
 4 files changed, 15 insertions(+), 15 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/MIRYamlMapping.h b/llvm/include/llvm/CodeGen/MIRYamlMapping.h
index 86a78b7f38569..fb3e7103d463a 100644
--- a/llvm/include/llvm/CodeGen/MIRYamlMapping.h
+++ b/llvm/include/llvm/CodeGen/MIRYamlMapping.h
@@ -636,7 +636,7 @@ namespace yaml {
 
 // Struct representing one save/restore point in the
 // 'savePoint' / 'restorePoint' list. One point consists of machine basic block
-// name and list of saved/restored in this basic block registers. There are
+// name and list of registers saved/restored in this basic block. There are
 // two forms of Save/Restore point representation:
 // 1. Without explicit register enumeration:
 //      savePoint:       '%bb.n'
diff --git a/llvm/include/llvm/CodeGen/MachineFrameInfo.h b/llvm/include/llvm/CodeGen/MachineFrameInfo.h
index 8765f7cbc4f4b..1ae6e76093a8d 100644
--- a/llvm/include/llvm/CodeGen/MachineFrameInfo.h
+++ b/llvm/include/llvm/CodeGen/MachineFrameInfo.h
@@ -86,7 +86,7 @@ class SaveRestorePoints {
 public:
   const PointsMap &get() const { return Map; }
 
-  const std::vector<CalleeSavedInfo> getCSInfo(MachineBasicBlock *MBB) const {
+  std::vector<CalleeSavedInfo> getCSInfo(MachineBasicBlock *MBB) const {
     return Map.lookup(MBB);
   }
 
@@ -853,8 +853,7 @@ class MachineFrameInfo {
 
   /// Returns callee saved info vector for provided save point in
   /// the current function.
-  const std::vector<CalleeSavedInfo>
-  getSaveCSInfo(MachineBasicBlock *MBB) const {
+  std::vector<CalleeSavedInfo> getSaveCSInfo(MachineBasicBlock *MBB) const {
     return SavePoints.getCSInfo(MBB);
   }
 
@@ -900,7 +899,7 @@ class MachineFrameInfo {
     RestorePoints.set(std::move(NewRestorePoints));
   }
 
-  static const SaveRestorePoints::PointsMap constructSaveRestorePoints(
+  static SaveRestorePoints::PointsMap constructSaveRestorePoints(
       const SaveRestorePoints::PointsMap &SRPoints,
       const DenseMap<MachineBasicBlock *, MachineBasicBlock *> &BBMap) {
     SaveRestorePoints::PointsMap Pts{};
diff --git a/llvm/lib/CodeGen/MIRParser/MIRParser.cpp b/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
index f64f7f7e42df7..76525e1ed738b 100644
--- a/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
+++ b/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
@@ -1107,19 +1107,20 @@ bool MIRParserImpl::initializeSaveRestorePoints(
         std::get<std::vector<yaml::SaveRestorePointEntry>>(YamlSRPoints);
     if (VectorRepr.empty())
       return false;
-    std::vector<CalleeSavedInfo> Registers;
+
     for (const auto &Entry : VectorRepr) {
       const auto &MBBSource = Entry.Point;
       if (parseMBBReference(PFS, MBB, MBBSource.Value))
         return true;
-      Registers.clear();
+
+      std::vector<CalleeSavedInfo> Registers;
       for (auto &RegStr : Entry.Registers) {
         Register Reg;
         if (parseNamedRegisterReference(PFS, Reg, RegStr.Value, Error))
           return error(Error, RegStr.SourceRange);
         Registers.push_back(CalleeSavedInfo(Reg));
       }
-      SRPoints.insert(std::make_pair(MBB, Registers));
+      SRPoints.try_emplace(MBB, std::move(Registers));
     }
   } else {
     yaml::StringValue StringRepr = std::get<yaml::StringValue>(YamlSRPoints);
@@ -1127,7 +1128,7 @@ bool MIRParserImpl::initializeSaveRestorePoints(
       return false;
     if (parseMBBReference(PFS, MBB, StringRepr))
       return true;
-    SRPoints.insert(std::make_pair(MBB, MFI.getCalleeSavedInfo()));
+    SRPoints.try_emplace(MBB, MFI.getCalleeSavedInfo());
   }
 
   if (IsSavePoints)
diff --git a/llvm/lib/CodeGen/PrologEpilogInserter.cpp b/llvm/lib/CodeGen/PrologEpilogInserter.cpp
index 3b4734c372bf0..dab04d2d5d174 100644
--- a/llvm/lib/CodeGen/PrologEpilogInserter.cpp
+++ b/llvm/lib/CodeGen/PrologEpilogInserter.cpp
@@ -682,15 +682,14 @@ static void insertCSRRestores(MachineBasicBlock &RestoreBlock,
 static void fillCSInfoPerBB(MachineFrameInfo &MFI,
                             DenseMap<MCRegister, CalleeSavedInfo *> &RegToInfo,
                             MBBVector &PrologEpilogBlocks, bool isSave) {
-  // CaleeSavedInfo list for each point
-  std::vector<CalleeSavedInfo> CSIV;
   // Global CalleeSavedInfo list aggregating CSIVs for all points
   std::vector<CalleeSavedInfo> GCSIV;
   const SaveRestorePoints::PointsMap &SRPoints =
       isSave ? MFI.getSavePoints() : MFI.getRestorePoints();
   SaveRestorePoints::PointsMap Inner;
   for (auto [BB, Regs] : SRPoints) {
-    CSIV.clear();
+    // CalleeSavedInfo list for each point
+    std::vector<CalleeSavedInfo> CSIV;
     for (auto &Reg : Regs) {
       auto It = RegToInfo.find(Reg.getReg());
       if (It == RegToInfo.end())
@@ -704,7 +703,7 @@ static void fillCSInfoPerBB(MachineFrameInfo &MFI,
               [](const CalleeSavedInfo &Lhs, const CalleeSavedInfo &Rhs) {
                 return Lhs.getFrameIdx() < Rhs.getFrameIdx();
               });
-    Inner.insert({BB, CSIV});
+    Inner.try_emplace(BB, std::move(CSIV));
   }
 
   // If in any case not all CSRs listed in MFI.getCalleeSavedInfo are in the
@@ -727,9 +726,10 @@ static void fillCSInfoPerBB(MachineFrameInfo &MFI,
                     });
           continue;
         }
-        CSIV.clear();
+        // CalleeSavedInfo list for each point
+        std::vector<CalleeSavedInfo> CSIV;
         CSIV.push_back(*RTI.second);
-        Inner.insert(std::make_pair(BB, CSIV));
+        Inner.try_emplace(BB, std::move(CSIV));
       }
     }
   }

>From 624d53eef2951e01fccad61959d9076c7ad22a6d Mon Sep 17 00:00:00 2001
From: ens-sc <elizaveta.noskova at syntacore.com>
Date: Thu, 24 Jul 2025 20:12:47 +0300
Subject: [PATCH 12/13] Review

---
 llvm/lib/CodeGen/MIRParser/MIRParser.cpp    |  7 +++----
 llvm/lib/CodeGen/PrologEpilogInserter.cpp   | 21 +++++++++------------
 llvm/lib/CodeGen/ShrinkWrap.cpp             |  2 +-
 llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp |  3 ++-
 4 files changed, 15 insertions(+), 18 deletions(-)

diff --git a/llvm/lib/CodeGen/MIRParser/MIRParser.cpp b/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
index 76525e1ed738b..3ebd0938b2e19 100644
--- a/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
+++ b/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
@@ -1108,13 +1108,12 @@ bool MIRParserImpl::initializeSaveRestorePoints(
     if (VectorRepr.empty())
       return false;
 
-    for (const auto &Entry : VectorRepr) {
-      const auto &MBBSource = Entry.Point;
-      if (parseMBBReference(PFS, MBB, MBBSource.Value))
+    for (const auto &[EntryMBB, EntryRegisters] : VectorRepr) {
+      if (parseMBBReference(PFS, MBB, EntryMBB.Value))
         return true;
 
       std::vector<CalleeSavedInfo> Registers;
-      for (auto &RegStr : Entry.Registers) {
+      for (auto &RegStr : EntryRegisters) {
         Register Reg;
         if (parseNamedRegisterReference(PFS, Reg, RegStr.Value, Error))
           return error(Error, RegStr.SourceRange);
diff --git a/llvm/lib/CodeGen/PrologEpilogInserter.cpp b/llvm/lib/CodeGen/PrologEpilogInserter.cpp
index dab04d2d5d174..668670abd6928 100644
--- a/llvm/lib/CodeGen/PrologEpilogInserter.cpp
+++ b/llvm/lib/CodeGen/PrologEpilogInserter.cpp
@@ -699,10 +699,9 @@ static void fillCSInfoPerBB(MachineFrameInfo &MFI,
     }
     // We need to sort CSIV, because Aarch64 expect CSI list to come sorted by
     // frame index
-    std::sort(CSIV.begin(), CSIV.end(),
-              [](const CalleeSavedInfo &Lhs, const CalleeSavedInfo &Rhs) {
-                return Lhs.getFrameIdx() < Rhs.getFrameIdx();
-              });
+    sort(CSIV, [](const CalleeSavedInfo &Lhs, const CalleeSavedInfo &Rhs) {
+      return Lhs.getFrameIdx() < Rhs.getFrameIdx();
+    });
     Inner.try_emplace(BB, std::move(CSIV));
   }
 
@@ -712,23 +711,21 @@ static void fillCSInfoPerBB(MachineFrameInfo &MFI,
   // should add them to this list and spill/restore them in Prolog/Epilog.
   if (GCSIV.size() < RegToInfo.size()) {
     for (auto &RTI : RegToInfo) {
-      if (find_if(GCSIV, [&RTI](const CalleeSavedInfo &CSI) {
+      if (count_if(GCSIV, [&RTI](const CalleeSavedInfo &CSI) {
             return CSI.getReg() == RTI.first;
-          }) != std::end(GCSIV))
+          }))
         continue;
       for (MachineBasicBlock *BB : PrologEpilogBlocks) {
         if (auto Entry = Inner.find(BB); Entry != Inner.end()) {
           auto &CSI = Entry->second;
           CSI.push_back(*RTI.second);
-          std::sort(CSI.begin(), CSI.end(),
-                    [](const CalleeSavedInfo &Lhs, const CalleeSavedInfo &Rhs) {
-                      return Lhs.getFrameIdx() < Rhs.getFrameIdx();
-                    });
+          sort(CSI, [](const CalleeSavedInfo &Lhs, const CalleeSavedInfo &Rhs) {
+            return Lhs.getFrameIdx() < Rhs.getFrameIdx();
+          });
           continue;
         }
         // CalleeSavedInfo list for each point
-        std::vector<CalleeSavedInfo> CSIV;
-        CSIV.push_back(*RTI.second);
+        auto CSIV = std::vector<CalleeSavedInfo>({*RTI.second});
         Inner.try_emplace(BB, std::move(CSIV));
       }
     }
diff --git a/llvm/lib/CodeGen/ShrinkWrap.cpp b/llvm/lib/CodeGen/ShrinkWrap.cpp
index b2592e177ee1d..399bcffb0957e 100644
--- a/llvm/lib/CodeGen/ShrinkWrap.cpp
+++ b/llvm/lib/CodeGen/ShrinkWrap.cpp
@@ -971,7 +971,7 @@ bool ShrinkWrapImpl::run(MachineFunction &MF) {
 
   std::vector<CalleeSavedInfo> CSIVec;
   SetOfRegs CSRSet = getCurrentCSRs(RS.get());
-  for (unsigned Reg : CSRSet)
+  for (Register Reg : CSRSet)
     CSIVec.push_back(CalleeSavedInfo(Reg));
 
   SaveRestorePoints::PointsMap SavePoints({{Save, CSIVec}});
diff --git a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
index baa65a0d6b122..a2e2fd0ffc4bf 100644
--- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
@@ -609,10 +609,11 @@ bool RISCVRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
       // Prolog or at the start of Epilog SP has maximum offset
       uint64_t FirstSPAdjustAmount =
           getFrameLowering(MF)->getFirstSPAdjustAmount(MF);
-      if (FirstSPAdjustAmount && !SpilledRestoredInPrologEpilog)
+      if (FirstSPAdjustAmount && !SpilledRestoredInPrologEpilog) {
         Offset += StackOffset::getFixed(
             getFrameLowering(MF)->getStackSizeWithRVVPadding(MF) -
             FirstSPAdjustAmount);
+      }
     }
   }
 

>From 7bfd4a8d38c704a29fbd26b551f9ce9b71f40bb6 Mon Sep 17 00:00:00 2001
From: ens-sc <elizaveta.noskova at syntacore.com>
Date: Tue, 29 Jul 2025 16:06:02 +0300
Subject: [PATCH 13/13] Review

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

diff --git a/llvm/lib/CodeGen/PrologEpilogInserter.cpp b/llvm/lib/CodeGen/PrologEpilogInserter.cpp
index 668670abd6928..3d287f34de50c 100644
--- a/llvm/lib/CodeGen/PrologEpilogInserter.cpp
+++ b/llvm/lib/CodeGen/PrologEpilogInserter.cpp
@@ -725,8 +725,8 @@ static void fillCSInfoPerBB(MachineFrameInfo &MFI,
           continue;
         }
         // CalleeSavedInfo list for each point
-        auto CSIV = std::vector<CalleeSavedInfo>({*RTI.second});
-        Inner.try_emplace(BB, std::move(CSIV));
+        Inner.try_emplace(BB,
+                          std::initializer_list<CalleeSavedInfo>{*RTI.second});
       }
     }
   }



More information about the llvm-commits mailing list