[llvm] Minimal version of DWARF CFI validation (PR #145443)

AmirHossein PashaeeHir via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 23 18:04:29 PDT 2025


https://github.com/amsen20 created https://github.com/llvm/llvm-project/pull/145443

This PR adds a minimal version of `UnwindInfoChecker` described in [here](https://discourse.llvm.org/t/rfc-dwarf-cfi-validation/86936). 

This implementation looks into the modified registers by each instruction and checks:
- If one of them is the CFA register, and it is updated, it informs the user if the CFA data is not up to date.
- If one of them is used in another register's unwinding rule, it informs the user if the unwind info is not updated after this instruction.

This implementation does not support DWARF expressions and treats them as unknown unwinding rules.

>From 17412ef0f5320f76c918e367e789c689e138752c 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/42] 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 fe972d972ca85704fb8aae436a31de2219b4da71 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/42] 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 8a1477bde966c2596378723db8ac1704bbcb4d4a 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/42] 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 2c1fd17df100b839342e7f491c5fe02204c560cb 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/42] 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 68274433f41e7dfd2534ed92a196230a5a0b5c70 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/42] 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 f0bdb322bf46019ff5747223fa3bfb559ce62bfa 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/42] 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 eec334a7817159e0f44585cc9f1824134e854548 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/42] 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 f189233d998d63c913a21fb88a0e526b3b9a7928 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/42] 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 fbc2264fb94b4dfd6166372e83475e487dcf9639 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/42] 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 75794310ef8c06aea062e7a7613e8d8ac7a288cc 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/42] 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 02da169f74aaa5a96a6383c574ef84e575226da2 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/42] 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 5e9acd2de72fa18331356061fef4568e842687d8 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/42] 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 95ef1a6555d2e2e232e348efa57d631cfd05399c 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/42] 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 6c7df4588235f694322c880b8c3bcbe7a31c542c 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/42] 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 2ef9b22a4d1ddb1f7be7c7cd3cb20a69735f1392 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/42] 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 f87ade713ac8b8490d845328b33b29c67c6d2e87 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/42] 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 008d1117819ab1dea8e202dd3d2e33aacca71883 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/42] 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 2758a89cf628b3439c87dd496df83adaf4a43b97 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/42] 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 92839c467dc7b40b1667e36878b9a549930ef650 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/42] 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 fafa366b54574b23ba2979817d097885b8f9c2f0 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/42] 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 5bc90c26901a17486602ae3a1a4764276b05289f 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/42] 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 8eca9e503693347ac8267bf27a5f0fda2eb0ddf6 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/42] 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 1ee570c57e267a2de4d5442466921578d28556ce 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/42] 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 f11403007555898d71304fc1d48714e0378b2d41 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/42] 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 2967cb7d34d3760435808a94e2ee7b148a5f0a79 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/42] 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 a3f9d593484149b609ebc05365a281fa81b822e2 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/42] 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 b5360c94a6b51e0a3daac166ee5e829f901458ea 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/42] 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 8973ab41cd9fa7d2cf411c385b8d3fb4093792ea 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/42] 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 0fc92311e7e192dc4e9fa3a360849ef30f50e8ed 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/42] 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 cbb158ecec07a987bf2d563898874d0584a73980 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/42] 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 b76fc6ea0a5ded5cb16db8f582a6a039113e1b0c 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/42] 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 9d7a0f38dbc3051c63b2081fabbbfa7c225c437b 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/42] 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    |  14 +-
 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, 290 insertions(+), 351 deletions(-)

diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h
index 051ea6e11e351..9981e2d34c9ed 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.
@@ -334,6 +335,7 @@ class UnwindTable {
     assert(Index < size());
     return Rows[Index];
   }
+  void insertRow(UnwindRow Row) { Rows.push_back(Row); }
 
   /// Dump the UnwindTable to the stream.
   ///
@@ -372,12 +374,6 @@ class UnwindTable {
   /// machine errors, or a valid UnwindTable otherwise.
   LLVM_ABI static Expected<UnwindTable> create(const FDE *Fde);
 
-private:
-  RowContainer Rows;
-  /// The end address when data is extracted from a FDE. This value will be
-  /// invalid when a UnwindTable is extracted from a CIE.
-  std::optional<uint64_t> EndAddress;
-
   /// Parse the information in the CFIProgram and update the CurrRow object
   /// that the state machine describes.
   ///
@@ -395,6 +391,12 @@ class UnwindTable {
   /// DW_CFA_restore and DW_CFA_restore_extended opcodes.
   Error parseRows(const CFIProgram &CFIP, UnwindRow &CurrRow,
                   const RegisterLocations *InitialLocs);
+private:
+  RowContainer Rows;
+  /// The end address when data is extracted from a FDE. This value will be
+  /// invalid when a UnwindTable is extracted from a CIE.
+  std::optional<uint64_t> EndAddress;
+
 };
 
 LLVM_ABI raw_ostream &operator<<(raw_ostream &OS, const UnwindTable &Rows);
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 822056e826f6a84101209a707214c5da816f231a 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/42] 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 95e63e4b291054f16cf918ffe970aaacc5b6ddba 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/42] 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 98c3ede548a31b948ccf8edc691ecc9f20e9db98 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/42] 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 9851b520ff5e647f9089b4b615a565d6f1e1d2d0 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/42] 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 4cff07e14cf2f4036da82114c0130cd6749934ff 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/42] 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 83083fed8dd468d7e27b57118d214dfc210aefab 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/42] 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 20faeb2cfba797afa38159a878b3eb14dc57b4af 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/42] 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 6018dc521370e1b4a60b4eece3337e31fdc275eb 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/42] 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 7ae2513114043c6446862cb3157733b18f0a05a0 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/42] 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 5f964a895396fb3da573782015b9e4d11701b66b 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/42] 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 ad7358c28f16b..09eaeca33c48e 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.
   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;



More information about the llvm-commits mailing list