[llvm] Minimal unwinding information (DWARF CFI) checker (PR #145633)

AmirHossein PashaeeHir via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 24 22:00:53 PDT 2025


https://github.com/amsen20 updated https://github.com/llvm/llvm-project/pull/145633

>From 5b78ea04455f8316737778f4940f1864689ff0b8 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Tue, 6 May 2025 17:45:34 +0000
Subject: [PATCH 01/58] Forward CFI directives alongside their associated
 instruction to a simple CFI analysis

---
 llvm/tools/llvm-mc/CFIAnalysis.h           |  88 ++++++++++++
 llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h | 151 +++++++++++++++++++++
 2 files changed, 239 insertions(+)
 create mode 100644 llvm/tools/llvm-mc/CFIAnalysis.h
 create mode 100644 llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h

diff --git a/llvm/tools/llvm-mc/CFIAnalysis.h b/llvm/tools/llvm-mc/CFIAnalysis.h
new file mode 100644
index 0000000000000..eeb8741fb012b
--- /dev/null
+++ b/llvm/tools/llvm-mc/CFIAnalysis.h
@@ -0,0 +1,88 @@
+#ifndef LLVM_TOOLS_LLVM_MC_CFI_ANALYSIS_H
+#define LLVM_TOOLS_LLVM_MC_CFI_ANALYSIS_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDwarf.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/Support/Debug.h"
+
+namespace llvm {
+
+// TODO remove it, it's just for debug purposes.
+void printUntilNextLine(const char *Str) {
+  for (int I = 0; Str[I] != '\0' && Str[I] != '\n'; I++)
+    dbgs() << Str[I];
+}
+
+class CFIAnalysis {
+  MCContext &Context;
+  MCInstrInfo const &MCII;
+
+public:
+  CFIAnalysis(MCContext &Context, MCInstrInfo const &MCII)
+      : Context(Context), MCII(MCII) {}
+
+  void update(const MCDwarfFrameInfo &DwarfFrame, const MCInst &Inst,
+              ArrayRef<MCCFIInstruction> CFIDirectives) {
+    dbgs() << "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n";
+    printUntilNextLine(Inst.getLoc().getPointer());
+    dbgs() << "\n";
+    dbgs() << "codes: ";
+    Inst.print(dbgs());
+    dbgs() << "\n";
+    dbgs() << "------------------------------\n";
+    auto *RI = Context.getRegisterInfo();
+    auto CFAReg = RI->getLLVMRegNum(DwarfFrame.CurrentCfaRegister, false);
+    dbgs() << "The CFA register is: " << CFAReg << "\n";
+    bool GoingToChangeCFA = false;
+    for (auto CFIDirective : CFIDirectives) {
+      auto Op = CFIDirective.getOperation();
+      GoingToChangeCFA |= (Op == MCCFIInstruction::OpDefCfa ||
+                           Op == MCCFIInstruction::OpDefCfaOffset ||
+                           Op == MCCFIInstruction::OpDefCfaRegister ||
+                           Op == MCCFIInstruction::OpAdjustCfaOffset ||
+                           Op == MCCFIInstruction::OpLLVMDefAspaceCfa);
+    }
+    dbgs() << "------------------------------\n";
+    bool ChangedCFA = false;
+    for (int I = 0; I < Inst.getNumOperands(); I++) {
+      auto &&Operand = Inst.getOperand(I);
+      if (!Operand.isReg())
+        continue;
+      if (MCII.get(Inst.getOpcode())
+              .hasDefOfPhysReg(Inst, Operand.getReg(), *RI)) {
+        dbgs() << "This instruction modifies: " << Operand.getReg().id()
+               << "\n";
+        if (Operand.getReg() == CFAReg.value())
+          ChangedCFA = true;
+      }
+    }
+    dbgs() << "------------------------------\n";
+    dbgs() << "The instruction DOES " << (ChangedCFA ? "" : "NOT ")
+           << "change the CFA.\n";
+    dbgs() << "The CFI directives DOES " << (GoingToChangeCFA ? "" : "NOT ")
+           << "change the CFA.\n";
+    if (ChangedCFA && !GoingToChangeCFA) {
+      Context.reportError(Inst.getLoc(),
+                          "The instruction changes CFA register value, but the "
+                          "CFI directives don't update the CFA.");
+    }
+    // TODO needs more work
+    // if (!ChangedCFA && GoingToChangeCFA) {
+    //   Context.reportError(
+    //       Inst.getLoc(),
+    //       "The instruction doesn't change CFA register value, but the "
+    //       "CFI directives update the CFA.");
+    // }
+    dbgs() << "vvvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n";
+    ChangedCFA = false;
+  }
+};
+
+} // namespace llvm
+#endif
\ No newline at end of file
diff --git a/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h b/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h
new file mode 100644
index 0000000000000..9c7747520a033
--- /dev/null
+++ b/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h
@@ -0,0 +1,151 @@
+#ifndef LLVM_TOOLS_LLVM_MC_CFI_ANALYSIS_MC_STREAMER_H
+#define LLVM_TOOLS_LLVM_MC_CFI_ANALYSIS_MC_STREAMER_H
+
+#include "CFIAnalysis.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDwarf.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/Support/Debug.h"
+#include <cstdio>
+#include <optional>
+#include <set>
+
+namespace llvm {
+
+class CFIAnalysisMCStreamer : public MCStreamer {
+  struct CFIDirectivesState {
+    int FrameIndex; // TODO remove it, no need for it
+    int DirectiveIndex;
+
+    CFIDirectivesState() : FrameIndex(-1), DirectiveIndex(0) {}
+
+    CFIDirectivesState(int FrameIndex, int InstructionIndex)
+        : FrameIndex(FrameIndex), DirectiveIndex(InstructionIndex) {}
+  } LastCFIDirectivesState;
+  std::vector<int> FrameIndices;
+
+  struct ICFI {
+    MCInst Instruction;
+    ArrayRef<MCCFIInstruction> CFIDirectives;
+
+    ICFI(MCInst Instruction, ArrayRef<MCCFIInstruction> CFIDirectives)
+        : Instruction(Instruction), CFIDirectives(CFIDirectives) {}
+  };
+
+  std::optional<MCInst> LastInstruction;
+  std::optional<MCDwarfFrameInfo> LastDwarfFrameInfo;
+  CFIAnalysis CFIA;
+
+  std::optional<ICFI> getLastICFI() {
+    if (!LastInstruction)
+      return std::nullopt;
+
+    auto DwarfFrameInfos = getDwarfFrameInfos();
+    int FrameIndex = FrameIndices.back();
+    auto CurrentCFIDirectiveState =
+        hasUnfinishedDwarfFrameInfo()
+            ? CFIDirectivesState(
+                  FrameIndex, DwarfFrameInfos[FrameIndex].Instructions.size())
+            : CFIDirectivesState();
+    assert(CurrentCFIDirectiveState.FrameIndex ==
+           LastCFIDirectivesState.FrameIndex);
+    assert(CurrentCFIDirectiveState.DirectiveIndex >=
+           LastCFIDirectivesState.DirectiveIndex);
+
+    std::vector<MCCFIInstruction> CFIDirectives;
+    if (LastCFIDirectivesState.FrameIndex >= 0) {
+      auto CFIInstructions = DwarfFrameInfos[FrameIndex].Instructions;
+      CFIDirectives = std::vector<MCCFIInstruction>(
+          CFIInstructions.begin() + LastCFIDirectivesState.DirectiveIndex,
+          CFIInstructions.begin() + CurrentCFIDirectiveState.DirectiveIndex);
+    }
+
+    LastCFIDirectivesState = CurrentCFIDirectiveState;
+    return ICFI(LastInstruction.value(), CFIDirectives);
+  }
+
+  void feedCFIA() {
+    if (!LastDwarfFrameInfo) {
+      // TODO Maybe this corner case causes bugs, when the programmer did a
+      // mistake in the startproc, endprocs and also made a mistake in not
+      // adding cfi directives for a instruction. Then this would cause to
+      // ignore the instruction.
+      auto LastICFI = getLastICFI();
+      assert(!LastICFI || LastICFI->CFIDirectives.empty());
+      return;
+    }
+
+    if (auto ICFI = getLastICFI())
+      CFIA.update(LastDwarfFrameInfo.value(), ICFI->Instruction,
+                  ICFI->CFIDirectives);
+  }
+
+public:
+  CFIAnalysisMCStreamer(MCContext &Context, const MCInstrInfo &MCII)
+      : MCStreamer(Context), LastCFIDirectivesState(),
+        LastInstruction(std::nullopt), CFIA(Context, MCII) {
+    FrameIndices.push_back(-1);
+  }
+
+  /// @name MCStreamer Interface
+  /// @{
+
+  bool hasRawTextSupport() const override { return true; }
+  void emitRawTextImpl(StringRef String) override {}
+
+  bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override {
+    return true;
+  }
+
+  void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
+                        Align ByteAlignment) override {}
+  void beginCOFFSymbolDef(const MCSymbol *Symbol) override {}
+  void emitCOFFSymbolStorageClass(int StorageClass) override {}
+  void emitCOFFSymbolType(int Type) override {}
+  void endCOFFSymbolDef() override {}
+  void emitXCOFFSymbolLinkageWithVisibility(MCSymbol *Symbol,
+                                            MCSymbolAttr Linkage,
+                                            MCSymbolAttr Visibility) override {}
+
+  void emitInstruction(const MCInst &Inst,
+                       const MCSubtargetInfo &STI) override {
+    feedCFIA();
+    LastInstruction = Inst;
+    if (hasUnfinishedDwarfFrameInfo())
+      LastDwarfFrameInfo = getDwarfFrameInfos()[FrameIndices.back()];
+    else
+      LastDwarfFrameInfo = std::nullopt;
+  }
+
+  void emitCFIStartProcImpl(MCDwarfFrameInfo &Frame) override {
+    feedCFIA();
+    FrameIndices.push_back(getNumFrameInfos());
+    LastInstruction = std::nullopt;
+    LastDwarfFrameInfo = std::nullopt;
+    LastCFIDirectivesState.FrameIndex = FrameIndices.back();
+    LastCFIDirectivesState.DirectiveIndex = 0;
+    MCStreamer::emitCFIStartProcImpl(Frame);
+  }
+
+  void emitCFIEndProcImpl(MCDwarfFrameInfo &CurFrame) override {
+    feedCFIA();
+    // TODO this will break if the input frame are malformed.
+    FrameIndices.pop_back();
+    LastInstruction = std::nullopt;
+    LastDwarfFrameInfo = std::nullopt;
+    LastCFIDirectivesState.FrameIndex = FrameIndices.back();
+    LastCFIDirectivesState.DirectiveIndex =
+        LastCFIDirectivesState.FrameIndex >= 0
+            ? getDwarfFrameInfos()[LastCFIDirectivesState.FrameIndex]
+                  .Instructions.size()
+            : 0;
+    MCStreamer::emitCFIEndProcImpl(CurFrame);
+  }
+};
+
+} // namespace llvm
+#endif
\ No newline at end of file

>From b781e831666abb532beefe776e13c72c408d6044 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Tue, 6 May 2025 18:00:50 +0000
Subject: [PATCH 02/58] Create a new CFI analysis for each dwarf separately

---
 llvm/tools/llvm-mc/CFIAnalysis.h           |  2 +-
 llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h | 21 ++++++++++++---------
 2 files changed, 13 insertions(+), 10 deletions(-)

diff --git a/llvm/tools/llvm-mc/CFIAnalysis.h b/llvm/tools/llvm-mc/CFIAnalysis.h
index eeb8741fb012b..6abbdfba6d28f 100644
--- a/llvm/tools/llvm-mc/CFIAnalysis.h
+++ b/llvm/tools/llvm-mc/CFIAnalysis.h
@@ -50,7 +50,7 @@ class CFIAnalysis {
     }
     dbgs() << "------------------------------\n";
     bool ChangedCFA = false;
-    for (int I = 0; I < Inst.getNumOperands(); I++) {
+    for (unsigned I = 0; I < Inst.getNumOperands(); I++) {
       auto &&Operand = Inst.getOperand(I);
       if (!Operand.isReg())
         continue;
diff --git a/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h b/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h
index 9c7747520a033..76ae536ab4bd3 100644
--- a/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h
+++ b/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h
@@ -7,16 +7,15 @@
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCDwarf.h"
 #include "llvm/MC/MCInstrInfo.h"
-#include "llvm/MC/MCRegisterInfo.h"
 #include "llvm/MC/MCStreamer.h"
-#include "llvm/Support/Debug.h"
 #include <cstdio>
 #include <optional>
-#include <set>
 
 namespace llvm {
 
 class CFIAnalysisMCStreamer : public MCStreamer {
+  MCInstrInfo const &MCII;
+
   struct CFIDirectivesState {
     int FrameIndex; // TODO remove it, no need for it
     int DirectiveIndex;
@@ -27,6 +26,7 @@ class CFIAnalysisMCStreamer : public MCStreamer {
         : FrameIndex(FrameIndex), DirectiveIndex(InstructionIndex) {}
   } LastCFIDirectivesState;
   std::vector<int> FrameIndices;
+  std::vector<CFIAnalysis> CFIAs;
 
   struct ICFI {
     MCInst Instruction;
@@ -38,7 +38,6 @@ class CFIAnalysisMCStreamer : public MCStreamer {
 
   std::optional<MCInst> LastInstruction;
   std::optional<MCDwarfFrameInfo> LastDwarfFrameInfo;
-  CFIAnalysis CFIA;
 
   std::optional<ICFI> getLastICFI() {
     if (!LastInstruction)
@@ -79,15 +78,17 @@ class CFIAnalysisMCStreamer : public MCStreamer {
       return;
     }
 
-    if (auto ICFI = getLastICFI())
-      CFIA.update(LastDwarfFrameInfo.value(), ICFI->Instruction,
-                  ICFI->CFIDirectives);
+    if (auto ICFI = getLastICFI()) {
+      assert(!CFIAs.empty());
+      CFIAs.back().update(LastDwarfFrameInfo.value(), ICFI->Instruction,
+                          ICFI->CFIDirectives);
+    }
   }
 
 public:
   CFIAnalysisMCStreamer(MCContext &Context, const MCInstrInfo &MCII)
-      : MCStreamer(Context), LastCFIDirectivesState(),
-        LastInstruction(std::nullopt), CFIA(Context, MCII) {
+      : MCStreamer(Context), MCII(MCII), LastCFIDirectivesState(),
+        LastInstruction(std::nullopt) {
     FrameIndices.push_back(-1);
   }
 
@@ -124,6 +125,7 @@ class CFIAnalysisMCStreamer : public MCStreamer {
   void emitCFIStartProcImpl(MCDwarfFrameInfo &Frame) override {
     feedCFIA();
     FrameIndices.push_back(getNumFrameInfos());
+    CFIAs.emplace_back(getContext(), MCII);
     LastInstruction = std::nullopt;
     LastDwarfFrameInfo = std::nullopt;
     LastCFIDirectivesState.FrameIndex = FrameIndices.back();
@@ -135,6 +137,7 @@ class CFIAnalysisMCStreamer : public MCStreamer {
     feedCFIA();
     // TODO this will break if the input frame are malformed.
     FrameIndices.pop_back();
+    CFIAs.pop_back();
     LastInstruction = std::nullopt;
     LastDwarfFrameInfo = std::nullopt;
     LastCFIDirectivesState.FrameIndex = FrameIndices.back();

>From 8b43f8c29b7c1fbc48a3bb86b765627e20ac6201 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Tue, 6 May 2025 23:42:31 +0000
Subject: [PATCH 03/58] Separate the logic and display

---
 llvm/tools/llvm-mc/CFIAnalysis.h | 93 +++++++++++++++++++-------------
 1 file changed, 57 insertions(+), 36 deletions(-)

diff --git a/llvm/tools/llvm-mc/CFIAnalysis.h b/llvm/tools/llvm-mc/CFIAnalysis.h
index 6abbdfba6d28f..f527043d3dbbb 100644
--- a/llvm/tools/llvm-mc/CFIAnalysis.h
+++ b/llvm/tools/llvm-mc/CFIAnalysis.h
@@ -2,14 +2,18 @@
 #define LLVM_TOOLS_LLVM_MC_CFI_ANALYSIS_H
 
 #include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCDwarf.h"
+#include "llvm/MC/MCExpr.h"
 #include "llvm/MC/MCInst.h"
 #include "llvm/MC/MCInstrInfo.h"
 #include "llvm/MC/MCRegisterInfo.h"
 #include "llvm/MC/MCStreamer.h"
 #include "llvm/Support/Debug.h"
+#include <ostream>
+#include <set>
 
 namespace llvm {
 
@@ -25,20 +29,47 @@ class CFIAnalysis {
 
 public:
   CFIAnalysis(MCContext &Context, MCInstrInfo const &MCII)
-      : Context(Context), MCII(MCII) {}
+      : Context(Context), MCII(MCII) {
+    // TODO it should look at the poluge directives and setup the
+    // registers' previous value state here, but for now, it's assumed that all
+    // values are by default `samevalue`.
+  }
 
   void update(const MCDwarfFrameInfo &DwarfFrame, const MCInst &Inst,
               ArrayRef<MCCFIInstruction> CFIDirectives) {
-    dbgs() << "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n";
-    printUntilNextLine(Inst.getLoc().getPointer());
-    dbgs() << "\n";
-    dbgs() << "codes: ";
-    Inst.print(dbgs());
-    dbgs() << "\n";
-    dbgs() << "------------------------------\n";
+
+    auto MCInstInfo = MCII.get(Inst.getOpcode());
     auto *RI = Context.getRegisterInfo();
     auto CFAReg = RI->getLLVMRegNum(DwarfFrame.CurrentCfaRegister, false);
-    dbgs() << "The CFA register is: " << CFAReg << "\n";
+
+    std::set<int> Writes, Reads; // TODO reads is not ready for now
+    // FIXME this way of extracting uses is buggy:
+    // for (unsigned I = 0; I < MCInstInfo.NumImplicitUses; I++)
+    //   Reads.insert(MCInstInfo.implicit_uses()[I]);
+    // for (unsigned I = 0; I < MCInstInfo.NumImplicitDefs; I++)
+    //   Writes.insert(MCInstInfo.implicit_defs()[I]);
+
+    for (unsigned I = 0; I < Inst.getNumOperands(); I++) {
+      auto &&Operand = Inst.getOperand(I);
+      if (Operand.isReg()) {
+        // TODO it is not percise, maybe this operand is for output, then it
+        // means that there is no read happening here.
+        Reads.insert(Operand.getReg());
+      }
+
+      if (Operand.isExpr()) {
+        // TODO maybe the argument is not a register, but is a expression like
+        // `34(sp)` that has a register in it. Check if this works or not and if
+        // no change it somehow that it count that register as reads or writes
+        // too.
+      }
+
+      if (Operand.isReg() &&
+          MCInstInfo.hasDefOfPhysReg(Inst, Operand.getReg(), *RI))
+        Writes.insert(Operand.getReg().id());
+    }
+
+    bool ChangedCFA = Writes.count(CFAReg->id());
     bool GoingToChangeCFA = false;
     for (auto CFIDirective : CFIDirectives) {
       auto Op = CFIDirective.getOperation();
@@ -48,38 +79,28 @@ class CFIAnalysis {
                            Op == MCCFIInstruction::OpAdjustCfaOffset ||
                            Op == MCCFIInstruction::OpLLVMDefAspaceCfa);
     }
-    dbgs() << "------------------------------\n";
-    bool ChangedCFA = false;
-    for (unsigned I = 0; I < Inst.getNumOperands(); I++) {
-      auto &&Operand = Inst.getOperand(I);
-      if (!Operand.isReg())
-        continue;
-      if (MCII.get(Inst.getOpcode())
-              .hasDefOfPhysReg(Inst, Operand.getReg(), *RI)) {
-        dbgs() << "This instruction modifies: " << Operand.getReg().id()
-               << "\n";
-        if (Operand.getReg() == CFAReg.value())
-          ChangedCFA = true;
-      }
-    }
-    dbgs() << "------------------------------\n";
-    dbgs() << "The instruction DOES " << (ChangedCFA ? "" : "NOT ")
-           << "change the CFA.\n";
-    dbgs() << "The CFI directives DOES " << (GoingToChangeCFA ? "" : "NOT ")
-           << "change the CFA.\n";
     if (ChangedCFA && !GoingToChangeCFA) {
       Context.reportError(Inst.getLoc(),
                           "The instruction changes CFA register value, but the "
                           "CFI directives don't update the CFA.");
     }
-    // TODO needs more work
-    // if (!ChangedCFA && GoingToChangeCFA) {
-    //   Context.reportError(
-    //       Inst.getLoc(),
-    //       "The instruction doesn't change CFA register value, but the "
-    //       "CFI directives update the CFA.");
-    // }
-    dbgs() << "vvvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n";
+
+    dbgs() << "^^^^^^^^^^^^^^^^ InsCFIs ^^^^^^^^^^^^^^^^\n";
+    printUntilNextLine(Inst.getLoc().getPointer());
+    dbgs() << "\n";
+    dbgs() << "-----------------------------------------\n";
+    dbgs() << "writes into: { ";
+    for (auto Reg : Writes) {
+      dbgs() << (int)Reg << " ";
+    }
+    dbgs() << "}\n";
+    dbgs() << "-----------------------------------------\n";
+    dbgs() << "The CFA register is: " << CFAReg << "\n";
+    dbgs() << "The instruction does " << (ChangedCFA ? "" : "NOT ")
+           << "change the CFA.\n";
+    dbgs() << "The CFI directives does " << (GoingToChangeCFA ? "" : "NOT ")
+           << "change the CFA.\n";
+    dbgs() << "vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n";
     ChangedCFA = false;
   }
 };

>From 6790f902972b05ac1d67c4315c12ec5904792bb4 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Fri, 9 May 2025 22:52:04 +0000
Subject: [PATCH 04/58] Compile llvm mc depending on bolt

---
 bolt/lib/Utils/CommandLineOpts.cpp         |  2 +-
 llvm/tools/llvm-mc/CFIAnalysis.h           | 35 ++++++++++++++++--
 llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h | 12 ++++--
 llvm/tools/llvm-mc/CMakeLists.txt          |  3 ++
 llvm/tools/llvm-mc/llvm-mc.cpp             | 43 +++++++++++++---------
 5 files changed, 69 insertions(+), 26 deletions(-)

diff --git a/bolt/lib/Utils/CommandLineOpts.cpp b/bolt/lib/Utils/CommandLineOpts.cpp
index 5635da476451d..d4d6dbcb72aac 100644
--- a/bolt/lib/Utils/CommandLineOpts.cpp
+++ b/bolt/lib/Utils/CommandLineOpts.cpp
@@ -202,7 +202,7 @@ cl::opt<bool> Lite("lite", cl::desc("skip processing of cold functions"),
                    cl::cat(BoltCategory));
 
 cl::opt<std::string>
-OutputFilename("o",
+OutputFilename("ooo",
   cl::desc("<output file>"),
   cl::Optional,
   cl::cat(BoltOutputCategory));
diff --git a/llvm/tools/llvm-mc/CFIAnalysis.h b/llvm/tools/llvm-mc/CFIAnalysis.h
index f527043d3dbbb..e3a09139d42af 100644
--- a/llvm/tools/llvm-mc/CFIAnalysis.h
+++ b/llvm/tools/llvm-mc/CFIAnalysis.h
@@ -1,8 +1,8 @@
 #ifndef LLVM_TOOLS_LLVM_MC_CFI_ANALYSIS_H
 #define LLVM_TOOLS_LLVM_MC_CFI_ANALYSIS_H
 
+#include "bolt/Core/MCPlusBuilder.h"
 #include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCDwarf.h"
@@ -11,12 +11,32 @@
 #include "llvm/MC/MCInstrInfo.h"
 #include "llvm/MC/MCRegisterInfo.h"
 #include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/TargetRegistry.h"
 #include "llvm/Support/Debug.h"
-#include <ostream>
+#include <memory>
 #include <set>
 
 namespace llvm {
 
+bolt::MCPlusBuilder *createMCPlusBuilder(const Triple::ArchType Arch,
+                                         const MCInstrAnalysis *Analysis,
+                                         const MCInstrInfo *Info,
+                                         const MCRegisterInfo *RegInfo,
+                                         const MCSubtargetInfo *STI) {
+  dbgs() << "arch: " << Arch << ", and expected " << Triple::x86_64 << "\n";
+  if (Arch == Triple::x86_64)
+    return bolt::createX86MCPlusBuilder(Analysis, Info, RegInfo, STI);
+
+  // if (Arch == Triple::aarch64)
+  //   return createAArch64MCPlusBuilder(Analysis, Info, RegInfo, STI);
+
+  // if (Arch == Triple::riscv64)
+  //   return createRISCVMCPlusBuilder(Analysis, Info, RegInfo, STI);
+
+  llvm_unreachable("architecture unsupported by MCPlusBuilder");
+}
+
 // TODO remove it, it's just for debug purposes.
 void printUntilNextLine(const char *Str) {
   for (int I = 0; Str[I] != '\0' && Str[I] != '\n'; I++)
@@ -26,19 +46,24 @@ void printUntilNextLine(const char *Str) {
 class CFIAnalysis {
   MCContext &Context;
   MCInstrInfo const &MCII;
+  std::unique_ptr<bolt::MCPlusBuilder> MCPB;
 
 public:
-  CFIAnalysis(MCContext &Context, MCInstrInfo const &MCII)
+  CFIAnalysis(MCContext &Context, MCInstrInfo const &MCII,
+              MCInstrAnalysis *MCIA)
       : Context(Context), MCII(MCII) {
     // TODO it should look at the poluge directives and setup the
     // registers' previous value state here, but for now, it's assumed that all
     // values are by default `samevalue`.
+    MCPB.reset(createMCPlusBuilder(Context.getTargetTriple().getArch(), MCIA,
+                                   &MCII, Context.getRegisterInfo(),
+                                   Context.getSubtargetInfo()));
   }
 
   void update(const MCDwarfFrameInfo &DwarfFrame, const MCInst &Inst,
               ArrayRef<MCCFIInstruction> CFIDirectives) {
 
-    auto MCInstInfo = MCII.get(Inst.getOpcode());
+    const MCInstrDesc &MCInstInfo = MCII.get(Inst.getOpcode());
     auto *RI = Context.getRegisterInfo();
     auto CFAReg = RI->getLLVMRegNum(DwarfFrame.CurrentCfaRegister, false);
 
@@ -95,6 +120,8 @@ class CFIAnalysis {
     }
     dbgs() << "}\n";
     dbgs() << "-----------------------------------------\n";
+    dbgs() << "isMoveMem2Reg: " << MCPB->isMoveMem2Reg(Inst) << "\n";
+    dbgs() << "-----------------------------------------\n";
     dbgs() << "The CFA register is: " << CFAReg << "\n";
     dbgs() << "The instruction does " << (ChangedCFA ? "" : "NOT ")
            << "change the CFA.\n";
diff --git a/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h b/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h
index 76ae536ab4bd3..382a80aca94b4 100644
--- a/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h
+++ b/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h
@@ -6,15 +6,18 @@
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCDwarf.h"
+#include "llvm/MC/MCInstrAnalysis.h"
 #include "llvm/MC/MCInstrInfo.h"
 #include "llvm/MC/MCStreamer.h"
 #include <cstdio>
+#include <memory>
 #include <optional>
 
 namespace llvm {
 
 class CFIAnalysisMCStreamer : public MCStreamer {
   MCInstrInfo const &MCII;
+  std::unique_ptr<MCInstrAnalysis> MCIA;
 
   struct CFIDirectivesState {
     int FrameIndex; // TODO remove it, no need for it
@@ -86,9 +89,10 @@ class CFIAnalysisMCStreamer : public MCStreamer {
   }
 
 public:
-  CFIAnalysisMCStreamer(MCContext &Context, const MCInstrInfo &MCII)
-      : MCStreamer(Context), MCII(MCII), LastCFIDirectivesState(),
-        LastInstruction(std::nullopt) {
+  CFIAnalysisMCStreamer(MCContext &Context, const MCInstrInfo &MCII,
+                        std::unique_ptr<MCInstrAnalysis> MCIA)
+      : MCStreamer(Context), MCII(MCII), MCIA(std::move(MCIA)),
+        LastCFIDirectivesState(), LastInstruction(std::nullopt) {
     FrameIndices.push_back(-1);
   }
 
@@ -125,7 +129,7 @@ class CFIAnalysisMCStreamer : public MCStreamer {
   void emitCFIStartProcImpl(MCDwarfFrameInfo &Frame) override {
     feedCFIA();
     FrameIndices.push_back(getNumFrameInfos());
-    CFIAs.emplace_back(getContext(), MCII);
+    CFIAs.emplace_back(getContext(), MCII, MCIA.get());
     LastInstruction = std::nullopt;
     LastDwarfFrameInfo = std::nullopt;
     LastCFIDirectivesState.FrameIndex = FrameIndices.back();
diff --git a/llvm/tools/llvm-mc/CMakeLists.txt b/llvm/tools/llvm-mc/CMakeLists.txt
index f57356f9ee0c0..368f29c62201f 100644
--- a/llvm/tools/llvm-mc/CMakeLists.txt
+++ b/llvm/tools/llvm-mc/CMakeLists.txt
@@ -13,3 +13,6 @@ add_llvm_tool(llvm-mc
   llvm-mc.cpp
   Disassembler.cpp
   )
+
+target_link_libraries(llvm-mc PRIVATE LLVMBOLTCore LLVMBOLTTargetX86)
+target_include_directories(llvm-mc PRIVATE "${LLVM_MAIN_SRC_DIR}/../bolt/include")
diff --git a/llvm/tools/llvm-mc/llvm-mc.cpp b/llvm/tools/llvm-mc/llvm-mc.cpp
index b59a54d8fbc8a..32f2fa0f05a7c 100644
--- a/llvm/tools/llvm-mc/llvm-mc.cpp
+++ b/llvm/tools/llvm-mc/llvm-mc.cpp
@@ -11,12 +11,14 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "CFIAnalysisMCStreamer.h"
 #include "Disassembler.h"
 #include "llvm/MC/MCAsmBackend.h"
 #include "llvm/MC/MCAsmInfo.h"
 #include "llvm/MC/MCCodeEmitter.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCInstPrinter.h"
+#include "llvm/MC/MCInstrAnalysis.h"
 #include "llvm/MC/MCInstrInfo.h"
 #include "llvm/MC/MCObjectFileInfo.h"
 #include "llvm/MC/MCObjectWriter.h"
@@ -25,6 +27,7 @@
 #include "llvm/MC/MCRegisterInfo.h"
 #include "llvm/MC/MCStreamer.h"
 #include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/MCTargetOptions.h"
 #include "llvm/MC/MCTargetOptionsCommandFlags.h"
 #include "llvm/MC/TargetRegistry.h"
 #include "llvm/Support/CommandLine.h"
@@ -37,7 +40,11 @@
 #include "llvm/Support/TargetSelect.h"
 #include "llvm/Support/ToolOutputFile.h"
 #include "llvm/Support/WithColor.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetOptions.h"
 #include "llvm/TargetParser/Host.h"
+#include <memory>
+#include <optional>
 
 using namespace llvm;
 
@@ -114,11 +121,7 @@ static cl::opt<unsigned> CommentColumn("comment-column",
                                        cl::desc("Asm comments indentation"),
                                        cl::init(40));
 
-enum OutputFileType {
-  OFT_Null,
-  OFT_AssemblyFile,
-  OFT_ObjectFile
-};
+enum OutputFileType { OFT_Null, OFT_AssemblyFile, OFT_ObjectFile };
 static cl::opt<OutputFileType>
     FileType("filetype", cl::init(OFT_AssemblyFile),
              cl::desc("Choose an output file type:"),
@@ -241,8 +244,8 @@ static const Target *GetTarget(const char *ProgName) {
 
   // Get the target specific parser.
   std::string Error;
-  const Target *TheTarget = TargetRegistry::lookupTarget(ArchName, TheTriple,
-                                                         Error);
+  const Target *TheTarget =
+      TargetRegistry::lookupTarget(ArchName, TheTriple, Error);
   if (!TheTarget) {
     WithColor::error(errs(), ProgName) << Error;
     return nullptr;
@@ -253,8 +256,8 @@ static const Target *GetTarget(const char *ProgName) {
   return TheTarget;
 }
 
-static std::unique_ptr<ToolOutputFile> GetOutputStream(StringRef Path,
-    sys::fs::OpenFlags Flags) {
+static std::unique_ptr<ToolOutputFile>
+GetOutputStream(StringRef Path, sys::fs::OpenFlags Flags) {
   std::error_code EC;
   auto Out = std::make_unique<ToolOutputFile>(Path, EC, Flags);
   if (EC) {
@@ -278,13 +281,12 @@ static void setDwarfDebugFlags(int argc, char **argv) {
 
 static std::string DwarfDebugProducer;
 static void setDwarfDebugProducer() {
-  if(!getenv("DEBUG_PRODUCER"))
+  if (!getenv("DEBUG_PRODUCER"))
     return;
   DwarfDebugProducer += getenv("DEBUG_PRODUCER");
 }
 
-static int AsLexInput(SourceMgr &SrcMgr, MCAsmInfo &MAI,
-                      raw_ostream &OS) {
+static int AsLexInput(SourceMgr &SrcMgr, MCAsmInfo &MAI, raw_ostream &OS) {
 
   AsmLexer Lexer(MAI);
   Lexer.setBuffer(SrcMgr.getMemoryBuffer(SrcMgr.getMainFileID())->getBuffer());
@@ -301,7 +303,7 @@ static int AsLexInput(SourceMgr &SrcMgr, MCAsmInfo &MAI,
 }
 
 static int fillCommandLineSymbols(MCAsmParser &Parser) {
-  for (auto &I: DefineSymbol) {
+  for (auto &I : DefineSymbol) {
     auto Pair = StringRef(I).split('=');
     auto Sym = Pair.first;
     auto Val = Pair.second;
@@ -325,8 +327,7 @@ static int AssembleInput(const char *ProgName, const Target *TheTarget,
                          SourceMgr &SrcMgr, MCContext &Ctx, MCStreamer &Str,
                          MCAsmInfo &MAI, MCSubtargetInfo &STI,
                          MCInstrInfo &MCII, MCTargetOptions const &MCOptions) {
-  std::unique_ptr<MCAsmParser> Parser(
-      createMCAsmParser(SrcMgr, Ctx, Str, MAI));
+  std::unique_ptr<MCAsmParser> Parser(createMCAsmParser(SrcMgr, Ctx, Str, MAI));
   std::unique_ptr<MCTargetAsmParser> TAP(
       TheTarget->createMCAsmParser(STI, *Parser, MCII, MCOptions));
 
@@ -337,7 +338,7 @@ static int AssembleInput(const char *ProgName, const Target *TheTarget,
   }
 
   int SymbolResult = fillCommandLineSymbols(*Parser);
-  if(SymbolResult)
+  if (SymbolResult)
     return SymbolResult;
   Parser->setShowParsedOperands(ShowInstOperands);
   Parser->setTargetParser(*TAP);
@@ -519,6 +520,10 @@ int main(int argc, char **argv) {
   std::unique_ptr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo());
   assert(MCII && "Unable to create instruction info!");
 
+  std::unique_ptr<MCInstrAnalysis> MCIA(
+      TheTarget->createMCInstrAnalysis(MCII.get()));
+  assert(MCIA && "Unable to create instruction analysis!");
+
   std::unique_ptr<MCInstPrinter> IP;
   if (FileType == OFT_AssemblyFile) {
     IP.reset(TheTarget->createMCInstPrinter(
@@ -564,7 +569,11 @@ int main(int argc, char **argv) {
                                            std::move(CE), std::move(MAB)));
 
   } else if (FileType == OFT_Null) {
-    Str.reset(TheTarget->createNullStreamer(Ctx));
+    auto *MyDummyStreamer =
+        new CFIAnalysisMCStreamer(Ctx, *MCII, std::move(MCIA));
+    TheTarget->createNullTargetStreamer(*MyDummyStreamer);
+    Str.reset(MyDummyStreamer);
+    // Str.reset(TheTarget->createNullStreamer(Ctx));
   } else {
     assert(FileType == OFT_ObjectFile && "Invalid file type!");
 

>From 75f3b2dfa38ca24e274868ce7a5f5ab00cb58e7f Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Tue, 13 May 2025 00:17:57 +0000
Subject: [PATCH 05/58] Extract semantic info on MCInst from bolt

---
 llvm/tools/llvm-mc/CFIAnalysis.h | 152 +++++++++++++++++++++++++++----
 1 file changed, 136 insertions(+), 16 deletions(-)

diff --git a/llvm/tools/llvm-mc/CFIAnalysis.h b/llvm/tools/llvm-mc/CFIAnalysis.h
index e3a09139d42af..70b8a855643b9 100644
--- a/llvm/tools/llvm-mc/CFIAnalysis.h
+++ b/llvm/tools/llvm-mc/CFIAnalysis.h
@@ -4,17 +4,21 @@
 #include "bolt/Core/MCPlusBuilder.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCDwarf.h"
 #include "llvm/MC/MCExpr.h"
 #include "llvm/MC/MCInst.h"
 #include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCRegister.h"
 #include "llvm/MC/MCRegisterInfo.h"
 #include "llvm/MC/MCStreamer.h"
 #include "llvm/MC/MCSubtargetInfo.h"
 #include "llvm/MC/TargetRegistry.h"
 #include "llvm/Support/Debug.h"
+#include "llvm/Support/Error.h"
 #include <memory>
+#include <optional>
 #include <set>
 
 namespace llvm {
@@ -60,7 +64,7 @@ class CFIAnalysis {
                                    Context.getSubtargetInfo()));
   }
 
-  void update(const MCDwarfFrameInfo &DwarfFrame, const MCInst &Inst,
+  void update(const MCDwarfFrameInfo &DwarfFrame, MCInst &Inst,
               ArrayRef<MCCFIInstruction> CFIDirectives) {
 
     const MCInstrDesc &MCInstInfo = MCII.get(Inst.getOpcode());
@@ -71,8 +75,8 @@ class CFIAnalysis {
     // FIXME this way of extracting uses is buggy:
     // for (unsigned I = 0; I < MCInstInfo.NumImplicitUses; I++)
     //   Reads.insert(MCInstInfo.implicit_uses()[I]);
-    // for (unsigned I = 0; I < MCInstInfo.NumImplicitDefs; I++)
-    //   Writes.insert(MCInstInfo.implicit_defs()[I]);
+    for (unsigned I = 0; I < MCInstInfo.NumImplicitDefs; I++)
+      Writes.insert(MCInstInfo.implicit_defs()[I]);
 
     for (unsigned I = 0; I < Inst.getNumOperands(); I++) {
       auto &&Operand = Inst.getOperand(I);
@@ -113,20 +117,136 @@ class CFIAnalysis {
     dbgs() << "^^^^^^^^^^^^^^^^ InsCFIs ^^^^^^^^^^^^^^^^\n";
     printUntilNextLine(Inst.getLoc().getPointer());
     dbgs() << "\n";
-    dbgs() << "-----------------------------------------\n";
-    dbgs() << "writes into: { ";
-    for (auto Reg : Writes) {
-      dbgs() << (int)Reg << " ";
+    dbgs() << "Op code: " << Inst.getOpcode() << "\n";
+    dbgs() << "--------------Operands Info--------------\n";
+    auto DefCount = MCInstInfo.getNumDefs();
+    for (unsigned I = 0; I < Inst.getNumOperands(); I++) {
+      dbgs() << "Operand #" << I << ", which will be "
+             << (I < DefCount ? "defined" : "used") << ", is a";
+      if (I == MCPB->getMemoryOperandNo(Inst)) {
+        dbgs() << " memory access, details are:\n";
+        auto X86MemoryOperand = MCPB->evaluateX86MemoryOperand(Inst);
+        dbgs() << "  Base Register{ reg#" << X86MemoryOperand->BaseRegNum
+               << " }";
+        dbgs() << " + (Index Register{ reg#" << X86MemoryOperand->IndexRegNum
+               << " }";
+        dbgs() << " * Scale{ value " << X86MemoryOperand->ScaleImm << " }";
+        dbgs() << ") + Displacement{ "
+               << (X86MemoryOperand->DispExpr
+                       ? "an expression"
+                       : "value " + itostr(X86MemoryOperand->DispImm))
+               << " }\n";
+        // TODO, it's not correct always, it cannot be assumed (or should be
+        // checked) that memory operands are flatten into 4 operands in MCInc.
+        I += 4;
+        continue;
+      }
+      auto &&Operand = Inst.getOperand(I);
+      if (Operand.isImm()) {
+        dbgs() << "n immediate with value " << Operand.getImm() << "\n";
+        continue;
+      }
+      if (Operand.isReg()) {
+        dbgs() << " reg#" << Operand.getReg() << "\n";
+        continue;
+      }
+      assert(Operand.isExpr());
+      dbgs() << "n unknown expression \n";
+    }
+    if (MCInstInfo.NumImplicitDefs) {
+      dbgs() << "implicitly defines: { ";
+      for (unsigned I = 0; I < MCInstInfo.NumImplicitDefs; I++) {
+        dbgs() << "reg#" << MCInstInfo.implicit_defs()[I] << " ";
+      }
+      dbgs() << "}\n";
+    }
+    if (MCInstInfo.NumImplicitUses) {
+      dbgs() << "implicitly uses: { ";
+      for (unsigned I = 0; I < MCInstInfo.NumImplicitUses; I++) {
+        dbgs() << "reg#" << MCInstInfo.implicit_uses()[I] << " ";
+      }
+      dbgs() << "}\n";
+    }
+    dbgs() << "----------------Move Info----------------\n";
+    {   // move
+      { // Reg2Reg
+        MCPhysReg From, To;
+        if (MCPB->isRegToRegMove(Inst, From, To)) {
+          dbgs() << "It's a reg to reg move.\nFrom reg#" << From << " to reg#"
+                 << To << "\n";
+        } else if (MCInstInfo.isMoveReg()) {
+          dbgs() << "It's reg to reg move from MCInstInfo view but not from "
+                    "MCPlus view.\n";
+        }
+      }
+      if (MCPB->isConditionalMove(Inst)) {
+        dbgs() << "Its a conditional move.\n";
+      }
+      if (MCPB->isMoveMem2Reg(Inst)) {
+        dbgs() << "It's a move from memory to register\n";
+        assert(MCPB->getMemoryOperandNo(Inst) == 1);
+      }
+    }
+
+    dbgs() << "---------------Stack Info----------------\n";
+    { // stack
+      int32_t SrcImm = 0;
+      MCPhysReg Reg = 0;
+      uint16_t StackPtrReg = 0;
+      int64_t StackOffset = 0;
+      uint8_t Size = 0;
+      bool IsSimple = false;
+      bool IsIndexed = false;
+      bool IsLoad = false;
+      bool IsStore = false;
+      bool IsStoreFromReg = false;
+      if (MCPB->isStackAccess(Inst, IsLoad, IsStore, IsStoreFromReg, Reg,
+                              SrcImm, StackPtrReg, StackOffset, Size, IsSimple,
+                              IsIndexed)) {
+        dbgs() << "This instruction accesses the stack, the details are:\n";
+        dbgs() << "  Source immediate: " << SrcImm << "\n";
+        dbgs() << "  Source reg#" << Reg << "\n";
+        dbgs() << "  Stack pointer: reg#" << StackPtrReg << "\n";
+        dbgs() << "  Stack offset: " << StackOffset << "\n";
+        dbgs() << "  size: " << (int)Size << "\n";
+        dbgs() << "  Is simple: " << (IsSimple ? "yes" : "no") << "\n";
+        dbgs() << "  Is indexed: " << (IsIndexed ? "yes" : "no") << "\n";
+        dbgs() << "  Is load: " << (IsLoad ? "yes" : "no") << "\n";
+        dbgs() << "  Is store: " << (IsStore ? "yes" : "no") << "\n";
+        dbgs() << "  Is store from reg: " << (IsStoreFromReg ? "yes" : "no")
+               << "\n";
+      }
+      if (MCPB->isPush(Inst)) {
+        dbgs() << "This is a push instruction with size "
+               << MCPB->getPushSize(Inst) << "\n";
+      }
+      if (MCPB->isPop(Inst)) {
+        dbgs() << "This is a pop instruction with size "
+               << MCPB->getPopSize(Inst) << "\n";
+      }
+    }
+
+    dbgs() << "---------------Arith Info----------------\n";
+    { // arith
+      MutableArrayRef<MCInst> MAR = {Inst};
+      if (MCPB->matchAdd(MCPB->matchAnyOperand(), MCPB->matchAnyOperand())
+              ->match(*RI, *MCPB, MutableArrayRef<MCInst>(), -1)) {
+        dbgs() << "It is an addition instruction.\n";
+      } else if (MCInstInfo.isAdd()) {
+        dbgs() << "It is an addition from MCInstInfo view but not from MCPlus "
+                  "view.\n";
+      }
+      if (MCPB->isSUB(Inst)) {
+        dbgs() << "This is a subtraction.\n";
+      }
     }
-    dbgs() << "}\n";
-    dbgs() << "-----------------------------------------\n";
-    dbgs() << "isMoveMem2Reg: " << MCPB->isMoveMem2Reg(Inst) << "\n";
-    dbgs() << "-----------------------------------------\n";
-    dbgs() << "The CFA register is: " << CFAReg << "\n";
-    dbgs() << "The instruction does " << (ChangedCFA ? "" : "NOT ")
-           << "change the CFA.\n";
-    dbgs() << "The CFI directives does " << (GoingToChangeCFA ? "" : "NOT ")
-           << "change the CFA.\n";
+
+    // dbgs() << "-----------------------------------------\n";
+    // dbgs() << "The CFA register is: " << CFAReg << "\n";
+    // dbgs() << "The instruction does " << (ChangedCFA ? "" : "NOT ")
+    //        << "change the CFA.\n";
+    // dbgs() << "The CFI directives does " << (GoingToChangeCFA ? "" : "NOT ")
+    //        << "change the CFA.\n";
     dbgs() << "vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n";
     ChangedCFA = false;
   }

>From a3d08d897bff5c75441eb1bbc00b1192c22d6fe4 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Tue, 13 May 2025 22:50:03 +0000
Subject: [PATCH 06/58] Typo in evaluateStackOffsetExpr doc

---
 bolt/include/bolt/Core/MCPlusBuilder.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/bolt/include/bolt/Core/MCPlusBuilder.h b/bolt/include/bolt/Core/MCPlusBuilder.h
index 804100db80793..c168f06762c0d 100644
--- a/bolt/include/bolt/Core/MCPlusBuilder.h
+++ b/bolt/include/bolt/Core/MCPlusBuilder.h
@@ -1164,7 +1164,7 @@ class MCPlusBuilder {
     return false;
   }
 
-  /// Use \p Input1 or Input2 as the current value for the input
+  /// Use \p Input1 or \p Input2 as the current value for the input
   /// register and put in \p Output the changes incurred by executing
   /// \p Inst. Return false if it was not possible to perform the
   /// evaluation. evaluateStackOffsetExpr is restricted to operations

>From 7a109231849989de93e846735adaec58be6a04ec Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Tue, 13 May 2025 22:50:40 +0000
Subject: [PATCH 07/58] Add a DS to keep track of each register CFI state

---
 llvm/tools/llvm-mc/CFIState.h | 160 ++++++++++++++++++++++++++++++++++
 1 file changed, 160 insertions(+)
 create mode 100644 llvm/tools/llvm-mc/CFIState.h

diff --git a/llvm/tools/llvm-mc/CFIState.h b/llvm/tools/llvm-mc/CFIState.h
new file mode 100644
index 0000000000000..b32de2b385316
--- /dev/null
+++ b/llvm/tools/llvm-mc/CFIState.h
@@ -0,0 +1,160 @@
+#ifndef LLVM_TOOLS_LLVM_MC_CFI_STATE_H
+#define LLVM_TOOLS_LLVM_MC_CFI_STATE_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/MC/MCDwarf.h"
+#include "llvm/MC/MCRegister.h"
+#include "llvm/Support/MathExtras.h"
+#include <cstdint>
+namespace llvm {
+
+using DWARFRegType = int64_t;
+
+struct RegisterCFIState {
+  enum Approach {
+    Undefined,
+    SameValue,
+    AnotherRegister,
+    OffsetFromCFAAddr,
+    OffsetFromCFAVal,
+    Other,
+  } RetrieveApproach;
+
+  // TODO use a correct type for this.
+  union {
+    int OffsetFromCFA;
+    DWARFRegType Register;
+  } Info;
+
+  static RegisterCFIState createUndefined() {
+    RegisterCFIState State;
+    State.RetrieveApproach = Undefined;
+
+    return State;
+  }
+
+  static RegisterCFIState createSameValue() {
+    RegisterCFIState State;
+    State.RetrieveApproach = SameValue;
+
+    return State;
+  }
+
+  static RegisterCFIState createAnotherRegister(DWARFRegType Register) {
+    RegisterCFIState State;
+    State.RetrieveApproach = AnotherRegister;
+    State.Info.Register = Register;
+
+    return State;
+  }
+
+  static RegisterCFIState createOffsetFromCFAAddr(int OffsetFromCFA) {
+    RegisterCFIState State;
+    State.RetrieveApproach = OffsetFromCFAAddr;
+    State.Info.OffsetFromCFA = OffsetFromCFA;
+
+    return State;
+  }
+
+  static RegisterCFIState createOffsetFromCFAVal(int OffsetFromCFA) {
+    RegisterCFIState State;
+    State.RetrieveApproach = OffsetFromCFAVal;
+    State.Info.OffsetFromCFA = OffsetFromCFA;
+
+    return State;
+  }
+
+  static RegisterCFIState createOther() {
+    RegisterCFIState State;
+    State.RetrieveApproach = Other;
+
+    return State;
+  }
+};
+struct CFIState {
+  DenseMap<DWARFRegType, RegisterCFIState> RegisterCFIStates;
+  DWARFRegType CFARegister;
+  int CFAOffset;
+
+  CFIState() : CFARegister(-1 /* Change to to max unsigned */), CFAOffset(-1) {}
+
+  CFIState(const CFIState &Other) {
+    CFARegister = Other.CFARegister;
+    CFAOffset = Other.CFAOffset;
+    RegisterCFIStates = Other.RegisterCFIStates;
+  }
+
+  CFIState &operator=(const CFIState &Other) {
+    if (this != &Other) {
+      CFARegister = Other.CFARegister;
+      CFAOffset = Other.CFAOffset;
+      RegisterCFIStates = Other.RegisterCFIStates;
+    }
+
+    return *this;
+  }
+
+  CFIState(DWARFRegType CFARegister, int CFIOffset)
+      : CFARegister(CFARegister), CFAOffset(CFIOffset) {}
+
+  bool apply(const MCCFIInstruction &CFIDirective) {
+    switch (CFIDirective.getOperation()) {
+    case MCCFIInstruction::OpDefCfaRegister:
+      CFARegister = CFIDirective.getRegister();
+      break;
+    case MCCFIInstruction::OpDefCfaOffset:
+      CFAOffset = CFIDirective.getOffset();
+      break;
+    case MCCFIInstruction::OpAdjustCfaOffset:
+      CFAOffset += CFIDirective.getOffset();
+      break;
+    case MCCFIInstruction::OpDefCfa:
+      CFARegister = CFIDirective.getRegister();
+      CFAOffset = CFIDirective.getOffset();
+      break;
+    case MCCFIInstruction::OpOffset:
+      RegisterCFIStates[CFIDirective.getRegister()] =
+          RegisterCFIState::createOffsetFromCFAAddr(CFIDirective.getOffset());
+      break;
+    case MCCFIInstruction::OpRegister:
+      RegisterCFIStates[CFIDirective.getRegister()] =
+          RegisterCFIState::createAnotherRegister(CFIDirective.getRegister2());
+      break;
+    case MCCFIInstruction::OpRelOffset:
+      RegisterCFIStates[CFIDirective.getRegister()] =
+          RegisterCFIState::createOffsetFromCFAAddr(CFIDirective.getOffset() -
+                                                    CFAOffset);
+      break;
+    case MCCFIInstruction::OpUndefined:
+      RegisterCFIStates[CFIDirective.getRegister()] =
+          RegisterCFIState::createUndefined();
+      break;
+    case MCCFIInstruction::OpSameValue:
+      RegisterCFIStates[CFIDirective.getRegister()] =
+          RegisterCFIState::createSameValue();
+      break;
+    case MCCFIInstruction::OpValOffset:
+      RegisterCFIStates[CFIDirective.getRegister()] =
+          RegisterCFIState::createOffsetFromCFAVal(CFIDirective.getOffset());
+      break;
+    case MCCFIInstruction::OpRestoreState:
+    case MCCFIInstruction::OpRememberState:
+    case MCCFIInstruction::OpLLVMDefAspaceCfa:
+    case MCCFIInstruction::OpRestore:
+    case MCCFIInstruction::OpEscape:
+    case MCCFIInstruction::OpWindowSave:
+    case MCCFIInstruction::OpNegateRAState:
+    case MCCFIInstruction::OpNegateRAStateWithPC:
+    case MCCFIInstruction::OpGnuArgsSize:
+    case MCCFIInstruction::OpLabel:
+      // TODO it's not supported.
+      return false;
+      break;
+    }
+
+    return true;
+  }
+};
+} // namespace llvm
+
+#endif
\ No newline at end of file

>From 5841b8fae1dda3c13b8b87c58a7c7a404a8cb5e2 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Wed, 14 May 2025 18:19:55 +0000
Subject: [PATCH 08/58] Check if the CFA change is correct or not

---
 llvm/tools/llvm-mc/CFIAnalysis.h           | 457 ++++++++++++++-------
 llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h |  36 +-
 2 files changed, 326 insertions(+), 167 deletions(-)

diff --git a/llvm/tools/llvm-mc/CFIAnalysis.h b/llvm/tools/llvm-mc/CFIAnalysis.h
index 70b8a855643b9..424290f3cab86 100644
--- a/llvm/tools/llvm-mc/CFIAnalysis.h
+++ b/llvm/tools/llvm-mc/CFIAnalysis.h
@@ -1,10 +1,12 @@
 #ifndef LLVM_TOOLS_LLVM_MC_CFI_ANALYSIS_H
 #define LLVM_TOOLS_LLVM_MC_CFI_ANALYSIS_H
 
+#include "CFIState.h"
 #include "bolt/Core/MCPlusBuilder.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/Twine.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCDwarf.h"
 #include "llvm/MC/MCExpr.h"
@@ -17,6 +19,8 @@
 #include "llvm/MC/TargetRegistry.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/Error.h"
+#include "llvm/Support/FormatVariadic.h"
+#include <cstdint>
 #include <memory>
 #include <optional>
 #include <set>
@@ -51,51 +55,196 @@ class CFIAnalysis {
   MCContext &Context;
   MCInstrInfo const &MCII;
   std::unique_ptr<bolt::MCPlusBuilder> MCPB;
+  MCRegisterInfo const *MCRI;
+  CFIState State;
 
 public:
   CFIAnalysis(MCContext &Context, MCInstrInfo const &MCII,
               MCInstrAnalysis *MCIA)
-      : Context(Context), MCII(MCII) {
-    // TODO it should look at the poluge directives and setup the
+      : Context(Context), MCII(MCII), MCRI(Context.getRegisterInfo()) {
+    // TODO it should look at the prologue directives and setup the
     // registers' previous value state here, but for now, it's assumed that all
     // values are by default `samevalue`.
     MCPB.reset(createMCPlusBuilder(Context.getTargetTriple().getArch(), MCIA,
                                    &MCII, Context.getRegisterInfo(),
                                    Context.getSubtargetInfo()));
+
+    // TODO CFA offset should be the slot size, but for now I don't have any
+    // access to it, maybe can be read from the prologue
+    // TODO check what should be passed as EH?
+    State = CFIState(MCRI->getDwarfRegNum(MCPB->getStackPointer(), false), 8);
+    for (unsigned I = 0; I < MCRI->getNumRegs(); I++) {
+      DWARFRegType DwarfI = MCRI->getDwarfRegNum(I, false);
+      State.RegisterCFIStates[DwarfI] = RegisterCFIState::createSameValue();
+    }
+
+    // TODO these are temporay added to make things work.
+    // Setup the basic information:
+    State.RegisterCFIStates[MCRI->getDwarfRegNum(MCRI->getProgramCounter(),
+                                                 false)] =
+        RegisterCFIState::createUndefined(); // For now, we don't care about the
+                                             // PC
+    State.RegisterCFIStates[MCRI->getDwarfRegNum(MCPB->getStackPointer(),
+                                                 false)] =
+        RegisterCFIState::createOffsetFromCFAVal(0); // sp's old value is CFA
+  }
+
+  bool doesConstantChange(const MCInst &Inst, MCPhysReg Reg, int64_t &HowMuch) {
+    if (MCPB->isPush(Inst) && Reg == MCPB->getStackPointer()) {
+      // TODO should get the stack direction here, now it assumes that it goes
+      // down.
+      HowMuch = -MCPB->getPushSize(Inst);
+      return true;
+    }
+
+    if (MCPB->isPop(Inst) && Reg == MCPB->getStackPointer()) {
+      // TODO should get the stack direction here, now it assumes that it goes
+      // down.
+      HowMuch = MCPB->getPushSize(Inst);
+      return true;
+    }
+
+    return false;
+  }
+
+  // Tries to guess Reg1's value in a form of Reg2 (before Inst's execution) +
+  // Diff.
+  bool isInConstantDistanceOfEachOther(const MCInst &Inst, MCPhysReg Reg1,
+                                       MCPhysReg Reg2, int &Diff) {
+    {
+      MCPhysReg From;
+      MCPhysReg To;
+      if (MCPB->isRegToRegMove(Inst, From, To) && From == Reg2 && To == Reg1) {
+        Diff = 0;
+        return true;
+      }
+    }
+
+    return false;
+  }
+
+  void checkCFADiff(const MCInst &Inst, const CFIState &PrevState,
+                    const CFIState &NextState,
+                    const std::set<DWARFRegType> &Reads,
+                    const std::set<DWARFRegType> &Writes) {
+    if (PrevState.CFARegister == NextState.CFARegister) {
+      if (PrevState.CFAOffset == NextState.CFAOffset) {
+        if (Writes.count(PrevState.CFARegister)) {
+          Context.reportWarning(
+              Inst.getLoc(),
+              formatv("This instruction changes reg#{0}, which is "
+                      "the CFA register, but the CFI directives do not.",
+                      MCRI->getLLVMRegNum(PrevState.CFARegister, false)));
+        }
+        return;
+      }
+      // The offset is changed.
+      if (!Writes.count(PrevState.CFARegister)) {
+        Context.reportWarning(
+            Inst.getLoc(),
+            formatv(
+                "You changed the CFA offset, but there is no modification to "
+                "the CFA register happening in this instruction."));
+      }
+      int64_t HowMuch;
+      if (!doesConstantChange(
+              Inst, MCRI->getLLVMRegNum(PrevState.CFARegister, false).value(),
+              HowMuch)) {
+        Context.reportWarning(
+            Inst.getLoc(),
+            formatv("The CFA register changed, but I don't know how, finger "
+                    "crossed the CFI directives are correct."));
+        return;
+      }
+      // we know it is changed by HowMuch, so the CFA offset should be changed
+      // by -HowMuch, i.e. AfterState.Offset - State.Offset = -HowMuch
+      if (NextState.CFAOffset - PrevState.CFAOffset != -HowMuch) {
+        Context.reportError(
+            Inst.getLoc(),
+            formatv("The CFA offset is changed by {0}, but "
+                    "the directives changed it by {1}. (to be exact, the new "
+                    "offset should be {2}, but it is {3})",
+                    -HowMuch, NextState.CFAOffset - PrevState.CFAOffset,
+                    PrevState.CFAOffset - HowMuch, NextState.CFAOffset));
+        return;
+      }
+
+      // Everything OK!
+      return;
+    }
+    // The CFA register is changed.
+    // TODO move it up
+    MCPhysReg OldCFAReg = MCRI->getLLVMRegNum(PrevState.CFARegister, false).value();
+    MCPhysReg NewCFAReg =
+        MCRI->getLLVMRegNum(NextState.CFARegister, false).value();
+    if (!Writes.count(NextState.CFARegister)) {
+      Context.reportWarning(
+          Inst.getLoc(),
+          formatv(
+              "The new CFA register reg#{0}'s value is not assigned by this "
+              "instruction, try to move the new CFA def to where this "
+              "value is changed, now I can't infer if this change is "
+              "correct or not.",
+              NewCFAReg));
+      return;
+    }
+    // Because CFA should is the CFA always stays the same:
+    int OffsetDiff = PrevState.CFAOffset - NextState.CFAOffset;
+    int Diff;
+    if (!isInConstantDistanceOfEachOther(Inst, NewCFAReg, OldCFAReg, Diff)) {
+      Context.reportWarning(
+          Inst.getLoc(),
+          formatv("Based on this instruction I cannot infer that the new and "
+                  "old CFA registers are in {0} distance of each other. I "
+                  "hope it's ok.",
+                  OffsetDiff));
+      return;
+    }
+    if (Diff != OffsetDiff) {
+      Context.reportError(
+          Inst.getLoc(), formatv("After changing the CFA register, the CFA "
+                                 "offset should be {0}, but it is {1}.",
+                                 PrevState.CFAOffset - Diff, NextState.CFAOffset));
+      return;
+    }
+    // Everything is OK!
   }
 
   void update(const MCDwarfFrameInfo &DwarfFrame, MCInst &Inst,
-              ArrayRef<MCCFIInstruction> CFIDirectives) {
+              std::pair<unsigned, unsigned>
+                  CFIDirectivesRange) { // FIXME this should not be a pair,
+                                        // but an ArrayRef
+    ArrayRef<MCCFIInstruction> CFIDirectives(DwarfFrame.Instructions);
+    CFIDirectives = CFIDirectives.drop_front(CFIDirectivesRange.first)
+                        .drop_back(DwarfFrame.Instructions.size() -
+                                   CFIDirectivesRange.second);
 
     const MCInstrDesc &MCInstInfo = MCII.get(Inst.getOpcode());
-    auto *RI = Context.getRegisterInfo();
-    auto CFAReg = RI->getLLVMRegNum(DwarfFrame.CurrentCfaRegister, false);
+    CFIState AfterState(State);
+    for (auto &&CFIDirective : CFIDirectives)
+      if (!AfterState.apply(CFIDirective))
+        Context.reportWarning(
+            CFIDirective.getLoc(),
+            "I don't support this CFI directive, I assume this does nothing "
+            "(which will probably break other things)");
+    auto CFAReg = MCRI->getLLVMRegNum(DwarfFrame.CurrentCfaRegister, false);
+    assert(DwarfFrame.CurrentCfaRegister == AfterState.CFARegister &&
+           "Checking if the CFA tracking is working");
 
-    std::set<int> Writes, Reads; // TODO reads is not ready for now
-    // FIXME this way of extracting uses is buggy:
-    // for (unsigned I = 0; I < MCInstInfo.NumImplicitUses; I++)
-    //   Reads.insert(MCInstInfo.implicit_uses()[I]);
+    std::set<DWARFRegType> Writes, Reads;
+    for (unsigned I = 0; I < MCInstInfo.NumImplicitUses; I++)
+      Reads.insert(MCRI->getDwarfRegNum(MCInstInfo.implicit_uses()[I], false));
     for (unsigned I = 0; I < MCInstInfo.NumImplicitDefs; I++)
-      Writes.insert(MCInstInfo.implicit_defs()[I]);
+      Writes.insert(MCRI->getDwarfRegNum(MCInstInfo.implicit_defs()[I], false));
 
     for (unsigned I = 0; I < Inst.getNumOperands(); I++) {
       auto &&Operand = Inst.getOperand(I);
       if (Operand.isReg()) {
-        // TODO it is not percise, maybe this operand is for output, then it
-        // means that there is no read happening here.
-        Reads.insert(Operand.getReg());
-      }
-
-      if (Operand.isExpr()) {
-        // TODO maybe the argument is not a register, but is a expression like
-        // `34(sp)` that has a register in it. Check if this works or not and if
-        // no change it somehow that it count that register as reads or writes
-        // too.
+        if (I < MCInstInfo.getNumDefs())
+          Writes.insert(MCRI->getDwarfRegNum(Operand.getReg(), false));
+        else
+          Reads.insert(MCRI->getDwarfRegNum(Operand.getReg(), false));
       }
-
-      if (Operand.isReg() &&
-          MCInstInfo.hasDefOfPhysReg(Inst, Operand.getReg(), *RI))
-        Writes.insert(Operand.getReg().id());
     }
 
     bool ChangedCFA = Writes.count(CFAReg->id());
@@ -114,132 +263,137 @@ class CFIAnalysis {
                           "CFI directives don't update the CFA.");
     }
 
-    dbgs() << "^^^^^^^^^^^^^^^^ InsCFIs ^^^^^^^^^^^^^^^^\n";
-    printUntilNextLine(Inst.getLoc().getPointer());
-    dbgs() << "\n";
-    dbgs() << "Op code: " << Inst.getOpcode() << "\n";
-    dbgs() << "--------------Operands Info--------------\n";
-    auto DefCount = MCInstInfo.getNumDefs();
-    for (unsigned I = 0; I < Inst.getNumOperands(); I++) {
-      dbgs() << "Operand #" << I << ", which will be "
-             << (I < DefCount ? "defined" : "used") << ", is a";
-      if (I == MCPB->getMemoryOperandNo(Inst)) {
-        dbgs() << " memory access, details are:\n";
-        auto X86MemoryOperand = MCPB->evaluateX86MemoryOperand(Inst);
-        dbgs() << "  Base Register{ reg#" << X86MemoryOperand->BaseRegNum
-               << " }";
-        dbgs() << " + (Index Register{ reg#" << X86MemoryOperand->IndexRegNum
-               << " }";
-        dbgs() << " * Scale{ value " << X86MemoryOperand->ScaleImm << " }";
-        dbgs() << ") + Displacement{ "
-               << (X86MemoryOperand->DispExpr
-                       ? "an expression"
-                       : "value " + itostr(X86MemoryOperand->DispImm))
-               << " }\n";
-        // TODO, it's not correct always, it cannot be assumed (or should be
-        // checked) that memory operands are flatten into 4 operands in MCInc.
-        I += 4;
-        continue;
-      }
-      auto &&Operand = Inst.getOperand(I);
-      if (Operand.isImm()) {
-        dbgs() << "n immediate with value " << Operand.getImm() << "\n";
-        continue;
-      }
-      if (Operand.isReg()) {
-        dbgs() << " reg#" << Operand.getReg() << "\n";
-        continue;
-      }
-      assert(Operand.isExpr());
-      dbgs() << "n unknown expression \n";
-    }
-    if (MCInstInfo.NumImplicitDefs) {
-      dbgs() << "implicitly defines: { ";
-      for (unsigned I = 0; I < MCInstInfo.NumImplicitDefs; I++) {
-        dbgs() << "reg#" << MCInstInfo.implicit_defs()[I] << " ";
-      }
-      dbgs() << "}\n";
-    }
-    if (MCInstInfo.NumImplicitUses) {
-      dbgs() << "implicitly uses: { ";
-      for (unsigned I = 0; I < MCInstInfo.NumImplicitUses; I++) {
-        dbgs() << "reg#" << MCInstInfo.implicit_uses()[I] << " ";
-      }
-      dbgs() << "}\n";
-    }
-    dbgs() << "----------------Move Info----------------\n";
-    {   // move
-      { // Reg2Reg
-        MCPhysReg From, To;
-        if (MCPB->isRegToRegMove(Inst, From, To)) {
-          dbgs() << "It's a reg to reg move.\nFrom reg#" << From << " to reg#"
-                 << To << "\n";
-        } else if (MCInstInfo.isMoveReg()) {
-          dbgs() << "It's reg to reg move from MCInstInfo view but not from "
-                    "MCPlus view.\n";
-        }
-      }
-      if (MCPB->isConditionalMove(Inst)) {
-        dbgs() << "Its a conditional move.\n";
-      }
-      if (MCPB->isMoveMem2Reg(Inst)) {
-        dbgs() << "It's a move from memory to register\n";
-        assert(MCPB->getMemoryOperandNo(Inst) == 1);
-      }
-    }
+    ///////////// being diffing the CFI states
+    checkCFADiff(Inst, State, AfterState, Reads, Writes);
+    ///////////// end diffing the CFI states
 
-    dbgs() << "---------------Stack Info----------------\n";
-    { // stack
-      int32_t SrcImm = 0;
-      MCPhysReg Reg = 0;
-      uint16_t StackPtrReg = 0;
-      int64_t StackOffset = 0;
-      uint8_t Size = 0;
-      bool IsSimple = false;
-      bool IsIndexed = false;
-      bool IsLoad = false;
-      bool IsStore = false;
-      bool IsStoreFromReg = false;
-      if (MCPB->isStackAccess(Inst, IsLoad, IsStore, IsStoreFromReg, Reg,
-                              SrcImm, StackPtrReg, StackOffset, Size, IsSimple,
-                              IsIndexed)) {
-        dbgs() << "This instruction accesses the stack, the details are:\n";
-        dbgs() << "  Source immediate: " << SrcImm << "\n";
-        dbgs() << "  Source reg#" << Reg << "\n";
-        dbgs() << "  Stack pointer: reg#" << StackPtrReg << "\n";
-        dbgs() << "  Stack offset: " << StackOffset << "\n";
-        dbgs() << "  size: " << (int)Size << "\n";
-        dbgs() << "  Is simple: " << (IsSimple ? "yes" : "no") << "\n";
-        dbgs() << "  Is indexed: " << (IsIndexed ? "yes" : "no") << "\n";
-        dbgs() << "  Is load: " << (IsLoad ? "yes" : "no") << "\n";
-        dbgs() << "  Is store: " << (IsStore ? "yes" : "no") << "\n";
-        dbgs() << "  Is store from reg: " << (IsStoreFromReg ? "yes" : "no")
-               << "\n";
-      }
-      if (MCPB->isPush(Inst)) {
-        dbgs() << "This is a push instruction with size "
-               << MCPB->getPushSize(Inst) << "\n";
-      }
-      if (MCPB->isPop(Inst)) {
-        dbgs() << "This is a pop instruction with size "
-               << MCPB->getPopSize(Inst) << "\n";
-      }
-    }
+    // dbgs() << "^^^^^^^^^^^^^^^^ InsCFIs ^^^^^^^^^^^^^^^^\n";
+    // printUntilNextLine(Inst.getLoc().getPointer());
+    // dbgs() << "\n";
+    // dbgs() << "Op code: " << Inst.getOpcode() << "\n";
+    // dbgs() << "--------------Operands Info--------------\n";
+    // auto DefCount = MCInstInfo.getNumDefs();
+    // for (unsigned I = 0; I < Inst.getNumOperands(); I++) {
+    //   dbgs() << "Operand #" << I << ", which will be "
+    //          << (I < DefCount ? "defined" : "used") << ", is a";
+    //   if (I == MCPB->getMemoryOperandNo(Inst)) {
+    //     dbgs() << " memory access, details are:\n";
+    //     auto X86MemoryOperand = MCPB->evaluateX86MemoryOperand(Inst);
+    //     dbgs() << "  Base Register{ reg#" << X86MemoryOperand->BaseRegNum
+    //            << " }";
+    //     dbgs() << " + (Index Register{ reg#" << X86MemoryOperand->IndexRegNum
+    //            << " }";
+    //     dbgs() << " * Scale{ value " << X86MemoryOperand->ScaleImm << " }";
+    //     dbgs() << ") + Displacement{ "
+    //            << (X86MemoryOperand->DispExpr
+    //                    ? "an expression"
+    //                    : "value " + itostr(X86MemoryOperand->DispImm))
+    //            << " }\n";
+    //     // TODO, it's not correct always, it cannot be assumed (or should be
+    //     // checked) that memory operands are flatten into 4 operands in
+    //     MCInc. I += 4; continue;
+    //   }
+    //   auto &&Operand = Inst.getOperand(I);
+    //   if (Operand.isImm()) {
+    //     dbgs() << "n immediate with value " << Operand.getImm() << "\n";
+    //     continue;
+    //   }
+    //   if (Operand.isReg()) {
+    //     dbgs() << " reg#" << Operand.getReg() << "\n";
+    //     continue;
+    //   }
+    //   assert(Operand.isExpr());
+    //   dbgs() << "n unknown expression \n";
+    // }
+    // if (MCInstInfo.NumImplicitDefs) {
+    //   dbgs() << "implicitly defines: { ";
+    //   for (unsigned I = 0; I < MCInstInfo.NumImplicitDefs; I++) {
+    //     dbgs() << "reg#" << MCInstInfo.implicit_defs()[I] << " ";
+    //   }
+    //   dbgs() << "}\n";
+    // }
+    // if (MCInstInfo.NumImplicitUses) {
+    //   dbgs() << "implicitly uses: { ";
+    //   for (unsigned I = 0; I < MCInstInfo.NumImplicitUses; I++) {
+    //     dbgs() << "reg#" << MCInstInfo.implicit_uses()[I] << " ";
+    //   }
+    //   dbgs() << "}\n";
+    // }
+    // dbgs() << "----------------Move Info----------------\n";
+    // {   // move
+    //   { // Reg2Reg
+    //     MCPhysReg From, To;
+    //     if (MCPB->isRegToRegMove(Inst, From, To)) {
+    //       dbgs() << "It's a reg to reg move.\nFrom reg#" << From << " to
+    //       reg#"
+    //              << To << "\n";
+    //     } else if (MCInstInfo.isMoveReg()) {
+    //       dbgs() << "It's reg to reg move from MCInstInfo view but not from "
+    //                 "MCPlus view.\n";
+    //     }
+    //   }
+    //   if (MCPB->isConditionalMove(Inst)) {
+    //     dbgs() << "Its a conditional move.\n";
+    //   }
+    //   if (MCPB->isMoveMem2Reg(Inst)) {
+    //     dbgs() << "It's a move from memory to register\n";
+    //     assert(MCPB->getMemoryOperandNo(Inst) == 1);
+    //   }
+    // }
 
-    dbgs() << "---------------Arith Info----------------\n";
-    { // arith
-      MutableArrayRef<MCInst> MAR = {Inst};
-      if (MCPB->matchAdd(MCPB->matchAnyOperand(), MCPB->matchAnyOperand())
-              ->match(*RI, *MCPB, MutableArrayRef<MCInst>(), -1)) {
-        dbgs() << "It is an addition instruction.\n";
-      } else if (MCInstInfo.isAdd()) {
-        dbgs() << "It is an addition from MCInstInfo view but not from MCPlus "
-                  "view.\n";
-      }
-      if (MCPB->isSUB(Inst)) {
-        dbgs() << "This is a subtraction.\n";
-      }
-    }
+    // dbgs() << "---------------Stack Info----------------\n";
+    // { // stack
+    //   int32_t SrcImm = 0;
+    //   MCPhysReg Reg = 0;
+    //   uint16_t StackPtrReg = 0;
+    //   int64_t StackOffset = 0;
+    //   uint8_t Size = 0;
+    //   bool IsSimple = false;
+    //   bool IsIndexed = false;
+    //   bool IsLoad = false;
+    //   bool IsStore = false;
+    //   bool IsStoreFromReg = false;
+    //   if (MCPB->isStackAccess(Inst, IsLoad, IsStore, IsStoreFromReg, Reg,
+    //                           SrcImm, StackPtrReg, StackOffset, Size,
+    //                           IsSimple, IsIndexed)) {
+    //     dbgs() << "This instruction accesses the stack, the details are:\n";
+    //     dbgs() << "  Source immediate: " << SrcImm << "\n";
+    //     dbgs() << "  Source reg#" << Reg << "\n";
+    //     dbgs() << "  Stack pointer: reg#" << StackPtrReg << "\n";
+    //     dbgs() << "  Stack offset: " << StackOffset << "\n";
+    //     dbgs() << "  size: " << (int)Size << "\n";
+    //     dbgs() << "  Is simple: " << (IsSimple ? "yes" : "no") << "\n";
+    //     dbgs() << "  Is indexed: " << (IsIndexed ? "yes" : "no") << "\n";
+    //     dbgs() << "  Is load: " << (IsLoad ? "yes" : "no") << "\n";
+    //     dbgs() << "  Is store: " << (IsStore ? "yes" : "no") << "\n";
+    //     dbgs() << "  Is store from reg: " << (IsStoreFromReg ? "yes" : "no")
+    //            << "\n";
+    //   }
+    //   if (MCPB->isPush(Inst)) {
+    //     dbgs() << "This is a push instruction with size "
+    //            << MCPB->getPushSize(Inst) << "\n";
+    //   }
+    //   if (MCPB->isPop(Inst)) {
+    //     dbgs() << "This is a pop instruction with size "
+    //            << MCPB->getPopSize(Inst) << "\n";
+    //   }
+    // }
+
+    // dbgs() << "---------------Arith Info----------------\n";
+    // { // arith
+    //   MutableArrayRef<MCInst> MAR = {Inst};
+    //   if (MCPB->matchAdd(MCPB->matchAnyOperand(), MCPB->matchAnyOperand())
+    //           ->match(*MCRI, *MCPB, MutableArrayRef<MCInst>(), -1)) {
+    //     dbgs() << "It is an addition instruction.\n";
+    //   } else if (MCInstInfo.isAdd()) {
+    //     dbgs() << "It is an addition from MCInstInfo view but not from MCPlus
+    //     "
+    //               "view.\n";
+    //   }
+    //   if (MCPB->isSUB(Inst)) {
+    //     dbgs() << "This is a subtraction.\n";
+    //   }
+    // }
 
     // dbgs() << "-----------------------------------------\n";
     // dbgs() << "The CFA register is: " << CFAReg << "\n";
@@ -247,9 +401,12 @@ class CFIAnalysis {
     //        << "change the CFA.\n";
     // dbgs() << "The CFI directives does " << (GoingToChangeCFA ? "" : "NOT ")
     //        << "change the CFA.\n";
-    dbgs() << "vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n";
-    ChangedCFA = false;
+    // dbgs() << "vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n";
+
+    State = AfterState;
   }
+
+private:
 };
 
 } // namespace llvm
diff --git a/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h b/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h
index 382a80aca94b4..48f530e6a9811 100644
--- a/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h
+++ b/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h
@@ -33,14 +33,14 @@ class CFIAnalysisMCStreamer : public MCStreamer {
 
   struct ICFI {
     MCInst Instruction;
-    ArrayRef<MCCFIInstruction> CFIDirectives;
+    std::pair<unsigned, unsigned> CFIDirectivesRange;
 
-    ICFI(MCInst Instruction, ArrayRef<MCCFIInstruction> CFIDirectives)
-        : Instruction(Instruction), CFIDirectives(CFIDirectives) {}
+    ICFI(MCInst Instruction, std::pair<unsigned, unsigned> CFIDirectives)
+        : Instruction(Instruction), CFIDirectivesRange(CFIDirectives) {}
   };
 
   std::optional<MCInst> LastInstruction;
-  std::optional<MCDwarfFrameInfo> LastDwarfFrameInfo;
+  MCDwarfFrameInfo const *LastDwarfFrameInfo;
 
   std::optional<ICFI> getLastICFI() {
     if (!LastInstruction)
@@ -58,16 +58,14 @@ class CFIAnalysisMCStreamer : public MCStreamer {
     assert(CurrentCFIDirectiveState.DirectiveIndex >=
            LastCFIDirectivesState.DirectiveIndex);
 
-    std::vector<MCCFIInstruction> CFIDirectives;
+    std::pair<unsigned, unsigned> CFIDirectivesRange;
     if (LastCFIDirectivesState.FrameIndex >= 0) {
-      auto CFIInstructions = DwarfFrameInfos[FrameIndex].Instructions;
-      CFIDirectives = std::vector<MCCFIInstruction>(
-          CFIInstructions.begin() + LastCFIDirectivesState.DirectiveIndex,
-          CFIInstructions.begin() + CurrentCFIDirectiveState.DirectiveIndex);
+      CFIDirectivesRange = {LastCFIDirectivesState.DirectiveIndex,
+                            CurrentCFIDirectiveState.DirectiveIndex};
     }
 
     LastCFIDirectivesState = CurrentCFIDirectiveState;
-    return ICFI(LastInstruction.value(), CFIDirectives);
+    return ICFI(LastInstruction.value(), CFIDirectivesRange);
   }
 
   void feedCFIA() {
@@ -77,14 +75,15 @@ class CFIAnalysisMCStreamer : public MCStreamer {
       // adding cfi directives for a instruction. Then this would cause to
       // ignore the instruction.
       auto LastICFI = getLastICFI();
-      assert(!LastICFI || LastICFI->CFIDirectives.empty());
+      assert(!LastICFI || LastICFI->CFIDirectivesRange.first ==
+                              LastICFI->CFIDirectivesRange.second);
       return;
     }
 
     if (auto ICFI = getLastICFI()) {
       assert(!CFIAs.empty());
-      CFIAs.back().update(LastDwarfFrameInfo.value(), ICFI->Instruction,
-                          ICFI->CFIDirectives);
+      CFIAs.back().update(*LastDwarfFrameInfo, ICFI->Instruction,
+                          ICFI->CFIDirectivesRange);
     }
   }
 
@@ -121,9 +120,12 @@ class CFIAnalysisMCStreamer : public MCStreamer {
     feedCFIA();
     LastInstruction = Inst;
     if (hasUnfinishedDwarfFrameInfo())
-      LastDwarfFrameInfo = getDwarfFrameInfos()[FrameIndices.back()];
+      LastDwarfFrameInfo =
+          &getDwarfFrameInfos()
+              [FrameIndices.back()]; // FIXME get this from emit yourself,
+                                     // instead of getting it in this way
     else
-      LastDwarfFrameInfo = std::nullopt;
+      LastDwarfFrameInfo = nullptr;
   }
 
   void emitCFIStartProcImpl(MCDwarfFrameInfo &Frame) override {
@@ -131,7 +133,7 @@ class CFIAnalysisMCStreamer : public MCStreamer {
     FrameIndices.push_back(getNumFrameInfos());
     CFIAs.emplace_back(getContext(), MCII, MCIA.get());
     LastInstruction = std::nullopt;
-    LastDwarfFrameInfo = std::nullopt;
+    LastDwarfFrameInfo = nullptr;
     LastCFIDirectivesState.FrameIndex = FrameIndices.back();
     LastCFIDirectivesState.DirectiveIndex = 0;
     MCStreamer::emitCFIStartProcImpl(Frame);
@@ -143,7 +145,7 @@ class CFIAnalysisMCStreamer : public MCStreamer {
     FrameIndices.pop_back();
     CFIAs.pop_back();
     LastInstruction = std::nullopt;
-    LastDwarfFrameInfo = std::nullopt;
+    LastDwarfFrameInfo = nullptr;
     LastCFIDirectivesState.FrameIndex = FrameIndices.back();
     LastCFIDirectivesState.DirectiveIndex =
         LastCFIDirectivesState.FrameIndex >= 0

>From 69a8e9da756c60ba18bfacfcfc7a55ccb59d9122 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Wed, 14 May 2025 22:45:23 +0000
Subject: [PATCH 09/58] Add the CFI validation as a option to llvm-mc tool

---
 llvm/tools/llvm-mc/llvm-mc.cpp | 17 +++++++++++------
 1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/llvm/tools/llvm-mc/llvm-mc.cpp b/llvm/tools/llvm-mc/llvm-mc.cpp
index 32f2fa0f05a7c..ca4f71cb9cabd 100644
--- a/llvm/tools/llvm-mc/llvm-mc.cpp
+++ b/llvm/tools/llvm-mc/llvm-mc.cpp
@@ -215,6 +215,10 @@ static cl::opt<bool> NoExecStack("no-exec-stack",
                                  cl::desc("File doesn't need an exec stack"),
                                  cl::cat(MCCategory));
 
+static cl::opt<bool> ValidateCFI("validate-cfi",
+                                 cl::desc("Validate the CFI directives"),
+                                 cl::cat(MCCategory));
+
 enum ActionType {
   AC_AsLex,
   AC_Assemble,
@@ -525,7 +529,12 @@ int main(int argc, char **argv) {
   assert(MCIA && "Unable to create instruction analysis!");
 
   std::unique_ptr<MCInstPrinter> IP;
-  if (FileType == OFT_AssemblyFile) {
+  if (ValidateCFI) {
+    assert(FileType == OFT_Null);
+    auto *CFIAMCS = new CFIAnalysisMCStreamer(Ctx, *MCII, std::move(MCIA));
+    TheTarget->createNullTargetStreamer(*CFIAMCS);
+    Str.reset(CFIAMCS);
+  } else if (FileType == OFT_AssemblyFile) {
     IP.reset(TheTarget->createMCInstPrinter(
         Triple(TripleName), OutputAsmVariant, *MAI, *MCII, *MRI));
 
@@ -569,11 +578,7 @@ int main(int argc, char **argv) {
                                            std::move(CE), std::move(MAB)));
 
   } else if (FileType == OFT_Null) {
-    auto *MyDummyStreamer =
-        new CFIAnalysisMCStreamer(Ctx, *MCII, std::move(MCIA));
-    TheTarget->createNullTargetStreamer(*MyDummyStreamer);
-    Str.reset(MyDummyStreamer);
-    // Str.reset(TheTarget->createNullStreamer(Ctx));
+    Str.reset(TheTarget->createNullStreamer(Ctx));
   } else {
     assert(FileType == OFT_ObjectFile && "Invalid file type!");
 

>From 43b54fd0d237c71dc15a2645319d627cf3ed1db9 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Wed, 14 May 2025 23:15:26 +0000
Subject: [PATCH 10/58] Provide the directives as an arrayref instead of index
 range

---
 llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h | 42 +++++++++-------------
 1 file changed, 17 insertions(+), 25 deletions(-)

diff --git a/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h b/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h
index 48f530e6a9811..a9354d7af8a2f 100644
--- a/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h
+++ b/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h
@@ -3,7 +3,6 @@
 
 #include "CFIAnalysis.h"
 #include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/SmallVector.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCDwarf.h"
 #include "llvm/MC/MCInstrAnalysis.h"
@@ -20,13 +19,12 @@ class CFIAnalysisMCStreamer : public MCStreamer {
   std::unique_ptr<MCInstrAnalysis> MCIA;
 
   struct CFIDirectivesState {
-    int FrameIndex; // TODO remove it, no need for it
     int DirectiveIndex;
 
-    CFIDirectivesState() : FrameIndex(-1), DirectiveIndex(0) {}
+    CFIDirectivesState() : DirectiveIndex(0) {}
 
     CFIDirectivesState(int FrameIndex, int InstructionIndex)
-        : FrameIndex(FrameIndex), DirectiveIndex(InstructionIndex) {}
+        : DirectiveIndex(InstructionIndex) {}
   } LastCFIDirectivesState;
   std::vector<int> FrameIndices;
   std::vector<CFIAnalysis> CFIAs;
@@ -53,16 +51,12 @@ class CFIAnalysisMCStreamer : public MCStreamer {
             ? CFIDirectivesState(
                   FrameIndex, DwarfFrameInfos[FrameIndex].Instructions.size())
             : CFIDirectivesState();
-    assert(CurrentCFIDirectiveState.FrameIndex ==
-           LastCFIDirectivesState.FrameIndex);
     assert(CurrentCFIDirectiveState.DirectiveIndex >=
            LastCFIDirectivesState.DirectiveIndex);
 
-    std::pair<unsigned, unsigned> CFIDirectivesRange;
-    if (LastCFIDirectivesState.FrameIndex >= 0) {
-      CFIDirectivesRange = {LastCFIDirectivesState.DirectiveIndex,
-                            CurrentCFIDirectiveState.DirectiveIndex};
-    }
+    std::pair<unsigned, unsigned> CFIDirectivesRange(
+        LastCFIDirectivesState.DirectiveIndex,
+        CurrentCFIDirectiveState.DirectiveIndex);
 
     LastCFIDirectivesState = CurrentCFIDirectiveState;
     return ICFI(LastInstruction.value(), CFIDirectivesRange);
@@ -82,8 +76,12 @@ class CFIAnalysisMCStreamer : public MCStreamer {
 
     if (auto ICFI = getLastICFI()) {
       assert(!CFIAs.empty());
-      CFIAs.back().update(*LastDwarfFrameInfo, ICFI->Instruction,
-                          ICFI->CFIDirectivesRange);
+      ArrayRef<MCCFIInstruction> CFIDirectives(
+          LastDwarfFrameInfo->Instructions);
+      CFIDirectives = CFIDirectives.drop_front(ICFI->CFIDirectivesRange.first)
+                          .drop_back(LastDwarfFrameInfo->Instructions.size() -
+                                     ICFI->CFIDirectivesRange.second);
+      CFIAs.back().update(ICFI->Instruction, CFIDirectives);
     }
   }
 
@@ -95,9 +93,6 @@ class CFIAnalysisMCStreamer : public MCStreamer {
     FrameIndices.push_back(-1);
   }
 
-  /// @name MCStreamer Interface
-  /// @{
-
   bool hasRawTextSupport() const override { return true; }
   void emitRawTextImpl(StringRef String) override {}
 
@@ -121,9 +116,9 @@ class CFIAnalysisMCStreamer : public MCStreamer {
     LastInstruction = Inst;
     if (hasUnfinishedDwarfFrameInfo())
       LastDwarfFrameInfo =
-          &getDwarfFrameInfos()
-              [FrameIndices.back()]; // FIXME get this from emit yourself,
-                                     // instead of getting it in this way
+          &getDwarfFrameInfos()[FrameIndices.back()]; // TODO get this from emit
+                                                      // yourself, instead of
+                                                      // getting it in this way
     else
       LastDwarfFrameInfo = nullptr;
   }
@@ -134,7 +129,6 @@ class CFIAnalysisMCStreamer : public MCStreamer {
     CFIAs.emplace_back(getContext(), MCII, MCIA.get());
     LastInstruction = std::nullopt;
     LastDwarfFrameInfo = nullptr;
-    LastCFIDirectivesState.FrameIndex = FrameIndices.back();
     LastCFIDirectivesState.DirectiveIndex = 0;
     MCStreamer::emitCFIStartProcImpl(Frame);
   }
@@ -146,12 +140,10 @@ class CFIAnalysisMCStreamer : public MCStreamer {
     CFIAs.pop_back();
     LastInstruction = std::nullopt;
     LastDwarfFrameInfo = nullptr;
-    LastCFIDirectivesState.FrameIndex = FrameIndices.back();
+    auto FrameIndex = FrameIndices.back();
     LastCFIDirectivesState.DirectiveIndex =
-        LastCFIDirectivesState.FrameIndex >= 0
-            ? getDwarfFrameInfos()[LastCFIDirectivesState.FrameIndex]
-                  .Instructions.size()
-            : 0;
+        FrameIndex >= 0 ? getDwarfFrameInfos()[FrameIndex].Instructions.size()
+                        : 0;
     MCStreamer::emitCFIEndProcImpl(CurFrame);
   }
 };

>From 474ff1c1ea503ca56c916223fdb1f281e6382eaa Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Wed, 14 May 2025 23:47:48 +0000
Subject: [PATCH 11/58] Remove TODOs

---
 llvm/tools/llvm-mc/CFIState.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/tools/llvm-mc/CFIState.h b/llvm/tools/llvm-mc/CFIState.h
index b32de2b385316..5551e9778f1d2 100644
--- a/llvm/tools/llvm-mc/CFIState.h
+++ b/llvm/tools/llvm-mc/CFIState.h
@@ -76,7 +76,7 @@ struct CFIState {
   DWARFRegType CFARegister;
   int CFAOffset;
 
-  CFIState() : CFARegister(-1 /* Change to to max unsigned */), CFAOffset(-1) {}
+  CFIState() : CFARegister(-1), CFAOffset(-1) {}
 
   CFIState(const CFIState &Other) {
     CFARegister = Other.CFARegister;
@@ -147,7 +147,7 @@ struct CFIState {
     case MCCFIInstruction::OpNegateRAStateWithPC:
     case MCCFIInstruction::OpGnuArgsSize:
     case MCCFIInstruction::OpLabel:
-      // TODO it's not supported.
+      // These instructions are not supported.
       return false;
       break;
     }

>From 8ea5d9c10ca5d1c42d718a9ff63d7edad2f667ee Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Wed, 14 May 2025 23:48:11 +0000
Subject: [PATCH 12/58] Wrap all the MCPB info needed into a
 ExtendedMCInstrAnalysis class

---
 llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h | 85 ++++++++++++++++++++
 1 file changed, 85 insertions(+)
 create mode 100644 llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h

diff --git a/llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h b/llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h
new file mode 100644
index 0000000000000..5323c4e3d1730
--- /dev/null
+++ b/llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h
@@ -0,0 +1,85 @@
+#ifndef LLVM_TOOLS_LLVM_MC_EXTENDED_MC_INSTR_ANALYSIS_H
+#define LLVM_TOOLS_LLVM_MC_EXTENDED_MC_INSTR_ANALYSIS_H
+
+#include "bolt/Core/MCPlusBuilder.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDwarf.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCRegister.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/TargetRegistry.h"
+#include <cstdint>
+#include <memory>
+#include <optional>
+
+namespace llvm {
+
+class ExtendedMCInstrAnalysis {
+private:
+  std::unique_ptr<bolt::MCPlusBuilder> MCPB;
+
+  static bolt::MCPlusBuilder *
+  createMCPlusBuilder(const Triple::ArchType Arch,
+                      const MCInstrAnalysis *Analysis, const MCInstrInfo *Info,
+                      const MCRegisterInfo *RegInfo,
+                      const MCSubtargetInfo *STI) {
+    if (Arch == Triple::x86_64)
+      return bolt::createX86MCPlusBuilder(Analysis, Info, RegInfo, STI);
+
+    llvm_unreachable("architecture unsupported by ExtendedMCInstrAnalysis");
+  }
+
+public:
+  ExtendedMCInstrAnalysis(MCContext &Context, MCInstrInfo const &MCII,
+                          MCInstrAnalysis *MCIA) {
+    MCPB.reset(createMCPlusBuilder(Context.getTargetTriple().getArch(), MCIA,
+                                   &MCII, Context.getRegisterInfo(),
+                                   Context.getSubtargetInfo()));
+  }
+
+  /// Extra semantic information needed from MC layer:
+
+  MCPhysReg getStackPointer() const { return MCPB->getStackPointer(); }
+
+  bool isPush(const MCInst &Inst) const { return MCPB->isPush(Inst); }
+  int getPushSize(const MCInst &Inst) const { return MCPB->getPushSize(Inst); }
+
+  bool isPop(const MCInst &Inst) const { return MCPB->isPop(Inst); }
+  int getPopSize(const MCInst &Inst) const { return MCPB->getPopSize(Inst); }
+
+  bool isRegToRegMove(const MCInst &Inst, MCPhysReg &From,
+                      MCPhysReg &To) const {
+    return MCPB->isRegToRegMove(Inst, From, To);
+  }
+  bool isConditionalMove(const MCInst &Inst) const {
+    return MCPB->isConditionalMove(Inst);
+  }
+  bool isMoveMem2Reg(const MCInst &Inst) const {
+    return MCPB->isMoveMem2Reg(Inst);
+  }
+  bool isSUB(const MCInst &Inst) const { return MCPB->isSUB(Inst); }
+
+  int getMemoryOperandNo(const MCInst &Inst) const {
+    return MCPB->getMemoryOperandNo(Inst);
+  }
+  std::optional<bolt::MCPlusBuilder::X86MemOperand>
+  evaluateX86MemoryOperand(const MCInst &Inst) const {
+    return MCPB->evaluateX86MemoryOperand(Inst);
+  }
+  bool isStackAccess(const MCInst &Inst, bool &IsLoad, bool &IsStore,
+                     bool &IsStoreFromReg, MCPhysReg &Reg, int32_t &SrcImm,
+                     uint16_t &StackPtrReg, int64_t &StackOffset, uint8_t &Size,
+                     bool &IsSimple, bool &IsIndexed) const {
+    return MCPB->isStackAccess(Inst, IsLoad, IsStore, IsStoreFromReg, Reg,
+                               SrcImm, StackPtrReg, StackOffset, Size, IsSimple,
+                               IsIndexed);
+  }
+};
+
+} // namespace llvm
+
+#endif
\ No newline at end of file

>From e92005c32a550b24df96ea4f5166bf656f73d493 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Wed, 14 May 2025 23:48:50 +0000
Subject: [PATCH 13/58] Use extended MCAnalysis instead of MCplus (directly)

---
 llvm/tools/llvm-mc/CFIAnalysis.h | 123 ++++++++++---------------------
 1 file changed, 39 insertions(+), 84 deletions(-)

diff --git a/llvm/tools/llvm-mc/CFIAnalysis.h b/llvm/tools/llvm-mc/CFIAnalysis.h
index 424290f3cab86..1a05dd6de5327 100644
--- a/llvm/tools/llvm-mc/CFIAnalysis.h
+++ b/llvm/tools/llvm-mc/CFIAnalysis.h
@@ -2,6 +2,7 @@
 #define LLVM_TOOLS_LLVM_MC_CFI_ANALYSIS_H
 
 #include "CFIState.h"
+#include "ExtendedMCInstrAnalysis.h"
 #include "bolt/Core/MCPlusBuilder.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/SmallVector.h"
@@ -18,7 +19,6 @@
 #include "llvm/MC/MCSubtargetInfo.h"
 #include "llvm/MC/TargetRegistry.h"
 #include "llvm/Support/Debug.h"
-#include "llvm/Support/Error.h"
 #include "llvm/Support/FormatVariadic.h"
 #include <cstdint>
 #include <memory>
@@ -27,24 +27,6 @@
 
 namespace llvm {
 
-bolt::MCPlusBuilder *createMCPlusBuilder(const Triple::ArchType Arch,
-                                         const MCInstrAnalysis *Analysis,
-                                         const MCInstrInfo *Info,
-                                         const MCRegisterInfo *RegInfo,
-                                         const MCSubtargetInfo *STI) {
-  dbgs() << "arch: " << Arch << ", and expected " << Triple::x86_64 << "\n";
-  if (Arch == Triple::x86_64)
-    return bolt::createX86MCPlusBuilder(Analysis, Info, RegInfo, STI);
-
-  // if (Arch == Triple::aarch64)
-  //   return createAArch64MCPlusBuilder(Analysis, Info, RegInfo, STI);
-
-  // if (Arch == Triple::riscv64)
-  //   return createRISCVMCPlusBuilder(Analysis, Info, RegInfo, STI);
-
-  llvm_unreachable("architecture unsupported by MCPlusBuilder");
-}
-
 // TODO remove it, it's just for debug purposes.
 void printUntilNextLine(const char *Str) {
   for (int I = 0; Str[I] != '\0' && Str[I] != '\n'; I++)
@@ -54,8 +36,8 @@ void printUntilNextLine(const char *Str) {
 class CFIAnalysis {
   MCContext &Context;
   MCInstrInfo const &MCII;
-  std::unique_ptr<bolt::MCPlusBuilder> MCPB;
   MCRegisterInfo const *MCRI;
+  std::unique_ptr<ExtendedMCInstrAnalysis> EMCIA;
   CFIState State;
 
 public:
@@ -65,14 +47,12 @@ class CFIAnalysis {
     // TODO it should look at the prologue directives and setup the
     // registers' previous value state here, but for now, it's assumed that all
     // values are by default `samevalue`.
-    MCPB.reset(createMCPlusBuilder(Context.getTargetTriple().getArch(), MCIA,
-                                   &MCII, Context.getRegisterInfo(),
-                                   Context.getSubtargetInfo()));
+    EMCIA.reset(new ExtendedMCInstrAnalysis(Context, MCII, MCIA));
 
     // TODO CFA offset should be the slot size, but for now I don't have any
     // access to it, maybe can be read from the prologue
     // TODO check what should be passed as EH?
-    State = CFIState(MCRI->getDwarfRegNum(MCPB->getStackPointer(), false), 8);
+    State = CFIState(MCRI->getDwarfRegNum(EMCIA->getStackPointer(), false), 8);
     for (unsigned I = 0; I < MCRI->getNumRegs(); I++) {
       DWARFRegType DwarfI = MCRI->getDwarfRegNum(I, false);
       State.RegisterCFIStates[DwarfI] = RegisterCFIState::createSameValue();
@@ -84,23 +64,23 @@ class CFIAnalysis {
                                                  false)] =
         RegisterCFIState::createUndefined(); // For now, we don't care about the
                                              // PC
-    State.RegisterCFIStates[MCRI->getDwarfRegNum(MCPB->getStackPointer(),
+    State.RegisterCFIStates[MCRI->getDwarfRegNum(EMCIA->getStackPointer(),
                                                  false)] =
         RegisterCFIState::createOffsetFromCFAVal(0); // sp's old value is CFA
   }
 
   bool doesConstantChange(const MCInst &Inst, MCPhysReg Reg, int64_t &HowMuch) {
-    if (MCPB->isPush(Inst) && Reg == MCPB->getStackPointer()) {
+    if (EMCIA->isPush(Inst) && Reg == EMCIA->getStackPointer()) {
       // TODO should get the stack direction here, now it assumes that it goes
       // down.
-      HowMuch = -MCPB->getPushSize(Inst);
+      HowMuch = -EMCIA->getPushSize(Inst);
       return true;
     }
 
-    if (MCPB->isPop(Inst) && Reg == MCPB->getStackPointer()) {
+    if (EMCIA->isPop(Inst) && Reg == EMCIA->getStackPointer()) {
       // TODO should get the stack direction here, now it assumes that it goes
       // down.
-      HowMuch = MCPB->getPushSize(Inst);
+      HowMuch = EMCIA->getPushSize(Inst);
       return true;
     }
 
@@ -114,7 +94,7 @@ class CFIAnalysis {
     {
       MCPhysReg From;
       MCPhysReg To;
-      if (MCPB->isRegToRegMove(Inst, From, To) && From == Reg2 && To == Reg1) {
+      if (EMCIA->isRegToRegMove(Inst, From, To) && From == Reg2 && To == Reg1) {
         Diff = 0;
         return true;
       }
@@ -174,7 +154,8 @@ class CFIAnalysis {
     }
     // The CFA register is changed.
     // TODO move it up
-    MCPhysReg OldCFAReg = MCRI->getLLVMRegNum(PrevState.CFARegister, false).value();
+    MCPhysReg OldCFAReg =
+        MCRI->getLLVMRegNum(PrevState.CFARegister, false).value();
     MCPhysReg NewCFAReg =
         MCRI->getLLVMRegNum(NextState.CFARegister, false).value();
     if (!Writes.count(NextState.CFARegister)) {
@@ -201,24 +182,17 @@ class CFIAnalysis {
       return;
     }
     if (Diff != OffsetDiff) {
-      Context.reportError(
-          Inst.getLoc(), formatv("After changing the CFA register, the CFA "
-                                 "offset should be {0}, but it is {1}.",
-                                 PrevState.CFAOffset - Diff, NextState.CFAOffset));
+      Context.reportError(Inst.getLoc(),
+                          formatv("After changing the CFA register, the CFA "
+                                  "offset should be {0}, but it is {1}.",
+                                  PrevState.CFAOffset - Diff,
+                                  NextState.CFAOffset));
       return;
     }
     // Everything is OK!
   }
 
-  void update(const MCDwarfFrameInfo &DwarfFrame, MCInst &Inst,
-              std::pair<unsigned, unsigned>
-                  CFIDirectivesRange) { // FIXME this should not be a pair,
-                                        // but an ArrayRef
-    ArrayRef<MCCFIInstruction> CFIDirectives(DwarfFrame.Instructions);
-    CFIDirectives = CFIDirectives.drop_front(CFIDirectivesRange.first)
-                        .drop_back(DwarfFrame.Instructions.size() -
-                                   CFIDirectivesRange.second);
-
+  void update(MCInst &Inst, ArrayRef<MCCFIInstruction> CFIDirectives) {
     const MCInstrDesc &MCInstInfo = MCII.get(Inst.getOpcode());
     CFIState AfterState(State);
     for (auto &&CFIDirective : CFIDirectives)
@@ -227,9 +201,6 @@ class CFIAnalysis {
             CFIDirective.getLoc(),
             "I don't support this CFI directive, I assume this does nothing "
             "(which will probably break other things)");
-    auto CFAReg = MCRI->getLLVMRegNum(DwarfFrame.CurrentCfaRegister, false);
-    assert(DwarfFrame.CurrentCfaRegister == AfterState.CFARegister &&
-           "Checking if the CFA tracking is working");
 
     std::set<DWARFRegType> Writes, Reads;
     for (unsigned I = 0; I < MCInstInfo.NumImplicitUses; I++)
@@ -246,23 +217,6 @@ class CFIAnalysis {
           Reads.insert(MCRI->getDwarfRegNum(Operand.getReg(), false));
       }
     }
-
-    bool ChangedCFA = Writes.count(CFAReg->id());
-    bool GoingToChangeCFA = false;
-    for (auto CFIDirective : CFIDirectives) {
-      auto Op = CFIDirective.getOperation();
-      GoingToChangeCFA |= (Op == MCCFIInstruction::OpDefCfa ||
-                           Op == MCCFIInstruction::OpDefCfaOffset ||
-                           Op == MCCFIInstruction::OpDefCfaRegister ||
-                           Op == MCCFIInstruction::OpAdjustCfaOffset ||
-                           Op == MCCFIInstruction::OpLLVMDefAspaceCfa);
-    }
-    if (ChangedCFA && !GoingToChangeCFA) {
-      Context.reportError(Inst.getLoc(),
-                          "The instruction changes CFA register value, but the "
-                          "CFI directives don't update the CFA.");
-    }
-
     ///////////// being diffing the CFI states
     checkCFADiff(Inst, State, AfterState, Reads, Writes);
     ///////////// end diffing the CFI states
@@ -276,9 +230,9 @@ class CFIAnalysis {
     // for (unsigned I = 0; I < Inst.getNumOperands(); I++) {
     //   dbgs() << "Operand #" << I << ", which will be "
     //          << (I < DefCount ? "defined" : "used") << ", is a";
-    //   if (I == MCPB->getMemoryOperandNo(Inst)) {
+    //   if (I == EMCIA->getMemoryOperandNo(Inst)) {
     //     dbgs() << " memory access, details are:\n";
-    //     auto X86MemoryOperand = MCPB->evaluateX86MemoryOperand(Inst);
+    //     auto X86MemoryOperand = EMCIA->evaluateX86MemoryOperand(Inst);
     //     dbgs() << "  Base Register{ reg#" << X86MemoryOperand->BaseRegNum
     //            << " }";
     //     dbgs() << " + (Index Register{ reg#" << X86MemoryOperand->IndexRegNum
@@ -323,21 +277,21 @@ class CFIAnalysis {
     // {   // move
     //   { // Reg2Reg
     //     MCPhysReg From, To;
-    //     if (MCPB->isRegToRegMove(Inst, From, To)) {
-    //       dbgs() << "It's a reg to reg move.\nFrom reg#" << From << " to
-    //       reg#"
+    //     if (EMCIA->isRegToRegMove(Inst, From, To)) {
+    //       dbgs() << "It's a reg to reg move.\nFrom reg#" << From << " to reg
+    //       #"
     //              << To << "\n";
     //     } else if (MCInstInfo.isMoveReg()) {
     //       dbgs() << "It's reg to reg move from MCInstInfo view but not from "
     //                 "MCPlus view.\n";
     //     }
     //   }
-    //   if (MCPB->isConditionalMove(Inst)) {
+    //   if (EMCIA->isConditionalMove(Inst)) {
     //     dbgs() << "Its a conditional move.\n";
     //   }
-    //   if (MCPB->isMoveMem2Reg(Inst)) {
+    //   if (EMCIA->isMoveMem2Reg(Inst)) {
     //     dbgs() << "It's a move from memory to register\n";
-    //     assert(MCPB->getMemoryOperandNo(Inst) == 1);
+    //     assert(EMCIA->getMemoryOperandNo(Inst) == 1);
     //   }
     // }
 
@@ -353,9 +307,9 @@ class CFIAnalysis {
     //   bool IsLoad = false;
     //   bool IsStore = false;
     //   bool IsStoreFromReg = false;
-    //   if (MCPB->isStackAccess(Inst, IsLoad, IsStore, IsStoreFromReg, Reg,
-    //                           SrcImm, StackPtrReg, StackOffset, Size,
-    //                           IsSimple, IsIndexed)) {
+    //   if (EMCIA->isStackAccess(Inst, IsLoad, IsStore, IsStoreFromReg, Reg,
+    //                            SrcImm, StackPtrReg, StackOffset, Size,
+    //                            IsSimple, IsIndexed)) {
     //     dbgs() << "This instruction accesses the stack, the details are:\n";
     //     dbgs() << "  Source immediate: " << SrcImm << "\n";
     //     dbgs() << "  Source reg#" << Reg << "\n";
@@ -369,28 +323,29 @@ class CFIAnalysis {
     //     dbgs() << "  Is store from reg: " << (IsStoreFromReg ? "yes" : "no")
     //            << "\n";
     //   }
-    //   if (MCPB->isPush(Inst)) {
+    //   if (EMCIA->isPush(Inst)) {
     //     dbgs() << "This is a push instruction with size "
-    //            << MCPB->getPushSize(Inst) << "\n";
+    //            << EMCIA->getPushSize(Inst) << "\n";
     //   }
-    //   if (MCPB->isPop(Inst)) {
+    //   if (EMCIA->isPop(Inst)) {
     //     dbgs() << "This is a pop instruction with size "
-    //            << MCPB->getPopSize(Inst) << "\n";
+    //            << EMCIA->getPopSize(Inst) << "\n";
     //   }
     // }
 
     // dbgs() << "---------------Arith Info----------------\n";
     // { // arith
-    //   MutableArrayRef<MCInst> MAR = {Inst};
+    //   /* MutableArrayRef<MCInst> MAR = {Inst};
     //   if (MCPB->matchAdd(MCPB->matchAnyOperand(), MCPB->matchAnyOperand())
     //           ->match(*MCRI, *MCPB, MutableArrayRef<MCInst>(), -1)) {
     //     dbgs() << "It is an addition instruction.\n";
-    //   } else if (MCInstInfo.isAdd()) {
-    //     dbgs() << "It is an addition from MCInstInfo view but not from MCPlus
-    //     "
+    //   } else */
+    //   if (MCInstInfo.isAdd()) {
+    //     dbgs() << "It is an addition from MCInstInfo view but not from
+    //     MCPlus"
     //               "view.\n";
     //   }
-    //   if (MCPB->isSUB(Inst)) {
+    //   if (EMCIA->isSUB(Inst)) {
     //     dbgs() << "This is a subtraction.\n";
     //   }
     // }

>From 7527ba2fd1fb10aff422c3ed1c8f5d795eb071fb Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Mon, 19 May 2025 18:08:23 +0000
Subject: [PATCH 14/58] Make the CFA checker to first generate, if not matched
 check the Read/Write conditions

---
 llvm/tools/llvm-mc/CFIAnalysis.h | 138 +++++++++++++++++--------------
 1 file changed, 74 insertions(+), 64 deletions(-)

diff --git a/llvm/tools/llvm-mc/CFIAnalysis.h b/llvm/tools/llvm-mc/CFIAnalysis.h
index 1a05dd6de5327..ab858e9ae7e52 100644
--- a/llvm/tools/llvm-mc/CFIAnalysis.h
+++ b/llvm/tools/llvm-mc/CFIAnalysis.h
@@ -89,12 +89,13 @@ class CFIAnalysis {
 
   // Tries to guess Reg1's value in a form of Reg2 (before Inst's execution) +
   // Diff.
-  bool isInConstantDistanceOfEachOther(const MCInst &Inst, MCPhysReg Reg1,
+  bool isInConstantDistanceOfEachOther(const MCInst &Inst, MCPhysReg &Reg1,
                                        MCPhysReg Reg2, int &Diff) {
     {
       MCPhysReg From;
       MCPhysReg To;
-      if (EMCIA->isRegToRegMove(Inst, From, To) && From == Reg2 && To == Reg1) {
+      if (EMCIA->isRegToRegMove(Inst, From, To) && From == Reg2) {
+        Reg1 = To;
         Diff = 0;
         return true;
       }
@@ -107,89 +108,98 @@ class CFIAnalysis {
                     const CFIState &NextState,
                     const std::set<DWARFRegType> &Reads,
                     const std::set<DWARFRegType> &Writes) {
+    MCPhysReg PrevCFAPhysReg =
+        MCRI->getLLVMRegNum(PrevState.CFARegister, false).value();
+    MCPhysReg NextCFAPhysReg =
+        MCRI->getLLVMRegNum(NextState.CFARegister, false).value();
+
+    // Try to guess the next state. (widen)
+    std::vector<std::pair<DWARFRegType, int>> PossibleNextCFAStates;
+    {   // try generate
+      { // no change
+        if (!Writes.count(PrevState.CFARegister)) {
+          PossibleNextCFAStates.emplace_back(PrevState.CFARegister,
+                                             PrevState.CFAOffset);
+        }
+      }
+
+      { // const change
+        int64_t HowMuch;
+        if (doesConstantChange(Inst, PrevCFAPhysReg, HowMuch)) {
+          PossibleNextCFAStates.emplace_back(PrevState.CFARegister,
+                                             PrevState.CFAOffset - HowMuch);
+        }
+      }
+
+      { // constant distance with each other
+        int Diff;
+        MCPhysReg PossibleNewCFAReg;
+        if (isInConstantDistanceOfEachOther(Inst, PossibleNewCFAReg,
+                                            PrevCFAPhysReg, Diff)) {
+          PossibleNextCFAStates.emplace_back(
+              MCRI->getDwarfRegNum(PossibleNewCFAReg, false),
+              PrevState.CFAOffset - Diff);
+        }
+      }
+    }
+
+    for (auto &&[PossibleNextCFAReg, PossibleNextCFAOffset] :
+         PossibleNextCFAStates) {
+      if (PossibleNextCFAReg != NextState.CFARegister)
+        continue;
+
+      if (PossibleNextCFAOffset == NextState.CFAOffset) {
+        // Everything is ok!
+        return;
+      }
+
+      Context.reportError(Inst.getLoc(),
+                          formatv("Expected CFA [reg: {0}, offset: {1}] but "
+                                  "got [reg: {2}, offset: {3}].",
+                                  NextCFAPhysReg, PossibleNextCFAOffset,
+                                  NextCFAPhysReg, NextState.CFAOffset));
+      return;
+    }
+
+    // Either couldn't generate, or did, but the programmer wants to change the
+    // source of register for CFA to something not expected by the generator. So
+    // it falls back into read/write checks.
+
     if (PrevState.CFARegister == NextState.CFARegister) {
       if (PrevState.CFAOffset == NextState.CFAOffset) {
         if (Writes.count(PrevState.CFARegister)) {
-          Context.reportWarning(
+          Context.reportError(
               Inst.getLoc(),
               formatv("This instruction changes reg#{0}, which is "
                       "the CFA register, but the CFI directives do not.",
-                      MCRI->getLLVMRegNum(PrevState.CFARegister, false)));
+                      PrevCFAPhysReg));
         }
+
+        // Everything is ok!
         return;
       }
       // The offset is changed.
+
       if (!Writes.count(PrevState.CFARegister)) {
-        Context.reportWarning(
+        Context.reportError(
             Inst.getLoc(),
             formatv(
                 "You changed the CFA offset, but there is no modification to "
                 "the CFA register happening in this instruction."));
       }
-      int64_t HowMuch;
-      if (!doesConstantChange(
-              Inst, MCRI->getLLVMRegNum(PrevState.CFARegister, false).value(),
-              HowMuch)) {
-        Context.reportWarning(
-            Inst.getLoc(),
-            formatv("The CFA register changed, but I don't know how, finger "
-                    "crossed the CFI directives are correct."));
-        return;
-      }
-      // we know it is changed by HowMuch, so the CFA offset should be changed
-      // by -HowMuch, i.e. AfterState.Offset - State.Offset = -HowMuch
-      if (NextState.CFAOffset - PrevState.CFAOffset != -HowMuch) {
-        Context.reportError(
-            Inst.getLoc(),
-            formatv("The CFA offset is changed by {0}, but "
-                    "the directives changed it by {1}. (to be exact, the new "
-                    "offset should be {2}, but it is {3})",
-                    -HowMuch, NextState.CFAOffset - PrevState.CFAOffset,
-                    PrevState.CFAOffset - HowMuch, NextState.CFAOffset));
-        return;
-      }
 
-      // Everything OK!
-      return;
-    }
-    // The CFA register is changed.
-    // TODO move it up
-    MCPhysReg OldCFAReg =
-        MCRI->getLLVMRegNum(PrevState.CFARegister, false).value();
-    MCPhysReg NewCFAReg =
-        MCRI->getLLVMRegNum(NextState.CFARegister, false).value();
-    if (!Writes.count(NextState.CFARegister)) {
       Context.reportWarning(
           Inst.getLoc(),
-          formatv(
-              "The new CFA register reg#{0}'s value is not assigned by this "
-              "instruction, try to move the new CFA def to where this "
-              "value is changed, now I can't infer if this change is "
-              "correct or not.",
-              NewCFAReg));
-      return;
-    }
-    // Because CFA should is the CFA always stays the same:
-    int OffsetDiff = PrevState.CFAOffset - NextState.CFAOffset;
-    int Diff;
-    if (!isInConstantDistanceOfEachOther(Inst, NewCFAReg, OldCFAReg, Diff)) {
-      Context.reportWarning(
-          Inst.getLoc(),
-          formatv("Based on this instruction I cannot infer that the new and "
-                  "old CFA registers are in {0} distance of each other. I "
-                  "hope it's ok.",
-                  OffsetDiff));
-      return;
-    }
-    if (Diff != OffsetDiff) {
-      Context.reportError(Inst.getLoc(),
-                          formatv("After changing the CFA register, the CFA "
-                                  "offset should be {0}, but it is {1}.",
-                                  PrevState.CFAOffset - Diff,
-                                  NextState.CFAOffset));
+          "I don't know what the instruction did, but it changed the CFA reg's "
+          "value, and the offset is changed as well by the CFI directives.");
+      // Everything may be ok!
       return;
     }
-    // Everything is OK!
+    // The CFA register is changed
+    Context.reportWarning(
+        Inst.getLoc(), "The CFA register is changed to something, and I don't "
+                       "have any idea on the new register relevance to CFA.");
+    // Everything may be ok!
   }
 
   void update(MCInst &Inst, ArrayRef<MCCFIInstruction> CFIDirectives) {

>From 3d65eebd051b17cbeb3422fe94911955e48b6eed Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Tue, 20 May 2025 01:19:00 +0000
Subject: [PATCH 15/58] Check register states as well

---
 llvm/tools/llvm-mc/CFIAnalysis.h | 405 ++++++++++++++++++++++++++++---
 llvm/tools/llvm-mc/CFIState.h    |  38 +++
 2 files changed, 403 insertions(+), 40 deletions(-)

diff --git a/llvm/tools/llvm-mc/CFIAnalysis.h b/llvm/tools/llvm-mc/CFIAnalysis.h
index ab858e9ae7e52..f0b81a85e2fd4 100644
--- a/llvm/tools/llvm-mc/CFIAnalysis.h
+++ b/llvm/tools/llvm-mc/CFIAnalysis.h
@@ -19,6 +19,7 @@
 #include "llvm/MC/MCSubtargetInfo.h"
 #include "llvm/MC/TargetRegistry.h"
 #include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/FormatVariadic.h"
 #include <cstdint>
 #include <memory>
@@ -40,6 +41,41 @@ class CFIAnalysis {
   std::unique_ptr<ExtendedMCInstrAnalysis> EMCIA;
   CFIState State;
 
+private:
+  // The CFI analysis only keeps track and cares about super registers, not the
+  // subregisters. All reads to/writes from subregisters and considered the same
+  // operation to super registers. Other operations like loading and stores are
+  // considered only if they are exactly doing the operation to or from a super
+  // register.
+  // As en example, if you spill a sub register to stack, the CFI analysis does
+  // not consider that a register spilling.
+  bool isSuperReg(MCPhysReg Reg) { return MCRI->superregs(Reg).empty(); }
+
+  std::set<MCPhysReg> getAllSuperRegs() {
+    std::set<MCPhysReg> SuperRegs;
+    for (auto &&RegClass : MCRI->regclasses()) {
+      for (unsigned I = 0; I < RegClass.getNumRegs(); I++) {
+        MCPhysReg Reg = RegClass.getRegister(I);
+        if (!isSuperReg(Reg))
+          continue;
+        SuperRegs.insert(Reg);
+      }
+    }
+
+    return SuperRegs;
+  }
+
+  MCPhysReg getSuperReg(MCPhysReg Reg) {
+    if (isSuperReg(Reg))
+      return Reg;
+    for (auto SuperReg : MCRI->superregs(Reg)) {
+      if (isSuperReg(SuperReg))
+        return SuperReg;
+    }
+
+    llvm_unreachable("Should either be a super reg, or have a super reg");
+  }
+
 public:
   CFIAnalysis(MCContext &Context, MCInstrInfo const &MCII,
               MCInstrAnalysis *MCIA)
@@ -53,7 +89,7 @@ class CFIAnalysis {
     // access to it, maybe can be read from the prologue
     // TODO check what should be passed as EH?
     State = CFIState(MCRI->getDwarfRegNum(EMCIA->getStackPointer(), false), 8);
-    for (unsigned I = 0; I < MCRI->getNumRegs(); I++) {
+    for (MCPhysReg I : getAllSuperRegs()) {
       DWARFRegType DwarfI = MCRI->getDwarfRegNum(I, false);
       State.RegisterCFIStates[DwarfI] = RegisterCFIState::createSameValue();
     }
@@ -104,6 +140,275 @@ class CFIAnalysis {
     return false;
   }
 
+  bool doStoreFromReg(const MCInst &Inst, MCPhysReg StoringReg,
+                      MCPhysReg FromReg, int64_t &Offset) {
+    if (EMCIA->isPush(Inst) && FromReg == EMCIA->getStackPointer()) {
+      // TODO should get the stack direction here, now it assumes that it goes
+      // down.
+      Offset = -EMCIA->getPushSize(Inst);
+      return true;
+    }
+
+    {
+      bool IsLoad;
+      bool IsStore;
+      bool IsStoreFromReg;
+      MCPhysReg SrcReg;
+      int32_t SrcImm;
+      uint16_t StackPtrReg;
+      int64_t StackOffset;
+      uint8_t Size;
+      bool IsSimple;
+      bool IsIndexed;
+      if (EMCIA->isStackAccess(Inst, IsLoad, IsStore, IsStoreFromReg, SrcReg,
+                               SrcImm, StackPtrReg, StackOffset, Size, IsSimple,
+                               IsIndexed)) {
+        // TODO make sure that simple means that it's store and does nothing
+        // more.
+        if (IsStore && IsSimple && StackPtrReg == FromReg && IsStoreFromReg &&
+            SrcReg == StoringReg) {
+          Offset = StackOffset;
+          return true;
+        }
+      }
+    }
+
+    return false;
+  }
+
+  bool doLoadFromReg(const MCInst &Inst, MCPhysReg FromReg, int64_t &Offset,
+                     MCPhysReg &LoadingReg) {
+    if (EMCIA->isPop(Inst) && FromReg == EMCIA->getStackPointer()) {
+      // TODO should get the stack direction here, now it assumes that it goes
+      // down.
+      Offset = 0;
+      LoadingReg = Inst.getOperand(0).getReg();
+      return true;
+    }
+
+    {
+      bool IsLoad;
+      bool IsStore;
+      bool IsStoreFromReg;
+      MCPhysReg SrcReg;
+      int32_t SrcImm;
+      uint16_t StackPtrReg;
+      int64_t StackOffset;
+      uint8_t Size;
+      bool IsSimple;
+      bool IsIndexed;
+      if (EMCIA->isStackAccess(Inst, IsLoad, IsStore, IsStoreFromReg, SrcReg,
+                               SrcImm, StackPtrReg, StackOffset, Size, IsSimple,
+                               IsIndexed)) {
+        // TODO make sure that simple means that it's store and does nothing
+        // more.
+        if (IsLoad && IsSimple && StackPtrReg == FromReg) {
+          Offset = StackOffset;
+          LoadingReg = SrcReg;
+          return true;
+        }
+      }
+    }
+
+    {
+      if (EMCIA->isMoveMem2Reg(Inst)) {
+        auto X86MemAccess = EMCIA->evaluateX86MemoryOperand(Inst).value();
+        if (X86MemAccess.BaseRegNum == FromReg &&
+            (X86MemAccess.ScaleImm == 0 || X86MemAccess.IndexRegNum == 0) &&
+            !X86MemAccess.DispExpr) {
+          LoadingReg = Inst.getOperand(0).getReg();
+          Offset = X86MemAccess.DispImm;
+          return true;
+        }
+      }
+    }
+
+    return false;
+  }
+
+  void checkRegDiff(const MCInst &Inst, DWARFRegType Reg,
+                    const CFIState &PrevState, const CFIState &NextState,
+                    const RegisterCFIState &PrevRegState,
+                    const RegisterCFIState &NextRegState,
+                    const std::set<DWARFRegType> &Reads,
+                    const std::set<DWARFRegType> &Writes) {
+    auto RegLLVMOpt = MCRI->getLLVMRegNum(Reg, false);
+    if (RegLLVMOpt == std::nullopt) {
+      assert(PrevRegState == NextRegState);
+      return;
+    }
+    MCPhysReg RegLLVM = RegLLVMOpt.value();
+
+    auto &&PrevRefReg =
+        PrevState.getReferenceRegisterForCallerValueOfRegister(Reg);
+    auto &&NextRefReg =
+        NextState.getReferenceRegisterForCallerValueOfRegister(Reg);
+
+    std::optional<MCPhysReg> PrevRefRegLLVM =
+        (PrevRefReg != std::nullopt
+             ? std::make_optional(
+                   MCRI->getLLVMRegNum(PrevRefReg.value(), false).value())
+             : std::nullopt);
+    std::optional<MCPhysReg> NextRefRegLLVM =
+        (PrevRefReg != std::nullopt
+             ? std::make_optional(
+                   MCRI->getLLVMRegNum(PrevRefReg.value(), false).value())
+             : std::nullopt);
+
+    MCPhysReg PrevStateCFARegLLVM =
+        MCRI->getLLVMRegNum(PrevState.CFARegister, false).value();
+
+    { // try generate
+      // Widen
+      std::vector<RegisterCFIState> PossibleNextRegStates;
+      { // storing to offset from CFA
+        if (PrevRegState.RetrieveApproach == RegisterCFIState::SameValue ||
+            PrevRegState.RetrieveApproach ==
+                RegisterCFIState::AnotherRegister) {
+          int64_t OffsetFromCFAReg;
+          if (doStoreFromReg(Inst, PrevRefRegLLVM.value(), PrevStateCFARegLLVM,
+                             OffsetFromCFAReg)) {
+            PossibleNextRegStates.push_back(
+                RegisterCFIState::createOffsetFromCFAAddr(OffsetFromCFAReg -
+                                                          PrevState.CFAOffset));
+          }
+        }
+      }
+
+      { // loading from an offset from CFA
+        if (PrevRegState.RetrieveApproach ==
+            RegisterCFIState::OffsetFromCFAAddr) {
+          int64_t OffsetFromCFAReg;
+          MCPhysReg ToRegLLVM;
+          if (doLoadFromReg(Inst, PrevStateCFARegLLVM, OffsetFromCFAReg,
+                            ToRegLLVM) &&
+              OffsetFromCFAReg == PrevRegState.Info.OffsetFromCFA) {
+            DWARFRegType ToReg = MCRI->getDwarfRegNum(ToRegLLVM, false);
+            if (ToReg == Reg) {
+              PossibleNextRegStates.push_back(
+                  RegisterCFIState::createSameValue());
+            } else {
+              PossibleNextRegStates.push_back(
+                  RegisterCFIState::createAnotherRegister(ToReg));
+            }
+          }
+        }
+      }
+
+      { // moved from reg to other reg
+        if (PrevRegState.RetrieveApproach == RegisterCFIState::SameValue ||
+            PrevRegState.RetrieveApproach ==
+                RegisterCFIState::AnotherRegister) {
+
+          int Diff;
+          MCPhysReg PossibleRegLLVM;
+          if (isInConstantDistanceOfEachOther(Inst, PossibleRegLLVM,
+                                              PrevRefRegLLVM.value(), Diff)) {
+            DWARFRegType PossibleReg =
+                MCRI->getDwarfRegNum(PossibleRegLLVM, false);
+            if (Diff == 0) {
+              if (PossibleReg == Reg) {
+                PossibleNextRegStates.push_back(
+                    RegisterCFIState::createSameValue());
+              } else {
+                PossibleNextRegStates.push_back(
+                    RegisterCFIState::createAnotherRegister(PossibleReg));
+              }
+            }
+          }
+        }
+      }
+
+      { // stay the same
+        bool CanStayTheSame = false;
+
+        switch (PrevRegState.RetrieveApproach) {
+        case RegisterCFIState::Undefined:
+        case RegisterCFIState::OffsetFromCFAVal:
+          CanStayTheSame = true;
+          break;
+        case RegisterCFIState::SameValue:
+        case RegisterCFIState::AnotherRegister:
+          CanStayTheSame = !Writes.count(PrevRefReg.value());
+          break;
+        case RegisterCFIState::OffsetFromCFAAddr:
+        case RegisterCFIState::Other:
+          // cannot be sure
+          break;
+        }
+
+        if (CanStayTheSame)
+          PossibleNextRegStates.push_back(PrevRegState);
+      }
+
+      for (auto &&PossibleNextRegState : PossibleNextRegStates) {
+        if (PossibleNextRegState == NextRegState) {
+          // Everything is ok
+          return;
+        }
+      }
+
+      for (auto &&PossibleNextRegState : PossibleNextRegStates) {
+        if (PossibleNextRegState.RetrieveApproach !=
+            NextRegState.RetrieveApproach)
+          continue;
+
+        if (PossibleNextRegState.RetrieveApproach ==
+            RegisterCFIState::OffsetFromCFAAddr) {
+          Context.reportError(
+              Inst.getLoc(),
+              formatv(
+                  "Expected caller's value of reg#{0} should be at offset {1} "
+                  "of CFA but the CFI directives say it's in {2}",
+                  RegLLVM, PossibleNextRegState.Info.OffsetFromCFA,
+                  NextRegState.Info.OffsetFromCFA));
+        }
+      }
+    }
+    // Either couldn't generate, or the programmer changed the state to
+    // something that couldn't be matched to any of the generated states. So
+    // it falls back into read/write checks.
+
+    if (PrevRegState == NextRegState) {
+      switch (PrevRegState.RetrieveApproach) {
+      case RegisterCFIState::SameValue:
+      case RegisterCFIState::AnotherRegister:
+        if (Writes.count(PrevRefReg.value())) {
+          Context.reportError(
+              Inst.getLoc(),
+              formatv("Reg#{0} caller's value is in reg#{1} which is changed "
+                      "by this instruction, but not changed in CFI directives",
+                      RegLLVM, PrevRefRegLLVM.value()));
+          return;
+        }
+        break;
+      default:
+        // Everything may be ok
+        break;
+      }
+      return;
+    }
+
+    if (PrevRegState.RetrieveApproach == NextRegState.RetrieveApproach) {
+      // Everything may be ok
+      return;
+    }
+
+    if (PrevRegState.RetrieveApproach == RegisterCFIState::Undefined) {
+      Context.reportError(Inst.getLoc(),
+                          "Cannot change a register CFI information from "
+                          "undefined to something else.");
+      return;
+    }
+
+    Context.reportWarning(Inst.getLoc(),
+                          formatv("The reg#{0} CFI state is changed, but I "
+                                  "don't have any idea how.",
+                                  RegLLVM));
+    // Everything may be ok
+    return;
+  }
+
   void checkCFADiff(const MCInst &Inst, const CFIState &PrevState,
                     const CFIState &NextState,
                     const std::set<DWARFRegType> &Reads,
@@ -113,9 +418,9 @@ class CFIAnalysis {
     MCPhysReg NextCFAPhysReg =
         MCRI->getLLVMRegNum(NextState.CFARegister, false).value();
 
-    // Try to guess the next state. (widen)
-    std::vector<std::pair<DWARFRegType, int>> PossibleNextCFAStates;
-    {   // try generate
+    { // try generate
+      // Widen
+      std::vector<std::pair<DWARFRegType, int>> PossibleNextCFAStates;
       { // no change
         if (!Writes.count(PrevState.CFARegister)) {
           PossibleNextCFAStates.emplace_back(PrevState.CFARegister,
@@ -141,29 +446,29 @@ class CFIAnalysis {
               PrevState.CFAOffset - Diff);
         }
       }
-    }
 
-    for (auto &&[PossibleNextCFAReg, PossibleNextCFAOffset] :
-         PossibleNextCFAStates) {
-      if (PossibleNextCFAReg != NextState.CFARegister)
-        continue;
+      for (auto &&[PossibleNextCFAReg, PossibleNextCFAOffset] :
+           PossibleNextCFAStates) {
+        if (PossibleNextCFAReg != NextState.CFARegister)
+          continue;
 
-      if (PossibleNextCFAOffset == NextState.CFAOffset) {
-        // Everything is ok!
+        if (PossibleNextCFAOffset == NextState.CFAOffset) {
+          // Everything is ok!
+          return;
+        }
+
+        Context.reportError(Inst.getLoc(),
+                            formatv("Expected CFA [reg: {0}, offset: {1}] but "
+                                    "got [reg: {2}, offset: {3}].",
+                                    NextCFAPhysReg, PossibleNextCFAOffset,
+                                    NextCFAPhysReg, NextState.CFAOffset));
         return;
       }
-
-      Context.reportError(Inst.getLoc(),
-                          formatv("Expected CFA [reg: {0}, offset: {1}] but "
-                                  "got [reg: {2}, offset: {3}].",
-                                  NextCFAPhysReg, PossibleNextCFAOffset,
-                                  NextCFAPhysReg, NextState.CFAOffset));
-      return;
     }
 
-    // Either couldn't generate, or did, but the programmer wants to change the
-    // source of register for CFA to something not expected by the generator. So
-    // it falls back into read/write checks.
+    // Either couldn't generate, or did, but the programmer wants to change
+    // the source of register for CFA to something not expected by the
+    // generator. So it falls back into read/write checks.
 
     if (PrevState.CFARegister == NextState.CFARegister) {
       if (PrevState.CFAOffset == NextState.CFAOffset) {
@@ -173,6 +478,7 @@ class CFIAnalysis {
               formatv("This instruction changes reg#{0}, which is "
                       "the CFA register, but the CFI directives do not.",
                       PrevCFAPhysReg));
+          return;
         }
 
         // Everything is ok!
@@ -190,7 +496,8 @@ class CFIAnalysis {
 
       Context.reportWarning(
           Inst.getLoc(),
-          "I don't know what the instruction did, but it changed the CFA reg's "
+          "I don't know what the instruction did, but it changed the CFA "
+          "reg's "
           "value, and the offset is changed as well by the CFI directives.");
       // Everything may be ok!
       return;
@@ -198,7 +505,8 @@ class CFIAnalysis {
     // The CFA register is changed
     Context.reportWarning(
         Inst.getLoc(), "The CFA register is changed to something, and I don't "
-                       "have any idea on the new register relevance to CFA.");
+                       "have any idea on the new register relevance to CFA. I "
+                       "assume CFA is preserved.");
     // Everything may be ok!
   }
 
@@ -214,21 +522,33 @@ class CFIAnalysis {
 
     std::set<DWARFRegType> Writes, Reads;
     for (unsigned I = 0; I < MCInstInfo.NumImplicitUses; I++)
-      Reads.insert(MCRI->getDwarfRegNum(MCInstInfo.implicit_uses()[I], false));
+      Reads.insert(MCRI->getDwarfRegNum(
+          getSuperReg(MCInstInfo.implicit_uses()[I]), false));
     for (unsigned I = 0; I < MCInstInfo.NumImplicitDefs; I++)
-      Writes.insert(MCRI->getDwarfRegNum(MCInstInfo.implicit_defs()[I], false));
+      Writes.insert(MCRI->getDwarfRegNum(
+          getSuperReg(MCInstInfo.implicit_defs()[I]), false));
 
     for (unsigned I = 0; I < Inst.getNumOperands(); I++) {
       auto &&Operand = Inst.getOperand(I);
       if (Operand.isReg()) {
         if (I < MCInstInfo.getNumDefs())
-          Writes.insert(MCRI->getDwarfRegNum(Operand.getReg(), false));
-        else
-          Reads.insert(MCRI->getDwarfRegNum(Operand.getReg(), false));
+          Writes.insert(
+              MCRI->getDwarfRegNum(getSuperReg(Operand.getReg()), false));
+        else if (Operand.getReg())
+          Reads.insert(
+              MCRI->getDwarfRegNum(getSuperReg(Operand.getReg()), false));
       }
     }
+
     ///////////// being diffing the CFI states
     checkCFADiff(Inst, State, AfterState, Reads, Writes);
+
+    for (auto &&[Reg, RegState] : State.RegisterCFIStates) {
+      assert(AfterState.RegisterCFIStates.count(Reg) &&
+             "Registers' state should not be deleted by CFI instruction.");
+      checkRegDiff(Inst, Reg, State, AfterState, RegState,
+                   AfterState.RegisterCFIStates[Reg], Reads, Writes);
+    }
     ///////////// end diffing the CFI states
 
     // dbgs() << "^^^^^^^^^^^^^^^^ InsCFIs ^^^^^^^^^^^^^^^^\n";
@@ -245,7 +565,8 @@ class CFIAnalysis {
     //     auto X86MemoryOperand = EMCIA->evaluateX86MemoryOperand(Inst);
     //     dbgs() << "  Base Register{ reg#" << X86MemoryOperand->BaseRegNum
     //            << " }";
-    //     dbgs() << " + (Index Register{ reg#" << X86MemoryOperand->IndexRegNum
+    //     dbgs() << " + (Index Register{ reg#" <<
+    //     X86MemoryOperand->IndexRegNum
     //            << " }";
     //     dbgs() << " * Scale{ value " << X86MemoryOperand->ScaleImm << " }";
     //     dbgs() << ") + Displacement{ "
@@ -253,7 +574,8 @@ class CFIAnalysis {
     //                    ? "an expression"
     //                    : "value " + itostr(X86MemoryOperand->DispImm))
     //            << " }\n";
-    //     // TODO, it's not correct always, it cannot be assumed (or should be
+    //     // TODO, it's not correct always, it cannot be assumed (or should
+    //     be
     //     // checked) that memory operands are flatten into 4 operands in
     //     MCInc. I += 4; continue;
     //   }
@@ -288,11 +610,13 @@ class CFIAnalysis {
     //   { // Reg2Reg
     //     MCPhysReg From, To;
     //     if (EMCIA->isRegToRegMove(Inst, From, To)) {
-    //       dbgs() << "It's a reg to reg move.\nFrom reg#" << From << " to reg
+    //       dbgs() << "It's a reg to reg move.\nFrom reg#" << From << " to
+    //       reg
     //       #"
     //              << To << "\n";
     //     } else if (MCInstInfo.isMoveReg()) {
-    //       dbgs() << "It's reg to reg move from MCInstInfo view but not from "
+    //       dbgs() << "It's reg to reg move from MCInstInfo view but not from
+    //       "
     //                 "MCPlus view.\n";
     //     }
     //   }
@@ -320,17 +644,17 @@ class CFIAnalysis {
     //   if (EMCIA->isStackAccess(Inst, IsLoad, IsStore, IsStoreFromReg, Reg,
     //                            SrcImm, StackPtrReg, StackOffset, Size,
     //                            IsSimple, IsIndexed)) {
-    //     dbgs() << "This instruction accesses the stack, the details are:\n";
-    //     dbgs() << "  Source immediate: " << SrcImm << "\n";
-    //     dbgs() << "  Source reg#" << Reg << "\n";
-    //     dbgs() << "  Stack pointer: reg#" << StackPtrReg << "\n";
-    //     dbgs() << "  Stack offset: " << StackOffset << "\n";
-    //     dbgs() << "  size: " << (int)Size << "\n";
+    //     dbgs() << "This instruction accesses the stack, the details
+    //     are:\n"; dbgs() << "  Source immediate: " << SrcImm << "\n"; dbgs()
+    //     << "  Source reg#" << Reg << "\n"; dbgs() << "  Stack pointer:
+    //     reg#" << StackPtrReg << "\n"; dbgs() << "  Stack offset: " <<
+    //     StackOffset << "\n"; dbgs() << "  size: " << (int)Size << "\n";
     //     dbgs() << "  Is simple: " << (IsSimple ? "yes" : "no") << "\n";
     //     dbgs() << "  Is indexed: " << (IsIndexed ? "yes" : "no") << "\n";
     //     dbgs() << "  Is load: " << (IsLoad ? "yes" : "no") << "\n";
     //     dbgs() << "  Is store: " << (IsStore ? "yes" : "no") << "\n";
-    //     dbgs() << "  Is store from reg: " << (IsStoreFromReg ? "yes" : "no")
+    //     dbgs() << "  Is store from reg: " << (IsStoreFromReg ? "yes" :
+    //     "no")
     //            << "\n";
     //   }
     //   if (EMCIA->isPush(Inst)) {
@@ -364,7 +688,8 @@ class CFIAnalysis {
     // dbgs() << "The CFA register is: " << CFAReg << "\n";
     // dbgs() << "The instruction does " << (ChangedCFA ? "" : "NOT ")
     //        << "change the CFA.\n";
-    // dbgs() << "The CFI directives does " << (GoingToChangeCFA ? "" : "NOT ")
+    // dbgs() << "The CFI directives does " << (GoingToChangeCFA ? "" : "NOT
+    // ")
     //        << "change the CFA.\n";
     // dbgs() << "vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n";
 
diff --git a/llvm/tools/llvm-mc/CFIState.h b/llvm/tools/llvm-mc/CFIState.h
index 5551e9778f1d2..b0091efecbb7b 100644
--- a/llvm/tools/llvm-mc/CFIState.h
+++ b/llvm/tools/llvm-mc/CFIState.h
@@ -5,7 +5,9 @@
 #include "llvm/MC/MCDwarf.h"
 #include "llvm/MC/MCRegister.h"
 #include "llvm/Support/MathExtras.h"
+#include <cassert>
 #include <cstdint>
+#include <optional>
 namespace llvm {
 
 using DWARFRegType = int64_t;
@@ -26,6 +28,23 @@ struct RegisterCFIState {
     DWARFRegType Register;
   } Info;
 
+  bool operator==(const RegisterCFIState &OtherState) const {
+    if (RetrieveApproach != OtherState.RetrieveApproach)
+      return false;
+
+    switch (RetrieveApproach) {
+    case Undefined:
+    case SameValue:
+    case Other:
+      return true;
+    case AnotherRegister:
+      return Info.Register == OtherState.Info.Register;
+    case OffsetFromCFAAddr:
+    case OffsetFromCFAVal:
+      return Info.OffsetFromCFA == OtherState.Info.OffsetFromCFA;
+    }
+  }
+
   static RegisterCFIState createUndefined() {
     RegisterCFIState State;
     State.RetrieveApproach = Undefined;
@@ -97,6 +116,25 @@ struct CFIState {
   CFIState(DWARFRegType CFARegister, int CFIOffset)
       : CFARegister(CFARegister), CFAOffset(CFIOffset) {}
 
+  std::optional<DWARFRegType>
+  getReferenceRegisterForCallerValueOfRegister(DWARFRegType Reg) const {
+    assert(RegisterCFIStates.count(Reg) &&
+           "The register should be tracked inside the register states");
+    auto &&RegState = RegisterCFIStates.at(Reg);
+    switch (RegState.RetrieveApproach) {
+    case RegisterCFIState::Undefined:
+    case RegisterCFIState::Other:
+      return std::nullopt;
+    case RegisterCFIState::SameValue:
+      return Reg;
+    case RegisterCFIState::AnotherRegister:
+      return RegState.Info.Register;
+    case RegisterCFIState::OffsetFromCFAAddr:
+    case RegisterCFIState::OffsetFromCFAVal:
+      return CFARegister;
+    }
+  }
+
   bool apply(const MCCFIInstruction &CFIDirective) {
     switch (CFIDirective.getOperation()) {
     case MCCFIInstruction::OpDefCfaRegister:

>From 79c166416a48da408310dd08a039978ae4d847d6 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Tue, 20 May 2025 02:29:47 +0000
Subject: [PATCH 16/58] Process prologue as well

---
 llvm/tools/llvm-mc/CFIAnalysis.h           | 11 +++--
 llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h | 53 ++++++++++------------
 2 files changed, 32 insertions(+), 32 deletions(-)

diff --git a/llvm/tools/llvm-mc/CFIAnalysis.h b/llvm/tools/llvm-mc/CFIAnalysis.h
index f0b81a85e2fd4..533ead49c300d 100644
--- a/llvm/tools/llvm-mc/CFIAnalysis.h
+++ b/llvm/tools/llvm-mc/CFIAnalysis.h
@@ -78,11 +78,9 @@ class CFIAnalysis {
 
 public:
   CFIAnalysis(MCContext &Context, MCInstrInfo const &MCII,
-              MCInstrAnalysis *MCIA)
+              MCInstrAnalysis *MCIA,
+              ArrayRef<MCCFIInstruction> PrologueCFIDirectives)
       : Context(Context), MCII(MCII), MCRI(Context.getRegisterInfo()) {
-    // TODO it should look at the prologue directives and setup the
-    // registers' previous value state here, but for now, it's assumed that all
-    // values are by default `samevalue`.
     EMCIA.reset(new ExtendedMCInstrAnalysis(Context, MCII, MCIA));
 
     // TODO CFA offset should be the slot size, but for now I don't have any
@@ -103,6 +101,11 @@ class CFIAnalysis {
     State.RegisterCFIStates[MCRI->getDwarfRegNum(EMCIA->getStackPointer(),
                                                  false)] =
         RegisterCFIState::createOffsetFromCFAVal(0); // sp's old value is CFA
+
+    // Applying the prologue after default assumptions to overwrite them.
+    for (auto &&PrologueCFIDirective : PrologueCFIDirectives) {
+      State.apply(PrologueCFIDirective);
+    }
   }
 
   bool doesConstantChange(const MCInst &Inst, MCPhysReg Reg, int64_t &HowMuch) {
diff --git a/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h b/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h
index a9354d7af8a2f..7f79653004e5e 100644
--- a/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h
+++ b/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h
@@ -38,12 +38,8 @@ class CFIAnalysisMCStreamer : public MCStreamer {
   };
 
   std::optional<MCInst> LastInstruction;
-  MCDwarfFrameInfo const *LastDwarfFrameInfo;
-
-  std::optional<ICFI> getLastICFI() {
-    if (!LastInstruction)
-      return std::nullopt;
 
+  std::pair<unsigned, unsigned> getCFIDirectivesRange() {
     auto DwarfFrameInfos = getDwarfFrameInfos();
     int FrameIndex = FrameIndices.back();
     auto CurrentCFIDirectiveState =
@@ -57,31 +53,42 @@ class CFIAnalysisMCStreamer : public MCStreamer {
     std::pair<unsigned, unsigned> CFIDirectivesRange(
         LastCFIDirectivesState.DirectiveIndex,
         CurrentCFIDirectiveState.DirectiveIndex);
-
     LastCFIDirectivesState = CurrentCFIDirectiveState;
-    return ICFI(LastInstruction.value(), CFIDirectivesRange);
+    return CFIDirectivesRange;
   }
 
   void feedCFIA() {
-    if (!LastDwarfFrameInfo) {
+    auto FrameIndex = FrameIndices.back();
+    if (FrameIndex < 0) {
       // TODO Maybe this corner case causes bugs, when the programmer did a
       // mistake in the startproc, endprocs and also made a mistake in not
       // adding cfi directives for a instruction. Then this would cause to
       // ignore the instruction.
-      auto LastICFI = getLastICFI();
-      assert(!LastICFI || LastICFI->CFIDirectivesRange.first ==
-                              LastICFI->CFIDirectivesRange.second);
+      auto CFIDirectivesRange = getCFIDirectivesRange();
+      assert(!LastInstruction ||
+             CFIDirectivesRange.first == CFIDirectivesRange.second);
       return;
     }
 
-    if (auto ICFI = getLastICFI()) {
-      assert(!CFIAs.empty());
-      ArrayRef<MCCFIInstruction> CFIDirectives(
-          LastDwarfFrameInfo->Instructions);
-      CFIDirectives = CFIDirectives.drop_front(ICFI->CFIDirectivesRange.first)
+    // TODO get this from emit yourself, instead of getting it in this way
+    const auto *LastDwarfFrameInfo = &getDwarfFrameInfos()[FrameIndex];
+
+    auto CFIDirectivesRange = getCFIDirectivesRange();
+    ArrayRef<MCCFIInstruction> CFIDirectives;
+    if (CFIDirectivesRange.first < CFIDirectivesRange.second) {
+      CFIDirectives =
+          ArrayRef<MCCFIInstruction>(LastDwarfFrameInfo->Instructions);
+      CFIDirectives = CFIDirectives.drop_front(CFIDirectivesRange.first)
                           .drop_back(LastDwarfFrameInfo->Instructions.size() -
-                                     ICFI->CFIDirectivesRange.second);
-      CFIAs.back().update(ICFI->Instruction, CFIDirectives);
+                                     CFIDirectivesRange.second);
+    }
+
+    if (LastInstruction != std::nullopt) {
+      assert(!CFIAs.empty());
+
+      CFIAs.back().update(LastInstruction.value(), CFIDirectives);
+    } else {
+      CFIAs.emplace_back(getContext(), MCII, MCIA.get(), CFIDirectives);
     }
   }
 
@@ -114,21 +121,12 @@ class CFIAnalysisMCStreamer : public MCStreamer {
                        const MCSubtargetInfo &STI) override {
     feedCFIA();
     LastInstruction = Inst;
-    if (hasUnfinishedDwarfFrameInfo())
-      LastDwarfFrameInfo =
-          &getDwarfFrameInfos()[FrameIndices.back()]; // TODO get this from emit
-                                                      // yourself, instead of
-                                                      // getting it in this way
-    else
-      LastDwarfFrameInfo = nullptr;
   }
 
   void emitCFIStartProcImpl(MCDwarfFrameInfo &Frame) override {
     feedCFIA();
     FrameIndices.push_back(getNumFrameInfos());
-    CFIAs.emplace_back(getContext(), MCII, MCIA.get());
     LastInstruction = std::nullopt;
-    LastDwarfFrameInfo = nullptr;
     LastCFIDirectivesState.DirectiveIndex = 0;
     MCStreamer::emitCFIStartProcImpl(Frame);
   }
@@ -139,7 +137,6 @@ class CFIAnalysisMCStreamer : public MCStreamer {
     FrameIndices.pop_back();
     CFIAs.pop_back();
     LastInstruction = std::nullopt;
-    LastDwarfFrameInfo = nullptr;
     auto FrameIndex = FrameIndices.back();
     LastCFIDirectivesState.DirectiveIndex =
         FrameIndex >= 0 ? getDwarfFrameInfos()[FrameIndex].Instructions.size()

>From 02410ac0633d30bed60f35c308f4e652b4a3ebd5 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Tue, 20 May 2025 17:54:28 +0000
Subject: [PATCH 17/58] Ignore flag registers as well

---
 llvm/tools/llvm-mc/CFIAnalysis.h | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/llvm/tools/llvm-mc/CFIAnalysis.h b/llvm/tools/llvm-mc/CFIAnalysis.h
index 533ead49c300d..55a02dcb1013e 100644
--- a/llvm/tools/llvm-mc/CFIAnalysis.h
+++ b/llvm/tools/llvm-mc/CFIAnalysis.h
@@ -102,6 +102,9 @@ class CFIAnalysis {
                                                  false)] =
         RegisterCFIState::createOffsetFromCFAVal(0); // sp's old value is CFA
 
+    State.RegisterCFIStates[MCRI->getDwarfRegNum(EMCIA->getFlagsReg(), false)] =
+        RegisterCFIState::createUndefined(); // Flags cannot be caller-saved
+
     // Applying the prologue after default assumptions to overwrite them.
     for (auto &&PrologueCFIDirective : PrologueCFIDirectives) {
       State.apply(PrologueCFIDirective);
@@ -119,7 +122,7 @@ class CFIAnalysis {
     if (EMCIA->isPop(Inst) && Reg == EMCIA->getStackPointer()) {
       // TODO should get the stack direction here, now it assumes that it goes
       // down.
-      HowMuch = EMCIA->getPushSize(Inst);
+      HowMuch = EMCIA->getPopSize(Inst);
       return true;
     }
 
@@ -285,7 +288,8 @@ class CFIAnalysis {
           MCPhysReg ToRegLLVM;
           if (doLoadFromReg(Inst, PrevStateCFARegLLVM, OffsetFromCFAReg,
                             ToRegLLVM) &&
-              OffsetFromCFAReg == PrevRegState.Info.OffsetFromCFA) {
+              OffsetFromCFAReg - PrevState.CFAOffset ==
+                  PrevRegState.Info.OffsetFromCFA) {
             DWARFRegType ToReg = MCRI->getDwarfRegNum(ToRegLLVM, false);
             if (ToReg == Reg) {
               PossibleNextRegStates.push_back(

>From dfdd22f78c73deb05806d754ba211ca39177509e Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Tue, 20 May 2025 17:54:44 +0000
Subject: [PATCH 18/58] Enable dump

---
 llvm/tools/llvm-mc/CFIState.h | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/llvm/tools/llvm-mc/CFIState.h b/llvm/tools/llvm-mc/CFIState.h
index b0091efecbb7b..1b66d0dd40904 100644
--- a/llvm/tools/llvm-mc/CFIState.h
+++ b/llvm/tools/llvm-mc/CFIState.h
@@ -2,12 +2,15 @@
 #define LLVM_TOOLS_LLVM_MC_CFI_STATE_H
 
 #include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringRef.h"
 #include "llvm/MC/MCDwarf.h"
 #include "llvm/MC/MCRegister.h"
+#include "llvm/Support/FormatVariadic.h"
 #include "llvm/Support/MathExtras.h"
 #include <cassert>
 #include <cstdint>
 #include <optional>
+#include <string>
 namespace llvm {
 
 using DWARFRegType = int64_t;
@@ -28,6 +31,24 @@ struct RegisterCFIState {
     DWARFRegType Register;
   } Info;
 
+  std::string dump() {
+    switch (RetrieveApproach) {
+    case Undefined:
+      return "undefined";
+    case SameValue:
+      return "same value";
+    case AnotherRegister:
+      return formatv("stored in another register, which is reg#{0}",
+                     Info.Register);
+    case OffsetFromCFAAddr:
+      return formatv("offset {0} from CFA", Info.OffsetFromCFA);
+    case OffsetFromCFAVal:
+      return formatv("CFA value + {0}", Info.OffsetFromCFA);
+    case Other:
+      return "other";
+    }
+  }
+
   bool operator==(const RegisterCFIState &OtherState) const {
     if (RetrieveApproach != OtherState.RetrieveApproach)
       return false;
@@ -45,6 +66,10 @@ struct RegisterCFIState {
     }
   }
 
+  bool operator!=(const RegisterCFIState &OtherState) const {
+    return !(*this == OtherState);
+  }
+
   static RegisterCFIState createUndefined() {
     RegisterCFIState State;
     State.RetrieveApproach = Undefined;

>From 4fd37bf32055c1ae3bbcf9f22b52a5f09b6af87b Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Tue, 20 May 2025 17:55:25 +0000
Subject: [PATCH 19/58] Enable getting flag register through extended
 MCInstrAnalysis

---
 llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h b/llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h
index 5323c4e3d1730..547d132671f45 100644
--- a/llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h
+++ b/llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h
@@ -44,6 +44,7 @@ class ExtendedMCInstrAnalysis {
   /// Extra semantic information needed from MC layer:
 
   MCPhysReg getStackPointer() const { return MCPB->getStackPointer(); }
+  MCPhysReg getFlagsReg() const { return MCPB->getFlagsReg(); }
 
   bool isPush(const MCInst &Inst) const { return MCPB->isPush(Inst); }
   int getPushSize(const MCInst &Inst) const { return MCPB->getPushSize(Inst); }

>From 07d38b246b4f851cc2d3c9656806a5b62fba21a7 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Tue, 20 May 2025 18:29:25 +0000
Subject: [PATCH 20/58] Move the isolated MC semantic methods to
 ExtendedMCAnalysis

---
 llvm/tools/llvm-mc/CFIAnalysis.h             | 350 +++----------------
 llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h | 120 +++++++
 2 files changed, 162 insertions(+), 308 deletions(-)

diff --git a/llvm/tools/llvm-mc/CFIAnalysis.h b/llvm/tools/llvm-mc/CFIAnalysis.h
index 55a02dcb1013e..57e2b7247b45f 100644
--- a/llvm/tools/llvm-mc/CFIAnalysis.h
+++ b/llvm/tools/llvm-mc/CFIAnalysis.h
@@ -111,127 +111,49 @@ class CFIAnalysis {
     }
   }
 
-  bool doesConstantChange(const MCInst &Inst, MCPhysReg Reg, int64_t &HowMuch) {
-    if (EMCIA->isPush(Inst) && Reg == EMCIA->getStackPointer()) {
-      // TODO should get the stack direction here, now it assumes that it goes
-      // down.
-      HowMuch = -EMCIA->getPushSize(Inst);
-      return true;
-    }
-
-    if (EMCIA->isPop(Inst) && Reg == EMCIA->getStackPointer()) {
-      // TODO should get the stack direction here, now it assumes that it goes
-      // down.
-      HowMuch = EMCIA->getPopSize(Inst);
-      return true;
-    }
-
-    return false;
-  }
-
-  // Tries to guess Reg1's value in a form of Reg2 (before Inst's execution) +
-  // Diff.
-  bool isInConstantDistanceOfEachOther(const MCInst &Inst, MCPhysReg &Reg1,
-                                       MCPhysReg Reg2, int &Diff) {
-    {
-      MCPhysReg From;
-      MCPhysReg To;
-      if (EMCIA->isRegToRegMove(Inst, From, To) && From == Reg2) {
-        Reg1 = To;
-        Diff = 0;
-        return true;
-      }
-    }
-
-    return false;
-  }
+  void update(MCInst &Inst, ArrayRef<MCCFIInstruction> CFIDirectives) {
+    const MCInstrDesc &MCInstInfo = MCII.get(Inst.getOpcode());
+    CFIState AfterState(State);
+    for (auto &&CFIDirective : CFIDirectives)
+      if (!AfterState.apply(CFIDirective))
+        Context.reportWarning(
+            CFIDirective.getLoc(),
+            "I don't support this CFI directive, I assume this does nothing "
+            "(which will probably break other things)");
 
-  bool doStoreFromReg(const MCInst &Inst, MCPhysReg StoringReg,
-                      MCPhysReg FromReg, int64_t &Offset) {
-    if (EMCIA->isPush(Inst) && FromReg == EMCIA->getStackPointer()) {
-      // TODO should get the stack direction here, now it assumes that it goes
-      // down.
-      Offset = -EMCIA->getPushSize(Inst);
-      return true;
-    }
+    std::set<DWARFRegType> Writes, Reads;
+    for (unsigned I = 0; I < MCInstInfo.NumImplicitUses; I++)
+      Reads.insert(MCRI->getDwarfRegNum(
+          getSuperReg(MCInstInfo.implicit_uses()[I]), false));
+    for (unsigned I = 0; I < MCInstInfo.NumImplicitDefs; I++)
+      Writes.insert(MCRI->getDwarfRegNum(
+          getSuperReg(MCInstInfo.implicit_defs()[I]), false));
 
-    {
-      bool IsLoad;
-      bool IsStore;
-      bool IsStoreFromReg;
-      MCPhysReg SrcReg;
-      int32_t SrcImm;
-      uint16_t StackPtrReg;
-      int64_t StackOffset;
-      uint8_t Size;
-      bool IsSimple;
-      bool IsIndexed;
-      if (EMCIA->isStackAccess(Inst, IsLoad, IsStore, IsStoreFromReg, SrcReg,
-                               SrcImm, StackPtrReg, StackOffset, Size, IsSimple,
-                               IsIndexed)) {
-        // TODO make sure that simple means that it's store and does nothing
-        // more.
-        if (IsStore && IsSimple && StackPtrReg == FromReg && IsStoreFromReg &&
-            SrcReg == StoringReg) {
-          Offset = StackOffset;
-          return true;
-        }
+    for (unsigned I = 0; I < Inst.getNumOperands(); I++) {
+      auto &&Operand = Inst.getOperand(I);
+      if (Operand.isReg()) {
+        if (I < MCInstInfo.getNumDefs())
+          Writes.insert(
+              MCRI->getDwarfRegNum(getSuperReg(Operand.getReg()), false));
+        else if (Operand.getReg())
+          Reads.insert(
+              MCRI->getDwarfRegNum(getSuperReg(Operand.getReg()), false));
       }
     }
 
-    return false;
-  }
-
-  bool doLoadFromReg(const MCInst &Inst, MCPhysReg FromReg, int64_t &Offset,
-                     MCPhysReg &LoadingReg) {
-    if (EMCIA->isPop(Inst) && FromReg == EMCIA->getStackPointer()) {
-      // TODO should get the stack direction here, now it assumes that it goes
-      // down.
-      Offset = 0;
-      LoadingReg = Inst.getOperand(0).getReg();
-      return true;
-    }
-
-    {
-      bool IsLoad;
-      bool IsStore;
-      bool IsStoreFromReg;
-      MCPhysReg SrcReg;
-      int32_t SrcImm;
-      uint16_t StackPtrReg;
-      int64_t StackOffset;
-      uint8_t Size;
-      bool IsSimple;
-      bool IsIndexed;
-      if (EMCIA->isStackAccess(Inst, IsLoad, IsStore, IsStoreFromReg, SrcReg,
-                               SrcImm, StackPtrReg, StackOffset, Size, IsSimple,
-                               IsIndexed)) {
-        // TODO make sure that simple means that it's store and does nothing
-        // more.
-        if (IsLoad && IsSimple && StackPtrReg == FromReg) {
-          Offset = StackOffset;
-          LoadingReg = SrcReg;
-          return true;
-        }
-      }
-    }
+    checkCFADiff(Inst, State, AfterState, Reads, Writes);
 
-    {
-      if (EMCIA->isMoveMem2Reg(Inst)) {
-        auto X86MemAccess = EMCIA->evaluateX86MemoryOperand(Inst).value();
-        if (X86MemAccess.BaseRegNum == FromReg &&
-            (X86MemAccess.ScaleImm == 0 || X86MemAccess.IndexRegNum == 0) &&
-            !X86MemAccess.DispExpr) {
-          LoadingReg = Inst.getOperand(0).getReg();
-          Offset = X86MemAccess.DispImm;
-          return true;
-        }
-      }
+    for (auto &&[Reg, RegState] : State.RegisterCFIStates) {
+      assert(AfterState.RegisterCFIStates.count(Reg) &&
+             "Registers' state should not be deleted by CFI instruction.");
+      checkRegDiff(Inst, Reg, State, AfterState, RegState,
+                   AfterState.RegisterCFIStates[Reg], Reads, Writes);
     }
 
-    return false;
+    State = AfterState;
   }
 
+private:
   void checkRegDiff(const MCInst &Inst, DWARFRegType Reg,
                     const CFIState &PrevState, const CFIState &NextState,
                     const RegisterCFIState &PrevRegState,
@@ -272,8 +194,8 @@ class CFIAnalysis {
             PrevRegState.RetrieveApproach ==
                 RegisterCFIState::AnotherRegister) {
           int64_t OffsetFromCFAReg;
-          if (doStoreFromReg(Inst, PrevRefRegLLVM.value(), PrevStateCFARegLLVM,
-                             OffsetFromCFAReg)) {
+          if (EMCIA->doStoreFromReg(Inst, PrevRefRegLLVM.value(),
+                                    PrevStateCFARegLLVM, OffsetFromCFAReg)) {
             PossibleNextRegStates.push_back(
                 RegisterCFIState::createOffsetFromCFAAddr(OffsetFromCFAReg -
                                                           PrevState.CFAOffset));
@@ -286,8 +208,8 @@ class CFIAnalysis {
             RegisterCFIState::OffsetFromCFAAddr) {
           int64_t OffsetFromCFAReg;
           MCPhysReg ToRegLLVM;
-          if (doLoadFromReg(Inst, PrevStateCFARegLLVM, OffsetFromCFAReg,
-                            ToRegLLVM) &&
+          if (EMCIA->doLoadFromReg(Inst, PrevStateCFARegLLVM, OffsetFromCFAReg,
+                                   ToRegLLVM) &&
               OffsetFromCFAReg - PrevState.CFAOffset ==
                   PrevRegState.Info.OffsetFromCFA) {
             DWARFRegType ToReg = MCRI->getDwarfRegNum(ToRegLLVM, false);
@@ -309,8 +231,8 @@ class CFIAnalysis {
 
           int Diff;
           MCPhysReg PossibleRegLLVM;
-          if (isInConstantDistanceOfEachOther(Inst, PossibleRegLLVM,
-                                              PrevRefRegLLVM.value(), Diff)) {
+          if (EMCIA->isInConstantDistanceOfEachOther(
+                  Inst, PossibleRegLLVM, PrevRefRegLLVM.value(), Diff)) {
             DWARFRegType PossibleReg =
                 MCRI->getDwarfRegNum(PossibleRegLLVM, false);
             if (Diff == 0) {
@@ -437,7 +359,7 @@ class CFIAnalysis {
 
       { // const change
         int64_t HowMuch;
-        if (doesConstantChange(Inst, PrevCFAPhysReg, HowMuch)) {
+        if (EMCIA->doesConstantChange(Inst, PrevCFAPhysReg, HowMuch)) {
           PossibleNextCFAStates.emplace_back(PrevState.CFARegister,
                                              PrevState.CFAOffset - HowMuch);
         }
@@ -446,8 +368,8 @@ class CFIAnalysis {
       { // constant distance with each other
         int Diff;
         MCPhysReg PossibleNewCFAReg;
-        if (isInConstantDistanceOfEachOther(Inst, PossibleNewCFAReg,
-                                            PrevCFAPhysReg, Diff)) {
+        if (EMCIA->isInConstantDistanceOfEachOther(Inst, PossibleNewCFAReg,
+                                                   PrevCFAPhysReg, Diff)) {
           PossibleNextCFAStates.emplace_back(
               MCRI->getDwarfRegNum(PossibleNewCFAReg, false),
               PrevState.CFAOffset - Diff);
@@ -516,194 +438,6 @@ class CFIAnalysis {
                        "assume CFA is preserved.");
     // Everything may be ok!
   }
-
-  void update(MCInst &Inst, ArrayRef<MCCFIInstruction> CFIDirectives) {
-    const MCInstrDesc &MCInstInfo = MCII.get(Inst.getOpcode());
-    CFIState AfterState(State);
-    for (auto &&CFIDirective : CFIDirectives)
-      if (!AfterState.apply(CFIDirective))
-        Context.reportWarning(
-            CFIDirective.getLoc(),
-            "I don't support this CFI directive, I assume this does nothing "
-            "(which will probably break other things)");
-
-    std::set<DWARFRegType> Writes, Reads;
-    for (unsigned I = 0; I < MCInstInfo.NumImplicitUses; I++)
-      Reads.insert(MCRI->getDwarfRegNum(
-          getSuperReg(MCInstInfo.implicit_uses()[I]), false));
-    for (unsigned I = 0; I < MCInstInfo.NumImplicitDefs; I++)
-      Writes.insert(MCRI->getDwarfRegNum(
-          getSuperReg(MCInstInfo.implicit_defs()[I]), false));
-
-    for (unsigned I = 0; I < Inst.getNumOperands(); I++) {
-      auto &&Operand = Inst.getOperand(I);
-      if (Operand.isReg()) {
-        if (I < MCInstInfo.getNumDefs())
-          Writes.insert(
-              MCRI->getDwarfRegNum(getSuperReg(Operand.getReg()), false));
-        else if (Operand.getReg())
-          Reads.insert(
-              MCRI->getDwarfRegNum(getSuperReg(Operand.getReg()), false));
-      }
-    }
-
-    ///////////// being diffing the CFI states
-    checkCFADiff(Inst, State, AfterState, Reads, Writes);
-
-    for (auto &&[Reg, RegState] : State.RegisterCFIStates) {
-      assert(AfterState.RegisterCFIStates.count(Reg) &&
-             "Registers' state should not be deleted by CFI instruction.");
-      checkRegDiff(Inst, Reg, State, AfterState, RegState,
-                   AfterState.RegisterCFIStates[Reg], Reads, Writes);
-    }
-    ///////////// end diffing the CFI states
-
-    // dbgs() << "^^^^^^^^^^^^^^^^ InsCFIs ^^^^^^^^^^^^^^^^\n";
-    // printUntilNextLine(Inst.getLoc().getPointer());
-    // dbgs() << "\n";
-    // dbgs() << "Op code: " << Inst.getOpcode() << "\n";
-    // dbgs() << "--------------Operands Info--------------\n";
-    // auto DefCount = MCInstInfo.getNumDefs();
-    // for (unsigned I = 0; I < Inst.getNumOperands(); I++) {
-    //   dbgs() << "Operand #" << I << ", which will be "
-    //          << (I < DefCount ? "defined" : "used") << ", is a";
-    //   if (I == EMCIA->getMemoryOperandNo(Inst)) {
-    //     dbgs() << " memory access, details are:\n";
-    //     auto X86MemoryOperand = EMCIA->evaluateX86MemoryOperand(Inst);
-    //     dbgs() << "  Base Register{ reg#" << X86MemoryOperand->BaseRegNum
-    //            << " }";
-    //     dbgs() << " + (Index Register{ reg#" <<
-    //     X86MemoryOperand->IndexRegNum
-    //            << " }";
-    //     dbgs() << " * Scale{ value " << X86MemoryOperand->ScaleImm << " }";
-    //     dbgs() << ") + Displacement{ "
-    //            << (X86MemoryOperand->DispExpr
-    //                    ? "an expression"
-    //                    : "value " + itostr(X86MemoryOperand->DispImm))
-    //            << " }\n";
-    //     // TODO, it's not correct always, it cannot be assumed (or should
-    //     be
-    //     // checked) that memory operands are flatten into 4 operands in
-    //     MCInc. I += 4; continue;
-    //   }
-    //   auto &&Operand = Inst.getOperand(I);
-    //   if (Operand.isImm()) {
-    //     dbgs() << "n immediate with value " << Operand.getImm() << "\n";
-    //     continue;
-    //   }
-    //   if (Operand.isReg()) {
-    //     dbgs() << " reg#" << Operand.getReg() << "\n";
-    //     continue;
-    //   }
-    //   assert(Operand.isExpr());
-    //   dbgs() << "n unknown expression \n";
-    // }
-    // if (MCInstInfo.NumImplicitDefs) {
-    //   dbgs() << "implicitly defines: { ";
-    //   for (unsigned I = 0; I < MCInstInfo.NumImplicitDefs; I++) {
-    //     dbgs() << "reg#" << MCInstInfo.implicit_defs()[I] << " ";
-    //   }
-    //   dbgs() << "}\n";
-    // }
-    // if (MCInstInfo.NumImplicitUses) {
-    //   dbgs() << "implicitly uses: { ";
-    //   for (unsigned I = 0; I < MCInstInfo.NumImplicitUses; I++) {
-    //     dbgs() << "reg#" << MCInstInfo.implicit_uses()[I] << " ";
-    //   }
-    //   dbgs() << "}\n";
-    // }
-    // dbgs() << "----------------Move Info----------------\n";
-    // {   // move
-    //   { // Reg2Reg
-    //     MCPhysReg From, To;
-    //     if (EMCIA->isRegToRegMove(Inst, From, To)) {
-    //       dbgs() << "It's a reg to reg move.\nFrom reg#" << From << " to
-    //       reg
-    //       #"
-    //              << To << "\n";
-    //     } else if (MCInstInfo.isMoveReg()) {
-    //       dbgs() << "It's reg to reg move from MCInstInfo view but not from
-    //       "
-    //                 "MCPlus view.\n";
-    //     }
-    //   }
-    //   if (EMCIA->isConditionalMove(Inst)) {
-    //     dbgs() << "Its a conditional move.\n";
-    //   }
-    //   if (EMCIA->isMoveMem2Reg(Inst)) {
-    //     dbgs() << "It's a move from memory to register\n";
-    //     assert(EMCIA->getMemoryOperandNo(Inst) == 1);
-    //   }
-    // }
-
-    // dbgs() << "---------------Stack Info----------------\n";
-    // { // stack
-    //   int32_t SrcImm = 0;
-    //   MCPhysReg Reg = 0;
-    //   uint16_t StackPtrReg = 0;
-    //   int64_t StackOffset = 0;
-    //   uint8_t Size = 0;
-    //   bool IsSimple = false;
-    //   bool IsIndexed = false;
-    //   bool IsLoad = false;
-    //   bool IsStore = false;
-    //   bool IsStoreFromReg = false;
-    //   if (EMCIA->isStackAccess(Inst, IsLoad, IsStore, IsStoreFromReg, Reg,
-    //                            SrcImm, StackPtrReg, StackOffset, Size,
-    //                            IsSimple, IsIndexed)) {
-    //     dbgs() << "This instruction accesses the stack, the details
-    //     are:\n"; dbgs() << "  Source immediate: " << SrcImm << "\n"; dbgs()
-    //     << "  Source reg#" << Reg << "\n"; dbgs() << "  Stack pointer:
-    //     reg#" << StackPtrReg << "\n"; dbgs() << "  Stack offset: " <<
-    //     StackOffset << "\n"; dbgs() << "  size: " << (int)Size << "\n";
-    //     dbgs() << "  Is simple: " << (IsSimple ? "yes" : "no") << "\n";
-    //     dbgs() << "  Is indexed: " << (IsIndexed ? "yes" : "no") << "\n";
-    //     dbgs() << "  Is load: " << (IsLoad ? "yes" : "no") << "\n";
-    //     dbgs() << "  Is store: " << (IsStore ? "yes" : "no") << "\n";
-    //     dbgs() << "  Is store from reg: " << (IsStoreFromReg ? "yes" :
-    //     "no")
-    //            << "\n";
-    //   }
-    //   if (EMCIA->isPush(Inst)) {
-    //     dbgs() << "This is a push instruction with size "
-    //            << EMCIA->getPushSize(Inst) << "\n";
-    //   }
-    //   if (EMCIA->isPop(Inst)) {
-    //     dbgs() << "This is a pop instruction with size "
-    //            << EMCIA->getPopSize(Inst) << "\n";
-    //   }
-    // }
-
-    // dbgs() << "---------------Arith Info----------------\n";
-    // { // arith
-    //   /* MutableArrayRef<MCInst> MAR = {Inst};
-    //   if (MCPB->matchAdd(MCPB->matchAnyOperand(), MCPB->matchAnyOperand())
-    //           ->match(*MCRI, *MCPB, MutableArrayRef<MCInst>(), -1)) {
-    //     dbgs() << "It is an addition instruction.\n";
-    //   } else */
-    //   if (MCInstInfo.isAdd()) {
-    //     dbgs() << "It is an addition from MCInstInfo view but not from
-    //     MCPlus"
-    //               "view.\n";
-    //   }
-    //   if (EMCIA->isSUB(Inst)) {
-    //     dbgs() << "This is a subtraction.\n";
-    //   }
-    // }
-
-    // dbgs() << "-----------------------------------------\n";
-    // dbgs() << "The CFA register is: " << CFAReg << "\n";
-    // dbgs() << "The instruction does " << (ChangedCFA ? "" : "NOT ")
-    //        << "change the CFA.\n";
-    // dbgs() << "The CFI directives does " << (GoingToChangeCFA ? "" : "NOT
-    // ")
-    //        << "change the CFA.\n";
-    // dbgs() << "vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n";
-
-    State = AfterState;
-  }
-
-private:
 };
 
 } // namespace llvm
diff --git a/llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h b/llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h
index 547d132671f45..dd23063555053 100644
--- a/llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h
+++ b/llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h
@@ -46,6 +46,126 @@ class ExtendedMCInstrAnalysis {
   MCPhysReg getStackPointer() const { return MCPB->getStackPointer(); }
   MCPhysReg getFlagsReg() const { return MCPB->getFlagsReg(); }
 
+  bool doesConstantChange(const MCInst &Inst, MCPhysReg Reg, int64_t &HowMuch) {
+    if (isPush(Inst) && Reg == getStackPointer()) {
+      // TODO should get the stack direction here, now it assumes that it goes
+      // down.
+      HowMuch = -getPushSize(Inst);
+      return true;
+    }
+
+    if (isPop(Inst) && Reg == getStackPointer()) {
+      // TODO should get the stack direction here, now it assumes that it goes
+      // down.
+      HowMuch = getPopSize(Inst);
+      return true;
+    }
+
+    return false;
+  }
+
+  // Tries to guess Reg1's value in a form of Reg2 (before Inst's execution) +
+  // Diff.
+  bool isInConstantDistanceOfEachOther(const MCInst &Inst, MCPhysReg &Reg1,
+                                       MCPhysReg Reg2, int &Diff) {
+    {
+      MCPhysReg From;
+      MCPhysReg To;
+      if (isRegToRegMove(Inst, From, To) && From == Reg2) {
+        Reg1 = To;
+        Diff = 0;
+        return true;
+      }
+    }
+
+    return false;
+  }
+
+  bool doStoreFromReg(const MCInst &Inst, MCPhysReg StoringReg,
+                      MCPhysReg FromReg, int64_t &Offset) {
+    if (isPush(Inst) && FromReg == getStackPointer()) {
+      // TODO should get the stack direction here, now it assumes that it goes
+      // down.
+      Offset = -getPushSize(Inst);
+      return true;
+    }
+
+    {
+      bool IsLoad;
+      bool IsStore;
+      bool IsStoreFromReg;
+      MCPhysReg SrcReg;
+      int32_t SrcImm;
+      uint16_t StackPtrReg;
+      int64_t StackOffset;
+      uint8_t Size;
+      bool IsSimple;
+      bool IsIndexed;
+      if (isStackAccess(Inst, IsLoad, IsStore, IsStoreFromReg, SrcReg, SrcImm,
+                        StackPtrReg, StackOffset, Size, IsSimple, IsIndexed)) {
+        // TODO make sure that simple means that it's store and does nothing
+        // more.
+        if (IsStore && IsSimple && StackPtrReg == FromReg && IsStoreFromReg &&
+            SrcReg == StoringReg) {
+          Offset = StackOffset;
+          return true;
+        }
+      }
+    }
+
+    return false;
+  }
+
+  bool doLoadFromReg(const MCInst &Inst, MCPhysReg FromReg, int64_t &Offset,
+                     MCPhysReg &LoadingReg) {
+    if (isPop(Inst) && FromReg == getStackPointer()) {
+      // TODO should get the stack direction here, now it assumes that it goes
+      // down.
+      Offset = 0;
+      LoadingReg = Inst.getOperand(0).getReg();
+      return true;
+    }
+
+    {
+      bool IsLoad;
+      bool IsStore;
+      bool IsStoreFromReg;
+      MCPhysReg SrcReg;
+      int32_t SrcImm;
+      uint16_t StackPtrReg;
+      int64_t StackOffset;
+      uint8_t Size;
+      bool IsSimple;
+      bool IsIndexed;
+      if (isStackAccess(Inst, IsLoad, IsStore, IsStoreFromReg, SrcReg, SrcImm,
+                        StackPtrReg, StackOffset, Size, IsSimple, IsIndexed)) {
+        // TODO make sure that simple means that it's store and does nothing
+        // more.
+        if (IsLoad && IsSimple && StackPtrReg == FromReg) {
+          Offset = StackOffset;
+          LoadingReg = SrcReg;
+          return true;
+        }
+      }
+    }
+
+    {
+      if (isMoveMem2Reg(Inst)) {
+        auto X86MemAccess = evaluateX86MemoryOperand(Inst).value();
+        if (X86MemAccess.BaseRegNum == FromReg &&
+            (X86MemAccess.ScaleImm == 0 || X86MemAccess.IndexRegNum == 0) &&
+            !X86MemAccess.DispExpr) {
+          LoadingReg = Inst.getOperand(0).getReg();
+          Offset = X86MemAccess.DispImm;
+          return true;
+        }
+      }
+    }
+
+    return false;
+  }
+
+private:
   bool isPush(const MCInst &Inst) const { return MCPB->isPush(Inst); }
   int getPushSize(const MCInst &Inst) const { return MCPB->getPushSize(Inst); }
 

>From eb06aa45be6c44e1a4801f4d7d39d4d6c8de4a56 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Wed, 21 May 2025 17:12:04 +0000
Subject: [PATCH 21/58] Remove unused includes

---
 llvm/tools/llvm-mc/CFIState.h | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/llvm/tools/llvm-mc/CFIState.h b/llvm/tools/llvm-mc/CFIState.h
index 1b66d0dd40904..4ffcda3c5063a 100644
--- a/llvm/tools/llvm-mc/CFIState.h
+++ b/llvm/tools/llvm-mc/CFIState.h
@@ -2,11 +2,8 @@
 #define LLVM_TOOLS_LLVM_MC_CFI_STATE_H
 
 #include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/StringRef.h"
 #include "llvm/MC/MCDwarf.h"
-#include "llvm/MC/MCRegister.h"
 #include "llvm/Support/FormatVariadic.h"
-#include "llvm/Support/MathExtras.h"
 #include <cassert>
 #include <cstdint>
 #include <optional>

>From e7c314062fa21d6d040c760948fbb05fe9d2c8a3 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Thu, 22 May 2025 18:40:39 +0000
Subject: [PATCH 22/58] Test cfi validator on following cases: - Changing the
 register and not informing it using cfi directives - Changing the CFA and
 report it wrong - Load a register from another register stored location

---
 .../cfi-validation/single-func-cfa-mistake.s  | 33 +++++++++++++
 .../single-func-missed-cfi-directive.s        | 32 +++++++++++++
 .../llvm-mc/cfi-validation/single-func.s      | 31 ++++++++++++
 .../cfi-validation/spill-two-reg-reversed.s   | 47 +++++++++++++++++++
 .../llvm-mc/cfi-validation/spill-two-reg.s    | 43 +++++++++++++++++
 .../cfi-validation/update-with-no-cfi.s       | 31 ++++++++++++
 6 files changed, 217 insertions(+)
 create mode 100644 llvm/test/tools/llvm-mc/cfi-validation/single-func-cfa-mistake.s
 create mode 100644 llvm/test/tools/llvm-mc/cfi-validation/single-func-missed-cfi-directive.s
 create mode 100644 llvm/test/tools/llvm-mc/cfi-validation/single-func.s
 create mode 100644 llvm/test/tools/llvm-mc/cfi-validation/spill-two-reg-reversed.s
 create mode 100644 llvm/test/tools/llvm-mc/cfi-validation/spill-two-reg.s
 create mode 100644 llvm/test/tools/llvm-mc/cfi-validation/update-with-no-cfi.s

diff --git a/llvm/test/tools/llvm-mc/cfi-validation/single-func-cfa-mistake.s b/llvm/test/tools/llvm-mc/cfi-validation/single-func-cfa-mistake.s
new file mode 100644
index 0000000000000..eb55ff6b378e8
--- /dev/null
+++ b/llvm/test/tools/llvm-mc/cfi-validation/single-func-cfa-mistake.s
@@ -0,0 +1,33 @@
+# RUN: not llvm-mc %s --validate-cfi --filetype=null 2>&1 \
+# RUN:   | FileCheck %s 
+        .text
+        .globl  f
+        .type   f, at function
+f:
+        .cfi_startproc
+
+        .cfi_undefined %rax
+
+        pushq   %rbp
+        # CHECK: error: Expected CFA [reg: 61, offset: 16] but got [reg: 61, offset: 17]
+        .cfi_def_cfa_offset 17
+        .cfi_offset %rbp, -16
+
+        movq    %rsp, %rbp
+        .cfi_def_cfa_register %rbp
+
+        movl    %edi, -4(%rbp)
+
+        movl    -4(%rbp), %eax
+
+        addl    $10, %eax
+
+        popq    %rbp
+        .cfi_def_cfa %rsp, 8
+
+        retq
+
+.Lfunc_end0:
+        .size   f, .Lfunc_end0-f
+
+        .cfi_endproc
diff --git a/llvm/test/tools/llvm-mc/cfi-validation/single-func-missed-cfi-directive.s b/llvm/test/tools/llvm-mc/cfi-validation/single-func-missed-cfi-directive.s
new file mode 100644
index 0000000000000..044c0bbf88eb6
--- /dev/null
+++ b/llvm/test/tools/llvm-mc/cfi-validation/single-func-missed-cfi-directive.s
@@ -0,0 +1,32 @@
+# RUN: not llvm-mc %s --validate-cfi --filetype=null 2>&1 \
+# RUN:   | FileCheck %s 
+        .text
+        .globl  f
+        .type   f, at function
+f:
+        .cfi_startproc
+        
+        .cfi_undefined %rax
+        
+        pushq   %rbp
+        .cfi_def_cfa_offset 16
+        
+        movq    %rsp, %rbp
+        # CHECK: error: Reg#52 caller's value is in reg#52 which is changed by this instruction, but not changed in CFI directives
+        .cfi_def_cfa_register %rbp
+        
+        movl    %edi, -4(%rbp)
+        
+        movl    -4(%rbp), %eax
+        
+        addl    $10, %eax
+        
+        popq    %rbp
+        .cfi_def_cfa %rsp, 8
+        
+        retq
+
+.Lfunc_end0:
+        .size   f, .Lfunc_end0-f
+
+        .cfi_endproc
diff --git a/llvm/test/tools/llvm-mc/cfi-validation/single-func.s b/llvm/test/tools/llvm-mc/cfi-validation/single-func.s
new file mode 100644
index 0000000000000..b2615eafce1d5
--- /dev/null
+++ b/llvm/test/tools/llvm-mc/cfi-validation/single-func.s
@@ -0,0 +1,31 @@
+# RUN: llvm-mc %s --validate-cfi --filetype=null
+        .text
+        .globl  f
+        .type   f, at function
+f:
+        .cfi_startproc
+        
+        .cfi_undefined %rax
+        
+        pushq   %rbp
+        .cfi_def_cfa_offset 16
+        .cfi_offset %rbp, -16
+        
+        movq    %rsp, %rbp
+        .cfi_def_cfa_register %rbp
+        
+        movl    %edi, -4(%rbp)
+        
+        movl    -4(%rbp), %eax
+        
+        addl    $10, %eax
+        
+        popq    %rbp
+        .cfi_def_cfa %rsp, 8
+        
+        retq
+
+.Lfunc_end0:
+        .size   f, .Lfunc_end0-f
+
+        .cfi_endproc
diff --git a/llvm/test/tools/llvm-mc/cfi-validation/spill-two-reg-reversed.s b/llvm/test/tools/llvm-mc/cfi-validation/spill-two-reg-reversed.s
new file mode 100644
index 0000000000000..d7baf3e871e87
--- /dev/null
+++ b/llvm/test/tools/llvm-mc/cfi-validation/spill-two-reg-reversed.s
@@ -0,0 +1,47 @@
+# RUN: not llvm-mc %s --validate-cfi --filetype=null 2>&1 \
+# RUN:   | FileCheck %s 
+        .text
+        .type   _start, at function
+        .globl  _start
+        .hidden _start
+_start:
+        .cfi_startproc
+
+        .cfi_same_value %rdi
+        .cfi_same_value %rsi
+
+        pushq   %rbp
+        .cfi_adjust_cfa_offset 8
+        .cfi_offset %rbp, -16
+
+        movq    %rsp, %rbp
+
+        pushq   %rdi
+        .cfi_adjust_cfa_offset 8
+        .cfi_rel_offset %rdi, 0
+
+        pushq   %rsi
+        .cfi_adjust_cfa_offset 8
+        .cfi_rel_offset %rsi, 0
+        
+        popq    %rsi
+        # CHECK: warning: The reg#55 CFI state is changed
+        .cfi_adjust_cfa_offset -8
+        .cfi_same_value %rdi
+
+        popq    %rdi
+        # CHECK: warning: The reg#60 CFI state is changed
+        # CHECK: Reg#55 caller's value is in reg#55 which is changed by this instruction, but not changed in CFI directives
+        .cfi_adjust_cfa_offset -8
+        .cfi_same_value %rsi
+
+        popq    %rbp
+        .cfi_adjust_cfa_offset -8
+        .cfi_same_value %rbp
+
+        retq
+
+        .cfi_endproc
+.Ltmp0:
+        .size   _start, .Ltmp0-_start
+        .text
diff --git a/llvm/test/tools/llvm-mc/cfi-validation/spill-two-reg.s b/llvm/test/tools/llvm-mc/cfi-validation/spill-two-reg.s
new file mode 100644
index 0000000000000..70ea3b49d8c75
--- /dev/null
+++ b/llvm/test/tools/llvm-mc/cfi-validation/spill-two-reg.s
@@ -0,0 +1,43 @@
+# RUN: llvm-mc %s --validate-cfi --filetype=null
+        .text
+        .type   _start, at function
+        .globl  _start
+        .hidden _start
+_start:
+        .cfi_startproc
+
+        .cfi_same_value %rdi
+        .cfi_same_value %rsi
+
+        pushq   %rbp
+        .cfi_adjust_cfa_offset 8
+        .cfi_offset %rbp, -16
+
+        movq    %rsp, %rbp
+
+        pushq   %rdi
+        .cfi_adjust_cfa_offset 8
+        .cfi_rel_offset %rdi, 0
+
+        pushq   %rsi
+        .cfi_adjust_cfa_offset 8
+        .cfi_rel_offset %rsi, 0
+        
+        popq    %rsi
+        .cfi_adjust_cfa_offset -8
+        .cfi_same_value %rsi
+
+        popq    %rdi
+        .cfi_adjust_cfa_offset -8
+        .cfi_same_value %rdi
+
+        popq    %rbp
+        .cfi_adjust_cfa_offset -8
+        .cfi_same_value %rbp
+
+        retq
+
+        .cfi_endproc
+.Ltmp0:
+        .size   _start, .Ltmp0-_start
+        .text
diff --git a/llvm/test/tools/llvm-mc/cfi-validation/update-with-no-cfi.s b/llvm/test/tools/llvm-mc/cfi-validation/update-with-no-cfi.s
new file mode 100644
index 0000000000000..1384d8a864608
--- /dev/null
+++ b/llvm/test/tools/llvm-mc/cfi-validation/update-with-no-cfi.s
@@ -0,0 +1,31 @@
+# RUN: not llvm-mc %s --validate-cfi --filetype=null 2>&1 \
+# RUN:   | FileCheck %s 
+        .text
+        .globl  f
+        .type   f, at function
+f:
+        .cfi_startproc
+
+        .cfi_same_value %rax
+        .cfi_same_value %rbx
+        .cfi_same_value %rcx
+        .cfi_same_value %rdx
+
+        movq $10, %rax
+        # CHECK: error: Reg#51 caller's value is in reg#51 which is changed by this instruction, but not changed in CFI directives
+
+        movq $10, %rbx
+        # CHECK: error: Reg#53 caller's value is in reg#53 which is changed by this instruction, but not changed in CFI directives
+
+        movq $10, %rcx
+        # CHECK: error: Reg#54 caller's value is in reg#54 which is changed by this instruction, but not changed in CFI directives
+
+        movq $10, %rdx
+        # CHECK: error: Reg#56 caller's value is in reg#56 which is changed by this instruction, but not changed in CFI directives
+
+        retq
+
+.Lfunc_end0:
+        .size   f, .Lfunc_end0-f
+
+        .cfi_endproc

>From 6347ef42e9d4f70b40018da7cc10ae334bbc4a6f Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Thu, 22 May 2025 23:28:16 +0000
Subject: [PATCH 23/58] Prune the CFA diff checker to only check read/write

---
 llvm/tools/llvm-mc/CFIAnalysis.h             | 183 ++++---------------
 llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h | 156 ----------------
 2 files changed, 36 insertions(+), 303 deletions(-)

diff --git a/llvm/tools/llvm-mc/CFIAnalysis.h b/llvm/tools/llvm-mc/CFIAnalysis.h
index 57e2b7247b45f..07f7d1e62b73d 100644
--- a/llvm/tools/llvm-mc/CFIAnalysis.h
+++ b/llvm/tools/llvm-mc/CFIAnalysis.h
@@ -51,18 +51,22 @@ class CFIAnalysis {
   // not consider that a register spilling.
   bool isSuperReg(MCPhysReg Reg) { return MCRI->superregs(Reg).empty(); }
 
-  std::set<MCPhysReg> getAllSuperRegs() {
-    std::set<MCPhysReg> SuperRegs;
+  std::vector<std::pair<MCPhysReg, MCRegisterClass const *>> getAllSuperRegs() {
+    std::map<MCPhysReg, MCRegisterClass const *> SuperRegs;
     for (auto &&RegClass : MCRI->regclasses()) {
       for (unsigned I = 0; I < RegClass.getNumRegs(); I++) {
         MCPhysReg Reg = RegClass.getRegister(I);
         if (!isSuperReg(Reg))
           continue;
-        SuperRegs.insert(Reg);
+        SuperRegs[Reg] = &RegClass;
       }
     }
 
-    return SuperRegs;
+    std::vector<std::pair<MCPhysReg, MCRegisterClass const *>>
+        SuperRegWithClass;
+    for (auto &&[Reg, RegClass] : SuperRegs)
+      SuperRegWithClass.emplace_back(Reg, RegClass);
+    return SuperRegWithClass;
   }
 
   MCPhysReg getSuperReg(MCPhysReg Reg) {
@@ -83,22 +87,28 @@ class CFIAnalysis {
       : Context(Context), MCII(MCII), MCRI(Context.getRegisterInfo()) {
     EMCIA.reset(new ExtendedMCInstrAnalysis(Context, MCII, MCIA));
 
-    // TODO CFA offset should be the slot size, but for now I don't have any
-    // access to it, maybe can be read from the prologue
+    MCPhysReg StackPointer = EMCIA->getStackPointer();
+
     // TODO check what should be passed as EH?
-    State = CFIState(MCRI->getDwarfRegNum(EMCIA->getStackPointer(), false), 8);
-    for (MCPhysReg I : getAllSuperRegs()) {
-      DWARFRegType DwarfI = MCRI->getDwarfRegNum(I, false);
-      State.RegisterCFIStates[DwarfI] = RegisterCFIState::createSameValue();
+    State = CFIState(MCRI->getDwarfRegNum(StackPointer, false), 0);
+    for (auto &&[Reg, RegClass] : getAllSuperRegs()) {
+      if (MCRI->get(Reg).IsArtificial || MCRI->get(Reg).IsConstant)
+        continue;
+
+      if (Reg == StackPointer)
+        State.CFAOffset = RegClass->getSizeInBits() / 8;
+
+      DWARFRegType DwarfReg = MCRI->getDwarfRegNum(Reg, false);
+      State.RegisterCFIStates[DwarfReg] = RegisterCFIState::createSameValue();
     }
 
     // TODO these are temporay added to make things work.
     // Setup the basic information:
     State.RegisterCFIStates[MCRI->getDwarfRegNum(MCRI->getProgramCounter(),
                                                  false)] =
-        RegisterCFIState::createUndefined(); // For now, we don't care about the
-                                             // PC
-    State.RegisterCFIStates[MCRI->getDwarfRegNum(EMCIA->getStackPointer(),
+        RegisterCFIState::createUndefined(); // TODO for now, we don't care
+                                             // about the PC
+    State.RegisterCFIStates[MCRI->getDwarfRegNum(StackPointer,
                                                  false)] =
         RegisterCFIState::createOffsetFromCFAVal(0); // sp's old value is CFA
 
@@ -169,8 +179,6 @@ class CFIAnalysis {
 
     auto &&PrevRefReg =
         PrevState.getReferenceRegisterForCallerValueOfRegister(Reg);
-    auto &&NextRefReg =
-        NextState.getReferenceRegisterForCallerValueOfRegister(Reg);
 
     std::optional<MCPhysReg> PrevRefRegLLVM =
         (PrevRefReg != std::nullopt
@@ -189,64 +197,6 @@ class CFIAnalysis {
     { // try generate
       // Widen
       std::vector<RegisterCFIState> PossibleNextRegStates;
-      { // storing to offset from CFA
-        if (PrevRegState.RetrieveApproach == RegisterCFIState::SameValue ||
-            PrevRegState.RetrieveApproach ==
-                RegisterCFIState::AnotherRegister) {
-          int64_t OffsetFromCFAReg;
-          if (EMCIA->doStoreFromReg(Inst, PrevRefRegLLVM.value(),
-                                    PrevStateCFARegLLVM, OffsetFromCFAReg)) {
-            PossibleNextRegStates.push_back(
-                RegisterCFIState::createOffsetFromCFAAddr(OffsetFromCFAReg -
-                                                          PrevState.CFAOffset));
-          }
-        }
-      }
-
-      { // loading from an offset from CFA
-        if (PrevRegState.RetrieveApproach ==
-            RegisterCFIState::OffsetFromCFAAddr) {
-          int64_t OffsetFromCFAReg;
-          MCPhysReg ToRegLLVM;
-          if (EMCIA->doLoadFromReg(Inst, PrevStateCFARegLLVM, OffsetFromCFAReg,
-                                   ToRegLLVM) &&
-              OffsetFromCFAReg - PrevState.CFAOffset ==
-                  PrevRegState.Info.OffsetFromCFA) {
-            DWARFRegType ToReg = MCRI->getDwarfRegNum(ToRegLLVM, false);
-            if (ToReg == Reg) {
-              PossibleNextRegStates.push_back(
-                  RegisterCFIState::createSameValue());
-            } else {
-              PossibleNextRegStates.push_back(
-                  RegisterCFIState::createAnotherRegister(ToReg));
-            }
-          }
-        }
-      }
-
-      { // moved from reg to other reg
-        if (PrevRegState.RetrieveApproach == RegisterCFIState::SameValue ||
-            PrevRegState.RetrieveApproach ==
-                RegisterCFIState::AnotherRegister) {
-
-          int Diff;
-          MCPhysReg PossibleRegLLVM;
-          if (EMCIA->isInConstantDistanceOfEachOther(
-                  Inst, PossibleRegLLVM, PrevRefRegLLVM.value(), Diff)) {
-            DWARFRegType PossibleReg =
-                MCRI->getDwarfRegNum(PossibleRegLLVM, false);
-            if (Diff == 0) {
-              if (PossibleReg == Reg) {
-                PossibleNextRegStates.push_back(
-                    RegisterCFIState::createSameValue());
-              } else {
-                PossibleNextRegStates.push_back(
-                    RegisterCFIState::createAnotherRegister(PossibleReg));
-              }
-            }
-          }
-        }
-      }
 
       { // stay the same
         bool CanStayTheSame = false;
@@ -342,71 +292,18 @@ class CFIAnalysis {
                     const CFIState &NextState,
                     const std::set<DWARFRegType> &Reads,
                     const std::set<DWARFRegType> &Writes) {
-    MCPhysReg PrevCFAPhysReg =
-        MCRI->getLLVMRegNum(PrevState.CFARegister, false).value();
-    MCPhysReg NextCFAPhysReg =
-        MCRI->getLLVMRegNum(NextState.CFARegister, false).value();
-
-    { // try generate
-      // Widen
-      std::vector<std::pair<DWARFRegType, int>> PossibleNextCFAStates;
-      { // no change
-        if (!Writes.count(PrevState.CFARegister)) {
-          PossibleNextCFAStates.emplace_back(PrevState.CFARegister,
-                                             PrevState.CFAOffset);
-        }
-      }
-
-      { // const change
-        int64_t HowMuch;
-        if (EMCIA->doesConstantChange(Inst, PrevCFAPhysReg, HowMuch)) {
-          PossibleNextCFAStates.emplace_back(PrevState.CFARegister,
-                                             PrevState.CFAOffset - HowMuch);
-        }
-      }
-
-      { // constant distance with each other
-        int Diff;
-        MCPhysReg PossibleNewCFAReg;
-        if (EMCIA->isInConstantDistanceOfEachOther(Inst, PossibleNewCFAReg,
-                                                   PrevCFAPhysReg, Diff)) {
-          PossibleNextCFAStates.emplace_back(
-              MCRI->getDwarfRegNum(PossibleNewCFAReg, false),
-              PrevState.CFAOffset - Diff);
-        }
-      }
-
-      for (auto &&[PossibleNextCFAReg, PossibleNextCFAOffset] :
-           PossibleNextCFAStates) {
-        if (PossibleNextCFAReg != NextState.CFARegister)
-          continue;
-
-        if (PossibleNextCFAOffset == NextState.CFAOffset) {
-          // Everything is ok!
-          return;
-        }
-
-        Context.reportError(Inst.getLoc(),
-                            formatv("Expected CFA [reg: {0}, offset: {1}] but "
-                                    "got [reg: {2}, offset: {3}].",
-                                    NextCFAPhysReg, PossibleNextCFAOffset,
-                                    NextCFAPhysReg, NextState.CFAOffset));
-        return;
-      }
-    }
-
-    // Either couldn't generate, or did, but the programmer wants to change
-    // the source of register for CFA to something not expected by the
-    // generator. So it falls back into read/write checks.
+    const char *PrevCFARegName = MCRI->getName(
+        MCRI->getLLVMRegNum(PrevState.CFARegister, false).value());
 
     if (PrevState.CFARegister == NextState.CFARegister) {
       if (PrevState.CFAOffset == NextState.CFAOffset) {
         if (Writes.count(PrevState.CFARegister)) {
           Context.reportError(
               Inst.getLoc(),
-              formatv("This instruction changes reg#{0}, which is "
-                      "the CFA register, but the CFI directives do not.",
-                      PrevCFAPhysReg));
+              formatv(
+                  "Missing CFI directive for the CFA offset adjustment. CFA "
+                  "register ({0}) is modified by this instruction.",
+                  PrevCFARegName));
           return;
         }
 
@@ -418,25 +315,17 @@ class CFIAnalysis {
       if (!Writes.count(PrevState.CFARegister)) {
         Context.reportError(
             Inst.getLoc(),
-            formatv(
-                "You changed the CFA offset, but there is no modification to "
-                "the CFA register happening in this instruction."));
+            formatv("Wrong adjustment to CFA offset. CFA register ({0}) is not "
+                    "modified by this instruction.",
+                    PrevCFARegName));
       }
 
-      Context.reportWarning(
-          Inst.getLoc(),
-          "I don't know what the instruction did, but it changed the CFA "
-          "reg's "
-          "value, and the offset is changed as well by the CFI directives.");
-      // Everything may be ok!
+      // The CFA register value is changed, and the offset is changed as well,
+      // everything may be ok.
       return;
     }
-    // The CFA register is changed
-    Context.reportWarning(
-        Inst.getLoc(), "The CFA register is changed to something, and I don't "
-                       "have any idea on the new register relevance to CFA. I "
-                       "assume CFA is preserved.");
-    // Everything may be ok!
+
+    // The CFA register is changed, everything may be ok.
   }
 };
 
diff --git a/llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h b/llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h
index dd23063555053..be6aa7d3faa41 100644
--- a/llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h
+++ b/llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h
@@ -12,9 +12,7 @@
 #include "llvm/MC/MCStreamer.h"
 #include "llvm/MC/MCSubtargetInfo.h"
 #include "llvm/MC/TargetRegistry.h"
-#include <cstdint>
 #include <memory>
-#include <optional>
 
 namespace llvm {
 
@@ -45,160 +43,6 @@ class ExtendedMCInstrAnalysis {
 
   MCPhysReg getStackPointer() const { return MCPB->getStackPointer(); }
   MCPhysReg getFlagsReg() const { return MCPB->getFlagsReg(); }
-
-  bool doesConstantChange(const MCInst &Inst, MCPhysReg Reg, int64_t &HowMuch) {
-    if (isPush(Inst) && Reg == getStackPointer()) {
-      // TODO should get the stack direction here, now it assumes that it goes
-      // down.
-      HowMuch = -getPushSize(Inst);
-      return true;
-    }
-
-    if (isPop(Inst) && Reg == getStackPointer()) {
-      // TODO should get the stack direction here, now it assumes that it goes
-      // down.
-      HowMuch = getPopSize(Inst);
-      return true;
-    }
-
-    return false;
-  }
-
-  // Tries to guess Reg1's value in a form of Reg2 (before Inst's execution) +
-  // Diff.
-  bool isInConstantDistanceOfEachOther(const MCInst &Inst, MCPhysReg &Reg1,
-                                       MCPhysReg Reg2, int &Diff) {
-    {
-      MCPhysReg From;
-      MCPhysReg To;
-      if (isRegToRegMove(Inst, From, To) && From == Reg2) {
-        Reg1 = To;
-        Diff = 0;
-        return true;
-      }
-    }
-
-    return false;
-  }
-
-  bool doStoreFromReg(const MCInst &Inst, MCPhysReg StoringReg,
-                      MCPhysReg FromReg, int64_t &Offset) {
-    if (isPush(Inst) && FromReg == getStackPointer()) {
-      // TODO should get the stack direction here, now it assumes that it goes
-      // down.
-      Offset = -getPushSize(Inst);
-      return true;
-    }
-
-    {
-      bool IsLoad;
-      bool IsStore;
-      bool IsStoreFromReg;
-      MCPhysReg SrcReg;
-      int32_t SrcImm;
-      uint16_t StackPtrReg;
-      int64_t StackOffset;
-      uint8_t Size;
-      bool IsSimple;
-      bool IsIndexed;
-      if (isStackAccess(Inst, IsLoad, IsStore, IsStoreFromReg, SrcReg, SrcImm,
-                        StackPtrReg, StackOffset, Size, IsSimple, IsIndexed)) {
-        // TODO make sure that simple means that it's store and does nothing
-        // more.
-        if (IsStore && IsSimple && StackPtrReg == FromReg && IsStoreFromReg &&
-            SrcReg == StoringReg) {
-          Offset = StackOffset;
-          return true;
-        }
-      }
-    }
-
-    return false;
-  }
-
-  bool doLoadFromReg(const MCInst &Inst, MCPhysReg FromReg, int64_t &Offset,
-                     MCPhysReg &LoadingReg) {
-    if (isPop(Inst) && FromReg == getStackPointer()) {
-      // TODO should get the stack direction here, now it assumes that it goes
-      // down.
-      Offset = 0;
-      LoadingReg = Inst.getOperand(0).getReg();
-      return true;
-    }
-
-    {
-      bool IsLoad;
-      bool IsStore;
-      bool IsStoreFromReg;
-      MCPhysReg SrcReg;
-      int32_t SrcImm;
-      uint16_t StackPtrReg;
-      int64_t StackOffset;
-      uint8_t Size;
-      bool IsSimple;
-      bool IsIndexed;
-      if (isStackAccess(Inst, IsLoad, IsStore, IsStoreFromReg, SrcReg, SrcImm,
-                        StackPtrReg, StackOffset, Size, IsSimple, IsIndexed)) {
-        // TODO make sure that simple means that it's store and does nothing
-        // more.
-        if (IsLoad && IsSimple && StackPtrReg == FromReg) {
-          Offset = StackOffset;
-          LoadingReg = SrcReg;
-          return true;
-        }
-      }
-    }
-
-    {
-      if (isMoveMem2Reg(Inst)) {
-        auto X86MemAccess = evaluateX86MemoryOperand(Inst).value();
-        if (X86MemAccess.BaseRegNum == FromReg &&
-            (X86MemAccess.ScaleImm == 0 || X86MemAccess.IndexRegNum == 0) &&
-            !X86MemAccess.DispExpr) {
-          LoadingReg = Inst.getOperand(0).getReg();
-          Offset = X86MemAccess.DispImm;
-          return true;
-        }
-      }
-    }
-
-    return false;
-  }
-
-private:
-  bool isPush(const MCInst &Inst) const { return MCPB->isPush(Inst); }
-  int getPushSize(const MCInst &Inst) const { return MCPB->getPushSize(Inst); }
-
-  bool isPop(const MCInst &Inst) const { return MCPB->isPop(Inst); }
-  int getPopSize(const MCInst &Inst) const { return MCPB->getPopSize(Inst); }
-
-  bool isRegToRegMove(const MCInst &Inst, MCPhysReg &From,
-                      MCPhysReg &To) const {
-    return MCPB->isRegToRegMove(Inst, From, To);
-  }
-  bool isConditionalMove(const MCInst &Inst) const {
-    return MCPB->isConditionalMove(Inst);
-  }
-  bool isMoveMem2Reg(const MCInst &Inst) const {
-    return MCPB->isMoveMem2Reg(Inst);
-  }
-  bool isSUB(const MCInst &Inst) const { return MCPB->isSUB(Inst); }
-
-  int getMemoryOperandNo(const MCInst &Inst) const {
-    return MCPB->getMemoryOperandNo(Inst);
-  }
-  std::optional<bolt::MCPlusBuilder::X86MemOperand>
-  evaluateX86MemoryOperand(const MCInst &Inst) const {
-    return MCPB->evaluateX86MemoryOperand(Inst);
-  }
-  bool isStackAccess(const MCInst &Inst, bool &IsLoad, bool &IsStore,
-                     bool &IsStoreFromReg, MCPhysReg &Reg, int32_t &SrcImm,
-                     uint16_t &StackPtrReg, int64_t &StackOffset, uint8_t &Size,
-                     bool &IsSimple, bool &IsIndexed) const {
-    return MCPB->isStackAccess(Inst, IsLoad, IsStore, IsStoreFromReg, Reg,
-                               SrcImm, StackPtrReg, StackOffset, Size, IsSimple,
-                               IsIndexed);
-  }
 };
 
 } // namespace llvm

>From 453917b195481ee9124169913834e535f54363c0 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Fri, 23 May 2025 22:11:21 +0000
Subject: [PATCH 24/58] Move the CFI analysis headers to MC

---
 .../llvm/MC/MCCFIAnalysis}/CFIAnalysis.h      |   2 -
 .../MC/MCCFIAnalysis}/CFIAnalysisMCStreamer.h |   0
 llvm/include/llvm/MC/MCCFIAnalysis/CFIState.h |  63 +++++
 .../MCCFIAnalysis/ExtendedMCInstrAnalysis.h   |  28 +++
 llvm/lib/MC/CFIAnalysis/CFIState.cpp          | 195 ++++++++++++++++
 llvm/lib/MC/CFIAnalysis/CMakeLists.txt        |  10 +
 llvm/lib/MC/CMakeLists.txt                    |   1 +
 llvm/tools/llvm-mc/CFIState.h                 | 220 ------------------
 llvm/tools/llvm-mc/CMakeLists.txt             |   3 +-
 llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h  |  50 ----
 llvm/tools/llvm-mc/llvm-mc.cpp                |   2 +-
 11 files changed, 299 insertions(+), 275 deletions(-)
 rename llvm/{tools/llvm-mc => include/llvm/MC/MCCFIAnalysis}/CFIAnalysis.h (99%)
 rename llvm/{tools/llvm-mc => include/llvm/MC/MCCFIAnalysis}/CFIAnalysisMCStreamer.h (100%)
 create mode 100644 llvm/include/llvm/MC/MCCFIAnalysis/CFIState.h
 create mode 100644 llvm/include/llvm/MC/MCCFIAnalysis/ExtendedMCInstrAnalysis.h
 create mode 100644 llvm/lib/MC/CFIAnalysis/CFIState.cpp
 create mode 100644 llvm/lib/MC/CFIAnalysis/CMakeLists.txt
 delete mode 100644 llvm/tools/llvm-mc/CFIState.h
 delete mode 100644 llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h

diff --git a/llvm/tools/llvm-mc/CFIAnalysis.h b/llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysis.h
similarity index 99%
rename from llvm/tools/llvm-mc/CFIAnalysis.h
rename to llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysis.h
index 07f7d1e62b73d..14c054b1cad3d 100644
--- a/llvm/tools/llvm-mc/CFIAnalysis.h
+++ b/llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysis.h
@@ -3,7 +3,6 @@
 
 #include "CFIState.h"
 #include "ExtendedMCInstrAnalysis.h"
-#include "bolt/Core/MCPlusBuilder.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringExtras.h"
@@ -21,7 +20,6 @@
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/FormatVariadic.h"
-#include <cstdint>
 #include <memory>
 #include <optional>
 #include <set>
diff --git a/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h b/llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysisMCStreamer.h
similarity index 100%
rename from llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h
rename to llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysisMCStreamer.h
diff --git a/llvm/include/llvm/MC/MCCFIAnalysis/CFIState.h b/llvm/include/llvm/MC/MCCFIAnalysis/CFIState.h
new file mode 100644
index 0000000000000..6ddd4916b5315
--- /dev/null
+++ b/llvm/include/llvm/MC/MCCFIAnalysis/CFIState.h
@@ -0,0 +1,63 @@
+#ifndef LLVM_TOOLS_LLVM_MC_CFI_STATE_H
+#define LLVM_TOOLS_LLVM_MC_CFI_STATE_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/MC/MCDwarf.h"
+#include "llvm/Support/FormatVariadic.h"
+#include <cassert>
+#include <cstdint>
+#include <optional>
+#include <string>
+namespace llvm {
+
+using DWARFRegType = int64_t;
+
+struct RegisterCFIState {
+  enum Approach {
+    Undefined,
+    SameValue,
+    AnotherRegister,
+    OffsetFromCFAAddr,
+    OffsetFromCFAVal,
+    Other,
+  } RetrieveApproach;
+
+  union {
+    int OffsetFromCFA;
+    DWARFRegType Register;
+  } Info;
+
+  // TODO change it to be like other dump methods
+  std::string dump();
+
+  bool operator==(const RegisterCFIState &OtherState) const;
+  bool operator!=(const RegisterCFIState &OtherState) const;
+
+  static RegisterCFIState createUndefined();
+  static RegisterCFIState createSameValue();
+  static RegisterCFIState createAnotherRegister(DWARFRegType Register);
+  static RegisterCFIState createOffsetFromCFAAddr(int OffsetFromCFA);
+  static RegisterCFIState createOffsetFromCFAVal(int OffsetFromCFA);
+  static RegisterCFIState createOther();
+};
+
+struct CFIState {
+  DenseMap<DWARFRegType, RegisterCFIState> RegisterCFIStates;
+  DWARFRegType CFARegister;
+  int CFAOffset;
+
+  CFIState();
+  CFIState(const CFIState &Other);
+
+  CFIState &operator=(const CFIState &Other);
+
+  CFIState(DWARFRegType CFARegister, int CFIOffset);
+
+  std::optional<DWARFRegType>
+  getReferenceRegisterForCallerValueOfRegister(DWARFRegType Reg) const;
+
+  bool apply(const MCCFIInstruction &CFIDirective);
+};
+} // namespace llvm
+
+#endif
\ No newline at end of file
diff --git a/llvm/include/llvm/MC/MCCFIAnalysis/ExtendedMCInstrAnalysis.h b/llvm/include/llvm/MC/MCCFIAnalysis/ExtendedMCInstrAnalysis.h
new file mode 100644
index 0000000000000..6d050a4defbcc
--- /dev/null
+++ b/llvm/include/llvm/MC/MCCFIAnalysis/ExtendedMCInstrAnalysis.h
@@ -0,0 +1,28 @@
+#ifndef LLVM_TOOLS_LLVM_MC_EXTENDED_MC_INSTR_ANALYSIS_H
+#define LLVM_TOOLS_LLVM_MC_EXTENDED_MC_INSTR_ANALYSIS_H
+
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDwarf.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCRegister.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/TargetRegistry.h"
+
+namespace llvm {
+
+class ExtendedMCInstrAnalysis {
+private:
+public:
+  ExtendedMCInstrAnalysis(MCContext &Context, MCInstrInfo const &MCII,
+                          MCInstrAnalysis *MCIA) {}
+
+  /// Extra semantic information needed from MC layer:
+
+  MCPhysReg getStackPointer() const { return 61; }
+  MCPhysReg getFlagsReg() const { return 57; }
+};
+
+} // namespace llvm
+
+#endif
\ No newline at end of file
diff --git a/llvm/lib/MC/CFIAnalysis/CFIState.cpp b/llvm/lib/MC/CFIAnalysis/CFIState.cpp
new file mode 100644
index 0000000000000..8a5efe31a2826
--- /dev/null
+++ b/llvm/lib/MC/CFIAnalysis/CFIState.cpp
@@ -0,0 +1,195 @@
+#include "llvm/MC/MCCFIAnalysis/CFIState.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/MC/MCDwarf.h"
+#include "llvm/Support/FormatVariadic.h"
+#include <cassert>
+#include <cstdint>
+#include <optional>
+#include <string>
+
+using namespace llvm;
+
+using DWARFRegType = int64_t;
+
+std::string RegisterCFIState::dump() {
+  switch (RetrieveApproach) {
+  case Undefined:
+    return "undefined";
+  case SameValue:
+    return "same value";
+  case AnotherRegister:
+    return formatv("stored in another register, which is reg#{0}",
+                   Info.Register);
+  case OffsetFromCFAAddr:
+    return formatv("offset {0} from CFA", Info.OffsetFromCFA);
+  case OffsetFromCFAVal:
+    return formatv("CFA value + {0}", Info.OffsetFromCFA);
+  case Other:
+    return "other";
+  }
+}
+
+bool RegisterCFIState::operator==(const RegisterCFIState &OtherState) const {
+  if (RetrieveApproach != OtherState.RetrieveApproach)
+    return false;
+
+  switch (RetrieveApproach) {
+  case Undefined:
+  case SameValue:
+  case Other:
+    return true;
+  case AnotherRegister:
+    return Info.Register == OtherState.Info.Register;
+  case OffsetFromCFAAddr:
+  case OffsetFromCFAVal:
+    return Info.OffsetFromCFA == OtherState.Info.OffsetFromCFA;
+  }
+}
+
+bool RegisterCFIState::operator!=(const RegisterCFIState &OtherState) const {
+  return !(*this == OtherState);
+}
+
+RegisterCFIState RegisterCFIState::createUndefined() {
+  RegisterCFIState State;
+  State.RetrieveApproach = Undefined;
+
+  return State;
+}
+
+RegisterCFIState RegisterCFIState::createSameValue() {
+  RegisterCFIState State;
+  State.RetrieveApproach = SameValue;
+
+  return State;
+}
+
+RegisterCFIState
+RegisterCFIState::createAnotherRegister(DWARFRegType Register) {
+  RegisterCFIState State;
+  State.RetrieveApproach = AnotherRegister;
+  State.Info.Register = Register;
+
+  return State;
+}
+
+RegisterCFIState RegisterCFIState::createOffsetFromCFAAddr(int OffsetFromCFA) {
+  RegisterCFIState State;
+  State.RetrieveApproach = OffsetFromCFAAddr;
+  State.Info.OffsetFromCFA = OffsetFromCFA;
+
+  return State;
+}
+
+RegisterCFIState RegisterCFIState::createOffsetFromCFAVal(int OffsetFromCFA) {
+  RegisterCFIState State;
+  State.RetrieveApproach = OffsetFromCFAVal;
+  State.Info.OffsetFromCFA = OffsetFromCFA;
+
+  return State;
+}
+
+RegisterCFIState RegisterCFIState::createOther() {
+  RegisterCFIState State;
+  State.RetrieveApproach = Other;
+
+  return State;
+}
+
+CFIState::CFIState() : CFARegister(-1), CFAOffset(-1) {}
+
+CFIState::CFIState(const CFIState &Other) {
+  CFARegister = Other.CFARegister;
+  CFAOffset = Other.CFAOffset;
+  RegisterCFIStates = Other.RegisterCFIStates;
+}
+
+CFIState &CFIState::operator=(const CFIState &Other) {
+  if (this != &Other) {
+    CFARegister = Other.CFARegister;
+    CFAOffset = Other.CFAOffset;
+    RegisterCFIStates = Other.RegisterCFIStates;
+  }
+
+  return *this;
+}
+
+CFIState::CFIState(DWARFRegType CFARegister, int CFIOffset)
+    : CFARegister(CFARegister), CFAOffset(CFIOffset) {}
+
+std::optional<DWARFRegType>
+CFIState::getReferenceRegisterForCallerValueOfRegister(DWARFRegType Reg) const {
+  assert(RegisterCFIStates.count(Reg) &&
+         "The register should be tracked inside the register states");
+  auto &&RegState = RegisterCFIStates.at(Reg);
+  switch (RegState.RetrieveApproach) {
+  case RegisterCFIState::Undefined:
+  case RegisterCFIState::Other:
+    return std::nullopt;
+  case RegisterCFIState::SameValue:
+    return Reg;
+  case RegisterCFIState::AnotherRegister:
+    return RegState.Info.Register;
+  case RegisterCFIState::OffsetFromCFAAddr:
+  case RegisterCFIState::OffsetFromCFAVal:
+    return CFARegister;
+  }
+}
+
+bool CFIState::apply(const MCCFIInstruction &CFIDirective) {
+  switch (CFIDirective.getOperation()) {
+  case MCCFIInstruction::OpDefCfaRegister:
+    CFARegister = CFIDirective.getRegister();
+    break;
+  case MCCFIInstruction::OpDefCfaOffset:
+    CFAOffset = CFIDirective.getOffset();
+    break;
+  case MCCFIInstruction::OpAdjustCfaOffset:
+    CFAOffset += CFIDirective.getOffset();
+    break;
+  case MCCFIInstruction::OpDefCfa:
+    CFARegister = CFIDirective.getRegister();
+    CFAOffset = CFIDirective.getOffset();
+    break;
+  case MCCFIInstruction::OpOffset:
+    RegisterCFIStates[CFIDirective.getRegister()] =
+        RegisterCFIState::createOffsetFromCFAAddr(CFIDirective.getOffset());
+    break;
+  case MCCFIInstruction::OpRegister:
+    RegisterCFIStates[CFIDirective.getRegister()] =
+        RegisterCFIState::createAnotherRegister(CFIDirective.getRegister2());
+    break;
+  case MCCFIInstruction::OpRelOffset:
+    RegisterCFIStates[CFIDirective.getRegister()] =
+        RegisterCFIState::createOffsetFromCFAAddr(CFIDirective.getOffset() -
+                                                  CFAOffset);
+    break;
+  case MCCFIInstruction::OpUndefined:
+    RegisterCFIStates[CFIDirective.getRegister()] =
+        RegisterCFIState::createUndefined();
+    break;
+  case MCCFIInstruction::OpSameValue:
+    RegisterCFIStates[CFIDirective.getRegister()] =
+        RegisterCFIState::createSameValue();
+    break;
+  case MCCFIInstruction::OpValOffset:
+    RegisterCFIStates[CFIDirective.getRegister()] =
+        RegisterCFIState::createOffsetFromCFAVal(CFIDirective.getOffset());
+    break;
+  case MCCFIInstruction::OpRestoreState:
+  case MCCFIInstruction::OpRememberState:
+  case MCCFIInstruction::OpLLVMDefAspaceCfa:
+  case MCCFIInstruction::OpRestore:
+  case MCCFIInstruction::OpEscape:
+  case MCCFIInstruction::OpWindowSave:
+  case MCCFIInstruction::OpNegateRAState:
+  case MCCFIInstruction::OpNegateRAStateWithPC:
+  case MCCFIInstruction::OpGnuArgsSize:
+  case MCCFIInstruction::OpLabel:
+    // These instructions are not supported.
+    return false;
+    break;
+  }
+
+  return true;
+}
diff --git a/llvm/lib/MC/CFIAnalysis/CMakeLists.txt b/llvm/lib/MC/CFIAnalysis/CMakeLists.txt
new file mode 100644
index 0000000000000..0bc829c754092
--- /dev/null
+++ b/llvm/lib/MC/CFIAnalysis/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_llvm_component_library(LLVMMCCFIAnalysis
+  CFIState.cpp
+  # CFIAnalysisMCStreamer.cpp
+  # CFIAnalysis.cpp
+  # ExtendedMCInstrAnalysis.cpp
+
+  LINK_COMPONENTS
+  MC
+  Support
+  )
diff --git a/llvm/lib/MC/CMakeLists.txt b/llvm/lib/MC/CMakeLists.txt
index f49f14c848b90..8f8637bd8580b 100644
--- a/llvm/lib/MC/CMakeLists.txt
+++ b/llvm/lib/MC/CMakeLists.txt
@@ -87,3 +87,4 @@ add_llvm_component_library(LLVMMC
 
 add_subdirectory(MCParser)
 add_subdirectory(MCDisassembler)
+add_subdirectory(CFIAnalysis)
diff --git a/llvm/tools/llvm-mc/CFIState.h b/llvm/tools/llvm-mc/CFIState.h
deleted file mode 100644
index 4ffcda3c5063a..0000000000000
--- a/llvm/tools/llvm-mc/CFIState.h
+++ /dev/null
@@ -1,220 +0,0 @@
-#ifndef LLVM_TOOLS_LLVM_MC_CFI_STATE_H
-#define LLVM_TOOLS_LLVM_MC_CFI_STATE_H
-
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/MC/MCDwarf.h"
-#include "llvm/Support/FormatVariadic.h"
-#include <cassert>
-#include <cstdint>
-#include <optional>
-#include <string>
-namespace llvm {
-
-using DWARFRegType = int64_t;
-
-struct RegisterCFIState {
-  enum Approach {
-    Undefined,
-    SameValue,
-    AnotherRegister,
-    OffsetFromCFAAddr,
-    OffsetFromCFAVal,
-    Other,
-  } RetrieveApproach;
-
-  // TODO use a correct type for this.
-  union {
-    int OffsetFromCFA;
-    DWARFRegType Register;
-  } Info;
-
-  std::string dump() {
-    switch (RetrieveApproach) {
-    case Undefined:
-      return "undefined";
-    case SameValue:
-      return "same value";
-    case AnotherRegister:
-      return formatv("stored in another register, which is reg#{0}",
-                     Info.Register);
-    case OffsetFromCFAAddr:
-      return formatv("offset {0} from CFA", Info.OffsetFromCFA);
-    case OffsetFromCFAVal:
-      return formatv("CFA value + {0}", Info.OffsetFromCFA);
-    case Other:
-      return "other";
-    }
-  }
-
-  bool operator==(const RegisterCFIState &OtherState) const {
-    if (RetrieveApproach != OtherState.RetrieveApproach)
-      return false;
-
-    switch (RetrieveApproach) {
-    case Undefined:
-    case SameValue:
-    case Other:
-      return true;
-    case AnotherRegister:
-      return Info.Register == OtherState.Info.Register;
-    case OffsetFromCFAAddr:
-    case OffsetFromCFAVal:
-      return Info.OffsetFromCFA == OtherState.Info.OffsetFromCFA;
-    }
-  }
-
-  bool operator!=(const RegisterCFIState &OtherState) const {
-    return !(*this == OtherState);
-  }
-
-  static RegisterCFIState createUndefined() {
-    RegisterCFIState State;
-    State.RetrieveApproach = Undefined;
-
-    return State;
-  }
-
-  static RegisterCFIState createSameValue() {
-    RegisterCFIState State;
-    State.RetrieveApproach = SameValue;
-
-    return State;
-  }
-
-  static RegisterCFIState createAnotherRegister(DWARFRegType Register) {
-    RegisterCFIState State;
-    State.RetrieveApproach = AnotherRegister;
-    State.Info.Register = Register;
-
-    return State;
-  }
-
-  static RegisterCFIState createOffsetFromCFAAddr(int OffsetFromCFA) {
-    RegisterCFIState State;
-    State.RetrieveApproach = OffsetFromCFAAddr;
-    State.Info.OffsetFromCFA = OffsetFromCFA;
-
-    return State;
-  }
-
-  static RegisterCFIState createOffsetFromCFAVal(int OffsetFromCFA) {
-    RegisterCFIState State;
-    State.RetrieveApproach = OffsetFromCFAVal;
-    State.Info.OffsetFromCFA = OffsetFromCFA;
-
-    return State;
-  }
-
-  static RegisterCFIState createOther() {
-    RegisterCFIState State;
-    State.RetrieveApproach = Other;
-
-    return State;
-  }
-};
-struct CFIState {
-  DenseMap<DWARFRegType, RegisterCFIState> RegisterCFIStates;
-  DWARFRegType CFARegister;
-  int CFAOffset;
-
-  CFIState() : CFARegister(-1), CFAOffset(-1) {}
-
-  CFIState(const CFIState &Other) {
-    CFARegister = Other.CFARegister;
-    CFAOffset = Other.CFAOffset;
-    RegisterCFIStates = Other.RegisterCFIStates;
-  }
-
-  CFIState &operator=(const CFIState &Other) {
-    if (this != &Other) {
-      CFARegister = Other.CFARegister;
-      CFAOffset = Other.CFAOffset;
-      RegisterCFIStates = Other.RegisterCFIStates;
-    }
-
-    return *this;
-  }
-
-  CFIState(DWARFRegType CFARegister, int CFIOffset)
-      : CFARegister(CFARegister), CFAOffset(CFIOffset) {}
-
-  std::optional<DWARFRegType>
-  getReferenceRegisterForCallerValueOfRegister(DWARFRegType Reg) const {
-    assert(RegisterCFIStates.count(Reg) &&
-           "The register should be tracked inside the register states");
-    auto &&RegState = RegisterCFIStates.at(Reg);
-    switch (RegState.RetrieveApproach) {
-    case RegisterCFIState::Undefined:
-    case RegisterCFIState::Other:
-      return std::nullopt;
-    case RegisterCFIState::SameValue:
-      return Reg;
-    case RegisterCFIState::AnotherRegister:
-      return RegState.Info.Register;
-    case RegisterCFIState::OffsetFromCFAAddr:
-    case RegisterCFIState::OffsetFromCFAVal:
-      return CFARegister;
-    }
-  }
-
-  bool apply(const MCCFIInstruction &CFIDirective) {
-    switch (CFIDirective.getOperation()) {
-    case MCCFIInstruction::OpDefCfaRegister:
-      CFARegister = CFIDirective.getRegister();
-      break;
-    case MCCFIInstruction::OpDefCfaOffset:
-      CFAOffset = CFIDirective.getOffset();
-      break;
-    case MCCFIInstruction::OpAdjustCfaOffset:
-      CFAOffset += CFIDirective.getOffset();
-      break;
-    case MCCFIInstruction::OpDefCfa:
-      CFARegister = CFIDirective.getRegister();
-      CFAOffset = CFIDirective.getOffset();
-      break;
-    case MCCFIInstruction::OpOffset:
-      RegisterCFIStates[CFIDirective.getRegister()] =
-          RegisterCFIState::createOffsetFromCFAAddr(CFIDirective.getOffset());
-      break;
-    case MCCFIInstruction::OpRegister:
-      RegisterCFIStates[CFIDirective.getRegister()] =
-          RegisterCFIState::createAnotherRegister(CFIDirective.getRegister2());
-      break;
-    case MCCFIInstruction::OpRelOffset:
-      RegisterCFIStates[CFIDirective.getRegister()] =
-          RegisterCFIState::createOffsetFromCFAAddr(CFIDirective.getOffset() -
-                                                    CFAOffset);
-      break;
-    case MCCFIInstruction::OpUndefined:
-      RegisterCFIStates[CFIDirective.getRegister()] =
-          RegisterCFIState::createUndefined();
-      break;
-    case MCCFIInstruction::OpSameValue:
-      RegisterCFIStates[CFIDirective.getRegister()] =
-          RegisterCFIState::createSameValue();
-      break;
-    case MCCFIInstruction::OpValOffset:
-      RegisterCFIStates[CFIDirective.getRegister()] =
-          RegisterCFIState::createOffsetFromCFAVal(CFIDirective.getOffset());
-      break;
-    case MCCFIInstruction::OpRestoreState:
-    case MCCFIInstruction::OpRememberState:
-    case MCCFIInstruction::OpLLVMDefAspaceCfa:
-    case MCCFIInstruction::OpRestore:
-    case MCCFIInstruction::OpEscape:
-    case MCCFIInstruction::OpWindowSave:
-    case MCCFIInstruction::OpNegateRAState:
-    case MCCFIInstruction::OpNegateRAStateWithPC:
-    case MCCFIInstruction::OpGnuArgsSize:
-    case MCCFIInstruction::OpLabel:
-      // These instructions are not supported.
-      return false;
-      break;
-    }
-
-    return true;
-  }
-};
-} // namespace llvm
-
-#endif
\ No newline at end of file
diff --git a/llvm/tools/llvm-mc/CMakeLists.txt b/llvm/tools/llvm-mc/CMakeLists.txt
index 368f29c62201f..83c40d1cd2122 100644
--- a/llvm/tools/llvm-mc/CMakeLists.txt
+++ b/llvm/tools/llvm-mc/CMakeLists.txt
@@ -4,6 +4,7 @@ set(LLVM_LINK_COMPONENTS
   AllTargetsDisassemblers
   AllTargetsInfos
   MC
+  MCCFIAnalysis
   MCParser
   Support
   TargetParser
@@ -14,5 +15,3 @@ add_llvm_tool(llvm-mc
   Disassembler.cpp
   )
 
-target_link_libraries(llvm-mc PRIVATE LLVMBOLTCore LLVMBOLTTargetX86)
-target_include_directories(llvm-mc PRIVATE "${LLVM_MAIN_SRC_DIR}/../bolt/include")
diff --git a/llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h b/llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h
deleted file mode 100644
index be6aa7d3faa41..0000000000000
--- a/llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h
+++ /dev/null
@@ -1,50 +0,0 @@
-#ifndef LLVM_TOOLS_LLVM_MC_EXTENDED_MC_INSTR_ANALYSIS_H
-#define LLVM_TOOLS_LLVM_MC_EXTENDED_MC_INSTR_ANALYSIS_H
-
-#include "bolt/Core/MCPlusBuilder.h"
-#include "llvm/MC/MCContext.h"
-#include "llvm/MC/MCDwarf.h"
-#include "llvm/MC/MCExpr.h"
-#include "llvm/MC/MCInst.h"
-#include "llvm/MC/MCInstrInfo.h"
-#include "llvm/MC/MCRegister.h"
-#include "llvm/MC/MCRegisterInfo.h"
-#include "llvm/MC/MCStreamer.h"
-#include "llvm/MC/MCSubtargetInfo.h"
-#include "llvm/MC/TargetRegistry.h"
-#include <memory>
-
-namespace llvm {
-
-class ExtendedMCInstrAnalysis {
-private:
-  std::unique_ptr<bolt::MCPlusBuilder> MCPB;
-
-  static bolt::MCPlusBuilder *
-  createMCPlusBuilder(const Triple::ArchType Arch,
-                      const MCInstrAnalysis *Analysis, const MCInstrInfo *Info,
-                      const MCRegisterInfo *RegInfo,
-                      const MCSubtargetInfo *STI) {
-    if (Arch == Triple::x86_64)
-      return bolt::createX86MCPlusBuilder(Analysis, Info, RegInfo, STI);
-
-    llvm_unreachable("architecture unsupported by ExtendedMCInstrAnalysis");
-  }
-
-public:
-  ExtendedMCInstrAnalysis(MCContext &Context, MCInstrInfo const &MCII,
-                          MCInstrAnalysis *MCIA) {
-    MCPB.reset(createMCPlusBuilder(Context.getTargetTriple().getArch(), MCIA,
-                                   &MCII, Context.getRegisterInfo(),
-                                   Context.getSubtargetInfo()));
-  }
-
-  /// Extra semantic information needed from MC layer:
-
-  MCPhysReg getStackPointer() const { return MCPB->getStackPointer(); }
-  MCPhysReg getFlagsReg() const { return MCPB->getFlagsReg(); }
-};
-
-} // namespace llvm
-
-#endif
\ No newline at end of file
diff --git a/llvm/tools/llvm-mc/llvm-mc.cpp b/llvm/tools/llvm-mc/llvm-mc.cpp
index ca4f71cb9cabd..2f1d6cb42aa0b 100644
--- a/llvm/tools/llvm-mc/llvm-mc.cpp
+++ b/llvm/tools/llvm-mc/llvm-mc.cpp
@@ -11,10 +11,10 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "CFIAnalysisMCStreamer.h"
 #include "Disassembler.h"
 #include "llvm/MC/MCAsmBackend.h"
 #include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCCFIAnalysis/CFIAnalysisMCStreamer.h"
 #include "llvm/MC/MCCodeEmitter.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCInstPrinter.h"

>From 9f8bca8b87462d09e9f970ff6019b7c201f348e6 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Tue, 27 May 2025 17:51:21 +0000
Subject: [PATCH 25/58] Move all the CFI analysis implementations to lib

---
 .../llvm/MC/MCCFIAnalysis/CFIAnalysis.h       | 279 +---------------
 .../MC/MCCFIAnalysis/CFIAnalysisMCStreamer.h  | 119 +------
 llvm/include/llvm/MC/MCCFIAnalysis/CFIState.h |   3 -
 llvm/lib/MC/CFIAnalysis/CFIAnalysis.cpp       | 310 ++++++++++++++++++
 .../MC/CFIAnalysis/CFIAnalysisMCStreamer.cpp  | 131 ++++++++
 llvm/lib/MC/CFIAnalysis/CFIState.cpp          |   1 +
 llvm/lib/MC/CFIAnalysis/CMakeLists.txt        |   5 +-
 7 files changed, 469 insertions(+), 379 deletions(-)
 create mode 100644 llvm/lib/MC/CFIAnalysis/CFIAnalysis.cpp
 create mode 100644 llvm/lib/MC/CFIAnalysis/CFIAnalysisMCStreamer.cpp

diff --git a/llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysis.h b/llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysis.h
index 14c054b1cad3d..8c70764cdde2d 100644
--- a/llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysis.h
+++ b/llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysis.h
@@ -5,8 +5,6 @@
 #include "ExtendedMCInstrAnalysis.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/ADT/Twine.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCDwarf.h"
 #include "llvm/MC/MCExpr.h"
@@ -17,21 +15,11 @@
 #include "llvm/MC/MCStreamer.h"
 #include "llvm/MC/MCSubtargetInfo.h"
 #include "llvm/MC/TargetRegistry.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/FormatVariadic.h"
 #include <memory>
-#include <optional>
 #include <set>
 
 namespace llvm {
 
-// TODO remove it, it's just for debug purposes.
-void printUntilNextLine(const char *Str) {
-  for (int I = 0; Str[I] != '\0' && Str[I] != '\n'; I++)
-    dbgs() << Str[I];
-}
-
 class CFIAnalysis {
   MCContext &Context;
   MCInstrInfo const &MCII;
@@ -47,119 +35,18 @@ class CFIAnalysis {
   // register.
   // As en example, if you spill a sub register to stack, the CFI analysis does
   // not consider that a register spilling.
-  bool isSuperReg(MCPhysReg Reg) { return MCRI->superregs(Reg).empty(); }
-
-  std::vector<std::pair<MCPhysReg, MCRegisterClass const *>> getAllSuperRegs() {
-    std::map<MCPhysReg, MCRegisterClass const *> SuperRegs;
-    for (auto &&RegClass : MCRI->regclasses()) {
-      for (unsigned I = 0; I < RegClass.getNumRegs(); I++) {
-        MCPhysReg Reg = RegClass.getRegister(I);
-        if (!isSuperReg(Reg))
-          continue;
-        SuperRegs[Reg] = &RegClass;
-      }
-    }
-
-    std::vector<std::pair<MCPhysReg, MCRegisterClass const *>>
-        SuperRegWithClass;
-    for (auto &&[Reg, RegClass] : SuperRegs)
-      SuperRegWithClass.emplace_back(Reg, RegClass);
-    return SuperRegWithClass;
-  }
+  bool isSuperReg(MCPhysReg Reg);
 
-  MCPhysReg getSuperReg(MCPhysReg Reg) {
-    if (isSuperReg(Reg))
-      return Reg;
-    for (auto SuperReg : MCRI->superregs(Reg)) {
-      if (isSuperReg(SuperReg))
-        return SuperReg;
-    }
+  SmallVector<std::pair<MCPhysReg, MCRegisterClass const *>> getAllSuperRegs();
 
-    llvm_unreachable("Should either be a super reg, or have a super reg");
-  }
+  MCPhysReg getSuperReg(MCPhysReg Reg);
 
 public:
   CFIAnalysis(MCContext &Context, MCInstrInfo const &MCII,
               MCInstrAnalysis *MCIA,
-              ArrayRef<MCCFIInstruction> PrologueCFIDirectives)
-      : Context(Context), MCII(MCII), MCRI(Context.getRegisterInfo()) {
-    EMCIA.reset(new ExtendedMCInstrAnalysis(Context, MCII, MCIA));
-
-    MCPhysReg StackPointer = EMCIA->getStackPointer();
-
-    // TODO check what should be passed as EH?
-    State = CFIState(MCRI->getDwarfRegNum(StackPointer, false), 0);
-    for (auto &&[Reg, RegClass] : getAllSuperRegs()) {
-      if (MCRI->get(Reg).IsArtificial || MCRI->get(Reg).IsConstant)
-        continue;
-
-      if (Reg == StackPointer)
-        State.CFAOffset = RegClass->getSizeInBits() / 8;
-
-      DWARFRegType DwarfReg = MCRI->getDwarfRegNum(Reg, false);
-      State.RegisterCFIStates[DwarfReg] = RegisterCFIState::createSameValue();
-    }
-
-    // TODO these are temporay added to make things work.
-    // Setup the basic information:
-    State.RegisterCFIStates[MCRI->getDwarfRegNum(MCRI->getProgramCounter(),
-                                                 false)] =
-        RegisterCFIState::createUndefined(); // TODO for now, we don't care
-                                             // about the PC
-    State.RegisterCFIStates[MCRI->getDwarfRegNum(StackPointer,
-                                                 false)] =
-        RegisterCFIState::createOffsetFromCFAVal(0); // sp's old value is CFA
-
-    State.RegisterCFIStates[MCRI->getDwarfRegNum(EMCIA->getFlagsReg(), false)] =
-        RegisterCFIState::createUndefined(); // Flags cannot be caller-saved
+              ArrayRef<MCCFIInstruction> PrologueCFIDirectives);
 
-    // Applying the prologue after default assumptions to overwrite them.
-    for (auto &&PrologueCFIDirective : PrologueCFIDirectives) {
-      State.apply(PrologueCFIDirective);
-    }
-  }
-
-  void update(MCInst &Inst, ArrayRef<MCCFIInstruction> CFIDirectives) {
-    const MCInstrDesc &MCInstInfo = MCII.get(Inst.getOpcode());
-    CFIState AfterState(State);
-    for (auto &&CFIDirective : CFIDirectives)
-      if (!AfterState.apply(CFIDirective))
-        Context.reportWarning(
-            CFIDirective.getLoc(),
-            "I don't support this CFI directive, I assume this does nothing "
-            "(which will probably break other things)");
-
-    std::set<DWARFRegType> Writes, Reads;
-    for (unsigned I = 0; I < MCInstInfo.NumImplicitUses; I++)
-      Reads.insert(MCRI->getDwarfRegNum(
-          getSuperReg(MCInstInfo.implicit_uses()[I]), false));
-    for (unsigned I = 0; I < MCInstInfo.NumImplicitDefs; I++)
-      Writes.insert(MCRI->getDwarfRegNum(
-          getSuperReg(MCInstInfo.implicit_defs()[I]), false));
-
-    for (unsigned I = 0; I < Inst.getNumOperands(); I++) {
-      auto &&Operand = Inst.getOperand(I);
-      if (Operand.isReg()) {
-        if (I < MCInstInfo.getNumDefs())
-          Writes.insert(
-              MCRI->getDwarfRegNum(getSuperReg(Operand.getReg()), false));
-        else if (Operand.getReg())
-          Reads.insert(
-              MCRI->getDwarfRegNum(getSuperReg(Operand.getReg()), false));
-      }
-    }
-
-    checkCFADiff(Inst, State, AfterState, Reads, Writes);
-
-    for (auto &&[Reg, RegState] : State.RegisterCFIStates) {
-      assert(AfterState.RegisterCFIStates.count(Reg) &&
-             "Registers' state should not be deleted by CFI instruction.");
-      checkRegDiff(Inst, Reg, State, AfterState, RegState,
-                   AfterState.RegisterCFIStates[Reg], Reads, Writes);
-    }
-
-    State = AfterState;
-  }
+  void update(MCInst &Inst, ArrayRef<MCCFIInstruction> CFIDirectives);
 
 private:
   void checkRegDiff(const MCInst &Inst, DWARFRegType Reg,
@@ -167,164 +54,12 @@ class CFIAnalysis {
                     const RegisterCFIState &PrevRegState,
                     const RegisterCFIState &NextRegState,
                     const std::set<DWARFRegType> &Reads,
-                    const std::set<DWARFRegType> &Writes) {
-    auto RegLLVMOpt = MCRI->getLLVMRegNum(Reg, false);
-    if (RegLLVMOpt == std::nullopt) {
-      assert(PrevRegState == NextRegState);
-      return;
-    }
-    MCPhysReg RegLLVM = RegLLVMOpt.value();
-
-    auto &&PrevRefReg =
-        PrevState.getReferenceRegisterForCallerValueOfRegister(Reg);
-
-    std::optional<MCPhysReg> PrevRefRegLLVM =
-        (PrevRefReg != std::nullopt
-             ? std::make_optional(
-                   MCRI->getLLVMRegNum(PrevRefReg.value(), false).value())
-             : std::nullopt);
-    std::optional<MCPhysReg> NextRefRegLLVM =
-        (PrevRefReg != std::nullopt
-             ? std::make_optional(
-                   MCRI->getLLVMRegNum(PrevRefReg.value(), false).value())
-             : std::nullopt);
-
-    MCPhysReg PrevStateCFARegLLVM =
-        MCRI->getLLVMRegNum(PrevState.CFARegister, false).value();
-
-    { // try generate
-      // Widen
-      std::vector<RegisterCFIState> PossibleNextRegStates;
-
-      { // stay the same
-        bool CanStayTheSame = false;
-
-        switch (PrevRegState.RetrieveApproach) {
-        case RegisterCFIState::Undefined:
-        case RegisterCFIState::OffsetFromCFAVal:
-          CanStayTheSame = true;
-          break;
-        case RegisterCFIState::SameValue:
-        case RegisterCFIState::AnotherRegister:
-          CanStayTheSame = !Writes.count(PrevRefReg.value());
-          break;
-        case RegisterCFIState::OffsetFromCFAAddr:
-        case RegisterCFIState::Other:
-          // cannot be sure
-          break;
-        }
-
-        if (CanStayTheSame)
-          PossibleNextRegStates.push_back(PrevRegState);
-      }
-
-      for (auto &&PossibleNextRegState : PossibleNextRegStates) {
-        if (PossibleNextRegState == NextRegState) {
-          // Everything is ok
-          return;
-        }
-      }
-
-      for (auto &&PossibleNextRegState : PossibleNextRegStates) {
-        if (PossibleNextRegState.RetrieveApproach !=
-            NextRegState.RetrieveApproach)
-          continue;
-
-        if (PossibleNextRegState.RetrieveApproach ==
-            RegisterCFIState::OffsetFromCFAAddr) {
-          Context.reportError(
-              Inst.getLoc(),
-              formatv(
-                  "Expected caller's value of reg#{0} should be at offset {1} "
-                  "of CFA but the CFI directives say it's in {2}",
-                  RegLLVM, PossibleNextRegState.Info.OffsetFromCFA,
-                  NextRegState.Info.OffsetFromCFA));
-        }
-      }
-    }
-    // Either couldn't generate, or the programmer changed the state to
-    // something that couldn't be matched to any of the generated states. So
-    // it falls back into read/write checks.
-
-    if (PrevRegState == NextRegState) {
-      switch (PrevRegState.RetrieveApproach) {
-      case RegisterCFIState::SameValue:
-      case RegisterCFIState::AnotherRegister:
-        if (Writes.count(PrevRefReg.value())) {
-          Context.reportError(
-              Inst.getLoc(),
-              formatv("Reg#{0} caller's value is in reg#{1} which is changed "
-                      "by this instruction, but not changed in CFI directives",
-                      RegLLVM, PrevRefRegLLVM.value()));
-          return;
-        }
-        break;
-      default:
-        // Everything may be ok
-        break;
-      }
-      return;
-    }
-
-    if (PrevRegState.RetrieveApproach == NextRegState.RetrieveApproach) {
-      // Everything may be ok
-      return;
-    }
-
-    if (PrevRegState.RetrieveApproach == RegisterCFIState::Undefined) {
-      Context.reportError(Inst.getLoc(),
-                          "Cannot change a register CFI information from "
-                          "undefined to something else.");
-      return;
-    }
-
-    Context.reportWarning(Inst.getLoc(),
-                          formatv("The reg#{0} CFI state is changed, but I "
-                                  "don't have any idea how.",
-                                  RegLLVM));
-    // Everything may be ok
-    return;
-  }
+                    const std::set<DWARFRegType> &Writes);
 
   void checkCFADiff(const MCInst &Inst, const CFIState &PrevState,
                     const CFIState &NextState,
                     const std::set<DWARFRegType> &Reads,
-                    const std::set<DWARFRegType> &Writes) {
-    const char *PrevCFARegName = MCRI->getName(
-        MCRI->getLLVMRegNum(PrevState.CFARegister, false).value());
-
-    if (PrevState.CFARegister == NextState.CFARegister) {
-      if (PrevState.CFAOffset == NextState.CFAOffset) {
-        if (Writes.count(PrevState.CFARegister)) {
-          Context.reportError(
-              Inst.getLoc(),
-              formatv(
-                  "Missing CFI directive for the CFA offset adjustment. CFA "
-                  "register ({0}) is modified by this instruction.",
-                  PrevCFARegName));
-          return;
-        }
-
-        // Everything is ok!
-        return;
-      }
-      // The offset is changed.
-
-      if (!Writes.count(PrevState.CFARegister)) {
-        Context.reportError(
-            Inst.getLoc(),
-            formatv("Wrong adjustment to CFA offset. CFA register ({0}) is not "
-                    "modified by this instruction.",
-                    PrevCFARegName));
-      }
-
-      // The CFA register value is changed, and the offset is changed as well,
-      // everything may be ok.
-      return;
-    }
-
-    // The CFA register is changed, everything may be ok.
-  }
+                    const std::set<DWARFRegType> &Writes);
 };
 
 } // namespace llvm
diff --git a/llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysisMCStreamer.h b/llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysisMCStreamer.h
index 7f79653004e5e..a42215685396e 100644
--- a/llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysisMCStreamer.h
+++ b/llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysisMCStreamer.h
@@ -21,10 +21,9 @@ class CFIAnalysisMCStreamer : public MCStreamer {
   struct CFIDirectivesState {
     int DirectiveIndex;
 
-    CFIDirectivesState() : DirectiveIndex(0) {}
+    CFIDirectivesState();
 
-    CFIDirectivesState(int FrameIndex, int InstructionIndex)
-        : DirectiveIndex(InstructionIndex) {}
+    CFIDirectivesState(int FrameIndex, int InstructionIndex);
   } LastCFIDirectivesState;
   std::vector<int> FrameIndices;
   std::vector<CFIAnalysis> CFIAs;
@@ -33,116 +32,34 @@ class CFIAnalysisMCStreamer : public MCStreamer {
     MCInst Instruction;
     std::pair<unsigned, unsigned> CFIDirectivesRange;
 
-    ICFI(MCInst Instruction, std::pair<unsigned, unsigned> CFIDirectives)
-        : Instruction(Instruction), CFIDirectivesRange(CFIDirectives) {}
+    ICFI(MCInst Instruction, std::pair<unsigned, unsigned> CFIDirectives);
   };
 
   std::optional<MCInst> LastInstruction;
 
-  std::pair<unsigned, unsigned> getCFIDirectivesRange() {
-    auto DwarfFrameInfos = getDwarfFrameInfos();
-    int FrameIndex = FrameIndices.back();
-    auto CurrentCFIDirectiveState =
-        hasUnfinishedDwarfFrameInfo()
-            ? CFIDirectivesState(
-                  FrameIndex, DwarfFrameInfos[FrameIndex].Instructions.size())
-            : CFIDirectivesState();
-    assert(CurrentCFIDirectiveState.DirectiveIndex >=
-           LastCFIDirectivesState.DirectiveIndex);
+  std::pair<unsigned, unsigned> getCFIDirectivesRange();
 
-    std::pair<unsigned, unsigned> CFIDirectivesRange(
-        LastCFIDirectivesState.DirectiveIndex,
-        CurrentCFIDirectiveState.DirectiveIndex);
-    LastCFIDirectivesState = CurrentCFIDirectiveState;
-    return CFIDirectivesRange;
-  }
-
-  void feedCFIA() {
-    auto FrameIndex = FrameIndices.back();
-    if (FrameIndex < 0) {
-      // TODO Maybe this corner case causes bugs, when the programmer did a
-      // mistake in the startproc, endprocs and also made a mistake in not
-      // adding cfi directives for a instruction. Then this would cause to
-      // ignore the instruction.
-      auto CFIDirectivesRange = getCFIDirectivesRange();
-      assert(!LastInstruction ||
-             CFIDirectivesRange.first == CFIDirectivesRange.second);
-      return;
-    }
-
-    // TODO get this from emit yourself, instead of getting it in this way
-    const auto *LastDwarfFrameInfo = &getDwarfFrameInfos()[FrameIndex];
-
-    auto CFIDirectivesRange = getCFIDirectivesRange();
-    ArrayRef<MCCFIInstruction> CFIDirectives;
-    if (CFIDirectivesRange.first < CFIDirectivesRange.second) {
-      CFIDirectives =
-          ArrayRef<MCCFIInstruction>(LastDwarfFrameInfo->Instructions);
-      CFIDirectives = CFIDirectives.drop_front(CFIDirectivesRange.first)
-                          .drop_back(LastDwarfFrameInfo->Instructions.size() -
-                                     CFIDirectivesRange.second);
-    }
-
-    if (LastInstruction != std::nullopt) {
-      assert(!CFIAs.empty());
-
-      CFIAs.back().update(LastInstruction.value(), CFIDirectives);
-    } else {
-      CFIAs.emplace_back(getContext(), MCII, MCIA.get(), CFIDirectives);
-    }
-  }
+  void feedCFIA();
 
 public:
   CFIAnalysisMCStreamer(MCContext &Context, const MCInstrInfo &MCII,
-                        std::unique_ptr<MCInstrAnalysis> MCIA)
-      : MCStreamer(Context), MCII(MCII), MCIA(std::move(MCIA)),
-        LastCFIDirectivesState(), LastInstruction(std::nullopt) {
-    FrameIndices.push_back(-1);
-  }
-
-  bool hasRawTextSupport() const override { return true; }
-  void emitRawTextImpl(StringRef String) override {}
-
-  bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override {
-    return true;
-  }
+                        std::unique_ptr<MCInstrAnalysis> MCIA);
 
+  bool hasRawTextSupport() const override;
+  void emitRawTextImpl(StringRef String) override;
+  bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override;
   void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
-                        Align ByteAlignment) override {}
-  void beginCOFFSymbolDef(const MCSymbol *Symbol) override {}
-  void emitCOFFSymbolStorageClass(int StorageClass) override {}
-  void emitCOFFSymbolType(int Type) override {}
-  void endCOFFSymbolDef() override {}
+                        Align ByteAlignment) override;
+  void beginCOFFSymbolDef(const MCSymbol *Symbol) override;
+  void emitCOFFSymbolStorageClass(int StorageClass) override;
+  void emitCOFFSymbolType(int Type) override;
+  void endCOFFSymbolDef() override;
   void emitXCOFFSymbolLinkageWithVisibility(MCSymbol *Symbol,
                                             MCSymbolAttr Linkage,
-                                            MCSymbolAttr Visibility) override {}
-
-  void emitInstruction(const MCInst &Inst,
-                       const MCSubtargetInfo &STI) override {
-    feedCFIA();
-    LastInstruction = Inst;
-  }
-
-  void emitCFIStartProcImpl(MCDwarfFrameInfo &Frame) override {
-    feedCFIA();
-    FrameIndices.push_back(getNumFrameInfos());
-    LastInstruction = std::nullopt;
-    LastCFIDirectivesState.DirectiveIndex = 0;
-    MCStreamer::emitCFIStartProcImpl(Frame);
-  }
-
-  void emitCFIEndProcImpl(MCDwarfFrameInfo &CurFrame) override {
-    feedCFIA();
-    // TODO this will break if the input frame are malformed.
-    FrameIndices.pop_back();
-    CFIAs.pop_back();
-    LastInstruction = std::nullopt;
-    auto FrameIndex = FrameIndices.back();
-    LastCFIDirectivesState.DirectiveIndex =
-        FrameIndex >= 0 ? getDwarfFrameInfos()[FrameIndex].Instructions.size()
-                        : 0;
-    MCStreamer::emitCFIEndProcImpl(CurFrame);
-  }
+                                            MCSymbolAttr Visibility) override;
+  void emitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI) override;
+  void emitCFIStartProcImpl(MCDwarfFrameInfo &Frame) override;
+  void emitCFIEndProcImpl(MCDwarfFrameInfo &CurFrame) override;
 };
 
 } // namespace llvm
diff --git a/llvm/include/llvm/MC/MCCFIAnalysis/CFIState.h b/llvm/include/llvm/MC/MCCFIAnalysis/CFIState.h
index 6ddd4916b5315..3141f65e642b4 100644
--- a/llvm/include/llvm/MC/MCCFIAnalysis/CFIState.h
+++ b/llvm/include/llvm/MC/MCCFIAnalysis/CFIState.h
@@ -3,9 +3,6 @@
 
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/MC/MCDwarf.h"
-#include "llvm/Support/FormatVariadic.h"
-#include <cassert>
-#include <cstdint>
 #include <optional>
 #include <string>
 namespace llvm {
diff --git a/llvm/lib/MC/CFIAnalysis/CFIAnalysis.cpp b/llvm/lib/MC/CFIAnalysis/CFIAnalysis.cpp
new file mode 100644
index 0000000000000..8a50fce8e4da9
--- /dev/null
+++ b/llvm/lib/MC/CFIAnalysis/CFIAnalysis.cpp
@@ -0,0 +1,310 @@
+#include "llvm/MC/MCCFIAnalysis/CFIAnalysis.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/MC/MCCFIAnalysis/ExtendedMCInstrAnalysis.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDwarf.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCRegister.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/TargetRegistry.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FormatVariadic.h"
+#include <memory>
+#include <optional>
+#include <set>
+
+using namespace llvm;
+
+// TODO remove it, it's just for debug purposes.
+void printUntilNextLine(const char *Str) {
+  for (int I = 0; Str[I] != '\0' && Str[I] != '\n'; I++)
+    dbgs() << Str[I];
+}
+
+bool CFIAnalysis::isSuperReg(MCPhysReg Reg) {
+  return MCRI->superregs(Reg).empty();
+}
+
+SmallVector<std::pair<MCPhysReg, MCRegisterClass const *>>
+CFIAnalysis::getAllSuperRegs() {
+  std::map<MCPhysReg, MCRegisterClass const *> SuperRegs;
+  for (auto &&RegClass : MCRI->regclasses()) {
+    for (unsigned I = 0; I < RegClass.getNumRegs(); I++) {
+      MCPhysReg Reg = RegClass.getRegister(I);
+      if (!isSuperReg(Reg))
+        continue;
+      SuperRegs[Reg] = &RegClass;
+    }
+  }
+
+  SmallVector<std::pair<MCPhysReg, MCRegisterClass const *>> SuperRegWithClass;
+  for (auto &&[Reg, RegClass] : SuperRegs)
+    SuperRegWithClass.emplace_back(Reg, RegClass);
+  return SuperRegWithClass;
+}
+
+MCPhysReg CFIAnalysis::getSuperReg(MCPhysReg Reg) {
+  if (isSuperReg(Reg))
+    return Reg;
+  for (auto SuperReg : MCRI->superregs(Reg)) {
+    if (isSuperReg(SuperReg))
+      return SuperReg;
+  }
+
+  llvm_unreachable("Should either be a super reg, or have a super reg");
+}
+
+CFIAnalysis::CFIAnalysis(MCContext &Context, MCInstrInfo const &MCII,
+                         MCInstrAnalysis *MCIA,
+                         ArrayRef<MCCFIInstruction> PrologueCFIDirectives)
+    : Context(Context), MCII(MCII), MCRI(Context.getRegisterInfo()) {
+  EMCIA.reset(new ExtendedMCInstrAnalysis(Context, MCII, MCIA));
+
+  MCPhysReg StackPointer = EMCIA->getStackPointer();
+
+  // TODO check what should be passed as EH?
+  State = CFIState(MCRI->getDwarfRegNum(StackPointer, false), 0);
+  for (auto &&[Reg, RegClass] : getAllSuperRegs()) {
+    if (MCRI->get(Reg).IsArtificial || MCRI->get(Reg).IsConstant)
+      continue;
+
+    if (Reg == StackPointer)
+      State.CFAOffset = RegClass->getSizeInBits() / 8;
+
+    DWARFRegType DwarfReg = MCRI->getDwarfRegNum(Reg, false);
+    State.RegisterCFIStates[DwarfReg] = RegisterCFIState::createSameValue();
+  }
+
+  // TODO these are temporay added to make things work.
+  // Setup the basic information:
+  State.RegisterCFIStates[MCRI->getDwarfRegNum(MCRI->getProgramCounter(),
+                                               false)] =
+      RegisterCFIState::createUndefined(); // TODO for now, we don't care
+                                           // about the PC
+  State.RegisterCFIStates[MCRI->getDwarfRegNum(StackPointer,
+                                               false)] =
+      RegisterCFIState::createOffsetFromCFAVal(0); // sp's old value is CFA
+
+  State.RegisterCFIStates[MCRI->getDwarfRegNum(EMCIA->getFlagsReg(), false)] =
+      RegisterCFIState::createUndefined(); // Flags cannot be caller-saved
+
+  // Applying the prologue after default assumptions to overwrite them.
+  for (auto &&PrologueCFIDirective : PrologueCFIDirectives) {
+    State.apply(PrologueCFIDirective);
+  }
+}
+
+void CFIAnalysis::update(MCInst &Inst,
+                         ArrayRef<MCCFIInstruction> CFIDirectives) {
+  const MCInstrDesc &MCInstInfo = MCII.get(Inst.getOpcode());
+  CFIState AfterState(State);
+  for (auto &&CFIDirective : CFIDirectives)
+    if (!AfterState.apply(CFIDirective))
+      Context.reportWarning(
+          CFIDirective.getLoc(),
+          "I don't support this CFI directive, I assume this does nothing "
+          "(which will probably break other things)");
+
+  std::set<DWARFRegType> Writes, Reads;
+  for (unsigned I = 0; I < MCInstInfo.NumImplicitUses; I++)
+    Reads.insert(MCRI->getDwarfRegNum(
+        getSuperReg(MCInstInfo.implicit_uses()[I]), false));
+  for (unsigned I = 0; I < MCInstInfo.NumImplicitDefs; I++)
+    Writes.insert(MCRI->getDwarfRegNum(
+        getSuperReg(MCInstInfo.implicit_defs()[I]), false));
+
+  for (unsigned I = 0; I < Inst.getNumOperands(); I++) {
+    auto &&Operand = Inst.getOperand(I);
+    if (Operand.isReg()) {
+      if (I < MCInstInfo.getNumDefs())
+        Writes.insert(
+            MCRI->getDwarfRegNum(getSuperReg(Operand.getReg()), false));
+      else if (Operand.getReg())
+        Reads.insert(
+            MCRI->getDwarfRegNum(getSuperReg(Operand.getReg()), false));
+    }
+  }
+
+  checkCFADiff(Inst, State, AfterState, Reads, Writes);
+
+  for (auto &&[Reg, RegState] : State.RegisterCFIStates) {
+    assert(AfterState.RegisterCFIStates.count(Reg) &&
+           "Registers' state should not be deleted by CFI instruction.");
+    checkRegDiff(Inst, Reg, State, AfterState, RegState,
+                 AfterState.RegisterCFIStates[Reg], Reads, Writes);
+  }
+
+  State = AfterState;
+}
+
+void CFIAnalysis::checkRegDiff(const MCInst &Inst, DWARFRegType Reg,
+                               const CFIState &PrevState,
+                               const CFIState &NextState,
+                               const RegisterCFIState &PrevRegState,
+                               const RegisterCFIState &NextRegState,
+                               const std::set<DWARFRegType> &Reads,
+                               const std::set<DWARFRegType> &Writes) {
+  auto RegLLVMOpt = MCRI->getLLVMRegNum(Reg, false);
+  if (RegLLVMOpt == std::nullopt) {
+    assert(PrevRegState == NextRegState);
+    return;
+  }
+  MCPhysReg RegLLVM = RegLLVMOpt.value();
+
+  auto &&PrevRefReg =
+      PrevState.getReferenceRegisterForCallerValueOfRegister(Reg);
+
+  std::optional<MCPhysReg> PrevRefRegLLVM =
+      (PrevRefReg != std::nullopt
+           ? std::make_optional(
+                 MCRI->getLLVMRegNum(PrevRefReg.value(), false).value())
+           : std::nullopt);
+  std::optional<MCPhysReg> NextRefRegLLVM =
+      (PrevRefReg != std::nullopt
+           ? std::make_optional(
+                 MCRI->getLLVMRegNum(PrevRefReg.value(), false).value())
+           : std::nullopt);
+
+  MCPhysReg PrevStateCFARegLLVM =
+      MCRI->getLLVMRegNum(PrevState.CFARegister, false).value();
+
+  { // try generate
+    // Widen
+    std::vector<RegisterCFIState> PossibleNextRegStates;
+
+    { // stay the same
+      bool CanStayTheSame = false;
+
+      switch (PrevRegState.RetrieveApproach) {
+      case RegisterCFIState::Undefined:
+      case RegisterCFIState::OffsetFromCFAVal:
+        CanStayTheSame = true;
+        break;
+      case RegisterCFIState::SameValue:
+      case RegisterCFIState::AnotherRegister:
+        CanStayTheSame = !Writes.count(PrevRefReg.value());
+        break;
+      case RegisterCFIState::OffsetFromCFAAddr:
+      case RegisterCFIState::Other:
+        // cannot be sure
+        break;
+      }
+
+      if (CanStayTheSame)
+        PossibleNextRegStates.push_back(PrevRegState);
+    }
+
+    for (auto &&PossibleNextRegState : PossibleNextRegStates) {
+      if (PossibleNextRegState == NextRegState) {
+        // Everything is ok
+        return;
+      }
+    }
+
+    for (auto &&PossibleNextRegState : PossibleNextRegStates) {
+      if (PossibleNextRegState.RetrieveApproach !=
+          NextRegState.RetrieveApproach)
+        continue;
+
+      if (PossibleNextRegState.RetrieveApproach ==
+          RegisterCFIState::OffsetFromCFAAddr) {
+        Context.reportError(
+            Inst.getLoc(),
+            formatv(
+                "Expected caller's value of reg#{0} should be at offset {1} "
+                "of CFA but the CFI directives say it's in {2}",
+                RegLLVM, PossibleNextRegState.Info.OffsetFromCFA,
+                NextRegState.Info.OffsetFromCFA));
+      }
+    }
+  }
+  // Either couldn't generate, or the programmer changed the state to
+  // something that couldn't be matched to any of the generated states. So
+  // it falls back into read/write checks.
+
+  if (PrevRegState == NextRegState) {
+    switch (PrevRegState.RetrieveApproach) {
+    case RegisterCFIState::SameValue:
+    case RegisterCFIState::AnotherRegister:
+      if (Writes.count(PrevRefReg.value())) {
+        Context.reportError(
+            Inst.getLoc(),
+            formatv("Reg#{0} caller's value is in reg#{1} which is changed "
+                    "by this instruction, but not changed in CFI directives",
+                    RegLLVM, PrevRefRegLLVM.value()));
+        return;
+      }
+      break;
+    default:
+      // Everything may be ok
+      break;
+    }
+    return;
+  }
+
+  if (PrevRegState.RetrieveApproach == NextRegState.RetrieveApproach) {
+    // Everything may be ok
+    return;
+  }
+
+  if (PrevRegState.RetrieveApproach == RegisterCFIState::Undefined) {
+    Context.reportError(Inst.getLoc(),
+                        "Cannot change a register CFI information from "
+                        "undefined to something else.");
+    return;
+  }
+
+  Context.reportWarning(Inst.getLoc(),
+                        formatv("The reg#{0} CFI state is changed, but I "
+                                "don't have any idea how.",
+                                RegLLVM));
+  // Everything may be ok
+  return;
+}
+
+void CFIAnalysis::checkCFADiff(const MCInst &Inst, const CFIState &PrevState,
+                               const CFIState &NextState,
+                               const std::set<DWARFRegType> &Reads,
+                               const std::set<DWARFRegType> &Writes) {
+  const char *PrevCFARegName =
+      MCRI->getName(MCRI->getLLVMRegNum(PrevState.CFARegister, false).value());
+
+  if (PrevState.CFARegister == NextState.CFARegister) {
+    if (PrevState.CFAOffset == NextState.CFAOffset) {
+      if (Writes.count(PrevState.CFARegister)) {
+        Context.reportError(
+            Inst.getLoc(),
+            formatv("Missing CFI directive for the CFA offset adjustment. CFA "
+                    "register ({0}) is modified by this instruction.",
+                    PrevCFARegName));
+        return;
+      }
+
+      // Everything is ok!
+      return;
+    }
+    // The offset is changed.
+
+    if (!Writes.count(PrevState.CFARegister)) {
+      Context.reportError(
+          Inst.getLoc(),
+          formatv("Wrong adjustment to CFA offset. CFA register ({0}) is not "
+                  "modified by this instruction.",
+                  PrevCFARegName));
+    }
+
+    // The CFA register value is changed, and the offset is changed as well,
+    // everything may be ok.
+    return;
+  }
+
+  // The CFA register is changed, everything may be ok.
+}
diff --git a/llvm/lib/MC/CFIAnalysis/CFIAnalysisMCStreamer.cpp b/llvm/lib/MC/CFIAnalysis/CFIAnalysisMCStreamer.cpp
new file mode 100644
index 0000000000000..72e1481c518d5
--- /dev/null
+++ b/llvm/lib/MC/CFIAnalysis/CFIAnalysisMCStreamer.cpp
@@ -0,0 +1,131 @@
+
+#include "llvm/MC/MCCFIAnalysis/CFIAnalysisMCStreamer.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDwarf.h"
+#include "llvm/MC/MCInstrAnalysis.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCStreamer.h"
+#include <cstdio>
+#include <memory>
+#include <optional>
+
+using namespace llvm;
+
+CFIAnalysisMCStreamer::CFIDirectivesState::CFIDirectivesState()
+    : DirectiveIndex(0) {}
+
+CFIAnalysisMCStreamer::CFIDirectivesState::CFIDirectivesState(
+    int FrameIndex, int InstructionIndex)
+    : DirectiveIndex(InstructionIndex) {}
+
+CFIAnalysisMCStreamer::ICFI::ICFI(MCInst Instruction,
+                                  std::pair<unsigned, unsigned> CFIDirectives)
+    : Instruction(Instruction), CFIDirectivesRange(CFIDirectives) {}
+
+std::optional<MCInst> LastInstruction;
+
+std::pair<unsigned, unsigned> CFIAnalysisMCStreamer::getCFIDirectivesRange() {
+  auto DwarfFrameInfos = getDwarfFrameInfos();
+  int FrameIndex = FrameIndices.back();
+  auto CurrentCFIDirectiveState =
+      hasUnfinishedDwarfFrameInfo()
+          ? CFIDirectivesState(FrameIndex,
+                               DwarfFrameInfos[FrameIndex].Instructions.size())
+          : CFIDirectivesState();
+  assert(CurrentCFIDirectiveState.DirectiveIndex >=
+         LastCFIDirectivesState.DirectiveIndex);
+
+  std::pair<unsigned, unsigned> CFIDirectivesRange(
+      LastCFIDirectivesState.DirectiveIndex,
+      CurrentCFIDirectiveState.DirectiveIndex);
+  LastCFIDirectivesState = CurrentCFIDirectiveState;
+  return CFIDirectivesRange;
+}
+
+void CFIAnalysisMCStreamer::feedCFIA() {
+  auto FrameIndex = FrameIndices.back();
+  if (FrameIndex < 0) {
+    // TODO Maybe this corner case causes bugs, when the programmer did a
+    // mistake in the startproc, endprocs and also made a mistake in not
+    // adding cfi directives for a instruction. Then this would cause to
+    // ignore the instruction.
+    auto CFIDirectivesRange = getCFIDirectivesRange();
+    assert(!LastInstruction ||
+           CFIDirectivesRange.first == CFIDirectivesRange.second);
+    return;
+  }
+
+  // TODO get this from emit yourself, instead of getting it in this way
+  const auto *LastDwarfFrameInfo = &getDwarfFrameInfos()[FrameIndex];
+
+  auto CFIDirectivesRange = getCFIDirectivesRange();
+  ArrayRef<MCCFIInstruction> CFIDirectives;
+  if (CFIDirectivesRange.first < CFIDirectivesRange.second) {
+    CFIDirectives =
+        ArrayRef<MCCFIInstruction>(LastDwarfFrameInfo->Instructions);
+    CFIDirectives = CFIDirectives.drop_front(CFIDirectivesRange.first)
+                        .drop_back(LastDwarfFrameInfo->Instructions.size() -
+                                   CFIDirectivesRange.second);
+  }
+
+  if (LastInstruction != std::nullopt) {
+    assert(!CFIAs.empty());
+
+    CFIAs.back().update(LastInstruction.value(), CFIDirectives);
+  } else {
+    CFIAs.emplace_back(getContext(), MCII, MCIA.get(), CFIDirectives);
+  }
+}
+
+CFIAnalysisMCStreamer::CFIAnalysisMCStreamer(
+    MCContext &Context, const MCInstrInfo &MCII,
+    std::unique_ptr<MCInstrAnalysis> MCIA)
+    : MCStreamer(Context), MCII(MCII), MCIA(std::move(MCIA)),
+      LastCFIDirectivesState(), LastInstruction(std::nullopt) {
+  FrameIndices.push_back(-1);
+}
+
+bool CFIAnalysisMCStreamer::hasRawTextSupport() const { return true; }
+void CFIAnalysisMCStreamer::emitRawTextImpl(StringRef String) {}
+
+bool CFIAnalysisMCStreamer::emitSymbolAttribute(MCSymbol *Symbol,
+                                                MCSymbolAttr Attribute) {
+  return true;
+}
+
+void CFIAnalysisMCStreamer::emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
+                                             Align ByteAlignment) {}
+void CFIAnalysisMCStreamer::beginCOFFSymbolDef(const MCSymbol *Symbol) {}
+void CFIAnalysisMCStreamer::emitCOFFSymbolStorageClass(int StorageClass) {}
+void CFIAnalysisMCStreamer::emitCOFFSymbolType(int Type) {}
+void CFIAnalysisMCStreamer::endCOFFSymbolDef() {}
+void CFIAnalysisMCStreamer::emitXCOFFSymbolLinkageWithVisibility(
+    MCSymbol *Symbol, MCSymbolAttr Linkage, MCSymbolAttr Visibility) {}
+
+void CFIAnalysisMCStreamer::emitInstruction(const MCInst &Inst,
+                                            const MCSubtargetInfo &STI) {
+  feedCFIA();
+  LastInstruction = Inst;
+}
+
+void CFIAnalysisMCStreamer::emitCFIStartProcImpl(MCDwarfFrameInfo &Frame) {
+  feedCFIA();
+  FrameIndices.push_back(getNumFrameInfos());
+  LastInstruction = std::nullopt;
+  LastCFIDirectivesState.DirectiveIndex = 0;
+  MCStreamer::emitCFIStartProcImpl(Frame);
+}
+
+void CFIAnalysisMCStreamer::emitCFIEndProcImpl(MCDwarfFrameInfo &CurFrame) {
+  feedCFIA();
+  // TODO this will break if the input frame are malformed.
+  FrameIndices.pop_back();
+  CFIAs.pop_back();
+  LastInstruction = std::nullopt;
+  auto FrameIndex = FrameIndices.back();
+  LastCFIDirectivesState.DirectiveIndex =
+      FrameIndex >= 0 ? getDwarfFrameInfos()[FrameIndex].Instructions.size()
+                      : 0;
+  MCStreamer::emitCFIEndProcImpl(CurFrame);
+}
diff --git a/llvm/lib/MC/CFIAnalysis/CFIState.cpp b/llvm/lib/MC/CFIAnalysis/CFIState.cpp
index 8a5efe31a2826..69b777cf096a7 100644
--- a/llvm/lib/MC/CFIAnalysis/CFIState.cpp
+++ b/llvm/lib/MC/CFIAnalysis/CFIState.cpp
@@ -1,3 +1,4 @@
+// TODO check what includes to keep and what to remove
 #include "llvm/MC/MCCFIAnalysis/CFIState.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/MC/MCDwarf.h"
diff --git a/llvm/lib/MC/CFIAnalysis/CMakeLists.txt b/llvm/lib/MC/CFIAnalysis/CMakeLists.txt
index 0bc829c754092..cbfac740c97ab 100644
--- a/llvm/lib/MC/CFIAnalysis/CMakeLists.txt
+++ b/llvm/lib/MC/CFIAnalysis/CMakeLists.txt
@@ -1,8 +1,7 @@
 add_llvm_component_library(LLVMMCCFIAnalysis
   CFIState.cpp
-  # CFIAnalysisMCStreamer.cpp
-  # CFIAnalysis.cpp
-  # ExtendedMCInstrAnalysis.cpp
+  CFIAnalysisMCStreamer.cpp
+  CFIAnalysis.cpp
 
   LINK_COMPONENTS
   MC

>From 2c233f90c5fd8e025f7f7506c48ac19c78e4f926 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Tue, 27 May 2025 19:14:44 +0000
Subject: [PATCH 26/58] Remove stack pointer method

---
 .../MC/MCCFIAnalysis/ExtendedMCInstrAnalysis.h   |  1 -
 llvm/lib/MC/CFIAnalysis/CFIAnalysis.cpp          | 16 ++++++++--------
 2 files changed, 8 insertions(+), 9 deletions(-)

diff --git a/llvm/include/llvm/MC/MCCFIAnalysis/ExtendedMCInstrAnalysis.h b/llvm/include/llvm/MC/MCCFIAnalysis/ExtendedMCInstrAnalysis.h
index 6d050a4defbcc..4d8ed38513d2a 100644
--- a/llvm/include/llvm/MC/MCCFIAnalysis/ExtendedMCInstrAnalysis.h
+++ b/llvm/include/llvm/MC/MCCFIAnalysis/ExtendedMCInstrAnalysis.h
@@ -19,7 +19,6 @@ class ExtendedMCInstrAnalysis {
 
   /// Extra semantic information needed from MC layer:
 
-  MCPhysReg getStackPointer() const { return 61; }
   MCPhysReg getFlagsReg() const { return 57; }
 };
 
diff --git a/llvm/lib/MC/CFIAnalysis/CFIAnalysis.cpp b/llvm/lib/MC/CFIAnalysis/CFIAnalysis.cpp
index 8a50fce8e4da9..b20f6cfe90b38 100644
--- a/llvm/lib/MC/CFIAnalysis/CFIAnalysis.cpp
+++ b/llvm/lib/MC/CFIAnalysis/CFIAnalysis.cpp
@@ -3,6 +3,7 @@
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/Twine.h"
+#include "llvm/MC/MCAsmInfo.h"
 #include "llvm/MC/MCCFIAnalysis/ExtendedMCInstrAnalysis.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCDwarf.h"
@@ -68,28 +69,27 @@ CFIAnalysis::CFIAnalysis(MCContext &Context, MCInstrInfo const &MCII,
     : Context(Context), MCII(MCII), MCRI(Context.getRegisterInfo()) {
   EMCIA.reset(new ExtendedMCInstrAnalysis(Context, MCII, MCIA));
 
-  MCPhysReg StackPointer = EMCIA->getStackPointer();
-
-  // TODO check what should be passed as EH?
-  State = CFIState(MCRI->getDwarfRegNum(StackPointer, false), 0);
+  // TODO check what should be passed as EH? I am putting false everywhere.
   for (auto &&[Reg, RegClass] : getAllSuperRegs()) {
     if (MCRI->get(Reg).IsArtificial || MCRI->get(Reg).IsConstant)
       continue;
 
-    if (Reg == StackPointer)
-      State.CFAOffset = RegClass->getSizeInBits() / 8;
-
     DWARFRegType DwarfReg = MCRI->getDwarfRegNum(Reg, false);
     State.RegisterCFIStates[DwarfReg] = RegisterCFIState::createSameValue();
   }
 
+  for (auto &&InitialFrameStateCFIDirective :
+       Context.getAsmInfo()->getInitialFrameState()) {
+    State.apply(InitialFrameStateCFIDirective);
+  }
+
   // TODO these are temporay added to make things work.
   // Setup the basic information:
   State.RegisterCFIStates[MCRI->getDwarfRegNum(MCRI->getProgramCounter(),
                                                false)] =
       RegisterCFIState::createUndefined(); // TODO for now, we don't care
                                            // about the PC
-  State.RegisterCFIStates[MCRI->getDwarfRegNum(StackPointer,
+  State.RegisterCFIStates[MCRI->getDwarfRegNum(State.CFARegister,
                                                false)] =
       RegisterCFIState::createOffsetFromCFAVal(0); // sp's old value is CFA
 

>From 12faad87e19892ce8fa71a58da936e070ef199bf Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Thu, 29 May 2025 18:49:37 +0000
Subject: [PATCH 27/58] Comment out Ignoring flags at the beginning CFI
 analysis

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

diff --git a/llvm/lib/MC/CFIAnalysis/CFIAnalysis.cpp b/llvm/lib/MC/CFIAnalysis/CFIAnalysis.cpp
index b20f6cfe90b38..02aed555f8c2c 100644
--- a/llvm/lib/MC/CFIAnalysis/CFIAnalysis.cpp
+++ b/llvm/lib/MC/CFIAnalysis/CFIAnalysis.cpp
@@ -93,8 +93,8 @@ CFIAnalysis::CFIAnalysis(MCContext &Context, MCInstrInfo const &MCII,
                                                false)] =
       RegisterCFIState::createOffsetFromCFAVal(0); // sp's old value is CFA
 
-  State.RegisterCFIStates[MCRI->getDwarfRegNum(EMCIA->getFlagsReg(), false)] =
-      RegisterCFIState::createUndefined(); // Flags cannot be caller-saved
+  // State.RegisterCFIStates[MCRI->getDwarfRegNum(EMCIA->getFlagsReg(), false)] =
+  //     RegisterCFIState::createUndefined(); // Flags cannot be caller-saved
 
   // Applying the prologue after default assumptions to overwrite them.
   for (auto &&PrologueCFIDirective : PrologueCFIDirectives) {

>From 282cb77715ab4531b19f702b28a9f0cb49826f19 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Tue, 3 Jun 2025 18:59:01 +0000
Subject: [PATCH 28/58] Move the necessary MCStreamer interface methods to
 CFIAnalysisMCStreamer.h

---
 .../MC/MCCFIAnalysis/CFIAnalysisMCStreamer.h  | 24 ++++++++++++-------
 .../MC/CFIAnalysis/CFIAnalysisMCStreamer.cpp  | 19 ---------------
 2 files changed, 15 insertions(+), 28 deletions(-)

diff --git a/llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysisMCStreamer.h b/llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysisMCStreamer.h
index a42215685396e..a5aecd05f41d5 100644
--- a/llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysisMCStreamer.h
+++ b/llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysisMCStreamer.h
@@ -45,18 +45,24 @@ class CFIAnalysisMCStreamer : public MCStreamer {
   CFIAnalysisMCStreamer(MCContext &Context, const MCInstrInfo &MCII,
                         std::unique_ptr<MCInstrAnalysis> MCIA);
 
-  bool hasRawTextSupport() const override;
-  void emitRawTextImpl(StringRef String) override;
-  bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override;
+  bool hasRawTextSupport() const override { return true; }
+  void emitRawTextImpl(StringRef String) override {}
+
+  bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override {
+    return true;
+  }
+
   void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
-                        Align ByteAlignment) override;
-  void beginCOFFSymbolDef(const MCSymbol *Symbol) override;
-  void emitCOFFSymbolStorageClass(int StorageClass) override;
-  void emitCOFFSymbolType(int Type) override;
-  void endCOFFSymbolDef() override;
+                        Align ByteAlignment) override {}
+  void emitSubsectionsViaSymbols() override {};
+  void beginCOFFSymbolDef(const MCSymbol *Symbol) override {}
+  void emitCOFFSymbolStorageClass(int StorageClass) override {}
+  void emitCOFFSymbolType(int Type) override {}
+  void endCOFFSymbolDef() override {}
   void emitXCOFFSymbolLinkageWithVisibility(MCSymbol *Symbol,
                                             MCSymbolAttr Linkage,
-                                            MCSymbolAttr Visibility) override;
+                                            MCSymbolAttr Visibility) override {}
+
   void emitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI) override;
   void emitCFIStartProcImpl(MCDwarfFrameInfo &Frame) override;
   void emitCFIEndProcImpl(MCDwarfFrameInfo &CurFrame) override;
diff --git a/llvm/lib/MC/CFIAnalysis/CFIAnalysisMCStreamer.cpp b/llvm/lib/MC/CFIAnalysis/CFIAnalysisMCStreamer.cpp
index 72e1481c518d5..994d7d56e0871 100644
--- a/llvm/lib/MC/CFIAnalysis/CFIAnalysisMCStreamer.cpp
+++ b/llvm/lib/MC/CFIAnalysis/CFIAnalysisMCStreamer.cpp
@@ -23,8 +23,6 @@ CFIAnalysisMCStreamer::ICFI::ICFI(MCInst Instruction,
                                   std::pair<unsigned, unsigned> CFIDirectives)
     : Instruction(Instruction), CFIDirectivesRange(CFIDirectives) {}
 
-std::optional<MCInst> LastInstruction;
-
 std::pair<unsigned, unsigned> CFIAnalysisMCStreamer::getCFIDirectivesRange() {
   auto DwarfFrameInfos = getDwarfFrameInfos();
   int FrameIndex = FrameIndices.back();
@@ -86,23 +84,6 @@ CFIAnalysisMCStreamer::CFIAnalysisMCStreamer(
   FrameIndices.push_back(-1);
 }
 
-bool CFIAnalysisMCStreamer::hasRawTextSupport() const { return true; }
-void CFIAnalysisMCStreamer::emitRawTextImpl(StringRef String) {}
-
-bool CFIAnalysisMCStreamer::emitSymbolAttribute(MCSymbol *Symbol,
-                                                MCSymbolAttr Attribute) {
-  return true;
-}
-
-void CFIAnalysisMCStreamer::emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
-                                             Align ByteAlignment) {}
-void CFIAnalysisMCStreamer::beginCOFFSymbolDef(const MCSymbol *Symbol) {}
-void CFIAnalysisMCStreamer::emitCOFFSymbolStorageClass(int StorageClass) {}
-void CFIAnalysisMCStreamer::emitCOFFSymbolType(int Type) {}
-void CFIAnalysisMCStreamer::endCOFFSymbolDef() {}
-void CFIAnalysisMCStreamer::emitXCOFFSymbolLinkageWithVisibility(
-    MCSymbol *Symbol, MCSymbolAttr Linkage, MCSymbolAttr Visibility) {}
-
 void CFIAnalysisMCStreamer::emitInstruction(const MCInst &Inst,
                                             const MCSubtargetInfo &STI) {
   feedCFIA();

>From 903e3fbc02c150a7ddebe5f98c03fc5b6390336d Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Thu, 5 Jun 2025 21:35:26 +0000
Subject: [PATCH 29/58] Make the update method const

---
 llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysis.h  | 2 +-
 llvm/lib/MC/CFIAnalysis/CFIAnalysis.cpp           | 2 +-
 llvm/lib/MC/CFIAnalysis/CFIAnalysisMCStreamer.cpp | 1 -
 3 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysis.h b/llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysis.h
index 8c70764cdde2d..180296755665e 100644
--- a/llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysis.h
+++ b/llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysis.h
@@ -46,7 +46,7 @@ class CFIAnalysis {
               MCInstrAnalysis *MCIA,
               ArrayRef<MCCFIInstruction> PrologueCFIDirectives);
 
-  void update(MCInst &Inst, ArrayRef<MCCFIInstruction> CFIDirectives);
+  void update(const MCInst &Inst, ArrayRef<MCCFIInstruction> CFIDirectives);
 
 private:
   void checkRegDiff(const MCInst &Inst, DWARFRegType Reg,
diff --git a/llvm/lib/MC/CFIAnalysis/CFIAnalysis.cpp b/llvm/lib/MC/CFIAnalysis/CFIAnalysis.cpp
index 02aed555f8c2c..97f52356dc69b 100644
--- a/llvm/lib/MC/CFIAnalysis/CFIAnalysis.cpp
+++ b/llvm/lib/MC/CFIAnalysis/CFIAnalysis.cpp
@@ -102,7 +102,7 @@ CFIAnalysis::CFIAnalysis(MCContext &Context, MCInstrInfo const &MCII,
   }
 }
 
-void CFIAnalysis::update(MCInst &Inst,
+void CFIAnalysis::update(const MCInst &Inst,
                          ArrayRef<MCCFIInstruction> CFIDirectives) {
   const MCInstrDesc &MCInstInfo = MCII.get(Inst.getOpcode());
   CFIState AfterState(State);
diff --git a/llvm/lib/MC/CFIAnalysis/CFIAnalysisMCStreamer.cpp b/llvm/lib/MC/CFIAnalysis/CFIAnalysisMCStreamer.cpp
index 994d7d56e0871..f286be9329475 100644
--- a/llvm/lib/MC/CFIAnalysis/CFIAnalysisMCStreamer.cpp
+++ b/llvm/lib/MC/CFIAnalysis/CFIAnalysisMCStreamer.cpp
@@ -54,7 +54,6 @@ void CFIAnalysisMCStreamer::feedCFIA() {
     return;
   }
 
-  // TODO get this from emit yourself, instead of getting it in this way
   const auto *LastDwarfFrameInfo = &getDwarfFrameInfos()[FrameIndex];
 
   auto CFIDirectivesRange = getCFIDirectivesRange();

>From 7bb20f823ad0c576a8bba83c5138432b1646ae2c Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Thu, 5 Jun 2025 21:50:28 +0000
Subject: [PATCH 30/58] Move CFI analysis out of MC layer

---
 llvm/include/llvm/{MC => }/MCCFIAnalysis/CFIAnalysis.h     | 0
 .../llvm/{MC => }/MCCFIAnalysis/CFIAnalysisMCStreamer.h    | 0
 llvm/include/llvm/{MC => }/MCCFIAnalysis/CFIState.h        | 0
 .../llvm/{MC => }/MCCFIAnalysis/ExtendedMCInstrAnalysis.h  | 0
 llvm/lib/CMakeLists.txt                                    | 1 +
 llvm/lib/MC/CMakeLists.txt                                 | 1 -
 llvm/lib/{MC/CFIAnalysis => MCCFIAnalysis}/CFIAnalysis.cpp | 7 ++++---
 .../CFIAnalysisMCStreamer.cpp                              | 2 +-
 llvm/lib/{MC/CFIAnalysis => MCCFIAnalysis}/CFIState.cpp    | 2 +-
 llvm/lib/{MC/CFIAnalysis => MCCFIAnalysis}/CMakeLists.txt  | 3 +++
 llvm/tools/llvm-mc/llvm-mc.cpp                             | 2 +-
 11 files changed, 11 insertions(+), 7 deletions(-)
 rename llvm/include/llvm/{MC => }/MCCFIAnalysis/CFIAnalysis.h (100%)
 rename llvm/include/llvm/{MC => }/MCCFIAnalysis/CFIAnalysisMCStreamer.h (100%)
 rename llvm/include/llvm/{MC => }/MCCFIAnalysis/CFIState.h (100%)
 rename llvm/include/llvm/{MC => }/MCCFIAnalysis/ExtendedMCInstrAnalysis.h (100%)
 rename llvm/lib/{MC/CFIAnalysis => MCCFIAnalysis}/CFIAnalysis.cpp (98%)
 rename llvm/lib/{MC/CFIAnalysis => MCCFIAnalysis}/CFIAnalysisMCStreamer.cpp (98%)
 rename llvm/lib/{MC/CFIAnalysis => MCCFIAnalysis}/CFIState.cpp (99%)
 rename llvm/lib/{MC/CFIAnalysis => MCCFIAnalysis}/CMakeLists.txt (69%)

diff --git a/llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysis.h b/llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h
similarity index 100%
rename from llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysis.h
rename to llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h
diff --git a/llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysisMCStreamer.h b/llvm/include/llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h
similarity index 100%
rename from llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysisMCStreamer.h
rename to llvm/include/llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h
diff --git a/llvm/include/llvm/MC/MCCFIAnalysis/CFIState.h b/llvm/include/llvm/MCCFIAnalysis/CFIState.h
similarity index 100%
rename from llvm/include/llvm/MC/MCCFIAnalysis/CFIState.h
rename to llvm/include/llvm/MCCFIAnalysis/CFIState.h
diff --git a/llvm/include/llvm/MC/MCCFIAnalysis/ExtendedMCInstrAnalysis.h b/llvm/include/llvm/MCCFIAnalysis/ExtendedMCInstrAnalysis.h
similarity index 100%
rename from llvm/include/llvm/MC/MCCFIAnalysis/ExtendedMCInstrAnalysis.h
rename to llvm/include/llvm/MCCFIAnalysis/ExtendedMCInstrAnalysis.h
diff --git a/llvm/lib/CMakeLists.txt b/llvm/lib/CMakeLists.txt
index f6465612d30c0..08b68aee46efd 100644
--- a/llvm/lib/CMakeLists.txt
+++ b/llvm/lib/CMakeLists.txt
@@ -24,6 +24,7 @@ add_subdirectory(Analysis)
 add_subdirectory(LTO)
 add_subdirectory(MC)
 add_subdirectory(MCA)
+add_subdirectory(MCCFIAnalysis)
 add_subdirectory(ObjCopy)
 add_subdirectory(Object)
 add_subdirectory(ObjectYAML)
diff --git a/llvm/lib/MC/CMakeLists.txt b/llvm/lib/MC/CMakeLists.txt
index 8f8637bd8580b..f49f14c848b90 100644
--- a/llvm/lib/MC/CMakeLists.txt
+++ b/llvm/lib/MC/CMakeLists.txt
@@ -87,4 +87,3 @@ add_llvm_component_library(LLVMMC
 
 add_subdirectory(MCParser)
 add_subdirectory(MCDisassembler)
-add_subdirectory(CFIAnalysis)
diff --git a/llvm/lib/MC/CFIAnalysis/CFIAnalysis.cpp b/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp
similarity index 98%
rename from llvm/lib/MC/CFIAnalysis/CFIAnalysis.cpp
rename to llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp
index 97f52356dc69b..1a5785e4eac0c 100644
--- a/llvm/lib/MC/CFIAnalysis/CFIAnalysis.cpp
+++ b/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp
@@ -1,10 +1,9 @@
-#include "llvm/MC/MCCFIAnalysis/CFIAnalysis.h"
+#include "llvm/MCCFIAnalysis/CFIAnalysis.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/Twine.h"
 #include "llvm/MC/MCAsmInfo.h"
-#include "llvm/MC/MCCFIAnalysis/ExtendedMCInstrAnalysis.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCDwarf.h"
 #include "llvm/MC/MCExpr.h"
@@ -15,6 +14,7 @@
 #include "llvm/MC/MCStreamer.h"
 #include "llvm/MC/MCSubtargetInfo.h"
 #include "llvm/MC/TargetRegistry.h"
+#include "llvm/MCCFIAnalysis/ExtendedMCInstrAnalysis.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/FormatVariadic.h"
@@ -93,7 +93,8 @@ CFIAnalysis::CFIAnalysis(MCContext &Context, MCInstrInfo const &MCII,
                                                false)] =
       RegisterCFIState::createOffsetFromCFAVal(0); // sp's old value is CFA
 
-  // State.RegisterCFIStates[MCRI->getDwarfRegNum(EMCIA->getFlagsReg(), false)] =
+  // State.RegisterCFIStates[MCRI->getDwarfRegNum(EMCIA->getFlagsReg(), false)]
+  // =
   //     RegisterCFIState::createUndefined(); // Flags cannot be caller-saved
 
   // Applying the prologue after default assumptions to overwrite them.
diff --git a/llvm/lib/MC/CFIAnalysis/CFIAnalysisMCStreamer.cpp b/llvm/lib/MCCFIAnalysis/CFIAnalysisMCStreamer.cpp
similarity index 98%
rename from llvm/lib/MC/CFIAnalysis/CFIAnalysisMCStreamer.cpp
rename to llvm/lib/MCCFIAnalysis/CFIAnalysisMCStreamer.cpp
index f286be9329475..43855a4d75dc2 100644
--- a/llvm/lib/MC/CFIAnalysis/CFIAnalysisMCStreamer.cpp
+++ b/llvm/lib/MCCFIAnalysis/CFIAnalysisMCStreamer.cpp
@@ -1,5 +1,5 @@
 
-#include "llvm/MC/MCCFIAnalysis/CFIAnalysisMCStreamer.h"
+#include "llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCDwarf.h"
diff --git a/llvm/lib/MC/CFIAnalysis/CFIState.cpp b/llvm/lib/MCCFIAnalysis/CFIState.cpp
similarity index 99%
rename from llvm/lib/MC/CFIAnalysis/CFIState.cpp
rename to llvm/lib/MCCFIAnalysis/CFIState.cpp
index 69b777cf096a7..56cee65c5235a 100644
--- a/llvm/lib/MC/CFIAnalysis/CFIState.cpp
+++ b/llvm/lib/MCCFIAnalysis/CFIState.cpp
@@ -1,5 +1,5 @@
 // TODO check what includes to keep and what to remove
-#include "llvm/MC/MCCFIAnalysis/CFIState.h"
+#include "llvm/MCCFIAnalysis/CFIState.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/MC/MCDwarf.h"
 #include "llvm/Support/FormatVariadic.h"
diff --git a/llvm/lib/MC/CFIAnalysis/CMakeLists.txt b/llvm/lib/MCCFIAnalysis/CMakeLists.txt
similarity index 69%
rename from llvm/lib/MC/CFIAnalysis/CMakeLists.txt
rename to llvm/lib/MCCFIAnalysis/CMakeLists.txt
index cbfac740c97ab..7b504d6f6f19c 100644
--- a/llvm/lib/MC/CFIAnalysis/CMakeLists.txt
+++ b/llvm/lib/MCCFIAnalysis/CMakeLists.txt
@@ -3,6 +3,9 @@ add_llvm_component_library(LLVMMCCFIAnalysis
   CFIAnalysisMCStreamer.cpp
   CFIAnalysis.cpp
 
+  ADDITIONAL_HEADER_DIRS
+  ${LLVM_MAIN_INCLUDE_DIR}/llvm/MCA
+
   LINK_COMPONENTS
   MC
   Support
diff --git a/llvm/tools/llvm-mc/llvm-mc.cpp b/llvm/tools/llvm-mc/llvm-mc.cpp
index 2f1d6cb42aa0b..c2852298aacb6 100644
--- a/llvm/tools/llvm-mc/llvm-mc.cpp
+++ b/llvm/tools/llvm-mc/llvm-mc.cpp
@@ -14,7 +14,7 @@
 #include "Disassembler.h"
 #include "llvm/MC/MCAsmBackend.h"
 #include "llvm/MC/MCAsmInfo.h"
-#include "llvm/MC/MCCFIAnalysis/CFIAnalysisMCStreamer.h"
+#include "llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h"
 #include "llvm/MC/MCCodeEmitter.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCInstPrinter.h"

>From 050dbdb947becca871cf14c067f57b507d96f5b9 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Fri, 6 Jun 2025 18:04:33 +0000
Subject: [PATCH 31/58] Write a CFI directive to DWARF operation converter

---
 llvm/include/llvm/MCCFIAnalysis/CFIState.h |  6 ++
 llvm/lib/MCCFIAnalysis/CFIState.cpp        | 97 ++++++++++++++++++++++
 llvm/lib/MCCFIAnalysis/CMakeLists.txt      |  1 +
 3 files changed, 104 insertions(+)

diff --git a/llvm/include/llvm/MCCFIAnalysis/CFIState.h b/llvm/include/llvm/MCCFIAnalysis/CFIState.h
index 3141f65e642b4..cfe2aacf02ce6 100644
--- a/llvm/include/llvm/MCCFIAnalysis/CFIState.h
+++ b/llvm/include/llvm/MCCFIAnalysis/CFIState.h
@@ -2,6 +2,8 @@
 #define LLVM_TOOLS_LLVM_MC_CFI_STATE_H
 
 #include "llvm/ADT/DenseMap.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
+#include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCDwarf.h"
 #include <optional>
 #include <string>
@@ -9,6 +11,10 @@ namespace llvm {
 
 using DWARFRegType = int64_t;
 
+dwarf::CFIProgram convertMC2DWARF(MCContext &Context,
+                                  MCCFIInstruction CFIDirective,
+                                  int64_t CFAOffset);
+
 struct RegisterCFIState {
   enum Approach {
     Undefined,
diff --git a/llvm/lib/MCCFIAnalysis/CFIState.cpp b/llvm/lib/MCCFIAnalysis/CFIState.cpp
index 56cee65c5235a..4f4a6e168bef6 100644
--- a/llvm/lib/MCCFIAnalysis/CFIState.cpp
+++ b/llvm/lib/MCCFIAnalysis/CFIState.cpp
@@ -1,6 +1,8 @@
 // TODO check what includes to keep and what to remove
 #include "llvm/MCCFIAnalysis/CFIState.h"
 #include "llvm/ADT/DenseMap.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
 #include "llvm/MC/MCDwarf.h"
 #include "llvm/Support/FormatVariadic.h"
 #include <cassert>
@@ -10,6 +12,101 @@
 
 using namespace llvm;
 
+dwarf::CFIProgram llvm::convertMC2DWARF(MCContext &Context,
+                                        MCCFIInstruction CFIDirective,
+                                        int64_t CFAOffset) {
+  //! FIXME, this way of instantiating CFI program does not look right, either
+  //! refactor CFIProgram to not depend on the Code/Data Alignment or add a new
+  //! type that is independent from this and is also feedable to UnwindTable.
+  auto DwarfOperations =
+      dwarf::CFIProgram(0, 0, Context.getTargetTriple().getArch());
+
+  switch (CFIDirective.getOperation()) {
+  case MCCFIInstruction::OpSameValue:
+    DwarfOperations.addInstruction(dwarf::DW_CFA_same_value,
+                                   CFIDirective.getRegister());
+    break;
+  case MCCFIInstruction::OpRememberState:
+    DwarfOperations.addInstruction(dwarf::DW_CFA_remember_state);
+    break;
+  case MCCFIInstruction::OpRestoreState:
+    DwarfOperations.addInstruction(dwarf::DW_CFA_restore_state);
+    break;
+  case MCCFIInstruction::OpOffset:
+    DwarfOperations.addInstruction(dwarf::DW_CFA_offset,
+                                   CFIDirective.getRegister(),
+                                   CFIDirective.getOffset());
+    break;
+  case MCCFIInstruction::OpLLVMDefAspaceCfa:
+    DwarfOperations.addInstruction(dwarf::DW_CFA_LLVM_def_aspace_cfa,
+                                   CFIDirective.getRegister());
+    break;
+  case MCCFIInstruction::OpDefCfaRegister:
+    DwarfOperations.addInstruction(dwarf::DW_CFA_def_cfa,
+                                   CFIDirective.getRegister());
+    break;
+  case MCCFIInstruction::OpDefCfaOffset:
+    DwarfOperations.addInstruction(dwarf::DW_CFA_def_cfa_offset,
+                                   CFIDirective.getOffset());
+    break;
+  case MCCFIInstruction::OpDefCfa:
+    DwarfOperations.addInstruction(dwarf::DW_CFA_def_cfa,
+                                   CFIDirective.getRegister(),
+                                   CFIDirective.getOffset());
+    break;
+  case MCCFIInstruction::OpRelOffset:
+    DwarfOperations.addInstruction(dwarf::DW_CFA_offset,
+                                   CFIDirective.getRegister(),
+                                   CFIDirective.getOffset() - CFAOffset);
+    break;
+  case MCCFIInstruction::OpAdjustCfaOffset:
+    DwarfOperations.addInstruction(dwarf::DW_CFA_def_cfa_offset,
+                                   CFIDirective.getOffset() + CFAOffset);
+    break;
+  case MCCFIInstruction::OpEscape:
+    // TODO It's now feasible but for now, I ignore it
+    break;
+  case MCCFIInstruction::OpRestore:
+    DwarfOperations.addInstruction(dwarf::DW_CFA_restore);
+    break;
+  case MCCFIInstruction::OpUndefined:
+    DwarfOperations.addInstruction(dwarf::DW_CFA_undefined,
+                                   CFIDirective.getRegister());
+    break;
+  case MCCFIInstruction::OpRegister:
+    DwarfOperations.addInstruction(dwarf::DW_CFA_register,
+                                   CFIDirective.getRegister(),
+                                   CFIDirective.getRegister2());
+    break;
+  case MCCFIInstruction::OpWindowSave:
+    // TODO make sure these are the same.
+    DwarfOperations.addInstruction(dwarf::DW_CFA_GNU_window_save);
+    break;
+  case MCCFIInstruction::OpNegateRAState:
+    // TODO make sure these are the same.
+    DwarfOperations.addInstruction(dwarf::DW_CFA_AARCH64_negate_ra_state);
+    break;
+  case MCCFIInstruction::OpNegateRAStateWithPC:
+    // TODO make sure these are the same.
+    DwarfOperations.addInstruction(
+        dwarf::DW_CFA_AARCH64_negate_ra_state_with_pc);
+    break;
+  case MCCFIInstruction::OpGnuArgsSize:
+    DwarfOperations.addInstruction(dwarf::DW_CFA_GNU_args_size);
+    break;
+  case MCCFIInstruction::OpLabel:
+    // TODO, I don't know what it is, I have to implement it.
+    break;
+  case MCCFIInstruction::OpValOffset:
+    DwarfOperations.addInstruction(dwarf::DW_CFA_val_offset,
+                                   CFIDirective.getRegister(),
+                                   CFIDirective.getOffset());
+    break;
+  }
+
+  return DwarfOperations;
+}
+
 using DWARFRegType = int64_t;
 
 std::string RegisterCFIState::dump() {
diff --git a/llvm/lib/MCCFIAnalysis/CMakeLists.txt b/llvm/lib/MCCFIAnalysis/CMakeLists.txt
index 7b504d6f6f19c..15622132de7d4 100644
--- a/llvm/lib/MCCFIAnalysis/CMakeLists.txt
+++ b/llvm/lib/MCCFIAnalysis/CMakeLists.txt
@@ -8,5 +8,6 @@ add_llvm_component_library(LLVMMCCFIAnalysis
 
   LINK_COMPONENTS
   MC
+  DebugInfoDWARF
   Support
   )

>From 223f4f7a380be230c526b9bddf4e265315446f1f Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Fri, 13 Jun 2025 03:58:13 +0000
Subject: [PATCH 32/58] Use UnwindTable instead of CFI State:

- Change unwind table (by making small things public) to be usable from CFIAnalysis
- Remove CFIState internal DS and use UnwindTable instead
- Add a MCCFIInstruction -> CFIProgram::Instruction converter
- Refactor CFIAnalysis to use UnwindTable
---
 .../llvm/DebugInfo/DWARF/DWARFDebugFrame.h    |   2 +
 llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h |  20 +-
 .../MCCFIAnalysis/CFIAnalysisMCStreamer.h     |   6 +
 llvm/include/llvm/MCCFIAnalysis/CFIState.h    |  58 +---
 .../MCCFIAnalysis/ExtendedMCInstrAnalysis.h   |   3 +-
 llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp        | 229 ++++++++------
 .../MCCFIAnalysis/CFIAnalysisMCStreamer.cpp   |   2 +-
 llvm/lib/MCCFIAnalysis/CFIState.cpp           | 284 ++++++------------
 .../cfi-validation/single-func-cfa-mistake.s  |   4 +-
 .../single-func-missed-cfi-directive.s        |   3 +-
 .../cfi-validation/spill-two-reg-reversed.s   |  10 +-
 .../cfi-validation/update-with-no-cfi.s       |   8 +-
 12 files changed, 284 insertions(+), 345 deletions(-)

diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h
index 3b367009a379d..c87abb010f039 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h
@@ -138,6 +138,7 @@ class UnwindLocation {
     return *AddrSpace;
   }
   int32_t getConstant() const { return Offset; }
+  bool getDereference() const { return Dereference; }
   /// Some opcodes will modify the CFA location's register only, so we need
   /// to be able to modify the CFA register when evaluating DWARF Call Frame
   /// Information opcodes.
@@ -333,6 +334,7 @@ class UnwindTable {
     assert(Index < size());
     return Rows[Index];
   }
+  void insertRow(UnwindRow Row) { Rows.push_back(Row); }
 
   /// Dump the UnwindTable to the stream.
   ///
diff --git a/llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h b/llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h
index 180296755665e..9642a3fafabb6 100644
--- a/llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h
+++ b/llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h
@@ -5,6 +5,7 @@
 #include "ExtendedMCInstrAnalysis.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/SmallVector.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCDwarf.h"
 #include "llvm/MC/MCExpr.h"
@@ -21,7 +22,7 @@
 namespace llvm {
 
 class CFIAnalysis {
-  MCContext &Context;
+  MCContext *Context;
   MCInstrInfo const &MCII;
   MCRegisterInfo const *MCRI;
   std::unique_ptr<ExtendedMCInstrAnalysis> EMCIA;
@@ -42,19 +43,22 @@ class CFIAnalysis {
   MCPhysReg getSuperReg(MCPhysReg Reg);
 
 public:
-  CFIAnalysis(MCContext &Context, MCInstrInfo const &MCII,
+  CFIAnalysis(MCContext *Context, MCInstrInfo const &MCII,
               MCInstrAnalysis *MCIA,
               ArrayRef<MCCFIInstruction> PrologueCFIDirectives);
 
   void update(const MCInst &Inst, ArrayRef<MCCFIInstruction> CFIDirectives);
 
 private:
-  void checkRegDiff(const MCInst &Inst, DWARFRegType Reg,
-                    const CFIState &PrevState, const CFIState &NextState,
-                    const RegisterCFIState &PrevRegState,
-                    const RegisterCFIState &NextRegState,
-                    const std::set<DWARFRegType> &Reads,
-                    const std::set<DWARFRegType> &Writes);
+  void checkRegDiff(
+      const MCInst &Inst, DWARFRegType Reg, const CFIState &PrevState,
+      const CFIState &NextState,
+      const dwarf::UnwindLocation
+          &PrevRegState, // TODO maybe should get them from prev next state
+      const dwarf::UnwindLocation
+          &NextRegState, // TODO themselves instead of by arguments.
+      const std::set<DWARFRegType> &Reads,
+      const std::set<DWARFRegType> &Writes);
 
   void checkCFADiff(const MCInst &Inst, const CFIState &PrevState,
                     const CFIState &NextState,
diff --git a/llvm/include/llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h b/llvm/include/llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h
index a5aecd05f41d5..895457bda3703 100644
--- a/llvm/include/llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h
+++ b/llvm/include/llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h
@@ -14,6 +14,12 @@
 
 namespace llvm {
 
+// TODO Now the design is that the streamer, make instances of the analysis and
+// TODO run the analysis on the instruction, but instead the streamer should
+// TODO divide the program into function units, and then emit the function units
+// TODO one by one. Also in each function unit, an instruction with associated
+// TODO directives should be emitted. The analysis should be run by the
+// TODO receiver.
 class CFIAnalysisMCStreamer : public MCStreamer {
   MCInstrInfo const &MCII;
   std::unique_ptr<MCInstrAnalysis> MCIA;
diff --git a/llvm/include/llvm/MCCFIAnalysis/CFIState.h b/llvm/include/llvm/MCCFIAnalysis/CFIState.h
index cfe2aacf02ce6..7da036c0009e8 100644
--- a/llvm/include/llvm/MCCFIAnalysis/CFIState.h
+++ b/llvm/include/llvm/MCCFIAnalysis/CFIState.h
@@ -1,65 +1,37 @@
 #ifndef LLVM_TOOLS_LLVM_MC_CFI_STATE_H
 #define LLVM_TOOLS_LLVM_MC_CFI_STATE_H
 
-#include "llvm/ADT/DenseMap.h"
 #include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCDwarf.h"
 #include <optional>
-#include <string>
 namespace llvm {
 
 using DWARFRegType = int64_t;
 
-dwarf::CFIProgram convertMC2DWARF(MCContext &Context,
-                                  MCCFIInstruction CFIDirective,
-                                  int64_t CFAOffset);
+class CFIState {
+private:
+  MCContext *Context;
+  // TODO the choice is questionable, should the state be the Table? or just a
+  // TODO row? In the current code we are using only the last row.
+  dwarf::UnwindTable State;
 
-struct RegisterCFIState {
-  enum Approach {
-    Undefined,
-    SameValue,
-    AnotherRegister,
-    OffsetFromCFAAddr,
-    OffsetFromCFAVal,
-    Other,
-  } RetrieveApproach;
+public:
+  std::optional<dwarf::UnwindRow>
+  getLastRow() const; // TODO maybe move it UnwindRow
 
-  union {
-    int OffsetFromCFA;
-    DWARFRegType Register;
-  } Info;
-
-  // TODO change it to be like other dump methods
-  std::string dump();
-
-  bool operator==(const RegisterCFIState &OtherState) const;
-  bool operator!=(const RegisterCFIState &OtherState) const;
-
-  static RegisterCFIState createUndefined();
-  static RegisterCFIState createSameValue();
-  static RegisterCFIState createAnotherRegister(DWARFRegType Register);
-  static RegisterCFIState createOffsetFromCFAAddr(int OffsetFromCFA);
-  static RegisterCFIState createOffsetFromCFAVal(int OffsetFromCFA);
-  static RegisterCFIState createOther();
-};
-
-struct CFIState {
-  DenseMap<DWARFRegType, RegisterCFIState> RegisterCFIStates;
-  DWARFRegType CFARegister;
-  int CFAOffset;
-
-  CFIState();
+  CFIState(MCContext *Context) : Context(Context) {};
   CFIState(const CFIState &Other);
-
   CFIState &operator=(const CFIState &Other);
 
-  CFIState(DWARFRegType CFARegister, int CFIOffset);
-
   std::optional<DWARFRegType>
   getReferenceRegisterForCallerValueOfRegister(DWARFRegType Reg) const;
 
-  bool apply(const MCCFIInstruction &CFIDirective);
+  void apply(const MCCFIInstruction &CFIDirective);
+
+private:
+  std::optional<dwarf::CFIProgram> convertMC2DWARF(
+      MCCFIInstruction CFIDirective); // TODO maybe move it somewhere else
 };
 } // namespace llvm
 
diff --git a/llvm/include/llvm/MCCFIAnalysis/ExtendedMCInstrAnalysis.h b/llvm/include/llvm/MCCFIAnalysis/ExtendedMCInstrAnalysis.h
index 4d8ed38513d2a..12d6227922a2b 100644
--- a/llvm/include/llvm/MCCFIAnalysis/ExtendedMCInstrAnalysis.h
+++ b/llvm/include/llvm/MCCFIAnalysis/ExtendedMCInstrAnalysis.h
@@ -11,10 +11,11 @@
 
 namespace llvm {
 
+// TODO remove this class entirely
 class ExtendedMCInstrAnalysis {
 private:
 public:
-  ExtendedMCInstrAnalysis(MCContext &Context, MCInstrInfo const &MCII,
+  ExtendedMCInstrAnalysis(MCContext *Context, MCInstrInfo const &MCII,
                           MCInstrAnalysis *MCIA) {}
 
   /// Extra semantic information needed from MC layer:
diff --git a/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp b/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp
index 1a5785e4eac0c..80403c341707c 100644
--- a/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp
+++ b/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp
@@ -3,6 +3,7 @@
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/Twine.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
 #include "llvm/MC/MCAsmInfo.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCDwarf.h"
@@ -14,10 +15,12 @@
 #include "llvm/MC/MCStreamer.h"
 #include "llvm/MC/MCSubtargetInfo.h"
 #include "llvm/MC/TargetRegistry.h"
+#include "llvm/MCCFIAnalysis/CFIState.h"
 #include "llvm/MCCFIAnalysis/ExtendedMCInstrAnalysis.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/FormatVariadic.h"
+#include <cstdint>
 #include <memory>
 #include <optional>
 #include <set>
@@ -63,10 +66,11 @@ MCPhysReg CFIAnalysis::getSuperReg(MCPhysReg Reg) {
   llvm_unreachable("Should either be a super reg, or have a super reg");
 }
 
-CFIAnalysis::CFIAnalysis(MCContext &Context, MCInstrInfo const &MCII,
+CFIAnalysis::CFIAnalysis(MCContext *Context, MCInstrInfo const &MCII,
                          MCInstrAnalysis *MCIA,
                          ArrayRef<MCCFIInstruction> PrologueCFIDirectives)
-    : Context(Context), MCII(MCII), MCRI(Context.getRegisterInfo()) {
+    : Context(Context), MCII(MCII), MCRI(Context->getRegisterInfo()),
+      State(Context) {
   EMCIA.reset(new ExtendedMCInstrAnalysis(Context, MCII, MCIA));
 
   // TODO check what should be passed as EH? I am putting false everywhere.
@@ -75,27 +79,34 @@ CFIAnalysis::CFIAnalysis(MCContext &Context, MCInstrInfo const &MCII,
       continue;
 
     DWARFRegType DwarfReg = MCRI->getDwarfRegNum(Reg, false);
-    State.RegisterCFIStates[DwarfReg] = RegisterCFIState::createSameValue();
+    // TODO is it OK to create fake CFI directives for doing this?
+    State.apply(MCCFIInstruction::createSameValue(nullptr, DwarfReg));
   }
 
   for (auto &&InitialFrameStateCFIDirective :
-       Context.getAsmInfo()->getInitialFrameState()) {
+       Context->getAsmInfo()->getInitialFrameState()) {
     State.apply(InitialFrameStateCFIDirective);
   }
 
   // TODO these are temporay added to make things work.
   // Setup the basic information:
-  State.RegisterCFIStates[MCRI->getDwarfRegNum(MCRI->getProgramCounter(),
-                                               false)] =
-      RegisterCFIState::createUndefined(); // TODO for now, we don't care
-                                           // about the PC
-  State.RegisterCFIStates[MCRI->getDwarfRegNum(State.CFARegister,
-                                               false)] =
-      RegisterCFIState::createOffsetFromCFAVal(0); // sp's old value is CFA
-
-  // State.RegisterCFIStates[MCRI->getDwarfRegNum(EMCIA->getFlagsReg(), false)]
-  // =
-  //     RegisterCFIState::createUndefined(); // Flags cannot be caller-saved
+  State.apply(MCCFIInstruction::createUndefined(
+      nullptr,
+      MCRI->getDwarfRegNum(MCRI->getProgramCounter(),
+                           false))); // TODO for now, we don't care about the PC
+  // TODO
+  auto LastRow = State.getLastRow();
+  assert(LastRow && "there should be at least one row");
+  // TODO assert that CFA is there, and based on register.
+  // TODO
+
+  State.apply(MCCFIInstruction::createOffset(
+      nullptr, LastRow->getCFAValue().getRegister(),
+      0)); // sp's old value is CFA
+
+  State.apply(MCCFIInstruction::createUndefined(
+      nullptr, MCRI->getDwarfRegNum(EMCIA->getFlagsReg(),
+                                    false))); // Flags cannot be caller-saved
 
   // Applying the prologue after default assumptions to overwrite them.
   for (auto &&PrologueCFIDirective : PrologueCFIDirectives) {
@@ -108,11 +119,13 @@ void CFIAnalysis::update(const MCInst &Inst,
   const MCInstrDesc &MCInstInfo = MCII.get(Inst.getOpcode());
   CFIState AfterState(State);
   for (auto &&CFIDirective : CFIDirectives)
-    if (!AfterState.apply(CFIDirective))
-      Context.reportWarning(
-          CFIDirective.getLoc(),
-          "I don't support this CFI directive, I assume this does nothing "
-          "(which will probably break other things)");
+    AfterState.apply(CFIDirective);
+
+  //! if (!AfterState.apply(CFIDirective))
+  //!     Context->reportWarning(
+  //!         CFIDirective.getLoc(),
+  //!         "I don't support this CFI directive, I assume this does nothing "
+  //!         "(which will probably break other things)");
 
   std::set<DWARFRegType> Writes, Reads;
   for (unsigned I = 0; I < MCInstInfo.NumImplicitUses; I++)
@@ -136,29 +149,45 @@ void CFIAnalysis::update(const MCInst &Inst,
 
   checkCFADiff(Inst, State, AfterState, Reads, Writes);
 
-  for (auto &&[Reg, RegState] : State.RegisterCFIStates) {
-    assert(AfterState.RegisterCFIStates.count(Reg) &&
-           "Registers' state should not be deleted by CFI instruction.");
-    checkRegDiff(Inst, Reg, State, AfterState, RegState,
-                 AfterState.RegisterCFIStates[Reg], Reads, Writes);
+  for (auto [LLVMReg, _] : getAllSuperRegs()) {
+    DWARFRegType Reg = MCRI->getDwarfRegNum(LLVMReg, false);
+
+    auto PrevUnwindLoc =
+        State.getLastRow()->getRegisterLocations().getRegisterLocation(Reg);
+    auto NextUnwindLoc =
+        AfterState.getLastRow()->getRegisterLocations().getRegisterLocation(
+            Reg);
+
+    // TODO think more if these assertions are OK
+    // TODO maybe change them to error messages.
+    if (!PrevUnwindLoc) {
+      assert(
+          !NextUnwindLoc &&
+          "A CFI directive should not define a new register out of thin air.");
+      continue;
+    }
+    assert(NextUnwindLoc &&
+           "A CFI directive should not delete a register state.");
+
+    checkRegDiff(Inst, Reg, State, AfterState, PrevUnwindLoc.value(),
+                 NextUnwindLoc.value(), Reads, Writes);
   }
 
   State = AfterState;
 }
 
-void CFIAnalysis::checkRegDiff(const MCInst &Inst, DWARFRegType Reg,
-                               const CFIState &PrevState,
-                               const CFIState &NextState,
-                               const RegisterCFIState &PrevRegState,
-                               const RegisterCFIState &NextRegState,
-                               const std::set<DWARFRegType> &Reads,
-                               const std::set<DWARFRegType> &Writes) {
+void CFIAnalysis::checkRegDiff(
+    const MCInst &Inst, DWARFRegType Reg, const CFIState &PrevState,
+    const CFIState &NextState,
+    const dwarf::UnwindLocation &PrevRegState, // TODO maybe re-name
+    const dwarf::UnwindLocation &NextRegState, // TODO maybe re-name
+    const std::set<DWARFRegType> &Reads, const std::set<DWARFRegType> &Writes) {
   auto RegLLVMOpt = MCRI->getLLVMRegNum(Reg, false);
   if (RegLLVMOpt == std::nullopt) {
     assert(PrevRegState == NextRegState);
     return;
   }
-  MCPhysReg RegLLVM = RegLLVMOpt.value();
+  const char *RegLLVMName = MCRI->getName(RegLLVMOpt.value());
 
   auto &&PrevRefReg =
       PrevState.getReferenceRegisterForCallerValueOfRegister(Reg);
@@ -174,35 +203,50 @@ void CFIAnalysis::checkRegDiff(const MCInst &Inst, DWARFRegType Reg,
                  MCRI->getLLVMRegNum(PrevRefReg.value(), false).value())
            : std::nullopt);
 
+  // TODO Again getting CFA register out of UnwindRow
+  // TODO consider either making it a help function.
+  // TODO Also, again you have to re-look in the assumption
+  // TODO that CFA is depending on another register, maybe
+  // TODO it's not true. And if it's always true, consider
+  // TODO asserting it (maybe in the helper function).
   MCPhysReg PrevStateCFARegLLVM =
-      MCRI->getLLVMRegNum(PrevState.CFARegister, false).value();
+      MCRI->getLLVMRegNum(PrevState.getLastRow()->getCFAValue().getRegister(),
+                          false)
+          .value();
 
   { // try generate
     // Widen
-    std::vector<RegisterCFIState> PossibleNextRegStates;
+    std::vector<dwarf::UnwindLocation> PossibleNextRegStates;
 
     { // stay the same
-      bool CanStayTheSame = false;
-
-      switch (PrevRegState.RetrieveApproach) {
-      case RegisterCFIState::Undefined:
-      case RegisterCFIState::OffsetFromCFAVal:
-        CanStayTheSame = true;
-        break;
-      case RegisterCFIState::SameValue:
-      case RegisterCFIState::AnotherRegister:
-        CanStayTheSame = !Writes.count(PrevRefReg.value());
-        break;
-      case RegisterCFIState::OffsetFromCFAAddr:
-      case RegisterCFIState::Other:
-        // cannot be sure
-        break;
+      bool CanStayTheSame = true;
+
+      // TODO make sure it has meaning in `Undefined` or `Unspecified` case.
+      // TODO make it smarter, if it's in the memory and the instruction does
+      // TODO not store anything and the register (if any) to access that part
+      // TODO is not changed, then it's OK.
+      if (PrevRegState.getDereference())
+        CanStayTheSame = false;
+
+      if (PrevRefReg && Writes.count(PrevRefReg.value())) {
+        CanStayTheSame = false;
+      }
+
+      if (PrevRegState.getLocation() == dwarf::UnwindLocation::DWARFExpr) {
+        // TODO this can be solved more precise, by looking into the expression,
+        // TODO finding registers that are used and checking if the instruction
+        // TODO is changing them or not.
+        CanStayTheSame = false;
       }
 
       if (CanStayTheSame)
         PossibleNextRegStates.push_back(PrevRegState);
     }
 
+    // TODO In this stage of program, there is not possible next stages, it's
+    // TODO either the same or nothing. The maybe I have to refactor it back to
+    // TODO the primitive design. And when got the semantic info, get back to
+    // TODO this code.
     for (auto &&PossibleNextRegState : PossibleNextRegStates) {
       if (PossibleNextRegState == NextRegState) {
         // Everything is ok
@@ -211,19 +255,19 @@ void CFIAnalysis::checkRegDiff(const MCInst &Inst, DWARFRegType Reg,
     }
 
     for (auto &&PossibleNextRegState : PossibleNextRegStates) {
-      if (PossibleNextRegState.RetrieveApproach !=
-          NextRegState.RetrieveApproach)
+      if (PossibleNextRegState.getLocation() != NextRegState.getLocation())
         continue;
 
-      if (PossibleNextRegState.RetrieveApproach ==
-          RegisterCFIState::OffsetFromCFAAddr) {
-        Context.reportError(
+      // TODO again, as said above, does this happen in the current primitive
+      // TODO design?
+      if (PossibleNextRegState.getLocation() ==
+          dwarf::UnwindLocation::CFAPlusOffset) {
+        Context->reportError(
             Inst.getLoc(),
-            formatv(
-                "Expected caller's value of reg#{0} should be at offset {1} "
-                "of CFA but the CFI directives say it's in {2}",
-                RegLLVM, PossibleNextRegState.Info.OffsetFromCFA,
-                NextRegState.Info.OffsetFromCFA));
+            formatv("Expected %{0} unwinding rule should be [CFA + {1}] but "
+                    "based CFI directives are [CFA + {2}]",
+                    RegLLVMName, PossibleNextRegState.getOffset(),
+                    NextRegState.getOffset()));
       }
     }
   }
@@ -232,18 +276,19 @@ void CFIAnalysis::checkRegDiff(const MCInst &Inst, DWARFRegType Reg,
   // it falls back into read/write checks.
 
   if (PrevRegState == NextRegState) {
-    switch (PrevRegState.RetrieveApproach) {
-    case RegisterCFIState::SameValue:
-    case RegisterCFIState::AnotherRegister:
+    switch (PrevRegState.getLocation()) {
+    case dwarf::UnwindLocation::Same:
+    case dwarf::UnwindLocation::RegPlusOffset:
       if (Writes.count(PrevRefReg.value())) {
-        Context.reportError(
+        Context->reportError(
             Inst.getLoc(),
-            formatv("Reg#{0} caller's value is in reg#{1} which is changed "
-                    "by this instruction, but not changed in CFI directives",
-                    RegLLVM, PrevRefRegLLVM.value()));
+            formatv("This instruction changes %{1}, that %{0} unwinding rule "
+                    "uses, but there is no CFI directives about it",
+                    RegLLVMName, MCRI->getName(PrevRefRegLLVM.value())));
         return;
       }
       break;
+      // TODO think about what to do with expressions here.
     default:
       // Everything may be ok
       break;
@@ -251,22 +296,21 @@ void CFIAnalysis::checkRegDiff(const MCInst &Inst, DWARFRegType Reg,
     return;
   }
 
-  if (PrevRegState.RetrieveApproach == NextRegState.RetrieveApproach) {
+  if (PrevRegState.getLocation() == NextRegState.getLocation()) {
     // Everything may be ok
     return;
   }
 
-  if (PrevRegState.RetrieveApproach == RegisterCFIState::Undefined) {
-    Context.reportError(Inst.getLoc(),
-                        "Cannot change a register CFI information from "
-                        "undefined to something else.");
+  if (PrevRegState.getLocation() == dwarf::UnwindLocation::Undefined) {
+    Context->reportError(
+        Inst.getLoc(),
+        "Changed %{0} unwinding rule from `undefined` to something else");
     return;
   }
 
-  Context.reportWarning(Inst.getLoc(),
-                        formatv("The reg#{0} CFI state is changed, but I "
-                                "don't have any idea how.",
-                                RegLLVM));
+  Context->reportWarning(
+      Inst.getLoc(),
+      formatv("Unknown change happened to %{0} unwinding rule", RegLLVMName));
   // Everything may be ok
   return;
 }
@@ -275,16 +319,27 @@ void CFIAnalysis::checkCFADiff(const MCInst &Inst, const CFIState &PrevState,
                                const CFIState &NextState,
                                const std::set<DWARFRegType> &Reads,
                                const std::set<DWARFRegType> &Writes) {
+  // TODO again getting the CFA register in the bad way.
+  const DWARFRegType PrevCFAReg =
+      PrevState.getLastRow()->getCFAValue().getRegister();
+  const int32_t PrevCFAOffset =
+      PrevState.getLastRow()->getCFAValue().getOffset();
+
+  const DWARFRegType NextCFAReg =
+      NextState.getLastRow()->getCFAValue().getRegister();
+  const int32_t NextCFAOffset =
+      NextState.getLastRow()->getCFAValue().getOffset();
+
   const char *PrevCFARegName =
-      MCRI->getName(MCRI->getLLVMRegNum(PrevState.CFARegister, false).value());
+      MCRI->getName(MCRI->getLLVMRegNum(PrevCFAReg, false /* TODO */).value());
 
-  if (PrevState.CFARegister == NextState.CFARegister) {
-    if (PrevState.CFAOffset == NextState.CFAOffset) {
-      if (Writes.count(PrevState.CFARegister)) {
-        Context.reportError(
+  if (PrevCFAReg == NextCFAReg) {
+    if (PrevCFAOffset == NextCFAOffset) {
+      if (Writes.count(PrevCFAReg)) {
+        Context->reportError(
             Inst.getLoc(),
-            formatv("Missing CFI directive for the CFA offset adjustment. CFA "
-                    "register ({0}) is modified by this instruction.",
+            formatv("This instruction modifies CFA register (%{0}) "
+                    "but CFA rule is not changed",
                     PrevCFARegName));
         return;
       }
@@ -294,11 +349,11 @@ void CFIAnalysis::checkCFADiff(const MCInst &Inst, const CFIState &PrevState,
     }
     // The offset is changed.
 
-    if (!Writes.count(PrevState.CFARegister)) {
-      Context.reportError(
+    if (!Writes.count(PrevCFAReg)) {
+      Context->reportError(
           Inst.getLoc(),
-          formatv("Wrong adjustment to CFA offset. CFA register ({0}) is not "
-                  "modified by this instruction.",
+          formatv("This instruction does not modifies CFA register (%{0}) "
+                  "but CFA rule is changed",
                   PrevCFARegName));
     }
 
diff --git a/llvm/lib/MCCFIAnalysis/CFIAnalysisMCStreamer.cpp b/llvm/lib/MCCFIAnalysis/CFIAnalysisMCStreamer.cpp
index 43855a4d75dc2..a2b5e308883d6 100644
--- a/llvm/lib/MCCFIAnalysis/CFIAnalysisMCStreamer.cpp
+++ b/llvm/lib/MCCFIAnalysis/CFIAnalysisMCStreamer.cpp
@@ -71,7 +71,7 @@ void CFIAnalysisMCStreamer::feedCFIA() {
 
     CFIAs.back().update(LastInstruction.value(), CFIDirectives);
   } else {
-    CFIAs.emplace_back(getContext(), MCII, MCIA.get(), CFIDirectives);
+    CFIAs.emplace_back(&getContext(), MCII, MCIA.get(), CFIDirectives);
   }
 }
 
diff --git a/llvm/lib/MCCFIAnalysis/CFIState.cpp b/llvm/lib/MCCFIAnalysis/CFIState.cpp
index 4f4a6e168bef6..2d65d325cb22d 100644
--- a/llvm/lib/MCCFIAnalysis/CFIState.cpp
+++ b/llvm/lib/MCCFIAnalysis/CFIState.cpp
@@ -1,25 +1,88 @@
 // TODO check what includes to keep and what to remove
 #include "llvm/MCCFIAnalysis/CFIState.h"
-#include "llvm/ADT/DenseMap.h"
 #include "llvm/BinaryFormat/Dwarf.h"
 #include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
 #include "llvm/MC/MCDwarf.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/FormatVariadic.h"
 #include <cassert>
-#include <cstdint>
 #include <optional>
-#include <string>
 
 using namespace llvm;
 
-dwarf::CFIProgram llvm::convertMC2DWARF(MCContext &Context,
-                                        MCCFIInstruction CFIDirective,
-                                        int64_t CFAOffset) {
+CFIState::CFIState(const CFIState &Other) : Context(Other.Context) {
+  // TODO maybe remove it
+  State = Other.State;
+}
+
+CFIState &CFIState::operator=(const CFIState &Other) {
+  // TODO maybe remove it
+  if (this != &Other) {
+    State = Other.State;
+    Context = Other.Context;
+  }
+
+  return *this;
+}
+
+std::optional<DWARFRegType>
+CFIState::getReferenceRegisterForCallerValueOfRegister(DWARFRegType Reg) const {
+  // TODO maybe move it the Location class
+  auto LastRow = getLastRow();
+  assert(LastRow && "The state is empty.");
+
+  auto UnwinLoc = LastRow->getRegisterLocations().getRegisterLocation(Reg);
+  assert(UnwinLoc &&
+         "The register should be tracked inside the register states");
+
+  switch (UnwinLoc->getLocation()) {
+  case dwarf::UnwindLocation::Location::Undefined:
+  case dwarf::UnwindLocation::Location::Constant:
+  case dwarf::UnwindLocation::Location::Unspecified:
+    // TODO here should look into expr and find the registers, but for now it's
+    // TODO like this:
+  case dwarf::UnwindLocation::Location::DWARFExpr:
+    return std::nullopt;
+  case dwarf::UnwindLocation::Location::Same:
+    return Reg;
+  case dwarf::UnwindLocation::Location::RegPlusOffset:
+    return UnwinLoc->getRegister();
+  case dwarf::UnwindLocation::Location::CFAPlusOffset:
+    // TODO check if it's ok to assume CFA is always depending on other
+    // TODO register, if yes assert it here!
+    return LastRow->getCFAValue().getRegister();
+  }
+}
+
+void CFIState::apply(const MCCFIInstruction &CFIDirective) {
+  auto DwarfOperations = convertMC2DWARF(CFIDirective);
+  if (!DwarfOperations) {
+    Context->reportError(
+        CFIDirective.getLoc(),
+        "couldn't apply this directive to the unwinding information state");
+  }
+
+  auto &&LastRow = getLastRow();
+  dwarf::UnwindRow Row = LastRow ? LastRow.value() : dwarf::UnwindRow();
+  if (Error Err = State.parseRows(DwarfOperations.value(), Row, nullptr)) {
+    // ! FIXME what should I do with this error?
+    Context->reportError(
+        CFIDirective.getLoc(),
+        formatv("could not parse this CFI directive due to: {0}",
+                toString(std::move(Err))));
+    assert(false);
+  }
+  State.insertRow(Row);
+}
+
+std::optional<dwarf::CFIProgram>
+CFIState::convertMC2DWARF(MCCFIInstruction CFIDirective) {
   //! FIXME, this way of instantiating CFI program does not look right, either
   //! refactor CFIProgram to not depend on the Code/Data Alignment or add a new
   //! type that is independent from this and is also feedable to UnwindTable.
-  auto DwarfOperations =
-      dwarf::CFIProgram(0, 0, Context.getTargetTriple().getArch());
+  auto DwarfOperations = dwarf::CFIProgram(
+      1 /* TODO */, 1 /* TODO */, Context->getTargetTriple().getArch());
 
   switch (CFIDirective.getOperation()) {
   case MCCFIInstruction::OpSameValue:
@@ -42,7 +105,7 @@ dwarf::CFIProgram llvm::convertMC2DWARF(MCContext &Context,
                                    CFIDirective.getRegister());
     break;
   case MCCFIInstruction::OpDefCfaRegister:
-    DwarfOperations.addInstruction(dwarf::DW_CFA_def_cfa,
+    DwarfOperations.addInstruction(dwarf::DW_CFA_def_cfa_register,
                                    CFIDirective.getRegister());
     break;
   case MCCFIInstruction::OpDefCfaOffset:
@@ -55,13 +118,20 @@ dwarf::CFIProgram llvm::convertMC2DWARF(MCContext &Context,
                                    CFIDirective.getOffset());
     break;
   case MCCFIInstruction::OpRelOffset:
-    DwarfOperations.addInstruction(dwarf::DW_CFA_offset,
-                                   CFIDirective.getRegister(),
-                                   CFIDirective.getOffset() - CFAOffset);
+    if (!getLastRow()) // TODO maybe replace it with assert
+      return std::nullopt;
+
+    DwarfOperations.addInstruction(
+        dwarf::DW_CFA_offset, CFIDirective.getRegister(),
+        CFIDirective.getOffset() - getLastRow()->getCFAValue().getOffset());
     break;
   case MCCFIInstruction::OpAdjustCfaOffset:
+    if (!getLastRow()) // TODO maybe replace it with assert
+      return std::nullopt;
+
     DwarfOperations.addInstruction(dwarf::DW_CFA_def_cfa_offset,
-                                   CFIDirective.getOffset() + CFAOffset);
+                                   CFIDirective.getOffset() +
+                                       getLastRow()->getCFAValue().getOffset());
     break;
   case MCCFIInstruction::OpEscape:
     // TODO It's now feasible but for now, I ignore it
@@ -107,187 +177,11 @@ dwarf::CFIProgram llvm::convertMC2DWARF(MCContext &Context,
   return DwarfOperations;
 }
 
-using DWARFRegType = int64_t;
-
-std::string RegisterCFIState::dump() {
-  switch (RetrieveApproach) {
-  case Undefined:
-    return "undefined";
-  case SameValue:
-    return "same value";
-  case AnotherRegister:
-    return formatv("stored in another register, which is reg#{0}",
-                   Info.Register);
-  case OffsetFromCFAAddr:
-    return formatv("offset {0} from CFA", Info.OffsetFromCFA);
-  case OffsetFromCFAVal:
-    return formatv("CFA value + {0}", Info.OffsetFromCFA);
-  case Other:
-    return "other";
-  }
-}
-
-bool RegisterCFIState::operator==(const RegisterCFIState &OtherState) const {
-  if (RetrieveApproach != OtherState.RetrieveApproach)
-    return false;
-
-  switch (RetrieveApproach) {
-  case Undefined:
-  case SameValue:
-  case Other:
-    return true;
-  case AnotherRegister:
-    return Info.Register == OtherState.Info.Register;
-  case OffsetFromCFAAddr:
-  case OffsetFromCFAVal:
-    return Info.OffsetFromCFA == OtherState.Info.OffsetFromCFA;
-  }
-}
-
-bool RegisterCFIState::operator!=(const RegisterCFIState &OtherState) const {
-  return !(*this == OtherState);
-}
-
-RegisterCFIState RegisterCFIState::createUndefined() {
-  RegisterCFIState State;
-  State.RetrieveApproach = Undefined;
-
-  return State;
-}
-
-RegisterCFIState RegisterCFIState::createSameValue() {
-  RegisterCFIState State;
-  State.RetrieveApproach = SameValue;
-
-  return State;
-}
-
-RegisterCFIState
-RegisterCFIState::createAnotherRegister(DWARFRegType Register) {
-  RegisterCFIState State;
-  State.RetrieveApproach = AnotherRegister;
-  State.Info.Register = Register;
-
-  return State;
-}
-
-RegisterCFIState RegisterCFIState::createOffsetFromCFAAddr(int OffsetFromCFA) {
-  RegisterCFIState State;
-  State.RetrieveApproach = OffsetFromCFAAddr;
-  State.Info.OffsetFromCFA = OffsetFromCFA;
-
-  return State;
-}
-
-RegisterCFIState RegisterCFIState::createOffsetFromCFAVal(int OffsetFromCFA) {
-  RegisterCFIState State;
-  State.RetrieveApproach = OffsetFromCFAVal;
-  State.Info.OffsetFromCFA = OffsetFromCFA;
-
-  return State;
-}
-
-RegisterCFIState RegisterCFIState::createOther() {
-  RegisterCFIState State;
-  State.RetrieveApproach = Other;
-
-  return State;
-}
-
-CFIState::CFIState() : CFARegister(-1), CFAOffset(-1) {}
-
-CFIState::CFIState(const CFIState &Other) {
-  CFARegister = Other.CFARegister;
-  CFAOffset = Other.CFAOffset;
-  RegisterCFIStates = Other.RegisterCFIStates;
-}
-
-CFIState &CFIState::operator=(const CFIState &Other) {
-  if (this != &Other) {
-    CFARegister = Other.CFARegister;
-    CFAOffset = Other.CFAOffset;
-    RegisterCFIStates = Other.RegisterCFIStates;
-  }
-
-  return *this;
-}
-
-CFIState::CFIState(DWARFRegType CFARegister, int CFIOffset)
-    : CFARegister(CFARegister), CFAOffset(CFIOffset) {}
-
-std::optional<DWARFRegType>
-CFIState::getReferenceRegisterForCallerValueOfRegister(DWARFRegType Reg) const {
-  assert(RegisterCFIStates.count(Reg) &&
-         "The register should be tracked inside the register states");
-  auto &&RegState = RegisterCFIStates.at(Reg);
-  switch (RegState.RetrieveApproach) {
-  case RegisterCFIState::Undefined:
-  case RegisterCFIState::Other:
+std::optional<dwarf::UnwindRow> CFIState::getLastRow() const {
+  if (!State.size())
     return std::nullopt;
-  case RegisterCFIState::SameValue:
-    return Reg;
-  case RegisterCFIState::AnotherRegister:
-    return RegState.Info.Register;
-  case RegisterCFIState::OffsetFromCFAAddr:
-  case RegisterCFIState::OffsetFromCFAVal:
-    return CFARegister;
-  }
-}
 
-bool CFIState::apply(const MCCFIInstruction &CFIDirective) {
-  switch (CFIDirective.getOperation()) {
-  case MCCFIInstruction::OpDefCfaRegister:
-    CFARegister = CFIDirective.getRegister();
-    break;
-  case MCCFIInstruction::OpDefCfaOffset:
-    CFAOffset = CFIDirective.getOffset();
-    break;
-  case MCCFIInstruction::OpAdjustCfaOffset:
-    CFAOffset += CFIDirective.getOffset();
-    break;
-  case MCCFIInstruction::OpDefCfa:
-    CFARegister = CFIDirective.getRegister();
-    CFAOffset = CFIDirective.getOffset();
-    break;
-  case MCCFIInstruction::OpOffset:
-    RegisterCFIStates[CFIDirective.getRegister()] =
-        RegisterCFIState::createOffsetFromCFAAddr(CFIDirective.getOffset());
-    break;
-  case MCCFIInstruction::OpRegister:
-    RegisterCFIStates[CFIDirective.getRegister()] =
-        RegisterCFIState::createAnotherRegister(CFIDirective.getRegister2());
-    break;
-  case MCCFIInstruction::OpRelOffset:
-    RegisterCFIStates[CFIDirective.getRegister()] =
-        RegisterCFIState::createOffsetFromCFAAddr(CFIDirective.getOffset() -
-                                                  CFAOffset);
-    break;
-  case MCCFIInstruction::OpUndefined:
-    RegisterCFIStates[CFIDirective.getRegister()] =
-        RegisterCFIState::createUndefined();
-    break;
-  case MCCFIInstruction::OpSameValue:
-    RegisterCFIStates[CFIDirective.getRegister()] =
-        RegisterCFIState::createSameValue();
-    break;
-  case MCCFIInstruction::OpValOffset:
-    RegisterCFIStates[CFIDirective.getRegister()] =
-        RegisterCFIState::createOffsetFromCFAVal(CFIDirective.getOffset());
-    break;
-  case MCCFIInstruction::OpRestoreState:
-  case MCCFIInstruction::OpRememberState:
-  case MCCFIInstruction::OpLLVMDefAspaceCfa:
-  case MCCFIInstruction::OpRestore:
-  case MCCFIInstruction::OpEscape:
-  case MCCFIInstruction::OpWindowSave:
-  case MCCFIInstruction::OpNegateRAState:
-  case MCCFIInstruction::OpNegateRAStateWithPC:
-  case MCCFIInstruction::OpGnuArgsSize:
-  case MCCFIInstruction::OpLabel:
-    // These instructions are not supported.
-    return false;
-    break;
-  }
-
-  return true;
-}
+  //! FIXME too dirty
+  auto &&it = State.end();
+  return *--it;
+}
\ No newline at end of file
diff --git a/llvm/test/tools/llvm-mc/cfi-validation/single-func-cfa-mistake.s b/llvm/test/tools/llvm-mc/cfi-validation/single-func-cfa-mistake.s
index eb55ff6b378e8..1e9ffecbed81b 100644
--- a/llvm/test/tools/llvm-mc/cfi-validation/single-func-cfa-mistake.s
+++ b/llvm/test/tools/llvm-mc/cfi-validation/single-func-cfa-mistake.s
@@ -1,4 +1,4 @@
-# RUN: not llvm-mc %s --validate-cfi --filetype=null 2>&1 \
+# RUN: llvm-mc %s --validate-cfi --filetype=null 2>&1 \
 # RUN:   | FileCheck %s 
         .text
         .globl  f
@@ -9,7 +9,7 @@ f:
         .cfi_undefined %rax
 
         pushq   %rbp
-        # CHECK: error: Expected CFA [reg: 61, offset: 16] but got [reg: 61, offset: 17]
+        # CHECK: warning: Unknown change happened to %RBP unwinding rule
         .cfi_def_cfa_offset 17
         .cfi_offset %rbp, -16
 
diff --git a/llvm/test/tools/llvm-mc/cfi-validation/single-func-missed-cfi-directive.s b/llvm/test/tools/llvm-mc/cfi-validation/single-func-missed-cfi-directive.s
index 044c0bbf88eb6..bacc78c146cc1 100644
--- a/llvm/test/tools/llvm-mc/cfi-validation/single-func-missed-cfi-directive.s
+++ b/llvm/test/tools/llvm-mc/cfi-validation/single-func-missed-cfi-directive.s
@@ -12,7 +12,7 @@ f:
         .cfi_def_cfa_offset 16
         
         movq    %rsp, %rbp
-        # CHECK: error: Reg#52 caller's value is in reg#52 which is changed by this instruction, but not changed in CFI directives
+        # CHECK: error: This instruction changes %RBP, that %RBP unwinding rule uses, but there is no CFI directives about it
         .cfi_def_cfa_register %rbp
         
         movl    %edi, -4(%rbp)
@@ -22,6 +22,7 @@ f:
         addl    $10, %eax
         
         popq    %rbp
+        # CHECK: error: This instruction changes %RBP, that %RBP unwinding rule uses, but there is no CFI directives about it
         .cfi_def_cfa %rsp, 8
         
         retq
diff --git a/llvm/test/tools/llvm-mc/cfi-validation/spill-two-reg-reversed.s b/llvm/test/tools/llvm-mc/cfi-validation/spill-two-reg-reversed.s
index d7baf3e871e87..30e74e5b159e7 100644
--- a/llvm/test/tools/llvm-mc/cfi-validation/spill-two-reg-reversed.s
+++ b/llvm/test/tools/llvm-mc/cfi-validation/spill-two-reg-reversed.s
@@ -11,31 +11,35 @@ _start:
         .cfi_same_value %rsi
 
         pushq   %rbp
+        # CHECK: warning: Unknown change happened to %RBP unwinding rule
         .cfi_adjust_cfa_offset 8
         .cfi_offset %rbp, -16
 
         movq    %rsp, %rbp
 
         pushq   %rdi
+        # CHECK: warning: Unknown change happened to %RDI unwinding rule
         .cfi_adjust_cfa_offset 8
         .cfi_rel_offset %rdi, 0
 
         pushq   %rsi
+        # CHECK: warning: Unknown change happened to %RSI unwinding rule
         .cfi_adjust_cfa_offset 8
         .cfi_rel_offset %rsi, 0
         
         popq    %rsi
-        # CHECK: warning: The reg#55 CFI state is changed
+        # CHECK: warning: Unknown change happened to %RDI unwinding rule
         .cfi_adjust_cfa_offset -8
         .cfi_same_value %rdi
 
         popq    %rdi
-        # CHECK: warning: The reg#60 CFI state is changed
-        # CHECK: Reg#55 caller's value is in reg#55 which is changed by this instruction, but not changed in CFI directives
+        # CHECK: error: This instruction changes %RDI, that %RDI unwinding rule uses, but there is no CFI directives about it
+        # CHECK: warning: Unknown change happened to %RSI unwinding rule
         .cfi_adjust_cfa_offset -8
         .cfi_same_value %rsi
 
         popq    %rbp
+        # CHECK: warning: Unknown change happened to %RBP unwinding rule
         .cfi_adjust_cfa_offset -8
         .cfi_same_value %rbp
 
diff --git a/llvm/test/tools/llvm-mc/cfi-validation/update-with-no-cfi.s b/llvm/test/tools/llvm-mc/cfi-validation/update-with-no-cfi.s
index 1384d8a864608..ebf4bf4ed5472 100644
--- a/llvm/test/tools/llvm-mc/cfi-validation/update-with-no-cfi.s
+++ b/llvm/test/tools/llvm-mc/cfi-validation/update-with-no-cfi.s
@@ -12,16 +12,16 @@ f:
         .cfi_same_value %rdx
 
         movq $10, %rax
-        # CHECK: error: Reg#51 caller's value is in reg#51 which is changed by this instruction, but not changed in CFI directives
+        # CHECK: error: This instruction changes %RAX, that %RAX unwinding rule uses, but there is no CFI directives about it
 
         movq $10, %rbx
-        # CHECK: error: Reg#53 caller's value is in reg#53 which is changed by this instruction, but not changed in CFI directives
+        # CHECK: error: This instruction changes %RBX, that %RBX unwinding rule uses, but there is no CFI directives about it
 
         movq $10, %rcx
-        # CHECK: error: Reg#54 caller's value is in reg#54 which is changed by this instruction, but not changed in CFI directives
+        # CHECK: error: This instruction changes %RCX, that %RCX unwinding rule uses, but there is no CFI directives about it
 
         movq $10, %rdx
-        # CHECK: error: Reg#56 caller's value is in reg#56 which is changed by this instruction, but not changed in CFI directives
+        # CHECK: error: This instruction changes %RDX, that %RDX unwinding rule uses, but there is no CFI directives about it
 
         retq
 

>From 6b727ec9eb95fe74d7facbd4288cafcac9e65126 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Tue, 17 Jun 2025 18:21:50 +0000
Subject: [PATCH 33/58] Make CFI analysis available both EH and Debug frames

---
 llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h |  3 +-
 llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp        | 38 +++++++++----------
 .../MCCFIAnalysis/CFIAnalysisMCStreamer.cpp   |  3 +-
 3 files changed, 22 insertions(+), 22 deletions(-)

diff --git a/llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h b/llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h
index 9642a3fafabb6..46e2c0a2c0656 100644
--- a/llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h
+++ b/llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h
@@ -27,6 +27,7 @@ class CFIAnalysis {
   MCRegisterInfo const *MCRI;
   std::unique_ptr<ExtendedMCInstrAnalysis> EMCIA;
   CFIState State;
+  bool IsEH;
 
 private:
   // The CFI analysis only keeps track and cares about super registers, not the
@@ -44,7 +45,7 @@ class CFIAnalysis {
 
 public:
   CFIAnalysis(MCContext *Context, MCInstrInfo const &MCII,
-              MCInstrAnalysis *MCIA,
+              MCInstrAnalysis *MCIA, bool IsEH,
               ArrayRef<MCCFIInstruction> PrologueCFIDirectives);
 
   void update(const MCInst &Inst, ArrayRef<MCCFIInstruction> CFIDirectives);
diff --git a/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp b/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp
index 80403c341707c..7e07d846860dc 100644
--- a/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp
+++ b/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp
@@ -67,18 +67,17 @@ MCPhysReg CFIAnalysis::getSuperReg(MCPhysReg Reg) {
 }
 
 CFIAnalysis::CFIAnalysis(MCContext *Context, MCInstrInfo const &MCII,
-                         MCInstrAnalysis *MCIA,
+                         MCInstrAnalysis *MCIA, bool IsEH,
                          ArrayRef<MCCFIInstruction> PrologueCFIDirectives)
     : Context(Context), MCII(MCII), MCRI(Context->getRegisterInfo()),
-      State(Context) {
+      State(Context), IsEH(IsEH) {
   EMCIA.reset(new ExtendedMCInstrAnalysis(Context, MCII, MCIA));
 
-  // TODO check what should be passed as EH? I am putting false everywhere.
   for (auto &&[Reg, RegClass] : getAllSuperRegs()) {
     if (MCRI->get(Reg).IsArtificial || MCRI->get(Reg).IsConstant)
       continue;
 
-    DWARFRegType DwarfReg = MCRI->getDwarfRegNum(Reg, false);
+    DWARFRegType DwarfReg = MCRI->getDwarfRegNum(Reg, IsEH);
     // TODO is it OK to create fake CFI directives for doing this?
     State.apply(MCCFIInstruction::createSameValue(nullptr, DwarfReg));
   }
@@ -93,7 +92,7 @@ CFIAnalysis::CFIAnalysis(MCContext *Context, MCInstrInfo const &MCII,
   State.apply(MCCFIInstruction::createUndefined(
       nullptr,
       MCRI->getDwarfRegNum(MCRI->getProgramCounter(),
-                           false))); // TODO for now, we don't care about the PC
+                           IsEH))); // TODO for now, we don't care about the PC
   // TODO
   auto LastRow = State.getLastRow();
   assert(LastRow && "there should be at least one row");
@@ -106,7 +105,7 @@ CFIAnalysis::CFIAnalysis(MCContext *Context, MCInstrInfo const &MCII,
 
   State.apply(MCCFIInstruction::createUndefined(
       nullptr, MCRI->getDwarfRegNum(EMCIA->getFlagsReg(),
-                                    false))); // Flags cannot be caller-saved
+                                    IsEH))); // Flags cannot be caller-saved
 
   // Applying the prologue after default assumptions to overwrite them.
   for (auto &&PrologueCFIDirective : PrologueCFIDirectives) {
@@ -129,28 +128,27 @@ void CFIAnalysis::update(const MCInst &Inst,
 
   std::set<DWARFRegType> Writes, Reads;
   for (unsigned I = 0; I < MCInstInfo.NumImplicitUses; I++)
-    Reads.insert(MCRI->getDwarfRegNum(
-        getSuperReg(MCInstInfo.implicit_uses()[I]), false));
+    Reads.insert(
+        MCRI->getDwarfRegNum(getSuperReg(MCInstInfo.implicit_uses()[I]), IsEH));
   for (unsigned I = 0; I < MCInstInfo.NumImplicitDefs; I++)
-    Writes.insert(MCRI->getDwarfRegNum(
-        getSuperReg(MCInstInfo.implicit_defs()[I]), false));
+    Writes.insert(
+        MCRI->getDwarfRegNum(getSuperReg(MCInstInfo.implicit_defs()[I]), IsEH));
 
   for (unsigned I = 0; I < Inst.getNumOperands(); I++) {
     auto &&Operand = Inst.getOperand(I);
     if (Operand.isReg()) {
       if (I < MCInstInfo.getNumDefs())
         Writes.insert(
-            MCRI->getDwarfRegNum(getSuperReg(Operand.getReg()), false));
+            MCRI->getDwarfRegNum(getSuperReg(Operand.getReg()), IsEH));
       else if (Operand.getReg())
-        Reads.insert(
-            MCRI->getDwarfRegNum(getSuperReg(Operand.getReg()), false));
+        Reads.insert(MCRI->getDwarfRegNum(getSuperReg(Operand.getReg()), IsEH));
     }
   }
 
   checkCFADiff(Inst, State, AfterState, Reads, Writes);
 
   for (auto [LLVMReg, _] : getAllSuperRegs()) {
-    DWARFRegType Reg = MCRI->getDwarfRegNum(LLVMReg, false);
+    DWARFRegType Reg = MCRI->getDwarfRegNum(LLVMReg, IsEH);
 
     auto PrevUnwindLoc =
         State.getLastRow()->getRegisterLocations().getRegisterLocation(Reg);
@@ -182,7 +180,7 @@ void CFIAnalysis::checkRegDiff(
     const dwarf::UnwindLocation &PrevRegState, // TODO maybe re-name
     const dwarf::UnwindLocation &NextRegState, // TODO maybe re-name
     const std::set<DWARFRegType> &Reads, const std::set<DWARFRegType> &Writes) {
-  auto RegLLVMOpt = MCRI->getLLVMRegNum(Reg, false);
+  auto RegLLVMOpt = MCRI->getLLVMRegNum(Reg, IsEH);
   if (RegLLVMOpt == std::nullopt) {
     assert(PrevRegState == NextRegState);
     return;
@@ -195,12 +193,12 @@ void CFIAnalysis::checkRegDiff(
   std::optional<MCPhysReg> PrevRefRegLLVM =
       (PrevRefReg != std::nullopt
            ? std::make_optional(
-                 MCRI->getLLVMRegNum(PrevRefReg.value(), false).value())
+                 MCRI->getLLVMRegNum(PrevRefReg.value(), IsEH).value())
            : std::nullopt);
   std::optional<MCPhysReg> NextRefRegLLVM =
       (PrevRefReg != std::nullopt
            ? std::make_optional(
-                 MCRI->getLLVMRegNum(PrevRefReg.value(), false).value())
+                 MCRI->getLLVMRegNum(PrevRefReg.value(), IsEH).value())
            : std::nullopt);
 
   // TODO Again getting CFA register out of UnwindRow
@@ -211,7 +209,7 @@ void CFIAnalysis::checkRegDiff(
   // TODO asserting it (maybe in the helper function).
   MCPhysReg PrevStateCFARegLLVM =
       MCRI->getLLVMRegNum(PrevState.getLastRow()->getCFAValue().getRegister(),
-                          false)
+                          IsEH)
           .value();
 
   { // try generate
@@ -244,7 +242,7 @@ void CFIAnalysis::checkRegDiff(
     }
 
     // TODO In this stage of program, there is not possible next stages, it's
-    // TODO either the same or nothing. The maybe I have to refactor it back to
+    // TODO either the same or nothing. Then maybe I have to refactor it back to
     // TODO the primitive design. And when got the semantic info, get back to
     // TODO this code.
     for (auto &&PossibleNextRegState : PossibleNextRegStates) {
@@ -331,7 +329,7 @@ void CFIAnalysis::checkCFADiff(const MCInst &Inst, const CFIState &PrevState,
       NextState.getLastRow()->getCFAValue().getOffset();
 
   const char *PrevCFARegName =
-      MCRI->getName(MCRI->getLLVMRegNum(PrevCFAReg, false /* TODO */).value());
+      MCRI->getName(MCRI->getLLVMRegNum(PrevCFAReg, IsEH).value());
 
   if (PrevCFAReg == NextCFAReg) {
     if (PrevCFAOffset == NextCFAOffset) {
diff --git a/llvm/lib/MCCFIAnalysis/CFIAnalysisMCStreamer.cpp b/llvm/lib/MCCFIAnalysis/CFIAnalysisMCStreamer.cpp
index a2b5e308883d6..822f7c3d61089 100644
--- a/llvm/lib/MCCFIAnalysis/CFIAnalysisMCStreamer.cpp
+++ b/llvm/lib/MCCFIAnalysis/CFIAnalysisMCStreamer.cpp
@@ -71,7 +71,8 @@ void CFIAnalysisMCStreamer::feedCFIA() {
 
     CFIAs.back().update(LastInstruction.value(), CFIDirectives);
   } else {
-    CFIAs.emplace_back(&getContext(), MCII, MCIA.get(), CFIDirectives);
+    CFIAs.emplace_back(&getContext(), MCII, MCIA.get(),
+                       false /* TODO should put isEH here */, CFIDirectives);
   }
 }
 

>From 580b1fc50e4fcc0e2d43db3e19ad94e263400c77 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Wed, 18 Jun 2025 22:43:31 +0000
Subject: [PATCH 34/58] Remove ExtendedMCA

---
 llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h |  3 --
 .../MCCFIAnalysis/ExtendedMCInstrAnalysis.h   | 28 -------------------
 llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp        |  8 +-----
 3 files changed, 1 insertion(+), 38 deletions(-)
 delete mode 100644 llvm/include/llvm/MCCFIAnalysis/ExtendedMCInstrAnalysis.h

diff --git a/llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h b/llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h
index 46e2c0a2c0656..32b02b67093a0 100644
--- a/llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h
+++ b/llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h
@@ -2,7 +2,6 @@
 #define LLVM_TOOLS_LLVM_MC_CFI_ANALYSIS_H
 
 #include "CFIState.h"
-#include "ExtendedMCInstrAnalysis.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
@@ -16,7 +15,6 @@
 #include "llvm/MC/MCStreamer.h"
 #include "llvm/MC/MCSubtargetInfo.h"
 #include "llvm/MC/TargetRegistry.h"
-#include <memory>
 #include <set>
 
 namespace llvm {
@@ -25,7 +23,6 @@ class CFIAnalysis {
   MCContext *Context;
   MCInstrInfo const &MCII;
   MCRegisterInfo const *MCRI;
-  std::unique_ptr<ExtendedMCInstrAnalysis> EMCIA;
   CFIState State;
   bool IsEH;
 
diff --git a/llvm/include/llvm/MCCFIAnalysis/ExtendedMCInstrAnalysis.h b/llvm/include/llvm/MCCFIAnalysis/ExtendedMCInstrAnalysis.h
deleted file mode 100644
index 12d6227922a2b..0000000000000
--- a/llvm/include/llvm/MCCFIAnalysis/ExtendedMCInstrAnalysis.h
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef LLVM_TOOLS_LLVM_MC_EXTENDED_MC_INSTR_ANALYSIS_H
-#define LLVM_TOOLS_LLVM_MC_EXTENDED_MC_INSTR_ANALYSIS_H
-
-#include "llvm/MC/MCContext.h"
-#include "llvm/MC/MCDwarf.h"
-#include "llvm/MC/MCExpr.h"
-#include "llvm/MC/MCInstrInfo.h"
-#include "llvm/MC/MCRegister.h"
-#include "llvm/MC/MCStreamer.h"
-#include "llvm/MC/TargetRegistry.h"
-
-namespace llvm {
-
-// TODO remove this class entirely
-class ExtendedMCInstrAnalysis {
-private:
-public:
-  ExtendedMCInstrAnalysis(MCContext *Context, MCInstrInfo const &MCII,
-                          MCInstrAnalysis *MCIA) {}
-
-  /// Extra semantic information needed from MC layer:
-
-  MCPhysReg getFlagsReg() const { return 57; }
-};
-
-} // namespace llvm
-
-#endif
\ No newline at end of file
diff --git a/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp b/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp
index 7e07d846860dc..82eb119e208bc 100644
--- a/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp
+++ b/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp
@@ -16,7 +16,6 @@
 #include "llvm/MC/MCSubtargetInfo.h"
 #include "llvm/MC/TargetRegistry.h"
 #include "llvm/MCCFIAnalysis/CFIState.h"
-#include "llvm/MCCFIAnalysis/ExtendedMCInstrAnalysis.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/FormatVariadic.h"
@@ -43,7 +42,7 @@ CFIAnalysis::getAllSuperRegs() {
   for (auto &&RegClass : MCRI->regclasses()) {
     for (unsigned I = 0; I < RegClass.getNumRegs(); I++) {
       MCPhysReg Reg = RegClass.getRegister(I);
-      if (!isSuperReg(Reg))
+      if (!isSuperReg(Reg) || MCRI->isArtificial(Reg) || MCRI->isConstant(Reg))
         continue;
       SuperRegs[Reg] = &RegClass;
     }
@@ -71,7 +70,6 @@ CFIAnalysis::CFIAnalysis(MCContext *Context, MCInstrInfo const &MCII,
                          ArrayRef<MCCFIInstruction> PrologueCFIDirectives)
     : Context(Context), MCII(MCII), MCRI(Context->getRegisterInfo()),
       State(Context), IsEH(IsEH) {
-  EMCIA.reset(new ExtendedMCInstrAnalysis(Context, MCII, MCIA));
 
   for (auto &&[Reg, RegClass] : getAllSuperRegs()) {
     if (MCRI->get(Reg).IsArtificial || MCRI->get(Reg).IsConstant)
@@ -103,10 +101,6 @@ CFIAnalysis::CFIAnalysis(MCContext *Context, MCInstrInfo const &MCII,
       nullptr, LastRow->getCFAValue().getRegister(),
       0)); // sp's old value is CFA
 
-  State.apply(MCCFIInstruction::createUndefined(
-      nullptr, MCRI->getDwarfRegNum(EMCIA->getFlagsReg(),
-                                    IsEH))); // Flags cannot be caller-saved
-
   // Applying the prologue after default assumptions to overwrite them.
   for (auto &&PrologueCFIDirective : PrologueCFIDirectives) {
     State.apply(PrologueCFIDirective);

>From 7f4daf84dc87d1a634bffd8f753167c1d0ea3aef Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Fri, 20 Jun 2025 02:40:30 +0000
Subject: [PATCH 35/58] Use UnwindRow as state and record the UnwindHistory

---
 llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h | 22 ++---
 llvm/include/llvm/MCCFIAnalysis/CFIState.h    | 38 ---------
 .../llvm/MCCFIAnalysis/UnwindInfoHistory.h    | 31 +++++++
 llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp        | 85 +++++++++----------
 llvm/lib/MCCFIAnalysis/CMakeLists.txt         |  2 +-
 .../{CFIState.cpp => UnwindInfoHistory.cpp}   | 74 ++++++----------
 6 files changed, 114 insertions(+), 138 deletions(-)
 delete mode 100644 llvm/include/llvm/MCCFIAnalysis/CFIState.h
 create mode 100644 llvm/include/llvm/MCCFIAnalysis/UnwindInfoHistory.h
 rename llvm/lib/MCCFIAnalysis/{CFIState.cpp => UnwindInfoHistory.cpp} (74%)

diff --git a/llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h b/llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h
index 32b02b67093a0..e150392ceb77c 100644
--- a/llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h
+++ b/llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h
@@ -1,7 +1,7 @@
 #ifndef LLVM_TOOLS_LLVM_MC_CFI_ANALYSIS_H
 #define LLVM_TOOLS_LLVM_MC_CFI_ANALYSIS_H
 
-#include "CFIState.h"
+#include "UnwindInfoHistory.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
@@ -23,7 +23,7 @@ class CFIAnalysis {
   MCContext *Context;
   MCInstrInfo const &MCII;
   MCRegisterInfo const *MCRI;
-  CFIState State;
+  UnwindInfoHistory State;
   bool IsEH;
 
 private:
@@ -49,19 +49,21 @@ class CFIAnalysis {
 
 private:
   void checkRegDiff(
-      const MCInst &Inst, DWARFRegType Reg, const CFIState &PrevState,
-      const CFIState &NextState,
+      const MCInst &Inst, UnwindInfoHistory::DWARFRegType Reg,
+      const dwarf::UnwindTable::const_iterator &PrevState,
+      const dwarf::UnwindTable::const_iterator &NextState,
       const dwarf::UnwindLocation
           &PrevRegState, // TODO maybe should get them from prev next state
       const dwarf::UnwindLocation
           &NextRegState, // TODO themselves instead of by arguments.
-      const std::set<DWARFRegType> &Reads,
-      const std::set<DWARFRegType> &Writes);
+      const std::set<UnwindInfoHistory::DWARFRegType> &Reads,
+      const std::set<UnwindInfoHistory::DWARFRegType> &Writes);
 
-  void checkCFADiff(const MCInst &Inst, const CFIState &PrevState,
-                    const CFIState &NextState,
-                    const std::set<DWARFRegType> &Reads,
-                    const std::set<DWARFRegType> &Writes);
+  void checkCFADiff(const MCInst &Inst,
+                    const dwarf::UnwindTable::const_iterator &PrevState,
+                    const dwarf::UnwindTable::const_iterator &NextState,
+                    const std::set<UnwindInfoHistory::DWARFRegType> &Reads,
+                    const std::set<UnwindInfoHistory::DWARFRegType> &Writes);
 };
 
 } // namespace llvm
diff --git a/llvm/include/llvm/MCCFIAnalysis/CFIState.h b/llvm/include/llvm/MCCFIAnalysis/CFIState.h
deleted file mode 100644
index 7da036c0009e8..0000000000000
--- a/llvm/include/llvm/MCCFIAnalysis/CFIState.h
+++ /dev/null
@@ -1,38 +0,0 @@
-#ifndef LLVM_TOOLS_LLVM_MC_CFI_STATE_H
-#define LLVM_TOOLS_LLVM_MC_CFI_STATE_H
-
-#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
-#include "llvm/MC/MCContext.h"
-#include "llvm/MC/MCDwarf.h"
-#include <optional>
-namespace llvm {
-
-using DWARFRegType = int64_t;
-
-class CFIState {
-private:
-  MCContext *Context;
-  // TODO the choice is questionable, should the state be the Table? or just a
-  // TODO row? In the current code we are using only the last row.
-  dwarf::UnwindTable State;
-
-public:
-  std::optional<dwarf::UnwindRow>
-  getLastRow() const; // TODO maybe move it UnwindRow
-
-  CFIState(MCContext *Context) : Context(Context) {};
-  CFIState(const CFIState &Other);
-  CFIState &operator=(const CFIState &Other);
-
-  std::optional<DWARFRegType>
-  getReferenceRegisterForCallerValueOfRegister(DWARFRegType Reg) const;
-
-  void apply(const MCCFIInstruction &CFIDirective);
-
-private:
-  std::optional<dwarf::CFIProgram> convertMC2DWARF(
-      MCCFIInstruction CFIDirective); // TODO maybe move it somewhere else
-};
-} // namespace llvm
-
-#endif
\ No newline at end of file
diff --git a/llvm/include/llvm/MCCFIAnalysis/UnwindInfoHistory.h b/llvm/include/llvm/MCCFIAnalysis/UnwindInfoHistory.h
new file mode 100644
index 0000000000000..9a792e1f5f39e
--- /dev/null
+++ b/llvm/include/llvm/MCCFIAnalysis/UnwindInfoHistory.h
@@ -0,0 +1,31 @@
+#ifndef LLVM_TOOLS_LLVM_MC_CFI_STATE_H
+#define LLVM_TOOLS_LLVM_MC_CFI_STATE_H
+
+#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDwarf.h"
+#include <optional>
+namespace llvm {
+
+class UnwindInfoHistory {
+public:
+  using DWARFRegType = uint32_t;
+
+  UnwindInfoHistory(MCContext *Context) : Context(Context) {};
+
+  static std::optional<DWARFRegType>
+  getReferenceRegisterForUnwindInfoOfRegister(
+      const dwarf::UnwindTable::const_iterator &UnwindRow, DWARFRegType Reg);
+
+  std::optional<dwarf::UnwindTable::const_iterator> getCurrentUnwindRow() const;
+  void update(const MCCFIInstruction &CFIDirective);
+
+private:
+  MCContext *Context;
+  dwarf::UnwindTable Table;
+
+  std::optional<dwarf::CFIProgram> convert(MCCFIInstruction CFIDirective);
+};
+} // namespace llvm
+
+#endif
\ No newline at end of file
diff --git a/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp b/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp
index 82eb119e208bc..dc4cda0bbe83d 100644
--- a/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp
+++ b/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp
@@ -15,12 +15,11 @@
 #include "llvm/MC/MCStreamer.h"
 #include "llvm/MC/MCSubtargetInfo.h"
 #include "llvm/MC/TargetRegistry.h"
-#include "llvm/MCCFIAnalysis/CFIState.h"
+#include "llvm/MCCFIAnalysis/UnwindInfoHistory.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/FormatVariadic.h"
 #include <cstdint>
-#include <memory>
 #include <optional>
 #include <set>
 
@@ -75,44 +74,44 @@ CFIAnalysis::CFIAnalysis(MCContext *Context, MCInstrInfo const &MCII,
     if (MCRI->get(Reg).IsArtificial || MCRI->get(Reg).IsConstant)
       continue;
 
-    DWARFRegType DwarfReg = MCRI->getDwarfRegNum(Reg, IsEH);
+    UnwindInfoHistory::DWARFRegType DwarfReg = MCRI->getDwarfRegNum(Reg, IsEH);
     // TODO is it OK to create fake CFI directives for doing this?
-    State.apply(MCCFIInstruction::createSameValue(nullptr, DwarfReg));
+    State.update(MCCFIInstruction::createSameValue(nullptr, DwarfReg));
   }
 
   for (auto &&InitialFrameStateCFIDirective :
        Context->getAsmInfo()->getInitialFrameState()) {
-    State.apply(InitialFrameStateCFIDirective);
+    State.update(InitialFrameStateCFIDirective);
   }
 
   // TODO these are temporay added to make things work.
   // Setup the basic information:
-  State.apply(MCCFIInstruction::createUndefined(
+  State.update(MCCFIInstruction::createUndefined(
       nullptr,
       MCRI->getDwarfRegNum(MCRI->getProgramCounter(),
                            IsEH))); // TODO for now, we don't care about the PC
   // TODO
-  auto LastRow = State.getLastRow();
+  auto LastRow = State.getCurrentUnwindRow();
   assert(LastRow && "there should be at least one row");
   // TODO assert that CFA is there, and based on register.
   // TODO
 
-  State.apply(MCCFIInstruction::createOffset(
-      nullptr, LastRow->getCFAValue().getRegister(),
+  State.update(MCCFIInstruction::createOffset(
+      nullptr, LastRow.value()->getCFAValue().getRegister(),
       0)); // sp's old value is CFA
 
   // Applying the prologue after default assumptions to overwrite them.
   for (auto &&PrologueCFIDirective : PrologueCFIDirectives) {
-    State.apply(PrologueCFIDirective);
+    State.update(PrologueCFIDirective);
   }
 }
 
 void CFIAnalysis::update(const MCInst &Inst,
                          ArrayRef<MCCFIInstruction> CFIDirectives) {
   const MCInstrDesc &MCInstInfo = MCII.get(Inst.getOpcode());
-  CFIState AfterState(State);
+  auto PrevUnwindRow = State.getCurrentUnwindRow().value();
   for (auto &&CFIDirective : CFIDirectives)
-    AfterState.apply(CFIDirective);
+    State.update(CFIDirective);
 
   //! if (!AfterState.apply(CFIDirective))
   //!     Context->reportWarning(
@@ -120,7 +119,7 @@ void CFIAnalysis::update(const MCInst &Inst,
   //!         "I don't support this CFI directive, I assume this does nothing "
   //!         "(which will probably break other things)");
 
-  std::set<DWARFRegType> Writes, Reads;
+  std::set<UnwindInfoHistory::DWARFRegType> Writes, Reads;
   for (unsigned I = 0; I < MCInstInfo.NumImplicitUses; I++)
     Reads.insert(
         MCRI->getDwarfRegNum(getSuperReg(MCInstInfo.implicit_uses()[I]), IsEH));
@@ -139,16 +138,18 @@ void CFIAnalysis::update(const MCInst &Inst,
     }
   }
 
-  checkCFADiff(Inst, State, AfterState, Reads, Writes);
+  checkCFADiff(Inst, PrevUnwindRow, State.getCurrentUnwindRow().value(), Reads,
+               Writes);
 
   for (auto [LLVMReg, _] : getAllSuperRegs()) {
-    DWARFRegType Reg = MCRI->getDwarfRegNum(LLVMReg, IsEH);
+    UnwindInfoHistory::DWARFRegType Reg = MCRI->getDwarfRegNum(LLVMReg, IsEH);
 
     auto PrevUnwindLoc =
-        State.getLastRow()->getRegisterLocations().getRegisterLocation(Reg);
-    auto NextUnwindLoc =
-        AfterState.getLastRow()->getRegisterLocations().getRegisterLocation(
-            Reg);
+        PrevUnwindRow->getRegisterLocations().getRegisterLocation(Reg);
+    auto NextUnwindLoc = State.getCurrentUnwindRow()
+                             .value()
+                             ->getRegisterLocations()
+                             .getRegisterLocation(Reg);
 
     // TODO think more if these assertions are OK
     // TODO maybe change them to error messages.
@@ -161,19 +162,19 @@ void CFIAnalysis::update(const MCInst &Inst,
     assert(NextUnwindLoc &&
            "A CFI directive should not delete a register state.");
 
-    checkRegDiff(Inst, Reg, State, AfterState, PrevUnwindLoc.value(),
-                 NextUnwindLoc.value(), Reads, Writes);
+    checkRegDiff(Inst, Reg, PrevUnwindRow, State.getCurrentUnwindRow().value(),
+                 PrevUnwindLoc.value(), NextUnwindLoc.value(), Reads, Writes);
   }
-
-  State = AfterState;
 }
 
 void CFIAnalysis::checkRegDiff(
-    const MCInst &Inst, DWARFRegType Reg, const CFIState &PrevState,
-    const CFIState &NextState,
+    const MCInst &Inst, UnwindInfoHistory::DWARFRegType Reg,
+    const dwarf::UnwindTable::const_iterator &PrevState,
+    const dwarf::UnwindTable::const_iterator &NextState,
     const dwarf::UnwindLocation &PrevRegState, // TODO maybe re-name
     const dwarf::UnwindLocation &NextRegState, // TODO maybe re-name
-    const std::set<DWARFRegType> &Reads, const std::set<DWARFRegType> &Writes) {
+    const std::set<UnwindInfoHistory::DWARFRegType> &Reads,
+    const std::set<UnwindInfoHistory::DWARFRegType> &Writes) {
   auto RegLLVMOpt = MCRI->getLLVMRegNum(Reg, IsEH);
   if (RegLLVMOpt == std::nullopt) {
     assert(PrevRegState == NextRegState);
@@ -182,7 +183,8 @@ void CFIAnalysis::checkRegDiff(
   const char *RegLLVMName = MCRI->getName(RegLLVMOpt.value());
 
   auto &&PrevRefReg =
-      PrevState.getReferenceRegisterForCallerValueOfRegister(Reg);
+      UnwindInfoHistory::getReferenceRegisterForUnwindInfoOfRegister(PrevState,
+                                                                     Reg);
 
   std::optional<MCPhysReg> PrevRefRegLLVM =
       (PrevRefReg != std::nullopt
@@ -202,9 +204,7 @@ void CFIAnalysis::checkRegDiff(
   // TODO it's not true. And if it's always true, consider
   // TODO asserting it (maybe in the helper function).
   MCPhysReg PrevStateCFARegLLVM =
-      MCRI->getLLVMRegNum(PrevState.getLastRow()->getCFAValue().getRegister(),
-                          IsEH)
-          .value();
+      MCRI->getLLVMRegNum(PrevState->getCFAValue().getRegister(), IsEH).value();
 
   { // try generate
     // Widen
@@ -307,20 +307,19 @@ void CFIAnalysis::checkRegDiff(
   return;
 }
 
-void CFIAnalysis::checkCFADiff(const MCInst &Inst, const CFIState &PrevState,
-                               const CFIState &NextState,
-                               const std::set<DWARFRegType> &Reads,
-                               const std::set<DWARFRegType> &Writes) {
+void CFIAnalysis::checkCFADiff(
+    const MCInst &Inst, const dwarf::UnwindTable::const_iterator &PrevState,
+    const dwarf::UnwindTable::const_iterator &NextState,
+    const std::set<UnwindInfoHistory::DWARFRegType> &Reads,
+    const std::set<UnwindInfoHistory::DWARFRegType> &Writes) {
   // TODO again getting the CFA register in the bad way.
-  const DWARFRegType PrevCFAReg =
-      PrevState.getLastRow()->getCFAValue().getRegister();
-  const int32_t PrevCFAOffset =
-      PrevState.getLastRow()->getCFAValue().getOffset();
-
-  const DWARFRegType NextCFAReg =
-      NextState.getLastRow()->getCFAValue().getRegister();
-  const int32_t NextCFAOffset =
-      NextState.getLastRow()->getCFAValue().getOffset();
+  const UnwindInfoHistory::DWARFRegType PrevCFAReg =
+      PrevState->getCFAValue().getRegister();
+  const int32_t PrevCFAOffset = PrevState->getCFAValue().getOffset();
+
+  const UnwindInfoHistory::DWARFRegType NextCFAReg =
+      NextState->getCFAValue().getRegister();
+  const int32_t NextCFAOffset = NextState->getCFAValue().getOffset();
 
   const char *PrevCFARegName =
       MCRI->getName(MCRI->getLLVMRegNum(PrevCFAReg, IsEH).value());
diff --git a/llvm/lib/MCCFIAnalysis/CMakeLists.txt b/llvm/lib/MCCFIAnalysis/CMakeLists.txt
index 15622132de7d4..b4a5da108de5b 100644
--- a/llvm/lib/MCCFIAnalysis/CMakeLists.txt
+++ b/llvm/lib/MCCFIAnalysis/CMakeLists.txt
@@ -1,5 +1,5 @@
 add_llvm_component_library(LLVMMCCFIAnalysis
-  CFIState.cpp
+  UnwindInfoHistory.cpp
   CFIAnalysisMCStreamer.cpp
   CFIAnalysis.cpp
 
diff --git a/llvm/lib/MCCFIAnalysis/CFIState.cpp b/llvm/lib/MCCFIAnalysis/UnwindInfoHistory.cpp
similarity index 74%
rename from llvm/lib/MCCFIAnalysis/CFIState.cpp
rename to llvm/lib/MCCFIAnalysis/UnwindInfoHistory.cpp
index 2d65d325cb22d..cc164aabfb1eb 100644
--- a/llvm/lib/MCCFIAnalysis/CFIState.cpp
+++ b/llvm/lib/MCCFIAnalysis/UnwindInfoHistory.cpp
@@ -1,5 +1,5 @@
 // TODO check what includes to keep and what to remove
-#include "llvm/MCCFIAnalysis/CFIState.h"
+#include "llvm/MCCFIAnalysis/UnwindInfoHistory.h"
 #include "llvm/BinaryFormat/Dwarf.h"
 #include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
 #include "llvm/MC/MCDwarf.h"
@@ -11,28 +11,18 @@
 
 using namespace llvm;
 
-CFIState::CFIState(const CFIState &Other) : Context(Other.Context) {
-  // TODO maybe remove it
-  State = Other.State;
-}
-
-CFIState &CFIState::operator=(const CFIState &Other) {
-  // TODO maybe remove it
-  if (this != &Other) {
-    State = Other.State;
-    Context = Other.Context;
-  }
+std::optional<dwarf::UnwindTable::const_iterator>
+UnwindInfoHistory::getCurrentUnwindRow() const {
+  if (!Table.size())
+    return std::nullopt;
 
-  return *this;
+  return --Table.end();
 }
 
-std::optional<DWARFRegType>
-CFIState::getReferenceRegisterForCallerValueOfRegister(DWARFRegType Reg) const {
-  // TODO maybe move it the Location class
-  auto LastRow = getLastRow();
-  assert(LastRow && "The state is empty.");
-
-  auto UnwinLoc = LastRow->getRegisterLocations().getRegisterLocation(Reg);
+std::optional<UnwindInfoHistory::DWARFRegType>
+UnwindInfoHistory::getReferenceRegisterForUnwindInfoOfRegister(
+    const dwarf::UnwindTable::const_iterator &UnwindRow, DWARFRegType Reg) {
+  auto UnwinLoc = UnwindRow->getRegisterLocations().getRegisterLocation(Reg);
   assert(UnwinLoc &&
          "The register should be tracked inside the register states");
 
@@ -40,9 +30,8 @@ CFIState::getReferenceRegisterForCallerValueOfRegister(DWARFRegType Reg) const {
   case dwarf::UnwindLocation::Location::Undefined:
   case dwarf::UnwindLocation::Location::Constant:
   case dwarf::UnwindLocation::Location::Unspecified:
-    // TODO here should look into expr and find the registers, but for now it's
-    // TODO like this:
   case dwarf::UnwindLocation::Location::DWARFExpr:
+    // TODO here should look into expr and find the registers.
     return std::nullopt;
   case dwarf::UnwindLocation::Location::Same:
     return Reg;
@@ -51,33 +40,33 @@ CFIState::getReferenceRegisterForCallerValueOfRegister(DWARFRegType Reg) const {
   case dwarf::UnwindLocation::Location::CFAPlusOffset:
     // TODO check if it's ok to assume CFA is always depending on other
     // TODO register, if yes assert it here!
-    return LastRow->getCFAValue().getRegister();
+    return UnwindRow->getCFAValue().getRegister();
   }
 }
 
-void CFIState::apply(const MCCFIInstruction &CFIDirective) {
-  auto DwarfOperations = convertMC2DWARF(CFIDirective);
+void UnwindInfoHistory::update(const MCCFIInstruction &CFIDirective) {
+  auto DwarfOperations = convert(CFIDirective);
   if (!DwarfOperations) {
     Context->reportError(
         CFIDirective.getLoc(),
         "couldn't apply this directive to the unwinding information state");
   }
 
-  auto &&LastRow = getLastRow();
-  dwarf::UnwindRow Row = LastRow ? LastRow.value() : dwarf::UnwindRow();
-  if (Error Err = State.parseRows(DwarfOperations.value(), Row, nullptr)) {
-    // ! FIXME what should I do with this error?
+  auto LastRow = getCurrentUnwindRow();
+  dwarf::UnwindRow Row =
+      LastRow.has_value() ? *(LastRow.value()) : dwarf::UnwindRow();
+  if (Error Err = Table.parseRows(DwarfOperations.value(), Row, nullptr)) {
     Context->reportError(
         CFIDirective.getLoc(),
         formatv("could not parse this CFI directive due to: {0}",
                 toString(std::move(Err))));
     assert(false);
   }
-  State.insertRow(Row);
+  Table.insertRow(Row);
 }
 
 std::optional<dwarf::CFIProgram>
-CFIState::convertMC2DWARF(MCCFIInstruction CFIDirective) {
+UnwindInfoHistory::convert(MCCFIInstruction CFIDirective) {
   //! FIXME, this way of instantiating CFI program does not look right, either
   //! refactor CFIProgram to not depend on the Code/Data Alignment or add a new
   //! type that is independent from this and is also feedable to UnwindTable.
@@ -118,20 +107,22 @@ CFIState::convertMC2DWARF(MCCFIInstruction CFIDirective) {
                                    CFIDirective.getOffset());
     break;
   case MCCFIInstruction::OpRelOffset:
-    if (!getLastRow()) // TODO maybe replace it with assert
+    if (!getCurrentUnwindRow()) // TODO maybe replace it with assert
       return std::nullopt;
 
     DwarfOperations.addInstruction(
         dwarf::DW_CFA_offset, CFIDirective.getRegister(),
-        CFIDirective.getOffset() - getLastRow()->getCFAValue().getOffset());
+        CFIDirective.getOffset() -
+            getCurrentUnwindRow().value()->getCFAValue().getOffset());
     break;
   case MCCFIInstruction::OpAdjustCfaOffset:
-    if (!getLastRow()) // TODO maybe replace it with assert
+    if (!getCurrentUnwindRow()) // TODO maybe replace it with assert
       return std::nullopt;
 
-    DwarfOperations.addInstruction(dwarf::DW_CFA_def_cfa_offset,
-                                   CFIDirective.getOffset() +
-                                       getLastRow()->getCFAValue().getOffset());
+    DwarfOperations.addInstruction(
+        dwarf::DW_CFA_def_cfa_offset,
+        CFIDirective.getOffset() +
+            getCurrentUnwindRow().value()->getCFAValue().getOffset());
     break;
   case MCCFIInstruction::OpEscape:
     // TODO It's now feasible but for now, I ignore it
@@ -176,12 +167,3 @@ CFIState::convertMC2DWARF(MCCFIInstruction CFIDirective) {
 
   return DwarfOperations;
 }
-
-std::optional<dwarf::UnwindRow> CFIState::getLastRow() const {
-  if (!State.size())
-    return std::nullopt;
-
-  //! FIXME too dirty
-  auto &&it = State.end();
-  return *--it;
-}
\ No newline at end of file

>From cece662935621a47db131cd5c6d5b7b424222d17 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Fri, 20 Jun 2025 23:43:51 +0000
Subject: [PATCH 36/58] Make CFA access easier

---
 llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h |  35 +-
 .../llvm/MCCFIAnalysis/UnwindInfoHistory.h    |   9 +-
 llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp        | 313 +++++++++---------
 llvm/lib/MCCFIAnalysis/UnwindInfoHistory.cpp  |  29 +-
 4 files changed, 176 insertions(+), 210 deletions(-)

diff --git a/llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h b/llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h
index e150392ceb77c..ac921e40ededf 100644
--- a/llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h
+++ b/llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h
@@ -29,11 +29,11 @@ class CFIAnalysis {
 private:
   // The CFI analysis only keeps track and cares about super registers, not the
   // subregisters. All reads to/writes from subregisters and considered the same
-  // operation to super registers. Other operations like loading and stores are
-  // considered only if they are exactly doing the operation to or from a super
-  // register.
-  // As en example, if you spill a sub register to stack, the CFI analysis does
-  // not consider that a register spilling.
+  // operation to super registers.
+  // TODO Other operations like loading and stores are considered only if they
+  // TODO are exactly doing the operation to or from a super register. As an
+  // TODO example, if you spill a sub register to stack, the CFI analysis does
+  // TODO not consider that a register spilling.
   bool isSuperReg(MCPhysReg Reg);
 
   SmallVector<std::pair<MCPhysReg, MCRegisterClass const *>> getAllSuperRegs();
@@ -48,22 +48,19 @@ class CFIAnalysis {
   void update(const MCInst &Inst, ArrayRef<MCCFIInstruction> CFIDirectives);
 
 private:
-  void checkRegDiff(
-      const MCInst &Inst, UnwindInfoHistory::DWARFRegType Reg,
-      const dwarf::UnwindTable::const_iterator &PrevState,
-      const dwarf::UnwindTable::const_iterator &NextState,
-      const dwarf::UnwindLocation
-          &PrevRegState, // TODO maybe should get them from prev next state
-      const dwarf::UnwindLocation
-          &NextRegState, // TODO themselves instead of by arguments.
-      const std::set<UnwindInfoHistory::DWARFRegType> &Reads,
-      const std::set<UnwindInfoHistory::DWARFRegType> &Writes);
+  void checkRegDiff(const MCInst &Inst, DWARFRegType Reg,
+                    const dwarf::UnwindTable::const_iterator &PrevRow,
+                    const dwarf::UnwindTable::const_iterator &NextRow,
+                    const dwarf::UnwindLocation &PrevRegLoc,
+                    const dwarf::UnwindLocation &NextRegLoc,
+                    const std::set<DWARFRegType> &Reads,
+                    const std::set<DWARFRegType> &Writes);
 
   void checkCFADiff(const MCInst &Inst,
-                    const dwarf::UnwindTable::const_iterator &PrevState,
-                    const dwarf::UnwindTable::const_iterator &NextState,
-                    const std::set<UnwindInfoHistory::DWARFRegType> &Reads,
-                    const std::set<UnwindInfoHistory::DWARFRegType> &Writes);
+                    const dwarf::UnwindTable::const_iterator &PrevRow,
+                    const dwarf::UnwindTable::const_iterator &NextRow,
+                    const std::set<DWARFRegType> &Reads,
+                    const std::set<DWARFRegType> &Writes);
 };
 
 } // namespace llvm
diff --git a/llvm/include/llvm/MCCFIAnalysis/UnwindInfoHistory.h b/llvm/include/llvm/MCCFIAnalysis/UnwindInfoHistory.h
index 9a792e1f5f39e..1f357e0e8fc55 100644
--- a/llvm/include/llvm/MCCFIAnalysis/UnwindInfoHistory.h
+++ b/llvm/include/llvm/MCCFIAnalysis/UnwindInfoHistory.h
@@ -4,19 +4,16 @@
 #include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCDwarf.h"
+#include <cstdint>
 #include <optional>
 namespace llvm {
 
+using DWARFRegType = uint32_t;
+
 class UnwindInfoHistory {
 public:
-  using DWARFRegType = uint32_t;
-
   UnwindInfoHistory(MCContext *Context) : Context(Context) {};
 
-  static std::optional<DWARFRegType>
-  getReferenceRegisterForUnwindInfoOfRegister(
-      const dwarf::UnwindTable::const_iterator &UnwindRow, DWARFRegType Reg);
-
   std::optional<dwarf::UnwindTable::const_iterator> getCurrentUnwindRow() const;
   void update(const MCCFIInstruction &CFIDirective);
 
diff --git a/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp b/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp
index dc4cda0bbe83d..5ac88cf56ec5c 100644
--- a/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp
+++ b/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp
@@ -18,6 +18,7 @@
 #include "llvm/MCCFIAnalysis/UnwindInfoHistory.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
 #include "llvm/Support/FormatVariadic.h"
 #include <cstdint>
 #include <optional>
@@ -25,6 +26,49 @@
 
 using namespace llvm;
 
+struct CFARegOffsetInfo {
+  DWARFRegType Reg;
+  int64_t Offset;
+
+  CFARegOffsetInfo(DWARFRegType Reg, int64_t Offset)
+      : Reg(Reg), Offset(Offset) {}
+};
+
+static std::optional<CFARegOffsetInfo>
+getCFARegOffsetInfo(const dwarf::UnwindTable::const_iterator &UnwindRow) {
+  auto CFALocation = UnwindRow->getCFAValue();
+  if (CFALocation.getLocation() !=
+      dwarf::UnwindLocation::Location::RegPlusOffset) {
+    return std::nullopt;
+  }
+
+  return CFARegOffsetInfo(CFALocation.getRegister(), CFALocation.getOffset());
+}
+
+static std::optional<DWARFRegType> getReferenceRegisterForUnwindInfoOfRegister(
+    const dwarf::UnwindTable::const_iterator &UnwindRow, DWARFRegType Reg) {
+  auto UnwinLoc = UnwindRow->getRegisterLocations().getRegisterLocation(Reg);
+  assert(UnwinLoc &&
+         "The register should be tracked inside the register states");
+
+  switch (UnwinLoc->getLocation()) {
+  case dwarf::UnwindLocation::Location::Undefined:
+  case dwarf::UnwindLocation::Location::Constant:
+  case dwarf::UnwindLocation::Location::Unspecified:
+  case dwarf::UnwindLocation::Location::DWARFExpr:
+    // TODO here should look into expr and find the registers.
+    return std::nullopt;
+  case dwarf::UnwindLocation::Location::Same:
+    return Reg;
+  case dwarf::UnwindLocation::Location::RegPlusOffset:
+    return UnwinLoc->getRegister();
+  case dwarf::UnwindLocation::Location::CFAPlusOffset:
+    // TODO check if it's ok to assume CFA is always depending on other
+    // TODO register, if yes assert it here!
+    return UnwindRow->getCFAValue().getRegister();
+  }
+}
+
 // TODO remove it, it's just for debug purposes.
 void printUntilNextLine(const char *Str) {
   for (int I = 0; Str[I] != '\0' && Str[I] != '\n'; I++)
@@ -70,35 +114,37 @@ CFIAnalysis::CFIAnalysis(MCContext *Context, MCInstrInfo const &MCII,
     : Context(Context), MCII(MCII), MCRI(Context->getRegisterInfo()),
       State(Context), IsEH(IsEH) {
 
+  // TODO These all should be handled by setting .cfi_same_value for only callee
+  // TODO saved registers inside `getInitialFrameState`. Instead now what's
+  // TODO happening is that the analysis .cfi_same_value all the registers and
+  // TODO remove PC (undefined), and RSP (CFA) from them.
   for (auto &&[Reg, RegClass] : getAllSuperRegs()) {
     if (MCRI->get(Reg).IsArtificial || MCRI->get(Reg).IsConstant)
       continue;
 
-    UnwindInfoHistory::DWARFRegType DwarfReg = MCRI->getDwarfRegNum(Reg, IsEH);
-    // TODO is it OK to create fake CFI directives for doing this?
+    DWARFRegType DwarfReg = MCRI->getDwarfRegNum(Reg, IsEH);
     State.update(MCCFIInstruction::createSameValue(nullptr, DwarfReg));
   }
 
+  State.update(MCCFIInstruction::createUndefined(
+      nullptr, MCRI->getDwarfRegNum(MCRI->getProgramCounter(), IsEH)));
+
   for (auto &&InitialFrameStateCFIDirective :
        Context->getAsmInfo()->getInitialFrameState()) {
     State.update(InitialFrameStateCFIDirective);
   }
 
-  // TODO these are temporay added to make things work.
-  // Setup the basic information:
-  State.update(MCCFIInstruction::createUndefined(
-      nullptr,
-      MCRI->getDwarfRegNum(MCRI->getProgramCounter(),
-                           IsEH))); // TODO for now, we don't care about the PC
-  // TODO
-  auto LastRow = State.getCurrentUnwindRow();
-  assert(LastRow && "there should be at least one row");
-  // TODO assert that CFA is there, and based on register.
-  // TODO
-
-  State.update(MCCFIInstruction::createOffset(
-      nullptr, LastRow.value()->getCFAValue().getRegister(),
-      0)); // sp's old value is CFA
+  auto MaybeLastRow = State.getCurrentUnwindRow();
+  assert(MaybeLastRow && "there should be at least one row");
+  auto LastRow = *MaybeLastRow;
+
+  auto MaybeCFA = getCFARegOffsetInfo(LastRow);
+  assert(MaybeCFA &&
+         "the CFA information should be describable in [Reg + Offset] in here");
+  auto CFA = *MaybeCFA;
+
+  State.update(MCCFIInstruction::createOffset(nullptr, CFA.Reg,
+                                              0)); // sp's old value is CFA
 
   // Applying the prologue after default assumptions to overwrite them.
   for (auto &&PrologueCFIDirective : PrologueCFIDirectives) {
@@ -109,17 +155,16 @@ CFIAnalysis::CFIAnalysis(MCContext *Context, MCInstrInfo const &MCII,
 void CFIAnalysis::update(const MCInst &Inst,
                          ArrayRef<MCCFIInstruction> CFIDirectives) {
   const MCInstrDesc &MCInstInfo = MCII.get(Inst.getOpcode());
-  auto PrevUnwindRow = State.getCurrentUnwindRow().value();
+
+  auto MaybePrevUnwindRow = State.getCurrentUnwindRow();
+  assert(MaybePrevUnwindRow && "The analysis should have initialized the "
+                               "history with at least one row by now");
+  auto PrevUnwindRow = MaybePrevUnwindRow.value();
+
   for (auto &&CFIDirective : CFIDirectives)
     State.update(CFIDirective);
 
-  //! if (!AfterState.apply(CFIDirective))
-  //!     Context->reportWarning(
-  //!         CFIDirective.getLoc(),
-  //!         "I don't support this CFI directive, I assume this does nothing "
-  //!         "(which will probably break other things)");
-
-  std::set<UnwindInfoHistory::DWARFRegType> Writes, Reads;
+  std::set<DWARFRegType> Writes, Reads;
   for (unsigned I = 0; I < MCInstInfo.NumImplicitUses; I++)
     Reads.insert(
         MCRI->getDwarfRegNum(getSuperReg(MCInstInfo.implicit_uses()[I]), IsEH));
@@ -138,140 +183,70 @@ void CFIAnalysis::update(const MCInst &Inst,
     }
   }
 
-  checkCFADiff(Inst, PrevUnwindRow, State.getCurrentUnwindRow().value(), Reads,
-               Writes);
+  auto MaybeCurrentUnwindRow = State.getCurrentUnwindRow();
+  assert(MaybeCurrentUnwindRow &&
+         "Prev row existed, so should the current row.");
+  auto CurrentUnwindRow = *MaybeCurrentUnwindRow;
+
+  checkCFADiff(Inst, PrevUnwindRow, CurrentUnwindRow, Reads, Writes);
 
   for (auto [LLVMReg, _] : getAllSuperRegs()) {
-    UnwindInfoHistory::DWARFRegType Reg = MCRI->getDwarfRegNum(LLVMReg, IsEH);
+    DWARFRegType Reg = MCRI->getDwarfRegNum(LLVMReg, IsEH);
 
-    auto PrevUnwindLoc =
+    auto MaybePrevUnwindLoc =
         PrevUnwindRow->getRegisterLocations().getRegisterLocation(Reg);
-    auto NextUnwindLoc = State.getCurrentUnwindRow()
-                             .value()
-                             ->getRegisterLocations()
-                             .getRegisterLocation(Reg);
-
-    // TODO think more if these assertions are OK
-    // TODO maybe change them to error messages.
-    if (!PrevUnwindLoc) {
-      assert(
-          !NextUnwindLoc &&
-          "A CFI directive should not define a new register out of thin air.");
+    auto MaybeNextUnwindLoc =
+        CurrentUnwindRow->getRegisterLocations().getRegisterLocation(Reg);
+
+    if (!MaybePrevUnwindLoc) {
+      assert(!MaybeNextUnwindLoc && "The register unwind info suddenly "
+                                    "appeared here, ignoring this change");
       continue;
     }
-    assert(NextUnwindLoc &&
-           "A CFI directive should not delete a register state.");
 
-    checkRegDiff(Inst, Reg, PrevUnwindRow, State.getCurrentUnwindRow().value(),
-                 PrevUnwindLoc.value(), NextUnwindLoc.value(), Reads, Writes);
+    assert(MaybeNextUnwindLoc && "The register unwind info suddenly vanished "
+                                 "here, ignoring this change");
+
+    auto PrevUnwindLoc = MaybePrevUnwindLoc.value();
+    auto NextUnwindLoc = MaybeNextUnwindLoc.value();
+
+    checkRegDiff(Inst, Reg, PrevUnwindRow, CurrentUnwindRow, PrevUnwindLoc,
+                 NextUnwindLoc, Reads, Writes);
   }
 }
 
 void CFIAnalysis::checkRegDiff(
-    const MCInst &Inst, UnwindInfoHistory::DWARFRegType Reg,
-    const dwarf::UnwindTable::const_iterator &PrevState,
-    const dwarf::UnwindTable::const_iterator &NextState,
-    const dwarf::UnwindLocation &PrevRegState, // TODO maybe re-name
-    const dwarf::UnwindLocation &NextRegState, // TODO maybe re-name
-    const std::set<UnwindInfoHistory::DWARFRegType> &Reads,
-    const std::set<UnwindInfoHistory::DWARFRegType> &Writes) {
-  auto RegLLVMOpt = MCRI->getLLVMRegNum(Reg, IsEH);
-  if (RegLLVMOpt == std::nullopt) {
-    assert(PrevRegState == NextRegState);
+    const MCInst &Inst, DWARFRegType Reg,
+    const dwarf::UnwindTable::const_iterator &PrevRow,
+    const dwarf::UnwindTable::const_iterator &NextRow,
+    const dwarf::UnwindLocation &PrevRegLoc,
+    const dwarf::UnwindLocation &NextRegLoc,
+    const std::set<DWARFRegType> &Reads, const std::set<DWARFRegType> &Writes) {
+  auto MaybeRegLLVM = MCRI->getLLVMRegNum(Reg, IsEH);
+  if (!MaybeRegLLVM) {
+    assert(PrevRegLoc == NextRegLoc &&
+           "The dwarf register does not have a LLVM number, so the unwind info "
+           "for it should not change");
     return;
   }
-  const char *RegLLVMName = MCRI->getName(RegLLVMOpt.value());
 
-  auto &&PrevRefReg =
-      UnwindInfoHistory::getReferenceRegisterForUnwindInfoOfRegister(PrevState,
-                                                                     Reg);
+  const char *RegLLVMName = MCRI->getName(MaybeRegLLVM.value());
+
+  auto &&MaybePrevRefReg =
+      getReferenceRegisterForUnwindInfoOfRegister(PrevRow, Reg);
 
   std::optional<MCPhysReg> PrevRefRegLLVM =
-      (PrevRefReg != std::nullopt
-           ? std::make_optional(
-                 MCRI->getLLVMRegNum(PrevRefReg.value(), IsEH).value())
-           : std::nullopt);
+      (MaybePrevRefReg ? MCRI->getLLVMRegNum(MaybePrevRefReg.value(), IsEH)
+                       : std::nullopt);
   std::optional<MCPhysReg> NextRefRegLLVM =
-      (PrevRefReg != std::nullopt
-           ? std::make_optional(
-                 MCRI->getLLVMRegNum(PrevRefReg.value(), IsEH).value())
-           : std::nullopt);
-
-  // TODO Again getting CFA register out of UnwindRow
-  // TODO consider either making it a help function.
-  // TODO Also, again you have to re-look in the assumption
-  // TODO that CFA is depending on another register, maybe
-  // TODO it's not true. And if it's always true, consider
-  // TODO asserting it (maybe in the helper function).
-  MCPhysReg PrevStateCFARegLLVM =
-      MCRI->getLLVMRegNum(PrevState->getCFAValue().getRegister(), IsEH).value();
-
-  { // try generate
-    // Widen
-    std::vector<dwarf::UnwindLocation> PossibleNextRegStates;
-
-    { // stay the same
-      bool CanStayTheSame = true;
-
-      // TODO make sure it has meaning in `Undefined` or `Unspecified` case.
-      // TODO make it smarter, if it's in the memory and the instruction does
-      // TODO not store anything and the register (if any) to access that part
-      // TODO is not changed, then it's OK.
-      if (PrevRegState.getDereference())
-        CanStayTheSame = false;
-
-      if (PrevRefReg && Writes.count(PrevRefReg.value())) {
-        CanStayTheSame = false;
-      }
-
-      if (PrevRegState.getLocation() == dwarf::UnwindLocation::DWARFExpr) {
-        // TODO this can be solved more precise, by looking into the expression,
-        // TODO finding registers that are used and checking if the instruction
-        // TODO is changing them or not.
-        CanStayTheSame = false;
-      }
-
-      if (CanStayTheSame)
-        PossibleNextRegStates.push_back(PrevRegState);
-    }
+      (MaybePrevRefReg ? MCRI->getLLVMRegNum(MaybePrevRefReg.value(), IsEH)
+                       : std::nullopt);
 
-    // TODO In this stage of program, there is not possible next stages, it's
-    // TODO either the same or nothing. Then maybe I have to refactor it back to
-    // TODO the primitive design. And when got the semantic info, get back to
-    // TODO this code.
-    for (auto &&PossibleNextRegState : PossibleNextRegStates) {
-      if (PossibleNextRegState == NextRegState) {
-        // Everything is ok
-        return;
-      }
-    }
-
-    for (auto &&PossibleNextRegState : PossibleNextRegStates) {
-      if (PossibleNextRegState.getLocation() != NextRegState.getLocation())
-        continue;
-
-      // TODO again, as said above, does this happen in the current primitive
-      // TODO design?
-      if (PossibleNextRegState.getLocation() ==
-          dwarf::UnwindLocation::CFAPlusOffset) {
-        Context->reportError(
-            Inst.getLoc(),
-            formatv("Expected %{0} unwinding rule should be [CFA + {1}] but "
-                    "based CFI directives are [CFA + {2}]",
-                    RegLLVMName, PossibleNextRegState.getOffset(),
-                    NextRegState.getOffset()));
-      }
-    }
-  }
-  // Either couldn't generate, or the programmer changed the state to
-  // something that couldn't be matched to any of the generated states. So
-  // it falls back into read/write checks.
-
-  if (PrevRegState == NextRegState) {
-    switch (PrevRegState.getLocation()) {
+  if (PrevRegLoc == NextRegLoc) {
+    switch (PrevRegLoc.getLocation()) {
     case dwarf::UnwindLocation::Same:
     case dwarf::UnwindLocation::RegPlusOffset:
-      if (Writes.count(PrevRefReg.value())) {
+      if (Writes.count(MaybePrevRefReg.value())) {
         Context->reportError(
             Inst.getLoc(),
             formatv("This instruction changes %{1}, that %{0} unwinding rule "
@@ -281,6 +256,9 @@ void CFIAnalysis::checkRegDiff(
       }
       break;
       // TODO think about what to do with expressions here.
+      // TODO the expressions be solved more precise, by looking into the
+      // TODO expression, finding registers that are used and checking if the
+      // TODO instruction is changing them or not.
     default:
       // Everything may be ok
       break;
@@ -288,12 +266,12 @@ void CFIAnalysis::checkRegDiff(
     return;
   }
 
-  if (PrevRegState.getLocation() == NextRegState.getLocation()) {
+  if (PrevRegLoc.getLocation() == NextRegLoc.getLocation()) {
     // Everything may be ok
     return;
   }
 
-  if (PrevRegState.getLocation() == dwarf::UnwindLocation::Undefined) {
+  if (PrevRegLoc.getLocation() == dwarf::UnwindLocation::Undefined) {
     Context->reportError(
         Inst.getLoc(),
         "Changed %{0} unwinding rule from `undefined` to something else");
@@ -308,25 +286,42 @@ void CFIAnalysis::checkRegDiff(
 }
 
 void CFIAnalysis::checkCFADiff(
-    const MCInst &Inst, const dwarf::UnwindTable::const_iterator &PrevState,
-    const dwarf::UnwindTable::const_iterator &NextState,
-    const std::set<UnwindInfoHistory::DWARFRegType> &Reads,
-    const std::set<UnwindInfoHistory::DWARFRegType> &Writes) {
-  // TODO again getting the CFA register in the bad way.
-  const UnwindInfoHistory::DWARFRegType PrevCFAReg =
-      PrevState->getCFAValue().getRegister();
-  const int32_t PrevCFAOffset = PrevState->getCFAValue().getOffset();
-
-  const UnwindInfoHistory::DWARFRegType NextCFAReg =
-      NextState->getCFAValue().getRegister();
-  const int32_t NextCFAOffset = NextState->getCFAValue().getOffset();
+    const MCInst &Inst, const dwarf::UnwindTable::const_iterator &PrevRow,
+    const dwarf::UnwindTable::const_iterator &NextRow,
+    const std::set<DWARFRegType> &Reads, const std::set<DWARFRegType> &Writes) {
+
+  auto MaybePrevCFA = getCFARegOffsetInfo(PrevRow);
+  auto MaybeNextCFA = getCFARegOffsetInfo(NextRow);
+
+  if (!MaybePrevCFA) {
+    if (MaybeNextCFA) {
+      Context->reportWarning(
+          Inst.getLoc(),
+          "CFA rule changed to [reg + offset], not checking the change");
+      return;
+    }
+
+    Context->reportWarning(Inst.getLoc(),
+                           "CFA rule is not [reg + offset], not checking it");
+    return;
+  }
+
+  if (!MaybeNextCFA) {
+    Context->reportWarning(
+        Inst.getLoc(),
+        "CFA rule changed from [reg + offset], not checking the change");
+    return;
+  }
+
+  auto PrevCFA = *MaybePrevCFA;
+  auto NextCFA = *MaybeNextCFA;
 
   const char *PrevCFARegName =
-      MCRI->getName(MCRI->getLLVMRegNum(PrevCFAReg, IsEH).value());
+      MCRI->getName(MCRI->getLLVMRegNum(PrevCFA.Reg, IsEH).value());
 
-  if (PrevCFAReg == NextCFAReg) {
-    if (PrevCFAOffset == NextCFAOffset) {
-      if (Writes.count(PrevCFAReg)) {
+  if (PrevCFA.Reg == NextCFA.Reg) {
+    if (PrevCFA.Offset == NextCFA.Offset) {
+      if (Writes.count(PrevCFA.Reg)) {
         Context->reportError(
             Inst.getLoc(),
             formatv("This instruction modifies CFA register (%{0}) "
@@ -338,9 +333,9 @@ void CFIAnalysis::checkCFADiff(
       // Everything is ok!
       return;
     }
-    // The offset is changed.
 
-    if (!Writes.count(PrevCFAReg)) {
+    // The offset is changed.
+    if (!Writes.count(PrevCFA.Reg)) {
       Context->reportError(
           Inst.getLoc(),
           formatv("This instruction does not modifies CFA register (%{0}) "
diff --git a/llvm/lib/MCCFIAnalysis/UnwindInfoHistory.cpp b/llvm/lib/MCCFIAnalysis/UnwindInfoHistory.cpp
index cc164aabfb1eb..f44ac07bc0acb 100644
--- a/llvm/lib/MCCFIAnalysis/UnwindInfoHistory.cpp
+++ b/llvm/lib/MCCFIAnalysis/UnwindInfoHistory.cpp
@@ -19,31 +19,6 @@ UnwindInfoHistory::getCurrentUnwindRow() const {
   return --Table.end();
 }
 
-std::optional<UnwindInfoHistory::DWARFRegType>
-UnwindInfoHistory::getReferenceRegisterForUnwindInfoOfRegister(
-    const dwarf::UnwindTable::const_iterator &UnwindRow, DWARFRegType Reg) {
-  auto UnwinLoc = UnwindRow->getRegisterLocations().getRegisterLocation(Reg);
-  assert(UnwinLoc &&
-         "The register should be tracked inside the register states");
-
-  switch (UnwinLoc->getLocation()) {
-  case dwarf::UnwindLocation::Location::Undefined:
-  case dwarf::UnwindLocation::Location::Constant:
-  case dwarf::UnwindLocation::Location::Unspecified:
-  case dwarf::UnwindLocation::Location::DWARFExpr:
-    // TODO here should look into expr and find the registers.
-    return std::nullopt;
-  case dwarf::UnwindLocation::Location::Same:
-    return Reg;
-  case dwarf::UnwindLocation::Location::RegPlusOffset:
-    return UnwinLoc->getRegister();
-  case dwarf::UnwindLocation::Location::CFAPlusOffset:
-    // TODO check if it's ok to assume CFA is always depending on other
-    // TODO register, if yes assert it here!
-    return UnwindRow->getCFAValue().getRegister();
-  }
-}
-
 void UnwindInfoHistory::update(const MCCFIInstruction &CFIDirective) {
   auto DwarfOperations = convert(CFIDirective);
   if (!DwarfOperations) {
@@ -60,7 +35,9 @@ void UnwindInfoHistory::update(const MCCFIInstruction &CFIDirective) {
         CFIDirective.getLoc(),
         formatv("could not parse this CFI directive due to: {0}",
                 toString(std::move(Err))));
-    assert(false);
+
+    // Proceed the analysis by ignoring this CFI directive.
+    return;
   }
   Table.insertRow(Row);
 }

>From fa0505bf459de28efb0d44d409118dcc00a44fdf Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Sat, 21 Jun 2025 00:15:14 +0000
Subject: [PATCH 37/58] Rename CFI to Unwind info analysis

---
 .../MCCFIAnalysis/CFIAnalysisMCStreamer.h     |  5 ++---
 .../{CFIAnalysis.h => UnwindInfoAnalysis.h}   |  8 +++----
 llvm/lib/MCCFIAnalysis/CMakeLists.txt         |  2 +-
 ...CFIAnalysis.cpp => UnwindInfoAnalysis.cpp} | 22 +++++++++----------
 4 files changed, 18 insertions(+), 19 deletions(-)
 rename llvm/include/llvm/MCCFIAnalysis/{CFIAnalysis.h => UnwindInfoAnalysis.h} (90%)
 rename llvm/lib/MCCFIAnalysis/{CFIAnalysis.cpp => UnwindInfoAnalysis.cpp} (95%)

diff --git a/llvm/include/llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h b/llvm/include/llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h
index 895457bda3703..be1fede55b612 100644
--- a/llvm/include/llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h
+++ b/llvm/include/llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h
@@ -1,8 +1,7 @@
 #ifndef LLVM_TOOLS_LLVM_MC_CFI_ANALYSIS_MC_STREAMER_H
 #define LLVM_TOOLS_LLVM_MC_CFI_ANALYSIS_MC_STREAMER_H
 
-#include "CFIAnalysis.h"
-#include "llvm/ADT/ArrayRef.h"
+#include "UnwindInfoAnalysis.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCDwarf.h"
 #include "llvm/MC/MCInstrAnalysis.h"
@@ -32,7 +31,7 @@ class CFIAnalysisMCStreamer : public MCStreamer {
     CFIDirectivesState(int FrameIndex, int InstructionIndex);
   } LastCFIDirectivesState;
   std::vector<int> FrameIndices;
-  std::vector<CFIAnalysis> CFIAs;
+  std::vector<UnwindInfoAnalysis> CFIAs;
 
   struct ICFI {
     MCInst Instruction;
diff --git a/llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h b/llvm/include/llvm/MCCFIAnalysis/UnwindInfoAnalysis.h
similarity index 90%
rename from llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h
rename to llvm/include/llvm/MCCFIAnalysis/UnwindInfoAnalysis.h
index ac921e40ededf..5c38439039fcb 100644
--- a/llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h
+++ b/llvm/include/llvm/MCCFIAnalysis/UnwindInfoAnalysis.h
@@ -19,7 +19,7 @@
 
 namespace llvm {
 
-class CFIAnalysis {
+class UnwindInfoAnalysis {
   MCContext *Context;
   MCInstrInfo const &MCII;
   MCRegisterInfo const *MCRI;
@@ -41,9 +41,9 @@ class CFIAnalysis {
   MCPhysReg getSuperReg(MCPhysReg Reg);
 
 public:
-  CFIAnalysis(MCContext *Context, MCInstrInfo const &MCII,
-              MCInstrAnalysis *MCIA, bool IsEH,
-              ArrayRef<MCCFIInstruction> PrologueCFIDirectives);
+  UnwindInfoAnalysis(MCContext *Context, MCInstrInfo const &MCII,
+                     MCInstrAnalysis *MCIA, bool IsEH,
+                     ArrayRef<MCCFIInstruction> PrologueCFIDirectives);
 
   void update(const MCInst &Inst, ArrayRef<MCCFIInstruction> CFIDirectives);
 
diff --git a/llvm/lib/MCCFIAnalysis/CMakeLists.txt b/llvm/lib/MCCFIAnalysis/CMakeLists.txt
index b4a5da108de5b..28329a5653f77 100644
--- a/llvm/lib/MCCFIAnalysis/CMakeLists.txt
+++ b/llvm/lib/MCCFIAnalysis/CMakeLists.txt
@@ -1,7 +1,7 @@
 add_llvm_component_library(LLVMMCCFIAnalysis
   UnwindInfoHistory.cpp
   CFIAnalysisMCStreamer.cpp
-  CFIAnalysis.cpp
+  UnwindInfoAnalysis.cpp
 
   ADDITIONAL_HEADER_DIRS
   ${LLVM_MAIN_INCLUDE_DIR}/llvm/MCA
diff --git a/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp b/llvm/lib/MCCFIAnalysis/UnwindInfoAnalysis.cpp
similarity index 95%
rename from llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp
rename to llvm/lib/MCCFIAnalysis/UnwindInfoAnalysis.cpp
index 5ac88cf56ec5c..1bebbffde5cce 100644
--- a/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp
+++ b/llvm/lib/MCCFIAnalysis/UnwindInfoAnalysis.cpp
@@ -1,4 +1,4 @@
-#include "llvm/MCCFIAnalysis/CFIAnalysis.h"
+#include "llvm/MCCFIAnalysis/UnwindInfoAnalysis.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringExtras.h"
@@ -75,12 +75,12 @@ void printUntilNextLine(const char *Str) {
     dbgs() << Str[I];
 }
 
-bool CFIAnalysis::isSuperReg(MCPhysReg Reg) {
+bool UnwindInfoAnalysis::isSuperReg(MCPhysReg Reg) {
   return MCRI->superregs(Reg).empty();
 }
 
 SmallVector<std::pair<MCPhysReg, MCRegisterClass const *>>
-CFIAnalysis::getAllSuperRegs() {
+UnwindInfoAnalysis::getAllSuperRegs() {
   std::map<MCPhysReg, MCRegisterClass const *> SuperRegs;
   for (auto &&RegClass : MCRI->regclasses()) {
     for (unsigned I = 0; I < RegClass.getNumRegs(); I++) {
@@ -97,7 +97,7 @@ CFIAnalysis::getAllSuperRegs() {
   return SuperRegWithClass;
 }
 
-MCPhysReg CFIAnalysis::getSuperReg(MCPhysReg Reg) {
+MCPhysReg UnwindInfoAnalysis::getSuperReg(MCPhysReg Reg) {
   if (isSuperReg(Reg))
     return Reg;
   for (auto SuperReg : MCRI->superregs(Reg)) {
@@ -108,9 +108,9 @@ MCPhysReg CFIAnalysis::getSuperReg(MCPhysReg Reg) {
   llvm_unreachable("Should either be a super reg, or have a super reg");
 }
 
-CFIAnalysis::CFIAnalysis(MCContext *Context, MCInstrInfo const &MCII,
-                         MCInstrAnalysis *MCIA, bool IsEH,
-                         ArrayRef<MCCFIInstruction> PrologueCFIDirectives)
+UnwindInfoAnalysis::UnwindInfoAnalysis(
+    MCContext *Context, MCInstrInfo const &MCII, MCInstrAnalysis *MCIA,
+    bool IsEH, ArrayRef<MCCFIInstruction> PrologueCFIDirectives)
     : Context(Context), MCII(MCII), MCRI(Context->getRegisterInfo()),
       State(Context), IsEH(IsEH) {
 
@@ -152,8 +152,8 @@ CFIAnalysis::CFIAnalysis(MCContext *Context, MCInstrInfo const &MCII,
   }
 }
 
-void CFIAnalysis::update(const MCInst &Inst,
-                         ArrayRef<MCCFIInstruction> CFIDirectives) {
+void UnwindInfoAnalysis::update(const MCInst &Inst,
+                                ArrayRef<MCCFIInstruction> CFIDirectives) {
   const MCInstrDesc &MCInstInfo = MCII.get(Inst.getOpcode());
 
   auto MaybePrevUnwindRow = State.getCurrentUnwindRow();
@@ -215,7 +215,7 @@ void CFIAnalysis::update(const MCInst &Inst,
   }
 }
 
-void CFIAnalysis::checkRegDiff(
+void UnwindInfoAnalysis::checkRegDiff(
     const MCInst &Inst, DWARFRegType Reg,
     const dwarf::UnwindTable::const_iterator &PrevRow,
     const dwarf::UnwindTable::const_iterator &NextRow,
@@ -285,7 +285,7 @@ void CFIAnalysis::checkRegDiff(
   return;
 }
 
-void CFIAnalysis::checkCFADiff(
+void UnwindInfoAnalysis::checkCFADiff(
     const MCInst &Inst, const dwarf::UnwindTable::const_iterator &PrevRow,
     const dwarf::UnwindTable::const_iterator &NextRow,
     const std::set<DWARFRegType> &Reads, const std::set<DWARFRegType> &Writes) {

>From ff81fa22e98e71af45f1074bc601274e87ed7167 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Sat, 21 Jun 2025 00:52:02 +0000
Subject: [PATCH 38/58] Remove MCInstrAnalysis from UnwindInfo analysis

---
 llvm/include/llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h | 1 -
 llvm/include/llvm/MCCFIAnalysis/UnwindInfoAnalysis.h    | 3 +--
 llvm/lib/MCCFIAnalysis/CFIAnalysisMCStreamer.cpp        | 6 +++---
 llvm/lib/MCCFIAnalysis/UnwindInfoAnalysis.cpp           | 4 ++--
 4 files changed, 6 insertions(+), 8 deletions(-)

diff --git a/llvm/include/llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h b/llvm/include/llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h
index be1fede55b612..60e7dcbe53331 100644
--- a/llvm/include/llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h
+++ b/llvm/include/llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h
@@ -21,7 +21,6 @@ namespace llvm {
 // TODO receiver.
 class CFIAnalysisMCStreamer : public MCStreamer {
   MCInstrInfo const &MCII;
-  std::unique_ptr<MCInstrAnalysis> MCIA;
 
   struct CFIDirectivesState {
     int DirectiveIndex;
diff --git a/llvm/include/llvm/MCCFIAnalysis/UnwindInfoAnalysis.h b/llvm/include/llvm/MCCFIAnalysis/UnwindInfoAnalysis.h
index 5c38439039fcb..acf5ec2139307 100644
--- a/llvm/include/llvm/MCCFIAnalysis/UnwindInfoAnalysis.h
+++ b/llvm/include/llvm/MCCFIAnalysis/UnwindInfoAnalysis.h
@@ -41,8 +41,7 @@ class UnwindInfoAnalysis {
   MCPhysReg getSuperReg(MCPhysReg Reg);
 
 public:
-  UnwindInfoAnalysis(MCContext *Context, MCInstrInfo const &MCII,
-                     MCInstrAnalysis *MCIA, bool IsEH,
+  UnwindInfoAnalysis(MCContext *Context, MCInstrInfo const &MCII, bool IsEH,
                      ArrayRef<MCCFIInstruction> PrologueCFIDirectives);
 
   void update(const MCInst &Inst, ArrayRef<MCCFIInstruction> CFIDirectives);
diff --git a/llvm/lib/MCCFIAnalysis/CFIAnalysisMCStreamer.cpp b/llvm/lib/MCCFIAnalysis/CFIAnalysisMCStreamer.cpp
index 822f7c3d61089..b7b5e1fd37905 100644
--- a/llvm/lib/MCCFIAnalysis/CFIAnalysisMCStreamer.cpp
+++ b/llvm/lib/MCCFIAnalysis/CFIAnalysisMCStreamer.cpp
@@ -71,7 +71,7 @@ void CFIAnalysisMCStreamer::feedCFIA() {
 
     CFIAs.back().update(LastInstruction.value(), CFIDirectives);
   } else {
-    CFIAs.emplace_back(&getContext(), MCII, MCIA.get(),
+    CFIAs.emplace_back(&getContext(), MCII,
                        false /* TODO should put isEH here */, CFIDirectives);
   }
 }
@@ -79,8 +79,8 @@ void CFIAnalysisMCStreamer::feedCFIA() {
 CFIAnalysisMCStreamer::CFIAnalysisMCStreamer(
     MCContext &Context, const MCInstrInfo &MCII,
     std::unique_ptr<MCInstrAnalysis> MCIA)
-    : MCStreamer(Context), MCII(MCII), MCIA(std::move(MCIA)),
-      LastCFIDirectivesState(), LastInstruction(std::nullopt) {
+    : MCStreamer(Context), MCII(MCII), LastCFIDirectivesState(),
+      LastInstruction(std::nullopt) {
   FrameIndices.push_back(-1);
 }
 
diff --git a/llvm/lib/MCCFIAnalysis/UnwindInfoAnalysis.cpp b/llvm/lib/MCCFIAnalysis/UnwindInfoAnalysis.cpp
index 1bebbffde5cce..263c5e280498b 100644
--- a/llvm/lib/MCCFIAnalysis/UnwindInfoAnalysis.cpp
+++ b/llvm/lib/MCCFIAnalysis/UnwindInfoAnalysis.cpp
@@ -109,8 +109,8 @@ MCPhysReg UnwindInfoAnalysis::getSuperReg(MCPhysReg Reg) {
 }
 
 UnwindInfoAnalysis::UnwindInfoAnalysis(
-    MCContext *Context, MCInstrInfo const &MCII, MCInstrAnalysis *MCIA,
-    bool IsEH, ArrayRef<MCCFIInstruction> PrologueCFIDirectives)
+    MCContext *Context, MCInstrInfo const &MCII, bool IsEH,
+    ArrayRef<MCCFIInstruction> PrologueCFIDirectives)
     : Context(Context), MCII(MCII), MCRI(Context->getRegisterInfo()),
       State(Context), IsEH(IsEH) {
 

>From 0cf499edb13d77d90692eea70cf6f06f923d1acf Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Sat, 21 Jun 2025 22:14:38 +0000
Subject: [PATCH 39/58] Remove redundant definitions and fields from
 CFIAnalysis streamer

---
 .../MCCFIAnalysis/CFIAnalysisMCStreamer.h     |  32 ++---
 .../MCCFIAnalysis/CFIAnalysisMCStreamer.cpp   | 130 ++++++++----------
 llvm/tools/llvm-mc/llvm-mc.cpp                |   6 +-
 3 files changed, 66 insertions(+), 102 deletions(-)

diff --git a/llvm/include/llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h b/llvm/include/llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h
index 60e7dcbe53331..f2c791a2addaf 100644
--- a/llvm/include/llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h
+++ b/llvm/include/llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h
@@ -4,11 +4,9 @@
 #include "UnwindInfoAnalysis.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCDwarf.h"
-#include "llvm/MC/MCInstrAnalysis.h"
 #include "llvm/MC/MCInstrInfo.h"
 #include "llvm/MC/MCStreamer.h"
 #include <cstdio>
-#include <memory>
 #include <optional>
 
 namespace llvm {
@@ -19,35 +17,23 @@ namespace llvm {
 // TODO one by one. Also in each function unit, an instruction with associated
 // TODO directives should be emitted. The analysis should be run by the
 // TODO receiver.
-class CFIAnalysisMCStreamer : public MCStreamer {
+class FunctionUnitStreamer : public MCStreamer {
   MCInstrInfo const &MCII;
 
-  struct CFIDirectivesState {
-    int DirectiveIndex;
-
-    CFIDirectivesState();
-
-    CFIDirectivesState(int FrameIndex, int InstructionIndex);
-  } LastCFIDirectivesState;
-  std::vector<int> FrameIndices;
-  std::vector<UnwindInfoAnalysis> CFIAs;
-
-  struct ICFI {
-    MCInst Instruction;
-    std::pair<unsigned, unsigned> CFIDirectivesRange;
-
-    ICFI(MCInst Instruction, std::pair<unsigned, unsigned> CFIDirectives);
-  };
+  std::vector<unsigned> FrameIndices;
+  std::vector<UnwindInfoAnalysis> UIAs;
 
+  unsigned LastDirectiveIndex;
   std::optional<MCInst> LastInstruction;
 
-  std::pair<unsigned, unsigned> getCFIDirectivesRange();
+  void updateUIA();
 
-  void feedCFIA();
+  std::pair<unsigned, unsigned> updateDirectivesRange();
 
 public:
-  CFIAnalysisMCStreamer(MCContext &Context, const MCInstrInfo &MCII,
-                        std::unique_ptr<MCInstrAnalysis> MCIA);
+  FunctionUnitStreamer(MCContext &Context, const MCInstrInfo &MCII)
+      : MCStreamer(Context), MCII(MCII), LastDirectiveIndex(0),
+        LastInstruction(std::nullopt) {}
 
   bool hasRawTextSupport() const override { return true; }
   void emitRawTextImpl(StringRef String) override {}
diff --git a/llvm/lib/MCCFIAnalysis/CFIAnalysisMCStreamer.cpp b/llvm/lib/MCCFIAnalysis/CFIAnalysisMCStreamer.cpp
index b7b5e1fd37905..827560aa28f1d 100644
--- a/llvm/lib/MCCFIAnalysis/CFIAnalysisMCStreamer.cpp
+++ b/llvm/lib/MCCFIAnalysis/CFIAnalysisMCStreamer.cpp
@@ -3,110 +3,92 @@
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCDwarf.h"
-#include "llvm/MC/MCInstrAnalysis.h"
 #include "llvm/MC/MCInstrInfo.h"
 #include "llvm/MC/MCStreamer.h"
 #include <cstdio>
-#include <memory>
 #include <optional>
 
 using namespace llvm;
 
-CFIAnalysisMCStreamer::CFIDirectivesState::CFIDirectivesState()
-    : DirectiveIndex(0) {}
-
-CFIAnalysisMCStreamer::CFIDirectivesState::CFIDirectivesState(
-    int FrameIndex, int InstructionIndex)
-    : DirectiveIndex(InstructionIndex) {}
-
-CFIAnalysisMCStreamer::ICFI::ICFI(MCInst Instruction,
-                                  std::pair<unsigned, unsigned> CFIDirectives)
-    : Instruction(Instruction), CFIDirectivesRange(CFIDirectives) {}
-
-std::pair<unsigned, unsigned> CFIAnalysisMCStreamer::getCFIDirectivesRange() {
-  auto DwarfFrameInfos = getDwarfFrameInfos();
-  int FrameIndex = FrameIndices.back();
-  auto CurrentCFIDirectiveState =
-      hasUnfinishedDwarfFrameInfo()
-          ? CFIDirectivesState(FrameIndex,
-                               DwarfFrameInfos[FrameIndex].Instructions.size())
-          : CFIDirectivesState();
-  assert(CurrentCFIDirectiveState.DirectiveIndex >=
-         LastCFIDirectivesState.DirectiveIndex);
+std::pair<unsigned, unsigned> FunctionUnitStreamer::updateDirectivesRange() {
+  auto Frames = getDwarfFrameInfos();
+  unsigned CurrentCFIDirectiveIndex = 0;
+  if (hasUnfinishedDwarfFrameInfo()) {
+    assert(!FrameIndices.empty() && "FunctionUnitStreamer frame indices should "
+                                    "be synced with MCStreamer's");
+    assert(FrameIndices.back() < Frames.size());
+    CurrentCFIDirectiveIndex = Frames[FrameIndices.back()].Instructions.size();
+  }
 
-  std::pair<unsigned, unsigned> CFIDirectivesRange(
-      LastCFIDirectivesState.DirectiveIndex,
-      CurrentCFIDirectiveState.DirectiveIndex);
-  LastCFIDirectivesState = CurrentCFIDirectiveState;
+  assert(CurrentCFIDirectiveIndex >= LastDirectiveIndex);
+  std::pair<unsigned, unsigned> CFIDirectivesRange(LastDirectiveIndex,
+                                                   CurrentCFIDirectiveIndex);
+  LastDirectiveIndex = CurrentCFIDirectiveIndex;
   return CFIDirectivesRange;
 }
 
-void CFIAnalysisMCStreamer::feedCFIA() {
-  auto FrameIndex = FrameIndices.back();
-  if (FrameIndex < 0) {
-    // TODO Maybe this corner case causes bugs, when the programmer did a
-    // mistake in the startproc, endprocs and also made a mistake in not
-    // adding cfi directives for a instruction. Then this would cause to
-    // ignore the instruction.
-    auto CFIDirectivesRange = getCFIDirectivesRange();
-    assert(!LastInstruction ||
-           CFIDirectivesRange.first == CFIDirectivesRange.second);
+void FunctionUnitStreamer::updateUIA() {
+  if (FrameIndices.empty()) {
+    auto CFIDirectivesRange = updateDirectivesRange();
+    assert(CFIDirectivesRange.first == CFIDirectivesRange.second &&
+           "CFI directives should be in some frame");
     return;
   }
 
-  const auto *LastDwarfFrameInfo = &getDwarfFrameInfos()[FrameIndex];
+  const auto *LastFrame = &getDwarfFrameInfos()[FrameIndices.back()];
 
-  auto CFIDirectivesRange = getCFIDirectivesRange();
-  ArrayRef<MCCFIInstruction> CFIDirectives;
-  if (CFIDirectivesRange.first < CFIDirectivesRange.second) {
-    CFIDirectives =
-        ArrayRef<MCCFIInstruction>(LastDwarfFrameInfo->Instructions);
-    CFIDirectives = CFIDirectives.drop_front(CFIDirectivesRange.first)
-                        .drop_back(LastDwarfFrameInfo->Instructions.size() -
-                                   CFIDirectivesRange.second);
+  auto DirectivesRange = updateDirectivesRange();
+  ArrayRef<MCCFIInstruction> Directives;
+  if (DirectivesRange.first < DirectivesRange.second) {
+    Directives = ArrayRef<MCCFIInstruction>(LastFrame->Instructions);
+    Directives =
+        Directives.drop_front(DirectivesRange.first)
+            .drop_back(LastFrame->Instructions.size() - DirectivesRange.second);
   }
 
-  if (LastInstruction != std::nullopt) {
-    assert(!CFIAs.empty());
-
-    CFIAs.back().update(LastInstruction.value(), CFIDirectives);
+  if (LastInstruction) {
+    assert(!UIAs.empty() && "If the instruction is in a frame, there should be "
+                            "a analysis instantiated for it");
+    UIAs.back().update(LastInstruction.value(), Directives);
   } else {
-    CFIAs.emplace_back(&getContext(), MCII,
-                       false /* TODO should put isEH here */, CFIDirectives);
+    assert(!DirectivesRange.first &&
+           "An analysis should be created at the begining of a frame");
+    UIAs.emplace_back(&getContext(), MCII,
+                      false /* TODO should put isEH here */, Directives);
   }
 }
 
-CFIAnalysisMCStreamer::CFIAnalysisMCStreamer(
-    MCContext &Context, const MCInstrInfo &MCII,
-    std::unique_ptr<MCInstrAnalysis> MCIA)
-    : MCStreamer(Context), MCII(MCII), LastCFIDirectivesState(),
-      LastInstruction(std::nullopt) {
-  FrameIndices.push_back(-1);
-}
-
-void CFIAnalysisMCStreamer::emitInstruction(const MCInst &Inst,
-                                            const MCSubtargetInfo &STI) {
-  feedCFIA();
+void FunctionUnitStreamer::emitInstruction(const MCInst &Inst,
+                                           const MCSubtargetInfo &STI) {
+  updateUIA();
   LastInstruction = Inst;
 }
 
-void CFIAnalysisMCStreamer::emitCFIStartProcImpl(MCDwarfFrameInfo &Frame) {
-  feedCFIA();
+void FunctionUnitStreamer::emitCFIStartProcImpl(MCDwarfFrameInfo &Frame) {
+  updateUIA();
   FrameIndices.push_back(getNumFrameInfos());
   LastInstruction = std::nullopt;
-  LastCFIDirectivesState.DirectiveIndex = 0;
+  LastDirectiveIndex = 0;
   MCStreamer::emitCFIStartProcImpl(Frame);
 }
 
-void CFIAnalysisMCStreamer::emitCFIEndProcImpl(MCDwarfFrameInfo &CurFrame) {
-  feedCFIA();
-  // TODO this will break if the input frame are malformed.
+void FunctionUnitStreamer::emitCFIEndProcImpl(MCDwarfFrameInfo &CurFrame) {
+  updateUIA();
+
+  assert(!FrameIndices.empty() && "There should be at least one frame to pop");
   FrameIndices.pop_back();
-  CFIAs.pop_back();
+
+  assert(!UIAs.empty() && "There should be an analysis for each frame");
+  UIAs.pop_back();
+
   LastInstruction = std::nullopt;
-  auto FrameIndex = FrameIndices.back();
-  LastCFIDirectivesState.DirectiveIndex =
-      FrameIndex >= 0 ? getDwarfFrameInfos()[FrameIndex].Instructions.size()
-                      : 0;
+  LastDirectiveIndex = 0;
+  if (!FrameIndices.empty()) {
+    auto DwarfFrameInfos = getDwarfFrameInfos();
+    assert(FrameIndices.back() < DwarfFrameInfos.size());
+
+    LastDirectiveIndex =
+        DwarfFrameInfos[FrameIndices.back()].Instructions.size();
+  }
   MCStreamer::emitCFIEndProcImpl(CurFrame);
 }
diff --git a/llvm/tools/llvm-mc/llvm-mc.cpp b/llvm/tools/llvm-mc/llvm-mc.cpp
index c2852298aacb6..eb1a9da56de9d 100644
--- a/llvm/tools/llvm-mc/llvm-mc.cpp
+++ b/llvm/tools/llvm-mc/llvm-mc.cpp
@@ -524,14 +524,10 @@ int main(int argc, char **argv) {
   std::unique_ptr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo());
   assert(MCII && "Unable to create instruction info!");
 
-  std::unique_ptr<MCInstrAnalysis> MCIA(
-      TheTarget->createMCInstrAnalysis(MCII.get()));
-  assert(MCIA && "Unable to create instruction analysis!");
-
   std::unique_ptr<MCInstPrinter> IP;
   if (ValidateCFI) {
     assert(FileType == OFT_Null);
-    auto *CFIAMCS = new CFIAnalysisMCStreamer(Ctx, *MCII, std::move(MCIA));
+    auto *CFIAMCS = new FunctionUnitStreamer(Ctx, *MCII);
     TheTarget->createNullTargetStreamer(*CFIAMCS);
     Str.reset(CFIAMCS);
   } else if (FileType == OFT_AssemblyFile) {

>From 969f86f987309467e4f818a03f8c39b3acb3ae65 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Sat, 21 Jun 2025 22:36:09 +0000
Subject: [PATCH 40/58] Rename CFIAnalysisStreamer to FunctionUnitStreamer

---
 ...IAnalysisMCStreamer.h => FunctionUnitStreamer.h} | 13 +++++++------
 llvm/lib/MCCFIAnalysis/CMakeLists.txt               |  2 +-
 ...lysisMCStreamer.cpp => FunctionUnitStreamer.cpp} |  2 +-
 llvm/tools/llvm-mc/llvm-mc.cpp                      |  2 +-
 4 files changed, 10 insertions(+), 9 deletions(-)
 rename llvm/include/llvm/MCCFIAnalysis/{CFIAnalysisMCStreamer.h => FunctionUnitStreamer.h} (79%)
 rename llvm/lib/MCCFIAnalysis/{CFIAnalysisMCStreamer.cpp => FunctionUnitStreamer.cpp} (98%)

diff --git a/llvm/include/llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h b/llvm/include/llvm/MCCFIAnalysis/FunctionUnitStreamer.h
similarity index 79%
rename from llvm/include/llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h
rename to llvm/include/llvm/MCCFIAnalysis/FunctionUnitStreamer.h
index f2c791a2addaf..164e810d1b667 100644
--- a/llvm/include/llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h
+++ b/llvm/include/llvm/MCCFIAnalysis/FunctionUnitStreamer.h
@@ -11,12 +11,13 @@
 
 namespace llvm {
 
-// TODO Now the design is that the streamer, make instances of the analysis and
-// TODO run the analysis on the instruction, but instead the streamer should
-// TODO divide the program into function units, and then emit the function units
-// TODO one by one. Also in each function unit, an instruction with associated
-// TODO directives should be emitted. The analysis should be run by the
-// TODO receiver.
+// ? Now the design is that the streamer, make instances of the analysis and
+// ? run the analysis on the instruction, I suspect that instead the streamer
+// ? should divide the program into function units, and then emit the function
+// ? units one by one. Also in each function unit, an instruction with
+// ? associated directives should be emitted. Furthermore, there should be a
+// ? receiver of these function units, that receive them and run a new analysis
+// ? on them.
 class FunctionUnitStreamer : public MCStreamer {
   MCInstrInfo const &MCII;
 
diff --git a/llvm/lib/MCCFIAnalysis/CMakeLists.txt b/llvm/lib/MCCFIAnalysis/CMakeLists.txt
index 28329a5653f77..3662f3e5a53e1 100644
--- a/llvm/lib/MCCFIAnalysis/CMakeLists.txt
+++ b/llvm/lib/MCCFIAnalysis/CMakeLists.txt
@@ -1,6 +1,6 @@
 add_llvm_component_library(LLVMMCCFIAnalysis
+  FunctionUnitStreamer.cpp
   UnwindInfoHistory.cpp
-  CFIAnalysisMCStreamer.cpp
   UnwindInfoAnalysis.cpp
 
   ADDITIONAL_HEADER_DIRS
diff --git a/llvm/lib/MCCFIAnalysis/CFIAnalysisMCStreamer.cpp b/llvm/lib/MCCFIAnalysis/FunctionUnitStreamer.cpp
similarity index 98%
rename from llvm/lib/MCCFIAnalysis/CFIAnalysisMCStreamer.cpp
rename to llvm/lib/MCCFIAnalysis/FunctionUnitStreamer.cpp
index 827560aa28f1d..d455c8692aab6 100644
--- a/llvm/lib/MCCFIAnalysis/CFIAnalysisMCStreamer.cpp
+++ b/llvm/lib/MCCFIAnalysis/FunctionUnitStreamer.cpp
@@ -1,5 +1,5 @@
 
-#include "llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h"
+#include "llvm/MCCFIAnalysis/FunctionUnitStreamer.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCDwarf.h"
diff --git a/llvm/tools/llvm-mc/llvm-mc.cpp b/llvm/tools/llvm-mc/llvm-mc.cpp
index eb1a9da56de9d..52363927d6668 100644
--- a/llvm/tools/llvm-mc/llvm-mc.cpp
+++ b/llvm/tools/llvm-mc/llvm-mc.cpp
@@ -14,7 +14,6 @@
 #include "Disassembler.h"
 #include "llvm/MC/MCAsmBackend.h"
 #include "llvm/MC/MCAsmInfo.h"
-#include "llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h"
 #include "llvm/MC/MCCodeEmitter.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCInstPrinter.h"
@@ -30,6 +29,7 @@
 #include "llvm/MC/MCTargetOptions.h"
 #include "llvm/MC/MCTargetOptionsCommandFlags.h"
 #include "llvm/MC/TargetRegistry.h"
+#include "llvm/MCCFIAnalysis/FunctionUnitStreamer.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Compression.h"
 #include "llvm/Support/FileUtilities.h"

>From c57ed1440112b8f011494872b38c3015add6b718 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Mon, 23 Jun 2025 18:00:02 +0000
Subject: [PATCH 41/58] Test function unit streamer functionalities

---
 .../llvm-mc/cfi-validation/empty-section.s    |  9 +++++++
 .../cfi-validation/multiple-sections.s        | 26 +++++++++++++++++++
 2 files changed, 35 insertions(+)
 create mode 100644 llvm/test/tools/llvm-mc/cfi-validation/empty-section.s
 create mode 100644 llvm/test/tools/llvm-mc/cfi-validation/multiple-sections.s

diff --git a/llvm/test/tools/llvm-mc/cfi-validation/empty-section.s b/llvm/test/tools/llvm-mc/cfi-validation/empty-section.s
new file mode 100644
index 0000000000000..849e49f5cba35
--- /dev/null
+++ b/llvm/test/tools/llvm-mc/cfi-validation/empty-section.s
@@ -0,0 +1,9 @@
+# RUN: llvm-mc %s --validate-cfi --filetype=null 2>&1
+.text
+        .globl  f
+        .type   f, @function
+f:
+        .cfi_startproc
+.Lfunc_end0:
+        .size   f, .Lfunc_end0-f
+        .cfi_endproc
\ No newline at end of file
diff --git a/llvm/test/tools/llvm-mc/cfi-validation/multiple-sections.s b/llvm/test/tools/llvm-mc/cfi-validation/multiple-sections.s
new file mode 100644
index 0000000000000..a045c94841435
--- /dev/null
+++ b/llvm/test/tools/llvm-mc/cfi-validation/multiple-sections.s
@@ -0,0 +1,26 @@
+# RUN: not llvm-mc %s --validate-cfi --filetype=null 2>&1 \
+# RUN:   | FileCheck %s 
+.text
+        .globl  f
+        .type   f, @function
+f:
+        .cfi_startproc
+        pushq %rax
+        # CHECK: error: This instruction modifies CFA register (%RSP) but CFA rule is not changed
+        pushq %rax
+        .cfi_def_cfa %rbp, -24
+        pushq %rax
+        .cfi_endproc
+
+        .cfi_startproc
+        pushq %rax
+        # CHECK: error: This instruction modifies CFA register (%RSP) but CFA rule is not changed
+        pushq %rax
+        .cfi_def_cfa %rbp, -24
+        pushq %rax
+        .cfi_endproc
+
+        retq
+
+.Lfunc_end0:
+        .size   f, .Lfunc_end0-f
\ No newline at end of file

>From 0a8f747e63ec2831bd36a4988ab4308ffd5c7e39 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Tue, 24 Jun 2025 00:46:44 +0000
Subject: [PATCH 42/58] Fix the CFIProgram usage temporary

---
 llvm/include/llvm/DebugInfo/DWARF/DWARFCFIProgram.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFCFIProgram.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFCFIProgram.h
index 1d89ac3578c10..0badfab89c839 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFCFIProgram.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFCFIProgram.h
@@ -112,7 +112,8 @@ class CFIProgram {
   /// above. This is indexed by opcode.
   LLVM_ABI static ArrayRef<OperandType[MaxOperands]> getOperandTypes();
 
-private:
+//! FIX me, making these methods public to be usable inside the UnwindInfoAnalysis
+// private:
   std::vector<Instruction> Instructions;
   const uint64_t CodeAlignmentFactor;
   const int64_t DataAlignmentFactor;

>From 48472ac62adac26ae174f83e6dd4e465b5fb6f7f Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Tue, 24 Jun 2025 03:24:32 +0000
Subject: [PATCH 43/58] Minimize check reg diff arguments

---
 .../llvm/MCCFIAnalysis/UnwindInfoAnalysis.h   |  2 -
 llvm/lib/MCCFIAnalysis/UnwindInfoAnalysis.cpp | 39 +++++++++----------
 2 files changed, 18 insertions(+), 23 deletions(-)

diff --git a/llvm/include/llvm/MCCFIAnalysis/UnwindInfoAnalysis.h b/llvm/include/llvm/MCCFIAnalysis/UnwindInfoAnalysis.h
index acf5ec2139307..66c22cd6e16d1 100644
--- a/llvm/include/llvm/MCCFIAnalysis/UnwindInfoAnalysis.h
+++ b/llvm/include/llvm/MCCFIAnalysis/UnwindInfoAnalysis.h
@@ -50,8 +50,6 @@ class UnwindInfoAnalysis {
   void checkRegDiff(const MCInst &Inst, DWARFRegType Reg,
                     const dwarf::UnwindTable::const_iterator &PrevRow,
                     const dwarf::UnwindTable::const_iterator &NextRow,
-                    const dwarf::UnwindLocation &PrevRegLoc,
-                    const dwarf::UnwindLocation &NextRegLoc,
                     const std::set<DWARFRegType> &Reads,
                     const std::set<DWARFRegType> &Writes);
 
diff --git a/llvm/lib/MCCFIAnalysis/UnwindInfoAnalysis.cpp b/llvm/lib/MCCFIAnalysis/UnwindInfoAnalysis.cpp
index 263c5e280498b..2f26374a12572 100644
--- a/llvm/lib/MCCFIAnalysis/UnwindInfoAnalysis.cpp
+++ b/llvm/lib/MCCFIAnalysis/UnwindInfoAnalysis.cpp
@@ -193,25 +193,7 @@ void UnwindInfoAnalysis::update(const MCInst &Inst,
   for (auto [LLVMReg, _] : getAllSuperRegs()) {
     DWARFRegType Reg = MCRI->getDwarfRegNum(LLVMReg, IsEH);
 
-    auto MaybePrevUnwindLoc =
-        PrevUnwindRow->getRegisterLocations().getRegisterLocation(Reg);
-    auto MaybeNextUnwindLoc =
-        CurrentUnwindRow->getRegisterLocations().getRegisterLocation(Reg);
-
-    if (!MaybePrevUnwindLoc) {
-      assert(!MaybeNextUnwindLoc && "The register unwind info suddenly "
-                                    "appeared here, ignoring this change");
-      continue;
-    }
-
-    assert(MaybeNextUnwindLoc && "The register unwind info suddenly vanished "
-                                 "here, ignoring this change");
-
-    auto PrevUnwindLoc = MaybePrevUnwindLoc.value();
-    auto NextUnwindLoc = MaybeNextUnwindLoc.value();
-
-    checkRegDiff(Inst, Reg, PrevUnwindRow, CurrentUnwindRow, PrevUnwindLoc,
-                 NextUnwindLoc, Reads, Writes);
+    checkRegDiff(Inst, Reg, PrevUnwindRow, CurrentUnwindRow, Reads, Writes);
   }
 }
 
@@ -219,9 +201,24 @@ void UnwindInfoAnalysis::checkRegDiff(
     const MCInst &Inst, DWARFRegType Reg,
     const dwarf::UnwindTable::const_iterator &PrevRow,
     const dwarf::UnwindTable::const_iterator &NextRow,
-    const dwarf::UnwindLocation &PrevRegLoc,
-    const dwarf::UnwindLocation &NextRegLoc,
     const std::set<DWARFRegType> &Reads, const std::set<DWARFRegType> &Writes) {
+  auto MaybePrevUnwindLoc =
+      PrevRow->getRegisterLocations().getRegisterLocation(Reg);
+  auto MaybeNextUnwindLoc =
+      NextRow->getRegisterLocations().getRegisterLocation(Reg);
+
+  if (!MaybePrevUnwindLoc) {
+    assert(!MaybeNextUnwindLoc && "The register unwind info suddenly "
+                                  "appeared here, ignoring this change");
+    return;
+  }
+
+  assert(MaybeNextUnwindLoc && "The register unwind info suddenly vanished "
+                               "here, ignoring this change");
+
+  auto PrevRegLoc = MaybePrevUnwindLoc.value();
+  auto NextRegLoc = MaybeNextUnwindLoc.value();
+
   auto MaybeRegLLVM = MCRI->getLLVMRegNum(Reg, IsEH);
   if (!MaybeRegLLVM) {
     assert(PrevRegLoc == NextRegLoc &&

>From 9b09b49e974d861cf663221c4f79bf8a6e0018a0 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Tue, 24 Jun 2025 18:53:26 +0000
Subject: [PATCH 44/58] Move `FunctionUnitStreamer` analysis calls to a
 different class called `FunctionUnitAnalyzer`.

Define `FunctionUnitUnwindInfoAnalyzer` that executes the Analysis during the stream.

The main reasons for doing this is:
- This is compatible with other use cases of `MCStreamer` implementers (e.g. `MCAsmStreamer` and `MCAssembler`).
- This approach result in on the fly analysis, if it was implemented like `RecordStreamer`, then all the instruction of the whole program have to be copied and be stored in the memory.
---
 .../llvm/MCCFIAnalysis/FunctionUnitAnalyzer.h | 36 +++++++++++++++++++
 .../llvm/MCCFIAnalysis/FunctionUnitStreamer.h | 26 ++++++--------
 .../FunctionUnitUnwindInfoAnalyzer.h          | 30 ++++++++++++++++
 llvm/lib/MCCFIAnalysis/CMakeLists.txt         |  2 ++
 .../MCCFIAnalysis/FunctionUnitAnalyzer.cpp    | 13 +++++++
 .../MCCFIAnalysis/FunctionUnitStreamer.cpp    | 21 +++++------
 .../FunctionUnitUnwindInfoAnalyzer.cpp        | 20 +++++++++++
 llvm/tools/llvm-mc/llvm-mc.cpp                | 10 ++++--
 8 files changed, 126 insertions(+), 32 deletions(-)
 create mode 100644 llvm/include/llvm/MCCFIAnalysis/FunctionUnitAnalyzer.h
 create mode 100644 llvm/include/llvm/MCCFIAnalysis/FunctionUnitUnwindInfoAnalyzer.h
 create mode 100644 llvm/lib/MCCFIAnalysis/FunctionUnitAnalyzer.cpp
 create mode 100644 llvm/lib/MCCFIAnalysis/FunctionUnitUnwindInfoAnalyzer.cpp

diff --git a/llvm/include/llvm/MCCFIAnalysis/FunctionUnitAnalyzer.h b/llvm/include/llvm/MCCFIAnalysis/FunctionUnitAnalyzer.h
new file mode 100644
index 0000000000000..aa0eb13e016be
--- /dev/null
+++ b/llvm/include/llvm/MCCFIAnalysis/FunctionUnitAnalyzer.h
@@ -0,0 +1,36 @@
+#ifndef LLVM_MC_CFI_ANALYSIS_FUNCTION_UNIT_ANALYZER_H
+#define LLVM_MC_CFI_ANALYSIS_FUNCTION_UNIT_ANALYZER_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include <cstdio>
+
+namespace llvm {
+
+class MCCFIInstruction;
+class MCContext;
+class MCInst;
+
+class FunctionUnitAnalyzer {
+private:
+  MCContext &Context;
+
+public:
+  FunctionUnitAnalyzer(const FunctionUnitAnalyzer &) = delete;
+  FunctionUnitAnalyzer &operator=(const FunctionUnitAnalyzer &) = delete;
+  virtual ~FunctionUnitAnalyzer();
+
+  FunctionUnitAnalyzer(MCContext &Context) : Context(Context) {}
+
+  MCContext &getContext() const { return Context; }
+
+  virtual void startFunctionUnit(bool IsEH,
+                                 ArrayRef<MCCFIInstruction> Prologue);
+  virtual void
+  emitInstructionAndDirectives(const MCInst &Inst,
+                               ArrayRef<MCCFIInstruction> Directives);
+  virtual void finishFunctionUnit();
+};
+
+} // namespace llvm
+
+#endif
\ No newline at end of file
diff --git a/llvm/include/llvm/MCCFIAnalysis/FunctionUnitStreamer.h b/llvm/include/llvm/MCCFIAnalysis/FunctionUnitStreamer.h
index 164e810d1b667..fa104b15a330c 100644
--- a/llvm/include/llvm/MCCFIAnalysis/FunctionUnitStreamer.h
+++ b/llvm/include/llvm/MCCFIAnalysis/FunctionUnitStreamer.h
@@ -1,40 +1,34 @@
 #ifndef LLVM_TOOLS_LLVM_MC_CFI_ANALYSIS_MC_STREAMER_H
 #define LLVM_TOOLS_LLVM_MC_CFI_ANALYSIS_MC_STREAMER_H
 
-#include "UnwindInfoAnalysis.h"
+#include "FunctionUnitAnalyzer.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCDwarf.h"
 #include "llvm/MC/MCInstrInfo.h"
 #include "llvm/MC/MCStreamer.h"
 #include <cstdio>
+#include <memory>
 #include <optional>
 
 namespace llvm {
 
-// ? Now the design is that the streamer, make instances of the analysis and
-// ? run the analysis on the instruction, I suspect that instead the streamer
-// ? should divide the program into function units, and then emit the function
-// ? units one by one. Also in each function unit, an instruction with
-// ? associated directives should be emitted. Furthermore, there should be a
-// ? receiver of these function units, that receive them and run a new analysis
-// ? on them.
 class FunctionUnitStreamer : public MCStreamer {
-  MCInstrInfo const &MCII;
-
   std::vector<unsigned> FrameIndices;
-  std::vector<UnwindInfoAnalysis> UIAs;
 
   unsigned LastDirectiveIndex;
   std::optional<MCInst> LastInstruction;
-
-  void updateUIA();
+  std::unique_ptr<FunctionUnitAnalyzer> Analyzer;
 
   std::pair<unsigned, unsigned> updateDirectivesRange();
+  void updateAnalyzer();
 
 public:
-  FunctionUnitStreamer(MCContext &Context, const MCInstrInfo &MCII)
-      : MCStreamer(Context), MCII(MCII), LastDirectiveIndex(0),
-        LastInstruction(std::nullopt) {}
+  FunctionUnitStreamer(MCContext &Context,
+                       std::unique_ptr<FunctionUnitAnalyzer> Analyzer)
+      : MCStreamer(Context), LastDirectiveIndex(0),
+        LastInstruction(std::nullopt), Analyzer(std::move(Analyzer)) {
+    assert(this->Analyzer && "Analyzer should not be null");
+  }
 
   bool hasRawTextSupport() const override { return true; }
   void emitRawTextImpl(StringRef String) override {}
diff --git a/llvm/include/llvm/MCCFIAnalysis/FunctionUnitUnwindInfoAnalyzer.h b/llvm/include/llvm/MCCFIAnalysis/FunctionUnitUnwindInfoAnalyzer.h
new file mode 100644
index 0000000000000..a48e7c90409cb
--- /dev/null
+++ b/llvm/include/llvm/MCCFIAnalysis/FunctionUnitUnwindInfoAnalyzer.h
@@ -0,0 +1,30 @@
+#ifndef LLVM_MC_CFI_ANALYSIS_FUNCTION_UNIT_UNWIND_INFO_ANALYZER_H
+#define LLVM_MC_CFI_ANALYSIS_FUNCTION_UNIT_UNWIND_INFO_ANALYZER_H
+
+#include "FunctionUnitAnalyzer.h"
+#include "UnwindInfoAnalysis.h"
+#include "llvm/ADT/ArrayRef.h"
+#include <cstdio>
+
+namespace llvm {
+
+class FunctionUnitUnwindInfoAnalyzer : public FunctionUnitAnalyzer {
+private:
+  std::vector<UnwindInfoAnalysis> UIAs;
+  MCInstrInfo const &MCII;
+
+public:
+  FunctionUnitUnwindInfoAnalyzer(MCContext &Context, const MCInstrInfo &MCII)
+      : FunctionUnitAnalyzer(Context), MCII(MCII) {}
+
+  void startFunctionUnit(bool IsEH,
+                         ArrayRef<MCCFIInstruction> Prologue) override;
+  void
+  emitInstructionAndDirectives(const MCInst &Inst,
+                               ArrayRef<MCCFIInstruction> Directives) override;
+  void finishFunctionUnit() override;
+};
+
+} // namespace llvm
+
+#endif
\ No newline at end of file
diff --git a/llvm/lib/MCCFIAnalysis/CMakeLists.txt b/llvm/lib/MCCFIAnalysis/CMakeLists.txt
index 3662f3e5a53e1..756cbeae22c33 100644
--- a/llvm/lib/MCCFIAnalysis/CMakeLists.txt
+++ b/llvm/lib/MCCFIAnalysis/CMakeLists.txt
@@ -1,5 +1,7 @@
 add_llvm_component_library(LLVMMCCFIAnalysis
+  FunctionUnitAnalyzer.cpp
   FunctionUnitStreamer.cpp
+  FunctionUnitUnwindInfoAnalyzer.cpp
   UnwindInfoHistory.cpp
   UnwindInfoAnalysis.cpp
 
diff --git a/llvm/lib/MCCFIAnalysis/FunctionUnitAnalyzer.cpp b/llvm/lib/MCCFIAnalysis/FunctionUnitAnalyzer.cpp
new file mode 100644
index 0000000000000..1a40c1285e263
--- /dev/null
+++ b/llvm/lib/MCCFIAnalysis/FunctionUnitAnalyzer.cpp
@@ -0,0 +1,13 @@
+#include "llvm/MCCFIAnalysis/FunctionUnitAnalyzer.h"
+
+using namespace llvm;
+
+FunctionUnitAnalyzer::~FunctionUnitAnalyzer() = default;
+
+void FunctionUnitAnalyzer::startFunctionUnit(
+    bool IsEH, ArrayRef<MCCFIInstruction> Prologue) {}
+
+void FunctionUnitAnalyzer::emitInstructionAndDirectives(
+    const MCInst &Inst, ArrayRef<MCCFIInstruction> Directives) {}
+
+void FunctionUnitAnalyzer::finishFunctionUnit() {}
\ No newline at end of file
diff --git a/llvm/lib/MCCFIAnalysis/FunctionUnitStreamer.cpp b/llvm/lib/MCCFIAnalysis/FunctionUnitStreamer.cpp
index d455c8692aab6..72d900b380040 100644
--- a/llvm/lib/MCCFIAnalysis/FunctionUnitStreamer.cpp
+++ b/llvm/lib/MCCFIAnalysis/FunctionUnitStreamer.cpp
@@ -27,7 +27,7 @@ std::pair<unsigned, unsigned> FunctionUnitStreamer::updateDirectivesRange() {
   return CFIDirectivesRange;
 }
 
-void FunctionUnitStreamer::updateUIA() {
+void FunctionUnitStreamer::updateAnalyzer() {
   if (FrameIndices.empty()) {
     auto CFIDirectivesRange = updateDirectivesRange();
     assert(CFIDirectivesRange.first == CFIDirectivesRange.second &&
@@ -47,25 +47,21 @@ void FunctionUnitStreamer::updateUIA() {
   }
 
   if (LastInstruction) {
-    assert(!UIAs.empty() && "If the instruction is in a frame, there should be "
-                            "a analysis instantiated for it");
-    UIAs.back().update(LastInstruction.value(), Directives);
+    Analyzer->emitInstructionAndDirectives(LastInstruction.value(), Directives);
   } else {
-    assert(!DirectivesRange.first &&
-           "An analysis should be created at the begining of a frame");
-    UIAs.emplace_back(&getContext(), MCII,
-                      false /* TODO should put isEH here */, Directives);
+    Analyzer->startFunctionUnit(false /* TODO should put isEH here */,
+                                Directives);
   }
 }
 
 void FunctionUnitStreamer::emitInstruction(const MCInst &Inst,
                                            const MCSubtargetInfo &STI) {
-  updateUIA();
+  updateAnalyzer();
   LastInstruction = Inst;
 }
 
 void FunctionUnitStreamer::emitCFIStartProcImpl(MCDwarfFrameInfo &Frame) {
-  updateUIA();
+  updateAnalyzer();
   FrameIndices.push_back(getNumFrameInfos());
   LastInstruction = std::nullopt;
   LastDirectiveIndex = 0;
@@ -73,13 +69,12 @@ void FunctionUnitStreamer::emitCFIStartProcImpl(MCDwarfFrameInfo &Frame) {
 }
 
 void FunctionUnitStreamer::emitCFIEndProcImpl(MCDwarfFrameInfo &CurFrame) {
-  updateUIA();
+  updateAnalyzer();
 
   assert(!FrameIndices.empty() && "There should be at least one frame to pop");
   FrameIndices.pop_back();
 
-  assert(!UIAs.empty() && "There should be an analysis for each frame");
-  UIAs.pop_back();
+  Analyzer->finishFunctionUnit();
 
   LastInstruction = std::nullopt;
   LastDirectiveIndex = 0;
diff --git a/llvm/lib/MCCFIAnalysis/FunctionUnitUnwindInfoAnalyzer.cpp b/llvm/lib/MCCFIAnalysis/FunctionUnitUnwindInfoAnalyzer.cpp
new file mode 100644
index 0000000000000..021d3ec9e07cb
--- /dev/null
+++ b/llvm/lib/MCCFIAnalysis/FunctionUnitUnwindInfoAnalyzer.cpp
@@ -0,0 +1,20 @@
+#include "llvm/MCCFIAnalysis/FunctionUnitUnwindInfoAnalyzer.h"
+
+using namespace llvm;
+
+void FunctionUnitUnwindInfoAnalyzer::startFunctionUnit(
+    bool IsEH, ArrayRef<MCCFIInstruction> Prologue) {
+  UIAs.emplace_back(&getContext(), MCII, IsEH, Prologue);
+}
+
+void FunctionUnitUnwindInfoAnalyzer::emitInstructionAndDirectives(
+    const MCInst &Inst, ArrayRef<MCCFIInstruction> Directives) {
+  assert(!UIAs.empty() && "If the instruction is in a frame, there should be "
+                          "a analysis instantiated for it");
+  UIAs.back().update(Inst, Directives);
+}
+
+void FunctionUnitUnwindInfoAnalyzer::finishFunctionUnit() {
+  assert(!UIAs.empty() && "There should be an analysis for each frame");
+  UIAs.pop_back();
+}
\ No newline at end of file
diff --git a/llvm/tools/llvm-mc/llvm-mc.cpp b/llvm/tools/llvm-mc/llvm-mc.cpp
index 52363927d6668..d8ff252685c88 100644
--- a/llvm/tools/llvm-mc/llvm-mc.cpp
+++ b/llvm/tools/llvm-mc/llvm-mc.cpp
@@ -30,6 +30,7 @@
 #include "llvm/MC/MCTargetOptionsCommandFlags.h"
 #include "llvm/MC/TargetRegistry.h"
 #include "llvm/MCCFIAnalysis/FunctionUnitStreamer.h"
+#include "llvm/MCCFIAnalysis/FunctionUnitUnwindInfoAnalyzer.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Compression.h"
 #include "llvm/Support/FileUtilities.h"
@@ -524,12 +525,15 @@ int main(int argc, char **argv) {
   std::unique_ptr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo());
   assert(MCII && "Unable to create instruction info!");
 
+  std::unique_ptr<FunctionUnitUnwindInfoAnalyzer> FUUIA(
+      new FunctionUnitUnwindInfoAnalyzer(Ctx, *MCII));
+
   std::unique_ptr<MCInstPrinter> IP;
   if (ValidateCFI) {
     assert(FileType == OFT_Null);
-    auto *CFIAMCS = new FunctionUnitStreamer(Ctx, *MCII);
-    TheTarget->createNullTargetStreamer(*CFIAMCS);
-    Str.reset(CFIAMCS);
+    auto *FUS = new FunctionUnitStreamer(Ctx, std::move(FUUIA));
+    TheTarget->createNullTargetStreamer(*FUS);
+    Str.reset(FUS);
   } else if (FileType == OFT_AssemblyFile) {
     IP.reset(TheTarget->createMCInstPrinter(
         Triple(TripleName), OutputAsmVariant, *MAI, *MCII, *MRI));

>From 7576857d697a2a8a4e87ed0023fa44d703c5e904 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Tue, 24 Jun 2025 21:07:49 +0000
Subject: [PATCH 45/58] Rename the library to UnwindInfoChecker

---
 .../FunctionUnitAnalyzer.h                                    | 0
 .../FunctionUnitStreamer.h                                    | 0
 .../FunctionUnitUnwindInfoAnalyzer.h                          | 0
 .../{MCCFIAnalysis => UnwindInfoChecker}/UnwindInfoAnalysis.h | 0
 .../{MCCFIAnalysis => UnwindInfoChecker}/UnwindInfoHistory.h  | 0
 llvm/lib/CMakeLists.txt                                       | 2 +-
 llvm/lib/{MCCFIAnalysis => UnwindInfoChecker}/CMakeLists.txt  | 2 +-
 .../FunctionUnitAnalyzer.cpp                                  | 2 +-
 .../FunctionUnitStreamer.cpp                                  | 2 +-
 .../FunctionUnitUnwindInfoAnalyzer.cpp                        | 2 +-
 .../UnwindInfoAnalysis.cpp                                    | 4 ++--
 .../UnwindInfoHistory.cpp                                     | 2 +-
 llvm/tools/llvm-mc/CMakeLists.txt                             | 2 +-
 llvm/tools/llvm-mc/llvm-mc.cpp                                | 4 ++--
 14 files changed, 11 insertions(+), 11 deletions(-)
 rename llvm/include/llvm/{MCCFIAnalysis => UnwindInfoChecker}/FunctionUnitAnalyzer.h (100%)
 rename llvm/include/llvm/{MCCFIAnalysis => UnwindInfoChecker}/FunctionUnitStreamer.h (100%)
 rename llvm/include/llvm/{MCCFIAnalysis => UnwindInfoChecker}/FunctionUnitUnwindInfoAnalyzer.h (100%)
 rename llvm/include/llvm/{MCCFIAnalysis => UnwindInfoChecker}/UnwindInfoAnalysis.h (100%)
 rename llvm/include/llvm/{MCCFIAnalysis => UnwindInfoChecker}/UnwindInfoHistory.h (100%)
 rename llvm/lib/{MCCFIAnalysis => UnwindInfoChecker}/CMakeLists.txt (83%)
 rename llvm/lib/{MCCFIAnalysis => UnwindInfoChecker}/FunctionUnitAnalyzer.cpp (86%)
 rename llvm/lib/{MCCFIAnalysis => UnwindInfoChecker}/FunctionUnitStreamer.cpp (98%)
 rename llvm/lib/{MCCFIAnalysis => UnwindInfoChecker}/FunctionUnitUnwindInfoAnalyzer.cpp (90%)
 rename llvm/lib/{MCCFIAnalysis => UnwindInfoChecker}/UnwindInfoAnalysis.cpp (99%)
 rename llvm/lib/{MCCFIAnalysis => UnwindInfoChecker}/UnwindInfoHistory.cpp (99%)

diff --git a/llvm/include/llvm/MCCFIAnalysis/FunctionUnitAnalyzer.h b/llvm/include/llvm/UnwindInfoChecker/FunctionUnitAnalyzer.h
similarity index 100%
rename from llvm/include/llvm/MCCFIAnalysis/FunctionUnitAnalyzer.h
rename to llvm/include/llvm/UnwindInfoChecker/FunctionUnitAnalyzer.h
diff --git a/llvm/include/llvm/MCCFIAnalysis/FunctionUnitStreamer.h b/llvm/include/llvm/UnwindInfoChecker/FunctionUnitStreamer.h
similarity index 100%
rename from llvm/include/llvm/MCCFIAnalysis/FunctionUnitStreamer.h
rename to llvm/include/llvm/UnwindInfoChecker/FunctionUnitStreamer.h
diff --git a/llvm/include/llvm/MCCFIAnalysis/FunctionUnitUnwindInfoAnalyzer.h b/llvm/include/llvm/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.h
similarity index 100%
rename from llvm/include/llvm/MCCFIAnalysis/FunctionUnitUnwindInfoAnalyzer.h
rename to llvm/include/llvm/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.h
diff --git a/llvm/include/llvm/MCCFIAnalysis/UnwindInfoAnalysis.h b/llvm/include/llvm/UnwindInfoChecker/UnwindInfoAnalysis.h
similarity index 100%
rename from llvm/include/llvm/MCCFIAnalysis/UnwindInfoAnalysis.h
rename to llvm/include/llvm/UnwindInfoChecker/UnwindInfoAnalysis.h
diff --git a/llvm/include/llvm/MCCFIAnalysis/UnwindInfoHistory.h b/llvm/include/llvm/UnwindInfoChecker/UnwindInfoHistory.h
similarity index 100%
rename from llvm/include/llvm/MCCFIAnalysis/UnwindInfoHistory.h
rename to llvm/include/llvm/UnwindInfoChecker/UnwindInfoHistory.h
diff --git a/llvm/lib/CMakeLists.txt b/llvm/lib/CMakeLists.txt
index 08b68aee46efd..63c2203c7caef 100644
--- a/llvm/lib/CMakeLists.txt
+++ b/llvm/lib/CMakeLists.txt
@@ -24,7 +24,7 @@ add_subdirectory(Analysis)
 add_subdirectory(LTO)
 add_subdirectory(MC)
 add_subdirectory(MCA)
-add_subdirectory(MCCFIAnalysis)
+add_subdirectory(UnwindInfoChecker)
 add_subdirectory(ObjCopy)
 add_subdirectory(Object)
 add_subdirectory(ObjectYAML)
diff --git a/llvm/lib/MCCFIAnalysis/CMakeLists.txt b/llvm/lib/UnwindInfoChecker/CMakeLists.txt
similarity index 83%
rename from llvm/lib/MCCFIAnalysis/CMakeLists.txt
rename to llvm/lib/UnwindInfoChecker/CMakeLists.txt
index 756cbeae22c33..c1ae214d2dc78 100644
--- a/llvm/lib/MCCFIAnalysis/CMakeLists.txt
+++ b/llvm/lib/UnwindInfoChecker/CMakeLists.txt
@@ -1,4 +1,4 @@
-add_llvm_component_library(LLVMMCCFIAnalysis
+add_llvm_component_library(LLVMUnwindInfoChecker
   FunctionUnitAnalyzer.cpp
   FunctionUnitStreamer.cpp
   FunctionUnitUnwindInfoAnalyzer.cpp
diff --git a/llvm/lib/MCCFIAnalysis/FunctionUnitAnalyzer.cpp b/llvm/lib/UnwindInfoChecker/FunctionUnitAnalyzer.cpp
similarity index 86%
rename from llvm/lib/MCCFIAnalysis/FunctionUnitAnalyzer.cpp
rename to llvm/lib/UnwindInfoChecker/FunctionUnitAnalyzer.cpp
index 1a40c1285e263..5b269db4ae141 100644
--- a/llvm/lib/MCCFIAnalysis/FunctionUnitAnalyzer.cpp
+++ b/llvm/lib/UnwindInfoChecker/FunctionUnitAnalyzer.cpp
@@ -1,4 +1,4 @@
-#include "llvm/MCCFIAnalysis/FunctionUnitAnalyzer.h"
+#include "llvm/UnwindInfoChecker/FunctionUnitAnalyzer.h"
 
 using namespace llvm;
 
diff --git a/llvm/lib/MCCFIAnalysis/FunctionUnitStreamer.cpp b/llvm/lib/UnwindInfoChecker/FunctionUnitStreamer.cpp
similarity index 98%
rename from llvm/lib/MCCFIAnalysis/FunctionUnitStreamer.cpp
rename to llvm/lib/UnwindInfoChecker/FunctionUnitStreamer.cpp
index 72d900b380040..74b7eec12acf0 100644
--- a/llvm/lib/MCCFIAnalysis/FunctionUnitStreamer.cpp
+++ b/llvm/lib/UnwindInfoChecker/FunctionUnitStreamer.cpp
@@ -1,5 +1,5 @@
 
-#include "llvm/MCCFIAnalysis/FunctionUnitStreamer.h"
+#include "llvm/UnwindInfoChecker/FunctionUnitStreamer.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCDwarf.h"
diff --git a/llvm/lib/MCCFIAnalysis/FunctionUnitUnwindInfoAnalyzer.cpp b/llvm/lib/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.cpp
similarity index 90%
rename from llvm/lib/MCCFIAnalysis/FunctionUnitUnwindInfoAnalyzer.cpp
rename to llvm/lib/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.cpp
index 021d3ec9e07cb..d37509298c9b6 100644
--- a/llvm/lib/MCCFIAnalysis/FunctionUnitUnwindInfoAnalyzer.cpp
+++ b/llvm/lib/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.cpp
@@ -1,4 +1,4 @@
-#include "llvm/MCCFIAnalysis/FunctionUnitUnwindInfoAnalyzer.h"
+#include "llvm/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.h"
 
 using namespace llvm;
 
diff --git a/llvm/lib/MCCFIAnalysis/UnwindInfoAnalysis.cpp b/llvm/lib/UnwindInfoChecker/UnwindInfoAnalysis.cpp
similarity index 99%
rename from llvm/lib/MCCFIAnalysis/UnwindInfoAnalysis.cpp
rename to llvm/lib/UnwindInfoChecker/UnwindInfoAnalysis.cpp
index 2f26374a12572..afb6af1be17a0 100644
--- a/llvm/lib/MCCFIAnalysis/UnwindInfoAnalysis.cpp
+++ b/llvm/lib/UnwindInfoChecker/UnwindInfoAnalysis.cpp
@@ -1,4 +1,4 @@
-#include "llvm/MCCFIAnalysis/UnwindInfoAnalysis.h"
+#include "llvm/UnwindInfoChecker/UnwindInfoAnalysis.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringExtras.h"
@@ -15,11 +15,11 @@
 #include "llvm/MC/MCStreamer.h"
 #include "llvm/MC/MCSubtargetInfo.h"
 #include "llvm/MC/TargetRegistry.h"
-#include "llvm/MCCFIAnalysis/UnwindInfoHistory.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/Format.h"
 #include "llvm/Support/FormatVariadic.h"
+#include "llvm/UnwindInfoChecker/UnwindInfoHistory.h"
 #include <cstdint>
 #include <optional>
 #include <set>
diff --git a/llvm/lib/MCCFIAnalysis/UnwindInfoHistory.cpp b/llvm/lib/UnwindInfoChecker/UnwindInfoHistory.cpp
similarity index 99%
rename from llvm/lib/MCCFIAnalysis/UnwindInfoHistory.cpp
rename to llvm/lib/UnwindInfoChecker/UnwindInfoHistory.cpp
index f44ac07bc0acb..9ee0be1770e99 100644
--- a/llvm/lib/MCCFIAnalysis/UnwindInfoHistory.cpp
+++ b/llvm/lib/UnwindInfoChecker/UnwindInfoHistory.cpp
@@ -1,5 +1,5 @@
 // TODO check what includes to keep and what to remove
-#include "llvm/MCCFIAnalysis/UnwindInfoHistory.h"
+#include "llvm/UnwindInfoChecker/UnwindInfoHistory.h"
 #include "llvm/BinaryFormat/Dwarf.h"
 #include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
 #include "llvm/MC/MCDwarf.h"
diff --git a/llvm/tools/llvm-mc/CMakeLists.txt b/llvm/tools/llvm-mc/CMakeLists.txt
index 83c40d1cd2122..c7e62156a9e68 100644
--- a/llvm/tools/llvm-mc/CMakeLists.txt
+++ b/llvm/tools/llvm-mc/CMakeLists.txt
@@ -4,10 +4,10 @@ set(LLVM_LINK_COMPONENTS
   AllTargetsDisassemblers
   AllTargetsInfos
   MC
-  MCCFIAnalysis
   MCParser
   Support
   TargetParser
+  UnwindInfoChecker
   )
 
 add_llvm_tool(llvm-mc
diff --git a/llvm/tools/llvm-mc/llvm-mc.cpp b/llvm/tools/llvm-mc/llvm-mc.cpp
index d8ff252685c88..a0f5998d3f8fd 100644
--- a/llvm/tools/llvm-mc/llvm-mc.cpp
+++ b/llvm/tools/llvm-mc/llvm-mc.cpp
@@ -29,8 +29,6 @@
 #include "llvm/MC/MCTargetOptions.h"
 #include "llvm/MC/MCTargetOptionsCommandFlags.h"
 #include "llvm/MC/TargetRegistry.h"
-#include "llvm/MCCFIAnalysis/FunctionUnitStreamer.h"
-#include "llvm/MCCFIAnalysis/FunctionUnitUnwindInfoAnalyzer.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Compression.h"
 #include "llvm/Support/FileUtilities.h"
@@ -44,6 +42,8 @@
 #include "llvm/Target/TargetMachine.h"
 #include "llvm/Target/TargetOptions.h"
 #include "llvm/TargetParser/Host.h"
+#include "llvm/UnwindInfoChecker/FunctionUnitStreamer.h"
+#include "llvm/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.h"
 #include <memory>
 #include <optional>
 

>From 374f144d25ead473c47fd76d0faffa0dd7877522 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Tue, 24 Jun 2025 21:32:51 +0000
Subject: [PATCH 46/58] Fix the header guards

---
 llvm/include/llvm/UnwindInfoChecker/FunctionUnitAnalyzer.h    | 4 ++--
 llvm/include/llvm/UnwindInfoChecker/FunctionUnitStreamer.h    | 4 ++--
 .../llvm/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.h   | 4 ++--
 llvm/include/llvm/UnwindInfoChecker/UnwindInfoAnalysis.h      | 4 ++--
 llvm/include/llvm/UnwindInfoChecker/UnwindInfoHistory.h       | 4 ++--
 5 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/llvm/include/llvm/UnwindInfoChecker/FunctionUnitAnalyzer.h b/llvm/include/llvm/UnwindInfoChecker/FunctionUnitAnalyzer.h
index aa0eb13e016be..8798620833b3f 100644
--- a/llvm/include/llvm/UnwindInfoChecker/FunctionUnitAnalyzer.h
+++ b/llvm/include/llvm/UnwindInfoChecker/FunctionUnitAnalyzer.h
@@ -1,5 +1,5 @@
-#ifndef LLVM_MC_CFI_ANALYSIS_FUNCTION_UNIT_ANALYZER_H
-#define LLVM_MC_CFI_ANALYSIS_FUNCTION_UNIT_ANALYZER_H
+#ifndef LLVM_UNWINDINFOCHECKER_FUNCTIONUNITANALYZER_H
+#define LLVM_UNWINDINFOCHECKER_FUNCTIONUNITANALYZER_H
 
 #include "llvm/ADT/ArrayRef.h"
 #include <cstdio>
diff --git a/llvm/include/llvm/UnwindInfoChecker/FunctionUnitStreamer.h b/llvm/include/llvm/UnwindInfoChecker/FunctionUnitStreamer.h
index fa104b15a330c..7546a7b172525 100644
--- a/llvm/include/llvm/UnwindInfoChecker/FunctionUnitStreamer.h
+++ b/llvm/include/llvm/UnwindInfoChecker/FunctionUnitStreamer.h
@@ -1,5 +1,5 @@
-#ifndef LLVM_TOOLS_LLVM_MC_CFI_ANALYSIS_MC_STREAMER_H
-#define LLVM_TOOLS_LLVM_MC_CFI_ANALYSIS_MC_STREAMER_H
+#ifndef LLVM_UNWINDINFOCHECKER_FUNCTIONUNITSTREAMER_H
+#define LLVM_UNWINDINFOCHECKER_FUNCTIONUNITSTREAMER_H
 
 #include "FunctionUnitAnalyzer.h"
 #include "llvm/MC/MCContext.h"
diff --git a/llvm/include/llvm/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.h b/llvm/include/llvm/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.h
index a48e7c90409cb..ccb5e16cb5bbf 100644
--- a/llvm/include/llvm/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.h
+++ b/llvm/include/llvm/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.h
@@ -1,5 +1,5 @@
-#ifndef LLVM_MC_CFI_ANALYSIS_FUNCTION_UNIT_UNWIND_INFO_ANALYZER_H
-#define LLVM_MC_CFI_ANALYSIS_FUNCTION_UNIT_UNWIND_INFO_ANALYZER_H
+#ifndef LLVM_UNWINDINFOCHECKER_FUNCTIONUNITUNWINDINFOANALYZER_H
+#define LLVM_UNWINDINFOCHECKER_FUNCTIONUNITUNWINDINFOANALYZER_H
 
 #include "FunctionUnitAnalyzer.h"
 #include "UnwindInfoAnalysis.h"
diff --git a/llvm/include/llvm/UnwindInfoChecker/UnwindInfoAnalysis.h b/llvm/include/llvm/UnwindInfoChecker/UnwindInfoAnalysis.h
index 66c22cd6e16d1..438f9c10c581a 100644
--- a/llvm/include/llvm/UnwindInfoChecker/UnwindInfoAnalysis.h
+++ b/llvm/include/llvm/UnwindInfoChecker/UnwindInfoAnalysis.h
@@ -1,5 +1,5 @@
-#ifndef LLVM_TOOLS_LLVM_MC_CFI_ANALYSIS_H
-#define LLVM_TOOLS_LLVM_MC_CFI_ANALYSIS_H
+#ifndef LLVM_UNWINDINFOCHECKER_UNWINDINFOANALYSIS_H
+#define LLVM_UNWINDINFOCHECKER_UNWINDINFOANALYSIS_H
 
 #include "UnwindInfoHistory.h"
 #include "llvm/ADT/ArrayRef.h"
diff --git a/llvm/include/llvm/UnwindInfoChecker/UnwindInfoHistory.h b/llvm/include/llvm/UnwindInfoChecker/UnwindInfoHistory.h
index 1f357e0e8fc55..3df26df5ca424 100644
--- a/llvm/include/llvm/UnwindInfoChecker/UnwindInfoHistory.h
+++ b/llvm/include/llvm/UnwindInfoChecker/UnwindInfoHistory.h
@@ -1,5 +1,5 @@
-#ifndef LLVM_TOOLS_LLVM_MC_CFI_STATE_H
-#define LLVM_TOOLS_LLVM_MC_CFI_STATE_H
+#ifndef LLVM_UNWINDINFOCHECKER_UNWINDINFOHISTORY_H
+#define LLVM_UNWINDINFOCHECKER_UNWINDINFOHISTORY_H
 
 #include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
 #include "llvm/MC/MCContext.h"

>From e42907f0aba11dff2292ec1f4cb2b91c815e7a8f Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Tue, 24 Jun 2025 22:13:45 +0000
Subject: [PATCH 47/58] Add file headers

---
 .../llvm/UnwindInfoChecker/FunctionUnitAnalyzer.h    | 12 ++++++++++++
 .../llvm/UnwindInfoChecker/FunctionUnitStreamer.h    | 12 ++++++++++++
 .../FunctionUnitUnwindInfoAnalyzer.h                 | 12 ++++++++++++
 .../llvm/UnwindInfoChecker/UnwindInfoAnalysis.h      | 12 ++++++++++++
 .../llvm/UnwindInfoChecker/UnwindInfoHistory.h       | 12 ++++++++++++
 llvm/lib/UnwindInfoChecker/FunctionUnitAnalyzer.cpp  |  8 ++++++++
 llvm/lib/UnwindInfoChecker/FunctionUnitStreamer.cpp  |  7 +++++++
 .../FunctionUnitUnwindInfoAnalyzer.cpp               |  8 ++++++++
 llvm/lib/UnwindInfoChecker/UnwindInfoAnalysis.cpp    |  8 ++++++++
 llvm/lib/UnwindInfoChecker/UnwindInfoHistory.cpp     |  9 ++++++++-
 10 files changed, 99 insertions(+), 1 deletion(-)

diff --git a/llvm/include/llvm/UnwindInfoChecker/FunctionUnitAnalyzer.h b/llvm/include/llvm/UnwindInfoChecker/FunctionUnitAnalyzer.h
index 8798620833b3f..2df320babcd38 100644
--- a/llvm/include/llvm/UnwindInfoChecker/FunctionUnitAnalyzer.h
+++ b/llvm/include/llvm/UnwindInfoChecker/FunctionUnitAnalyzer.h
@@ -1,3 +1,15 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// This file declares FunctionUnitAnalyzer class.
+///
+//===----------------------------------------------------------------------===//
+
 #ifndef LLVM_UNWINDINFOCHECKER_FUNCTIONUNITANALYZER_H
 #define LLVM_UNWINDINFOCHECKER_FUNCTIONUNITANALYZER_H
 
diff --git a/llvm/include/llvm/UnwindInfoChecker/FunctionUnitStreamer.h b/llvm/include/llvm/UnwindInfoChecker/FunctionUnitStreamer.h
index 7546a7b172525..517f82a4bb588 100644
--- a/llvm/include/llvm/UnwindInfoChecker/FunctionUnitStreamer.h
+++ b/llvm/include/llvm/UnwindInfoChecker/FunctionUnitStreamer.h
@@ -1,3 +1,15 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// This file declares FunctionUnitStreamer class.
+///
+//===----------------------------------------------------------------------===//
+
 #ifndef LLVM_UNWINDINFOCHECKER_FUNCTIONUNITSTREAMER_H
 #define LLVM_UNWINDINFOCHECKER_FUNCTIONUNITSTREAMER_H
 
diff --git a/llvm/include/llvm/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.h b/llvm/include/llvm/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.h
index ccb5e16cb5bbf..4e9b27d8da0ca 100644
--- a/llvm/include/llvm/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.h
+++ b/llvm/include/llvm/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.h
@@ -1,3 +1,15 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// This file declares FunctionUnitUnwindInfoAnalyzer class.
+///
+//===----------------------------------------------------------------------===//
+
 #ifndef LLVM_UNWINDINFOCHECKER_FUNCTIONUNITUNWINDINFOANALYZER_H
 #define LLVM_UNWINDINFOCHECKER_FUNCTIONUNITUNWINDINFOANALYZER_H
 
diff --git a/llvm/include/llvm/UnwindInfoChecker/UnwindInfoAnalysis.h b/llvm/include/llvm/UnwindInfoChecker/UnwindInfoAnalysis.h
index 438f9c10c581a..18d6f9c887b9a 100644
--- a/llvm/include/llvm/UnwindInfoChecker/UnwindInfoAnalysis.h
+++ b/llvm/include/llvm/UnwindInfoChecker/UnwindInfoAnalysis.h
@@ -1,3 +1,15 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// This file declares UnwindInfoAnalysis class.
+///
+//===----------------------------------------------------------------------===//
+
 #ifndef LLVM_UNWINDINFOCHECKER_UNWINDINFOANALYSIS_H
 #define LLVM_UNWINDINFOCHECKER_UNWINDINFOANALYSIS_H
 
diff --git a/llvm/include/llvm/UnwindInfoChecker/UnwindInfoHistory.h b/llvm/include/llvm/UnwindInfoChecker/UnwindInfoHistory.h
index 3df26df5ca424..8b454aa0ac539 100644
--- a/llvm/include/llvm/UnwindInfoChecker/UnwindInfoHistory.h
+++ b/llvm/include/llvm/UnwindInfoChecker/UnwindInfoHistory.h
@@ -1,3 +1,15 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// This file declares UnwindInfoHistory class.
+///
+//===----------------------------------------------------------------------===//
+
 #ifndef LLVM_UNWINDINFOCHECKER_UNWINDINFOHISTORY_H
 #define LLVM_UNWINDINFOCHECKER_UNWINDINFOHISTORY_H
 
diff --git a/llvm/lib/UnwindInfoChecker/FunctionUnitAnalyzer.cpp b/llvm/lib/UnwindInfoChecker/FunctionUnitAnalyzer.cpp
index 5b269db4ae141..7f6a06850bd7f 100644
--- a/llvm/lib/UnwindInfoChecker/FunctionUnitAnalyzer.cpp
+++ b/llvm/lib/UnwindInfoChecker/FunctionUnitAnalyzer.cpp
@@ -1,3 +1,11 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
 #include "llvm/UnwindInfoChecker/FunctionUnitAnalyzer.h"
 
 using namespace llvm;
diff --git a/llvm/lib/UnwindInfoChecker/FunctionUnitStreamer.cpp b/llvm/lib/UnwindInfoChecker/FunctionUnitStreamer.cpp
index 74b7eec12acf0..c58339a0d978d 100644
--- a/llvm/lib/UnwindInfoChecker/FunctionUnitStreamer.cpp
+++ b/llvm/lib/UnwindInfoChecker/FunctionUnitStreamer.cpp
@@ -1,3 +1,10 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
 
 #include "llvm/UnwindInfoChecker/FunctionUnitStreamer.h"
 #include "llvm/ADT/ArrayRef.h"
diff --git a/llvm/lib/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.cpp b/llvm/lib/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.cpp
index d37509298c9b6..808d0658d3f9c 100644
--- a/llvm/lib/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.cpp
+++ b/llvm/lib/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.cpp
@@ -1,3 +1,11 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
 #include "llvm/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.h"
 
 using namespace llvm;
diff --git a/llvm/lib/UnwindInfoChecker/UnwindInfoAnalysis.cpp b/llvm/lib/UnwindInfoChecker/UnwindInfoAnalysis.cpp
index afb6af1be17a0..c5093dd3aa771 100644
--- a/llvm/lib/UnwindInfoChecker/UnwindInfoAnalysis.cpp
+++ b/llvm/lib/UnwindInfoChecker/UnwindInfoAnalysis.cpp
@@ -1,3 +1,11 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
 #include "llvm/UnwindInfoChecker/UnwindInfoAnalysis.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/SmallVector.h"
diff --git a/llvm/lib/UnwindInfoChecker/UnwindInfoHistory.cpp b/llvm/lib/UnwindInfoChecker/UnwindInfoHistory.cpp
index 9ee0be1770e99..77ed6122c3dfd 100644
--- a/llvm/lib/UnwindInfoChecker/UnwindInfoHistory.cpp
+++ b/llvm/lib/UnwindInfoChecker/UnwindInfoHistory.cpp
@@ -1,4 +1,11 @@
-// TODO check what includes to keep and what to remove
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
 #include "llvm/UnwindInfoChecker/UnwindInfoHistory.h"
 #include "llvm/BinaryFormat/Dwarf.h"
 #include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"

>From 37858ef3dd1f132387037b9e431e20c1b1020d3f Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Tue, 24 Jun 2025 22:24:37 +0000
Subject: [PATCH 48/58] Resolve warnings

---
 llvm/lib/UnwindInfoChecker/UnwindInfoAnalysis.cpp | 9 ---------
 1 file changed, 9 deletions(-)

diff --git a/llvm/lib/UnwindInfoChecker/UnwindInfoAnalysis.cpp b/llvm/lib/UnwindInfoChecker/UnwindInfoAnalysis.cpp
index c5093dd3aa771..78a29e0d2dd79 100644
--- a/llvm/lib/UnwindInfoChecker/UnwindInfoAnalysis.cpp
+++ b/llvm/lib/UnwindInfoChecker/UnwindInfoAnalysis.cpp
@@ -9,7 +9,6 @@
 #include "llvm/UnwindInfoChecker/UnwindInfoAnalysis.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/Twine.h"
 #include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
 #include "llvm/MC/MCAsmInfo.h"
@@ -23,9 +22,7 @@
 #include "llvm/MC/MCStreamer.h"
 #include "llvm/MC/MCSubtargetInfo.h"
 #include "llvm/MC/TargetRegistry.h"
-#include "llvm/Support/Debug.h"
 #include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/Format.h"
 #include "llvm/Support/FormatVariadic.h"
 #include "llvm/UnwindInfoChecker/UnwindInfoHistory.h"
 #include <cstdint>
@@ -77,12 +74,6 @@ static std::optional<DWARFRegType> getReferenceRegisterForUnwindInfoOfRegister(
   }
 }
 
-// TODO remove it, it's just for debug purposes.
-void printUntilNextLine(const char *Str) {
-  for (int I = 0; Str[I] != '\0' && Str[I] != '\n'; I++)
-    dbgs() << Str[I];
-}
-
 bool UnwindInfoAnalysis::isSuperReg(MCPhysReg Reg) {
   return MCRI->superregs(Reg).empty();
 }

>From b8cdef68539eb378bedbbb30d1955a0f5f87f9e4 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Wed, 25 Jun 2025 03:46:34 +0000
Subject: [PATCH 49/58] Refactor UnwindInfoAnalysis

---
 .../UnwindInfoChecker/FunctionUnitAnalyzer.h  |   1 +
 .../UnwindInfoChecker/FunctionUnitStreamer.h  |   1 +
 .../FunctionUnitUnwindInfoAnalyzer.h          |   1 +
 .../UnwindInfoChecker/UnwindInfoAnalysis.h    |  30 +-
 .../UnwindInfoChecker/UnwindInfoHistory.h     |   9 +-
 llvm/lib/UnwindInfoChecker/Registers.h        |  68 ++++
 .../UnwindInfoChecker/UnwindInfoAnalysis.cpp  | 321 ++++++++----------
 .../UnwindInfoChecker/UnwindInfoHistory.cpp   |   6 +-
 8 files changed, 223 insertions(+), 214 deletions(-)
 create mode 100644 llvm/lib/UnwindInfoChecker/Registers.h

diff --git a/llvm/include/llvm/UnwindInfoChecker/FunctionUnitAnalyzer.h b/llvm/include/llvm/UnwindInfoChecker/FunctionUnitAnalyzer.h
index 2df320babcd38..e7791e1b59f14 100644
--- a/llvm/include/llvm/UnwindInfoChecker/FunctionUnitAnalyzer.h
+++ b/llvm/include/llvm/UnwindInfoChecker/FunctionUnitAnalyzer.h
@@ -6,6 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 ///
+/// \file
 /// This file declares FunctionUnitAnalyzer class.
 ///
 //===----------------------------------------------------------------------===//
diff --git a/llvm/include/llvm/UnwindInfoChecker/FunctionUnitStreamer.h b/llvm/include/llvm/UnwindInfoChecker/FunctionUnitStreamer.h
index 517f82a4bb588..f161c22fa9880 100644
--- a/llvm/include/llvm/UnwindInfoChecker/FunctionUnitStreamer.h
+++ b/llvm/include/llvm/UnwindInfoChecker/FunctionUnitStreamer.h
@@ -6,6 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 ///
+/// \file
 /// This file declares FunctionUnitStreamer class.
 ///
 //===----------------------------------------------------------------------===//
diff --git a/llvm/include/llvm/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.h b/llvm/include/llvm/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.h
index 4e9b27d8da0ca..b5cff539e8e08 100644
--- a/llvm/include/llvm/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.h
+++ b/llvm/include/llvm/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.h
@@ -6,6 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 ///
+/// \file
 /// This file declares FunctionUnitUnwindInfoAnalyzer class.
 ///
 //===----------------------------------------------------------------------===//
diff --git a/llvm/include/llvm/UnwindInfoChecker/UnwindInfoAnalysis.h b/llvm/include/llvm/UnwindInfoChecker/UnwindInfoAnalysis.h
index 18d6f9c887b9a..7b60745fea826 100644
--- a/llvm/include/llvm/UnwindInfoChecker/UnwindInfoAnalysis.h
+++ b/llvm/include/llvm/UnwindInfoChecker/UnwindInfoAnalysis.h
@@ -6,6 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 ///
+/// \file
 /// This file declares UnwindInfoAnalysis class.
 ///
 //===----------------------------------------------------------------------===//
@@ -22,7 +23,6 @@
 #include "llvm/MC/MCExpr.h"
 #include "llvm/MC/MCInst.h"
 #include "llvm/MC/MCInstrInfo.h"
-#include "llvm/MC/MCRegister.h"
 #include "llvm/MC/MCRegisterInfo.h"
 #include "llvm/MC/MCStreamer.h"
 #include "llvm/MC/MCSubtargetInfo.h"
@@ -35,41 +35,27 @@ class UnwindInfoAnalysis {
   MCContext *Context;
   MCInstrInfo const &MCII;
   MCRegisterInfo const *MCRI;
-  UnwindInfoHistory State;
+  UnwindInfoState State;
   bool IsEH;
 
-private:
-  // The CFI analysis only keeps track and cares about super registers, not the
-  // subregisters. All reads to/writes from subregisters and considered the same
-  // operation to super registers.
-  // TODO Other operations like loading and stores are considered only if they
-  // TODO are exactly doing the operation to or from a super register. As an
-  // TODO example, if you spill a sub register to stack, the CFI analysis does
-  // TODO not consider that a register spilling.
-  bool isSuperReg(MCPhysReg Reg);
-
-  SmallVector<std::pair<MCPhysReg, MCRegisterClass const *>> getAllSuperRegs();
-
-  MCPhysReg getSuperReg(MCPhysReg Reg);
-
 public:
   UnwindInfoAnalysis(MCContext *Context, MCInstrInfo const &MCII, bool IsEH,
-                     ArrayRef<MCCFIInstruction> PrologueCFIDirectives);
+                     ArrayRef<MCCFIInstruction> Prologue);
 
   void update(const MCInst &Inst, ArrayRef<MCCFIInstruction> CFIDirectives);
 
 private:
-  void checkRegDiff(const MCInst &Inst, DWARFRegType Reg,
+  void checkRegDiff(const MCInst &Inst, DWARFRegNum Reg,
                     const dwarf::UnwindTable::const_iterator &PrevRow,
                     const dwarf::UnwindTable::const_iterator &NextRow,
-                    const std::set<DWARFRegType> &Reads,
-                    const std::set<DWARFRegType> &Writes);
+                    const std::set<DWARFRegNum> &Reads,
+                    const std::set<DWARFRegNum> &Writes);
 
   void checkCFADiff(const MCInst &Inst,
                     const dwarf::UnwindTable::const_iterator &PrevRow,
                     const dwarf::UnwindTable::const_iterator &NextRow,
-                    const std::set<DWARFRegType> &Reads,
-                    const std::set<DWARFRegType> &Writes);
+                    const std::set<DWARFRegNum> &Reads,
+                    const std::set<DWARFRegNum> &Writes);
 };
 
 } // namespace llvm
diff --git a/llvm/include/llvm/UnwindInfoChecker/UnwindInfoHistory.h b/llvm/include/llvm/UnwindInfoChecker/UnwindInfoHistory.h
index 8b454aa0ac539..8bad58ca31428 100644
--- a/llvm/include/llvm/UnwindInfoChecker/UnwindInfoHistory.h
+++ b/llvm/include/llvm/UnwindInfoChecker/UnwindInfoHistory.h
@@ -6,7 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 ///
-/// This file declares UnwindInfoHistory class.
+/// \file
+/// This file declares UnwindInfoState class.
 ///
 //===----------------------------------------------------------------------===//
 
@@ -20,11 +21,11 @@
 #include <optional>
 namespace llvm {
 
-using DWARFRegType = uint32_t;
+using DWARFRegNum = uint32_t;
 
-class UnwindInfoHistory {
+class UnwindInfoState {
 public:
-  UnwindInfoHistory(MCContext *Context) : Context(Context) {};
+  UnwindInfoState(MCContext *Context) : Context(Context) {};
 
   std::optional<dwarf::UnwindTable::const_iterator> getCurrentUnwindRow() const;
   void update(const MCCFIInstruction &CFIDirective);
diff --git a/llvm/lib/UnwindInfoChecker/Registers.h b/llvm/lib/UnwindInfoChecker/Registers.h
new file mode 100644
index 0000000000000..f661ae0d211fc
--- /dev/null
+++ b/llvm/lib/UnwindInfoChecker/Registers.h
@@ -0,0 +1,68 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains helper functions to find and list registers that are
+/// tracked by the unwinding information checker.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_UNWINDINFOCHECKER_REGISTERS_H
+#define LLVM_UNWINDINFOCHECKER_REGISTERS_H
+
+#include "llvm/MC/MCRegister.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include <iterator>
+
+namespace llvm {
+
+/// This analysis only keeps track and cares about super registers, not the
+/// subregisters. All reads from/writes to subregisters are considered the
+/// same operation to super registers.
+inline bool isSuperReg(const MCRegisterInfo *MCRI, MCPhysReg Reg) {
+  return MCRI->superregs(Reg).empty();
+}
+
+inline SmallVector<MCPhysReg> getSuperRegs(const MCRegisterInfo *MCRI) {
+  SmallVector<MCPhysReg> SuperRegs;
+  for (auto &&RegClass : MCRI->regclasses()) {
+    for (unsigned I = 0; I < RegClass.getNumRegs(); I++) {
+      MCPhysReg Reg = RegClass.getRegister(I);
+      if (isSuperReg(MCRI, Reg))
+        SuperRegs.push_back(Reg);
+    }
+  }
+
+  std::sort(SuperRegs.begin(), SuperRegs.end());
+  SuperRegs.resize(std::distance(
+      SuperRegs.begin(), std::unique(SuperRegs.begin(), SuperRegs.end())));
+  return SuperRegs;
+}
+
+inline SmallVector<MCPhysReg> getTrackingRegs(const MCRegisterInfo *MCRI) {
+  SmallVector<MCPhysReg> TrackingRegs;
+  for (auto Reg : getSuperRegs(MCRI))
+    if (!MCRI->isArtificial(Reg) && !MCRI->isConstant(Reg))
+      TrackingRegs.push_back(Reg);
+  return TrackingRegs;
+}
+
+inline MCPhysReg getSuperReg(const MCRegisterInfo *MCRI, MCPhysReg Reg) {
+  if (isSuperReg(MCRI, Reg))
+    return Reg;
+  for (auto SuperReg : MCRI->superregs(Reg)) {
+    if (isSuperReg(MCRI, SuperReg))
+      return SuperReg;
+  }
+
+  llvm_unreachable("Should either be a super reg, or have a super reg");
+}
+
+} // namespace llvm
+
+#endif
\ No newline at end of file
diff --git a/llvm/lib/UnwindInfoChecker/UnwindInfoAnalysis.cpp b/llvm/lib/UnwindInfoChecker/UnwindInfoAnalysis.cpp
index 78a29e0d2dd79..99952a6db3f4c 100644
--- a/llvm/lib/UnwindInfoChecker/UnwindInfoAnalysis.cpp
+++ b/llvm/lib/UnwindInfoChecker/UnwindInfoAnalysis.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/UnwindInfoChecker/UnwindInfoAnalysis.h"
+#include "Registers.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/Twine.h"
@@ -32,10 +33,10 @@
 using namespace llvm;
 
 struct CFARegOffsetInfo {
-  DWARFRegType Reg;
+  DWARFRegNum Reg;
   int64_t Offset;
 
-  CFARegOffsetInfo(DWARFRegType Reg, int64_t Offset)
+  CFARegOffsetInfo(DWARFRegNum Reg, int64_t Offset)
       : Reg(Reg), Offset(Offset) {}
 };
 
@@ -50,13 +51,15 @@ getCFARegOffsetInfo(const dwarf::UnwindTable::const_iterator &UnwindRow) {
   return CFARegOffsetInfo(CFALocation.getRegister(), CFALocation.getOffset());
 }
 
-static std::optional<DWARFRegType> getReferenceRegisterForUnwindInfoOfRegister(
-    const dwarf::UnwindTable::const_iterator &UnwindRow, DWARFRegType Reg) {
-  auto UnwinLoc = UnwindRow->getRegisterLocations().getRegisterLocation(Reg);
-  assert(UnwinLoc &&
+static std::optional<DWARFRegNum>
+getUnwindRuleRefReg(const dwarf::UnwindTable::const_iterator &UnwindRow,
+                    DWARFRegNum Reg) {
+  auto MaybeLoc = UnwindRow->getRegisterLocations().getRegisterLocation(Reg);
+  assert(MaybeLoc &&
          "The register should be tracked inside the register states");
+  auto Loc = *MaybeLoc;
 
-  switch (UnwinLoc->getLocation()) {
+  switch (Loc.getLocation()) {
   case dwarf::UnwindLocation::Location::Undefined:
   case dwarf::UnwindLocation::Location::Constant:
   case dwarf::UnwindLocation::Location::Unspecified:
@@ -66,65 +69,34 @@ static std::optional<DWARFRegType> getReferenceRegisterForUnwindInfoOfRegister(
   case dwarf::UnwindLocation::Location::Same:
     return Reg;
   case dwarf::UnwindLocation::Location::RegPlusOffset:
-    return UnwinLoc->getRegister();
+    return Loc.getRegister();
   case dwarf::UnwindLocation::Location::CFAPlusOffset:
-    // TODO check if it's ok to assume CFA is always depending on other
-    // TODO register, if yes assert it here!
-    return UnwindRow->getCFAValue().getRegister();
-  }
-}
-
-bool UnwindInfoAnalysis::isSuperReg(MCPhysReg Reg) {
-  return MCRI->superregs(Reg).empty();
-}
-
-SmallVector<std::pair<MCPhysReg, MCRegisterClass const *>>
-UnwindInfoAnalysis::getAllSuperRegs() {
-  std::map<MCPhysReg, MCRegisterClass const *> SuperRegs;
-  for (auto &&RegClass : MCRI->regclasses()) {
-    for (unsigned I = 0; I < RegClass.getNumRegs(); I++) {
-      MCPhysReg Reg = RegClass.getRegister(I);
-      if (!isSuperReg(Reg) || MCRI->isArtificial(Reg) || MCRI->isConstant(Reg))
-        continue;
-      SuperRegs[Reg] = &RegClass;
-    }
-  }
-
-  SmallVector<std::pair<MCPhysReg, MCRegisterClass const *>> SuperRegWithClass;
-  for (auto &&[Reg, RegClass] : SuperRegs)
-    SuperRegWithClass.emplace_back(Reg, RegClass);
-  return SuperRegWithClass;
-}
-
-MCPhysReg UnwindInfoAnalysis::getSuperReg(MCPhysReg Reg) {
-  if (isSuperReg(Reg))
-    return Reg;
-  for (auto SuperReg : MCRI->superregs(Reg)) {
-    if (isSuperReg(SuperReg))
-      return SuperReg;
+    auto MaybeCFA = getCFARegOffsetInfo(UnwindRow);
+    if (MaybeCFA)
+      return MaybeCFA->Reg;
+    return std::nullopt;
   }
-
-  llvm_unreachable("Should either be a super reg, or have a super reg");
 }
 
-UnwindInfoAnalysis::UnwindInfoAnalysis(
-    MCContext *Context, MCInstrInfo const &MCII, bool IsEH,
-    ArrayRef<MCCFIInstruction> PrologueCFIDirectives)
+UnwindInfoAnalysis::UnwindInfoAnalysis(MCContext *Context,
+                                       MCInstrInfo const &MCII, bool IsEH,
+                                       ArrayRef<MCCFIInstruction> Prologue)
     : Context(Context), MCII(MCII), MCRI(Context->getRegisterInfo()),
       State(Context), IsEH(IsEH) {
 
-  // TODO These all should be handled by setting .cfi_same_value for only callee
-  // TODO saved registers inside `getInitialFrameState`. Instead now what's
-  // TODO happening is that the analysis .cfi_same_value all the registers and
-  // TODO remove PC (undefined), and RSP (CFA) from them.
-  for (auto &&[Reg, RegClass] : getAllSuperRegs()) {
-    if (MCRI->get(Reg).IsArtificial || MCRI->get(Reg).IsConstant)
+  for (auto LLVMReg : getTrackingRegs(MCRI)) {
+    if (MCRI->get(LLVMReg).IsArtificial || MCRI->get(LLVMReg).IsConstant)
       continue;
 
-    DWARFRegType DwarfReg = MCRI->getDwarfRegNum(Reg, IsEH);
-    State.update(MCCFIInstruction::createSameValue(nullptr, DwarfReg));
+    DWARFRegNum Reg = MCRI->getDwarfRegNum(LLVMReg, IsEH);
+    // TODO this should be `undefined` instead of `same_value`, but because
+    // initial frame state doesn't have any directives about callee saved
+    // registers, every register is tracked. After initial frame state is
+    // corrected, this should be changed.
+    State.update(MCCFIInstruction::createSameValue(nullptr, Reg));
   }
 
+  // TODO Ignoring PC should be in initial frame state.
   State.update(MCCFIInstruction::createUndefined(
       nullptr, MCRI->getDwarfRegNum(MCRI->getProgramCounter(), IsEH)));
 
@@ -133,21 +105,20 @@ UnwindInfoAnalysis::UnwindInfoAnalysis(
     State.update(InitialFrameStateCFIDirective);
   }
 
-  auto MaybeLastRow = State.getCurrentUnwindRow();
-  assert(MaybeLastRow && "there should be at least one row");
-  auto LastRow = *MaybeLastRow;
-
-  auto MaybeCFA = getCFARegOffsetInfo(LastRow);
+  auto MaybeCurrentRow = State.getCurrentUnwindRow();
+  assert(MaybeCurrentRow && "there should be at least one row");
+  auto MaybeCFA = getCFARegOffsetInfo(*MaybeCurrentRow);
   assert(MaybeCFA &&
          "the CFA information should be describable in [Reg + Offset] in here");
   auto CFA = *MaybeCFA;
 
-  State.update(MCCFIInstruction::createOffset(nullptr, CFA.Reg,
-                                              0)); // sp's old value is CFA
+  // TODO CFA register callee value is CFA's value, this should be in initial
+  // frame state.
+  State.update(MCCFIInstruction::createOffset(nullptr, CFA.Reg, 0));
 
   // Applying the prologue after default assumptions to overwrite them.
-  for (auto &&PrologueCFIDirective : PrologueCFIDirectives) {
-    State.update(PrologueCFIDirective);
+  for (auto &&Directive : Prologue) {
+    State.update(Directive);
   }
 }
 
@@ -155,145 +126,133 @@ void UnwindInfoAnalysis::update(const MCInst &Inst,
                                 ArrayRef<MCCFIInstruction> CFIDirectives) {
   const MCInstrDesc &MCInstInfo = MCII.get(Inst.getOpcode());
 
-  auto MaybePrevUnwindRow = State.getCurrentUnwindRow();
-  assert(MaybePrevUnwindRow && "The analysis should have initialized the "
-                               "history with at least one row by now");
-  auto PrevUnwindRow = MaybePrevUnwindRow.value();
+  auto MaybePrevRow = State.getCurrentUnwindRow();
+  assert(MaybePrevRow && "The analysis should have initialized the "
+                         "history with at least one row by now");
+  auto PrevRow = MaybePrevRow.value();
 
-  for (auto &&CFIDirective : CFIDirectives)
-    State.update(CFIDirective);
+  for (auto &&Directive : CFIDirectives)
+    State.update(Directive);
 
-  std::set<DWARFRegType> Writes, Reads;
+  std::set<DWARFRegNum> Writes, Reads;
   for (unsigned I = 0; I < MCInstInfo.NumImplicitUses; I++)
-    Reads.insert(
-        MCRI->getDwarfRegNum(getSuperReg(MCInstInfo.implicit_uses()[I]), IsEH));
+    Reads.insert(MCRI->getDwarfRegNum(
+        getSuperReg(MCRI, MCInstInfo.implicit_uses()[I]), IsEH));
   for (unsigned I = 0; I < MCInstInfo.NumImplicitDefs; I++)
-    Writes.insert(
-        MCRI->getDwarfRegNum(getSuperReg(MCInstInfo.implicit_defs()[I]), IsEH));
+    Writes.insert(MCRI->getDwarfRegNum(
+        getSuperReg(MCRI, MCInstInfo.implicit_defs()[I]), IsEH));
 
   for (unsigned I = 0; I < Inst.getNumOperands(); I++) {
-    auto &&Operand = Inst.getOperand(I);
-    if (Operand.isReg()) {
+    auto &&Op = Inst.getOperand(I);
+    if (Op.isReg()) {
       if (I < MCInstInfo.getNumDefs())
         Writes.insert(
-            MCRI->getDwarfRegNum(getSuperReg(Operand.getReg()), IsEH));
-      else if (Operand.getReg())
-        Reads.insert(MCRI->getDwarfRegNum(getSuperReg(Operand.getReg()), IsEH));
+            MCRI->getDwarfRegNum(getSuperReg(MCRI, Op.getReg()), IsEH));
+      else if (Op.getReg())
+        Reads.insert(
+            MCRI->getDwarfRegNum(getSuperReg(MCRI, Op.getReg()), IsEH));
     }
   }
 
-  auto MaybeCurrentUnwindRow = State.getCurrentUnwindRow();
-  assert(MaybeCurrentUnwindRow &&
-         "Prev row existed, so should the current row.");
-  auto CurrentUnwindRow = *MaybeCurrentUnwindRow;
+  auto MaybeNextRow = State.getCurrentUnwindRow();
+  assert(MaybeNextRow && "Prev row existed, so should the current row.");
+  auto NextRow = *MaybeNextRow;
 
-  checkCFADiff(Inst, PrevUnwindRow, CurrentUnwindRow, Reads, Writes);
+  checkCFADiff(Inst, PrevRow, NextRow, Reads, Writes);
 
-  for (auto [LLVMReg, _] : getAllSuperRegs()) {
-    DWARFRegType Reg = MCRI->getDwarfRegNum(LLVMReg, IsEH);
+  for (auto LLVMReg : getTrackingRegs(MCRI)) {
+    DWARFRegNum Reg = MCRI->getDwarfRegNum(LLVMReg, IsEH);
 
-    checkRegDiff(Inst, Reg, PrevUnwindRow, CurrentUnwindRow, Reads, Writes);
+    checkRegDiff(Inst, Reg, PrevRow, NextRow, Reads, Writes);
   }
 }
 
 void UnwindInfoAnalysis::checkRegDiff(
-    const MCInst &Inst, DWARFRegType Reg,
+    const MCInst &Inst, DWARFRegNum Reg,
     const dwarf::UnwindTable::const_iterator &PrevRow,
     const dwarf::UnwindTable::const_iterator &NextRow,
-    const std::set<DWARFRegType> &Reads, const std::set<DWARFRegType> &Writes) {
-  auto MaybePrevUnwindLoc =
-      PrevRow->getRegisterLocations().getRegisterLocation(Reg);
-  auto MaybeNextUnwindLoc =
-      NextRow->getRegisterLocations().getRegisterLocation(Reg);
-
-  if (!MaybePrevUnwindLoc) {
-    assert(!MaybeNextUnwindLoc && "The register unwind info suddenly "
-                                  "appeared here, ignoring this change");
+    const std::set<DWARFRegNum> &Reads, const std::set<DWARFRegNum> &Writes) {
+  auto MaybePrevLoc = PrevRow->getRegisterLocations().getRegisterLocation(Reg);
+  auto MaybeNextLoc = NextRow->getRegisterLocations().getRegisterLocation(Reg);
+
+  if (!MaybePrevLoc) {
+    assert(!MaybeNextLoc && "The register unwind info suddenly "
+                            "appeared here, ignoring this change");
     return;
   }
 
-  assert(MaybeNextUnwindLoc && "The register unwind info suddenly vanished "
-                               "here, ignoring this change");
+  assert(MaybeNextLoc && "The register unwind info suddenly vanished "
+                         "here, ignoring this change");
 
-  auto PrevRegLoc = MaybePrevUnwindLoc.value();
-  auto NextRegLoc = MaybeNextUnwindLoc.value();
+  auto PrevLoc = MaybePrevLoc.value();
+  auto NextLoc = MaybeNextLoc.value();
 
-  auto MaybeRegLLVM = MCRI->getLLVMRegNum(Reg, IsEH);
-  if (!MaybeRegLLVM) {
-    assert(PrevRegLoc == NextRegLoc &&
+  auto MaybeLLVMReg = MCRI->getLLVMRegNum(Reg, IsEH);
+  if (!MaybeLLVMReg) {
+    assert(PrevLoc == NextLoc &&
            "The dwarf register does not have a LLVM number, so the unwind info "
            "for it should not change");
     return;
   }
+  const char *RegName = MCRI->getName(*MaybeLLVMReg);
 
-  const char *RegLLVMName = MCRI->getName(MaybeRegLLVM.value());
-
-  auto &&MaybePrevRefReg =
-      getReferenceRegisterForUnwindInfoOfRegister(PrevRow, Reg);
-
-  std::optional<MCPhysReg> PrevRefRegLLVM =
-      (MaybePrevRefReg ? MCRI->getLLVMRegNum(MaybePrevRefReg.value(), IsEH)
-                       : std::nullopt);
-  std::optional<MCPhysReg> NextRefRegLLVM =
+  auto &&MaybePrevRefReg = getUnwindRuleRefReg(PrevRow, Reg);
+  std::optional<MCPhysReg> PrevRefLLVMReg =
       (MaybePrevRefReg ? MCRI->getLLVMRegNum(MaybePrevRefReg.value(), IsEH)
                        : std::nullopt);
 
-  if (PrevRegLoc == NextRegLoc) {
-    switch (PrevRegLoc.getLocation()) {
-    case dwarf::UnwindLocation::Same:
-    case dwarf::UnwindLocation::RegPlusOffset:
-      if (Writes.count(MaybePrevRefReg.value())) {
-        Context->reportError(
-            Inst.getLoc(),
-            formatv("This instruction changes %{1}, that %{0} unwinding rule "
-                    "uses, but there is no CFI directives about it",
-                    RegLLVMName, MCRI->getName(PrevRefRegLLVM.value())));
-        return;
-      }
-      break;
-      // TODO think about what to do with expressions here.
-      // TODO the expressions be solved more precise, by looking into the
-      // TODO expression, finding registers that are used and checking if the
-      // TODO instruction is changing them or not.
-    default:
-      // Everything may be ok
-      break;
+  if (!(PrevLoc == NextLoc)) {
+    if (PrevLoc.getLocation() == NextLoc.getLocation()) {
+      Context->reportWarning(
+          Inst.getLoc(),
+          formatv("unknown change happened to %{0} unwinding rule values",
+                  RegName));
+      //! FIXME Check if the register is changed or not
+      return;
     }
-    return;
-  }
-
-  if (PrevRegLoc.getLocation() == NextRegLoc.getLocation()) {
-    // Everything may be ok
-    return;
-  }
 
-  if (PrevRegLoc.getLocation() == dwarf::UnwindLocation::Undefined) {
-    Context->reportError(
+    Context->reportWarning(
         Inst.getLoc(),
-        "Changed %{0} unwinding rule from `undefined` to something else");
+        formatv("unknown change happened to %{0} unwinding rule structure",
+                RegName));
     return;
   }
 
-  Context->reportWarning(
-      Inst.getLoc(),
-      formatv("Unknown change happened to %{0} unwinding rule", RegLLVMName));
-  // Everything may be ok
-  return;
+  switch (PrevLoc.getLocation()) {
+  case dwarf::UnwindLocation::Same:
+  case dwarf::UnwindLocation::RegPlusOffset:
+    if (Writes.count(MaybePrevRefReg.value())) {
+      Context->reportError(
+          Inst.getLoc(),
+          formatv("changed %{1}, that %{0} unwinding rule "
+                  "uses, but there is no CFI directives about it",
+                  RegName, MCRI->getName(*PrevRefLLVMReg)));
+      return;
+    }
+    break;
+  case dwarf::UnwindLocation::DWARFExpr:
+    // TODO Expressions are not supported yet, but if wanted to be supported,
+    // all the registers used in an expression should extracted and checked if
+    // the instruction modifies them or not.
+  default:
+    // Everything may be ok
+    break;
+  }
 }
 
 void UnwindInfoAnalysis::checkCFADiff(
     const MCInst &Inst, const dwarf::UnwindTable::const_iterator &PrevRow,
     const dwarf::UnwindTable::const_iterator &NextRow,
-    const std::set<DWARFRegType> &Reads, const std::set<DWARFRegType> &Writes) {
+    const std::set<DWARFRegNum> &Reads, const std::set<DWARFRegNum> &Writes) {
 
   auto MaybePrevCFA = getCFARegOffsetInfo(PrevRow);
   auto MaybeNextCFA = getCFARegOffsetInfo(NextRow);
 
   if (!MaybePrevCFA) {
     if (MaybeNextCFA) {
-      Context->reportWarning(
-          Inst.getLoc(),
-          "CFA rule changed to [reg + offset], not checking the change");
+      Context->reportWarning(Inst.getLoc(),
+                             "CFA rule changed to [reg + offset], this "
+                             "transition will not be checked");
       return;
     }
 
@@ -303,46 +262,38 @@ void UnwindInfoAnalysis::checkCFADiff(
   }
 
   if (!MaybeNextCFA) {
-    Context->reportWarning(
-        Inst.getLoc(),
-        "CFA rule changed from [reg + offset], not checking the change");
+    Context->reportWarning(Inst.getLoc(),
+                           "CFA rule changed from [reg + offset], this "
+                           "transition will not be checked");
     return;
   }
 
   auto PrevCFA = *MaybePrevCFA;
   auto NextCFA = *MaybeNextCFA;
 
-  const char *PrevCFARegName =
-      MCRI->getName(MCRI->getLLVMRegNum(PrevCFA.Reg, IsEH).value());
-
-  if (PrevCFA.Reg == NextCFA.Reg) {
-    if (PrevCFA.Offset == NextCFA.Offset) {
-      if (Writes.count(PrevCFA.Reg)) {
-        Context->reportError(
-            Inst.getLoc(),
-            formatv("This instruction modifies CFA register (%{0}) "
-                    "but CFA rule is not changed",
-                    PrevCFARegName));
-        return;
-      }
-
-      // Everything is ok!
-      return;
-    }
+  auto MaybeLLVMReg = MCRI->getLLVMRegNum(PrevCFA.Reg, IsEH);
+  const char *PrevCFARegName = MaybeLLVMReg ? MCRI->getName(*MaybeLLVMReg) : "";
 
-    // The offset is changed.
-    if (!Writes.count(PrevCFA.Reg)) {
-      Context->reportError(
-          Inst.getLoc(),
-          formatv("This instruction does not modifies CFA register (%{0}) "
-                  "but CFA rule is changed",
-                  PrevCFARegName));
-    }
-
-    // The CFA register value is changed, and the offset is changed as well,
-    // everything may be ok.
+  if (PrevCFA.Reg != NextCFA.Reg) {
+    //! FIXME warn here
     return;
   }
 
-  // The CFA register is changed, everything may be ok.
+  if (PrevCFA.Offset == NextCFA.Offset) {
+    if (!Writes.count(PrevCFA.Reg))
+      return;
+    Context->reportError(
+        Inst.getLoc(),
+        formatv("modified CFA register (%{0}) but not changed CFA rule",
+                PrevCFARegName));
+  }
+
+  // The offset is changed.
+  if (Writes.count(PrevCFA.Reg))
+    return;
+
+  Context->reportError(
+      Inst.getLoc(),
+      formatv("did not modify CFA register (%{0}) but changed CFA rule",
+              PrevCFARegName));
 }
diff --git a/llvm/lib/UnwindInfoChecker/UnwindInfoHistory.cpp b/llvm/lib/UnwindInfoChecker/UnwindInfoHistory.cpp
index 77ed6122c3dfd..19bb5f9f175a3 100644
--- a/llvm/lib/UnwindInfoChecker/UnwindInfoHistory.cpp
+++ b/llvm/lib/UnwindInfoChecker/UnwindInfoHistory.cpp
@@ -19,14 +19,14 @@
 using namespace llvm;
 
 std::optional<dwarf::UnwindTable::const_iterator>
-UnwindInfoHistory::getCurrentUnwindRow() const {
+UnwindInfoState::getCurrentUnwindRow() const {
   if (!Table.size())
     return std::nullopt;
 
   return --Table.end();
 }
 
-void UnwindInfoHistory::update(const MCCFIInstruction &CFIDirective) {
+void UnwindInfoState::update(const MCCFIInstruction &CFIDirective) {
   auto DwarfOperations = convert(CFIDirective);
   if (!DwarfOperations) {
     Context->reportError(
@@ -50,7 +50,7 @@ void UnwindInfoHistory::update(const MCCFIInstruction &CFIDirective) {
 }
 
 std::optional<dwarf::CFIProgram>
-UnwindInfoHistory::convert(MCCFIInstruction CFIDirective) {
+UnwindInfoState::convert(MCCFIInstruction CFIDirective) {
   //! FIXME, this way of instantiating CFI program does not look right, either
   //! refactor CFIProgram to not depend on the Code/Data Alignment or add a new
   //! type that is independent from this and is also feedable to UnwindTable.

>From c1538d37b692af846446f19e680a91e5089eff96 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Wed, 25 Jun 2025 03:47:04 +0000
Subject: [PATCH 50/58] Move tests to UnwindInfoChecker folder

---
 .../cfi-validation => UnwindInfoChecker/X86}/empty-section.s      | 0
 .../cfi-validation => UnwindInfoChecker/X86}/multiple-sections.s  | 0
 .../X86}/single-func-cfa-mistake.s                                | 0
 .../X86}/single-func-missed-cfi-directive.s                       | 0
 .../cfi-validation => UnwindInfoChecker/X86}/single-func.s        | 0
 .../X86}/spill-two-reg-reversed.s                                 | 0
 .../cfi-validation => UnwindInfoChecker/X86}/spill-two-reg.s      | 0
 .../cfi-validation => UnwindInfoChecker/X86}/update-with-no-cfi.s | 0
 8 files changed, 0 insertions(+), 0 deletions(-)
 rename llvm/test/{tools/llvm-mc/cfi-validation => UnwindInfoChecker/X86}/empty-section.s (100%)
 rename llvm/test/{tools/llvm-mc/cfi-validation => UnwindInfoChecker/X86}/multiple-sections.s (100%)
 rename llvm/test/{tools/llvm-mc/cfi-validation => UnwindInfoChecker/X86}/single-func-cfa-mistake.s (100%)
 rename llvm/test/{tools/llvm-mc/cfi-validation => UnwindInfoChecker/X86}/single-func-missed-cfi-directive.s (100%)
 rename llvm/test/{tools/llvm-mc/cfi-validation => UnwindInfoChecker/X86}/single-func.s (100%)
 rename llvm/test/{tools/llvm-mc/cfi-validation => UnwindInfoChecker/X86}/spill-two-reg-reversed.s (100%)
 rename llvm/test/{tools/llvm-mc/cfi-validation => UnwindInfoChecker/X86}/spill-two-reg.s (100%)
 rename llvm/test/{tools/llvm-mc/cfi-validation => UnwindInfoChecker/X86}/update-with-no-cfi.s (100%)

diff --git a/llvm/test/tools/llvm-mc/cfi-validation/empty-section.s b/llvm/test/UnwindInfoChecker/X86/empty-section.s
similarity index 100%
rename from llvm/test/tools/llvm-mc/cfi-validation/empty-section.s
rename to llvm/test/UnwindInfoChecker/X86/empty-section.s
diff --git a/llvm/test/tools/llvm-mc/cfi-validation/multiple-sections.s b/llvm/test/UnwindInfoChecker/X86/multiple-sections.s
similarity index 100%
rename from llvm/test/tools/llvm-mc/cfi-validation/multiple-sections.s
rename to llvm/test/UnwindInfoChecker/X86/multiple-sections.s
diff --git a/llvm/test/tools/llvm-mc/cfi-validation/single-func-cfa-mistake.s b/llvm/test/UnwindInfoChecker/X86/single-func-cfa-mistake.s
similarity index 100%
rename from llvm/test/tools/llvm-mc/cfi-validation/single-func-cfa-mistake.s
rename to llvm/test/UnwindInfoChecker/X86/single-func-cfa-mistake.s
diff --git a/llvm/test/tools/llvm-mc/cfi-validation/single-func-missed-cfi-directive.s b/llvm/test/UnwindInfoChecker/X86/single-func-missed-cfi-directive.s
similarity index 100%
rename from llvm/test/tools/llvm-mc/cfi-validation/single-func-missed-cfi-directive.s
rename to llvm/test/UnwindInfoChecker/X86/single-func-missed-cfi-directive.s
diff --git a/llvm/test/tools/llvm-mc/cfi-validation/single-func.s b/llvm/test/UnwindInfoChecker/X86/single-func.s
similarity index 100%
rename from llvm/test/tools/llvm-mc/cfi-validation/single-func.s
rename to llvm/test/UnwindInfoChecker/X86/single-func.s
diff --git a/llvm/test/tools/llvm-mc/cfi-validation/spill-two-reg-reversed.s b/llvm/test/UnwindInfoChecker/X86/spill-two-reg-reversed.s
similarity index 100%
rename from llvm/test/tools/llvm-mc/cfi-validation/spill-two-reg-reversed.s
rename to llvm/test/UnwindInfoChecker/X86/spill-two-reg-reversed.s
diff --git a/llvm/test/tools/llvm-mc/cfi-validation/spill-two-reg.s b/llvm/test/UnwindInfoChecker/X86/spill-two-reg.s
similarity index 100%
rename from llvm/test/tools/llvm-mc/cfi-validation/spill-two-reg.s
rename to llvm/test/UnwindInfoChecker/X86/spill-two-reg.s
diff --git a/llvm/test/tools/llvm-mc/cfi-validation/update-with-no-cfi.s b/llvm/test/UnwindInfoChecker/X86/update-with-no-cfi.s
similarity index 100%
rename from llvm/test/tools/llvm-mc/cfi-validation/update-with-no-cfi.s
rename to llvm/test/UnwindInfoChecker/X86/update-with-no-cfi.s

>From 88952b038f722a8f326abdb9295e0aec0f2fc6b7 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Wed, 25 Jun 2025 03:49:47 +0000
Subject: [PATCH 51/58] Rename UnwindHistory to UnwindState

---
 llvm/include/llvm/UnwindInfoChecker/UnwindInfoAnalysis.h      | 2 +-
 .../{UnwindInfoHistory.h => UnwindInfoState.h}                | 4 ++--
 llvm/lib/UnwindInfoChecker/CMakeLists.txt                     | 2 +-
 llvm/lib/UnwindInfoChecker/UnwindInfoAnalysis.cpp             | 2 +-
 .../{UnwindInfoHistory.cpp => UnwindInfoState.cpp}            | 2 +-
 5 files changed, 6 insertions(+), 6 deletions(-)
 rename llvm/include/llvm/UnwindInfoChecker/{UnwindInfoHistory.h => UnwindInfoState.h} (91%)
 rename llvm/lib/UnwindInfoChecker/{UnwindInfoHistory.cpp => UnwindInfoState.cpp} (99%)

diff --git a/llvm/include/llvm/UnwindInfoChecker/UnwindInfoAnalysis.h b/llvm/include/llvm/UnwindInfoChecker/UnwindInfoAnalysis.h
index 7b60745fea826..954dc6a4a8edb 100644
--- a/llvm/include/llvm/UnwindInfoChecker/UnwindInfoAnalysis.h
+++ b/llvm/include/llvm/UnwindInfoChecker/UnwindInfoAnalysis.h
@@ -14,7 +14,7 @@
 #ifndef LLVM_UNWINDINFOCHECKER_UNWINDINFOANALYSIS_H
 #define LLVM_UNWINDINFOCHECKER_UNWINDINFOANALYSIS_H
 
-#include "UnwindInfoHistory.h"
+#include "UnwindInfoState.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
diff --git a/llvm/include/llvm/UnwindInfoChecker/UnwindInfoHistory.h b/llvm/include/llvm/UnwindInfoChecker/UnwindInfoState.h
similarity index 91%
rename from llvm/include/llvm/UnwindInfoChecker/UnwindInfoHistory.h
rename to llvm/include/llvm/UnwindInfoChecker/UnwindInfoState.h
index 8bad58ca31428..d2e4a3d36252b 100644
--- a/llvm/include/llvm/UnwindInfoChecker/UnwindInfoHistory.h
+++ b/llvm/include/llvm/UnwindInfoChecker/UnwindInfoState.h
@@ -11,8 +11,8 @@
 ///
 //===----------------------------------------------------------------------===//
 
-#ifndef LLVM_UNWINDINFOCHECKER_UNWINDINFOHISTORY_H
-#define LLVM_UNWINDINFOCHECKER_UNWINDINFOHISTORY_H
+#ifndef LLVM_UNWINDINFOCHECKER_UNWINDINFOSTATE_H
+#define LLVM_UNWINDINFOCHECKER_UNWINDINFOSTATE_H
 
 #include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
 #include "llvm/MC/MCContext.h"
diff --git a/llvm/lib/UnwindInfoChecker/CMakeLists.txt b/llvm/lib/UnwindInfoChecker/CMakeLists.txt
index c1ae214d2dc78..2b93c1acf4642 100644
--- a/llvm/lib/UnwindInfoChecker/CMakeLists.txt
+++ b/llvm/lib/UnwindInfoChecker/CMakeLists.txt
@@ -2,8 +2,8 @@ add_llvm_component_library(LLVMUnwindInfoChecker
   FunctionUnitAnalyzer.cpp
   FunctionUnitStreamer.cpp
   FunctionUnitUnwindInfoAnalyzer.cpp
-  UnwindInfoHistory.cpp
   UnwindInfoAnalysis.cpp
+  UnwindInfoState.cpp
 
   ADDITIONAL_HEADER_DIRS
   ${LLVM_MAIN_INCLUDE_DIR}/llvm/MCA
diff --git a/llvm/lib/UnwindInfoChecker/UnwindInfoAnalysis.cpp b/llvm/lib/UnwindInfoChecker/UnwindInfoAnalysis.cpp
index 99952a6db3f4c..23e3b68ef91ae 100644
--- a/llvm/lib/UnwindInfoChecker/UnwindInfoAnalysis.cpp
+++ b/llvm/lib/UnwindInfoChecker/UnwindInfoAnalysis.cpp
@@ -25,7 +25,7 @@
 #include "llvm/MC/TargetRegistry.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/FormatVariadic.h"
-#include "llvm/UnwindInfoChecker/UnwindInfoHistory.h"
+#include "llvm/UnwindInfoChecker/UnwindInfoState.h"
 #include <cstdint>
 #include <optional>
 #include <set>
diff --git a/llvm/lib/UnwindInfoChecker/UnwindInfoHistory.cpp b/llvm/lib/UnwindInfoChecker/UnwindInfoState.cpp
similarity index 99%
rename from llvm/lib/UnwindInfoChecker/UnwindInfoHistory.cpp
rename to llvm/lib/UnwindInfoChecker/UnwindInfoState.cpp
index 19bb5f9f175a3..b310f915ab610 100644
--- a/llvm/lib/UnwindInfoChecker/UnwindInfoHistory.cpp
+++ b/llvm/lib/UnwindInfoChecker/UnwindInfoState.cpp
@@ -6,7 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "llvm/UnwindInfoChecker/UnwindInfoHistory.h"
+#include "llvm/UnwindInfoChecker/UnwindInfoState.h"
 #include "llvm/BinaryFormat/Dwarf.h"
 #include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
 #include "llvm/MC/MCDwarf.h"

>From 017d89086eb17e9ef2a6634c7425dac8c57f1561 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Wed, 25 Jun 2025 03:53:46 +0000
Subject: [PATCH 52/58] Make different methods to add instruction public

---
 .../include/llvm/DebugInfo/DWARF/DWARFCFIProgram.h | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFCFIProgram.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFCFIProgram.h
index 0badfab89c839..5613a3e21f5ae 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFCFIProgram.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFCFIProgram.h
@@ -112,13 +112,6 @@ class CFIProgram {
   /// above. This is indexed by opcode.
   LLVM_ABI static ArrayRef<OperandType[MaxOperands]> getOperandTypes();
 
-//! FIX me, making these methods public to be usable inside the UnwindInfoAnalysis
-// private:
-  std::vector<Instruction> Instructions;
-  const uint64_t CodeAlignmentFactor;
-  const int64_t DataAlignmentFactor;
-  Triple::ArchType Arch;
-
   /// Convenience method to add a new instruction with the given opcode.
   void addInstruction(uint8_t Opcode) {
     Instructions.push_back(Instruction(Opcode));
@@ -145,6 +138,13 @@ class CFIProgram {
     Instructions.back().Ops.push_back(Operand2);
     Instructions.back().Ops.push_back(Operand3);
   }
+
+private:
+  std::vector<Instruction> Instructions;
+  const uint64_t CodeAlignmentFactor;
+  const int64_t DataAlignmentFactor;
+  Triple::ArchType Arch;
+
 };
 
 } // end namespace dwarf

>From 76b96ddfb97bd487534313a899f0ad7d630b4182 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Wed, 25 Jun 2025 03:59:50 +0000
Subject: [PATCH 53/58] Revert bolt change

---
 bolt/lib/Utils/CommandLineOpts.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/bolt/lib/Utils/CommandLineOpts.cpp b/bolt/lib/Utils/CommandLineOpts.cpp
index d4d6dbcb72aac..5635da476451d 100644
--- a/bolt/lib/Utils/CommandLineOpts.cpp
+++ b/bolt/lib/Utils/CommandLineOpts.cpp
@@ -202,7 +202,7 @@ cl::opt<bool> Lite("lite", cl::desc("skip processing of cold functions"),
                    cl::cat(BoltCategory));
 
 cl::opt<std::string>
-OutputFilename("ooo",
+OutputFilename("o",
   cl::desc("<output file>"),
   cl::Optional,
   cl::cat(BoltOutputCategory));

>From 60689b3daa172495a01278b2133aa8875d44d708 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Wed, 25 Jun 2025 04:00:54 +0000
Subject: [PATCH 54/58] Revert bolt changes

---
 bolt/include/bolt/Core/MCPlusBuilder.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/bolt/include/bolt/Core/MCPlusBuilder.h b/bolt/include/bolt/Core/MCPlusBuilder.h
index c168f06762c0d..804100db80793 100644
--- a/bolt/include/bolt/Core/MCPlusBuilder.h
+++ b/bolt/include/bolt/Core/MCPlusBuilder.h
@@ -1164,7 +1164,7 @@ class MCPlusBuilder {
     return false;
   }
 
-  /// Use \p Input1 or \p Input2 as the current value for the input
+  /// Use \p Input1 or Input2 as the current value for the input
   /// register and put in \p Output the changes incurred by executing
   /// \p Inst. Return false if it was not possible to perform the
   /// evaluation. evaluateStackOffsetExpr is restricted to operations

>From 5b3475bc46a15019265f28d23de349b9f1f10977 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Wed, 25 Jun 2025 04:10:01 +0000
Subject: [PATCH 55/58] Change UnwindTable to RowContainer

---
 llvm/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h   | 1 -
 llvm/include/llvm/UnwindInfoChecker/UnwindInfoState.h | 2 +-
 llvm/lib/UnwindInfoChecker/UnwindInfoState.cpp        | 5 +++--
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h
index c87abb010f039..f1c5392e29925 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h
@@ -334,7 +334,6 @@ class UnwindTable {
     assert(Index < size());
     return Rows[Index];
   }
-  void insertRow(UnwindRow Row) { Rows.push_back(Row); }
 
   /// Dump the UnwindTable to the stream.
   ///
diff --git a/llvm/include/llvm/UnwindInfoChecker/UnwindInfoState.h b/llvm/include/llvm/UnwindInfoChecker/UnwindInfoState.h
index d2e4a3d36252b..decf7f84f05b2 100644
--- a/llvm/include/llvm/UnwindInfoChecker/UnwindInfoState.h
+++ b/llvm/include/llvm/UnwindInfoChecker/UnwindInfoState.h
@@ -32,7 +32,7 @@ class UnwindInfoState {
 
 private:
   MCContext *Context;
-  dwarf::UnwindTable Table;
+  dwarf::UnwindTable::RowContainer Table;
 
   std::optional<dwarf::CFIProgram> convert(MCCFIInstruction CFIDirective);
 };
diff --git a/llvm/lib/UnwindInfoChecker/UnwindInfoState.cpp b/llvm/lib/UnwindInfoChecker/UnwindInfoState.cpp
index b310f915ab610..4d8dd1e0283bb 100644
--- a/llvm/lib/UnwindInfoChecker/UnwindInfoState.cpp
+++ b/llvm/lib/UnwindInfoChecker/UnwindInfoState.cpp
@@ -37,7 +37,8 @@ void UnwindInfoState::update(const MCCFIInstruction &CFIDirective) {
   auto LastRow = getCurrentUnwindRow();
   dwarf::UnwindRow Row =
       LastRow.has_value() ? *(LastRow.value()) : dwarf::UnwindRow();
-  if (Error Err = Table.parseRows(DwarfOperations.value(), Row, nullptr)) {
+  if (Error Err =
+          parseRows(DwarfOperations.value(), Row, nullptr).moveInto(Table)) {
     Context->reportError(
         CFIDirective.getLoc(),
         formatv("could not parse this CFI directive due to: {0}",
@@ -46,7 +47,7 @@ void UnwindInfoState::update(const MCCFIInstruction &CFIDirective) {
     // Proceed the analysis by ignoring this CFI directive.
     return;
   }
-  Table.insertRow(Row);
+  Table.push_back(Row);
 }
 
 std::optional<dwarf::CFIProgram>

>From 6bcc0ccd75404eb6aa3993774a5651b98b05a02f Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Wed, 25 Jun 2025 04:32:57 +0000
Subject: [PATCH 56/58] Refactor UnwindInfoState

---
 .../lib/UnwindInfoChecker/UnwindInfoState.cpp | 113 ++++++++----------
 1 file changed, 50 insertions(+), 63 deletions(-)

diff --git a/llvm/lib/UnwindInfoChecker/UnwindInfoState.cpp b/llvm/lib/UnwindInfoChecker/UnwindInfoState.cpp
index 4d8dd1e0283bb..72fa2dc21fc22 100644
--- a/llvm/lib/UnwindInfoChecker/UnwindInfoState.cpp
+++ b/llvm/lib/UnwindInfoChecker/UnwindInfoState.cpp
@@ -26,21 +26,21 @@ UnwindInfoState::getCurrentUnwindRow() const {
   return --Table.end();
 }
 
-void UnwindInfoState::update(const MCCFIInstruction &CFIDirective) {
-  auto DwarfOperations = convert(CFIDirective);
-  if (!DwarfOperations) {
+void UnwindInfoState::update(const MCCFIInstruction &Directive) {
+  auto MaybeCFIP = convert(Directive);
+  if (!MaybeCFIP) {
     Context->reportError(
-        CFIDirective.getLoc(),
+        Directive.getLoc(),
         "couldn't apply this directive to the unwinding information state");
   }
+  auto CFIP = *MaybeCFIP;
 
-  auto LastRow = getCurrentUnwindRow();
+  auto MaybeLastRow = getCurrentUnwindRow();
   dwarf::UnwindRow Row =
-      LastRow.has_value() ? *(LastRow.value()) : dwarf::UnwindRow();
-  if (Error Err =
-          parseRows(DwarfOperations.value(), Row, nullptr).moveInto(Table)) {
+      MaybeLastRow.has_value() ? *(MaybeLastRow.value()) : dwarf::UnwindRow();
+  if (Error Err = parseRows(CFIP, Row, nullptr).moveInto(Table)) {
     Context->reportError(
-        CFIDirective.getLoc(),
+        Directive.getLoc(),
         formatv("could not parse this CFI directive due to: {0}",
                 toString(std::move(Err))));
 
@@ -51,104 +51,91 @@ void UnwindInfoState::update(const MCCFIInstruction &CFIDirective) {
 }
 
 std::optional<dwarf::CFIProgram>
-UnwindInfoState::convert(MCCFIInstruction CFIDirective) {
-  //! FIXME, this way of instantiating CFI program does not look right, either
-  //! refactor CFIProgram to not depend on the Code/Data Alignment or add a new
-  //! type that is independent from this and is also feedable to UnwindTable.
-  auto DwarfOperations = dwarf::CFIProgram(
-      1 /* TODO */, 1 /* TODO */, Context->getTargetTriple().getArch());
+UnwindInfoState::convert(MCCFIInstruction Directive) {
+  auto CFIP = dwarf::CFIProgram(
+      /* CodeAlignmentFactor */ 1, /* DataAlignmentFactor */ 1,
+      Context->getTargetTriple().getArch());
 
-  switch (CFIDirective.getOperation()) {
+  auto MaybeCurrentRow = getCurrentUnwindRow();
+  switch (Directive.getOperation()) {
   case MCCFIInstruction::OpSameValue:
-    DwarfOperations.addInstruction(dwarf::DW_CFA_same_value,
-                                   CFIDirective.getRegister());
+    CFIP.addInstruction(dwarf::DW_CFA_same_value, Directive.getRegister());
     break;
   case MCCFIInstruction::OpRememberState:
-    DwarfOperations.addInstruction(dwarf::DW_CFA_remember_state);
+    CFIP.addInstruction(dwarf::DW_CFA_remember_state);
     break;
   case MCCFIInstruction::OpRestoreState:
-    DwarfOperations.addInstruction(dwarf::DW_CFA_restore_state);
+    CFIP.addInstruction(dwarf::DW_CFA_restore_state);
     break;
   case MCCFIInstruction::OpOffset:
-    DwarfOperations.addInstruction(dwarf::DW_CFA_offset,
-                                   CFIDirective.getRegister(),
-                                   CFIDirective.getOffset());
+    CFIP.addInstruction(dwarf::DW_CFA_offset, Directive.getRegister(),
+                        Directive.getOffset());
     break;
   case MCCFIInstruction::OpLLVMDefAspaceCfa:
-    DwarfOperations.addInstruction(dwarf::DW_CFA_LLVM_def_aspace_cfa,
-                                   CFIDirective.getRegister());
+    CFIP.addInstruction(dwarf::DW_CFA_LLVM_def_aspace_cfa,
+                        Directive.getRegister());
     break;
   case MCCFIInstruction::OpDefCfaRegister:
-    DwarfOperations.addInstruction(dwarf::DW_CFA_def_cfa_register,
-                                   CFIDirective.getRegister());
+    CFIP.addInstruction(dwarf::DW_CFA_def_cfa_register,
+                        Directive.getRegister());
     break;
   case MCCFIInstruction::OpDefCfaOffset:
-    DwarfOperations.addInstruction(dwarf::DW_CFA_def_cfa_offset,
-                                   CFIDirective.getOffset());
+    CFIP.addInstruction(dwarf::DW_CFA_def_cfa_offset, Directive.getOffset());
     break;
   case MCCFIInstruction::OpDefCfa:
-    DwarfOperations.addInstruction(dwarf::DW_CFA_def_cfa,
-                                   CFIDirective.getRegister(),
-                                   CFIDirective.getOffset());
+    CFIP.addInstruction(dwarf::DW_CFA_def_cfa, Directive.getRegister(),
+                        Directive.getOffset());
     break;
   case MCCFIInstruction::OpRelOffset:
-    if (!getCurrentUnwindRow()) // TODO maybe replace it with assert
-      return std::nullopt;
+    assert(
+        MaybeCurrentRow &&
+        "Cannot define relative offset to a non-existing CFA unwinding rule");
 
-    DwarfOperations.addInstruction(
-        dwarf::DW_CFA_offset, CFIDirective.getRegister(),
-        CFIDirective.getOffset() -
-            getCurrentUnwindRow().value()->getCFAValue().getOffset());
+    CFIP.addInstruction(dwarf::DW_CFA_offset, Directive.getRegister(),
+                        Directive.getOffset() -
+                            (*MaybeCurrentRow)->getCFAValue().getOffset());
     break;
   case MCCFIInstruction::OpAdjustCfaOffset:
-    if (!getCurrentUnwindRow()) // TODO maybe replace it with assert
-      return std::nullopt;
+    assert(MaybeCurrentRow &&
+           "Cannot adjust CFA offset of a non-existing CFA unwinding rule");
 
-    DwarfOperations.addInstruction(
-        dwarf::DW_CFA_def_cfa_offset,
-        CFIDirective.getOffset() +
-            getCurrentUnwindRow().value()->getCFAValue().getOffset());
+    CFIP.addInstruction(dwarf::DW_CFA_def_cfa_offset,
+                        Directive.getOffset() +
+                            (*MaybeCurrentRow)->getCFAValue().getOffset());
     break;
   case MCCFIInstruction::OpEscape:
-    // TODO It's now feasible but for now, I ignore it
+    // TODO DWARFExpressions are not supported yet.
     break;
   case MCCFIInstruction::OpRestore:
-    DwarfOperations.addInstruction(dwarf::DW_CFA_restore);
+    CFIP.addInstruction(dwarf::DW_CFA_restore);
     break;
   case MCCFIInstruction::OpUndefined:
-    DwarfOperations.addInstruction(dwarf::DW_CFA_undefined,
-                                   CFIDirective.getRegister());
+    CFIP.addInstruction(dwarf::DW_CFA_undefined, Directive.getRegister());
     break;
   case MCCFIInstruction::OpRegister:
-    DwarfOperations.addInstruction(dwarf::DW_CFA_register,
-                                   CFIDirective.getRegister(),
-                                   CFIDirective.getRegister2());
+    CFIP.addInstruction(dwarf::DW_CFA_register, Directive.getRegister(),
+                        Directive.getRegister2());
     break;
   case MCCFIInstruction::OpWindowSave:
-    // TODO make sure these are the same.
-    DwarfOperations.addInstruction(dwarf::DW_CFA_GNU_window_save);
+    CFIP.addInstruction(dwarf::DW_CFA_GNU_window_save);
     break;
   case MCCFIInstruction::OpNegateRAState:
-    // TODO make sure these are the same.
-    DwarfOperations.addInstruction(dwarf::DW_CFA_AARCH64_negate_ra_state);
+    CFIP.addInstruction(dwarf::DW_CFA_AARCH64_negate_ra_state);
     break;
   case MCCFIInstruction::OpNegateRAStateWithPC:
-    // TODO make sure these are the same.
-    DwarfOperations.addInstruction(
-        dwarf::DW_CFA_AARCH64_negate_ra_state_with_pc);
+    CFIP.addInstruction(dwarf::DW_CFA_AARCH64_negate_ra_state_with_pc);
     break;
   case MCCFIInstruction::OpGnuArgsSize:
-    DwarfOperations.addInstruction(dwarf::DW_CFA_GNU_args_size);
+    CFIP.addInstruction(dwarf::DW_CFA_GNU_args_size);
     break;
   case MCCFIInstruction::OpLabel:
     // TODO, I don't know what it is, I have to implement it.
     break;
   case MCCFIInstruction::OpValOffset:
-    DwarfOperations.addInstruction(dwarf::DW_CFA_val_offset,
-                                   CFIDirective.getRegister(),
-                                   CFIDirective.getOffset());
+    CFIP.addInstruction(dwarf::DW_CFA_val_offset, Directive.getRegister(),
+                        Directive.getOffset());
     break;
   }
 
-  return DwarfOperations;
+  return CFIP;
 }

>From 439c1d0083eb8742ce16e9d171a6c02258e52dbe Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Wed, 25 Jun 2025 04:43:12 +0000
Subject: [PATCH 57/58] Revert unnecessary changes to llvm-mc

---
 llvm/tools/llvm-mc/llvm-mc.cpp | 31 ++++++++++++++++---------------
 1 file changed, 16 insertions(+), 15 deletions(-)

diff --git a/llvm/tools/llvm-mc/llvm-mc.cpp b/llvm/tools/llvm-mc/llvm-mc.cpp
index a0f5998d3f8fd..a23a69c4f0b39 100644
--- a/llvm/tools/llvm-mc/llvm-mc.cpp
+++ b/llvm/tools/llvm-mc/llvm-mc.cpp
@@ -17,7 +17,6 @@
 #include "llvm/MC/MCCodeEmitter.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCInstPrinter.h"
-#include "llvm/MC/MCInstrAnalysis.h"
 #include "llvm/MC/MCInstrInfo.h"
 #include "llvm/MC/MCObjectFileInfo.h"
 #include "llvm/MC/MCObjectWriter.h"
@@ -26,7 +25,6 @@
 #include "llvm/MC/MCRegisterInfo.h"
 #include "llvm/MC/MCStreamer.h"
 #include "llvm/MC/MCSubtargetInfo.h"
-#include "llvm/MC/MCTargetOptions.h"
 #include "llvm/MC/MCTargetOptionsCommandFlags.h"
 #include "llvm/MC/TargetRegistry.h"
 #include "llvm/Support/CommandLine.h"
@@ -39,13 +37,10 @@
 #include "llvm/Support/TargetSelect.h"
 #include "llvm/Support/ToolOutputFile.h"
 #include "llvm/Support/WithColor.h"
-#include "llvm/Target/TargetMachine.h"
-#include "llvm/Target/TargetOptions.h"
 #include "llvm/TargetParser/Host.h"
 #include "llvm/UnwindInfoChecker/FunctionUnitStreamer.h"
 #include "llvm/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.h"
 #include <memory>
-#include <optional>
 
 using namespace llvm;
 
@@ -122,7 +117,11 @@ static cl::opt<unsigned> CommentColumn("comment-column",
                                        cl::desc("Asm comments indentation"),
                                        cl::init(40));
 
-enum OutputFileType { OFT_Null, OFT_AssemblyFile, OFT_ObjectFile };
+enum OutputFileType {
+  OFT_Null,
+  OFT_AssemblyFile,
+  OFT_ObjectFile
+};
 static cl::opt<OutputFileType>
     FileType("filetype", cl::init(OFT_AssemblyFile),
              cl::desc("Choose an output file type:"),
@@ -249,8 +248,8 @@ static const Target *GetTarget(const char *ProgName) {
 
   // Get the target specific parser.
   std::string Error;
-  const Target *TheTarget =
-      TargetRegistry::lookupTarget(ArchName, TheTriple, Error);
+  const Target *TheTarget = TargetRegistry::lookupTarget(ArchName, TheTriple,
+                                                         Error);
   if (!TheTarget) {
     WithColor::error(errs(), ProgName) << Error;
     return nullptr;
@@ -261,8 +260,8 @@ static const Target *GetTarget(const char *ProgName) {
   return TheTarget;
 }
 
-static std::unique_ptr<ToolOutputFile>
-GetOutputStream(StringRef Path, sys::fs::OpenFlags Flags) {
+static std::unique_ptr<ToolOutputFile> GetOutputStream(StringRef Path,
+    sys::fs::OpenFlags Flags) {
   std::error_code EC;
   auto Out = std::make_unique<ToolOutputFile>(Path, EC, Flags);
   if (EC) {
@@ -286,12 +285,13 @@ static void setDwarfDebugFlags(int argc, char **argv) {
 
 static std::string DwarfDebugProducer;
 static void setDwarfDebugProducer() {
-  if (!getenv("DEBUG_PRODUCER"))
+  if(!getenv("DEBUG_PRODUCER"))
     return;
   DwarfDebugProducer += getenv("DEBUG_PRODUCER");
 }
 
-static int AsLexInput(SourceMgr &SrcMgr, MCAsmInfo &MAI, raw_ostream &OS) {
+static int AsLexInput(SourceMgr &SrcMgr, MCAsmInfo &MAI,
+                      raw_ostream &OS) {
 
   AsmLexer Lexer(MAI);
   Lexer.setBuffer(SrcMgr.getMemoryBuffer(SrcMgr.getMainFileID())->getBuffer());
@@ -308,7 +308,7 @@ static int AsLexInput(SourceMgr &SrcMgr, MCAsmInfo &MAI, raw_ostream &OS) {
 }
 
 static int fillCommandLineSymbols(MCAsmParser &Parser) {
-  for (auto &I : DefineSymbol) {
+  for (auto &I: DefineSymbol) {
     auto Pair = StringRef(I).split('=');
     auto Sym = Pair.first;
     auto Val = Pair.second;
@@ -332,7 +332,8 @@ static int AssembleInput(const char *ProgName, const Target *TheTarget,
                          SourceMgr &SrcMgr, MCContext &Ctx, MCStreamer &Str,
                          MCAsmInfo &MAI, MCSubtargetInfo &STI,
                          MCInstrInfo &MCII, MCTargetOptions const &MCOptions) {
-  std::unique_ptr<MCAsmParser> Parser(createMCAsmParser(SrcMgr, Ctx, Str, MAI));
+  std::unique_ptr<MCAsmParser> Parser(
+      createMCAsmParser(SrcMgr, Ctx, Str, MAI));
   std::unique_ptr<MCTargetAsmParser> TAP(
       TheTarget->createMCAsmParser(STI, *Parser, MCII, MCOptions));
 
@@ -343,7 +344,7 @@ static int AssembleInput(const char *ProgName, const Target *TheTarget,
   }
 
   int SymbolResult = fillCommandLineSymbols(*Parser);
-  if (SymbolResult)
+  if(SymbolResult)
     return SymbolResult;
   Parser->setShowParsedOperands(ShowInstOperands);
   Parser->setTargetParser(*TAP);

>From dfddfea2ed5d68821004a5d979fa026a3b2ac915 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Wed, 25 Jun 2025 05:00:03 +0000
Subject: [PATCH 58/58] Lint

---
 llvm/include/llvm/DebugInfo/DWARF/DWARFCFIProgram.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFCFIProgram.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFCFIProgram.h
index 5613a3e21f5ae..79a2be7ef2584 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFCFIProgram.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFCFIProgram.h
@@ -144,7 +144,6 @@ class CFIProgram {
   const uint64_t CodeAlignmentFactor;
   const int64_t DataAlignmentFactor;
   Triple::ArchType Arch;
-
 };
 
 } // end namespace dwarf



More information about the llvm-commits mailing list