[llvm] Minimal unwinding information (DWARF CFI) checker (PR #145633)
AmirHossein PashaeeHir via llvm-commits
llvm-commits at lists.llvm.org
Tue Jun 24 22:00:53 PDT 2025
https://github.com/amsen20 updated https://github.com/llvm/llvm-project/pull/145633
>From 5b78ea04455f8316737778f4940f1864689ff0b8 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Tue, 6 May 2025 17:45:34 +0000
Subject: [PATCH 01/58] Forward CFI directives alongside their associated
instruction to a simple CFI analysis
---
llvm/tools/llvm-mc/CFIAnalysis.h | 88 ++++++++++++
llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h | 151 +++++++++++++++++++++
2 files changed, 239 insertions(+)
create mode 100644 llvm/tools/llvm-mc/CFIAnalysis.h
create mode 100644 llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h
diff --git a/llvm/tools/llvm-mc/CFIAnalysis.h b/llvm/tools/llvm-mc/CFIAnalysis.h
new file mode 100644
index 0000000000000..eeb8741fb012b
--- /dev/null
+++ b/llvm/tools/llvm-mc/CFIAnalysis.h
@@ -0,0 +1,88 @@
+#ifndef LLVM_TOOLS_LLVM_MC_CFI_ANALYSIS_H
+#define LLVM_TOOLS_LLVM_MC_CFI_ANALYSIS_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDwarf.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/Support/Debug.h"
+
+namespace llvm {
+
+// TODO remove it, it's just for debug purposes.
+void printUntilNextLine(const char *Str) {
+ for (int I = 0; Str[I] != '\0' && Str[I] != '\n'; I++)
+ dbgs() << Str[I];
+}
+
+class CFIAnalysis {
+ MCContext &Context;
+ MCInstrInfo const &MCII;
+
+public:
+ CFIAnalysis(MCContext &Context, MCInstrInfo const &MCII)
+ : Context(Context), MCII(MCII) {}
+
+ void update(const MCDwarfFrameInfo &DwarfFrame, const MCInst &Inst,
+ ArrayRef<MCCFIInstruction> CFIDirectives) {
+ dbgs() << "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n";
+ printUntilNextLine(Inst.getLoc().getPointer());
+ dbgs() << "\n";
+ dbgs() << "codes: ";
+ Inst.print(dbgs());
+ dbgs() << "\n";
+ dbgs() << "------------------------------\n";
+ auto *RI = Context.getRegisterInfo();
+ auto CFAReg = RI->getLLVMRegNum(DwarfFrame.CurrentCfaRegister, false);
+ dbgs() << "The CFA register is: " << CFAReg << "\n";
+ bool GoingToChangeCFA = false;
+ for (auto CFIDirective : CFIDirectives) {
+ auto Op = CFIDirective.getOperation();
+ GoingToChangeCFA |= (Op == MCCFIInstruction::OpDefCfa ||
+ Op == MCCFIInstruction::OpDefCfaOffset ||
+ Op == MCCFIInstruction::OpDefCfaRegister ||
+ Op == MCCFIInstruction::OpAdjustCfaOffset ||
+ Op == MCCFIInstruction::OpLLVMDefAspaceCfa);
+ }
+ dbgs() << "------------------------------\n";
+ bool ChangedCFA = false;
+ for (int I = 0; I < Inst.getNumOperands(); I++) {
+ auto &&Operand = Inst.getOperand(I);
+ if (!Operand.isReg())
+ continue;
+ if (MCII.get(Inst.getOpcode())
+ .hasDefOfPhysReg(Inst, Operand.getReg(), *RI)) {
+ dbgs() << "This instruction modifies: " << Operand.getReg().id()
+ << "\n";
+ if (Operand.getReg() == CFAReg.value())
+ ChangedCFA = true;
+ }
+ }
+ dbgs() << "------------------------------\n";
+ dbgs() << "The instruction DOES " << (ChangedCFA ? "" : "NOT ")
+ << "change the CFA.\n";
+ dbgs() << "The CFI directives DOES " << (GoingToChangeCFA ? "" : "NOT ")
+ << "change the CFA.\n";
+ if (ChangedCFA && !GoingToChangeCFA) {
+ Context.reportError(Inst.getLoc(),
+ "The instruction changes CFA register value, but the "
+ "CFI directives don't update the CFA.");
+ }
+ // TODO needs more work
+ // if (!ChangedCFA && GoingToChangeCFA) {
+ // Context.reportError(
+ // Inst.getLoc(),
+ // "The instruction doesn't change CFA register value, but the "
+ // "CFI directives update the CFA.");
+ // }
+ dbgs() << "vvvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n";
+ ChangedCFA = false;
+ }
+};
+
+} // namespace llvm
+#endif
\ No newline at end of file
diff --git a/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h b/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h
new file mode 100644
index 0000000000000..9c7747520a033
--- /dev/null
+++ b/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h
@@ -0,0 +1,151 @@
+#ifndef LLVM_TOOLS_LLVM_MC_CFI_ANALYSIS_MC_STREAMER_H
+#define LLVM_TOOLS_LLVM_MC_CFI_ANALYSIS_MC_STREAMER_H
+
+#include "CFIAnalysis.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDwarf.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/Support/Debug.h"
+#include <cstdio>
+#include <optional>
+#include <set>
+
+namespace llvm {
+
+class CFIAnalysisMCStreamer : public MCStreamer {
+ struct CFIDirectivesState {
+ int FrameIndex; // TODO remove it, no need for it
+ int DirectiveIndex;
+
+ CFIDirectivesState() : FrameIndex(-1), DirectiveIndex(0) {}
+
+ CFIDirectivesState(int FrameIndex, int InstructionIndex)
+ : FrameIndex(FrameIndex), DirectiveIndex(InstructionIndex) {}
+ } LastCFIDirectivesState;
+ std::vector<int> FrameIndices;
+
+ struct ICFI {
+ MCInst Instruction;
+ ArrayRef<MCCFIInstruction> CFIDirectives;
+
+ ICFI(MCInst Instruction, ArrayRef<MCCFIInstruction> CFIDirectives)
+ : Instruction(Instruction), CFIDirectives(CFIDirectives) {}
+ };
+
+ std::optional<MCInst> LastInstruction;
+ std::optional<MCDwarfFrameInfo> LastDwarfFrameInfo;
+ CFIAnalysis CFIA;
+
+ std::optional<ICFI> getLastICFI() {
+ if (!LastInstruction)
+ return std::nullopt;
+
+ auto DwarfFrameInfos = getDwarfFrameInfos();
+ int FrameIndex = FrameIndices.back();
+ auto CurrentCFIDirectiveState =
+ hasUnfinishedDwarfFrameInfo()
+ ? CFIDirectivesState(
+ FrameIndex, DwarfFrameInfos[FrameIndex].Instructions.size())
+ : CFIDirectivesState();
+ assert(CurrentCFIDirectiveState.FrameIndex ==
+ LastCFIDirectivesState.FrameIndex);
+ assert(CurrentCFIDirectiveState.DirectiveIndex >=
+ LastCFIDirectivesState.DirectiveIndex);
+
+ std::vector<MCCFIInstruction> CFIDirectives;
+ if (LastCFIDirectivesState.FrameIndex >= 0) {
+ auto CFIInstructions = DwarfFrameInfos[FrameIndex].Instructions;
+ CFIDirectives = std::vector<MCCFIInstruction>(
+ CFIInstructions.begin() + LastCFIDirectivesState.DirectiveIndex,
+ CFIInstructions.begin() + CurrentCFIDirectiveState.DirectiveIndex);
+ }
+
+ LastCFIDirectivesState = CurrentCFIDirectiveState;
+ return ICFI(LastInstruction.value(), CFIDirectives);
+ }
+
+ void feedCFIA() {
+ if (!LastDwarfFrameInfo) {
+ // TODO Maybe this corner case causes bugs, when the programmer did a
+ // mistake in the startproc, endprocs and also made a mistake in not
+ // adding cfi directives for a instruction. Then this would cause to
+ // ignore the instruction.
+ auto LastICFI = getLastICFI();
+ assert(!LastICFI || LastICFI->CFIDirectives.empty());
+ return;
+ }
+
+ if (auto ICFI = getLastICFI())
+ CFIA.update(LastDwarfFrameInfo.value(), ICFI->Instruction,
+ ICFI->CFIDirectives);
+ }
+
+public:
+ CFIAnalysisMCStreamer(MCContext &Context, const MCInstrInfo &MCII)
+ : MCStreamer(Context), LastCFIDirectivesState(),
+ LastInstruction(std::nullopt), CFIA(Context, MCII) {
+ FrameIndices.push_back(-1);
+ }
+
+ /// @name MCStreamer Interface
+ /// @{
+
+ bool hasRawTextSupport() const override { return true; }
+ void emitRawTextImpl(StringRef String) override {}
+
+ bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override {
+ return true;
+ }
+
+ void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
+ Align ByteAlignment) override {}
+ void beginCOFFSymbolDef(const MCSymbol *Symbol) override {}
+ void emitCOFFSymbolStorageClass(int StorageClass) override {}
+ void emitCOFFSymbolType(int Type) override {}
+ void endCOFFSymbolDef() override {}
+ void emitXCOFFSymbolLinkageWithVisibility(MCSymbol *Symbol,
+ MCSymbolAttr Linkage,
+ MCSymbolAttr Visibility) override {}
+
+ void emitInstruction(const MCInst &Inst,
+ const MCSubtargetInfo &STI) override {
+ feedCFIA();
+ LastInstruction = Inst;
+ if (hasUnfinishedDwarfFrameInfo())
+ LastDwarfFrameInfo = getDwarfFrameInfos()[FrameIndices.back()];
+ else
+ LastDwarfFrameInfo = std::nullopt;
+ }
+
+ void emitCFIStartProcImpl(MCDwarfFrameInfo &Frame) override {
+ feedCFIA();
+ FrameIndices.push_back(getNumFrameInfos());
+ LastInstruction = std::nullopt;
+ LastDwarfFrameInfo = std::nullopt;
+ LastCFIDirectivesState.FrameIndex = FrameIndices.back();
+ LastCFIDirectivesState.DirectiveIndex = 0;
+ MCStreamer::emitCFIStartProcImpl(Frame);
+ }
+
+ void emitCFIEndProcImpl(MCDwarfFrameInfo &CurFrame) override {
+ feedCFIA();
+ // TODO this will break if the input frame are malformed.
+ FrameIndices.pop_back();
+ LastInstruction = std::nullopt;
+ LastDwarfFrameInfo = std::nullopt;
+ LastCFIDirectivesState.FrameIndex = FrameIndices.back();
+ LastCFIDirectivesState.DirectiveIndex =
+ LastCFIDirectivesState.FrameIndex >= 0
+ ? getDwarfFrameInfos()[LastCFIDirectivesState.FrameIndex]
+ .Instructions.size()
+ : 0;
+ MCStreamer::emitCFIEndProcImpl(CurFrame);
+ }
+};
+
+} // namespace llvm
+#endif
\ No newline at end of file
>From b781e831666abb532beefe776e13c72c408d6044 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Tue, 6 May 2025 18:00:50 +0000
Subject: [PATCH 02/58] Create a new CFI analysis for each dwarf separately
---
llvm/tools/llvm-mc/CFIAnalysis.h | 2 +-
llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h | 21 ++++++++++++---------
2 files changed, 13 insertions(+), 10 deletions(-)
diff --git a/llvm/tools/llvm-mc/CFIAnalysis.h b/llvm/tools/llvm-mc/CFIAnalysis.h
index eeb8741fb012b..6abbdfba6d28f 100644
--- a/llvm/tools/llvm-mc/CFIAnalysis.h
+++ b/llvm/tools/llvm-mc/CFIAnalysis.h
@@ -50,7 +50,7 @@ class CFIAnalysis {
}
dbgs() << "------------------------------\n";
bool ChangedCFA = false;
- for (int I = 0; I < Inst.getNumOperands(); I++) {
+ for (unsigned I = 0; I < Inst.getNumOperands(); I++) {
auto &&Operand = Inst.getOperand(I);
if (!Operand.isReg())
continue;
diff --git a/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h b/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h
index 9c7747520a033..76ae536ab4bd3 100644
--- a/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h
+++ b/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h
@@ -7,16 +7,15 @@
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDwarf.h"
#include "llvm/MC/MCInstrInfo.h"
-#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCStreamer.h"
-#include "llvm/Support/Debug.h"
#include <cstdio>
#include <optional>
-#include <set>
namespace llvm {
class CFIAnalysisMCStreamer : public MCStreamer {
+ MCInstrInfo const &MCII;
+
struct CFIDirectivesState {
int FrameIndex; // TODO remove it, no need for it
int DirectiveIndex;
@@ -27,6 +26,7 @@ class CFIAnalysisMCStreamer : public MCStreamer {
: FrameIndex(FrameIndex), DirectiveIndex(InstructionIndex) {}
} LastCFIDirectivesState;
std::vector<int> FrameIndices;
+ std::vector<CFIAnalysis> CFIAs;
struct ICFI {
MCInst Instruction;
@@ -38,7 +38,6 @@ class CFIAnalysisMCStreamer : public MCStreamer {
std::optional<MCInst> LastInstruction;
std::optional<MCDwarfFrameInfo> LastDwarfFrameInfo;
- CFIAnalysis CFIA;
std::optional<ICFI> getLastICFI() {
if (!LastInstruction)
@@ -79,15 +78,17 @@ class CFIAnalysisMCStreamer : public MCStreamer {
return;
}
- if (auto ICFI = getLastICFI())
- CFIA.update(LastDwarfFrameInfo.value(), ICFI->Instruction,
- ICFI->CFIDirectives);
+ if (auto ICFI = getLastICFI()) {
+ assert(!CFIAs.empty());
+ CFIAs.back().update(LastDwarfFrameInfo.value(), ICFI->Instruction,
+ ICFI->CFIDirectives);
+ }
}
public:
CFIAnalysisMCStreamer(MCContext &Context, const MCInstrInfo &MCII)
- : MCStreamer(Context), LastCFIDirectivesState(),
- LastInstruction(std::nullopt), CFIA(Context, MCII) {
+ : MCStreamer(Context), MCII(MCII), LastCFIDirectivesState(),
+ LastInstruction(std::nullopt) {
FrameIndices.push_back(-1);
}
@@ -124,6 +125,7 @@ class CFIAnalysisMCStreamer : public MCStreamer {
void emitCFIStartProcImpl(MCDwarfFrameInfo &Frame) override {
feedCFIA();
FrameIndices.push_back(getNumFrameInfos());
+ CFIAs.emplace_back(getContext(), MCII);
LastInstruction = std::nullopt;
LastDwarfFrameInfo = std::nullopt;
LastCFIDirectivesState.FrameIndex = FrameIndices.back();
@@ -135,6 +137,7 @@ class CFIAnalysisMCStreamer : public MCStreamer {
feedCFIA();
// TODO this will break if the input frame are malformed.
FrameIndices.pop_back();
+ CFIAs.pop_back();
LastInstruction = std::nullopt;
LastDwarfFrameInfo = std::nullopt;
LastCFIDirectivesState.FrameIndex = FrameIndices.back();
>From 8b43f8c29b7c1fbc48a3bb86b765627e20ac6201 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Tue, 6 May 2025 23:42:31 +0000
Subject: [PATCH 03/58] Separate the logic and display
---
llvm/tools/llvm-mc/CFIAnalysis.h | 93 +++++++++++++++++++-------------
1 file changed, 57 insertions(+), 36 deletions(-)
diff --git a/llvm/tools/llvm-mc/CFIAnalysis.h b/llvm/tools/llvm-mc/CFIAnalysis.h
index 6abbdfba6d28f..f527043d3dbbb 100644
--- a/llvm/tools/llvm-mc/CFIAnalysis.h
+++ b/llvm/tools/llvm-mc/CFIAnalysis.h
@@ -2,14 +2,18 @@
#define LLVM_TOOLS_LLVM_MC_CFI_ANALYSIS_H
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDwarf.h"
+#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/Support/Debug.h"
+#include <ostream>
+#include <set>
namespace llvm {
@@ -25,20 +29,47 @@ class CFIAnalysis {
public:
CFIAnalysis(MCContext &Context, MCInstrInfo const &MCII)
- : Context(Context), MCII(MCII) {}
+ : Context(Context), MCII(MCII) {
+ // TODO it should look at the poluge directives and setup the
+ // registers' previous value state here, but for now, it's assumed that all
+ // values are by default `samevalue`.
+ }
void update(const MCDwarfFrameInfo &DwarfFrame, const MCInst &Inst,
ArrayRef<MCCFIInstruction> CFIDirectives) {
- dbgs() << "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n";
- printUntilNextLine(Inst.getLoc().getPointer());
- dbgs() << "\n";
- dbgs() << "codes: ";
- Inst.print(dbgs());
- dbgs() << "\n";
- dbgs() << "------------------------------\n";
+
+ auto MCInstInfo = MCII.get(Inst.getOpcode());
auto *RI = Context.getRegisterInfo();
auto CFAReg = RI->getLLVMRegNum(DwarfFrame.CurrentCfaRegister, false);
- dbgs() << "The CFA register is: " << CFAReg << "\n";
+
+ std::set<int> Writes, Reads; // TODO reads is not ready for now
+ // FIXME this way of extracting uses is buggy:
+ // for (unsigned I = 0; I < MCInstInfo.NumImplicitUses; I++)
+ // Reads.insert(MCInstInfo.implicit_uses()[I]);
+ // for (unsigned I = 0; I < MCInstInfo.NumImplicitDefs; I++)
+ // Writes.insert(MCInstInfo.implicit_defs()[I]);
+
+ for (unsigned I = 0; I < Inst.getNumOperands(); I++) {
+ auto &&Operand = Inst.getOperand(I);
+ if (Operand.isReg()) {
+ // TODO it is not percise, maybe this operand is for output, then it
+ // means that there is no read happening here.
+ Reads.insert(Operand.getReg());
+ }
+
+ if (Operand.isExpr()) {
+ // TODO maybe the argument is not a register, but is a expression like
+ // `34(sp)` that has a register in it. Check if this works or not and if
+ // no change it somehow that it count that register as reads or writes
+ // too.
+ }
+
+ if (Operand.isReg() &&
+ MCInstInfo.hasDefOfPhysReg(Inst, Operand.getReg(), *RI))
+ Writes.insert(Operand.getReg().id());
+ }
+
+ bool ChangedCFA = Writes.count(CFAReg->id());
bool GoingToChangeCFA = false;
for (auto CFIDirective : CFIDirectives) {
auto Op = CFIDirective.getOperation();
@@ -48,38 +79,28 @@ class CFIAnalysis {
Op == MCCFIInstruction::OpAdjustCfaOffset ||
Op == MCCFIInstruction::OpLLVMDefAspaceCfa);
}
- dbgs() << "------------------------------\n";
- bool ChangedCFA = false;
- for (unsigned I = 0; I < Inst.getNumOperands(); I++) {
- auto &&Operand = Inst.getOperand(I);
- if (!Operand.isReg())
- continue;
- if (MCII.get(Inst.getOpcode())
- .hasDefOfPhysReg(Inst, Operand.getReg(), *RI)) {
- dbgs() << "This instruction modifies: " << Operand.getReg().id()
- << "\n";
- if (Operand.getReg() == CFAReg.value())
- ChangedCFA = true;
- }
- }
- dbgs() << "------------------------------\n";
- dbgs() << "The instruction DOES " << (ChangedCFA ? "" : "NOT ")
- << "change the CFA.\n";
- dbgs() << "The CFI directives DOES " << (GoingToChangeCFA ? "" : "NOT ")
- << "change the CFA.\n";
if (ChangedCFA && !GoingToChangeCFA) {
Context.reportError(Inst.getLoc(),
"The instruction changes CFA register value, but the "
"CFI directives don't update the CFA.");
}
- // TODO needs more work
- // if (!ChangedCFA && GoingToChangeCFA) {
- // Context.reportError(
- // Inst.getLoc(),
- // "The instruction doesn't change CFA register value, but the "
- // "CFI directives update the CFA.");
- // }
- dbgs() << "vvvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n";
+
+ dbgs() << "^^^^^^^^^^^^^^^^ InsCFIs ^^^^^^^^^^^^^^^^\n";
+ printUntilNextLine(Inst.getLoc().getPointer());
+ dbgs() << "\n";
+ dbgs() << "-----------------------------------------\n";
+ dbgs() << "writes into: { ";
+ for (auto Reg : Writes) {
+ dbgs() << (int)Reg << " ";
+ }
+ dbgs() << "}\n";
+ dbgs() << "-----------------------------------------\n";
+ dbgs() << "The CFA register is: " << CFAReg << "\n";
+ dbgs() << "The instruction does " << (ChangedCFA ? "" : "NOT ")
+ << "change the CFA.\n";
+ dbgs() << "The CFI directives does " << (GoingToChangeCFA ? "" : "NOT ")
+ << "change the CFA.\n";
+ dbgs() << "vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n";
ChangedCFA = false;
}
};
>From 6790f902972b05ac1d67c4315c12ec5904792bb4 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Fri, 9 May 2025 22:52:04 +0000
Subject: [PATCH 04/58] Compile llvm mc depending on bolt
---
bolt/lib/Utils/CommandLineOpts.cpp | 2 +-
llvm/tools/llvm-mc/CFIAnalysis.h | 35 ++++++++++++++++--
llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h | 12 ++++--
llvm/tools/llvm-mc/CMakeLists.txt | 3 ++
llvm/tools/llvm-mc/llvm-mc.cpp | 43 +++++++++++++---------
5 files changed, 69 insertions(+), 26 deletions(-)
diff --git a/bolt/lib/Utils/CommandLineOpts.cpp b/bolt/lib/Utils/CommandLineOpts.cpp
index 5635da476451d..d4d6dbcb72aac 100644
--- a/bolt/lib/Utils/CommandLineOpts.cpp
+++ b/bolt/lib/Utils/CommandLineOpts.cpp
@@ -202,7 +202,7 @@ cl::opt<bool> Lite("lite", cl::desc("skip processing of cold functions"),
cl::cat(BoltCategory));
cl::opt<std::string>
-OutputFilename("o",
+OutputFilename("ooo",
cl::desc("<output file>"),
cl::Optional,
cl::cat(BoltOutputCategory));
diff --git a/llvm/tools/llvm-mc/CFIAnalysis.h b/llvm/tools/llvm-mc/CFIAnalysis.h
index f527043d3dbbb..e3a09139d42af 100644
--- a/llvm/tools/llvm-mc/CFIAnalysis.h
+++ b/llvm/tools/llvm-mc/CFIAnalysis.h
@@ -1,8 +1,8 @@
#ifndef LLVM_TOOLS_LLVM_MC_CFI_ANALYSIS_H
#define LLVM_TOOLS_LLVM_MC_CFI_ANALYSIS_H
+#include "bolt/Core/MCPlusBuilder.h"
#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDwarf.h"
@@ -11,12 +11,32 @@
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/Debug.h"
-#include <ostream>
+#include <memory>
#include <set>
namespace llvm {
+bolt::MCPlusBuilder *createMCPlusBuilder(const Triple::ArchType Arch,
+ const MCInstrAnalysis *Analysis,
+ const MCInstrInfo *Info,
+ const MCRegisterInfo *RegInfo,
+ const MCSubtargetInfo *STI) {
+ dbgs() << "arch: " << Arch << ", and expected " << Triple::x86_64 << "\n";
+ if (Arch == Triple::x86_64)
+ return bolt::createX86MCPlusBuilder(Analysis, Info, RegInfo, STI);
+
+ // if (Arch == Triple::aarch64)
+ // return createAArch64MCPlusBuilder(Analysis, Info, RegInfo, STI);
+
+ // if (Arch == Triple::riscv64)
+ // return createRISCVMCPlusBuilder(Analysis, Info, RegInfo, STI);
+
+ llvm_unreachable("architecture unsupported by MCPlusBuilder");
+}
+
// TODO remove it, it's just for debug purposes.
void printUntilNextLine(const char *Str) {
for (int I = 0; Str[I] != '\0' && Str[I] != '\n'; I++)
@@ -26,19 +46,24 @@ void printUntilNextLine(const char *Str) {
class CFIAnalysis {
MCContext &Context;
MCInstrInfo const &MCII;
+ std::unique_ptr<bolt::MCPlusBuilder> MCPB;
public:
- CFIAnalysis(MCContext &Context, MCInstrInfo const &MCII)
+ CFIAnalysis(MCContext &Context, MCInstrInfo const &MCII,
+ MCInstrAnalysis *MCIA)
: Context(Context), MCII(MCII) {
// TODO it should look at the poluge directives and setup the
// registers' previous value state here, but for now, it's assumed that all
// values are by default `samevalue`.
+ MCPB.reset(createMCPlusBuilder(Context.getTargetTriple().getArch(), MCIA,
+ &MCII, Context.getRegisterInfo(),
+ Context.getSubtargetInfo()));
}
void update(const MCDwarfFrameInfo &DwarfFrame, const MCInst &Inst,
ArrayRef<MCCFIInstruction> CFIDirectives) {
- auto MCInstInfo = MCII.get(Inst.getOpcode());
+ const MCInstrDesc &MCInstInfo = MCII.get(Inst.getOpcode());
auto *RI = Context.getRegisterInfo();
auto CFAReg = RI->getLLVMRegNum(DwarfFrame.CurrentCfaRegister, false);
@@ -95,6 +120,8 @@ class CFIAnalysis {
}
dbgs() << "}\n";
dbgs() << "-----------------------------------------\n";
+ dbgs() << "isMoveMem2Reg: " << MCPB->isMoveMem2Reg(Inst) << "\n";
+ dbgs() << "-----------------------------------------\n";
dbgs() << "The CFA register is: " << CFAReg << "\n";
dbgs() << "The instruction does " << (ChangedCFA ? "" : "NOT ")
<< "change the CFA.\n";
diff --git a/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h b/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h
index 76ae536ab4bd3..382a80aca94b4 100644
--- a/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h
+++ b/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h
@@ -6,15 +6,18 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDwarf.h"
+#include "llvm/MC/MCInstrAnalysis.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCStreamer.h"
#include <cstdio>
+#include <memory>
#include <optional>
namespace llvm {
class CFIAnalysisMCStreamer : public MCStreamer {
MCInstrInfo const &MCII;
+ std::unique_ptr<MCInstrAnalysis> MCIA;
struct CFIDirectivesState {
int FrameIndex; // TODO remove it, no need for it
@@ -86,9 +89,10 @@ class CFIAnalysisMCStreamer : public MCStreamer {
}
public:
- CFIAnalysisMCStreamer(MCContext &Context, const MCInstrInfo &MCII)
- : MCStreamer(Context), MCII(MCII), LastCFIDirectivesState(),
- LastInstruction(std::nullopt) {
+ CFIAnalysisMCStreamer(MCContext &Context, const MCInstrInfo &MCII,
+ std::unique_ptr<MCInstrAnalysis> MCIA)
+ : MCStreamer(Context), MCII(MCII), MCIA(std::move(MCIA)),
+ LastCFIDirectivesState(), LastInstruction(std::nullopt) {
FrameIndices.push_back(-1);
}
@@ -125,7 +129,7 @@ class CFIAnalysisMCStreamer : public MCStreamer {
void emitCFIStartProcImpl(MCDwarfFrameInfo &Frame) override {
feedCFIA();
FrameIndices.push_back(getNumFrameInfos());
- CFIAs.emplace_back(getContext(), MCII);
+ CFIAs.emplace_back(getContext(), MCII, MCIA.get());
LastInstruction = std::nullopt;
LastDwarfFrameInfo = std::nullopt;
LastCFIDirectivesState.FrameIndex = FrameIndices.back();
diff --git a/llvm/tools/llvm-mc/CMakeLists.txt b/llvm/tools/llvm-mc/CMakeLists.txt
index f57356f9ee0c0..368f29c62201f 100644
--- a/llvm/tools/llvm-mc/CMakeLists.txt
+++ b/llvm/tools/llvm-mc/CMakeLists.txt
@@ -13,3 +13,6 @@ add_llvm_tool(llvm-mc
llvm-mc.cpp
Disassembler.cpp
)
+
+target_link_libraries(llvm-mc PRIVATE LLVMBOLTCore LLVMBOLTTargetX86)
+target_include_directories(llvm-mc PRIVATE "${LLVM_MAIN_SRC_DIR}/../bolt/include")
diff --git a/llvm/tools/llvm-mc/llvm-mc.cpp b/llvm/tools/llvm-mc/llvm-mc.cpp
index b59a54d8fbc8a..32f2fa0f05a7c 100644
--- a/llvm/tools/llvm-mc/llvm-mc.cpp
+++ b/llvm/tools/llvm-mc/llvm-mc.cpp
@@ -11,12 +11,14 @@
//
//===----------------------------------------------------------------------===//
+#include "CFIAnalysisMCStreamer.h"
#include "Disassembler.h"
#include "llvm/MC/MCAsmBackend.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCInstPrinter.h"
+#include "llvm/MC/MCInstrAnalysis.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCObjectFileInfo.h"
#include "llvm/MC/MCObjectWriter.h"
@@ -25,6 +27,7 @@
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/MCTargetOptions.h"
#include "llvm/MC/MCTargetOptionsCommandFlags.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/CommandLine.h"
@@ -37,7 +40,11 @@
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/ToolOutputFile.h"
#include "llvm/Support/WithColor.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetOptions.h"
#include "llvm/TargetParser/Host.h"
+#include <memory>
+#include <optional>
using namespace llvm;
@@ -114,11 +121,7 @@ static cl::opt<unsigned> CommentColumn("comment-column",
cl::desc("Asm comments indentation"),
cl::init(40));
-enum OutputFileType {
- OFT_Null,
- OFT_AssemblyFile,
- OFT_ObjectFile
-};
+enum OutputFileType { OFT_Null, OFT_AssemblyFile, OFT_ObjectFile };
static cl::opt<OutputFileType>
FileType("filetype", cl::init(OFT_AssemblyFile),
cl::desc("Choose an output file type:"),
@@ -241,8 +244,8 @@ static const Target *GetTarget(const char *ProgName) {
// Get the target specific parser.
std::string Error;
- const Target *TheTarget = TargetRegistry::lookupTarget(ArchName, TheTriple,
- Error);
+ const Target *TheTarget =
+ TargetRegistry::lookupTarget(ArchName, TheTriple, Error);
if (!TheTarget) {
WithColor::error(errs(), ProgName) << Error;
return nullptr;
@@ -253,8 +256,8 @@ static const Target *GetTarget(const char *ProgName) {
return TheTarget;
}
-static std::unique_ptr<ToolOutputFile> GetOutputStream(StringRef Path,
- sys::fs::OpenFlags Flags) {
+static std::unique_ptr<ToolOutputFile>
+GetOutputStream(StringRef Path, sys::fs::OpenFlags Flags) {
std::error_code EC;
auto Out = std::make_unique<ToolOutputFile>(Path, EC, Flags);
if (EC) {
@@ -278,13 +281,12 @@ static void setDwarfDebugFlags(int argc, char **argv) {
static std::string DwarfDebugProducer;
static void setDwarfDebugProducer() {
- if(!getenv("DEBUG_PRODUCER"))
+ if (!getenv("DEBUG_PRODUCER"))
return;
DwarfDebugProducer += getenv("DEBUG_PRODUCER");
}
-static int AsLexInput(SourceMgr &SrcMgr, MCAsmInfo &MAI,
- raw_ostream &OS) {
+static int AsLexInput(SourceMgr &SrcMgr, MCAsmInfo &MAI, raw_ostream &OS) {
AsmLexer Lexer(MAI);
Lexer.setBuffer(SrcMgr.getMemoryBuffer(SrcMgr.getMainFileID())->getBuffer());
@@ -301,7 +303,7 @@ static int AsLexInput(SourceMgr &SrcMgr, MCAsmInfo &MAI,
}
static int fillCommandLineSymbols(MCAsmParser &Parser) {
- for (auto &I: DefineSymbol) {
+ for (auto &I : DefineSymbol) {
auto Pair = StringRef(I).split('=');
auto Sym = Pair.first;
auto Val = Pair.second;
@@ -325,8 +327,7 @@ static int AssembleInput(const char *ProgName, const Target *TheTarget,
SourceMgr &SrcMgr, MCContext &Ctx, MCStreamer &Str,
MCAsmInfo &MAI, MCSubtargetInfo &STI,
MCInstrInfo &MCII, MCTargetOptions const &MCOptions) {
- std::unique_ptr<MCAsmParser> Parser(
- createMCAsmParser(SrcMgr, Ctx, Str, MAI));
+ std::unique_ptr<MCAsmParser> Parser(createMCAsmParser(SrcMgr, Ctx, Str, MAI));
std::unique_ptr<MCTargetAsmParser> TAP(
TheTarget->createMCAsmParser(STI, *Parser, MCII, MCOptions));
@@ -337,7 +338,7 @@ static int AssembleInput(const char *ProgName, const Target *TheTarget,
}
int SymbolResult = fillCommandLineSymbols(*Parser);
- if(SymbolResult)
+ if (SymbolResult)
return SymbolResult;
Parser->setShowParsedOperands(ShowInstOperands);
Parser->setTargetParser(*TAP);
@@ -519,6 +520,10 @@ int main(int argc, char **argv) {
std::unique_ptr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo());
assert(MCII && "Unable to create instruction info!");
+ std::unique_ptr<MCInstrAnalysis> MCIA(
+ TheTarget->createMCInstrAnalysis(MCII.get()));
+ assert(MCIA && "Unable to create instruction analysis!");
+
std::unique_ptr<MCInstPrinter> IP;
if (FileType == OFT_AssemblyFile) {
IP.reset(TheTarget->createMCInstPrinter(
@@ -564,7 +569,11 @@ int main(int argc, char **argv) {
std::move(CE), std::move(MAB)));
} else if (FileType == OFT_Null) {
- Str.reset(TheTarget->createNullStreamer(Ctx));
+ auto *MyDummyStreamer =
+ new CFIAnalysisMCStreamer(Ctx, *MCII, std::move(MCIA));
+ TheTarget->createNullTargetStreamer(*MyDummyStreamer);
+ Str.reset(MyDummyStreamer);
+ // Str.reset(TheTarget->createNullStreamer(Ctx));
} else {
assert(FileType == OFT_ObjectFile && "Invalid file type!");
>From 75f3b2dfa38ca24e274868ce7a5f5ab00cb58e7f Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Tue, 13 May 2025 00:17:57 +0000
Subject: [PATCH 05/58] Extract semantic info on MCInst from bolt
---
llvm/tools/llvm-mc/CFIAnalysis.h | 152 +++++++++++++++++++++++++++----
1 file changed, 136 insertions(+), 16 deletions(-)
diff --git a/llvm/tools/llvm-mc/CFIAnalysis.h b/llvm/tools/llvm-mc/CFIAnalysis.h
index e3a09139d42af..70b8a855643b9 100644
--- a/llvm/tools/llvm-mc/CFIAnalysis.h
+++ b/llvm/tools/llvm-mc/CFIAnalysis.h
@@ -4,17 +4,21 @@
#include "bolt/Core/MCPlusBuilder.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDwarf.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCRegister.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/Error.h"
#include <memory>
+#include <optional>
#include <set>
namespace llvm {
@@ -60,7 +64,7 @@ class CFIAnalysis {
Context.getSubtargetInfo()));
}
- void update(const MCDwarfFrameInfo &DwarfFrame, const MCInst &Inst,
+ void update(const MCDwarfFrameInfo &DwarfFrame, MCInst &Inst,
ArrayRef<MCCFIInstruction> CFIDirectives) {
const MCInstrDesc &MCInstInfo = MCII.get(Inst.getOpcode());
@@ -71,8 +75,8 @@ class CFIAnalysis {
// FIXME this way of extracting uses is buggy:
// for (unsigned I = 0; I < MCInstInfo.NumImplicitUses; I++)
// Reads.insert(MCInstInfo.implicit_uses()[I]);
- // for (unsigned I = 0; I < MCInstInfo.NumImplicitDefs; I++)
- // Writes.insert(MCInstInfo.implicit_defs()[I]);
+ for (unsigned I = 0; I < MCInstInfo.NumImplicitDefs; I++)
+ Writes.insert(MCInstInfo.implicit_defs()[I]);
for (unsigned I = 0; I < Inst.getNumOperands(); I++) {
auto &&Operand = Inst.getOperand(I);
@@ -113,20 +117,136 @@ class CFIAnalysis {
dbgs() << "^^^^^^^^^^^^^^^^ InsCFIs ^^^^^^^^^^^^^^^^\n";
printUntilNextLine(Inst.getLoc().getPointer());
dbgs() << "\n";
- dbgs() << "-----------------------------------------\n";
- dbgs() << "writes into: { ";
- for (auto Reg : Writes) {
- dbgs() << (int)Reg << " ";
+ dbgs() << "Op code: " << Inst.getOpcode() << "\n";
+ dbgs() << "--------------Operands Info--------------\n";
+ auto DefCount = MCInstInfo.getNumDefs();
+ for (unsigned I = 0; I < Inst.getNumOperands(); I++) {
+ dbgs() << "Operand #" << I << ", which will be "
+ << (I < DefCount ? "defined" : "used") << ", is a";
+ if (I == MCPB->getMemoryOperandNo(Inst)) {
+ dbgs() << " memory access, details are:\n";
+ auto X86MemoryOperand = MCPB->evaluateX86MemoryOperand(Inst);
+ dbgs() << " Base Register{ reg#" << X86MemoryOperand->BaseRegNum
+ << " }";
+ dbgs() << " + (Index Register{ reg#" << X86MemoryOperand->IndexRegNum
+ << " }";
+ dbgs() << " * Scale{ value " << X86MemoryOperand->ScaleImm << " }";
+ dbgs() << ") + Displacement{ "
+ << (X86MemoryOperand->DispExpr
+ ? "an expression"
+ : "value " + itostr(X86MemoryOperand->DispImm))
+ << " }\n";
+ // TODO, it's not correct always, it cannot be assumed (or should be
+ // checked) that memory operands are flatten into 4 operands in MCInc.
+ I += 4;
+ continue;
+ }
+ auto &&Operand = Inst.getOperand(I);
+ if (Operand.isImm()) {
+ dbgs() << "n immediate with value " << Operand.getImm() << "\n";
+ continue;
+ }
+ if (Operand.isReg()) {
+ dbgs() << " reg#" << Operand.getReg() << "\n";
+ continue;
+ }
+ assert(Operand.isExpr());
+ dbgs() << "n unknown expression \n";
+ }
+ if (MCInstInfo.NumImplicitDefs) {
+ dbgs() << "implicitly defines: { ";
+ for (unsigned I = 0; I < MCInstInfo.NumImplicitDefs; I++) {
+ dbgs() << "reg#" << MCInstInfo.implicit_defs()[I] << " ";
+ }
+ dbgs() << "}\n";
+ }
+ if (MCInstInfo.NumImplicitUses) {
+ dbgs() << "implicitly uses: { ";
+ for (unsigned I = 0; I < MCInstInfo.NumImplicitUses; I++) {
+ dbgs() << "reg#" << MCInstInfo.implicit_uses()[I] << " ";
+ }
+ dbgs() << "}\n";
+ }
+ dbgs() << "----------------Move Info----------------\n";
+ { // move
+ { // Reg2Reg
+ MCPhysReg From, To;
+ if (MCPB->isRegToRegMove(Inst, From, To)) {
+ dbgs() << "It's a reg to reg move.\nFrom reg#" << From << " to reg#"
+ << To << "\n";
+ } else if (MCInstInfo.isMoveReg()) {
+ dbgs() << "It's reg to reg move from MCInstInfo view but not from "
+ "MCPlus view.\n";
+ }
+ }
+ if (MCPB->isConditionalMove(Inst)) {
+ dbgs() << "Its a conditional move.\n";
+ }
+ if (MCPB->isMoveMem2Reg(Inst)) {
+ dbgs() << "It's a move from memory to register\n";
+ assert(MCPB->getMemoryOperandNo(Inst) == 1);
+ }
+ }
+
+ dbgs() << "---------------Stack Info----------------\n";
+ { // stack
+ int32_t SrcImm = 0;
+ MCPhysReg Reg = 0;
+ uint16_t StackPtrReg = 0;
+ int64_t StackOffset = 0;
+ uint8_t Size = 0;
+ bool IsSimple = false;
+ bool IsIndexed = false;
+ bool IsLoad = false;
+ bool IsStore = false;
+ bool IsStoreFromReg = false;
+ if (MCPB->isStackAccess(Inst, IsLoad, IsStore, IsStoreFromReg, Reg,
+ SrcImm, StackPtrReg, StackOffset, Size, IsSimple,
+ IsIndexed)) {
+ dbgs() << "This instruction accesses the stack, the details are:\n";
+ dbgs() << " Source immediate: " << SrcImm << "\n";
+ dbgs() << " Source reg#" << Reg << "\n";
+ dbgs() << " Stack pointer: reg#" << StackPtrReg << "\n";
+ dbgs() << " Stack offset: " << StackOffset << "\n";
+ dbgs() << " size: " << (int)Size << "\n";
+ dbgs() << " Is simple: " << (IsSimple ? "yes" : "no") << "\n";
+ dbgs() << " Is indexed: " << (IsIndexed ? "yes" : "no") << "\n";
+ dbgs() << " Is load: " << (IsLoad ? "yes" : "no") << "\n";
+ dbgs() << " Is store: " << (IsStore ? "yes" : "no") << "\n";
+ dbgs() << " Is store from reg: " << (IsStoreFromReg ? "yes" : "no")
+ << "\n";
+ }
+ if (MCPB->isPush(Inst)) {
+ dbgs() << "This is a push instruction with size "
+ << MCPB->getPushSize(Inst) << "\n";
+ }
+ if (MCPB->isPop(Inst)) {
+ dbgs() << "This is a pop instruction with size "
+ << MCPB->getPopSize(Inst) << "\n";
+ }
+ }
+
+ dbgs() << "---------------Arith Info----------------\n";
+ { // arith
+ MutableArrayRef<MCInst> MAR = {Inst};
+ if (MCPB->matchAdd(MCPB->matchAnyOperand(), MCPB->matchAnyOperand())
+ ->match(*RI, *MCPB, MutableArrayRef<MCInst>(), -1)) {
+ dbgs() << "It is an addition instruction.\n";
+ } else if (MCInstInfo.isAdd()) {
+ dbgs() << "It is an addition from MCInstInfo view but not from MCPlus "
+ "view.\n";
+ }
+ if (MCPB->isSUB(Inst)) {
+ dbgs() << "This is a subtraction.\n";
+ }
}
- dbgs() << "}\n";
- dbgs() << "-----------------------------------------\n";
- dbgs() << "isMoveMem2Reg: " << MCPB->isMoveMem2Reg(Inst) << "\n";
- dbgs() << "-----------------------------------------\n";
- dbgs() << "The CFA register is: " << CFAReg << "\n";
- dbgs() << "The instruction does " << (ChangedCFA ? "" : "NOT ")
- << "change the CFA.\n";
- dbgs() << "The CFI directives does " << (GoingToChangeCFA ? "" : "NOT ")
- << "change the CFA.\n";
+
+ // dbgs() << "-----------------------------------------\n";
+ // dbgs() << "The CFA register is: " << CFAReg << "\n";
+ // dbgs() << "The instruction does " << (ChangedCFA ? "" : "NOT ")
+ // << "change the CFA.\n";
+ // dbgs() << "The CFI directives does " << (GoingToChangeCFA ? "" : "NOT ")
+ // << "change the CFA.\n";
dbgs() << "vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n";
ChangedCFA = false;
}
>From a3d08d897bff5c75441eb1bbc00b1192c22d6fe4 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Tue, 13 May 2025 22:50:03 +0000
Subject: [PATCH 06/58] Typo in evaluateStackOffsetExpr doc
---
bolt/include/bolt/Core/MCPlusBuilder.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/bolt/include/bolt/Core/MCPlusBuilder.h b/bolt/include/bolt/Core/MCPlusBuilder.h
index 804100db80793..c168f06762c0d 100644
--- a/bolt/include/bolt/Core/MCPlusBuilder.h
+++ b/bolt/include/bolt/Core/MCPlusBuilder.h
@@ -1164,7 +1164,7 @@ class MCPlusBuilder {
return false;
}
- /// Use \p Input1 or Input2 as the current value for the input
+ /// Use \p Input1 or \p Input2 as the current value for the input
/// register and put in \p Output the changes incurred by executing
/// \p Inst. Return false if it was not possible to perform the
/// evaluation. evaluateStackOffsetExpr is restricted to operations
>From 7a109231849989de93e846735adaec58be6a04ec Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Tue, 13 May 2025 22:50:40 +0000
Subject: [PATCH 07/58] Add a DS to keep track of each register CFI state
---
llvm/tools/llvm-mc/CFIState.h | 160 ++++++++++++++++++++++++++++++++++
1 file changed, 160 insertions(+)
create mode 100644 llvm/tools/llvm-mc/CFIState.h
diff --git a/llvm/tools/llvm-mc/CFIState.h b/llvm/tools/llvm-mc/CFIState.h
new file mode 100644
index 0000000000000..b32de2b385316
--- /dev/null
+++ b/llvm/tools/llvm-mc/CFIState.h
@@ -0,0 +1,160 @@
+#ifndef LLVM_TOOLS_LLVM_MC_CFI_STATE_H
+#define LLVM_TOOLS_LLVM_MC_CFI_STATE_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/MC/MCDwarf.h"
+#include "llvm/MC/MCRegister.h"
+#include "llvm/Support/MathExtras.h"
+#include <cstdint>
+namespace llvm {
+
+using DWARFRegType = int64_t;
+
+struct RegisterCFIState {
+ enum Approach {
+ Undefined,
+ SameValue,
+ AnotherRegister,
+ OffsetFromCFAAddr,
+ OffsetFromCFAVal,
+ Other,
+ } RetrieveApproach;
+
+ // TODO use a correct type for this.
+ union {
+ int OffsetFromCFA;
+ DWARFRegType Register;
+ } Info;
+
+ static RegisterCFIState createUndefined() {
+ RegisterCFIState State;
+ State.RetrieveApproach = Undefined;
+
+ return State;
+ }
+
+ static RegisterCFIState createSameValue() {
+ RegisterCFIState State;
+ State.RetrieveApproach = SameValue;
+
+ return State;
+ }
+
+ static RegisterCFIState createAnotherRegister(DWARFRegType Register) {
+ RegisterCFIState State;
+ State.RetrieveApproach = AnotherRegister;
+ State.Info.Register = Register;
+
+ return State;
+ }
+
+ static RegisterCFIState createOffsetFromCFAAddr(int OffsetFromCFA) {
+ RegisterCFIState State;
+ State.RetrieveApproach = OffsetFromCFAAddr;
+ State.Info.OffsetFromCFA = OffsetFromCFA;
+
+ return State;
+ }
+
+ static RegisterCFIState createOffsetFromCFAVal(int OffsetFromCFA) {
+ RegisterCFIState State;
+ State.RetrieveApproach = OffsetFromCFAVal;
+ State.Info.OffsetFromCFA = OffsetFromCFA;
+
+ return State;
+ }
+
+ static RegisterCFIState createOther() {
+ RegisterCFIState State;
+ State.RetrieveApproach = Other;
+
+ return State;
+ }
+};
+struct CFIState {
+ DenseMap<DWARFRegType, RegisterCFIState> RegisterCFIStates;
+ DWARFRegType CFARegister;
+ int CFAOffset;
+
+ CFIState() : CFARegister(-1 /* Change to to max unsigned */), CFAOffset(-1) {}
+
+ CFIState(const CFIState &Other) {
+ CFARegister = Other.CFARegister;
+ CFAOffset = Other.CFAOffset;
+ RegisterCFIStates = Other.RegisterCFIStates;
+ }
+
+ CFIState &operator=(const CFIState &Other) {
+ if (this != &Other) {
+ CFARegister = Other.CFARegister;
+ CFAOffset = Other.CFAOffset;
+ RegisterCFIStates = Other.RegisterCFIStates;
+ }
+
+ return *this;
+ }
+
+ CFIState(DWARFRegType CFARegister, int CFIOffset)
+ : CFARegister(CFARegister), CFAOffset(CFIOffset) {}
+
+ bool apply(const MCCFIInstruction &CFIDirective) {
+ switch (CFIDirective.getOperation()) {
+ case MCCFIInstruction::OpDefCfaRegister:
+ CFARegister = CFIDirective.getRegister();
+ break;
+ case MCCFIInstruction::OpDefCfaOffset:
+ CFAOffset = CFIDirective.getOffset();
+ break;
+ case MCCFIInstruction::OpAdjustCfaOffset:
+ CFAOffset += CFIDirective.getOffset();
+ break;
+ case MCCFIInstruction::OpDefCfa:
+ CFARegister = CFIDirective.getRegister();
+ CFAOffset = CFIDirective.getOffset();
+ break;
+ case MCCFIInstruction::OpOffset:
+ RegisterCFIStates[CFIDirective.getRegister()] =
+ RegisterCFIState::createOffsetFromCFAAddr(CFIDirective.getOffset());
+ break;
+ case MCCFIInstruction::OpRegister:
+ RegisterCFIStates[CFIDirective.getRegister()] =
+ RegisterCFIState::createAnotherRegister(CFIDirective.getRegister2());
+ break;
+ case MCCFIInstruction::OpRelOffset:
+ RegisterCFIStates[CFIDirective.getRegister()] =
+ RegisterCFIState::createOffsetFromCFAAddr(CFIDirective.getOffset() -
+ CFAOffset);
+ break;
+ case MCCFIInstruction::OpUndefined:
+ RegisterCFIStates[CFIDirective.getRegister()] =
+ RegisterCFIState::createUndefined();
+ break;
+ case MCCFIInstruction::OpSameValue:
+ RegisterCFIStates[CFIDirective.getRegister()] =
+ RegisterCFIState::createSameValue();
+ break;
+ case MCCFIInstruction::OpValOffset:
+ RegisterCFIStates[CFIDirective.getRegister()] =
+ RegisterCFIState::createOffsetFromCFAVal(CFIDirective.getOffset());
+ break;
+ case MCCFIInstruction::OpRestoreState:
+ case MCCFIInstruction::OpRememberState:
+ case MCCFIInstruction::OpLLVMDefAspaceCfa:
+ case MCCFIInstruction::OpRestore:
+ case MCCFIInstruction::OpEscape:
+ case MCCFIInstruction::OpWindowSave:
+ case MCCFIInstruction::OpNegateRAState:
+ case MCCFIInstruction::OpNegateRAStateWithPC:
+ case MCCFIInstruction::OpGnuArgsSize:
+ case MCCFIInstruction::OpLabel:
+ // TODO it's not supported.
+ return false;
+ break;
+ }
+
+ return true;
+ }
+};
+} // namespace llvm
+
+#endif
\ No newline at end of file
>From 5841b8fae1dda3c13b8b87c58a7c7a404a8cb5e2 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Wed, 14 May 2025 18:19:55 +0000
Subject: [PATCH 08/58] Check if the CFA change is correct or not
---
llvm/tools/llvm-mc/CFIAnalysis.h | 457 ++++++++++++++-------
llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h | 36 +-
2 files changed, 326 insertions(+), 167 deletions(-)
diff --git a/llvm/tools/llvm-mc/CFIAnalysis.h b/llvm/tools/llvm-mc/CFIAnalysis.h
index 70b8a855643b9..424290f3cab86 100644
--- a/llvm/tools/llvm-mc/CFIAnalysis.h
+++ b/llvm/tools/llvm-mc/CFIAnalysis.h
@@ -1,10 +1,12 @@
#ifndef LLVM_TOOLS_LLVM_MC_CFI_ANALYSIS_H
#define LLVM_TOOLS_LLVM_MC_CFI_ANALYSIS_H
+#include "CFIState.h"
#include "bolt/Core/MCPlusBuilder.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/Twine.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDwarf.h"
#include "llvm/MC/MCExpr.h"
@@ -17,6 +19,8 @@
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Error.h"
+#include "llvm/Support/FormatVariadic.h"
+#include <cstdint>
#include <memory>
#include <optional>
#include <set>
@@ -51,51 +55,196 @@ class CFIAnalysis {
MCContext &Context;
MCInstrInfo const &MCII;
std::unique_ptr<bolt::MCPlusBuilder> MCPB;
+ MCRegisterInfo const *MCRI;
+ CFIState State;
public:
CFIAnalysis(MCContext &Context, MCInstrInfo const &MCII,
MCInstrAnalysis *MCIA)
- : Context(Context), MCII(MCII) {
- // TODO it should look at the poluge directives and setup the
+ : Context(Context), MCII(MCII), MCRI(Context.getRegisterInfo()) {
+ // TODO it should look at the prologue directives and setup the
// registers' previous value state here, but for now, it's assumed that all
// values are by default `samevalue`.
MCPB.reset(createMCPlusBuilder(Context.getTargetTriple().getArch(), MCIA,
&MCII, Context.getRegisterInfo(),
Context.getSubtargetInfo()));
+
+ // TODO CFA offset should be the slot size, but for now I don't have any
+ // access to it, maybe can be read from the prologue
+ // TODO check what should be passed as EH?
+ State = CFIState(MCRI->getDwarfRegNum(MCPB->getStackPointer(), false), 8);
+ for (unsigned I = 0; I < MCRI->getNumRegs(); I++) {
+ DWARFRegType DwarfI = MCRI->getDwarfRegNum(I, false);
+ State.RegisterCFIStates[DwarfI] = RegisterCFIState::createSameValue();
+ }
+
+ // TODO these are temporay added to make things work.
+ // Setup the basic information:
+ State.RegisterCFIStates[MCRI->getDwarfRegNum(MCRI->getProgramCounter(),
+ false)] =
+ RegisterCFIState::createUndefined(); // For now, we don't care about the
+ // PC
+ State.RegisterCFIStates[MCRI->getDwarfRegNum(MCPB->getStackPointer(),
+ false)] =
+ RegisterCFIState::createOffsetFromCFAVal(0); // sp's old value is CFA
+ }
+
+ bool doesConstantChange(const MCInst &Inst, MCPhysReg Reg, int64_t &HowMuch) {
+ if (MCPB->isPush(Inst) && Reg == MCPB->getStackPointer()) {
+ // TODO should get the stack direction here, now it assumes that it goes
+ // down.
+ HowMuch = -MCPB->getPushSize(Inst);
+ return true;
+ }
+
+ if (MCPB->isPop(Inst) && Reg == MCPB->getStackPointer()) {
+ // TODO should get the stack direction here, now it assumes that it goes
+ // down.
+ HowMuch = MCPB->getPushSize(Inst);
+ return true;
+ }
+
+ return false;
+ }
+
+ // Tries to guess Reg1's value in a form of Reg2 (before Inst's execution) +
+ // Diff.
+ bool isInConstantDistanceOfEachOther(const MCInst &Inst, MCPhysReg Reg1,
+ MCPhysReg Reg2, int &Diff) {
+ {
+ MCPhysReg From;
+ MCPhysReg To;
+ if (MCPB->isRegToRegMove(Inst, From, To) && From == Reg2 && To == Reg1) {
+ Diff = 0;
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ void checkCFADiff(const MCInst &Inst, const CFIState &PrevState,
+ const CFIState &NextState,
+ const std::set<DWARFRegType> &Reads,
+ const std::set<DWARFRegType> &Writes) {
+ if (PrevState.CFARegister == NextState.CFARegister) {
+ if (PrevState.CFAOffset == NextState.CFAOffset) {
+ if (Writes.count(PrevState.CFARegister)) {
+ Context.reportWarning(
+ Inst.getLoc(),
+ formatv("This instruction changes reg#{0}, which is "
+ "the CFA register, but the CFI directives do not.",
+ MCRI->getLLVMRegNum(PrevState.CFARegister, false)));
+ }
+ return;
+ }
+ // The offset is changed.
+ if (!Writes.count(PrevState.CFARegister)) {
+ Context.reportWarning(
+ Inst.getLoc(),
+ formatv(
+ "You changed the CFA offset, but there is no modification to "
+ "the CFA register happening in this instruction."));
+ }
+ int64_t HowMuch;
+ if (!doesConstantChange(
+ Inst, MCRI->getLLVMRegNum(PrevState.CFARegister, false).value(),
+ HowMuch)) {
+ Context.reportWarning(
+ Inst.getLoc(),
+ formatv("The CFA register changed, but I don't know how, finger "
+ "crossed the CFI directives are correct."));
+ return;
+ }
+ // we know it is changed by HowMuch, so the CFA offset should be changed
+ // by -HowMuch, i.e. AfterState.Offset - State.Offset = -HowMuch
+ if (NextState.CFAOffset - PrevState.CFAOffset != -HowMuch) {
+ Context.reportError(
+ Inst.getLoc(),
+ formatv("The CFA offset is changed by {0}, but "
+ "the directives changed it by {1}. (to be exact, the new "
+ "offset should be {2}, but it is {3})",
+ -HowMuch, NextState.CFAOffset - PrevState.CFAOffset,
+ PrevState.CFAOffset - HowMuch, NextState.CFAOffset));
+ return;
+ }
+
+ // Everything OK!
+ return;
+ }
+ // The CFA register is changed.
+ // TODO move it up
+ MCPhysReg OldCFAReg = MCRI->getLLVMRegNum(PrevState.CFARegister, false).value();
+ MCPhysReg NewCFAReg =
+ MCRI->getLLVMRegNum(NextState.CFARegister, false).value();
+ if (!Writes.count(NextState.CFARegister)) {
+ Context.reportWarning(
+ Inst.getLoc(),
+ formatv(
+ "The new CFA register reg#{0}'s value is not assigned by this "
+ "instruction, try to move the new CFA def to where this "
+ "value is changed, now I can't infer if this change is "
+ "correct or not.",
+ NewCFAReg));
+ return;
+ }
+ // Because CFA should is the CFA always stays the same:
+ int OffsetDiff = PrevState.CFAOffset - NextState.CFAOffset;
+ int Diff;
+ if (!isInConstantDistanceOfEachOther(Inst, NewCFAReg, OldCFAReg, Diff)) {
+ Context.reportWarning(
+ Inst.getLoc(),
+ formatv("Based on this instruction I cannot infer that the new and "
+ "old CFA registers are in {0} distance of each other. I "
+ "hope it's ok.",
+ OffsetDiff));
+ return;
+ }
+ if (Diff != OffsetDiff) {
+ Context.reportError(
+ Inst.getLoc(), formatv("After changing the CFA register, the CFA "
+ "offset should be {0}, but it is {1}.",
+ PrevState.CFAOffset - Diff, NextState.CFAOffset));
+ return;
+ }
+ // Everything is OK!
}
void update(const MCDwarfFrameInfo &DwarfFrame, MCInst &Inst,
- ArrayRef<MCCFIInstruction> CFIDirectives) {
+ std::pair<unsigned, unsigned>
+ CFIDirectivesRange) { // FIXME this should not be a pair,
+ // but an ArrayRef
+ ArrayRef<MCCFIInstruction> CFIDirectives(DwarfFrame.Instructions);
+ CFIDirectives = CFIDirectives.drop_front(CFIDirectivesRange.first)
+ .drop_back(DwarfFrame.Instructions.size() -
+ CFIDirectivesRange.second);
const MCInstrDesc &MCInstInfo = MCII.get(Inst.getOpcode());
- auto *RI = Context.getRegisterInfo();
- auto CFAReg = RI->getLLVMRegNum(DwarfFrame.CurrentCfaRegister, false);
+ CFIState AfterState(State);
+ for (auto &&CFIDirective : CFIDirectives)
+ if (!AfterState.apply(CFIDirective))
+ Context.reportWarning(
+ CFIDirective.getLoc(),
+ "I don't support this CFI directive, I assume this does nothing "
+ "(which will probably break other things)");
+ auto CFAReg = MCRI->getLLVMRegNum(DwarfFrame.CurrentCfaRegister, false);
+ assert(DwarfFrame.CurrentCfaRegister == AfterState.CFARegister &&
+ "Checking if the CFA tracking is working");
- std::set<int> Writes, Reads; // TODO reads is not ready for now
- // FIXME this way of extracting uses is buggy:
- // for (unsigned I = 0; I < MCInstInfo.NumImplicitUses; I++)
- // Reads.insert(MCInstInfo.implicit_uses()[I]);
+ std::set<DWARFRegType> Writes, Reads;
+ for (unsigned I = 0; I < MCInstInfo.NumImplicitUses; I++)
+ Reads.insert(MCRI->getDwarfRegNum(MCInstInfo.implicit_uses()[I], false));
for (unsigned I = 0; I < MCInstInfo.NumImplicitDefs; I++)
- Writes.insert(MCInstInfo.implicit_defs()[I]);
+ Writes.insert(MCRI->getDwarfRegNum(MCInstInfo.implicit_defs()[I], false));
for (unsigned I = 0; I < Inst.getNumOperands(); I++) {
auto &&Operand = Inst.getOperand(I);
if (Operand.isReg()) {
- // TODO it is not percise, maybe this operand is for output, then it
- // means that there is no read happening here.
- Reads.insert(Operand.getReg());
- }
-
- if (Operand.isExpr()) {
- // TODO maybe the argument is not a register, but is a expression like
- // `34(sp)` that has a register in it. Check if this works or not and if
- // no change it somehow that it count that register as reads or writes
- // too.
+ if (I < MCInstInfo.getNumDefs())
+ Writes.insert(MCRI->getDwarfRegNum(Operand.getReg(), false));
+ else
+ Reads.insert(MCRI->getDwarfRegNum(Operand.getReg(), false));
}
-
- if (Operand.isReg() &&
- MCInstInfo.hasDefOfPhysReg(Inst, Operand.getReg(), *RI))
- Writes.insert(Operand.getReg().id());
}
bool ChangedCFA = Writes.count(CFAReg->id());
@@ -114,132 +263,137 @@ class CFIAnalysis {
"CFI directives don't update the CFA.");
}
- dbgs() << "^^^^^^^^^^^^^^^^ InsCFIs ^^^^^^^^^^^^^^^^\n";
- printUntilNextLine(Inst.getLoc().getPointer());
- dbgs() << "\n";
- dbgs() << "Op code: " << Inst.getOpcode() << "\n";
- dbgs() << "--------------Operands Info--------------\n";
- auto DefCount = MCInstInfo.getNumDefs();
- for (unsigned I = 0; I < Inst.getNumOperands(); I++) {
- dbgs() << "Operand #" << I << ", which will be "
- << (I < DefCount ? "defined" : "used") << ", is a";
- if (I == MCPB->getMemoryOperandNo(Inst)) {
- dbgs() << " memory access, details are:\n";
- auto X86MemoryOperand = MCPB->evaluateX86MemoryOperand(Inst);
- dbgs() << " Base Register{ reg#" << X86MemoryOperand->BaseRegNum
- << " }";
- dbgs() << " + (Index Register{ reg#" << X86MemoryOperand->IndexRegNum
- << " }";
- dbgs() << " * Scale{ value " << X86MemoryOperand->ScaleImm << " }";
- dbgs() << ") + Displacement{ "
- << (X86MemoryOperand->DispExpr
- ? "an expression"
- : "value " + itostr(X86MemoryOperand->DispImm))
- << " }\n";
- // TODO, it's not correct always, it cannot be assumed (or should be
- // checked) that memory operands are flatten into 4 operands in MCInc.
- I += 4;
- continue;
- }
- auto &&Operand = Inst.getOperand(I);
- if (Operand.isImm()) {
- dbgs() << "n immediate with value " << Operand.getImm() << "\n";
- continue;
- }
- if (Operand.isReg()) {
- dbgs() << " reg#" << Operand.getReg() << "\n";
- continue;
- }
- assert(Operand.isExpr());
- dbgs() << "n unknown expression \n";
- }
- if (MCInstInfo.NumImplicitDefs) {
- dbgs() << "implicitly defines: { ";
- for (unsigned I = 0; I < MCInstInfo.NumImplicitDefs; I++) {
- dbgs() << "reg#" << MCInstInfo.implicit_defs()[I] << " ";
- }
- dbgs() << "}\n";
- }
- if (MCInstInfo.NumImplicitUses) {
- dbgs() << "implicitly uses: { ";
- for (unsigned I = 0; I < MCInstInfo.NumImplicitUses; I++) {
- dbgs() << "reg#" << MCInstInfo.implicit_uses()[I] << " ";
- }
- dbgs() << "}\n";
- }
- dbgs() << "----------------Move Info----------------\n";
- { // move
- { // Reg2Reg
- MCPhysReg From, To;
- if (MCPB->isRegToRegMove(Inst, From, To)) {
- dbgs() << "It's a reg to reg move.\nFrom reg#" << From << " to reg#"
- << To << "\n";
- } else if (MCInstInfo.isMoveReg()) {
- dbgs() << "It's reg to reg move from MCInstInfo view but not from "
- "MCPlus view.\n";
- }
- }
- if (MCPB->isConditionalMove(Inst)) {
- dbgs() << "Its a conditional move.\n";
- }
- if (MCPB->isMoveMem2Reg(Inst)) {
- dbgs() << "It's a move from memory to register\n";
- assert(MCPB->getMemoryOperandNo(Inst) == 1);
- }
- }
+ ///////////// being diffing the CFI states
+ checkCFADiff(Inst, State, AfterState, Reads, Writes);
+ ///////////// end diffing the CFI states
- dbgs() << "---------------Stack Info----------------\n";
- { // stack
- int32_t SrcImm = 0;
- MCPhysReg Reg = 0;
- uint16_t StackPtrReg = 0;
- int64_t StackOffset = 0;
- uint8_t Size = 0;
- bool IsSimple = false;
- bool IsIndexed = false;
- bool IsLoad = false;
- bool IsStore = false;
- bool IsStoreFromReg = false;
- if (MCPB->isStackAccess(Inst, IsLoad, IsStore, IsStoreFromReg, Reg,
- SrcImm, StackPtrReg, StackOffset, Size, IsSimple,
- IsIndexed)) {
- dbgs() << "This instruction accesses the stack, the details are:\n";
- dbgs() << " Source immediate: " << SrcImm << "\n";
- dbgs() << " Source reg#" << Reg << "\n";
- dbgs() << " Stack pointer: reg#" << StackPtrReg << "\n";
- dbgs() << " Stack offset: " << StackOffset << "\n";
- dbgs() << " size: " << (int)Size << "\n";
- dbgs() << " Is simple: " << (IsSimple ? "yes" : "no") << "\n";
- dbgs() << " Is indexed: " << (IsIndexed ? "yes" : "no") << "\n";
- dbgs() << " Is load: " << (IsLoad ? "yes" : "no") << "\n";
- dbgs() << " Is store: " << (IsStore ? "yes" : "no") << "\n";
- dbgs() << " Is store from reg: " << (IsStoreFromReg ? "yes" : "no")
- << "\n";
- }
- if (MCPB->isPush(Inst)) {
- dbgs() << "This is a push instruction with size "
- << MCPB->getPushSize(Inst) << "\n";
- }
- if (MCPB->isPop(Inst)) {
- dbgs() << "This is a pop instruction with size "
- << MCPB->getPopSize(Inst) << "\n";
- }
- }
+ // dbgs() << "^^^^^^^^^^^^^^^^ InsCFIs ^^^^^^^^^^^^^^^^\n";
+ // printUntilNextLine(Inst.getLoc().getPointer());
+ // dbgs() << "\n";
+ // dbgs() << "Op code: " << Inst.getOpcode() << "\n";
+ // dbgs() << "--------------Operands Info--------------\n";
+ // auto DefCount = MCInstInfo.getNumDefs();
+ // for (unsigned I = 0; I < Inst.getNumOperands(); I++) {
+ // dbgs() << "Operand #" << I << ", which will be "
+ // << (I < DefCount ? "defined" : "used") << ", is a";
+ // if (I == MCPB->getMemoryOperandNo(Inst)) {
+ // dbgs() << " memory access, details are:\n";
+ // auto X86MemoryOperand = MCPB->evaluateX86MemoryOperand(Inst);
+ // dbgs() << " Base Register{ reg#" << X86MemoryOperand->BaseRegNum
+ // << " }";
+ // dbgs() << " + (Index Register{ reg#" << X86MemoryOperand->IndexRegNum
+ // << " }";
+ // dbgs() << " * Scale{ value " << X86MemoryOperand->ScaleImm << " }";
+ // dbgs() << ") + Displacement{ "
+ // << (X86MemoryOperand->DispExpr
+ // ? "an expression"
+ // : "value " + itostr(X86MemoryOperand->DispImm))
+ // << " }\n";
+ // // TODO, it's not correct always, it cannot be assumed (or should be
+ // // checked) that memory operands are flatten into 4 operands in
+ // MCInc. I += 4; continue;
+ // }
+ // auto &&Operand = Inst.getOperand(I);
+ // if (Operand.isImm()) {
+ // dbgs() << "n immediate with value " << Operand.getImm() << "\n";
+ // continue;
+ // }
+ // if (Operand.isReg()) {
+ // dbgs() << " reg#" << Operand.getReg() << "\n";
+ // continue;
+ // }
+ // assert(Operand.isExpr());
+ // dbgs() << "n unknown expression \n";
+ // }
+ // if (MCInstInfo.NumImplicitDefs) {
+ // dbgs() << "implicitly defines: { ";
+ // for (unsigned I = 0; I < MCInstInfo.NumImplicitDefs; I++) {
+ // dbgs() << "reg#" << MCInstInfo.implicit_defs()[I] << " ";
+ // }
+ // dbgs() << "}\n";
+ // }
+ // if (MCInstInfo.NumImplicitUses) {
+ // dbgs() << "implicitly uses: { ";
+ // for (unsigned I = 0; I < MCInstInfo.NumImplicitUses; I++) {
+ // dbgs() << "reg#" << MCInstInfo.implicit_uses()[I] << " ";
+ // }
+ // dbgs() << "}\n";
+ // }
+ // dbgs() << "----------------Move Info----------------\n";
+ // { // move
+ // { // Reg2Reg
+ // MCPhysReg From, To;
+ // if (MCPB->isRegToRegMove(Inst, From, To)) {
+ // dbgs() << "It's a reg to reg move.\nFrom reg#" << From << " to
+ // reg#"
+ // << To << "\n";
+ // } else if (MCInstInfo.isMoveReg()) {
+ // dbgs() << "It's reg to reg move from MCInstInfo view but not from "
+ // "MCPlus view.\n";
+ // }
+ // }
+ // if (MCPB->isConditionalMove(Inst)) {
+ // dbgs() << "Its a conditional move.\n";
+ // }
+ // if (MCPB->isMoveMem2Reg(Inst)) {
+ // dbgs() << "It's a move from memory to register\n";
+ // assert(MCPB->getMemoryOperandNo(Inst) == 1);
+ // }
+ // }
- dbgs() << "---------------Arith Info----------------\n";
- { // arith
- MutableArrayRef<MCInst> MAR = {Inst};
- if (MCPB->matchAdd(MCPB->matchAnyOperand(), MCPB->matchAnyOperand())
- ->match(*RI, *MCPB, MutableArrayRef<MCInst>(), -1)) {
- dbgs() << "It is an addition instruction.\n";
- } else if (MCInstInfo.isAdd()) {
- dbgs() << "It is an addition from MCInstInfo view but not from MCPlus "
- "view.\n";
- }
- if (MCPB->isSUB(Inst)) {
- dbgs() << "This is a subtraction.\n";
- }
- }
+ // dbgs() << "---------------Stack Info----------------\n";
+ // { // stack
+ // int32_t SrcImm = 0;
+ // MCPhysReg Reg = 0;
+ // uint16_t StackPtrReg = 0;
+ // int64_t StackOffset = 0;
+ // uint8_t Size = 0;
+ // bool IsSimple = false;
+ // bool IsIndexed = false;
+ // bool IsLoad = false;
+ // bool IsStore = false;
+ // bool IsStoreFromReg = false;
+ // if (MCPB->isStackAccess(Inst, IsLoad, IsStore, IsStoreFromReg, Reg,
+ // SrcImm, StackPtrReg, StackOffset, Size,
+ // IsSimple, IsIndexed)) {
+ // dbgs() << "This instruction accesses the stack, the details are:\n";
+ // dbgs() << " Source immediate: " << SrcImm << "\n";
+ // dbgs() << " Source reg#" << Reg << "\n";
+ // dbgs() << " Stack pointer: reg#" << StackPtrReg << "\n";
+ // dbgs() << " Stack offset: " << StackOffset << "\n";
+ // dbgs() << " size: " << (int)Size << "\n";
+ // dbgs() << " Is simple: " << (IsSimple ? "yes" : "no") << "\n";
+ // dbgs() << " Is indexed: " << (IsIndexed ? "yes" : "no") << "\n";
+ // dbgs() << " Is load: " << (IsLoad ? "yes" : "no") << "\n";
+ // dbgs() << " Is store: " << (IsStore ? "yes" : "no") << "\n";
+ // dbgs() << " Is store from reg: " << (IsStoreFromReg ? "yes" : "no")
+ // << "\n";
+ // }
+ // if (MCPB->isPush(Inst)) {
+ // dbgs() << "This is a push instruction with size "
+ // << MCPB->getPushSize(Inst) << "\n";
+ // }
+ // if (MCPB->isPop(Inst)) {
+ // dbgs() << "This is a pop instruction with size "
+ // << MCPB->getPopSize(Inst) << "\n";
+ // }
+ // }
+
+ // dbgs() << "---------------Arith Info----------------\n";
+ // { // arith
+ // MutableArrayRef<MCInst> MAR = {Inst};
+ // if (MCPB->matchAdd(MCPB->matchAnyOperand(), MCPB->matchAnyOperand())
+ // ->match(*MCRI, *MCPB, MutableArrayRef<MCInst>(), -1)) {
+ // dbgs() << "It is an addition instruction.\n";
+ // } else if (MCInstInfo.isAdd()) {
+ // dbgs() << "It is an addition from MCInstInfo view but not from MCPlus
+ // "
+ // "view.\n";
+ // }
+ // if (MCPB->isSUB(Inst)) {
+ // dbgs() << "This is a subtraction.\n";
+ // }
+ // }
// dbgs() << "-----------------------------------------\n";
// dbgs() << "The CFA register is: " << CFAReg << "\n";
@@ -247,9 +401,12 @@ class CFIAnalysis {
// << "change the CFA.\n";
// dbgs() << "The CFI directives does " << (GoingToChangeCFA ? "" : "NOT ")
// << "change the CFA.\n";
- dbgs() << "vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n";
- ChangedCFA = false;
+ // dbgs() << "vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n";
+
+ State = AfterState;
}
+
+private:
};
} // namespace llvm
diff --git a/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h b/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h
index 382a80aca94b4..48f530e6a9811 100644
--- a/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h
+++ b/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h
@@ -33,14 +33,14 @@ class CFIAnalysisMCStreamer : public MCStreamer {
struct ICFI {
MCInst Instruction;
- ArrayRef<MCCFIInstruction> CFIDirectives;
+ std::pair<unsigned, unsigned> CFIDirectivesRange;
- ICFI(MCInst Instruction, ArrayRef<MCCFIInstruction> CFIDirectives)
- : Instruction(Instruction), CFIDirectives(CFIDirectives) {}
+ ICFI(MCInst Instruction, std::pair<unsigned, unsigned> CFIDirectives)
+ : Instruction(Instruction), CFIDirectivesRange(CFIDirectives) {}
};
std::optional<MCInst> LastInstruction;
- std::optional<MCDwarfFrameInfo> LastDwarfFrameInfo;
+ MCDwarfFrameInfo const *LastDwarfFrameInfo;
std::optional<ICFI> getLastICFI() {
if (!LastInstruction)
@@ -58,16 +58,14 @@ class CFIAnalysisMCStreamer : public MCStreamer {
assert(CurrentCFIDirectiveState.DirectiveIndex >=
LastCFIDirectivesState.DirectiveIndex);
- std::vector<MCCFIInstruction> CFIDirectives;
+ std::pair<unsigned, unsigned> CFIDirectivesRange;
if (LastCFIDirectivesState.FrameIndex >= 0) {
- auto CFIInstructions = DwarfFrameInfos[FrameIndex].Instructions;
- CFIDirectives = std::vector<MCCFIInstruction>(
- CFIInstructions.begin() + LastCFIDirectivesState.DirectiveIndex,
- CFIInstructions.begin() + CurrentCFIDirectiveState.DirectiveIndex);
+ CFIDirectivesRange = {LastCFIDirectivesState.DirectiveIndex,
+ CurrentCFIDirectiveState.DirectiveIndex};
}
LastCFIDirectivesState = CurrentCFIDirectiveState;
- return ICFI(LastInstruction.value(), CFIDirectives);
+ return ICFI(LastInstruction.value(), CFIDirectivesRange);
}
void feedCFIA() {
@@ -77,14 +75,15 @@ class CFIAnalysisMCStreamer : public MCStreamer {
// adding cfi directives for a instruction. Then this would cause to
// ignore the instruction.
auto LastICFI = getLastICFI();
- assert(!LastICFI || LastICFI->CFIDirectives.empty());
+ assert(!LastICFI || LastICFI->CFIDirectivesRange.first ==
+ LastICFI->CFIDirectivesRange.second);
return;
}
if (auto ICFI = getLastICFI()) {
assert(!CFIAs.empty());
- CFIAs.back().update(LastDwarfFrameInfo.value(), ICFI->Instruction,
- ICFI->CFIDirectives);
+ CFIAs.back().update(*LastDwarfFrameInfo, ICFI->Instruction,
+ ICFI->CFIDirectivesRange);
}
}
@@ -121,9 +120,12 @@ class CFIAnalysisMCStreamer : public MCStreamer {
feedCFIA();
LastInstruction = Inst;
if (hasUnfinishedDwarfFrameInfo())
- LastDwarfFrameInfo = getDwarfFrameInfos()[FrameIndices.back()];
+ LastDwarfFrameInfo =
+ &getDwarfFrameInfos()
+ [FrameIndices.back()]; // FIXME get this from emit yourself,
+ // instead of getting it in this way
else
- LastDwarfFrameInfo = std::nullopt;
+ LastDwarfFrameInfo = nullptr;
}
void emitCFIStartProcImpl(MCDwarfFrameInfo &Frame) override {
@@ -131,7 +133,7 @@ class CFIAnalysisMCStreamer : public MCStreamer {
FrameIndices.push_back(getNumFrameInfos());
CFIAs.emplace_back(getContext(), MCII, MCIA.get());
LastInstruction = std::nullopt;
- LastDwarfFrameInfo = std::nullopt;
+ LastDwarfFrameInfo = nullptr;
LastCFIDirectivesState.FrameIndex = FrameIndices.back();
LastCFIDirectivesState.DirectiveIndex = 0;
MCStreamer::emitCFIStartProcImpl(Frame);
@@ -143,7 +145,7 @@ class CFIAnalysisMCStreamer : public MCStreamer {
FrameIndices.pop_back();
CFIAs.pop_back();
LastInstruction = std::nullopt;
- LastDwarfFrameInfo = std::nullopt;
+ LastDwarfFrameInfo = nullptr;
LastCFIDirectivesState.FrameIndex = FrameIndices.back();
LastCFIDirectivesState.DirectiveIndex =
LastCFIDirectivesState.FrameIndex >= 0
>From 69a8e9da756c60ba18bfacfcfc7a55ccb59d9122 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Wed, 14 May 2025 22:45:23 +0000
Subject: [PATCH 09/58] Add the CFI validation as a option to llvm-mc tool
---
llvm/tools/llvm-mc/llvm-mc.cpp | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
diff --git a/llvm/tools/llvm-mc/llvm-mc.cpp b/llvm/tools/llvm-mc/llvm-mc.cpp
index 32f2fa0f05a7c..ca4f71cb9cabd 100644
--- a/llvm/tools/llvm-mc/llvm-mc.cpp
+++ b/llvm/tools/llvm-mc/llvm-mc.cpp
@@ -215,6 +215,10 @@ static cl::opt<bool> NoExecStack("no-exec-stack",
cl::desc("File doesn't need an exec stack"),
cl::cat(MCCategory));
+static cl::opt<bool> ValidateCFI("validate-cfi",
+ cl::desc("Validate the CFI directives"),
+ cl::cat(MCCategory));
+
enum ActionType {
AC_AsLex,
AC_Assemble,
@@ -525,7 +529,12 @@ int main(int argc, char **argv) {
assert(MCIA && "Unable to create instruction analysis!");
std::unique_ptr<MCInstPrinter> IP;
- if (FileType == OFT_AssemblyFile) {
+ if (ValidateCFI) {
+ assert(FileType == OFT_Null);
+ auto *CFIAMCS = new CFIAnalysisMCStreamer(Ctx, *MCII, std::move(MCIA));
+ TheTarget->createNullTargetStreamer(*CFIAMCS);
+ Str.reset(CFIAMCS);
+ } else if (FileType == OFT_AssemblyFile) {
IP.reset(TheTarget->createMCInstPrinter(
Triple(TripleName), OutputAsmVariant, *MAI, *MCII, *MRI));
@@ -569,11 +578,7 @@ int main(int argc, char **argv) {
std::move(CE), std::move(MAB)));
} else if (FileType == OFT_Null) {
- auto *MyDummyStreamer =
- new CFIAnalysisMCStreamer(Ctx, *MCII, std::move(MCIA));
- TheTarget->createNullTargetStreamer(*MyDummyStreamer);
- Str.reset(MyDummyStreamer);
- // Str.reset(TheTarget->createNullStreamer(Ctx));
+ Str.reset(TheTarget->createNullStreamer(Ctx));
} else {
assert(FileType == OFT_ObjectFile && "Invalid file type!");
>From 43b54fd0d237c71dc15a2645319d627cf3ed1db9 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Wed, 14 May 2025 23:15:26 +0000
Subject: [PATCH 10/58] Provide the directives as an arrayref instead of index
range
---
llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h | 42 +++++++++-------------
1 file changed, 17 insertions(+), 25 deletions(-)
diff --git a/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h b/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h
index 48f530e6a9811..a9354d7af8a2f 100644
--- a/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h
+++ b/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h
@@ -3,7 +3,6 @@
#include "CFIAnalysis.h"
#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/SmallVector.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDwarf.h"
#include "llvm/MC/MCInstrAnalysis.h"
@@ -20,13 +19,12 @@ class CFIAnalysisMCStreamer : public MCStreamer {
std::unique_ptr<MCInstrAnalysis> MCIA;
struct CFIDirectivesState {
- int FrameIndex; // TODO remove it, no need for it
int DirectiveIndex;
- CFIDirectivesState() : FrameIndex(-1), DirectiveIndex(0) {}
+ CFIDirectivesState() : DirectiveIndex(0) {}
CFIDirectivesState(int FrameIndex, int InstructionIndex)
- : FrameIndex(FrameIndex), DirectiveIndex(InstructionIndex) {}
+ : DirectiveIndex(InstructionIndex) {}
} LastCFIDirectivesState;
std::vector<int> FrameIndices;
std::vector<CFIAnalysis> CFIAs;
@@ -53,16 +51,12 @@ class CFIAnalysisMCStreamer : public MCStreamer {
? CFIDirectivesState(
FrameIndex, DwarfFrameInfos[FrameIndex].Instructions.size())
: CFIDirectivesState();
- assert(CurrentCFIDirectiveState.FrameIndex ==
- LastCFIDirectivesState.FrameIndex);
assert(CurrentCFIDirectiveState.DirectiveIndex >=
LastCFIDirectivesState.DirectiveIndex);
- std::pair<unsigned, unsigned> CFIDirectivesRange;
- if (LastCFIDirectivesState.FrameIndex >= 0) {
- CFIDirectivesRange = {LastCFIDirectivesState.DirectiveIndex,
- CurrentCFIDirectiveState.DirectiveIndex};
- }
+ std::pair<unsigned, unsigned> CFIDirectivesRange(
+ LastCFIDirectivesState.DirectiveIndex,
+ CurrentCFIDirectiveState.DirectiveIndex);
LastCFIDirectivesState = CurrentCFIDirectiveState;
return ICFI(LastInstruction.value(), CFIDirectivesRange);
@@ -82,8 +76,12 @@ class CFIAnalysisMCStreamer : public MCStreamer {
if (auto ICFI = getLastICFI()) {
assert(!CFIAs.empty());
- CFIAs.back().update(*LastDwarfFrameInfo, ICFI->Instruction,
- ICFI->CFIDirectivesRange);
+ ArrayRef<MCCFIInstruction> CFIDirectives(
+ LastDwarfFrameInfo->Instructions);
+ CFIDirectives = CFIDirectives.drop_front(ICFI->CFIDirectivesRange.first)
+ .drop_back(LastDwarfFrameInfo->Instructions.size() -
+ ICFI->CFIDirectivesRange.second);
+ CFIAs.back().update(ICFI->Instruction, CFIDirectives);
}
}
@@ -95,9 +93,6 @@ class CFIAnalysisMCStreamer : public MCStreamer {
FrameIndices.push_back(-1);
}
- /// @name MCStreamer Interface
- /// @{
-
bool hasRawTextSupport() const override { return true; }
void emitRawTextImpl(StringRef String) override {}
@@ -121,9 +116,9 @@ class CFIAnalysisMCStreamer : public MCStreamer {
LastInstruction = Inst;
if (hasUnfinishedDwarfFrameInfo())
LastDwarfFrameInfo =
- &getDwarfFrameInfos()
- [FrameIndices.back()]; // FIXME get this from emit yourself,
- // instead of getting it in this way
+ &getDwarfFrameInfos()[FrameIndices.back()]; // TODO get this from emit
+ // yourself, instead of
+ // getting it in this way
else
LastDwarfFrameInfo = nullptr;
}
@@ -134,7 +129,6 @@ class CFIAnalysisMCStreamer : public MCStreamer {
CFIAs.emplace_back(getContext(), MCII, MCIA.get());
LastInstruction = std::nullopt;
LastDwarfFrameInfo = nullptr;
- LastCFIDirectivesState.FrameIndex = FrameIndices.back();
LastCFIDirectivesState.DirectiveIndex = 0;
MCStreamer::emitCFIStartProcImpl(Frame);
}
@@ -146,12 +140,10 @@ class CFIAnalysisMCStreamer : public MCStreamer {
CFIAs.pop_back();
LastInstruction = std::nullopt;
LastDwarfFrameInfo = nullptr;
- LastCFIDirectivesState.FrameIndex = FrameIndices.back();
+ auto FrameIndex = FrameIndices.back();
LastCFIDirectivesState.DirectiveIndex =
- LastCFIDirectivesState.FrameIndex >= 0
- ? getDwarfFrameInfos()[LastCFIDirectivesState.FrameIndex]
- .Instructions.size()
- : 0;
+ FrameIndex >= 0 ? getDwarfFrameInfos()[FrameIndex].Instructions.size()
+ : 0;
MCStreamer::emitCFIEndProcImpl(CurFrame);
}
};
>From 474ff1c1ea503ca56c916223fdb1f281e6382eaa Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Wed, 14 May 2025 23:47:48 +0000
Subject: [PATCH 11/58] Remove TODOs
---
llvm/tools/llvm-mc/CFIState.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/tools/llvm-mc/CFIState.h b/llvm/tools/llvm-mc/CFIState.h
index b32de2b385316..5551e9778f1d2 100644
--- a/llvm/tools/llvm-mc/CFIState.h
+++ b/llvm/tools/llvm-mc/CFIState.h
@@ -76,7 +76,7 @@ struct CFIState {
DWARFRegType CFARegister;
int CFAOffset;
- CFIState() : CFARegister(-1 /* Change to to max unsigned */), CFAOffset(-1) {}
+ CFIState() : CFARegister(-1), CFAOffset(-1) {}
CFIState(const CFIState &Other) {
CFARegister = Other.CFARegister;
@@ -147,7 +147,7 @@ struct CFIState {
case MCCFIInstruction::OpNegateRAStateWithPC:
case MCCFIInstruction::OpGnuArgsSize:
case MCCFIInstruction::OpLabel:
- // TODO it's not supported.
+ // These instructions are not supported.
return false;
break;
}
>From 8ea5d9c10ca5d1c42d718a9ff63d7edad2f667ee Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Wed, 14 May 2025 23:48:11 +0000
Subject: [PATCH 12/58] Wrap all the MCPB info needed into a
ExtendedMCInstrAnalysis class
---
llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h | 85 ++++++++++++++++++++
1 file changed, 85 insertions(+)
create mode 100644 llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h
diff --git a/llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h b/llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h
new file mode 100644
index 0000000000000..5323c4e3d1730
--- /dev/null
+++ b/llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h
@@ -0,0 +1,85 @@
+#ifndef LLVM_TOOLS_LLVM_MC_EXTENDED_MC_INSTR_ANALYSIS_H
+#define LLVM_TOOLS_LLVM_MC_EXTENDED_MC_INSTR_ANALYSIS_H
+
+#include "bolt/Core/MCPlusBuilder.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDwarf.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCRegister.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/TargetRegistry.h"
+#include <cstdint>
+#include <memory>
+#include <optional>
+
+namespace llvm {
+
+class ExtendedMCInstrAnalysis {
+private:
+ std::unique_ptr<bolt::MCPlusBuilder> MCPB;
+
+ static bolt::MCPlusBuilder *
+ createMCPlusBuilder(const Triple::ArchType Arch,
+ const MCInstrAnalysis *Analysis, const MCInstrInfo *Info,
+ const MCRegisterInfo *RegInfo,
+ const MCSubtargetInfo *STI) {
+ if (Arch == Triple::x86_64)
+ return bolt::createX86MCPlusBuilder(Analysis, Info, RegInfo, STI);
+
+ llvm_unreachable("architecture unsupported by ExtendedMCInstrAnalysis");
+ }
+
+public:
+ ExtendedMCInstrAnalysis(MCContext &Context, MCInstrInfo const &MCII,
+ MCInstrAnalysis *MCIA) {
+ MCPB.reset(createMCPlusBuilder(Context.getTargetTriple().getArch(), MCIA,
+ &MCII, Context.getRegisterInfo(),
+ Context.getSubtargetInfo()));
+ }
+
+ /// Extra semantic information needed from MC layer:
+
+ MCPhysReg getStackPointer() const { return MCPB->getStackPointer(); }
+
+ bool isPush(const MCInst &Inst) const { return MCPB->isPush(Inst); }
+ int getPushSize(const MCInst &Inst) const { return MCPB->getPushSize(Inst); }
+
+ bool isPop(const MCInst &Inst) const { return MCPB->isPop(Inst); }
+ int getPopSize(const MCInst &Inst) const { return MCPB->getPopSize(Inst); }
+
+ bool isRegToRegMove(const MCInst &Inst, MCPhysReg &From,
+ MCPhysReg &To) const {
+ return MCPB->isRegToRegMove(Inst, From, To);
+ }
+ bool isConditionalMove(const MCInst &Inst) const {
+ return MCPB->isConditionalMove(Inst);
+ }
+ bool isMoveMem2Reg(const MCInst &Inst) const {
+ return MCPB->isMoveMem2Reg(Inst);
+ }
+ bool isSUB(const MCInst &Inst) const { return MCPB->isSUB(Inst); }
+
+ int getMemoryOperandNo(const MCInst &Inst) const {
+ return MCPB->getMemoryOperandNo(Inst);
+ }
+ std::optional<bolt::MCPlusBuilder::X86MemOperand>
+ evaluateX86MemoryOperand(const MCInst &Inst) const {
+ return MCPB->evaluateX86MemoryOperand(Inst);
+ }
+ bool isStackAccess(const MCInst &Inst, bool &IsLoad, bool &IsStore,
+ bool &IsStoreFromReg, MCPhysReg &Reg, int32_t &SrcImm,
+ uint16_t &StackPtrReg, int64_t &StackOffset, uint8_t &Size,
+ bool &IsSimple, bool &IsIndexed) const {
+ return MCPB->isStackAccess(Inst, IsLoad, IsStore, IsStoreFromReg, Reg,
+ SrcImm, StackPtrReg, StackOffset, Size, IsSimple,
+ IsIndexed);
+ }
+};
+
+} // namespace llvm
+
+#endif
\ No newline at end of file
>From e92005c32a550b24df96ea4f5166bf656f73d493 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Wed, 14 May 2025 23:48:50 +0000
Subject: [PATCH 13/58] Use extended MCAnalysis instead of MCplus (directly)
---
llvm/tools/llvm-mc/CFIAnalysis.h | 123 ++++++++++---------------------
1 file changed, 39 insertions(+), 84 deletions(-)
diff --git a/llvm/tools/llvm-mc/CFIAnalysis.h b/llvm/tools/llvm-mc/CFIAnalysis.h
index 424290f3cab86..1a05dd6de5327 100644
--- a/llvm/tools/llvm-mc/CFIAnalysis.h
+++ b/llvm/tools/llvm-mc/CFIAnalysis.h
@@ -2,6 +2,7 @@
#define LLVM_TOOLS_LLVM_MC_CFI_ANALYSIS_H
#include "CFIState.h"
+#include "ExtendedMCInstrAnalysis.h"
#include "bolt/Core/MCPlusBuilder.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
@@ -18,7 +19,6 @@
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/Debug.h"
-#include "llvm/Support/Error.h"
#include "llvm/Support/FormatVariadic.h"
#include <cstdint>
#include <memory>
@@ -27,24 +27,6 @@
namespace llvm {
-bolt::MCPlusBuilder *createMCPlusBuilder(const Triple::ArchType Arch,
- const MCInstrAnalysis *Analysis,
- const MCInstrInfo *Info,
- const MCRegisterInfo *RegInfo,
- const MCSubtargetInfo *STI) {
- dbgs() << "arch: " << Arch << ", and expected " << Triple::x86_64 << "\n";
- if (Arch == Triple::x86_64)
- return bolt::createX86MCPlusBuilder(Analysis, Info, RegInfo, STI);
-
- // if (Arch == Triple::aarch64)
- // return createAArch64MCPlusBuilder(Analysis, Info, RegInfo, STI);
-
- // if (Arch == Triple::riscv64)
- // return createRISCVMCPlusBuilder(Analysis, Info, RegInfo, STI);
-
- llvm_unreachable("architecture unsupported by MCPlusBuilder");
-}
-
// TODO remove it, it's just for debug purposes.
void printUntilNextLine(const char *Str) {
for (int I = 0; Str[I] != '\0' && Str[I] != '\n'; I++)
@@ -54,8 +36,8 @@ void printUntilNextLine(const char *Str) {
class CFIAnalysis {
MCContext &Context;
MCInstrInfo const &MCII;
- std::unique_ptr<bolt::MCPlusBuilder> MCPB;
MCRegisterInfo const *MCRI;
+ std::unique_ptr<ExtendedMCInstrAnalysis> EMCIA;
CFIState State;
public:
@@ -65,14 +47,12 @@ class CFIAnalysis {
// TODO it should look at the prologue directives and setup the
// registers' previous value state here, but for now, it's assumed that all
// values are by default `samevalue`.
- MCPB.reset(createMCPlusBuilder(Context.getTargetTriple().getArch(), MCIA,
- &MCII, Context.getRegisterInfo(),
- Context.getSubtargetInfo()));
+ EMCIA.reset(new ExtendedMCInstrAnalysis(Context, MCII, MCIA));
// TODO CFA offset should be the slot size, but for now I don't have any
// access to it, maybe can be read from the prologue
// TODO check what should be passed as EH?
- State = CFIState(MCRI->getDwarfRegNum(MCPB->getStackPointer(), false), 8);
+ State = CFIState(MCRI->getDwarfRegNum(EMCIA->getStackPointer(), false), 8);
for (unsigned I = 0; I < MCRI->getNumRegs(); I++) {
DWARFRegType DwarfI = MCRI->getDwarfRegNum(I, false);
State.RegisterCFIStates[DwarfI] = RegisterCFIState::createSameValue();
@@ -84,23 +64,23 @@ class CFIAnalysis {
false)] =
RegisterCFIState::createUndefined(); // For now, we don't care about the
// PC
- State.RegisterCFIStates[MCRI->getDwarfRegNum(MCPB->getStackPointer(),
+ State.RegisterCFIStates[MCRI->getDwarfRegNum(EMCIA->getStackPointer(),
false)] =
RegisterCFIState::createOffsetFromCFAVal(0); // sp's old value is CFA
}
bool doesConstantChange(const MCInst &Inst, MCPhysReg Reg, int64_t &HowMuch) {
- if (MCPB->isPush(Inst) && Reg == MCPB->getStackPointer()) {
+ if (EMCIA->isPush(Inst) && Reg == EMCIA->getStackPointer()) {
// TODO should get the stack direction here, now it assumes that it goes
// down.
- HowMuch = -MCPB->getPushSize(Inst);
+ HowMuch = -EMCIA->getPushSize(Inst);
return true;
}
- if (MCPB->isPop(Inst) && Reg == MCPB->getStackPointer()) {
+ if (EMCIA->isPop(Inst) && Reg == EMCIA->getStackPointer()) {
// TODO should get the stack direction here, now it assumes that it goes
// down.
- HowMuch = MCPB->getPushSize(Inst);
+ HowMuch = EMCIA->getPushSize(Inst);
return true;
}
@@ -114,7 +94,7 @@ class CFIAnalysis {
{
MCPhysReg From;
MCPhysReg To;
- if (MCPB->isRegToRegMove(Inst, From, To) && From == Reg2 && To == Reg1) {
+ if (EMCIA->isRegToRegMove(Inst, From, To) && From == Reg2 && To == Reg1) {
Diff = 0;
return true;
}
@@ -174,7 +154,8 @@ class CFIAnalysis {
}
// The CFA register is changed.
// TODO move it up
- MCPhysReg OldCFAReg = MCRI->getLLVMRegNum(PrevState.CFARegister, false).value();
+ MCPhysReg OldCFAReg =
+ MCRI->getLLVMRegNum(PrevState.CFARegister, false).value();
MCPhysReg NewCFAReg =
MCRI->getLLVMRegNum(NextState.CFARegister, false).value();
if (!Writes.count(NextState.CFARegister)) {
@@ -201,24 +182,17 @@ class CFIAnalysis {
return;
}
if (Diff != OffsetDiff) {
- Context.reportError(
- Inst.getLoc(), formatv("After changing the CFA register, the CFA "
- "offset should be {0}, but it is {1}.",
- PrevState.CFAOffset - Diff, NextState.CFAOffset));
+ Context.reportError(Inst.getLoc(),
+ formatv("After changing the CFA register, the CFA "
+ "offset should be {0}, but it is {1}.",
+ PrevState.CFAOffset - Diff,
+ NextState.CFAOffset));
return;
}
// Everything is OK!
}
- void update(const MCDwarfFrameInfo &DwarfFrame, MCInst &Inst,
- std::pair<unsigned, unsigned>
- CFIDirectivesRange) { // FIXME this should not be a pair,
- // but an ArrayRef
- ArrayRef<MCCFIInstruction> CFIDirectives(DwarfFrame.Instructions);
- CFIDirectives = CFIDirectives.drop_front(CFIDirectivesRange.first)
- .drop_back(DwarfFrame.Instructions.size() -
- CFIDirectivesRange.second);
-
+ void update(MCInst &Inst, ArrayRef<MCCFIInstruction> CFIDirectives) {
const MCInstrDesc &MCInstInfo = MCII.get(Inst.getOpcode());
CFIState AfterState(State);
for (auto &&CFIDirective : CFIDirectives)
@@ -227,9 +201,6 @@ class CFIAnalysis {
CFIDirective.getLoc(),
"I don't support this CFI directive, I assume this does nothing "
"(which will probably break other things)");
- auto CFAReg = MCRI->getLLVMRegNum(DwarfFrame.CurrentCfaRegister, false);
- assert(DwarfFrame.CurrentCfaRegister == AfterState.CFARegister &&
- "Checking if the CFA tracking is working");
std::set<DWARFRegType> Writes, Reads;
for (unsigned I = 0; I < MCInstInfo.NumImplicitUses; I++)
@@ -246,23 +217,6 @@ class CFIAnalysis {
Reads.insert(MCRI->getDwarfRegNum(Operand.getReg(), false));
}
}
-
- bool ChangedCFA = Writes.count(CFAReg->id());
- bool GoingToChangeCFA = false;
- for (auto CFIDirective : CFIDirectives) {
- auto Op = CFIDirective.getOperation();
- GoingToChangeCFA |= (Op == MCCFIInstruction::OpDefCfa ||
- Op == MCCFIInstruction::OpDefCfaOffset ||
- Op == MCCFIInstruction::OpDefCfaRegister ||
- Op == MCCFIInstruction::OpAdjustCfaOffset ||
- Op == MCCFIInstruction::OpLLVMDefAspaceCfa);
- }
- if (ChangedCFA && !GoingToChangeCFA) {
- Context.reportError(Inst.getLoc(),
- "The instruction changes CFA register value, but the "
- "CFI directives don't update the CFA.");
- }
-
///////////// being diffing the CFI states
checkCFADiff(Inst, State, AfterState, Reads, Writes);
///////////// end diffing the CFI states
@@ -276,9 +230,9 @@ class CFIAnalysis {
// for (unsigned I = 0; I < Inst.getNumOperands(); I++) {
// dbgs() << "Operand #" << I << ", which will be "
// << (I < DefCount ? "defined" : "used") << ", is a";
- // if (I == MCPB->getMemoryOperandNo(Inst)) {
+ // if (I == EMCIA->getMemoryOperandNo(Inst)) {
// dbgs() << " memory access, details are:\n";
- // auto X86MemoryOperand = MCPB->evaluateX86MemoryOperand(Inst);
+ // auto X86MemoryOperand = EMCIA->evaluateX86MemoryOperand(Inst);
// dbgs() << " Base Register{ reg#" << X86MemoryOperand->BaseRegNum
// << " }";
// dbgs() << " + (Index Register{ reg#" << X86MemoryOperand->IndexRegNum
@@ -323,21 +277,21 @@ class CFIAnalysis {
// { // move
// { // Reg2Reg
// MCPhysReg From, To;
- // if (MCPB->isRegToRegMove(Inst, From, To)) {
- // dbgs() << "It's a reg to reg move.\nFrom reg#" << From << " to
- // reg#"
+ // if (EMCIA->isRegToRegMove(Inst, From, To)) {
+ // dbgs() << "It's a reg to reg move.\nFrom reg#" << From << " to reg
+ // #"
// << To << "\n";
// } else if (MCInstInfo.isMoveReg()) {
// dbgs() << "It's reg to reg move from MCInstInfo view but not from "
// "MCPlus view.\n";
// }
// }
- // if (MCPB->isConditionalMove(Inst)) {
+ // if (EMCIA->isConditionalMove(Inst)) {
// dbgs() << "Its a conditional move.\n";
// }
- // if (MCPB->isMoveMem2Reg(Inst)) {
+ // if (EMCIA->isMoveMem2Reg(Inst)) {
// dbgs() << "It's a move from memory to register\n";
- // assert(MCPB->getMemoryOperandNo(Inst) == 1);
+ // assert(EMCIA->getMemoryOperandNo(Inst) == 1);
// }
// }
@@ -353,9 +307,9 @@ class CFIAnalysis {
// bool IsLoad = false;
// bool IsStore = false;
// bool IsStoreFromReg = false;
- // if (MCPB->isStackAccess(Inst, IsLoad, IsStore, IsStoreFromReg, Reg,
- // SrcImm, StackPtrReg, StackOffset, Size,
- // IsSimple, IsIndexed)) {
+ // if (EMCIA->isStackAccess(Inst, IsLoad, IsStore, IsStoreFromReg, Reg,
+ // SrcImm, StackPtrReg, StackOffset, Size,
+ // IsSimple, IsIndexed)) {
// dbgs() << "This instruction accesses the stack, the details are:\n";
// dbgs() << " Source immediate: " << SrcImm << "\n";
// dbgs() << " Source reg#" << Reg << "\n";
@@ -369,28 +323,29 @@ class CFIAnalysis {
// dbgs() << " Is store from reg: " << (IsStoreFromReg ? "yes" : "no")
// << "\n";
// }
- // if (MCPB->isPush(Inst)) {
+ // if (EMCIA->isPush(Inst)) {
// dbgs() << "This is a push instruction with size "
- // << MCPB->getPushSize(Inst) << "\n";
+ // << EMCIA->getPushSize(Inst) << "\n";
// }
- // if (MCPB->isPop(Inst)) {
+ // if (EMCIA->isPop(Inst)) {
// dbgs() << "This is a pop instruction with size "
- // << MCPB->getPopSize(Inst) << "\n";
+ // << EMCIA->getPopSize(Inst) << "\n";
// }
// }
// dbgs() << "---------------Arith Info----------------\n";
// { // arith
- // MutableArrayRef<MCInst> MAR = {Inst};
+ // /* MutableArrayRef<MCInst> MAR = {Inst};
// if (MCPB->matchAdd(MCPB->matchAnyOperand(), MCPB->matchAnyOperand())
// ->match(*MCRI, *MCPB, MutableArrayRef<MCInst>(), -1)) {
// dbgs() << "It is an addition instruction.\n";
- // } else if (MCInstInfo.isAdd()) {
- // dbgs() << "It is an addition from MCInstInfo view but not from MCPlus
- // "
+ // } else */
+ // if (MCInstInfo.isAdd()) {
+ // dbgs() << "It is an addition from MCInstInfo view but not from
+ // MCPlus"
// "view.\n";
// }
- // if (MCPB->isSUB(Inst)) {
+ // if (EMCIA->isSUB(Inst)) {
// dbgs() << "This is a subtraction.\n";
// }
// }
>From 7527ba2fd1fb10aff422c3ed1c8f5d795eb071fb Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Mon, 19 May 2025 18:08:23 +0000
Subject: [PATCH 14/58] Make the CFA checker to first generate, if not matched
check the Read/Write conditions
---
llvm/tools/llvm-mc/CFIAnalysis.h | 138 +++++++++++++++++--------------
1 file changed, 74 insertions(+), 64 deletions(-)
diff --git a/llvm/tools/llvm-mc/CFIAnalysis.h b/llvm/tools/llvm-mc/CFIAnalysis.h
index 1a05dd6de5327..ab858e9ae7e52 100644
--- a/llvm/tools/llvm-mc/CFIAnalysis.h
+++ b/llvm/tools/llvm-mc/CFIAnalysis.h
@@ -89,12 +89,13 @@ class CFIAnalysis {
// Tries to guess Reg1's value in a form of Reg2 (before Inst's execution) +
// Diff.
- bool isInConstantDistanceOfEachOther(const MCInst &Inst, MCPhysReg Reg1,
+ bool isInConstantDistanceOfEachOther(const MCInst &Inst, MCPhysReg &Reg1,
MCPhysReg Reg2, int &Diff) {
{
MCPhysReg From;
MCPhysReg To;
- if (EMCIA->isRegToRegMove(Inst, From, To) && From == Reg2 && To == Reg1) {
+ if (EMCIA->isRegToRegMove(Inst, From, To) && From == Reg2) {
+ Reg1 = To;
Diff = 0;
return true;
}
@@ -107,89 +108,98 @@ class CFIAnalysis {
const CFIState &NextState,
const std::set<DWARFRegType> &Reads,
const std::set<DWARFRegType> &Writes) {
+ MCPhysReg PrevCFAPhysReg =
+ MCRI->getLLVMRegNum(PrevState.CFARegister, false).value();
+ MCPhysReg NextCFAPhysReg =
+ MCRI->getLLVMRegNum(NextState.CFARegister, false).value();
+
+ // Try to guess the next state. (widen)
+ std::vector<std::pair<DWARFRegType, int>> PossibleNextCFAStates;
+ { // try generate
+ { // no change
+ if (!Writes.count(PrevState.CFARegister)) {
+ PossibleNextCFAStates.emplace_back(PrevState.CFARegister,
+ PrevState.CFAOffset);
+ }
+ }
+
+ { // const change
+ int64_t HowMuch;
+ if (doesConstantChange(Inst, PrevCFAPhysReg, HowMuch)) {
+ PossibleNextCFAStates.emplace_back(PrevState.CFARegister,
+ PrevState.CFAOffset - HowMuch);
+ }
+ }
+
+ { // constant distance with each other
+ int Diff;
+ MCPhysReg PossibleNewCFAReg;
+ if (isInConstantDistanceOfEachOther(Inst, PossibleNewCFAReg,
+ PrevCFAPhysReg, Diff)) {
+ PossibleNextCFAStates.emplace_back(
+ MCRI->getDwarfRegNum(PossibleNewCFAReg, false),
+ PrevState.CFAOffset - Diff);
+ }
+ }
+ }
+
+ for (auto &&[PossibleNextCFAReg, PossibleNextCFAOffset] :
+ PossibleNextCFAStates) {
+ if (PossibleNextCFAReg != NextState.CFARegister)
+ continue;
+
+ if (PossibleNextCFAOffset == NextState.CFAOffset) {
+ // Everything is ok!
+ return;
+ }
+
+ Context.reportError(Inst.getLoc(),
+ formatv("Expected CFA [reg: {0}, offset: {1}] but "
+ "got [reg: {2}, offset: {3}].",
+ NextCFAPhysReg, PossibleNextCFAOffset,
+ NextCFAPhysReg, NextState.CFAOffset));
+ return;
+ }
+
+ // Either couldn't generate, or did, but the programmer wants to change the
+ // source of register for CFA to something not expected by the generator. So
+ // it falls back into read/write checks.
+
if (PrevState.CFARegister == NextState.CFARegister) {
if (PrevState.CFAOffset == NextState.CFAOffset) {
if (Writes.count(PrevState.CFARegister)) {
- Context.reportWarning(
+ Context.reportError(
Inst.getLoc(),
formatv("This instruction changes reg#{0}, which is "
"the CFA register, but the CFI directives do not.",
- MCRI->getLLVMRegNum(PrevState.CFARegister, false)));
+ PrevCFAPhysReg));
}
+
+ // Everything is ok!
return;
}
// The offset is changed.
+
if (!Writes.count(PrevState.CFARegister)) {
- Context.reportWarning(
+ Context.reportError(
Inst.getLoc(),
formatv(
"You changed the CFA offset, but there is no modification to "
"the CFA register happening in this instruction."));
}
- int64_t HowMuch;
- if (!doesConstantChange(
- Inst, MCRI->getLLVMRegNum(PrevState.CFARegister, false).value(),
- HowMuch)) {
- Context.reportWarning(
- Inst.getLoc(),
- formatv("The CFA register changed, but I don't know how, finger "
- "crossed the CFI directives are correct."));
- return;
- }
- // we know it is changed by HowMuch, so the CFA offset should be changed
- // by -HowMuch, i.e. AfterState.Offset - State.Offset = -HowMuch
- if (NextState.CFAOffset - PrevState.CFAOffset != -HowMuch) {
- Context.reportError(
- Inst.getLoc(),
- formatv("The CFA offset is changed by {0}, but "
- "the directives changed it by {1}. (to be exact, the new "
- "offset should be {2}, but it is {3})",
- -HowMuch, NextState.CFAOffset - PrevState.CFAOffset,
- PrevState.CFAOffset - HowMuch, NextState.CFAOffset));
- return;
- }
- // Everything OK!
- return;
- }
- // The CFA register is changed.
- // TODO move it up
- MCPhysReg OldCFAReg =
- MCRI->getLLVMRegNum(PrevState.CFARegister, false).value();
- MCPhysReg NewCFAReg =
- MCRI->getLLVMRegNum(NextState.CFARegister, false).value();
- if (!Writes.count(NextState.CFARegister)) {
Context.reportWarning(
Inst.getLoc(),
- formatv(
- "The new CFA register reg#{0}'s value is not assigned by this "
- "instruction, try to move the new CFA def to where this "
- "value is changed, now I can't infer if this change is "
- "correct or not.",
- NewCFAReg));
- return;
- }
- // Because CFA should is the CFA always stays the same:
- int OffsetDiff = PrevState.CFAOffset - NextState.CFAOffset;
- int Diff;
- if (!isInConstantDistanceOfEachOther(Inst, NewCFAReg, OldCFAReg, Diff)) {
- Context.reportWarning(
- Inst.getLoc(),
- formatv("Based on this instruction I cannot infer that the new and "
- "old CFA registers are in {0} distance of each other. I "
- "hope it's ok.",
- OffsetDiff));
- return;
- }
- if (Diff != OffsetDiff) {
- Context.reportError(Inst.getLoc(),
- formatv("After changing the CFA register, the CFA "
- "offset should be {0}, but it is {1}.",
- PrevState.CFAOffset - Diff,
- NextState.CFAOffset));
+ "I don't know what the instruction did, but it changed the CFA reg's "
+ "value, and the offset is changed as well by the CFI directives.");
+ // Everything may be ok!
return;
}
- // Everything is OK!
+ // The CFA register is changed
+ Context.reportWarning(
+ Inst.getLoc(), "The CFA register is changed to something, and I don't "
+ "have any idea on the new register relevance to CFA.");
+ // Everything may be ok!
}
void update(MCInst &Inst, ArrayRef<MCCFIInstruction> CFIDirectives) {
>From 3d65eebd051b17cbeb3422fe94911955e48b6eed Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Tue, 20 May 2025 01:19:00 +0000
Subject: [PATCH 15/58] Check register states as well
---
llvm/tools/llvm-mc/CFIAnalysis.h | 405 ++++++++++++++++++++++++++++---
llvm/tools/llvm-mc/CFIState.h | 38 +++
2 files changed, 403 insertions(+), 40 deletions(-)
diff --git a/llvm/tools/llvm-mc/CFIAnalysis.h b/llvm/tools/llvm-mc/CFIAnalysis.h
index ab858e9ae7e52..f0b81a85e2fd4 100644
--- a/llvm/tools/llvm-mc/CFIAnalysis.h
+++ b/llvm/tools/llvm-mc/CFIAnalysis.h
@@ -19,6 +19,7 @@
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormatVariadic.h"
#include <cstdint>
#include <memory>
@@ -40,6 +41,41 @@ class CFIAnalysis {
std::unique_ptr<ExtendedMCInstrAnalysis> EMCIA;
CFIState State;
+private:
+ // The CFI analysis only keeps track and cares about super registers, not the
+ // subregisters. All reads to/writes from subregisters and considered the same
+ // operation to super registers. Other operations like loading and stores are
+ // considered only if they are exactly doing the operation to or from a super
+ // register.
+ // As en example, if you spill a sub register to stack, the CFI analysis does
+ // not consider that a register spilling.
+ bool isSuperReg(MCPhysReg Reg) { return MCRI->superregs(Reg).empty(); }
+
+ std::set<MCPhysReg> getAllSuperRegs() {
+ std::set<MCPhysReg> SuperRegs;
+ for (auto &&RegClass : MCRI->regclasses()) {
+ for (unsigned I = 0; I < RegClass.getNumRegs(); I++) {
+ MCPhysReg Reg = RegClass.getRegister(I);
+ if (!isSuperReg(Reg))
+ continue;
+ SuperRegs.insert(Reg);
+ }
+ }
+
+ return SuperRegs;
+ }
+
+ MCPhysReg getSuperReg(MCPhysReg Reg) {
+ if (isSuperReg(Reg))
+ return Reg;
+ for (auto SuperReg : MCRI->superregs(Reg)) {
+ if (isSuperReg(SuperReg))
+ return SuperReg;
+ }
+
+ llvm_unreachable("Should either be a super reg, or have a super reg");
+ }
+
public:
CFIAnalysis(MCContext &Context, MCInstrInfo const &MCII,
MCInstrAnalysis *MCIA)
@@ -53,7 +89,7 @@ class CFIAnalysis {
// access to it, maybe can be read from the prologue
// TODO check what should be passed as EH?
State = CFIState(MCRI->getDwarfRegNum(EMCIA->getStackPointer(), false), 8);
- for (unsigned I = 0; I < MCRI->getNumRegs(); I++) {
+ for (MCPhysReg I : getAllSuperRegs()) {
DWARFRegType DwarfI = MCRI->getDwarfRegNum(I, false);
State.RegisterCFIStates[DwarfI] = RegisterCFIState::createSameValue();
}
@@ -104,6 +140,275 @@ class CFIAnalysis {
return false;
}
+ bool doStoreFromReg(const MCInst &Inst, MCPhysReg StoringReg,
+ MCPhysReg FromReg, int64_t &Offset) {
+ if (EMCIA->isPush(Inst) && FromReg == EMCIA->getStackPointer()) {
+ // TODO should get the stack direction here, now it assumes that it goes
+ // down.
+ Offset = -EMCIA->getPushSize(Inst);
+ return true;
+ }
+
+ {
+ bool IsLoad;
+ bool IsStore;
+ bool IsStoreFromReg;
+ MCPhysReg SrcReg;
+ int32_t SrcImm;
+ uint16_t StackPtrReg;
+ int64_t StackOffset;
+ uint8_t Size;
+ bool IsSimple;
+ bool IsIndexed;
+ if (EMCIA->isStackAccess(Inst, IsLoad, IsStore, IsStoreFromReg, SrcReg,
+ SrcImm, StackPtrReg, StackOffset, Size, IsSimple,
+ IsIndexed)) {
+ // TODO make sure that simple means that it's store and does nothing
+ // more.
+ if (IsStore && IsSimple && StackPtrReg == FromReg && IsStoreFromReg &&
+ SrcReg == StoringReg) {
+ Offset = StackOffset;
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ bool doLoadFromReg(const MCInst &Inst, MCPhysReg FromReg, int64_t &Offset,
+ MCPhysReg &LoadingReg) {
+ if (EMCIA->isPop(Inst) && FromReg == EMCIA->getStackPointer()) {
+ // TODO should get the stack direction here, now it assumes that it goes
+ // down.
+ Offset = 0;
+ LoadingReg = Inst.getOperand(0).getReg();
+ return true;
+ }
+
+ {
+ bool IsLoad;
+ bool IsStore;
+ bool IsStoreFromReg;
+ MCPhysReg SrcReg;
+ int32_t SrcImm;
+ uint16_t StackPtrReg;
+ int64_t StackOffset;
+ uint8_t Size;
+ bool IsSimple;
+ bool IsIndexed;
+ if (EMCIA->isStackAccess(Inst, IsLoad, IsStore, IsStoreFromReg, SrcReg,
+ SrcImm, StackPtrReg, StackOffset, Size, IsSimple,
+ IsIndexed)) {
+ // TODO make sure that simple means that it's store and does nothing
+ // more.
+ if (IsLoad && IsSimple && StackPtrReg == FromReg) {
+ Offset = StackOffset;
+ LoadingReg = SrcReg;
+ return true;
+ }
+ }
+ }
+
+ {
+ if (EMCIA->isMoveMem2Reg(Inst)) {
+ auto X86MemAccess = EMCIA->evaluateX86MemoryOperand(Inst).value();
+ if (X86MemAccess.BaseRegNum == FromReg &&
+ (X86MemAccess.ScaleImm == 0 || X86MemAccess.IndexRegNum == 0) &&
+ !X86MemAccess.DispExpr) {
+ LoadingReg = Inst.getOperand(0).getReg();
+ Offset = X86MemAccess.DispImm;
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ void checkRegDiff(const MCInst &Inst, DWARFRegType Reg,
+ const CFIState &PrevState, const CFIState &NextState,
+ const RegisterCFIState &PrevRegState,
+ const RegisterCFIState &NextRegState,
+ const std::set<DWARFRegType> &Reads,
+ const std::set<DWARFRegType> &Writes) {
+ auto RegLLVMOpt = MCRI->getLLVMRegNum(Reg, false);
+ if (RegLLVMOpt == std::nullopt) {
+ assert(PrevRegState == NextRegState);
+ return;
+ }
+ MCPhysReg RegLLVM = RegLLVMOpt.value();
+
+ auto &&PrevRefReg =
+ PrevState.getReferenceRegisterForCallerValueOfRegister(Reg);
+ auto &&NextRefReg =
+ NextState.getReferenceRegisterForCallerValueOfRegister(Reg);
+
+ std::optional<MCPhysReg> PrevRefRegLLVM =
+ (PrevRefReg != std::nullopt
+ ? std::make_optional(
+ MCRI->getLLVMRegNum(PrevRefReg.value(), false).value())
+ : std::nullopt);
+ std::optional<MCPhysReg> NextRefRegLLVM =
+ (PrevRefReg != std::nullopt
+ ? std::make_optional(
+ MCRI->getLLVMRegNum(PrevRefReg.value(), false).value())
+ : std::nullopt);
+
+ MCPhysReg PrevStateCFARegLLVM =
+ MCRI->getLLVMRegNum(PrevState.CFARegister, false).value();
+
+ { // try generate
+ // Widen
+ std::vector<RegisterCFIState> PossibleNextRegStates;
+ { // storing to offset from CFA
+ if (PrevRegState.RetrieveApproach == RegisterCFIState::SameValue ||
+ PrevRegState.RetrieveApproach ==
+ RegisterCFIState::AnotherRegister) {
+ int64_t OffsetFromCFAReg;
+ if (doStoreFromReg(Inst, PrevRefRegLLVM.value(), PrevStateCFARegLLVM,
+ OffsetFromCFAReg)) {
+ PossibleNextRegStates.push_back(
+ RegisterCFIState::createOffsetFromCFAAddr(OffsetFromCFAReg -
+ PrevState.CFAOffset));
+ }
+ }
+ }
+
+ { // loading from an offset from CFA
+ if (PrevRegState.RetrieveApproach ==
+ RegisterCFIState::OffsetFromCFAAddr) {
+ int64_t OffsetFromCFAReg;
+ MCPhysReg ToRegLLVM;
+ if (doLoadFromReg(Inst, PrevStateCFARegLLVM, OffsetFromCFAReg,
+ ToRegLLVM) &&
+ OffsetFromCFAReg == PrevRegState.Info.OffsetFromCFA) {
+ DWARFRegType ToReg = MCRI->getDwarfRegNum(ToRegLLVM, false);
+ if (ToReg == Reg) {
+ PossibleNextRegStates.push_back(
+ RegisterCFIState::createSameValue());
+ } else {
+ PossibleNextRegStates.push_back(
+ RegisterCFIState::createAnotherRegister(ToReg));
+ }
+ }
+ }
+ }
+
+ { // moved from reg to other reg
+ if (PrevRegState.RetrieveApproach == RegisterCFIState::SameValue ||
+ PrevRegState.RetrieveApproach ==
+ RegisterCFIState::AnotherRegister) {
+
+ int Diff;
+ MCPhysReg PossibleRegLLVM;
+ if (isInConstantDistanceOfEachOther(Inst, PossibleRegLLVM,
+ PrevRefRegLLVM.value(), Diff)) {
+ DWARFRegType PossibleReg =
+ MCRI->getDwarfRegNum(PossibleRegLLVM, false);
+ if (Diff == 0) {
+ if (PossibleReg == Reg) {
+ PossibleNextRegStates.push_back(
+ RegisterCFIState::createSameValue());
+ } else {
+ PossibleNextRegStates.push_back(
+ RegisterCFIState::createAnotherRegister(PossibleReg));
+ }
+ }
+ }
+ }
+ }
+
+ { // stay the same
+ bool CanStayTheSame = false;
+
+ switch (PrevRegState.RetrieveApproach) {
+ case RegisterCFIState::Undefined:
+ case RegisterCFIState::OffsetFromCFAVal:
+ CanStayTheSame = true;
+ break;
+ case RegisterCFIState::SameValue:
+ case RegisterCFIState::AnotherRegister:
+ CanStayTheSame = !Writes.count(PrevRefReg.value());
+ break;
+ case RegisterCFIState::OffsetFromCFAAddr:
+ case RegisterCFIState::Other:
+ // cannot be sure
+ break;
+ }
+
+ if (CanStayTheSame)
+ PossibleNextRegStates.push_back(PrevRegState);
+ }
+
+ for (auto &&PossibleNextRegState : PossibleNextRegStates) {
+ if (PossibleNextRegState == NextRegState) {
+ // Everything is ok
+ return;
+ }
+ }
+
+ for (auto &&PossibleNextRegState : PossibleNextRegStates) {
+ if (PossibleNextRegState.RetrieveApproach !=
+ NextRegState.RetrieveApproach)
+ continue;
+
+ if (PossibleNextRegState.RetrieveApproach ==
+ RegisterCFIState::OffsetFromCFAAddr) {
+ Context.reportError(
+ Inst.getLoc(),
+ formatv(
+ "Expected caller's value of reg#{0} should be at offset {1} "
+ "of CFA but the CFI directives say it's in {2}",
+ RegLLVM, PossibleNextRegState.Info.OffsetFromCFA,
+ NextRegState.Info.OffsetFromCFA));
+ }
+ }
+ }
+ // Either couldn't generate, or the programmer changed the state to
+ // something that couldn't be matched to any of the generated states. So
+ // it falls back into read/write checks.
+
+ if (PrevRegState == NextRegState) {
+ switch (PrevRegState.RetrieveApproach) {
+ case RegisterCFIState::SameValue:
+ case RegisterCFIState::AnotherRegister:
+ if (Writes.count(PrevRefReg.value())) {
+ Context.reportError(
+ Inst.getLoc(),
+ formatv("Reg#{0} caller's value is in reg#{1} which is changed "
+ "by this instruction, but not changed in CFI directives",
+ RegLLVM, PrevRefRegLLVM.value()));
+ return;
+ }
+ break;
+ default:
+ // Everything may be ok
+ break;
+ }
+ return;
+ }
+
+ if (PrevRegState.RetrieveApproach == NextRegState.RetrieveApproach) {
+ // Everything may be ok
+ return;
+ }
+
+ if (PrevRegState.RetrieveApproach == RegisterCFIState::Undefined) {
+ Context.reportError(Inst.getLoc(),
+ "Cannot change a register CFI information from "
+ "undefined to something else.");
+ return;
+ }
+
+ Context.reportWarning(Inst.getLoc(),
+ formatv("The reg#{0} CFI state is changed, but I "
+ "don't have any idea how.",
+ RegLLVM));
+ // Everything may be ok
+ return;
+ }
+
void checkCFADiff(const MCInst &Inst, const CFIState &PrevState,
const CFIState &NextState,
const std::set<DWARFRegType> &Reads,
@@ -113,9 +418,9 @@ class CFIAnalysis {
MCPhysReg NextCFAPhysReg =
MCRI->getLLVMRegNum(NextState.CFARegister, false).value();
- // Try to guess the next state. (widen)
- std::vector<std::pair<DWARFRegType, int>> PossibleNextCFAStates;
- { // try generate
+ { // try generate
+ // Widen
+ std::vector<std::pair<DWARFRegType, int>> PossibleNextCFAStates;
{ // no change
if (!Writes.count(PrevState.CFARegister)) {
PossibleNextCFAStates.emplace_back(PrevState.CFARegister,
@@ -141,29 +446,29 @@ class CFIAnalysis {
PrevState.CFAOffset - Diff);
}
}
- }
- for (auto &&[PossibleNextCFAReg, PossibleNextCFAOffset] :
- PossibleNextCFAStates) {
- if (PossibleNextCFAReg != NextState.CFARegister)
- continue;
+ for (auto &&[PossibleNextCFAReg, PossibleNextCFAOffset] :
+ PossibleNextCFAStates) {
+ if (PossibleNextCFAReg != NextState.CFARegister)
+ continue;
- if (PossibleNextCFAOffset == NextState.CFAOffset) {
- // Everything is ok!
+ if (PossibleNextCFAOffset == NextState.CFAOffset) {
+ // Everything is ok!
+ return;
+ }
+
+ Context.reportError(Inst.getLoc(),
+ formatv("Expected CFA [reg: {0}, offset: {1}] but "
+ "got [reg: {2}, offset: {3}].",
+ NextCFAPhysReg, PossibleNextCFAOffset,
+ NextCFAPhysReg, NextState.CFAOffset));
return;
}
-
- Context.reportError(Inst.getLoc(),
- formatv("Expected CFA [reg: {0}, offset: {1}] but "
- "got [reg: {2}, offset: {3}].",
- NextCFAPhysReg, PossibleNextCFAOffset,
- NextCFAPhysReg, NextState.CFAOffset));
- return;
}
- // Either couldn't generate, or did, but the programmer wants to change the
- // source of register for CFA to something not expected by the generator. So
- // it falls back into read/write checks.
+ // Either couldn't generate, or did, but the programmer wants to change
+ // the source of register for CFA to something not expected by the
+ // generator. So it falls back into read/write checks.
if (PrevState.CFARegister == NextState.CFARegister) {
if (PrevState.CFAOffset == NextState.CFAOffset) {
@@ -173,6 +478,7 @@ class CFIAnalysis {
formatv("This instruction changes reg#{0}, which is "
"the CFA register, but the CFI directives do not.",
PrevCFAPhysReg));
+ return;
}
// Everything is ok!
@@ -190,7 +496,8 @@ class CFIAnalysis {
Context.reportWarning(
Inst.getLoc(),
- "I don't know what the instruction did, but it changed the CFA reg's "
+ "I don't know what the instruction did, but it changed the CFA "
+ "reg's "
"value, and the offset is changed as well by the CFI directives.");
// Everything may be ok!
return;
@@ -198,7 +505,8 @@ class CFIAnalysis {
// The CFA register is changed
Context.reportWarning(
Inst.getLoc(), "The CFA register is changed to something, and I don't "
- "have any idea on the new register relevance to CFA.");
+ "have any idea on the new register relevance to CFA. I "
+ "assume CFA is preserved.");
// Everything may be ok!
}
@@ -214,21 +522,33 @@ class CFIAnalysis {
std::set<DWARFRegType> Writes, Reads;
for (unsigned I = 0; I < MCInstInfo.NumImplicitUses; I++)
- Reads.insert(MCRI->getDwarfRegNum(MCInstInfo.implicit_uses()[I], false));
+ Reads.insert(MCRI->getDwarfRegNum(
+ getSuperReg(MCInstInfo.implicit_uses()[I]), false));
for (unsigned I = 0; I < MCInstInfo.NumImplicitDefs; I++)
- Writes.insert(MCRI->getDwarfRegNum(MCInstInfo.implicit_defs()[I], false));
+ Writes.insert(MCRI->getDwarfRegNum(
+ getSuperReg(MCInstInfo.implicit_defs()[I]), false));
for (unsigned I = 0; I < Inst.getNumOperands(); I++) {
auto &&Operand = Inst.getOperand(I);
if (Operand.isReg()) {
if (I < MCInstInfo.getNumDefs())
- Writes.insert(MCRI->getDwarfRegNum(Operand.getReg(), false));
- else
- Reads.insert(MCRI->getDwarfRegNum(Operand.getReg(), false));
+ Writes.insert(
+ MCRI->getDwarfRegNum(getSuperReg(Operand.getReg()), false));
+ else if (Operand.getReg())
+ Reads.insert(
+ MCRI->getDwarfRegNum(getSuperReg(Operand.getReg()), false));
}
}
+
///////////// being diffing the CFI states
checkCFADiff(Inst, State, AfterState, Reads, Writes);
+
+ for (auto &&[Reg, RegState] : State.RegisterCFIStates) {
+ assert(AfterState.RegisterCFIStates.count(Reg) &&
+ "Registers' state should not be deleted by CFI instruction.");
+ checkRegDiff(Inst, Reg, State, AfterState, RegState,
+ AfterState.RegisterCFIStates[Reg], Reads, Writes);
+ }
///////////// end diffing the CFI states
// dbgs() << "^^^^^^^^^^^^^^^^ InsCFIs ^^^^^^^^^^^^^^^^\n";
@@ -245,7 +565,8 @@ class CFIAnalysis {
// auto X86MemoryOperand = EMCIA->evaluateX86MemoryOperand(Inst);
// dbgs() << " Base Register{ reg#" << X86MemoryOperand->BaseRegNum
// << " }";
- // dbgs() << " + (Index Register{ reg#" << X86MemoryOperand->IndexRegNum
+ // dbgs() << " + (Index Register{ reg#" <<
+ // X86MemoryOperand->IndexRegNum
// << " }";
// dbgs() << " * Scale{ value " << X86MemoryOperand->ScaleImm << " }";
// dbgs() << ") + Displacement{ "
@@ -253,7 +574,8 @@ class CFIAnalysis {
// ? "an expression"
// : "value " + itostr(X86MemoryOperand->DispImm))
// << " }\n";
- // // TODO, it's not correct always, it cannot be assumed (or should be
+ // // TODO, it's not correct always, it cannot be assumed (or should
+ // be
// // checked) that memory operands are flatten into 4 operands in
// MCInc. I += 4; continue;
// }
@@ -288,11 +610,13 @@ class CFIAnalysis {
// { // Reg2Reg
// MCPhysReg From, To;
// if (EMCIA->isRegToRegMove(Inst, From, To)) {
- // dbgs() << "It's a reg to reg move.\nFrom reg#" << From << " to reg
+ // dbgs() << "It's a reg to reg move.\nFrom reg#" << From << " to
+ // reg
// #"
// << To << "\n";
// } else if (MCInstInfo.isMoveReg()) {
- // dbgs() << "It's reg to reg move from MCInstInfo view but not from "
+ // dbgs() << "It's reg to reg move from MCInstInfo view but not from
+ // "
// "MCPlus view.\n";
// }
// }
@@ -320,17 +644,17 @@ class CFIAnalysis {
// if (EMCIA->isStackAccess(Inst, IsLoad, IsStore, IsStoreFromReg, Reg,
// SrcImm, StackPtrReg, StackOffset, Size,
// IsSimple, IsIndexed)) {
- // dbgs() << "This instruction accesses the stack, the details are:\n";
- // dbgs() << " Source immediate: " << SrcImm << "\n";
- // dbgs() << " Source reg#" << Reg << "\n";
- // dbgs() << " Stack pointer: reg#" << StackPtrReg << "\n";
- // dbgs() << " Stack offset: " << StackOffset << "\n";
- // dbgs() << " size: " << (int)Size << "\n";
+ // dbgs() << "This instruction accesses the stack, the details
+ // are:\n"; dbgs() << " Source immediate: " << SrcImm << "\n"; dbgs()
+ // << " Source reg#" << Reg << "\n"; dbgs() << " Stack pointer:
+ // reg#" << StackPtrReg << "\n"; dbgs() << " Stack offset: " <<
+ // StackOffset << "\n"; dbgs() << " size: " << (int)Size << "\n";
// dbgs() << " Is simple: " << (IsSimple ? "yes" : "no") << "\n";
// dbgs() << " Is indexed: " << (IsIndexed ? "yes" : "no") << "\n";
// dbgs() << " Is load: " << (IsLoad ? "yes" : "no") << "\n";
// dbgs() << " Is store: " << (IsStore ? "yes" : "no") << "\n";
- // dbgs() << " Is store from reg: " << (IsStoreFromReg ? "yes" : "no")
+ // dbgs() << " Is store from reg: " << (IsStoreFromReg ? "yes" :
+ // "no")
// << "\n";
// }
// if (EMCIA->isPush(Inst)) {
@@ -364,7 +688,8 @@ class CFIAnalysis {
// dbgs() << "The CFA register is: " << CFAReg << "\n";
// dbgs() << "The instruction does " << (ChangedCFA ? "" : "NOT ")
// << "change the CFA.\n";
- // dbgs() << "The CFI directives does " << (GoingToChangeCFA ? "" : "NOT ")
+ // dbgs() << "The CFI directives does " << (GoingToChangeCFA ? "" : "NOT
+ // ")
// << "change the CFA.\n";
// dbgs() << "vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n";
diff --git a/llvm/tools/llvm-mc/CFIState.h b/llvm/tools/llvm-mc/CFIState.h
index 5551e9778f1d2..b0091efecbb7b 100644
--- a/llvm/tools/llvm-mc/CFIState.h
+++ b/llvm/tools/llvm-mc/CFIState.h
@@ -5,7 +5,9 @@
#include "llvm/MC/MCDwarf.h"
#include "llvm/MC/MCRegister.h"
#include "llvm/Support/MathExtras.h"
+#include <cassert>
#include <cstdint>
+#include <optional>
namespace llvm {
using DWARFRegType = int64_t;
@@ -26,6 +28,23 @@ struct RegisterCFIState {
DWARFRegType Register;
} Info;
+ bool operator==(const RegisterCFIState &OtherState) const {
+ if (RetrieveApproach != OtherState.RetrieveApproach)
+ return false;
+
+ switch (RetrieveApproach) {
+ case Undefined:
+ case SameValue:
+ case Other:
+ return true;
+ case AnotherRegister:
+ return Info.Register == OtherState.Info.Register;
+ case OffsetFromCFAAddr:
+ case OffsetFromCFAVal:
+ return Info.OffsetFromCFA == OtherState.Info.OffsetFromCFA;
+ }
+ }
+
static RegisterCFIState createUndefined() {
RegisterCFIState State;
State.RetrieveApproach = Undefined;
@@ -97,6 +116,25 @@ struct CFIState {
CFIState(DWARFRegType CFARegister, int CFIOffset)
: CFARegister(CFARegister), CFAOffset(CFIOffset) {}
+ std::optional<DWARFRegType>
+ getReferenceRegisterForCallerValueOfRegister(DWARFRegType Reg) const {
+ assert(RegisterCFIStates.count(Reg) &&
+ "The register should be tracked inside the register states");
+ auto &&RegState = RegisterCFIStates.at(Reg);
+ switch (RegState.RetrieveApproach) {
+ case RegisterCFIState::Undefined:
+ case RegisterCFIState::Other:
+ return std::nullopt;
+ case RegisterCFIState::SameValue:
+ return Reg;
+ case RegisterCFIState::AnotherRegister:
+ return RegState.Info.Register;
+ case RegisterCFIState::OffsetFromCFAAddr:
+ case RegisterCFIState::OffsetFromCFAVal:
+ return CFARegister;
+ }
+ }
+
bool apply(const MCCFIInstruction &CFIDirective) {
switch (CFIDirective.getOperation()) {
case MCCFIInstruction::OpDefCfaRegister:
>From 79c166416a48da408310dd08a039978ae4d847d6 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Tue, 20 May 2025 02:29:47 +0000
Subject: [PATCH 16/58] Process prologue as well
---
llvm/tools/llvm-mc/CFIAnalysis.h | 11 +++--
llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h | 53 ++++++++++------------
2 files changed, 32 insertions(+), 32 deletions(-)
diff --git a/llvm/tools/llvm-mc/CFIAnalysis.h b/llvm/tools/llvm-mc/CFIAnalysis.h
index f0b81a85e2fd4..533ead49c300d 100644
--- a/llvm/tools/llvm-mc/CFIAnalysis.h
+++ b/llvm/tools/llvm-mc/CFIAnalysis.h
@@ -78,11 +78,9 @@ class CFIAnalysis {
public:
CFIAnalysis(MCContext &Context, MCInstrInfo const &MCII,
- MCInstrAnalysis *MCIA)
+ MCInstrAnalysis *MCIA,
+ ArrayRef<MCCFIInstruction> PrologueCFIDirectives)
: Context(Context), MCII(MCII), MCRI(Context.getRegisterInfo()) {
- // TODO it should look at the prologue directives and setup the
- // registers' previous value state here, but for now, it's assumed that all
- // values are by default `samevalue`.
EMCIA.reset(new ExtendedMCInstrAnalysis(Context, MCII, MCIA));
// TODO CFA offset should be the slot size, but for now I don't have any
@@ -103,6 +101,11 @@ class CFIAnalysis {
State.RegisterCFIStates[MCRI->getDwarfRegNum(EMCIA->getStackPointer(),
false)] =
RegisterCFIState::createOffsetFromCFAVal(0); // sp's old value is CFA
+
+ // Applying the prologue after default assumptions to overwrite them.
+ for (auto &&PrologueCFIDirective : PrologueCFIDirectives) {
+ State.apply(PrologueCFIDirective);
+ }
}
bool doesConstantChange(const MCInst &Inst, MCPhysReg Reg, int64_t &HowMuch) {
diff --git a/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h b/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h
index a9354d7af8a2f..7f79653004e5e 100644
--- a/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h
+++ b/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h
@@ -38,12 +38,8 @@ class CFIAnalysisMCStreamer : public MCStreamer {
};
std::optional<MCInst> LastInstruction;
- MCDwarfFrameInfo const *LastDwarfFrameInfo;
-
- std::optional<ICFI> getLastICFI() {
- if (!LastInstruction)
- return std::nullopt;
+ std::pair<unsigned, unsigned> getCFIDirectivesRange() {
auto DwarfFrameInfos = getDwarfFrameInfos();
int FrameIndex = FrameIndices.back();
auto CurrentCFIDirectiveState =
@@ -57,31 +53,42 @@ class CFIAnalysisMCStreamer : public MCStreamer {
std::pair<unsigned, unsigned> CFIDirectivesRange(
LastCFIDirectivesState.DirectiveIndex,
CurrentCFIDirectiveState.DirectiveIndex);
-
LastCFIDirectivesState = CurrentCFIDirectiveState;
- return ICFI(LastInstruction.value(), CFIDirectivesRange);
+ return CFIDirectivesRange;
}
void feedCFIA() {
- if (!LastDwarfFrameInfo) {
+ auto FrameIndex = FrameIndices.back();
+ if (FrameIndex < 0) {
// TODO Maybe this corner case causes bugs, when the programmer did a
// mistake in the startproc, endprocs and also made a mistake in not
// adding cfi directives for a instruction. Then this would cause to
// ignore the instruction.
- auto LastICFI = getLastICFI();
- assert(!LastICFI || LastICFI->CFIDirectivesRange.first ==
- LastICFI->CFIDirectivesRange.second);
+ auto CFIDirectivesRange = getCFIDirectivesRange();
+ assert(!LastInstruction ||
+ CFIDirectivesRange.first == CFIDirectivesRange.second);
return;
}
- if (auto ICFI = getLastICFI()) {
- assert(!CFIAs.empty());
- ArrayRef<MCCFIInstruction> CFIDirectives(
- LastDwarfFrameInfo->Instructions);
- CFIDirectives = CFIDirectives.drop_front(ICFI->CFIDirectivesRange.first)
+ // TODO get this from emit yourself, instead of getting it in this way
+ const auto *LastDwarfFrameInfo = &getDwarfFrameInfos()[FrameIndex];
+
+ auto CFIDirectivesRange = getCFIDirectivesRange();
+ ArrayRef<MCCFIInstruction> CFIDirectives;
+ if (CFIDirectivesRange.first < CFIDirectivesRange.second) {
+ CFIDirectives =
+ ArrayRef<MCCFIInstruction>(LastDwarfFrameInfo->Instructions);
+ CFIDirectives = CFIDirectives.drop_front(CFIDirectivesRange.first)
.drop_back(LastDwarfFrameInfo->Instructions.size() -
- ICFI->CFIDirectivesRange.second);
- CFIAs.back().update(ICFI->Instruction, CFIDirectives);
+ CFIDirectivesRange.second);
+ }
+
+ if (LastInstruction != std::nullopt) {
+ assert(!CFIAs.empty());
+
+ CFIAs.back().update(LastInstruction.value(), CFIDirectives);
+ } else {
+ CFIAs.emplace_back(getContext(), MCII, MCIA.get(), CFIDirectives);
}
}
@@ -114,21 +121,12 @@ class CFIAnalysisMCStreamer : public MCStreamer {
const MCSubtargetInfo &STI) override {
feedCFIA();
LastInstruction = Inst;
- if (hasUnfinishedDwarfFrameInfo())
- LastDwarfFrameInfo =
- &getDwarfFrameInfos()[FrameIndices.back()]; // TODO get this from emit
- // yourself, instead of
- // getting it in this way
- else
- LastDwarfFrameInfo = nullptr;
}
void emitCFIStartProcImpl(MCDwarfFrameInfo &Frame) override {
feedCFIA();
FrameIndices.push_back(getNumFrameInfos());
- CFIAs.emplace_back(getContext(), MCII, MCIA.get());
LastInstruction = std::nullopt;
- LastDwarfFrameInfo = nullptr;
LastCFIDirectivesState.DirectiveIndex = 0;
MCStreamer::emitCFIStartProcImpl(Frame);
}
@@ -139,7 +137,6 @@ class CFIAnalysisMCStreamer : public MCStreamer {
FrameIndices.pop_back();
CFIAs.pop_back();
LastInstruction = std::nullopt;
- LastDwarfFrameInfo = nullptr;
auto FrameIndex = FrameIndices.back();
LastCFIDirectivesState.DirectiveIndex =
FrameIndex >= 0 ? getDwarfFrameInfos()[FrameIndex].Instructions.size()
>From 02410ac0633d30bed60f35c308f4e652b4a3ebd5 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Tue, 20 May 2025 17:54:28 +0000
Subject: [PATCH 17/58] Ignore flag registers as well
---
llvm/tools/llvm-mc/CFIAnalysis.h | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/llvm/tools/llvm-mc/CFIAnalysis.h b/llvm/tools/llvm-mc/CFIAnalysis.h
index 533ead49c300d..55a02dcb1013e 100644
--- a/llvm/tools/llvm-mc/CFIAnalysis.h
+++ b/llvm/tools/llvm-mc/CFIAnalysis.h
@@ -102,6 +102,9 @@ class CFIAnalysis {
false)] =
RegisterCFIState::createOffsetFromCFAVal(0); // sp's old value is CFA
+ State.RegisterCFIStates[MCRI->getDwarfRegNum(EMCIA->getFlagsReg(), false)] =
+ RegisterCFIState::createUndefined(); // Flags cannot be caller-saved
+
// Applying the prologue after default assumptions to overwrite them.
for (auto &&PrologueCFIDirective : PrologueCFIDirectives) {
State.apply(PrologueCFIDirective);
@@ -119,7 +122,7 @@ class CFIAnalysis {
if (EMCIA->isPop(Inst) && Reg == EMCIA->getStackPointer()) {
// TODO should get the stack direction here, now it assumes that it goes
// down.
- HowMuch = EMCIA->getPushSize(Inst);
+ HowMuch = EMCIA->getPopSize(Inst);
return true;
}
@@ -285,7 +288,8 @@ class CFIAnalysis {
MCPhysReg ToRegLLVM;
if (doLoadFromReg(Inst, PrevStateCFARegLLVM, OffsetFromCFAReg,
ToRegLLVM) &&
- OffsetFromCFAReg == PrevRegState.Info.OffsetFromCFA) {
+ OffsetFromCFAReg - PrevState.CFAOffset ==
+ PrevRegState.Info.OffsetFromCFA) {
DWARFRegType ToReg = MCRI->getDwarfRegNum(ToRegLLVM, false);
if (ToReg == Reg) {
PossibleNextRegStates.push_back(
>From dfdd22f78c73deb05806d754ba211ca39177509e Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Tue, 20 May 2025 17:54:44 +0000
Subject: [PATCH 18/58] Enable dump
---
llvm/tools/llvm-mc/CFIState.h | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/llvm/tools/llvm-mc/CFIState.h b/llvm/tools/llvm-mc/CFIState.h
index b0091efecbb7b..1b66d0dd40904 100644
--- a/llvm/tools/llvm-mc/CFIState.h
+++ b/llvm/tools/llvm-mc/CFIState.h
@@ -2,12 +2,15 @@
#define LLVM_TOOLS_LLVM_MC_CFI_STATE_H
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/MC/MCDwarf.h"
#include "llvm/MC/MCRegister.h"
+#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/MathExtras.h"
#include <cassert>
#include <cstdint>
#include <optional>
+#include <string>
namespace llvm {
using DWARFRegType = int64_t;
@@ -28,6 +31,24 @@ struct RegisterCFIState {
DWARFRegType Register;
} Info;
+ std::string dump() {
+ switch (RetrieveApproach) {
+ case Undefined:
+ return "undefined";
+ case SameValue:
+ return "same value";
+ case AnotherRegister:
+ return formatv("stored in another register, which is reg#{0}",
+ Info.Register);
+ case OffsetFromCFAAddr:
+ return formatv("offset {0} from CFA", Info.OffsetFromCFA);
+ case OffsetFromCFAVal:
+ return formatv("CFA value + {0}", Info.OffsetFromCFA);
+ case Other:
+ return "other";
+ }
+ }
+
bool operator==(const RegisterCFIState &OtherState) const {
if (RetrieveApproach != OtherState.RetrieveApproach)
return false;
@@ -45,6 +66,10 @@ struct RegisterCFIState {
}
}
+ bool operator!=(const RegisterCFIState &OtherState) const {
+ return !(*this == OtherState);
+ }
+
static RegisterCFIState createUndefined() {
RegisterCFIState State;
State.RetrieveApproach = Undefined;
>From 4fd37bf32055c1ae3bbcf9f22b52a5f09b6af87b Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Tue, 20 May 2025 17:55:25 +0000
Subject: [PATCH 19/58] Enable getting flag register through extended
MCInstrAnalysis
---
llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h b/llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h
index 5323c4e3d1730..547d132671f45 100644
--- a/llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h
+++ b/llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h
@@ -44,6 +44,7 @@ class ExtendedMCInstrAnalysis {
/// Extra semantic information needed from MC layer:
MCPhysReg getStackPointer() const { return MCPB->getStackPointer(); }
+ MCPhysReg getFlagsReg() const { return MCPB->getFlagsReg(); }
bool isPush(const MCInst &Inst) const { return MCPB->isPush(Inst); }
int getPushSize(const MCInst &Inst) const { return MCPB->getPushSize(Inst); }
>From 07d38b246b4f851cc2d3c9656806a5b62fba21a7 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Tue, 20 May 2025 18:29:25 +0000
Subject: [PATCH 20/58] Move the isolated MC semantic methods to
ExtendedMCAnalysis
---
llvm/tools/llvm-mc/CFIAnalysis.h | 350 +++----------------
llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h | 120 +++++++
2 files changed, 162 insertions(+), 308 deletions(-)
diff --git a/llvm/tools/llvm-mc/CFIAnalysis.h b/llvm/tools/llvm-mc/CFIAnalysis.h
index 55a02dcb1013e..57e2b7247b45f 100644
--- a/llvm/tools/llvm-mc/CFIAnalysis.h
+++ b/llvm/tools/llvm-mc/CFIAnalysis.h
@@ -111,127 +111,49 @@ class CFIAnalysis {
}
}
- bool doesConstantChange(const MCInst &Inst, MCPhysReg Reg, int64_t &HowMuch) {
- if (EMCIA->isPush(Inst) && Reg == EMCIA->getStackPointer()) {
- // TODO should get the stack direction here, now it assumes that it goes
- // down.
- HowMuch = -EMCIA->getPushSize(Inst);
- return true;
- }
-
- if (EMCIA->isPop(Inst) && Reg == EMCIA->getStackPointer()) {
- // TODO should get the stack direction here, now it assumes that it goes
- // down.
- HowMuch = EMCIA->getPopSize(Inst);
- return true;
- }
-
- return false;
- }
-
- // Tries to guess Reg1's value in a form of Reg2 (before Inst's execution) +
- // Diff.
- bool isInConstantDistanceOfEachOther(const MCInst &Inst, MCPhysReg &Reg1,
- MCPhysReg Reg2, int &Diff) {
- {
- MCPhysReg From;
- MCPhysReg To;
- if (EMCIA->isRegToRegMove(Inst, From, To) && From == Reg2) {
- Reg1 = To;
- Diff = 0;
- return true;
- }
- }
-
- return false;
- }
+ void update(MCInst &Inst, ArrayRef<MCCFIInstruction> CFIDirectives) {
+ const MCInstrDesc &MCInstInfo = MCII.get(Inst.getOpcode());
+ CFIState AfterState(State);
+ for (auto &&CFIDirective : CFIDirectives)
+ if (!AfterState.apply(CFIDirective))
+ Context.reportWarning(
+ CFIDirective.getLoc(),
+ "I don't support this CFI directive, I assume this does nothing "
+ "(which will probably break other things)");
- bool doStoreFromReg(const MCInst &Inst, MCPhysReg StoringReg,
- MCPhysReg FromReg, int64_t &Offset) {
- if (EMCIA->isPush(Inst) && FromReg == EMCIA->getStackPointer()) {
- // TODO should get the stack direction here, now it assumes that it goes
- // down.
- Offset = -EMCIA->getPushSize(Inst);
- return true;
- }
+ std::set<DWARFRegType> Writes, Reads;
+ for (unsigned I = 0; I < MCInstInfo.NumImplicitUses; I++)
+ Reads.insert(MCRI->getDwarfRegNum(
+ getSuperReg(MCInstInfo.implicit_uses()[I]), false));
+ for (unsigned I = 0; I < MCInstInfo.NumImplicitDefs; I++)
+ Writes.insert(MCRI->getDwarfRegNum(
+ getSuperReg(MCInstInfo.implicit_defs()[I]), false));
- {
- bool IsLoad;
- bool IsStore;
- bool IsStoreFromReg;
- MCPhysReg SrcReg;
- int32_t SrcImm;
- uint16_t StackPtrReg;
- int64_t StackOffset;
- uint8_t Size;
- bool IsSimple;
- bool IsIndexed;
- if (EMCIA->isStackAccess(Inst, IsLoad, IsStore, IsStoreFromReg, SrcReg,
- SrcImm, StackPtrReg, StackOffset, Size, IsSimple,
- IsIndexed)) {
- // TODO make sure that simple means that it's store and does nothing
- // more.
- if (IsStore && IsSimple && StackPtrReg == FromReg && IsStoreFromReg &&
- SrcReg == StoringReg) {
- Offset = StackOffset;
- return true;
- }
+ for (unsigned I = 0; I < Inst.getNumOperands(); I++) {
+ auto &&Operand = Inst.getOperand(I);
+ if (Operand.isReg()) {
+ if (I < MCInstInfo.getNumDefs())
+ Writes.insert(
+ MCRI->getDwarfRegNum(getSuperReg(Operand.getReg()), false));
+ else if (Operand.getReg())
+ Reads.insert(
+ MCRI->getDwarfRegNum(getSuperReg(Operand.getReg()), false));
}
}
- return false;
- }
-
- bool doLoadFromReg(const MCInst &Inst, MCPhysReg FromReg, int64_t &Offset,
- MCPhysReg &LoadingReg) {
- if (EMCIA->isPop(Inst) && FromReg == EMCIA->getStackPointer()) {
- // TODO should get the stack direction here, now it assumes that it goes
- // down.
- Offset = 0;
- LoadingReg = Inst.getOperand(0).getReg();
- return true;
- }
-
- {
- bool IsLoad;
- bool IsStore;
- bool IsStoreFromReg;
- MCPhysReg SrcReg;
- int32_t SrcImm;
- uint16_t StackPtrReg;
- int64_t StackOffset;
- uint8_t Size;
- bool IsSimple;
- bool IsIndexed;
- if (EMCIA->isStackAccess(Inst, IsLoad, IsStore, IsStoreFromReg, SrcReg,
- SrcImm, StackPtrReg, StackOffset, Size, IsSimple,
- IsIndexed)) {
- // TODO make sure that simple means that it's store and does nothing
- // more.
- if (IsLoad && IsSimple && StackPtrReg == FromReg) {
- Offset = StackOffset;
- LoadingReg = SrcReg;
- return true;
- }
- }
- }
+ checkCFADiff(Inst, State, AfterState, Reads, Writes);
- {
- if (EMCIA->isMoveMem2Reg(Inst)) {
- auto X86MemAccess = EMCIA->evaluateX86MemoryOperand(Inst).value();
- if (X86MemAccess.BaseRegNum == FromReg &&
- (X86MemAccess.ScaleImm == 0 || X86MemAccess.IndexRegNum == 0) &&
- !X86MemAccess.DispExpr) {
- LoadingReg = Inst.getOperand(0).getReg();
- Offset = X86MemAccess.DispImm;
- return true;
- }
- }
+ for (auto &&[Reg, RegState] : State.RegisterCFIStates) {
+ assert(AfterState.RegisterCFIStates.count(Reg) &&
+ "Registers' state should not be deleted by CFI instruction.");
+ checkRegDiff(Inst, Reg, State, AfterState, RegState,
+ AfterState.RegisterCFIStates[Reg], Reads, Writes);
}
- return false;
+ State = AfterState;
}
+private:
void checkRegDiff(const MCInst &Inst, DWARFRegType Reg,
const CFIState &PrevState, const CFIState &NextState,
const RegisterCFIState &PrevRegState,
@@ -272,8 +194,8 @@ class CFIAnalysis {
PrevRegState.RetrieveApproach ==
RegisterCFIState::AnotherRegister) {
int64_t OffsetFromCFAReg;
- if (doStoreFromReg(Inst, PrevRefRegLLVM.value(), PrevStateCFARegLLVM,
- OffsetFromCFAReg)) {
+ if (EMCIA->doStoreFromReg(Inst, PrevRefRegLLVM.value(),
+ PrevStateCFARegLLVM, OffsetFromCFAReg)) {
PossibleNextRegStates.push_back(
RegisterCFIState::createOffsetFromCFAAddr(OffsetFromCFAReg -
PrevState.CFAOffset));
@@ -286,8 +208,8 @@ class CFIAnalysis {
RegisterCFIState::OffsetFromCFAAddr) {
int64_t OffsetFromCFAReg;
MCPhysReg ToRegLLVM;
- if (doLoadFromReg(Inst, PrevStateCFARegLLVM, OffsetFromCFAReg,
- ToRegLLVM) &&
+ if (EMCIA->doLoadFromReg(Inst, PrevStateCFARegLLVM, OffsetFromCFAReg,
+ ToRegLLVM) &&
OffsetFromCFAReg - PrevState.CFAOffset ==
PrevRegState.Info.OffsetFromCFA) {
DWARFRegType ToReg = MCRI->getDwarfRegNum(ToRegLLVM, false);
@@ -309,8 +231,8 @@ class CFIAnalysis {
int Diff;
MCPhysReg PossibleRegLLVM;
- if (isInConstantDistanceOfEachOther(Inst, PossibleRegLLVM,
- PrevRefRegLLVM.value(), Diff)) {
+ if (EMCIA->isInConstantDistanceOfEachOther(
+ Inst, PossibleRegLLVM, PrevRefRegLLVM.value(), Diff)) {
DWARFRegType PossibleReg =
MCRI->getDwarfRegNum(PossibleRegLLVM, false);
if (Diff == 0) {
@@ -437,7 +359,7 @@ class CFIAnalysis {
{ // const change
int64_t HowMuch;
- if (doesConstantChange(Inst, PrevCFAPhysReg, HowMuch)) {
+ if (EMCIA->doesConstantChange(Inst, PrevCFAPhysReg, HowMuch)) {
PossibleNextCFAStates.emplace_back(PrevState.CFARegister,
PrevState.CFAOffset - HowMuch);
}
@@ -446,8 +368,8 @@ class CFIAnalysis {
{ // constant distance with each other
int Diff;
MCPhysReg PossibleNewCFAReg;
- if (isInConstantDistanceOfEachOther(Inst, PossibleNewCFAReg,
- PrevCFAPhysReg, Diff)) {
+ if (EMCIA->isInConstantDistanceOfEachOther(Inst, PossibleNewCFAReg,
+ PrevCFAPhysReg, Diff)) {
PossibleNextCFAStates.emplace_back(
MCRI->getDwarfRegNum(PossibleNewCFAReg, false),
PrevState.CFAOffset - Diff);
@@ -516,194 +438,6 @@ class CFIAnalysis {
"assume CFA is preserved.");
// Everything may be ok!
}
-
- void update(MCInst &Inst, ArrayRef<MCCFIInstruction> CFIDirectives) {
- const MCInstrDesc &MCInstInfo = MCII.get(Inst.getOpcode());
- CFIState AfterState(State);
- for (auto &&CFIDirective : CFIDirectives)
- if (!AfterState.apply(CFIDirective))
- Context.reportWarning(
- CFIDirective.getLoc(),
- "I don't support this CFI directive, I assume this does nothing "
- "(which will probably break other things)");
-
- std::set<DWARFRegType> Writes, Reads;
- for (unsigned I = 0; I < MCInstInfo.NumImplicitUses; I++)
- Reads.insert(MCRI->getDwarfRegNum(
- getSuperReg(MCInstInfo.implicit_uses()[I]), false));
- for (unsigned I = 0; I < MCInstInfo.NumImplicitDefs; I++)
- Writes.insert(MCRI->getDwarfRegNum(
- getSuperReg(MCInstInfo.implicit_defs()[I]), false));
-
- for (unsigned I = 0; I < Inst.getNumOperands(); I++) {
- auto &&Operand = Inst.getOperand(I);
- if (Operand.isReg()) {
- if (I < MCInstInfo.getNumDefs())
- Writes.insert(
- MCRI->getDwarfRegNum(getSuperReg(Operand.getReg()), false));
- else if (Operand.getReg())
- Reads.insert(
- MCRI->getDwarfRegNum(getSuperReg(Operand.getReg()), false));
- }
- }
-
- ///////////// being diffing the CFI states
- checkCFADiff(Inst, State, AfterState, Reads, Writes);
-
- for (auto &&[Reg, RegState] : State.RegisterCFIStates) {
- assert(AfterState.RegisterCFIStates.count(Reg) &&
- "Registers' state should not be deleted by CFI instruction.");
- checkRegDiff(Inst, Reg, State, AfterState, RegState,
- AfterState.RegisterCFIStates[Reg], Reads, Writes);
- }
- ///////////// end diffing the CFI states
-
- // dbgs() << "^^^^^^^^^^^^^^^^ InsCFIs ^^^^^^^^^^^^^^^^\n";
- // printUntilNextLine(Inst.getLoc().getPointer());
- // dbgs() << "\n";
- // dbgs() << "Op code: " << Inst.getOpcode() << "\n";
- // dbgs() << "--------------Operands Info--------------\n";
- // auto DefCount = MCInstInfo.getNumDefs();
- // for (unsigned I = 0; I < Inst.getNumOperands(); I++) {
- // dbgs() << "Operand #" << I << ", which will be "
- // << (I < DefCount ? "defined" : "used") << ", is a";
- // if (I == EMCIA->getMemoryOperandNo(Inst)) {
- // dbgs() << " memory access, details are:\n";
- // auto X86MemoryOperand = EMCIA->evaluateX86MemoryOperand(Inst);
- // dbgs() << " Base Register{ reg#" << X86MemoryOperand->BaseRegNum
- // << " }";
- // dbgs() << " + (Index Register{ reg#" <<
- // X86MemoryOperand->IndexRegNum
- // << " }";
- // dbgs() << " * Scale{ value " << X86MemoryOperand->ScaleImm << " }";
- // dbgs() << ") + Displacement{ "
- // << (X86MemoryOperand->DispExpr
- // ? "an expression"
- // : "value " + itostr(X86MemoryOperand->DispImm))
- // << " }\n";
- // // TODO, it's not correct always, it cannot be assumed (or should
- // be
- // // checked) that memory operands are flatten into 4 operands in
- // MCInc. I += 4; continue;
- // }
- // auto &&Operand = Inst.getOperand(I);
- // if (Operand.isImm()) {
- // dbgs() << "n immediate with value " << Operand.getImm() << "\n";
- // continue;
- // }
- // if (Operand.isReg()) {
- // dbgs() << " reg#" << Operand.getReg() << "\n";
- // continue;
- // }
- // assert(Operand.isExpr());
- // dbgs() << "n unknown expression \n";
- // }
- // if (MCInstInfo.NumImplicitDefs) {
- // dbgs() << "implicitly defines: { ";
- // for (unsigned I = 0; I < MCInstInfo.NumImplicitDefs; I++) {
- // dbgs() << "reg#" << MCInstInfo.implicit_defs()[I] << " ";
- // }
- // dbgs() << "}\n";
- // }
- // if (MCInstInfo.NumImplicitUses) {
- // dbgs() << "implicitly uses: { ";
- // for (unsigned I = 0; I < MCInstInfo.NumImplicitUses; I++) {
- // dbgs() << "reg#" << MCInstInfo.implicit_uses()[I] << " ";
- // }
- // dbgs() << "}\n";
- // }
- // dbgs() << "----------------Move Info----------------\n";
- // { // move
- // { // Reg2Reg
- // MCPhysReg From, To;
- // if (EMCIA->isRegToRegMove(Inst, From, To)) {
- // dbgs() << "It's a reg to reg move.\nFrom reg#" << From << " to
- // reg
- // #"
- // << To << "\n";
- // } else if (MCInstInfo.isMoveReg()) {
- // dbgs() << "It's reg to reg move from MCInstInfo view but not from
- // "
- // "MCPlus view.\n";
- // }
- // }
- // if (EMCIA->isConditionalMove(Inst)) {
- // dbgs() << "Its a conditional move.\n";
- // }
- // if (EMCIA->isMoveMem2Reg(Inst)) {
- // dbgs() << "It's a move from memory to register\n";
- // assert(EMCIA->getMemoryOperandNo(Inst) == 1);
- // }
- // }
-
- // dbgs() << "---------------Stack Info----------------\n";
- // { // stack
- // int32_t SrcImm = 0;
- // MCPhysReg Reg = 0;
- // uint16_t StackPtrReg = 0;
- // int64_t StackOffset = 0;
- // uint8_t Size = 0;
- // bool IsSimple = false;
- // bool IsIndexed = false;
- // bool IsLoad = false;
- // bool IsStore = false;
- // bool IsStoreFromReg = false;
- // if (EMCIA->isStackAccess(Inst, IsLoad, IsStore, IsStoreFromReg, Reg,
- // SrcImm, StackPtrReg, StackOffset, Size,
- // IsSimple, IsIndexed)) {
- // dbgs() << "This instruction accesses the stack, the details
- // are:\n"; dbgs() << " Source immediate: " << SrcImm << "\n"; dbgs()
- // << " Source reg#" << Reg << "\n"; dbgs() << " Stack pointer:
- // reg#" << StackPtrReg << "\n"; dbgs() << " Stack offset: " <<
- // StackOffset << "\n"; dbgs() << " size: " << (int)Size << "\n";
- // dbgs() << " Is simple: " << (IsSimple ? "yes" : "no") << "\n";
- // dbgs() << " Is indexed: " << (IsIndexed ? "yes" : "no") << "\n";
- // dbgs() << " Is load: " << (IsLoad ? "yes" : "no") << "\n";
- // dbgs() << " Is store: " << (IsStore ? "yes" : "no") << "\n";
- // dbgs() << " Is store from reg: " << (IsStoreFromReg ? "yes" :
- // "no")
- // << "\n";
- // }
- // if (EMCIA->isPush(Inst)) {
- // dbgs() << "This is a push instruction with size "
- // << EMCIA->getPushSize(Inst) << "\n";
- // }
- // if (EMCIA->isPop(Inst)) {
- // dbgs() << "This is a pop instruction with size "
- // << EMCIA->getPopSize(Inst) << "\n";
- // }
- // }
-
- // dbgs() << "---------------Arith Info----------------\n";
- // { // arith
- // /* MutableArrayRef<MCInst> MAR = {Inst};
- // if (MCPB->matchAdd(MCPB->matchAnyOperand(), MCPB->matchAnyOperand())
- // ->match(*MCRI, *MCPB, MutableArrayRef<MCInst>(), -1)) {
- // dbgs() << "It is an addition instruction.\n";
- // } else */
- // if (MCInstInfo.isAdd()) {
- // dbgs() << "It is an addition from MCInstInfo view but not from
- // MCPlus"
- // "view.\n";
- // }
- // if (EMCIA->isSUB(Inst)) {
- // dbgs() << "This is a subtraction.\n";
- // }
- // }
-
- // dbgs() << "-----------------------------------------\n";
- // dbgs() << "The CFA register is: " << CFAReg << "\n";
- // dbgs() << "The instruction does " << (ChangedCFA ? "" : "NOT ")
- // << "change the CFA.\n";
- // dbgs() << "The CFI directives does " << (GoingToChangeCFA ? "" : "NOT
- // ")
- // << "change the CFA.\n";
- // dbgs() << "vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n";
-
- State = AfterState;
- }
-
-private:
};
} // namespace llvm
diff --git a/llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h b/llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h
index 547d132671f45..dd23063555053 100644
--- a/llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h
+++ b/llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h
@@ -46,6 +46,126 @@ class ExtendedMCInstrAnalysis {
MCPhysReg getStackPointer() const { return MCPB->getStackPointer(); }
MCPhysReg getFlagsReg() const { return MCPB->getFlagsReg(); }
+ bool doesConstantChange(const MCInst &Inst, MCPhysReg Reg, int64_t &HowMuch) {
+ if (isPush(Inst) && Reg == getStackPointer()) {
+ // TODO should get the stack direction here, now it assumes that it goes
+ // down.
+ HowMuch = -getPushSize(Inst);
+ return true;
+ }
+
+ if (isPop(Inst) && Reg == getStackPointer()) {
+ // TODO should get the stack direction here, now it assumes that it goes
+ // down.
+ HowMuch = getPopSize(Inst);
+ return true;
+ }
+
+ return false;
+ }
+
+ // Tries to guess Reg1's value in a form of Reg2 (before Inst's execution) +
+ // Diff.
+ bool isInConstantDistanceOfEachOther(const MCInst &Inst, MCPhysReg &Reg1,
+ MCPhysReg Reg2, int &Diff) {
+ {
+ MCPhysReg From;
+ MCPhysReg To;
+ if (isRegToRegMove(Inst, From, To) && From == Reg2) {
+ Reg1 = To;
+ Diff = 0;
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ bool doStoreFromReg(const MCInst &Inst, MCPhysReg StoringReg,
+ MCPhysReg FromReg, int64_t &Offset) {
+ if (isPush(Inst) && FromReg == getStackPointer()) {
+ // TODO should get the stack direction here, now it assumes that it goes
+ // down.
+ Offset = -getPushSize(Inst);
+ return true;
+ }
+
+ {
+ bool IsLoad;
+ bool IsStore;
+ bool IsStoreFromReg;
+ MCPhysReg SrcReg;
+ int32_t SrcImm;
+ uint16_t StackPtrReg;
+ int64_t StackOffset;
+ uint8_t Size;
+ bool IsSimple;
+ bool IsIndexed;
+ if (isStackAccess(Inst, IsLoad, IsStore, IsStoreFromReg, SrcReg, SrcImm,
+ StackPtrReg, StackOffset, Size, IsSimple, IsIndexed)) {
+ // TODO make sure that simple means that it's store and does nothing
+ // more.
+ if (IsStore && IsSimple && StackPtrReg == FromReg && IsStoreFromReg &&
+ SrcReg == StoringReg) {
+ Offset = StackOffset;
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ bool doLoadFromReg(const MCInst &Inst, MCPhysReg FromReg, int64_t &Offset,
+ MCPhysReg &LoadingReg) {
+ if (isPop(Inst) && FromReg == getStackPointer()) {
+ // TODO should get the stack direction here, now it assumes that it goes
+ // down.
+ Offset = 0;
+ LoadingReg = Inst.getOperand(0).getReg();
+ return true;
+ }
+
+ {
+ bool IsLoad;
+ bool IsStore;
+ bool IsStoreFromReg;
+ MCPhysReg SrcReg;
+ int32_t SrcImm;
+ uint16_t StackPtrReg;
+ int64_t StackOffset;
+ uint8_t Size;
+ bool IsSimple;
+ bool IsIndexed;
+ if (isStackAccess(Inst, IsLoad, IsStore, IsStoreFromReg, SrcReg, SrcImm,
+ StackPtrReg, StackOffset, Size, IsSimple, IsIndexed)) {
+ // TODO make sure that simple means that it's store and does nothing
+ // more.
+ if (IsLoad && IsSimple && StackPtrReg == FromReg) {
+ Offset = StackOffset;
+ LoadingReg = SrcReg;
+ return true;
+ }
+ }
+ }
+
+ {
+ if (isMoveMem2Reg(Inst)) {
+ auto X86MemAccess = evaluateX86MemoryOperand(Inst).value();
+ if (X86MemAccess.BaseRegNum == FromReg &&
+ (X86MemAccess.ScaleImm == 0 || X86MemAccess.IndexRegNum == 0) &&
+ !X86MemAccess.DispExpr) {
+ LoadingReg = Inst.getOperand(0).getReg();
+ Offset = X86MemAccess.DispImm;
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+private:
bool isPush(const MCInst &Inst) const { return MCPB->isPush(Inst); }
int getPushSize(const MCInst &Inst) const { return MCPB->getPushSize(Inst); }
>From eb06aa45be6c44e1a4801f4d7d39d4d6c8de4a56 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Wed, 21 May 2025 17:12:04 +0000
Subject: [PATCH 21/58] Remove unused includes
---
llvm/tools/llvm-mc/CFIState.h | 3 ---
1 file changed, 3 deletions(-)
diff --git a/llvm/tools/llvm-mc/CFIState.h b/llvm/tools/llvm-mc/CFIState.h
index 1b66d0dd40904..4ffcda3c5063a 100644
--- a/llvm/tools/llvm-mc/CFIState.h
+++ b/llvm/tools/llvm-mc/CFIState.h
@@ -2,11 +2,8 @@
#define LLVM_TOOLS_LLVM_MC_CFI_STATE_H
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/StringRef.h"
#include "llvm/MC/MCDwarf.h"
-#include "llvm/MC/MCRegister.h"
#include "llvm/Support/FormatVariadic.h"
-#include "llvm/Support/MathExtras.h"
#include <cassert>
#include <cstdint>
#include <optional>
>From e7c314062fa21d6d040c760948fbb05fe9d2c8a3 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Thu, 22 May 2025 18:40:39 +0000
Subject: [PATCH 22/58] Test cfi validator on following cases: - Changing the
register and not informing it using cfi directives - Changing the CFA and
report it wrong - Load a register from another register stored location
---
.../cfi-validation/single-func-cfa-mistake.s | 33 +++++++++++++
.../single-func-missed-cfi-directive.s | 32 +++++++++++++
.../llvm-mc/cfi-validation/single-func.s | 31 ++++++++++++
.../cfi-validation/spill-two-reg-reversed.s | 47 +++++++++++++++++++
.../llvm-mc/cfi-validation/spill-two-reg.s | 43 +++++++++++++++++
.../cfi-validation/update-with-no-cfi.s | 31 ++++++++++++
6 files changed, 217 insertions(+)
create mode 100644 llvm/test/tools/llvm-mc/cfi-validation/single-func-cfa-mistake.s
create mode 100644 llvm/test/tools/llvm-mc/cfi-validation/single-func-missed-cfi-directive.s
create mode 100644 llvm/test/tools/llvm-mc/cfi-validation/single-func.s
create mode 100644 llvm/test/tools/llvm-mc/cfi-validation/spill-two-reg-reversed.s
create mode 100644 llvm/test/tools/llvm-mc/cfi-validation/spill-two-reg.s
create mode 100644 llvm/test/tools/llvm-mc/cfi-validation/update-with-no-cfi.s
diff --git a/llvm/test/tools/llvm-mc/cfi-validation/single-func-cfa-mistake.s b/llvm/test/tools/llvm-mc/cfi-validation/single-func-cfa-mistake.s
new file mode 100644
index 0000000000000..eb55ff6b378e8
--- /dev/null
+++ b/llvm/test/tools/llvm-mc/cfi-validation/single-func-cfa-mistake.s
@@ -0,0 +1,33 @@
+# RUN: not llvm-mc %s --validate-cfi --filetype=null 2>&1 \
+# RUN: | FileCheck %s
+ .text
+ .globl f
+ .type f, at function
+f:
+ .cfi_startproc
+
+ .cfi_undefined %rax
+
+ pushq %rbp
+ # CHECK: error: Expected CFA [reg: 61, offset: 16] but got [reg: 61, offset: 17]
+ .cfi_def_cfa_offset 17
+ .cfi_offset %rbp, -16
+
+ movq %rsp, %rbp
+ .cfi_def_cfa_register %rbp
+
+ movl %edi, -4(%rbp)
+
+ movl -4(%rbp), %eax
+
+ addl $10, %eax
+
+ popq %rbp
+ .cfi_def_cfa %rsp, 8
+
+ retq
+
+.Lfunc_end0:
+ .size f, .Lfunc_end0-f
+
+ .cfi_endproc
diff --git a/llvm/test/tools/llvm-mc/cfi-validation/single-func-missed-cfi-directive.s b/llvm/test/tools/llvm-mc/cfi-validation/single-func-missed-cfi-directive.s
new file mode 100644
index 0000000000000..044c0bbf88eb6
--- /dev/null
+++ b/llvm/test/tools/llvm-mc/cfi-validation/single-func-missed-cfi-directive.s
@@ -0,0 +1,32 @@
+# RUN: not llvm-mc %s --validate-cfi --filetype=null 2>&1 \
+# RUN: | FileCheck %s
+ .text
+ .globl f
+ .type f, at function
+f:
+ .cfi_startproc
+
+ .cfi_undefined %rax
+
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+
+ movq %rsp, %rbp
+ # CHECK: error: Reg#52 caller's value is in reg#52 which is changed by this instruction, but not changed in CFI directives
+ .cfi_def_cfa_register %rbp
+
+ movl %edi, -4(%rbp)
+
+ movl -4(%rbp), %eax
+
+ addl $10, %eax
+
+ popq %rbp
+ .cfi_def_cfa %rsp, 8
+
+ retq
+
+.Lfunc_end0:
+ .size f, .Lfunc_end0-f
+
+ .cfi_endproc
diff --git a/llvm/test/tools/llvm-mc/cfi-validation/single-func.s b/llvm/test/tools/llvm-mc/cfi-validation/single-func.s
new file mode 100644
index 0000000000000..b2615eafce1d5
--- /dev/null
+++ b/llvm/test/tools/llvm-mc/cfi-validation/single-func.s
@@ -0,0 +1,31 @@
+# RUN: llvm-mc %s --validate-cfi --filetype=null
+ .text
+ .globl f
+ .type f, at function
+f:
+ .cfi_startproc
+
+ .cfi_undefined %rax
+
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset %rbp, -16
+
+ movq %rsp, %rbp
+ .cfi_def_cfa_register %rbp
+
+ movl %edi, -4(%rbp)
+
+ movl -4(%rbp), %eax
+
+ addl $10, %eax
+
+ popq %rbp
+ .cfi_def_cfa %rsp, 8
+
+ retq
+
+.Lfunc_end0:
+ .size f, .Lfunc_end0-f
+
+ .cfi_endproc
diff --git a/llvm/test/tools/llvm-mc/cfi-validation/spill-two-reg-reversed.s b/llvm/test/tools/llvm-mc/cfi-validation/spill-two-reg-reversed.s
new file mode 100644
index 0000000000000..d7baf3e871e87
--- /dev/null
+++ b/llvm/test/tools/llvm-mc/cfi-validation/spill-two-reg-reversed.s
@@ -0,0 +1,47 @@
+# RUN: not llvm-mc %s --validate-cfi --filetype=null 2>&1 \
+# RUN: | FileCheck %s
+ .text
+ .type _start, at function
+ .globl _start
+ .hidden _start
+_start:
+ .cfi_startproc
+
+ .cfi_same_value %rdi
+ .cfi_same_value %rsi
+
+ pushq %rbp
+ .cfi_adjust_cfa_offset 8
+ .cfi_offset %rbp, -16
+
+ movq %rsp, %rbp
+
+ pushq %rdi
+ .cfi_adjust_cfa_offset 8
+ .cfi_rel_offset %rdi, 0
+
+ pushq %rsi
+ .cfi_adjust_cfa_offset 8
+ .cfi_rel_offset %rsi, 0
+
+ popq %rsi
+ # CHECK: warning: The reg#55 CFI state is changed
+ .cfi_adjust_cfa_offset -8
+ .cfi_same_value %rdi
+
+ popq %rdi
+ # CHECK: warning: The reg#60 CFI state is changed
+ # CHECK: Reg#55 caller's value is in reg#55 which is changed by this instruction, but not changed in CFI directives
+ .cfi_adjust_cfa_offset -8
+ .cfi_same_value %rsi
+
+ popq %rbp
+ .cfi_adjust_cfa_offset -8
+ .cfi_same_value %rbp
+
+ retq
+
+ .cfi_endproc
+.Ltmp0:
+ .size _start, .Ltmp0-_start
+ .text
diff --git a/llvm/test/tools/llvm-mc/cfi-validation/spill-two-reg.s b/llvm/test/tools/llvm-mc/cfi-validation/spill-two-reg.s
new file mode 100644
index 0000000000000..70ea3b49d8c75
--- /dev/null
+++ b/llvm/test/tools/llvm-mc/cfi-validation/spill-two-reg.s
@@ -0,0 +1,43 @@
+# RUN: llvm-mc %s --validate-cfi --filetype=null
+ .text
+ .type _start, at function
+ .globl _start
+ .hidden _start
+_start:
+ .cfi_startproc
+
+ .cfi_same_value %rdi
+ .cfi_same_value %rsi
+
+ pushq %rbp
+ .cfi_adjust_cfa_offset 8
+ .cfi_offset %rbp, -16
+
+ movq %rsp, %rbp
+
+ pushq %rdi
+ .cfi_adjust_cfa_offset 8
+ .cfi_rel_offset %rdi, 0
+
+ pushq %rsi
+ .cfi_adjust_cfa_offset 8
+ .cfi_rel_offset %rsi, 0
+
+ popq %rsi
+ .cfi_adjust_cfa_offset -8
+ .cfi_same_value %rsi
+
+ popq %rdi
+ .cfi_adjust_cfa_offset -8
+ .cfi_same_value %rdi
+
+ popq %rbp
+ .cfi_adjust_cfa_offset -8
+ .cfi_same_value %rbp
+
+ retq
+
+ .cfi_endproc
+.Ltmp0:
+ .size _start, .Ltmp0-_start
+ .text
diff --git a/llvm/test/tools/llvm-mc/cfi-validation/update-with-no-cfi.s b/llvm/test/tools/llvm-mc/cfi-validation/update-with-no-cfi.s
new file mode 100644
index 0000000000000..1384d8a864608
--- /dev/null
+++ b/llvm/test/tools/llvm-mc/cfi-validation/update-with-no-cfi.s
@@ -0,0 +1,31 @@
+# RUN: not llvm-mc %s --validate-cfi --filetype=null 2>&1 \
+# RUN: | FileCheck %s
+ .text
+ .globl f
+ .type f, at function
+f:
+ .cfi_startproc
+
+ .cfi_same_value %rax
+ .cfi_same_value %rbx
+ .cfi_same_value %rcx
+ .cfi_same_value %rdx
+
+ movq $10, %rax
+ # CHECK: error: Reg#51 caller's value is in reg#51 which is changed by this instruction, but not changed in CFI directives
+
+ movq $10, %rbx
+ # CHECK: error: Reg#53 caller's value is in reg#53 which is changed by this instruction, but not changed in CFI directives
+
+ movq $10, %rcx
+ # CHECK: error: Reg#54 caller's value is in reg#54 which is changed by this instruction, but not changed in CFI directives
+
+ movq $10, %rdx
+ # CHECK: error: Reg#56 caller's value is in reg#56 which is changed by this instruction, but not changed in CFI directives
+
+ retq
+
+.Lfunc_end0:
+ .size f, .Lfunc_end0-f
+
+ .cfi_endproc
>From 6347ef42e9d4f70b40018da7cc10ae334bbc4a6f Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Thu, 22 May 2025 23:28:16 +0000
Subject: [PATCH 23/58] Prune the CFA diff checker to only check read/write
---
llvm/tools/llvm-mc/CFIAnalysis.h | 183 ++++---------------
llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h | 156 ----------------
2 files changed, 36 insertions(+), 303 deletions(-)
diff --git a/llvm/tools/llvm-mc/CFIAnalysis.h b/llvm/tools/llvm-mc/CFIAnalysis.h
index 57e2b7247b45f..07f7d1e62b73d 100644
--- a/llvm/tools/llvm-mc/CFIAnalysis.h
+++ b/llvm/tools/llvm-mc/CFIAnalysis.h
@@ -51,18 +51,22 @@ class CFIAnalysis {
// not consider that a register spilling.
bool isSuperReg(MCPhysReg Reg) { return MCRI->superregs(Reg).empty(); }
- std::set<MCPhysReg> getAllSuperRegs() {
- std::set<MCPhysReg> SuperRegs;
+ std::vector<std::pair<MCPhysReg, MCRegisterClass const *>> getAllSuperRegs() {
+ std::map<MCPhysReg, MCRegisterClass const *> SuperRegs;
for (auto &&RegClass : MCRI->regclasses()) {
for (unsigned I = 0; I < RegClass.getNumRegs(); I++) {
MCPhysReg Reg = RegClass.getRegister(I);
if (!isSuperReg(Reg))
continue;
- SuperRegs.insert(Reg);
+ SuperRegs[Reg] = &RegClass;
}
}
- return SuperRegs;
+ std::vector<std::pair<MCPhysReg, MCRegisterClass const *>>
+ SuperRegWithClass;
+ for (auto &&[Reg, RegClass] : SuperRegs)
+ SuperRegWithClass.emplace_back(Reg, RegClass);
+ return SuperRegWithClass;
}
MCPhysReg getSuperReg(MCPhysReg Reg) {
@@ -83,22 +87,28 @@ class CFIAnalysis {
: Context(Context), MCII(MCII), MCRI(Context.getRegisterInfo()) {
EMCIA.reset(new ExtendedMCInstrAnalysis(Context, MCII, MCIA));
- // TODO CFA offset should be the slot size, but for now I don't have any
- // access to it, maybe can be read from the prologue
+ MCPhysReg StackPointer = EMCIA->getStackPointer();
+
// TODO check what should be passed as EH?
- State = CFIState(MCRI->getDwarfRegNum(EMCIA->getStackPointer(), false), 8);
- for (MCPhysReg I : getAllSuperRegs()) {
- DWARFRegType DwarfI = MCRI->getDwarfRegNum(I, false);
- State.RegisterCFIStates[DwarfI] = RegisterCFIState::createSameValue();
+ State = CFIState(MCRI->getDwarfRegNum(StackPointer, false), 0);
+ for (auto &&[Reg, RegClass] : getAllSuperRegs()) {
+ if (MCRI->get(Reg).IsArtificial || MCRI->get(Reg).IsConstant)
+ continue;
+
+ if (Reg == StackPointer)
+ State.CFAOffset = RegClass->getSizeInBits() / 8;
+
+ DWARFRegType DwarfReg = MCRI->getDwarfRegNum(Reg, false);
+ State.RegisterCFIStates[DwarfReg] = RegisterCFIState::createSameValue();
}
// TODO these are temporay added to make things work.
// Setup the basic information:
State.RegisterCFIStates[MCRI->getDwarfRegNum(MCRI->getProgramCounter(),
false)] =
- RegisterCFIState::createUndefined(); // For now, we don't care about the
- // PC
- State.RegisterCFIStates[MCRI->getDwarfRegNum(EMCIA->getStackPointer(),
+ RegisterCFIState::createUndefined(); // TODO for now, we don't care
+ // about the PC
+ State.RegisterCFIStates[MCRI->getDwarfRegNum(StackPointer,
false)] =
RegisterCFIState::createOffsetFromCFAVal(0); // sp's old value is CFA
@@ -169,8 +179,6 @@ class CFIAnalysis {
auto &&PrevRefReg =
PrevState.getReferenceRegisterForCallerValueOfRegister(Reg);
- auto &&NextRefReg =
- NextState.getReferenceRegisterForCallerValueOfRegister(Reg);
std::optional<MCPhysReg> PrevRefRegLLVM =
(PrevRefReg != std::nullopt
@@ -189,64 +197,6 @@ class CFIAnalysis {
{ // try generate
// Widen
std::vector<RegisterCFIState> PossibleNextRegStates;
- { // storing to offset from CFA
- if (PrevRegState.RetrieveApproach == RegisterCFIState::SameValue ||
- PrevRegState.RetrieveApproach ==
- RegisterCFIState::AnotherRegister) {
- int64_t OffsetFromCFAReg;
- if (EMCIA->doStoreFromReg(Inst, PrevRefRegLLVM.value(),
- PrevStateCFARegLLVM, OffsetFromCFAReg)) {
- PossibleNextRegStates.push_back(
- RegisterCFIState::createOffsetFromCFAAddr(OffsetFromCFAReg -
- PrevState.CFAOffset));
- }
- }
- }
-
- { // loading from an offset from CFA
- if (PrevRegState.RetrieveApproach ==
- RegisterCFIState::OffsetFromCFAAddr) {
- int64_t OffsetFromCFAReg;
- MCPhysReg ToRegLLVM;
- if (EMCIA->doLoadFromReg(Inst, PrevStateCFARegLLVM, OffsetFromCFAReg,
- ToRegLLVM) &&
- OffsetFromCFAReg - PrevState.CFAOffset ==
- PrevRegState.Info.OffsetFromCFA) {
- DWARFRegType ToReg = MCRI->getDwarfRegNum(ToRegLLVM, false);
- if (ToReg == Reg) {
- PossibleNextRegStates.push_back(
- RegisterCFIState::createSameValue());
- } else {
- PossibleNextRegStates.push_back(
- RegisterCFIState::createAnotherRegister(ToReg));
- }
- }
- }
- }
-
- { // moved from reg to other reg
- if (PrevRegState.RetrieveApproach == RegisterCFIState::SameValue ||
- PrevRegState.RetrieveApproach ==
- RegisterCFIState::AnotherRegister) {
-
- int Diff;
- MCPhysReg PossibleRegLLVM;
- if (EMCIA->isInConstantDistanceOfEachOther(
- Inst, PossibleRegLLVM, PrevRefRegLLVM.value(), Diff)) {
- DWARFRegType PossibleReg =
- MCRI->getDwarfRegNum(PossibleRegLLVM, false);
- if (Diff == 0) {
- if (PossibleReg == Reg) {
- PossibleNextRegStates.push_back(
- RegisterCFIState::createSameValue());
- } else {
- PossibleNextRegStates.push_back(
- RegisterCFIState::createAnotherRegister(PossibleReg));
- }
- }
- }
- }
- }
{ // stay the same
bool CanStayTheSame = false;
@@ -342,71 +292,18 @@ class CFIAnalysis {
const CFIState &NextState,
const std::set<DWARFRegType> &Reads,
const std::set<DWARFRegType> &Writes) {
- MCPhysReg PrevCFAPhysReg =
- MCRI->getLLVMRegNum(PrevState.CFARegister, false).value();
- MCPhysReg NextCFAPhysReg =
- MCRI->getLLVMRegNum(NextState.CFARegister, false).value();
-
- { // try generate
- // Widen
- std::vector<std::pair<DWARFRegType, int>> PossibleNextCFAStates;
- { // no change
- if (!Writes.count(PrevState.CFARegister)) {
- PossibleNextCFAStates.emplace_back(PrevState.CFARegister,
- PrevState.CFAOffset);
- }
- }
-
- { // const change
- int64_t HowMuch;
- if (EMCIA->doesConstantChange(Inst, PrevCFAPhysReg, HowMuch)) {
- PossibleNextCFAStates.emplace_back(PrevState.CFARegister,
- PrevState.CFAOffset - HowMuch);
- }
- }
-
- { // constant distance with each other
- int Diff;
- MCPhysReg PossibleNewCFAReg;
- if (EMCIA->isInConstantDistanceOfEachOther(Inst, PossibleNewCFAReg,
- PrevCFAPhysReg, Diff)) {
- PossibleNextCFAStates.emplace_back(
- MCRI->getDwarfRegNum(PossibleNewCFAReg, false),
- PrevState.CFAOffset - Diff);
- }
- }
-
- for (auto &&[PossibleNextCFAReg, PossibleNextCFAOffset] :
- PossibleNextCFAStates) {
- if (PossibleNextCFAReg != NextState.CFARegister)
- continue;
-
- if (PossibleNextCFAOffset == NextState.CFAOffset) {
- // Everything is ok!
- return;
- }
-
- Context.reportError(Inst.getLoc(),
- formatv("Expected CFA [reg: {0}, offset: {1}] but "
- "got [reg: {2}, offset: {3}].",
- NextCFAPhysReg, PossibleNextCFAOffset,
- NextCFAPhysReg, NextState.CFAOffset));
- return;
- }
- }
-
- // Either couldn't generate, or did, but the programmer wants to change
- // the source of register for CFA to something not expected by the
- // generator. So it falls back into read/write checks.
+ const char *PrevCFARegName = MCRI->getName(
+ MCRI->getLLVMRegNum(PrevState.CFARegister, false).value());
if (PrevState.CFARegister == NextState.CFARegister) {
if (PrevState.CFAOffset == NextState.CFAOffset) {
if (Writes.count(PrevState.CFARegister)) {
Context.reportError(
Inst.getLoc(),
- formatv("This instruction changes reg#{0}, which is "
- "the CFA register, but the CFI directives do not.",
- PrevCFAPhysReg));
+ formatv(
+ "Missing CFI directive for the CFA offset adjustment. CFA "
+ "register ({0}) is modified by this instruction.",
+ PrevCFARegName));
return;
}
@@ -418,25 +315,17 @@ class CFIAnalysis {
if (!Writes.count(PrevState.CFARegister)) {
Context.reportError(
Inst.getLoc(),
- formatv(
- "You changed the CFA offset, but there is no modification to "
- "the CFA register happening in this instruction."));
+ formatv("Wrong adjustment to CFA offset. CFA register ({0}) is not "
+ "modified by this instruction.",
+ PrevCFARegName));
}
- Context.reportWarning(
- Inst.getLoc(),
- "I don't know what the instruction did, but it changed the CFA "
- "reg's "
- "value, and the offset is changed as well by the CFI directives.");
- // Everything may be ok!
+ // The CFA register value is changed, and the offset is changed as well,
+ // everything may be ok.
return;
}
- // The CFA register is changed
- Context.reportWarning(
- Inst.getLoc(), "The CFA register is changed to something, and I don't "
- "have any idea on the new register relevance to CFA. I "
- "assume CFA is preserved.");
- // Everything may be ok!
+
+ // The CFA register is changed, everything may be ok.
}
};
diff --git a/llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h b/llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h
index dd23063555053..be6aa7d3faa41 100644
--- a/llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h
+++ b/llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h
@@ -12,9 +12,7 @@
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/TargetRegistry.h"
-#include <cstdint>
#include <memory>
-#include <optional>
namespace llvm {
@@ -45,160 +43,6 @@ class ExtendedMCInstrAnalysis {
MCPhysReg getStackPointer() const { return MCPB->getStackPointer(); }
MCPhysReg getFlagsReg() const { return MCPB->getFlagsReg(); }
-
- bool doesConstantChange(const MCInst &Inst, MCPhysReg Reg, int64_t &HowMuch) {
- if (isPush(Inst) && Reg == getStackPointer()) {
- // TODO should get the stack direction here, now it assumes that it goes
- // down.
- HowMuch = -getPushSize(Inst);
- return true;
- }
-
- if (isPop(Inst) && Reg == getStackPointer()) {
- // TODO should get the stack direction here, now it assumes that it goes
- // down.
- HowMuch = getPopSize(Inst);
- return true;
- }
-
- return false;
- }
-
- // Tries to guess Reg1's value in a form of Reg2 (before Inst's execution) +
- // Diff.
- bool isInConstantDistanceOfEachOther(const MCInst &Inst, MCPhysReg &Reg1,
- MCPhysReg Reg2, int &Diff) {
- {
- MCPhysReg From;
- MCPhysReg To;
- if (isRegToRegMove(Inst, From, To) && From == Reg2) {
- Reg1 = To;
- Diff = 0;
- return true;
- }
- }
-
- return false;
- }
-
- bool doStoreFromReg(const MCInst &Inst, MCPhysReg StoringReg,
- MCPhysReg FromReg, int64_t &Offset) {
- if (isPush(Inst) && FromReg == getStackPointer()) {
- // TODO should get the stack direction here, now it assumes that it goes
- // down.
- Offset = -getPushSize(Inst);
- return true;
- }
-
- {
- bool IsLoad;
- bool IsStore;
- bool IsStoreFromReg;
- MCPhysReg SrcReg;
- int32_t SrcImm;
- uint16_t StackPtrReg;
- int64_t StackOffset;
- uint8_t Size;
- bool IsSimple;
- bool IsIndexed;
- if (isStackAccess(Inst, IsLoad, IsStore, IsStoreFromReg, SrcReg, SrcImm,
- StackPtrReg, StackOffset, Size, IsSimple, IsIndexed)) {
- // TODO make sure that simple means that it's store and does nothing
- // more.
- if (IsStore && IsSimple && StackPtrReg == FromReg && IsStoreFromReg &&
- SrcReg == StoringReg) {
- Offset = StackOffset;
- return true;
- }
- }
- }
-
- return false;
- }
-
- bool doLoadFromReg(const MCInst &Inst, MCPhysReg FromReg, int64_t &Offset,
- MCPhysReg &LoadingReg) {
- if (isPop(Inst) && FromReg == getStackPointer()) {
- // TODO should get the stack direction here, now it assumes that it goes
- // down.
- Offset = 0;
- LoadingReg = Inst.getOperand(0).getReg();
- return true;
- }
-
- {
- bool IsLoad;
- bool IsStore;
- bool IsStoreFromReg;
- MCPhysReg SrcReg;
- int32_t SrcImm;
- uint16_t StackPtrReg;
- int64_t StackOffset;
- uint8_t Size;
- bool IsSimple;
- bool IsIndexed;
- if (isStackAccess(Inst, IsLoad, IsStore, IsStoreFromReg, SrcReg, SrcImm,
- StackPtrReg, StackOffset, Size, IsSimple, IsIndexed)) {
- // TODO make sure that simple means that it's store and does nothing
- // more.
- if (IsLoad && IsSimple && StackPtrReg == FromReg) {
- Offset = StackOffset;
- LoadingReg = SrcReg;
- return true;
- }
- }
- }
-
- {
- if (isMoveMem2Reg(Inst)) {
- auto X86MemAccess = evaluateX86MemoryOperand(Inst).value();
- if (X86MemAccess.BaseRegNum == FromReg &&
- (X86MemAccess.ScaleImm == 0 || X86MemAccess.IndexRegNum == 0) &&
- !X86MemAccess.DispExpr) {
- LoadingReg = Inst.getOperand(0).getReg();
- Offset = X86MemAccess.DispImm;
- return true;
- }
- }
- }
-
- return false;
- }
-
-private:
- bool isPush(const MCInst &Inst) const { return MCPB->isPush(Inst); }
- int getPushSize(const MCInst &Inst) const { return MCPB->getPushSize(Inst); }
-
- bool isPop(const MCInst &Inst) const { return MCPB->isPop(Inst); }
- int getPopSize(const MCInst &Inst) const { return MCPB->getPopSize(Inst); }
-
- bool isRegToRegMove(const MCInst &Inst, MCPhysReg &From,
- MCPhysReg &To) const {
- return MCPB->isRegToRegMove(Inst, From, To);
- }
- bool isConditionalMove(const MCInst &Inst) const {
- return MCPB->isConditionalMove(Inst);
- }
- bool isMoveMem2Reg(const MCInst &Inst) const {
- return MCPB->isMoveMem2Reg(Inst);
- }
- bool isSUB(const MCInst &Inst) const { return MCPB->isSUB(Inst); }
-
- int getMemoryOperandNo(const MCInst &Inst) const {
- return MCPB->getMemoryOperandNo(Inst);
- }
- std::optional<bolt::MCPlusBuilder::X86MemOperand>
- evaluateX86MemoryOperand(const MCInst &Inst) const {
- return MCPB->evaluateX86MemoryOperand(Inst);
- }
- bool isStackAccess(const MCInst &Inst, bool &IsLoad, bool &IsStore,
- bool &IsStoreFromReg, MCPhysReg &Reg, int32_t &SrcImm,
- uint16_t &StackPtrReg, int64_t &StackOffset, uint8_t &Size,
- bool &IsSimple, bool &IsIndexed) const {
- return MCPB->isStackAccess(Inst, IsLoad, IsStore, IsStoreFromReg, Reg,
- SrcImm, StackPtrReg, StackOffset, Size, IsSimple,
- IsIndexed);
- }
};
} // namespace llvm
>From 453917b195481ee9124169913834e535f54363c0 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Fri, 23 May 2025 22:11:21 +0000
Subject: [PATCH 24/58] Move the CFI analysis headers to MC
---
.../llvm/MC/MCCFIAnalysis}/CFIAnalysis.h | 2 -
.../MC/MCCFIAnalysis}/CFIAnalysisMCStreamer.h | 0
llvm/include/llvm/MC/MCCFIAnalysis/CFIState.h | 63 +++++
.../MCCFIAnalysis/ExtendedMCInstrAnalysis.h | 28 +++
llvm/lib/MC/CFIAnalysis/CFIState.cpp | 195 ++++++++++++++++
llvm/lib/MC/CFIAnalysis/CMakeLists.txt | 10 +
llvm/lib/MC/CMakeLists.txt | 1 +
llvm/tools/llvm-mc/CFIState.h | 220 ------------------
llvm/tools/llvm-mc/CMakeLists.txt | 3 +-
llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h | 50 ----
llvm/tools/llvm-mc/llvm-mc.cpp | 2 +-
11 files changed, 299 insertions(+), 275 deletions(-)
rename llvm/{tools/llvm-mc => include/llvm/MC/MCCFIAnalysis}/CFIAnalysis.h (99%)
rename llvm/{tools/llvm-mc => include/llvm/MC/MCCFIAnalysis}/CFIAnalysisMCStreamer.h (100%)
create mode 100644 llvm/include/llvm/MC/MCCFIAnalysis/CFIState.h
create mode 100644 llvm/include/llvm/MC/MCCFIAnalysis/ExtendedMCInstrAnalysis.h
create mode 100644 llvm/lib/MC/CFIAnalysis/CFIState.cpp
create mode 100644 llvm/lib/MC/CFIAnalysis/CMakeLists.txt
delete mode 100644 llvm/tools/llvm-mc/CFIState.h
delete mode 100644 llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h
diff --git a/llvm/tools/llvm-mc/CFIAnalysis.h b/llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysis.h
similarity index 99%
rename from llvm/tools/llvm-mc/CFIAnalysis.h
rename to llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysis.h
index 07f7d1e62b73d..14c054b1cad3d 100644
--- a/llvm/tools/llvm-mc/CFIAnalysis.h
+++ b/llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysis.h
@@ -3,7 +3,6 @@
#include "CFIState.h"
#include "ExtendedMCInstrAnalysis.h"
-#include "bolt/Core/MCPlusBuilder.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
@@ -21,7 +20,6 @@
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormatVariadic.h"
-#include <cstdint>
#include <memory>
#include <optional>
#include <set>
diff --git a/llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h b/llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysisMCStreamer.h
similarity index 100%
rename from llvm/tools/llvm-mc/CFIAnalysisMCStreamer.h
rename to llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysisMCStreamer.h
diff --git a/llvm/include/llvm/MC/MCCFIAnalysis/CFIState.h b/llvm/include/llvm/MC/MCCFIAnalysis/CFIState.h
new file mode 100644
index 0000000000000..6ddd4916b5315
--- /dev/null
+++ b/llvm/include/llvm/MC/MCCFIAnalysis/CFIState.h
@@ -0,0 +1,63 @@
+#ifndef LLVM_TOOLS_LLVM_MC_CFI_STATE_H
+#define LLVM_TOOLS_LLVM_MC_CFI_STATE_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/MC/MCDwarf.h"
+#include "llvm/Support/FormatVariadic.h"
+#include <cassert>
+#include <cstdint>
+#include <optional>
+#include <string>
+namespace llvm {
+
+using DWARFRegType = int64_t;
+
+struct RegisterCFIState {
+ enum Approach {
+ Undefined,
+ SameValue,
+ AnotherRegister,
+ OffsetFromCFAAddr,
+ OffsetFromCFAVal,
+ Other,
+ } RetrieveApproach;
+
+ union {
+ int OffsetFromCFA;
+ DWARFRegType Register;
+ } Info;
+
+ // TODO change it to be like other dump methods
+ std::string dump();
+
+ bool operator==(const RegisterCFIState &OtherState) const;
+ bool operator!=(const RegisterCFIState &OtherState) const;
+
+ static RegisterCFIState createUndefined();
+ static RegisterCFIState createSameValue();
+ static RegisterCFIState createAnotherRegister(DWARFRegType Register);
+ static RegisterCFIState createOffsetFromCFAAddr(int OffsetFromCFA);
+ static RegisterCFIState createOffsetFromCFAVal(int OffsetFromCFA);
+ static RegisterCFIState createOther();
+};
+
+struct CFIState {
+ DenseMap<DWARFRegType, RegisterCFIState> RegisterCFIStates;
+ DWARFRegType CFARegister;
+ int CFAOffset;
+
+ CFIState();
+ CFIState(const CFIState &Other);
+
+ CFIState &operator=(const CFIState &Other);
+
+ CFIState(DWARFRegType CFARegister, int CFIOffset);
+
+ std::optional<DWARFRegType>
+ getReferenceRegisterForCallerValueOfRegister(DWARFRegType Reg) const;
+
+ bool apply(const MCCFIInstruction &CFIDirective);
+};
+} // namespace llvm
+
+#endif
\ No newline at end of file
diff --git a/llvm/include/llvm/MC/MCCFIAnalysis/ExtendedMCInstrAnalysis.h b/llvm/include/llvm/MC/MCCFIAnalysis/ExtendedMCInstrAnalysis.h
new file mode 100644
index 0000000000000..6d050a4defbcc
--- /dev/null
+++ b/llvm/include/llvm/MC/MCCFIAnalysis/ExtendedMCInstrAnalysis.h
@@ -0,0 +1,28 @@
+#ifndef LLVM_TOOLS_LLVM_MC_EXTENDED_MC_INSTR_ANALYSIS_H
+#define LLVM_TOOLS_LLVM_MC_EXTENDED_MC_INSTR_ANALYSIS_H
+
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDwarf.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCRegister.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/TargetRegistry.h"
+
+namespace llvm {
+
+class ExtendedMCInstrAnalysis {
+private:
+public:
+ ExtendedMCInstrAnalysis(MCContext &Context, MCInstrInfo const &MCII,
+ MCInstrAnalysis *MCIA) {}
+
+ /// Extra semantic information needed from MC layer:
+
+ MCPhysReg getStackPointer() const { return 61; }
+ MCPhysReg getFlagsReg() const { return 57; }
+};
+
+} // namespace llvm
+
+#endif
\ No newline at end of file
diff --git a/llvm/lib/MC/CFIAnalysis/CFIState.cpp b/llvm/lib/MC/CFIAnalysis/CFIState.cpp
new file mode 100644
index 0000000000000..8a5efe31a2826
--- /dev/null
+++ b/llvm/lib/MC/CFIAnalysis/CFIState.cpp
@@ -0,0 +1,195 @@
+#include "llvm/MC/MCCFIAnalysis/CFIState.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/MC/MCDwarf.h"
+#include "llvm/Support/FormatVariadic.h"
+#include <cassert>
+#include <cstdint>
+#include <optional>
+#include <string>
+
+using namespace llvm;
+
+using DWARFRegType = int64_t;
+
+std::string RegisterCFIState::dump() {
+ switch (RetrieveApproach) {
+ case Undefined:
+ return "undefined";
+ case SameValue:
+ return "same value";
+ case AnotherRegister:
+ return formatv("stored in another register, which is reg#{0}",
+ Info.Register);
+ case OffsetFromCFAAddr:
+ return formatv("offset {0} from CFA", Info.OffsetFromCFA);
+ case OffsetFromCFAVal:
+ return formatv("CFA value + {0}", Info.OffsetFromCFA);
+ case Other:
+ return "other";
+ }
+}
+
+bool RegisterCFIState::operator==(const RegisterCFIState &OtherState) const {
+ if (RetrieveApproach != OtherState.RetrieveApproach)
+ return false;
+
+ switch (RetrieveApproach) {
+ case Undefined:
+ case SameValue:
+ case Other:
+ return true;
+ case AnotherRegister:
+ return Info.Register == OtherState.Info.Register;
+ case OffsetFromCFAAddr:
+ case OffsetFromCFAVal:
+ return Info.OffsetFromCFA == OtherState.Info.OffsetFromCFA;
+ }
+}
+
+bool RegisterCFIState::operator!=(const RegisterCFIState &OtherState) const {
+ return !(*this == OtherState);
+}
+
+RegisterCFIState RegisterCFIState::createUndefined() {
+ RegisterCFIState State;
+ State.RetrieveApproach = Undefined;
+
+ return State;
+}
+
+RegisterCFIState RegisterCFIState::createSameValue() {
+ RegisterCFIState State;
+ State.RetrieveApproach = SameValue;
+
+ return State;
+}
+
+RegisterCFIState
+RegisterCFIState::createAnotherRegister(DWARFRegType Register) {
+ RegisterCFIState State;
+ State.RetrieveApproach = AnotherRegister;
+ State.Info.Register = Register;
+
+ return State;
+}
+
+RegisterCFIState RegisterCFIState::createOffsetFromCFAAddr(int OffsetFromCFA) {
+ RegisterCFIState State;
+ State.RetrieveApproach = OffsetFromCFAAddr;
+ State.Info.OffsetFromCFA = OffsetFromCFA;
+
+ return State;
+}
+
+RegisterCFIState RegisterCFIState::createOffsetFromCFAVal(int OffsetFromCFA) {
+ RegisterCFIState State;
+ State.RetrieveApproach = OffsetFromCFAVal;
+ State.Info.OffsetFromCFA = OffsetFromCFA;
+
+ return State;
+}
+
+RegisterCFIState RegisterCFIState::createOther() {
+ RegisterCFIState State;
+ State.RetrieveApproach = Other;
+
+ return State;
+}
+
+CFIState::CFIState() : CFARegister(-1), CFAOffset(-1) {}
+
+CFIState::CFIState(const CFIState &Other) {
+ CFARegister = Other.CFARegister;
+ CFAOffset = Other.CFAOffset;
+ RegisterCFIStates = Other.RegisterCFIStates;
+}
+
+CFIState &CFIState::operator=(const CFIState &Other) {
+ if (this != &Other) {
+ CFARegister = Other.CFARegister;
+ CFAOffset = Other.CFAOffset;
+ RegisterCFIStates = Other.RegisterCFIStates;
+ }
+
+ return *this;
+}
+
+CFIState::CFIState(DWARFRegType CFARegister, int CFIOffset)
+ : CFARegister(CFARegister), CFAOffset(CFIOffset) {}
+
+std::optional<DWARFRegType>
+CFIState::getReferenceRegisterForCallerValueOfRegister(DWARFRegType Reg) const {
+ assert(RegisterCFIStates.count(Reg) &&
+ "The register should be tracked inside the register states");
+ auto &&RegState = RegisterCFIStates.at(Reg);
+ switch (RegState.RetrieveApproach) {
+ case RegisterCFIState::Undefined:
+ case RegisterCFIState::Other:
+ return std::nullopt;
+ case RegisterCFIState::SameValue:
+ return Reg;
+ case RegisterCFIState::AnotherRegister:
+ return RegState.Info.Register;
+ case RegisterCFIState::OffsetFromCFAAddr:
+ case RegisterCFIState::OffsetFromCFAVal:
+ return CFARegister;
+ }
+}
+
+bool CFIState::apply(const MCCFIInstruction &CFIDirective) {
+ switch (CFIDirective.getOperation()) {
+ case MCCFIInstruction::OpDefCfaRegister:
+ CFARegister = CFIDirective.getRegister();
+ break;
+ case MCCFIInstruction::OpDefCfaOffset:
+ CFAOffset = CFIDirective.getOffset();
+ break;
+ case MCCFIInstruction::OpAdjustCfaOffset:
+ CFAOffset += CFIDirective.getOffset();
+ break;
+ case MCCFIInstruction::OpDefCfa:
+ CFARegister = CFIDirective.getRegister();
+ CFAOffset = CFIDirective.getOffset();
+ break;
+ case MCCFIInstruction::OpOffset:
+ RegisterCFIStates[CFIDirective.getRegister()] =
+ RegisterCFIState::createOffsetFromCFAAddr(CFIDirective.getOffset());
+ break;
+ case MCCFIInstruction::OpRegister:
+ RegisterCFIStates[CFIDirective.getRegister()] =
+ RegisterCFIState::createAnotherRegister(CFIDirective.getRegister2());
+ break;
+ case MCCFIInstruction::OpRelOffset:
+ RegisterCFIStates[CFIDirective.getRegister()] =
+ RegisterCFIState::createOffsetFromCFAAddr(CFIDirective.getOffset() -
+ CFAOffset);
+ break;
+ case MCCFIInstruction::OpUndefined:
+ RegisterCFIStates[CFIDirective.getRegister()] =
+ RegisterCFIState::createUndefined();
+ break;
+ case MCCFIInstruction::OpSameValue:
+ RegisterCFIStates[CFIDirective.getRegister()] =
+ RegisterCFIState::createSameValue();
+ break;
+ case MCCFIInstruction::OpValOffset:
+ RegisterCFIStates[CFIDirective.getRegister()] =
+ RegisterCFIState::createOffsetFromCFAVal(CFIDirective.getOffset());
+ break;
+ case MCCFIInstruction::OpRestoreState:
+ case MCCFIInstruction::OpRememberState:
+ case MCCFIInstruction::OpLLVMDefAspaceCfa:
+ case MCCFIInstruction::OpRestore:
+ case MCCFIInstruction::OpEscape:
+ case MCCFIInstruction::OpWindowSave:
+ case MCCFIInstruction::OpNegateRAState:
+ case MCCFIInstruction::OpNegateRAStateWithPC:
+ case MCCFIInstruction::OpGnuArgsSize:
+ case MCCFIInstruction::OpLabel:
+ // These instructions are not supported.
+ return false;
+ break;
+ }
+
+ return true;
+}
diff --git a/llvm/lib/MC/CFIAnalysis/CMakeLists.txt b/llvm/lib/MC/CFIAnalysis/CMakeLists.txt
new file mode 100644
index 0000000000000..0bc829c754092
--- /dev/null
+++ b/llvm/lib/MC/CFIAnalysis/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_llvm_component_library(LLVMMCCFIAnalysis
+ CFIState.cpp
+ # CFIAnalysisMCStreamer.cpp
+ # CFIAnalysis.cpp
+ # ExtendedMCInstrAnalysis.cpp
+
+ LINK_COMPONENTS
+ MC
+ Support
+ )
diff --git a/llvm/lib/MC/CMakeLists.txt b/llvm/lib/MC/CMakeLists.txt
index f49f14c848b90..8f8637bd8580b 100644
--- a/llvm/lib/MC/CMakeLists.txt
+++ b/llvm/lib/MC/CMakeLists.txt
@@ -87,3 +87,4 @@ add_llvm_component_library(LLVMMC
add_subdirectory(MCParser)
add_subdirectory(MCDisassembler)
+add_subdirectory(CFIAnalysis)
diff --git a/llvm/tools/llvm-mc/CFIState.h b/llvm/tools/llvm-mc/CFIState.h
deleted file mode 100644
index 4ffcda3c5063a..0000000000000
--- a/llvm/tools/llvm-mc/CFIState.h
+++ /dev/null
@@ -1,220 +0,0 @@
-#ifndef LLVM_TOOLS_LLVM_MC_CFI_STATE_H
-#define LLVM_TOOLS_LLVM_MC_CFI_STATE_H
-
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/MC/MCDwarf.h"
-#include "llvm/Support/FormatVariadic.h"
-#include <cassert>
-#include <cstdint>
-#include <optional>
-#include <string>
-namespace llvm {
-
-using DWARFRegType = int64_t;
-
-struct RegisterCFIState {
- enum Approach {
- Undefined,
- SameValue,
- AnotherRegister,
- OffsetFromCFAAddr,
- OffsetFromCFAVal,
- Other,
- } RetrieveApproach;
-
- // TODO use a correct type for this.
- union {
- int OffsetFromCFA;
- DWARFRegType Register;
- } Info;
-
- std::string dump() {
- switch (RetrieveApproach) {
- case Undefined:
- return "undefined";
- case SameValue:
- return "same value";
- case AnotherRegister:
- return formatv("stored in another register, which is reg#{0}",
- Info.Register);
- case OffsetFromCFAAddr:
- return formatv("offset {0} from CFA", Info.OffsetFromCFA);
- case OffsetFromCFAVal:
- return formatv("CFA value + {0}", Info.OffsetFromCFA);
- case Other:
- return "other";
- }
- }
-
- bool operator==(const RegisterCFIState &OtherState) const {
- if (RetrieveApproach != OtherState.RetrieveApproach)
- return false;
-
- switch (RetrieveApproach) {
- case Undefined:
- case SameValue:
- case Other:
- return true;
- case AnotherRegister:
- return Info.Register == OtherState.Info.Register;
- case OffsetFromCFAAddr:
- case OffsetFromCFAVal:
- return Info.OffsetFromCFA == OtherState.Info.OffsetFromCFA;
- }
- }
-
- bool operator!=(const RegisterCFIState &OtherState) const {
- return !(*this == OtherState);
- }
-
- static RegisterCFIState createUndefined() {
- RegisterCFIState State;
- State.RetrieveApproach = Undefined;
-
- return State;
- }
-
- static RegisterCFIState createSameValue() {
- RegisterCFIState State;
- State.RetrieveApproach = SameValue;
-
- return State;
- }
-
- static RegisterCFIState createAnotherRegister(DWARFRegType Register) {
- RegisterCFIState State;
- State.RetrieveApproach = AnotherRegister;
- State.Info.Register = Register;
-
- return State;
- }
-
- static RegisterCFIState createOffsetFromCFAAddr(int OffsetFromCFA) {
- RegisterCFIState State;
- State.RetrieveApproach = OffsetFromCFAAddr;
- State.Info.OffsetFromCFA = OffsetFromCFA;
-
- return State;
- }
-
- static RegisterCFIState createOffsetFromCFAVal(int OffsetFromCFA) {
- RegisterCFIState State;
- State.RetrieveApproach = OffsetFromCFAVal;
- State.Info.OffsetFromCFA = OffsetFromCFA;
-
- return State;
- }
-
- static RegisterCFIState createOther() {
- RegisterCFIState State;
- State.RetrieveApproach = Other;
-
- return State;
- }
-};
-struct CFIState {
- DenseMap<DWARFRegType, RegisterCFIState> RegisterCFIStates;
- DWARFRegType CFARegister;
- int CFAOffset;
-
- CFIState() : CFARegister(-1), CFAOffset(-1) {}
-
- CFIState(const CFIState &Other) {
- CFARegister = Other.CFARegister;
- CFAOffset = Other.CFAOffset;
- RegisterCFIStates = Other.RegisterCFIStates;
- }
-
- CFIState &operator=(const CFIState &Other) {
- if (this != &Other) {
- CFARegister = Other.CFARegister;
- CFAOffset = Other.CFAOffset;
- RegisterCFIStates = Other.RegisterCFIStates;
- }
-
- return *this;
- }
-
- CFIState(DWARFRegType CFARegister, int CFIOffset)
- : CFARegister(CFARegister), CFAOffset(CFIOffset) {}
-
- std::optional<DWARFRegType>
- getReferenceRegisterForCallerValueOfRegister(DWARFRegType Reg) const {
- assert(RegisterCFIStates.count(Reg) &&
- "The register should be tracked inside the register states");
- auto &&RegState = RegisterCFIStates.at(Reg);
- switch (RegState.RetrieveApproach) {
- case RegisterCFIState::Undefined:
- case RegisterCFIState::Other:
- return std::nullopt;
- case RegisterCFIState::SameValue:
- return Reg;
- case RegisterCFIState::AnotherRegister:
- return RegState.Info.Register;
- case RegisterCFIState::OffsetFromCFAAddr:
- case RegisterCFIState::OffsetFromCFAVal:
- return CFARegister;
- }
- }
-
- bool apply(const MCCFIInstruction &CFIDirective) {
- switch (CFIDirective.getOperation()) {
- case MCCFIInstruction::OpDefCfaRegister:
- CFARegister = CFIDirective.getRegister();
- break;
- case MCCFIInstruction::OpDefCfaOffset:
- CFAOffset = CFIDirective.getOffset();
- break;
- case MCCFIInstruction::OpAdjustCfaOffset:
- CFAOffset += CFIDirective.getOffset();
- break;
- case MCCFIInstruction::OpDefCfa:
- CFARegister = CFIDirective.getRegister();
- CFAOffset = CFIDirective.getOffset();
- break;
- case MCCFIInstruction::OpOffset:
- RegisterCFIStates[CFIDirective.getRegister()] =
- RegisterCFIState::createOffsetFromCFAAddr(CFIDirective.getOffset());
- break;
- case MCCFIInstruction::OpRegister:
- RegisterCFIStates[CFIDirective.getRegister()] =
- RegisterCFIState::createAnotherRegister(CFIDirective.getRegister2());
- break;
- case MCCFIInstruction::OpRelOffset:
- RegisterCFIStates[CFIDirective.getRegister()] =
- RegisterCFIState::createOffsetFromCFAAddr(CFIDirective.getOffset() -
- CFAOffset);
- break;
- case MCCFIInstruction::OpUndefined:
- RegisterCFIStates[CFIDirective.getRegister()] =
- RegisterCFIState::createUndefined();
- break;
- case MCCFIInstruction::OpSameValue:
- RegisterCFIStates[CFIDirective.getRegister()] =
- RegisterCFIState::createSameValue();
- break;
- case MCCFIInstruction::OpValOffset:
- RegisterCFIStates[CFIDirective.getRegister()] =
- RegisterCFIState::createOffsetFromCFAVal(CFIDirective.getOffset());
- break;
- case MCCFIInstruction::OpRestoreState:
- case MCCFIInstruction::OpRememberState:
- case MCCFIInstruction::OpLLVMDefAspaceCfa:
- case MCCFIInstruction::OpRestore:
- case MCCFIInstruction::OpEscape:
- case MCCFIInstruction::OpWindowSave:
- case MCCFIInstruction::OpNegateRAState:
- case MCCFIInstruction::OpNegateRAStateWithPC:
- case MCCFIInstruction::OpGnuArgsSize:
- case MCCFIInstruction::OpLabel:
- // These instructions are not supported.
- return false;
- break;
- }
-
- return true;
- }
-};
-} // namespace llvm
-
-#endif
\ No newline at end of file
diff --git a/llvm/tools/llvm-mc/CMakeLists.txt b/llvm/tools/llvm-mc/CMakeLists.txt
index 368f29c62201f..83c40d1cd2122 100644
--- a/llvm/tools/llvm-mc/CMakeLists.txt
+++ b/llvm/tools/llvm-mc/CMakeLists.txt
@@ -4,6 +4,7 @@ set(LLVM_LINK_COMPONENTS
AllTargetsDisassemblers
AllTargetsInfos
MC
+ MCCFIAnalysis
MCParser
Support
TargetParser
@@ -14,5 +15,3 @@ add_llvm_tool(llvm-mc
Disassembler.cpp
)
-target_link_libraries(llvm-mc PRIVATE LLVMBOLTCore LLVMBOLTTargetX86)
-target_include_directories(llvm-mc PRIVATE "${LLVM_MAIN_SRC_DIR}/../bolt/include")
diff --git a/llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h b/llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h
deleted file mode 100644
index be6aa7d3faa41..0000000000000
--- a/llvm/tools/llvm-mc/ExtendedMCInstrAnalysis.h
+++ /dev/null
@@ -1,50 +0,0 @@
-#ifndef LLVM_TOOLS_LLVM_MC_EXTENDED_MC_INSTR_ANALYSIS_H
-#define LLVM_TOOLS_LLVM_MC_EXTENDED_MC_INSTR_ANALYSIS_H
-
-#include "bolt/Core/MCPlusBuilder.h"
-#include "llvm/MC/MCContext.h"
-#include "llvm/MC/MCDwarf.h"
-#include "llvm/MC/MCExpr.h"
-#include "llvm/MC/MCInst.h"
-#include "llvm/MC/MCInstrInfo.h"
-#include "llvm/MC/MCRegister.h"
-#include "llvm/MC/MCRegisterInfo.h"
-#include "llvm/MC/MCStreamer.h"
-#include "llvm/MC/MCSubtargetInfo.h"
-#include "llvm/MC/TargetRegistry.h"
-#include <memory>
-
-namespace llvm {
-
-class ExtendedMCInstrAnalysis {
-private:
- std::unique_ptr<bolt::MCPlusBuilder> MCPB;
-
- static bolt::MCPlusBuilder *
- createMCPlusBuilder(const Triple::ArchType Arch,
- const MCInstrAnalysis *Analysis, const MCInstrInfo *Info,
- const MCRegisterInfo *RegInfo,
- const MCSubtargetInfo *STI) {
- if (Arch == Triple::x86_64)
- return bolt::createX86MCPlusBuilder(Analysis, Info, RegInfo, STI);
-
- llvm_unreachable("architecture unsupported by ExtendedMCInstrAnalysis");
- }
-
-public:
- ExtendedMCInstrAnalysis(MCContext &Context, MCInstrInfo const &MCII,
- MCInstrAnalysis *MCIA) {
- MCPB.reset(createMCPlusBuilder(Context.getTargetTriple().getArch(), MCIA,
- &MCII, Context.getRegisterInfo(),
- Context.getSubtargetInfo()));
- }
-
- /// Extra semantic information needed from MC layer:
-
- MCPhysReg getStackPointer() const { return MCPB->getStackPointer(); }
- MCPhysReg getFlagsReg() const { return MCPB->getFlagsReg(); }
-};
-
-} // namespace llvm
-
-#endif
\ No newline at end of file
diff --git a/llvm/tools/llvm-mc/llvm-mc.cpp b/llvm/tools/llvm-mc/llvm-mc.cpp
index ca4f71cb9cabd..2f1d6cb42aa0b 100644
--- a/llvm/tools/llvm-mc/llvm-mc.cpp
+++ b/llvm/tools/llvm-mc/llvm-mc.cpp
@@ -11,10 +11,10 @@
//
//===----------------------------------------------------------------------===//
-#include "CFIAnalysisMCStreamer.h"
#include "Disassembler.h"
#include "llvm/MC/MCAsmBackend.h"
#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCCFIAnalysis/CFIAnalysisMCStreamer.h"
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCInstPrinter.h"
>From 9f8bca8b87462d09e9f970ff6019b7c201f348e6 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Tue, 27 May 2025 17:51:21 +0000
Subject: [PATCH 25/58] Move all the CFI analysis implementations to lib
---
.../llvm/MC/MCCFIAnalysis/CFIAnalysis.h | 279 +---------------
.../MC/MCCFIAnalysis/CFIAnalysisMCStreamer.h | 119 +------
llvm/include/llvm/MC/MCCFIAnalysis/CFIState.h | 3 -
llvm/lib/MC/CFIAnalysis/CFIAnalysis.cpp | 310 ++++++++++++++++++
.../MC/CFIAnalysis/CFIAnalysisMCStreamer.cpp | 131 ++++++++
llvm/lib/MC/CFIAnalysis/CFIState.cpp | 1 +
llvm/lib/MC/CFIAnalysis/CMakeLists.txt | 5 +-
7 files changed, 469 insertions(+), 379 deletions(-)
create mode 100644 llvm/lib/MC/CFIAnalysis/CFIAnalysis.cpp
create mode 100644 llvm/lib/MC/CFIAnalysis/CFIAnalysisMCStreamer.cpp
diff --git a/llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysis.h b/llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysis.h
index 14c054b1cad3d..8c70764cdde2d 100644
--- a/llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysis.h
+++ b/llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysis.h
@@ -5,8 +5,6 @@
#include "ExtendedMCInstrAnalysis.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/ADT/Twine.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDwarf.h"
#include "llvm/MC/MCExpr.h"
@@ -17,21 +15,11 @@
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/TargetRegistry.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/FormatVariadic.h"
#include <memory>
-#include <optional>
#include <set>
namespace llvm {
-// TODO remove it, it's just for debug purposes.
-void printUntilNextLine(const char *Str) {
- for (int I = 0; Str[I] != '\0' && Str[I] != '\n'; I++)
- dbgs() << Str[I];
-}
-
class CFIAnalysis {
MCContext &Context;
MCInstrInfo const &MCII;
@@ -47,119 +35,18 @@ class CFIAnalysis {
// register.
// As en example, if you spill a sub register to stack, the CFI analysis does
// not consider that a register spilling.
- bool isSuperReg(MCPhysReg Reg) { return MCRI->superregs(Reg).empty(); }
-
- std::vector<std::pair<MCPhysReg, MCRegisterClass const *>> getAllSuperRegs() {
- std::map<MCPhysReg, MCRegisterClass const *> SuperRegs;
- for (auto &&RegClass : MCRI->regclasses()) {
- for (unsigned I = 0; I < RegClass.getNumRegs(); I++) {
- MCPhysReg Reg = RegClass.getRegister(I);
- if (!isSuperReg(Reg))
- continue;
- SuperRegs[Reg] = &RegClass;
- }
- }
-
- std::vector<std::pair<MCPhysReg, MCRegisterClass const *>>
- SuperRegWithClass;
- for (auto &&[Reg, RegClass] : SuperRegs)
- SuperRegWithClass.emplace_back(Reg, RegClass);
- return SuperRegWithClass;
- }
+ bool isSuperReg(MCPhysReg Reg);
- MCPhysReg getSuperReg(MCPhysReg Reg) {
- if (isSuperReg(Reg))
- return Reg;
- for (auto SuperReg : MCRI->superregs(Reg)) {
- if (isSuperReg(SuperReg))
- return SuperReg;
- }
+ SmallVector<std::pair<MCPhysReg, MCRegisterClass const *>> getAllSuperRegs();
- llvm_unreachable("Should either be a super reg, or have a super reg");
- }
+ MCPhysReg getSuperReg(MCPhysReg Reg);
public:
CFIAnalysis(MCContext &Context, MCInstrInfo const &MCII,
MCInstrAnalysis *MCIA,
- ArrayRef<MCCFIInstruction> PrologueCFIDirectives)
- : Context(Context), MCII(MCII), MCRI(Context.getRegisterInfo()) {
- EMCIA.reset(new ExtendedMCInstrAnalysis(Context, MCII, MCIA));
-
- MCPhysReg StackPointer = EMCIA->getStackPointer();
-
- // TODO check what should be passed as EH?
- State = CFIState(MCRI->getDwarfRegNum(StackPointer, false), 0);
- for (auto &&[Reg, RegClass] : getAllSuperRegs()) {
- if (MCRI->get(Reg).IsArtificial || MCRI->get(Reg).IsConstant)
- continue;
-
- if (Reg == StackPointer)
- State.CFAOffset = RegClass->getSizeInBits() / 8;
-
- DWARFRegType DwarfReg = MCRI->getDwarfRegNum(Reg, false);
- State.RegisterCFIStates[DwarfReg] = RegisterCFIState::createSameValue();
- }
-
- // TODO these are temporay added to make things work.
- // Setup the basic information:
- State.RegisterCFIStates[MCRI->getDwarfRegNum(MCRI->getProgramCounter(),
- false)] =
- RegisterCFIState::createUndefined(); // TODO for now, we don't care
- // about the PC
- State.RegisterCFIStates[MCRI->getDwarfRegNum(StackPointer,
- false)] =
- RegisterCFIState::createOffsetFromCFAVal(0); // sp's old value is CFA
-
- State.RegisterCFIStates[MCRI->getDwarfRegNum(EMCIA->getFlagsReg(), false)] =
- RegisterCFIState::createUndefined(); // Flags cannot be caller-saved
+ ArrayRef<MCCFIInstruction> PrologueCFIDirectives);
- // Applying the prologue after default assumptions to overwrite them.
- for (auto &&PrologueCFIDirective : PrologueCFIDirectives) {
- State.apply(PrologueCFIDirective);
- }
- }
-
- void update(MCInst &Inst, ArrayRef<MCCFIInstruction> CFIDirectives) {
- const MCInstrDesc &MCInstInfo = MCII.get(Inst.getOpcode());
- CFIState AfterState(State);
- for (auto &&CFIDirective : CFIDirectives)
- if (!AfterState.apply(CFIDirective))
- Context.reportWarning(
- CFIDirective.getLoc(),
- "I don't support this CFI directive, I assume this does nothing "
- "(which will probably break other things)");
-
- std::set<DWARFRegType> Writes, Reads;
- for (unsigned I = 0; I < MCInstInfo.NumImplicitUses; I++)
- Reads.insert(MCRI->getDwarfRegNum(
- getSuperReg(MCInstInfo.implicit_uses()[I]), false));
- for (unsigned I = 0; I < MCInstInfo.NumImplicitDefs; I++)
- Writes.insert(MCRI->getDwarfRegNum(
- getSuperReg(MCInstInfo.implicit_defs()[I]), false));
-
- for (unsigned I = 0; I < Inst.getNumOperands(); I++) {
- auto &&Operand = Inst.getOperand(I);
- if (Operand.isReg()) {
- if (I < MCInstInfo.getNumDefs())
- Writes.insert(
- MCRI->getDwarfRegNum(getSuperReg(Operand.getReg()), false));
- else if (Operand.getReg())
- Reads.insert(
- MCRI->getDwarfRegNum(getSuperReg(Operand.getReg()), false));
- }
- }
-
- checkCFADiff(Inst, State, AfterState, Reads, Writes);
-
- for (auto &&[Reg, RegState] : State.RegisterCFIStates) {
- assert(AfterState.RegisterCFIStates.count(Reg) &&
- "Registers' state should not be deleted by CFI instruction.");
- checkRegDiff(Inst, Reg, State, AfterState, RegState,
- AfterState.RegisterCFIStates[Reg], Reads, Writes);
- }
-
- State = AfterState;
- }
+ void update(MCInst &Inst, ArrayRef<MCCFIInstruction> CFIDirectives);
private:
void checkRegDiff(const MCInst &Inst, DWARFRegType Reg,
@@ -167,164 +54,12 @@ class CFIAnalysis {
const RegisterCFIState &PrevRegState,
const RegisterCFIState &NextRegState,
const std::set<DWARFRegType> &Reads,
- const std::set<DWARFRegType> &Writes) {
- auto RegLLVMOpt = MCRI->getLLVMRegNum(Reg, false);
- if (RegLLVMOpt == std::nullopt) {
- assert(PrevRegState == NextRegState);
- return;
- }
- MCPhysReg RegLLVM = RegLLVMOpt.value();
-
- auto &&PrevRefReg =
- PrevState.getReferenceRegisterForCallerValueOfRegister(Reg);
-
- std::optional<MCPhysReg> PrevRefRegLLVM =
- (PrevRefReg != std::nullopt
- ? std::make_optional(
- MCRI->getLLVMRegNum(PrevRefReg.value(), false).value())
- : std::nullopt);
- std::optional<MCPhysReg> NextRefRegLLVM =
- (PrevRefReg != std::nullopt
- ? std::make_optional(
- MCRI->getLLVMRegNum(PrevRefReg.value(), false).value())
- : std::nullopt);
-
- MCPhysReg PrevStateCFARegLLVM =
- MCRI->getLLVMRegNum(PrevState.CFARegister, false).value();
-
- { // try generate
- // Widen
- std::vector<RegisterCFIState> PossibleNextRegStates;
-
- { // stay the same
- bool CanStayTheSame = false;
-
- switch (PrevRegState.RetrieveApproach) {
- case RegisterCFIState::Undefined:
- case RegisterCFIState::OffsetFromCFAVal:
- CanStayTheSame = true;
- break;
- case RegisterCFIState::SameValue:
- case RegisterCFIState::AnotherRegister:
- CanStayTheSame = !Writes.count(PrevRefReg.value());
- break;
- case RegisterCFIState::OffsetFromCFAAddr:
- case RegisterCFIState::Other:
- // cannot be sure
- break;
- }
-
- if (CanStayTheSame)
- PossibleNextRegStates.push_back(PrevRegState);
- }
-
- for (auto &&PossibleNextRegState : PossibleNextRegStates) {
- if (PossibleNextRegState == NextRegState) {
- // Everything is ok
- return;
- }
- }
-
- for (auto &&PossibleNextRegState : PossibleNextRegStates) {
- if (PossibleNextRegState.RetrieveApproach !=
- NextRegState.RetrieveApproach)
- continue;
-
- if (PossibleNextRegState.RetrieveApproach ==
- RegisterCFIState::OffsetFromCFAAddr) {
- Context.reportError(
- Inst.getLoc(),
- formatv(
- "Expected caller's value of reg#{0} should be at offset {1} "
- "of CFA but the CFI directives say it's in {2}",
- RegLLVM, PossibleNextRegState.Info.OffsetFromCFA,
- NextRegState.Info.OffsetFromCFA));
- }
- }
- }
- // Either couldn't generate, or the programmer changed the state to
- // something that couldn't be matched to any of the generated states. So
- // it falls back into read/write checks.
-
- if (PrevRegState == NextRegState) {
- switch (PrevRegState.RetrieveApproach) {
- case RegisterCFIState::SameValue:
- case RegisterCFIState::AnotherRegister:
- if (Writes.count(PrevRefReg.value())) {
- Context.reportError(
- Inst.getLoc(),
- formatv("Reg#{0} caller's value is in reg#{1} which is changed "
- "by this instruction, but not changed in CFI directives",
- RegLLVM, PrevRefRegLLVM.value()));
- return;
- }
- break;
- default:
- // Everything may be ok
- break;
- }
- return;
- }
-
- if (PrevRegState.RetrieveApproach == NextRegState.RetrieveApproach) {
- // Everything may be ok
- return;
- }
-
- if (PrevRegState.RetrieveApproach == RegisterCFIState::Undefined) {
- Context.reportError(Inst.getLoc(),
- "Cannot change a register CFI information from "
- "undefined to something else.");
- return;
- }
-
- Context.reportWarning(Inst.getLoc(),
- formatv("The reg#{0} CFI state is changed, but I "
- "don't have any idea how.",
- RegLLVM));
- // Everything may be ok
- return;
- }
+ const std::set<DWARFRegType> &Writes);
void checkCFADiff(const MCInst &Inst, const CFIState &PrevState,
const CFIState &NextState,
const std::set<DWARFRegType> &Reads,
- const std::set<DWARFRegType> &Writes) {
- const char *PrevCFARegName = MCRI->getName(
- MCRI->getLLVMRegNum(PrevState.CFARegister, false).value());
-
- if (PrevState.CFARegister == NextState.CFARegister) {
- if (PrevState.CFAOffset == NextState.CFAOffset) {
- if (Writes.count(PrevState.CFARegister)) {
- Context.reportError(
- Inst.getLoc(),
- formatv(
- "Missing CFI directive for the CFA offset adjustment. CFA "
- "register ({0}) is modified by this instruction.",
- PrevCFARegName));
- return;
- }
-
- // Everything is ok!
- return;
- }
- // The offset is changed.
-
- if (!Writes.count(PrevState.CFARegister)) {
- Context.reportError(
- Inst.getLoc(),
- formatv("Wrong adjustment to CFA offset. CFA register ({0}) is not "
- "modified by this instruction.",
- PrevCFARegName));
- }
-
- // The CFA register value is changed, and the offset is changed as well,
- // everything may be ok.
- return;
- }
-
- // The CFA register is changed, everything may be ok.
- }
+ const std::set<DWARFRegType> &Writes);
};
} // namespace llvm
diff --git a/llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysisMCStreamer.h b/llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysisMCStreamer.h
index 7f79653004e5e..a42215685396e 100644
--- a/llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysisMCStreamer.h
+++ b/llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysisMCStreamer.h
@@ -21,10 +21,9 @@ class CFIAnalysisMCStreamer : public MCStreamer {
struct CFIDirectivesState {
int DirectiveIndex;
- CFIDirectivesState() : DirectiveIndex(0) {}
+ CFIDirectivesState();
- CFIDirectivesState(int FrameIndex, int InstructionIndex)
- : DirectiveIndex(InstructionIndex) {}
+ CFIDirectivesState(int FrameIndex, int InstructionIndex);
} LastCFIDirectivesState;
std::vector<int> FrameIndices;
std::vector<CFIAnalysis> CFIAs;
@@ -33,116 +32,34 @@ class CFIAnalysisMCStreamer : public MCStreamer {
MCInst Instruction;
std::pair<unsigned, unsigned> CFIDirectivesRange;
- ICFI(MCInst Instruction, std::pair<unsigned, unsigned> CFIDirectives)
- : Instruction(Instruction), CFIDirectivesRange(CFIDirectives) {}
+ ICFI(MCInst Instruction, std::pair<unsigned, unsigned> CFIDirectives);
};
std::optional<MCInst> LastInstruction;
- std::pair<unsigned, unsigned> getCFIDirectivesRange() {
- auto DwarfFrameInfos = getDwarfFrameInfos();
- int FrameIndex = FrameIndices.back();
- auto CurrentCFIDirectiveState =
- hasUnfinishedDwarfFrameInfo()
- ? CFIDirectivesState(
- FrameIndex, DwarfFrameInfos[FrameIndex].Instructions.size())
- : CFIDirectivesState();
- assert(CurrentCFIDirectiveState.DirectiveIndex >=
- LastCFIDirectivesState.DirectiveIndex);
+ std::pair<unsigned, unsigned> getCFIDirectivesRange();
- std::pair<unsigned, unsigned> CFIDirectivesRange(
- LastCFIDirectivesState.DirectiveIndex,
- CurrentCFIDirectiveState.DirectiveIndex);
- LastCFIDirectivesState = CurrentCFIDirectiveState;
- return CFIDirectivesRange;
- }
-
- void feedCFIA() {
- auto FrameIndex = FrameIndices.back();
- if (FrameIndex < 0) {
- // TODO Maybe this corner case causes bugs, when the programmer did a
- // mistake in the startproc, endprocs and also made a mistake in not
- // adding cfi directives for a instruction. Then this would cause to
- // ignore the instruction.
- auto CFIDirectivesRange = getCFIDirectivesRange();
- assert(!LastInstruction ||
- CFIDirectivesRange.first == CFIDirectivesRange.second);
- return;
- }
-
- // TODO get this from emit yourself, instead of getting it in this way
- const auto *LastDwarfFrameInfo = &getDwarfFrameInfos()[FrameIndex];
-
- auto CFIDirectivesRange = getCFIDirectivesRange();
- ArrayRef<MCCFIInstruction> CFIDirectives;
- if (CFIDirectivesRange.first < CFIDirectivesRange.second) {
- CFIDirectives =
- ArrayRef<MCCFIInstruction>(LastDwarfFrameInfo->Instructions);
- CFIDirectives = CFIDirectives.drop_front(CFIDirectivesRange.first)
- .drop_back(LastDwarfFrameInfo->Instructions.size() -
- CFIDirectivesRange.second);
- }
-
- if (LastInstruction != std::nullopt) {
- assert(!CFIAs.empty());
-
- CFIAs.back().update(LastInstruction.value(), CFIDirectives);
- } else {
- CFIAs.emplace_back(getContext(), MCII, MCIA.get(), CFIDirectives);
- }
- }
+ void feedCFIA();
public:
CFIAnalysisMCStreamer(MCContext &Context, const MCInstrInfo &MCII,
- std::unique_ptr<MCInstrAnalysis> MCIA)
- : MCStreamer(Context), MCII(MCII), MCIA(std::move(MCIA)),
- LastCFIDirectivesState(), LastInstruction(std::nullopt) {
- FrameIndices.push_back(-1);
- }
-
- bool hasRawTextSupport() const override { return true; }
- void emitRawTextImpl(StringRef String) override {}
-
- bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override {
- return true;
- }
+ std::unique_ptr<MCInstrAnalysis> MCIA);
+ bool hasRawTextSupport() const override;
+ void emitRawTextImpl(StringRef String) override;
+ bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override;
void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
- Align ByteAlignment) override {}
- void beginCOFFSymbolDef(const MCSymbol *Symbol) override {}
- void emitCOFFSymbolStorageClass(int StorageClass) override {}
- void emitCOFFSymbolType(int Type) override {}
- void endCOFFSymbolDef() override {}
+ Align ByteAlignment) override;
+ void beginCOFFSymbolDef(const MCSymbol *Symbol) override;
+ void emitCOFFSymbolStorageClass(int StorageClass) override;
+ void emitCOFFSymbolType(int Type) override;
+ void endCOFFSymbolDef() override;
void emitXCOFFSymbolLinkageWithVisibility(MCSymbol *Symbol,
MCSymbolAttr Linkage,
- MCSymbolAttr Visibility) override {}
-
- void emitInstruction(const MCInst &Inst,
- const MCSubtargetInfo &STI) override {
- feedCFIA();
- LastInstruction = Inst;
- }
-
- void emitCFIStartProcImpl(MCDwarfFrameInfo &Frame) override {
- feedCFIA();
- FrameIndices.push_back(getNumFrameInfos());
- LastInstruction = std::nullopt;
- LastCFIDirectivesState.DirectiveIndex = 0;
- MCStreamer::emitCFIStartProcImpl(Frame);
- }
-
- void emitCFIEndProcImpl(MCDwarfFrameInfo &CurFrame) override {
- feedCFIA();
- // TODO this will break if the input frame are malformed.
- FrameIndices.pop_back();
- CFIAs.pop_back();
- LastInstruction = std::nullopt;
- auto FrameIndex = FrameIndices.back();
- LastCFIDirectivesState.DirectiveIndex =
- FrameIndex >= 0 ? getDwarfFrameInfos()[FrameIndex].Instructions.size()
- : 0;
- MCStreamer::emitCFIEndProcImpl(CurFrame);
- }
+ MCSymbolAttr Visibility) override;
+ void emitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI) override;
+ void emitCFIStartProcImpl(MCDwarfFrameInfo &Frame) override;
+ void emitCFIEndProcImpl(MCDwarfFrameInfo &CurFrame) override;
};
} // namespace llvm
diff --git a/llvm/include/llvm/MC/MCCFIAnalysis/CFIState.h b/llvm/include/llvm/MC/MCCFIAnalysis/CFIState.h
index 6ddd4916b5315..3141f65e642b4 100644
--- a/llvm/include/llvm/MC/MCCFIAnalysis/CFIState.h
+++ b/llvm/include/llvm/MC/MCCFIAnalysis/CFIState.h
@@ -3,9 +3,6 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/MC/MCDwarf.h"
-#include "llvm/Support/FormatVariadic.h"
-#include <cassert>
-#include <cstdint>
#include <optional>
#include <string>
namespace llvm {
diff --git a/llvm/lib/MC/CFIAnalysis/CFIAnalysis.cpp b/llvm/lib/MC/CFIAnalysis/CFIAnalysis.cpp
new file mode 100644
index 0000000000000..8a50fce8e4da9
--- /dev/null
+++ b/llvm/lib/MC/CFIAnalysis/CFIAnalysis.cpp
@@ -0,0 +1,310 @@
+#include "llvm/MC/MCCFIAnalysis/CFIAnalysis.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/MC/MCCFIAnalysis/ExtendedMCInstrAnalysis.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDwarf.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCRegister.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/TargetRegistry.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FormatVariadic.h"
+#include <memory>
+#include <optional>
+#include <set>
+
+using namespace llvm;
+
+// TODO remove it, it's just for debug purposes.
+void printUntilNextLine(const char *Str) {
+ for (int I = 0; Str[I] != '\0' && Str[I] != '\n'; I++)
+ dbgs() << Str[I];
+}
+
+bool CFIAnalysis::isSuperReg(MCPhysReg Reg) {
+ return MCRI->superregs(Reg).empty();
+}
+
+SmallVector<std::pair<MCPhysReg, MCRegisterClass const *>>
+CFIAnalysis::getAllSuperRegs() {
+ std::map<MCPhysReg, MCRegisterClass const *> SuperRegs;
+ for (auto &&RegClass : MCRI->regclasses()) {
+ for (unsigned I = 0; I < RegClass.getNumRegs(); I++) {
+ MCPhysReg Reg = RegClass.getRegister(I);
+ if (!isSuperReg(Reg))
+ continue;
+ SuperRegs[Reg] = &RegClass;
+ }
+ }
+
+ SmallVector<std::pair<MCPhysReg, MCRegisterClass const *>> SuperRegWithClass;
+ for (auto &&[Reg, RegClass] : SuperRegs)
+ SuperRegWithClass.emplace_back(Reg, RegClass);
+ return SuperRegWithClass;
+}
+
+MCPhysReg CFIAnalysis::getSuperReg(MCPhysReg Reg) {
+ if (isSuperReg(Reg))
+ return Reg;
+ for (auto SuperReg : MCRI->superregs(Reg)) {
+ if (isSuperReg(SuperReg))
+ return SuperReg;
+ }
+
+ llvm_unreachable("Should either be a super reg, or have a super reg");
+}
+
+CFIAnalysis::CFIAnalysis(MCContext &Context, MCInstrInfo const &MCII,
+ MCInstrAnalysis *MCIA,
+ ArrayRef<MCCFIInstruction> PrologueCFIDirectives)
+ : Context(Context), MCII(MCII), MCRI(Context.getRegisterInfo()) {
+ EMCIA.reset(new ExtendedMCInstrAnalysis(Context, MCII, MCIA));
+
+ MCPhysReg StackPointer = EMCIA->getStackPointer();
+
+ // TODO check what should be passed as EH?
+ State = CFIState(MCRI->getDwarfRegNum(StackPointer, false), 0);
+ for (auto &&[Reg, RegClass] : getAllSuperRegs()) {
+ if (MCRI->get(Reg).IsArtificial || MCRI->get(Reg).IsConstant)
+ continue;
+
+ if (Reg == StackPointer)
+ State.CFAOffset = RegClass->getSizeInBits() / 8;
+
+ DWARFRegType DwarfReg = MCRI->getDwarfRegNum(Reg, false);
+ State.RegisterCFIStates[DwarfReg] = RegisterCFIState::createSameValue();
+ }
+
+ // TODO these are temporay added to make things work.
+ // Setup the basic information:
+ State.RegisterCFIStates[MCRI->getDwarfRegNum(MCRI->getProgramCounter(),
+ false)] =
+ RegisterCFIState::createUndefined(); // TODO for now, we don't care
+ // about the PC
+ State.RegisterCFIStates[MCRI->getDwarfRegNum(StackPointer,
+ false)] =
+ RegisterCFIState::createOffsetFromCFAVal(0); // sp's old value is CFA
+
+ State.RegisterCFIStates[MCRI->getDwarfRegNum(EMCIA->getFlagsReg(), false)] =
+ RegisterCFIState::createUndefined(); // Flags cannot be caller-saved
+
+ // Applying the prologue after default assumptions to overwrite them.
+ for (auto &&PrologueCFIDirective : PrologueCFIDirectives) {
+ State.apply(PrologueCFIDirective);
+ }
+}
+
+void CFIAnalysis::update(MCInst &Inst,
+ ArrayRef<MCCFIInstruction> CFIDirectives) {
+ const MCInstrDesc &MCInstInfo = MCII.get(Inst.getOpcode());
+ CFIState AfterState(State);
+ for (auto &&CFIDirective : CFIDirectives)
+ if (!AfterState.apply(CFIDirective))
+ Context.reportWarning(
+ CFIDirective.getLoc(),
+ "I don't support this CFI directive, I assume this does nothing "
+ "(which will probably break other things)");
+
+ std::set<DWARFRegType> Writes, Reads;
+ for (unsigned I = 0; I < MCInstInfo.NumImplicitUses; I++)
+ Reads.insert(MCRI->getDwarfRegNum(
+ getSuperReg(MCInstInfo.implicit_uses()[I]), false));
+ for (unsigned I = 0; I < MCInstInfo.NumImplicitDefs; I++)
+ Writes.insert(MCRI->getDwarfRegNum(
+ getSuperReg(MCInstInfo.implicit_defs()[I]), false));
+
+ for (unsigned I = 0; I < Inst.getNumOperands(); I++) {
+ auto &&Operand = Inst.getOperand(I);
+ if (Operand.isReg()) {
+ if (I < MCInstInfo.getNumDefs())
+ Writes.insert(
+ MCRI->getDwarfRegNum(getSuperReg(Operand.getReg()), false));
+ else if (Operand.getReg())
+ Reads.insert(
+ MCRI->getDwarfRegNum(getSuperReg(Operand.getReg()), false));
+ }
+ }
+
+ checkCFADiff(Inst, State, AfterState, Reads, Writes);
+
+ for (auto &&[Reg, RegState] : State.RegisterCFIStates) {
+ assert(AfterState.RegisterCFIStates.count(Reg) &&
+ "Registers' state should not be deleted by CFI instruction.");
+ checkRegDiff(Inst, Reg, State, AfterState, RegState,
+ AfterState.RegisterCFIStates[Reg], Reads, Writes);
+ }
+
+ State = AfterState;
+}
+
+void CFIAnalysis::checkRegDiff(const MCInst &Inst, DWARFRegType Reg,
+ const CFIState &PrevState,
+ const CFIState &NextState,
+ const RegisterCFIState &PrevRegState,
+ const RegisterCFIState &NextRegState,
+ const std::set<DWARFRegType> &Reads,
+ const std::set<DWARFRegType> &Writes) {
+ auto RegLLVMOpt = MCRI->getLLVMRegNum(Reg, false);
+ if (RegLLVMOpt == std::nullopt) {
+ assert(PrevRegState == NextRegState);
+ return;
+ }
+ MCPhysReg RegLLVM = RegLLVMOpt.value();
+
+ auto &&PrevRefReg =
+ PrevState.getReferenceRegisterForCallerValueOfRegister(Reg);
+
+ std::optional<MCPhysReg> PrevRefRegLLVM =
+ (PrevRefReg != std::nullopt
+ ? std::make_optional(
+ MCRI->getLLVMRegNum(PrevRefReg.value(), false).value())
+ : std::nullopt);
+ std::optional<MCPhysReg> NextRefRegLLVM =
+ (PrevRefReg != std::nullopt
+ ? std::make_optional(
+ MCRI->getLLVMRegNum(PrevRefReg.value(), false).value())
+ : std::nullopt);
+
+ MCPhysReg PrevStateCFARegLLVM =
+ MCRI->getLLVMRegNum(PrevState.CFARegister, false).value();
+
+ { // try generate
+ // Widen
+ std::vector<RegisterCFIState> PossibleNextRegStates;
+
+ { // stay the same
+ bool CanStayTheSame = false;
+
+ switch (PrevRegState.RetrieveApproach) {
+ case RegisterCFIState::Undefined:
+ case RegisterCFIState::OffsetFromCFAVal:
+ CanStayTheSame = true;
+ break;
+ case RegisterCFIState::SameValue:
+ case RegisterCFIState::AnotherRegister:
+ CanStayTheSame = !Writes.count(PrevRefReg.value());
+ break;
+ case RegisterCFIState::OffsetFromCFAAddr:
+ case RegisterCFIState::Other:
+ // cannot be sure
+ break;
+ }
+
+ if (CanStayTheSame)
+ PossibleNextRegStates.push_back(PrevRegState);
+ }
+
+ for (auto &&PossibleNextRegState : PossibleNextRegStates) {
+ if (PossibleNextRegState == NextRegState) {
+ // Everything is ok
+ return;
+ }
+ }
+
+ for (auto &&PossibleNextRegState : PossibleNextRegStates) {
+ if (PossibleNextRegState.RetrieveApproach !=
+ NextRegState.RetrieveApproach)
+ continue;
+
+ if (PossibleNextRegState.RetrieveApproach ==
+ RegisterCFIState::OffsetFromCFAAddr) {
+ Context.reportError(
+ Inst.getLoc(),
+ formatv(
+ "Expected caller's value of reg#{0} should be at offset {1} "
+ "of CFA but the CFI directives say it's in {2}",
+ RegLLVM, PossibleNextRegState.Info.OffsetFromCFA,
+ NextRegState.Info.OffsetFromCFA));
+ }
+ }
+ }
+ // Either couldn't generate, or the programmer changed the state to
+ // something that couldn't be matched to any of the generated states. So
+ // it falls back into read/write checks.
+
+ if (PrevRegState == NextRegState) {
+ switch (PrevRegState.RetrieveApproach) {
+ case RegisterCFIState::SameValue:
+ case RegisterCFIState::AnotherRegister:
+ if (Writes.count(PrevRefReg.value())) {
+ Context.reportError(
+ Inst.getLoc(),
+ formatv("Reg#{0} caller's value is in reg#{1} which is changed "
+ "by this instruction, but not changed in CFI directives",
+ RegLLVM, PrevRefRegLLVM.value()));
+ return;
+ }
+ break;
+ default:
+ // Everything may be ok
+ break;
+ }
+ return;
+ }
+
+ if (PrevRegState.RetrieveApproach == NextRegState.RetrieveApproach) {
+ // Everything may be ok
+ return;
+ }
+
+ if (PrevRegState.RetrieveApproach == RegisterCFIState::Undefined) {
+ Context.reportError(Inst.getLoc(),
+ "Cannot change a register CFI information from "
+ "undefined to something else.");
+ return;
+ }
+
+ Context.reportWarning(Inst.getLoc(),
+ formatv("The reg#{0} CFI state is changed, but I "
+ "don't have any idea how.",
+ RegLLVM));
+ // Everything may be ok
+ return;
+}
+
+void CFIAnalysis::checkCFADiff(const MCInst &Inst, const CFIState &PrevState,
+ const CFIState &NextState,
+ const std::set<DWARFRegType> &Reads,
+ const std::set<DWARFRegType> &Writes) {
+ const char *PrevCFARegName =
+ MCRI->getName(MCRI->getLLVMRegNum(PrevState.CFARegister, false).value());
+
+ if (PrevState.CFARegister == NextState.CFARegister) {
+ if (PrevState.CFAOffset == NextState.CFAOffset) {
+ if (Writes.count(PrevState.CFARegister)) {
+ Context.reportError(
+ Inst.getLoc(),
+ formatv("Missing CFI directive for the CFA offset adjustment. CFA "
+ "register ({0}) is modified by this instruction.",
+ PrevCFARegName));
+ return;
+ }
+
+ // Everything is ok!
+ return;
+ }
+ // The offset is changed.
+
+ if (!Writes.count(PrevState.CFARegister)) {
+ Context.reportError(
+ Inst.getLoc(),
+ formatv("Wrong adjustment to CFA offset. CFA register ({0}) is not "
+ "modified by this instruction.",
+ PrevCFARegName));
+ }
+
+ // The CFA register value is changed, and the offset is changed as well,
+ // everything may be ok.
+ return;
+ }
+
+ // The CFA register is changed, everything may be ok.
+}
diff --git a/llvm/lib/MC/CFIAnalysis/CFIAnalysisMCStreamer.cpp b/llvm/lib/MC/CFIAnalysis/CFIAnalysisMCStreamer.cpp
new file mode 100644
index 0000000000000..72e1481c518d5
--- /dev/null
+++ b/llvm/lib/MC/CFIAnalysis/CFIAnalysisMCStreamer.cpp
@@ -0,0 +1,131 @@
+
+#include "llvm/MC/MCCFIAnalysis/CFIAnalysisMCStreamer.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDwarf.h"
+#include "llvm/MC/MCInstrAnalysis.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCStreamer.h"
+#include <cstdio>
+#include <memory>
+#include <optional>
+
+using namespace llvm;
+
+CFIAnalysisMCStreamer::CFIDirectivesState::CFIDirectivesState()
+ : DirectiveIndex(0) {}
+
+CFIAnalysisMCStreamer::CFIDirectivesState::CFIDirectivesState(
+ int FrameIndex, int InstructionIndex)
+ : DirectiveIndex(InstructionIndex) {}
+
+CFIAnalysisMCStreamer::ICFI::ICFI(MCInst Instruction,
+ std::pair<unsigned, unsigned> CFIDirectives)
+ : Instruction(Instruction), CFIDirectivesRange(CFIDirectives) {}
+
+std::optional<MCInst> LastInstruction;
+
+std::pair<unsigned, unsigned> CFIAnalysisMCStreamer::getCFIDirectivesRange() {
+ auto DwarfFrameInfos = getDwarfFrameInfos();
+ int FrameIndex = FrameIndices.back();
+ auto CurrentCFIDirectiveState =
+ hasUnfinishedDwarfFrameInfo()
+ ? CFIDirectivesState(FrameIndex,
+ DwarfFrameInfos[FrameIndex].Instructions.size())
+ : CFIDirectivesState();
+ assert(CurrentCFIDirectiveState.DirectiveIndex >=
+ LastCFIDirectivesState.DirectiveIndex);
+
+ std::pair<unsigned, unsigned> CFIDirectivesRange(
+ LastCFIDirectivesState.DirectiveIndex,
+ CurrentCFIDirectiveState.DirectiveIndex);
+ LastCFIDirectivesState = CurrentCFIDirectiveState;
+ return CFIDirectivesRange;
+}
+
+void CFIAnalysisMCStreamer::feedCFIA() {
+ auto FrameIndex = FrameIndices.back();
+ if (FrameIndex < 0) {
+ // TODO Maybe this corner case causes bugs, when the programmer did a
+ // mistake in the startproc, endprocs and also made a mistake in not
+ // adding cfi directives for a instruction. Then this would cause to
+ // ignore the instruction.
+ auto CFIDirectivesRange = getCFIDirectivesRange();
+ assert(!LastInstruction ||
+ CFIDirectivesRange.first == CFIDirectivesRange.second);
+ return;
+ }
+
+ // TODO get this from emit yourself, instead of getting it in this way
+ const auto *LastDwarfFrameInfo = &getDwarfFrameInfos()[FrameIndex];
+
+ auto CFIDirectivesRange = getCFIDirectivesRange();
+ ArrayRef<MCCFIInstruction> CFIDirectives;
+ if (CFIDirectivesRange.first < CFIDirectivesRange.second) {
+ CFIDirectives =
+ ArrayRef<MCCFIInstruction>(LastDwarfFrameInfo->Instructions);
+ CFIDirectives = CFIDirectives.drop_front(CFIDirectivesRange.first)
+ .drop_back(LastDwarfFrameInfo->Instructions.size() -
+ CFIDirectivesRange.second);
+ }
+
+ if (LastInstruction != std::nullopt) {
+ assert(!CFIAs.empty());
+
+ CFIAs.back().update(LastInstruction.value(), CFIDirectives);
+ } else {
+ CFIAs.emplace_back(getContext(), MCII, MCIA.get(), CFIDirectives);
+ }
+}
+
+CFIAnalysisMCStreamer::CFIAnalysisMCStreamer(
+ MCContext &Context, const MCInstrInfo &MCII,
+ std::unique_ptr<MCInstrAnalysis> MCIA)
+ : MCStreamer(Context), MCII(MCII), MCIA(std::move(MCIA)),
+ LastCFIDirectivesState(), LastInstruction(std::nullopt) {
+ FrameIndices.push_back(-1);
+}
+
+bool CFIAnalysisMCStreamer::hasRawTextSupport() const { return true; }
+void CFIAnalysisMCStreamer::emitRawTextImpl(StringRef String) {}
+
+bool CFIAnalysisMCStreamer::emitSymbolAttribute(MCSymbol *Symbol,
+ MCSymbolAttr Attribute) {
+ return true;
+}
+
+void CFIAnalysisMCStreamer::emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
+ Align ByteAlignment) {}
+void CFIAnalysisMCStreamer::beginCOFFSymbolDef(const MCSymbol *Symbol) {}
+void CFIAnalysisMCStreamer::emitCOFFSymbolStorageClass(int StorageClass) {}
+void CFIAnalysisMCStreamer::emitCOFFSymbolType(int Type) {}
+void CFIAnalysisMCStreamer::endCOFFSymbolDef() {}
+void CFIAnalysisMCStreamer::emitXCOFFSymbolLinkageWithVisibility(
+ MCSymbol *Symbol, MCSymbolAttr Linkage, MCSymbolAttr Visibility) {}
+
+void CFIAnalysisMCStreamer::emitInstruction(const MCInst &Inst,
+ const MCSubtargetInfo &STI) {
+ feedCFIA();
+ LastInstruction = Inst;
+}
+
+void CFIAnalysisMCStreamer::emitCFIStartProcImpl(MCDwarfFrameInfo &Frame) {
+ feedCFIA();
+ FrameIndices.push_back(getNumFrameInfos());
+ LastInstruction = std::nullopt;
+ LastCFIDirectivesState.DirectiveIndex = 0;
+ MCStreamer::emitCFIStartProcImpl(Frame);
+}
+
+void CFIAnalysisMCStreamer::emitCFIEndProcImpl(MCDwarfFrameInfo &CurFrame) {
+ feedCFIA();
+ // TODO this will break if the input frame are malformed.
+ FrameIndices.pop_back();
+ CFIAs.pop_back();
+ LastInstruction = std::nullopt;
+ auto FrameIndex = FrameIndices.back();
+ LastCFIDirectivesState.DirectiveIndex =
+ FrameIndex >= 0 ? getDwarfFrameInfos()[FrameIndex].Instructions.size()
+ : 0;
+ MCStreamer::emitCFIEndProcImpl(CurFrame);
+}
diff --git a/llvm/lib/MC/CFIAnalysis/CFIState.cpp b/llvm/lib/MC/CFIAnalysis/CFIState.cpp
index 8a5efe31a2826..69b777cf096a7 100644
--- a/llvm/lib/MC/CFIAnalysis/CFIState.cpp
+++ b/llvm/lib/MC/CFIAnalysis/CFIState.cpp
@@ -1,3 +1,4 @@
+// TODO check what includes to keep and what to remove
#include "llvm/MC/MCCFIAnalysis/CFIState.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/MC/MCDwarf.h"
diff --git a/llvm/lib/MC/CFIAnalysis/CMakeLists.txt b/llvm/lib/MC/CFIAnalysis/CMakeLists.txt
index 0bc829c754092..cbfac740c97ab 100644
--- a/llvm/lib/MC/CFIAnalysis/CMakeLists.txt
+++ b/llvm/lib/MC/CFIAnalysis/CMakeLists.txt
@@ -1,8 +1,7 @@
add_llvm_component_library(LLVMMCCFIAnalysis
CFIState.cpp
- # CFIAnalysisMCStreamer.cpp
- # CFIAnalysis.cpp
- # ExtendedMCInstrAnalysis.cpp
+ CFIAnalysisMCStreamer.cpp
+ CFIAnalysis.cpp
LINK_COMPONENTS
MC
>From 2c233f90c5fd8e025f7f7506c48ac19c78e4f926 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Tue, 27 May 2025 19:14:44 +0000
Subject: [PATCH 26/58] Remove stack pointer method
---
.../MC/MCCFIAnalysis/ExtendedMCInstrAnalysis.h | 1 -
llvm/lib/MC/CFIAnalysis/CFIAnalysis.cpp | 16 ++++++++--------
2 files changed, 8 insertions(+), 9 deletions(-)
diff --git a/llvm/include/llvm/MC/MCCFIAnalysis/ExtendedMCInstrAnalysis.h b/llvm/include/llvm/MC/MCCFIAnalysis/ExtendedMCInstrAnalysis.h
index 6d050a4defbcc..4d8ed38513d2a 100644
--- a/llvm/include/llvm/MC/MCCFIAnalysis/ExtendedMCInstrAnalysis.h
+++ b/llvm/include/llvm/MC/MCCFIAnalysis/ExtendedMCInstrAnalysis.h
@@ -19,7 +19,6 @@ class ExtendedMCInstrAnalysis {
/// Extra semantic information needed from MC layer:
- MCPhysReg getStackPointer() const { return 61; }
MCPhysReg getFlagsReg() const { return 57; }
};
diff --git a/llvm/lib/MC/CFIAnalysis/CFIAnalysis.cpp b/llvm/lib/MC/CFIAnalysis/CFIAnalysis.cpp
index 8a50fce8e4da9..b20f6cfe90b38 100644
--- a/llvm/lib/MC/CFIAnalysis/CFIAnalysis.cpp
+++ b/llvm/lib/MC/CFIAnalysis/CFIAnalysis.cpp
@@ -3,6 +3,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Twine.h"
+#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCCFIAnalysis/ExtendedMCInstrAnalysis.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDwarf.h"
@@ -68,28 +69,27 @@ CFIAnalysis::CFIAnalysis(MCContext &Context, MCInstrInfo const &MCII,
: Context(Context), MCII(MCII), MCRI(Context.getRegisterInfo()) {
EMCIA.reset(new ExtendedMCInstrAnalysis(Context, MCII, MCIA));
- MCPhysReg StackPointer = EMCIA->getStackPointer();
-
- // TODO check what should be passed as EH?
- State = CFIState(MCRI->getDwarfRegNum(StackPointer, false), 0);
+ // TODO check what should be passed as EH? I am putting false everywhere.
for (auto &&[Reg, RegClass] : getAllSuperRegs()) {
if (MCRI->get(Reg).IsArtificial || MCRI->get(Reg).IsConstant)
continue;
- if (Reg == StackPointer)
- State.CFAOffset = RegClass->getSizeInBits() / 8;
-
DWARFRegType DwarfReg = MCRI->getDwarfRegNum(Reg, false);
State.RegisterCFIStates[DwarfReg] = RegisterCFIState::createSameValue();
}
+ for (auto &&InitialFrameStateCFIDirective :
+ Context.getAsmInfo()->getInitialFrameState()) {
+ State.apply(InitialFrameStateCFIDirective);
+ }
+
// TODO these are temporay added to make things work.
// Setup the basic information:
State.RegisterCFIStates[MCRI->getDwarfRegNum(MCRI->getProgramCounter(),
false)] =
RegisterCFIState::createUndefined(); // TODO for now, we don't care
// about the PC
- State.RegisterCFIStates[MCRI->getDwarfRegNum(StackPointer,
+ State.RegisterCFIStates[MCRI->getDwarfRegNum(State.CFARegister,
false)] =
RegisterCFIState::createOffsetFromCFAVal(0); // sp's old value is CFA
>From 12faad87e19892ce8fa71a58da936e070ef199bf Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Thu, 29 May 2025 18:49:37 +0000
Subject: [PATCH 27/58] Comment out Ignoring flags at the beginning CFI
analysis
---
llvm/lib/MC/CFIAnalysis/CFIAnalysis.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/MC/CFIAnalysis/CFIAnalysis.cpp b/llvm/lib/MC/CFIAnalysis/CFIAnalysis.cpp
index b20f6cfe90b38..02aed555f8c2c 100644
--- a/llvm/lib/MC/CFIAnalysis/CFIAnalysis.cpp
+++ b/llvm/lib/MC/CFIAnalysis/CFIAnalysis.cpp
@@ -93,8 +93,8 @@ CFIAnalysis::CFIAnalysis(MCContext &Context, MCInstrInfo const &MCII,
false)] =
RegisterCFIState::createOffsetFromCFAVal(0); // sp's old value is CFA
- State.RegisterCFIStates[MCRI->getDwarfRegNum(EMCIA->getFlagsReg(), false)] =
- RegisterCFIState::createUndefined(); // Flags cannot be caller-saved
+ // State.RegisterCFIStates[MCRI->getDwarfRegNum(EMCIA->getFlagsReg(), false)] =
+ // RegisterCFIState::createUndefined(); // Flags cannot be caller-saved
// Applying the prologue after default assumptions to overwrite them.
for (auto &&PrologueCFIDirective : PrologueCFIDirectives) {
>From 282cb77715ab4531b19f702b28a9f0cb49826f19 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Tue, 3 Jun 2025 18:59:01 +0000
Subject: [PATCH 28/58] Move the necessary MCStreamer interface methods to
CFIAnalysisMCStreamer.h
---
.../MC/MCCFIAnalysis/CFIAnalysisMCStreamer.h | 24 ++++++++++++-------
.../MC/CFIAnalysis/CFIAnalysisMCStreamer.cpp | 19 ---------------
2 files changed, 15 insertions(+), 28 deletions(-)
diff --git a/llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysisMCStreamer.h b/llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysisMCStreamer.h
index a42215685396e..a5aecd05f41d5 100644
--- a/llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysisMCStreamer.h
+++ b/llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysisMCStreamer.h
@@ -45,18 +45,24 @@ class CFIAnalysisMCStreamer : public MCStreamer {
CFIAnalysisMCStreamer(MCContext &Context, const MCInstrInfo &MCII,
std::unique_ptr<MCInstrAnalysis> MCIA);
- bool hasRawTextSupport() const override;
- void emitRawTextImpl(StringRef String) override;
- bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override;
+ bool hasRawTextSupport() const override { return true; }
+ void emitRawTextImpl(StringRef String) override {}
+
+ bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override {
+ return true;
+ }
+
void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
- Align ByteAlignment) override;
- void beginCOFFSymbolDef(const MCSymbol *Symbol) override;
- void emitCOFFSymbolStorageClass(int StorageClass) override;
- void emitCOFFSymbolType(int Type) override;
- void endCOFFSymbolDef() override;
+ Align ByteAlignment) override {}
+ void emitSubsectionsViaSymbols() override {};
+ void beginCOFFSymbolDef(const MCSymbol *Symbol) override {}
+ void emitCOFFSymbolStorageClass(int StorageClass) override {}
+ void emitCOFFSymbolType(int Type) override {}
+ void endCOFFSymbolDef() override {}
void emitXCOFFSymbolLinkageWithVisibility(MCSymbol *Symbol,
MCSymbolAttr Linkage,
- MCSymbolAttr Visibility) override;
+ MCSymbolAttr Visibility) override {}
+
void emitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI) override;
void emitCFIStartProcImpl(MCDwarfFrameInfo &Frame) override;
void emitCFIEndProcImpl(MCDwarfFrameInfo &CurFrame) override;
diff --git a/llvm/lib/MC/CFIAnalysis/CFIAnalysisMCStreamer.cpp b/llvm/lib/MC/CFIAnalysis/CFIAnalysisMCStreamer.cpp
index 72e1481c518d5..994d7d56e0871 100644
--- a/llvm/lib/MC/CFIAnalysis/CFIAnalysisMCStreamer.cpp
+++ b/llvm/lib/MC/CFIAnalysis/CFIAnalysisMCStreamer.cpp
@@ -23,8 +23,6 @@ CFIAnalysisMCStreamer::ICFI::ICFI(MCInst Instruction,
std::pair<unsigned, unsigned> CFIDirectives)
: Instruction(Instruction), CFIDirectivesRange(CFIDirectives) {}
-std::optional<MCInst> LastInstruction;
-
std::pair<unsigned, unsigned> CFIAnalysisMCStreamer::getCFIDirectivesRange() {
auto DwarfFrameInfos = getDwarfFrameInfos();
int FrameIndex = FrameIndices.back();
@@ -86,23 +84,6 @@ CFIAnalysisMCStreamer::CFIAnalysisMCStreamer(
FrameIndices.push_back(-1);
}
-bool CFIAnalysisMCStreamer::hasRawTextSupport() const { return true; }
-void CFIAnalysisMCStreamer::emitRawTextImpl(StringRef String) {}
-
-bool CFIAnalysisMCStreamer::emitSymbolAttribute(MCSymbol *Symbol,
- MCSymbolAttr Attribute) {
- return true;
-}
-
-void CFIAnalysisMCStreamer::emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
- Align ByteAlignment) {}
-void CFIAnalysisMCStreamer::beginCOFFSymbolDef(const MCSymbol *Symbol) {}
-void CFIAnalysisMCStreamer::emitCOFFSymbolStorageClass(int StorageClass) {}
-void CFIAnalysisMCStreamer::emitCOFFSymbolType(int Type) {}
-void CFIAnalysisMCStreamer::endCOFFSymbolDef() {}
-void CFIAnalysisMCStreamer::emitXCOFFSymbolLinkageWithVisibility(
- MCSymbol *Symbol, MCSymbolAttr Linkage, MCSymbolAttr Visibility) {}
-
void CFIAnalysisMCStreamer::emitInstruction(const MCInst &Inst,
const MCSubtargetInfo &STI) {
feedCFIA();
>From 903e3fbc02c150a7ddebe5f98c03fc5b6390336d Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Thu, 5 Jun 2025 21:35:26 +0000
Subject: [PATCH 29/58] Make the update method const
---
llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysis.h | 2 +-
llvm/lib/MC/CFIAnalysis/CFIAnalysis.cpp | 2 +-
llvm/lib/MC/CFIAnalysis/CFIAnalysisMCStreamer.cpp | 1 -
3 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysis.h b/llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysis.h
index 8c70764cdde2d..180296755665e 100644
--- a/llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysis.h
+++ b/llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysis.h
@@ -46,7 +46,7 @@ class CFIAnalysis {
MCInstrAnalysis *MCIA,
ArrayRef<MCCFIInstruction> PrologueCFIDirectives);
- void update(MCInst &Inst, ArrayRef<MCCFIInstruction> CFIDirectives);
+ void update(const MCInst &Inst, ArrayRef<MCCFIInstruction> CFIDirectives);
private:
void checkRegDiff(const MCInst &Inst, DWARFRegType Reg,
diff --git a/llvm/lib/MC/CFIAnalysis/CFIAnalysis.cpp b/llvm/lib/MC/CFIAnalysis/CFIAnalysis.cpp
index 02aed555f8c2c..97f52356dc69b 100644
--- a/llvm/lib/MC/CFIAnalysis/CFIAnalysis.cpp
+++ b/llvm/lib/MC/CFIAnalysis/CFIAnalysis.cpp
@@ -102,7 +102,7 @@ CFIAnalysis::CFIAnalysis(MCContext &Context, MCInstrInfo const &MCII,
}
}
-void CFIAnalysis::update(MCInst &Inst,
+void CFIAnalysis::update(const MCInst &Inst,
ArrayRef<MCCFIInstruction> CFIDirectives) {
const MCInstrDesc &MCInstInfo = MCII.get(Inst.getOpcode());
CFIState AfterState(State);
diff --git a/llvm/lib/MC/CFIAnalysis/CFIAnalysisMCStreamer.cpp b/llvm/lib/MC/CFIAnalysis/CFIAnalysisMCStreamer.cpp
index 994d7d56e0871..f286be9329475 100644
--- a/llvm/lib/MC/CFIAnalysis/CFIAnalysisMCStreamer.cpp
+++ b/llvm/lib/MC/CFIAnalysis/CFIAnalysisMCStreamer.cpp
@@ -54,7 +54,6 @@ void CFIAnalysisMCStreamer::feedCFIA() {
return;
}
- // TODO get this from emit yourself, instead of getting it in this way
const auto *LastDwarfFrameInfo = &getDwarfFrameInfos()[FrameIndex];
auto CFIDirectivesRange = getCFIDirectivesRange();
>From 7bb20f823ad0c576a8bba83c5138432b1646ae2c Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Thu, 5 Jun 2025 21:50:28 +0000
Subject: [PATCH 30/58] Move CFI analysis out of MC layer
---
llvm/include/llvm/{MC => }/MCCFIAnalysis/CFIAnalysis.h | 0
.../llvm/{MC => }/MCCFIAnalysis/CFIAnalysisMCStreamer.h | 0
llvm/include/llvm/{MC => }/MCCFIAnalysis/CFIState.h | 0
.../llvm/{MC => }/MCCFIAnalysis/ExtendedMCInstrAnalysis.h | 0
llvm/lib/CMakeLists.txt | 1 +
llvm/lib/MC/CMakeLists.txt | 1 -
llvm/lib/{MC/CFIAnalysis => MCCFIAnalysis}/CFIAnalysis.cpp | 7 ++++---
.../CFIAnalysisMCStreamer.cpp | 2 +-
llvm/lib/{MC/CFIAnalysis => MCCFIAnalysis}/CFIState.cpp | 2 +-
llvm/lib/{MC/CFIAnalysis => MCCFIAnalysis}/CMakeLists.txt | 3 +++
llvm/tools/llvm-mc/llvm-mc.cpp | 2 +-
11 files changed, 11 insertions(+), 7 deletions(-)
rename llvm/include/llvm/{MC => }/MCCFIAnalysis/CFIAnalysis.h (100%)
rename llvm/include/llvm/{MC => }/MCCFIAnalysis/CFIAnalysisMCStreamer.h (100%)
rename llvm/include/llvm/{MC => }/MCCFIAnalysis/CFIState.h (100%)
rename llvm/include/llvm/{MC => }/MCCFIAnalysis/ExtendedMCInstrAnalysis.h (100%)
rename llvm/lib/{MC/CFIAnalysis => MCCFIAnalysis}/CFIAnalysis.cpp (98%)
rename llvm/lib/{MC/CFIAnalysis => MCCFIAnalysis}/CFIAnalysisMCStreamer.cpp (98%)
rename llvm/lib/{MC/CFIAnalysis => MCCFIAnalysis}/CFIState.cpp (99%)
rename llvm/lib/{MC/CFIAnalysis => MCCFIAnalysis}/CMakeLists.txt (69%)
diff --git a/llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysis.h b/llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h
similarity index 100%
rename from llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysis.h
rename to llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h
diff --git a/llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysisMCStreamer.h b/llvm/include/llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h
similarity index 100%
rename from llvm/include/llvm/MC/MCCFIAnalysis/CFIAnalysisMCStreamer.h
rename to llvm/include/llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h
diff --git a/llvm/include/llvm/MC/MCCFIAnalysis/CFIState.h b/llvm/include/llvm/MCCFIAnalysis/CFIState.h
similarity index 100%
rename from llvm/include/llvm/MC/MCCFIAnalysis/CFIState.h
rename to llvm/include/llvm/MCCFIAnalysis/CFIState.h
diff --git a/llvm/include/llvm/MC/MCCFIAnalysis/ExtendedMCInstrAnalysis.h b/llvm/include/llvm/MCCFIAnalysis/ExtendedMCInstrAnalysis.h
similarity index 100%
rename from llvm/include/llvm/MC/MCCFIAnalysis/ExtendedMCInstrAnalysis.h
rename to llvm/include/llvm/MCCFIAnalysis/ExtendedMCInstrAnalysis.h
diff --git a/llvm/lib/CMakeLists.txt b/llvm/lib/CMakeLists.txt
index f6465612d30c0..08b68aee46efd 100644
--- a/llvm/lib/CMakeLists.txt
+++ b/llvm/lib/CMakeLists.txt
@@ -24,6 +24,7 @@ add_subdirectory(Analysis)
add_subdirectory(LTO)
add_subdirectory(MC)
add_subdirectory(MCA)
+add_subdirectory(MCCFIAnalysis)
add_subdirectory(ObjCopy)
add_subdirectory(Object)
add_subdirectory(ObjectYAML)
diff --git a/llvm/lib/MC/CMakeLists.txt b/llvm/lib/MC/CMakeLists.txt
index 8f8637bd8580b..f49f14c848b90 100644
--- a/llvm/lib/MC/CMakeLists.txt
+++ b/llvm/lib/MC/CMakeLists.txt
@@ -87,4 +87,3 @@ add_llvm_component_library(LLVMMC
add_subdirectory(MCParser)
add_subdirectory(MCDisassembler)
-add_subdirectory(CFIAnalysis)
diff --git a/llvm/lib/MC/CFIAnalysis/CFIAnalysis.cpp b/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp
similarity index 98%
rename from llvm/lib/MC/CFIAnalysis/CFIAnalysis.cpp
rename to llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp
index 97f52356dc69b..1a5785e4eac0c 100644
--- a/llvm/lib/MC/CFIAnalysis/CFIAnalysis.cpp
+++ b/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp
@@ -1,10 +1,9 @@
-#include "llvm/MC/MCCFIAnalysis/CFIAnalysis.h"
+#include "llvm/MCCFIAnalysis/CFIAnalysis.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Twine.h"
#include "llvm/MC/MCAsmInfo.h"
-#include "llvm/MC/MCCFIAnalysis/ExtendedMCInstrAnalysis.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDwarf.h"
#include "llvm/MC/MCExpr.h"
@@ -15,6 +14,7 @@
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/TargetRegistry.h"
+#include "llvm/MCCFIAnalysis/ExtendedMCInstrAnalysis.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormatVariadic.h"
@@ -93,7 +93,8 @@ CFIAnalysis::CFIAnalysis(MCContext &Context, MCInstrInfo const &MCII,
false)] =
RegisterCFIState::createOffsetFromCFAVal(0); // sp's old value is CFA
- // State.RegisterCFIStates[MCRI->getDwarfRegNum(EMCIA->getFlagsReg(), false)] =
+ // State.RegisterCFIStates[MCRI->getDwarfRegNum(EMCIA->getFlagsReg(), false)]
+ // =
// RegisterCFIState::createUndefined(); // Flags cannot be caller-saved
// Applying the prologue after default assumptions to overwrite them.
diff --git a/llvm/lib/MC/CFIAnalysis/CFIAnalysisMCStreamer.cpp b/llvm/lib/MCCFIAnalysis/CFIAnalysisMCStreamer.cpp
similarity index 98%
rename from llvm/lib/MC/CFIAnalysis/CFIAnalysisMCStreamer.cpp
rename to llvm/lib/MCCFIAnalysis/CFIAnalysisMCStreamer.cpp
index f286be9329475..43855a4d75dc2 100644
--- a/llvm/lib/MC/CFIAnalysis/CFIAnalysisMCStreamer.cpp
+++ b/llvm/lib/MCCFIAnalysis/CFIAnalysisMCStreamer.cpp
@@ -1,5 +1,5 @@
-#include "llvm/MC/MCCFIAnalysis/CFIAnalysisMCStreamer.h"
+#include "llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDwarf.h"
diff --git a/llvm/lib/MC/CFIAnalysis/CFIState.cpp b/llvm/lib/MCCFIAnalysis/CFIState.cpp
similarity index 99%
rename from llvm/lib/MC/CFIAnalysis/CFIState.cpp
rename to llvm/lib/MCCFIAnalysis/CFIState.cpp
index 69b777cf096a7..56cee65c5235a 100644
--- a/llvm/lib/MC/CFIAnalysis/CFIState.cpp
+++ b/llvm/lib/MCCFIAnalysis/CFIState.cpp
@@ -1,5 +1,5 @@
// TODO check what includes to keep and what to remove
-#include "llvm/MC/MCCFIAnalysis/CFIState.h"
+#include "llvm/MCCFIAnalysis/CFIState.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/MC/MCDwarf.h"
#include "llvm/Support/FormatVariadic.h"
diff --git a/llvm/lib/MC/CFIAnalysis/CMakeLists.txt b/llvm/lib/MCCFIAnalysis/CMakeLists.txt
similarity index 69%
rename from llvm/lib/MC/CFIAnalysis/CMakeLists.txt
rename to llvm/lib/MCCFIAnalysis/CMakeLists.txt
index cbfac740c97ab..7b504d6f6f19c 100644
--- a/llvm/lib/MC/CFIAnalysis/CMakeLists.txt
+++ b/llvm/lib/MCCFIAnalysis/CMakeLists.txt
@@ -3,6 +3,9 @@ add_llvm_component_library(LLVMMCCFIAnalysis
CFIAnalysisMCStreamer.cpp
CFIAnalysis.cpp
+ ADDITIONAL_HEADER_DIRS
+ ${LLVM_MAIN_INCLUDE_DIR}/llvm/MCA
+
LINK_COMPONENTS
MC
Support
diff --git a/llvm/tools/llvm-mc/llvm-mc.cpp b/llvm/tools/llvm-mc/llvm-mc.cpp
index 2f1d6cb42aa0b..c2852298aacb6 100644
--- a/llvm/tools/llvm-mc/llvm-mc.cpp
+++ b/llvm/tools/llvm-mc/llvm-mc.cpp
@@ -14,7 +14,7 @@
#include "Disassembler.h"
#include "llvm/MC/MCAsmBackend.h"
#include "llvm/MC/MCAsmInfo.h"
-#include "llvm/MC/MCCFIAnalysis/CFIAnalysisMCStreamer.h"
+#include "llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h"
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCInstPrinter.h"
>From 050dbdb947becca871cf14c067f57b507d96f5b9 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Fri, 6 Jun 2025 18:04:33 +0000
Subject: [PATCH 31/58] Write a CFI directive to DWARF operation converter
---
llvm/include/llvm/MCCFIAnalysis/CFIState.h | 6 ++
llvm/lib/MCCFIAnalysis/CFIState.cpp | 97 ++++++++++++++++++++++
llvm/lib/MCCFIAnalysis/CMakeLists.txt | 1 +
3 files changed, 104 insertions(+)
diff --git a/llvm/include/llvm/MCCFIAnalysis/CFIState.h b/llvm/include/llvm/MCCFIAnalysis/CFIState.h
index 3141f65e642b4..cfe2aacf02ce6 100644
--- a/llvm/include/llvm/MCCFIAnalysis/CFIState.h
+++ b/llvm/include/llvm/MCCFIAnalysis/CFIState.h
@@ -2,6 +2,8 @@
#define LLVM_TOOLS_LLVM_MC_CFI_STATE_H
#include "llvm/ADT/DenseMap.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
+#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDwarf.h"
#include <optional>
#include <string>
@@ -9,6 +11,10 @@ namespace llvm {
using DWARFRegType = int64_t;
+dwarf::CFIProgram convertMC2DWARF(MCContext &Context,
+ MCCFIInstruction CFIDirective,
+ int64_t CFAOffset);
+
struct RegisterCFIState {
enum Approach {
Undefined,
diff --git a/llvm/lib/MCCFIAnalysis/CFIState.cpp b/llvm/lib/MCCFIAnalysis/CFIState.cpp
index 56cee65c5235a..4f4a6e168bef6 100644
--- a/llvm/lib/MCCFIAnalysis/CFIState.cpp
+++ b/llvm/lib/MCCFIAnalysis/CFIState.cpp
@@ -1,6 +1,8 @@
// TODO check what includes to keep and what to remove
#include "llvm/MCCFIAnalysis/CFIState.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
#include "llvm/MC/MCDwarf.h"
#include "llvm/Support/FormatVariadic.h"
#include <cassert>
@@ -10,6 +12,101 @@
using namespace llvm;
+dwarf::CFIProgram llvm::convertMC2DWARF(MCContext &Context,
+ MCCFIInstruction CFIDirective,
+ int64_t CFAOffset) {
+ //! FIXME, this way of instantiating CFI program does not look right, either
+ //! refactor CFIProgram to not depend on the Code/Data Alignment or add a new
+ //! type that is independent from this and is also feedable to UnwindTable.
+ auto DwarfOperations =
+ dwarf::CFIProgram(0, 0, Context.getTargetTriple().getArch());
+
+ switch (CFIDirective.getOperation()) {
+ case MCCFIInstruction::OpSameValue:
+ DwarfOperations.addInstruction(dwarf::DW_CFA_same_value,
+ CFIDirective.getRegister());
+ break;
+ case MCCFIInstruction::OpRememberState:
+ DwarfOperations.addInstruction(dwarf::DW_CFA_remember_state);
+ break;
+ case MCCFIInstruction::OpRestoreState:
+ DwarfOperations.addInstruction(dwarf::DW_CFA_restore_state);
+ break;
+ case MCCFIInstruction::OpOffset:
+ DwarfOperations.addInstruction(dwarf::DW_CFA_offset,
+ CFIDirective.getRegister(),
+ CFIDirective.getOffset());
+ break;
+ case MCCFIInstruction::OpLLVMDefAspaceCfa:
+ DwarfOperations.addInstruction(dwarf::DW_CFA_LLVM_def_aspace_cfa,
+ CFIDirective.getRegister());
+ break;
+ case MCCFIInstruction::OpDefCfaRegister:
+ DwarfOperations.addInstruction(dwarf::DW_CFA_def_cfa,
+ CFIDirective.getRegister());
+ break;
+ case MCCFIInstruction::OpDefCfaOffset:
+ DwarfOperations.addInstruction(dwarf::DW_CFA_def_cfa_offset,
+ CFIDirective.getOffset());
+ break;
+ case MCCFIInstruction::OpDefCfa:
+ DwarfOperations.addInstruction(dwarf::DW_CFA_def_cfa,
+ CFIDirective.getRegister(),
+ CFIDirective.getOffset());
+ break;
+ case MCCFIInstruction::OpRelOffset:
+ DwarfOperations.addInstruction(dwarf::DW_CFA_offset,
+ CFIDirective.getRegister(),
+ CFIDirective.getOffset() - CFAOffset);
+ break;
+ case MCCFIInstruction::OpAdjustCfaOffset:
+ DwarfOperations.addInstruction(dwarf::DW_CFA_def_cfa_offset,
+ CFIDirective.getOffset() + CFAOffset);
+ break;
+ case MCCFIInstruction::OpEscape:
+ // TODO It's now feasible but for now, I ignore it
+ break;
+ case MCCFIInstruction::OpRestore:
+ DwarfOperations.addInstruction(dwarf::DW_CFA_restore);
+ break;
+ case MCCFIInstruction::OpUndefined:
+ DwarfOperations.addInstruction(dwarf::DW_CFA_undefined,
+ CFIDirective.getRegister());
+ break;
+ case MCCFIInstruction::OpRegister:
+ DwarfOperations.addInstruction(dwarf::DW_CFA_register,
+ CFIDirective.getRegister(),
+ CFIDirective.getRegister2());
+ break;
+ case MCCFIInstruction::OpWindowSave:
+ // TODO make sure these are the same.
+ DwarfOperations.addInstruction(dwarf::DW_CFA_GNU_window_save);
+ break;
+ case MCCFIInstruction::OpNegateRAState:
+ // TODO make sure these are the same.
+ DwarfOperations.addInstruction(dwarf::DW_CFA_AARCH64_negate_ra_state);
+ break;
+ case MCCFIInstruction::OpNegateRAStateWithPC:
+ // TODO make sure these are the same.
+ DwarfOperations.addInstruction(
+ dwarf::DW_CFA_AARCH64_negate_ra_state_with_pc);
+ break;
+ case MCCFIInstruction::OpGnuArgsSize:
+ DwarfOperations.addInstruction(dwarf::DW_CFA_GNU_args_size);
+ break;
+ case MCCFIInstruction::OpLabel:
+ // TODO, I don't know what it is, I have to implement it.
+ break;
+ case MCCFIInstruction::OpValOffset:
+ DwarfOperations.addInstruction(dwarf::DW_CFA_val_offset,
+ CFIDirective.getRegister(),
+ CFIDirective.getOffset());
+ break;
+ }
+
+ return DwarfOperations;
+}
+
using DWARFRegType = int64_t;
std::string RegisterCFIState::dump() {
diff --git a/llvm/lib/MCCFIAnalysis/CMakeLists.txt b/llvm/lib/MCCFIAnalysis/CMakeLists.txt
index 7b504d6f6f19c..15622132de7d4 100644
--- a/llvm/lib/MCCFIAnalysis/CMakeLists.txt
+++ b/llvm/lib/MCCFIAnalysis/CMakeLists.txt
@@ -8,5 +8,6 @@ add_llvm_component_library(LLVMMCCFIAnalysis
LINK_COMPONENTS
MC
+ DebugInfoDWARF
Support
)
>From 223f4f7a380be230c526b9bddf4e265315446f1f Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Fri, 13 Jun 2025 03:58:13 +0000
Subject: [PATCH 32/58] Use UnwindTable instead of CFI State:
- Change unwind table (by making small things public) to be usable from CFIAnalysis
- Remove CFIState internal DS and use UnwindTable instead
- Add a MCCFIInstruction -> CFIProgram::Instruction converter
- Refactor CFIAnalysis to use UnwindTable
---
.../llvm/DebugInfo/DWARF/DWARFDebugFrame.h | 2 +
llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h | 20 +-
.../MCCFIAnalysis/CFIAnalysisMCStreamer.h | 6 +
llvm/include/llvm/MCCFIAnalysis/CFIState.h | 58 +---
.../MCCFIAnalysis/ExtendedMCInstrAnalysis.h | 3 +-
llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp | 229 ++++++++------
.../MCCFIAnalysis/CFIAnalysisMCStreamer.cpp | 2 +-
llvm/lib/MCCFIAnalysis/CFIState.cpp | 284 ++++++------------
.../cfi-validation/single-func-cfa-mistake.s | 4 +-
.../single-func-missed-cfi-directive.s | 3 +-
.../cfi-validation/spill-two-reg-reversed.s | 10 +-
.../cfi-validation/update-with-no-cfi.s | 8 +-
12 files changed, 284 insertions(+), 345 deletions(-)
diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h
index 3b367009a379d..c87abb010f039 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h
@@ -138,6 +138,7 @@ class UnwindLocation {
return *AddrSpace;
}
int32_t getConstant() const { return Offset; }
+ bool getDereference() const { return Dereference; }
/// Some opcodes will modify the CFA location's register only, so we need
/// to be able to modify the CFA register when evaluating DWARF Call Frame
/// Information opcodes.
@@ -333,6 +334,7 @@ class UnwindTable {
assert(Index < size());
return Rows[Index];
}
+ void insertRow(UnwindRow Row) { Rows.push_back(Row); }
/// Dump the UnwindTable to the stream.
///
diff --git a/llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h b/llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h
index 180296755665e..9642a3fafabb6 100644
--- a/llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h
+++ b/llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h
@@ -5,6 +5,7 @@
#include "ExtendedMCInstrAnalysis.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDwarf.h"
#include "llvm/MC/MCExpr.h"
@@ -21,7 +22,7 @@
namespace llvm {
class CFIAnalysis {
- MCContext &Context;
+ MCContext *Context;
MCInstrInfo const &MCII;
MCRegisterInfo const *MCRI;
std::unique_ptr<ExtendedMCInstrAnalysis> EMCIA;
@@ -42,19 +43,22 @@ class CFIAnalysis {
MCPhysReg getSuperReg(MCPhysReg Reg);
public:
- CFIAnalysis(MCContext &Context, MCInstrInfo const &MCII,
+ CFIAnalysis(MCContext *Context, MCInstrInfo const &MCII,
MCInstrAnalysis *MCIA,
ArrayRef<MCCFIInstruction> PrologueCFIDirectives);
void update(const MCInst &Inst, ArrayRef<MCCFIInstruction> CFIDirectives);
private:
- void checkRegDiff(const MCInst &Inst, DWARFRegType Reg,
- const CFIState &PrevState, const CFIState &NextState,
- const RegisterCFIState &PrevRegState,
- const RegisterCFIState &NextRegState,
- const std::set<DWARFRegType> &Reads,
- const std::set<DWARFRegType> &Writes);
+ void checkRegDiff(
+ const MCInst &Inst, DWARFRegType Reg, const CFIState &PrevState,
+ const CFIState &NextState,
+ const dwarf::UnwindLocation
+ &PrevRegState, // TODO maybe should get them from prev next state
+ const dwarf::UnwindLocation
+ &NextRegState, // TODO themselves instead of by arguments.
+ const std::set<DWARFRegType> &Reads,
+ const std::set<DWARFRegType> &Writes);
void checkCFADiff(const MCInst &Inst, const CFIState &PrevState,
const CFIState &NextState,
diff --git a/llvm/include/llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h b/llvm/include/llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h
index a5aecd05f41d5..895457bda3703 100644
--- a/llvm/include/llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h
+++ b/llvm/include/llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h
@@ -14,6 +14,12 @@
namespace llvm {
+// TODO Now the design is that the streamer, make instances of the analysis and
+// TODO run the analysis on the instruction, but instead the streamer should
+// TODO divide the program into function units, and then emit the function units
+// TODO one by one. Also in each function unit, an instruction with associated
+// TODO directives should be emitted. The analysis should be run by the
+// TODO receiver.
class CFIAnalysisMCStreamer : public MCStreamer {
MCInstrInfo const &MCII;
std::unique_ptr<MCInstrAnalysis> MCIA;
diff --git a/llvm/include/llvm/MCCFIAnalysis/CFIState.h b/llvm/include/llvm/MCCFIAnalysis/CFIState.h
index cfe2aacf02ce6..7da036c0009e8 100644
--- a/llvm/include/llvm/MCCFIAnalysis/CFIState.h
+++ b/llvm/include/llvm/MCCFIAnalysis/CFIState.h
@@ -1,65 +1,37 @@
#ifndef LLVM_TOOLS_LLVM_MC_CFI_STATE_H
#define LLVM_TOOLS_LLVM_MC_CFI_STATE_H
-#include "llvm/ADT/DenseMap.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDwarf.h"
#include <optional>
-#include <string>
namespace llvm {
using DWARFRegType = int64_t;
-dwarf::CFIProgram convertMC2DWARF(MCContext &Context,
- MCCFIInstruction CFIDirective,
- int64_t CFAOffset);
+class CFIState {
+private:
+ MCContext *Context;
+ // TODO the choice is questionable, should the state be the Table? or just a
+ // TODO row? In the current code we are using only the last row.
+ dwarf::UnwindTable State;
-struct RegisterCFIState {
- enum Approach {
- Undefined,
- SameValue,
- AnotherRegister,
- OffsetFromCFAAddr,
- OffsetFromCFAVal,
- Other,
- } RetrieveApproach;
+public:
+ std::optional<dwarf::UnwindRow>
+ getLastRow() const; // TODO maybe move it UnwindRow
- union {
- int OffsetFromCFA;
- DWARFRegType Register;
- } Info;
-
- // TODO change it to be like other dump methods
- std::string dump();
-
- bool operator==(const RegisterCFIState &OtherState) const;
- bool operator!=(const RegisterCFIState &OtherState) const;
-
- static RegisterCFIState createUndefined();
- static RegisterCFIState createSameValue();
- static RegisterCFIState createAnotherRegister(DWARFRegType Register);
- static RegisterCFIState createOffsetFromCFAAddr(int OffsetFromCFA);
- static RegisterCFIState createOffsetFromCFAVal(int OffsetFromCFA);
- static RegisterCFIState createOther();
-};
-
-struct CFIState {
- DenseMap<DWARFRegType, RegisterCFIState> RegisterCFIStates;
- DWARFRegType CFARegister;
- int CFAOffset;
-
- CFIState();
+ CFIState(MCContext *Context) : Context(Context) {};
CFIState(const CFIState &Other);
-
CFIState &operator=(const CFIState &Other);
- CFIState(DWARFRegType CFARegister, int CFIOffset);
-
std::optional<DWARFRegType>
getReferenceRegisterForCallerValueOfRegister(DWARFRegType Reg) const;
- bool apply(const MCCFIInstruction &CFIDirective);
+ void apply(const MCCFIInstruction &CFIDirective);
+
+private:
+ std::optional<dwarf::CFIProgram> convertMC2DWARF(
+ MCCFIInstruction CFIDirective); // TODO maybe move it somewhere else
};
} // namespace llvm
diff --git a/llvm/include/llvm/MCCFIAnalysis/ExtendedMCInstrAnalysis.h b/llvm/include/llvm/MCCFIAnalysis/ExtendedMCInstrAnalysis.h
index 4d8ed38513d2a..12d6227922a2b 100644
--- a/llvm/include/llvm/MCCFIAnalysis/ExtendedMCInstrAnalysis.h
+++ b/llvm/include/llvm/MCCFIAnalysis/ExtendedMCInstrAnalysis.h
@@ -11,10 +11,11 @@
namespace llvm {
+// TODO remove this class entirely
class ExtendedMCInstrAnalysis {
private:
public:
- ExtendedMCInstrAnalysis(MCContext &Context, MCInstrInfo const &MCII,
+ ExtendedMCInstrAnalysis(MCContext *Context, MCInstrInfo const &MCII,
MCInstrAnalysis *MCIA) {}
/// Extra semantic information needed from MC layer:
diff --git a/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp b/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp
index 1a5785e4eac0c..80403c341707c 100644
--- a/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp
+++ b/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp
@@ -3,6 +3,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Twine.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDwarf.h"
@@ -14,10 +15,12 @@
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/TargetRegistry.h"
+#include "llvm/MCCFIAnalysis/CFIState.h"
#include "llvm/MCCFIAnalysis/ExtendedMCInstrAnalysis.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormatVariadic.h"
+#include <cstdint>
#include <memory>
#include <optional>
#include <set>
@@ -63,10 +66,11 @@ MCPhysReg CFIAnalysis::getSuperReg(MCPhysReg Reg) {
llvm_unreachable("Should either be a super reg, or have a super reg");
}
-CFIAnalysis::CFIAnalysis(MCContext &Context, MCInstrInfo const &MCII,
+CFIAnalysis::CFIAnalysis(MCContext *Context, MCInstrInfo const &MCII,
MCInstrAnalysis *MCIA,
ArrayRef<MCCFIInstruction> PrologueCFIDirectives)
- : Context(Context), MCII(MCII), MCRI(Context.getRegisterInfo()) {
+ : Context(Context), MCII(MCII), MCRI(Context->getRegisterInfo()),
+ State(Context) {
EMCIA.reset(new ExtendedMCInstrAnalysis(Context, MCII, MCIA));
// TODO check what should be passed as EH? I am putting false everywhere.
@@ -75,27 +79,34 @@ CFIAnalysis::CFIAnalysis(MCContext &Context, MCInstrInfo const &MCII,
continue;
DWARFRegType DwarfReg = MCRI->getDwarfRegNum(Reg, false);
- State.RegisterCFIStates[DwarfReg] = RegisterCFIState::createSameValue();
+ // TODO is it OK to create fake CFI directives for doing this?
+ State.apply(MCCFIInstruction::createSameValue(nullptr, DwarfReg));
}
for (auto &&InitialFrameStateCFIDirective :
- Context.getAsmInfo()->getInitialFrameState()) {
+ Context->getAsmInfo()->getInitialFrameState()) {
State.apply(InitialFrameStateCFIDirective);
}
// TODO these are temporay added to make things work.
// Setup the basic information:
- State.RegisterCFIStates[MCRI->getDwarfRegNum(MCRI->getProgramCounter(),
- false)] =
- RegisterCFIState::createUndefined(); // TODO for now, we don't care
- // about the PC
- State.RegisterCFIStates[MCRI->getDwarfRegNum(State.CFARegister,
- false)] =
- RegisterCFIState::createOffsetFromCFAVal(0); // sp's old value is CFA
-
- // State.RegisterCFIStates[MCRI->getDwarfRegNum(EMCIA->getFlagsReg(), false)]
- // =
- // RegisterCFIState::createUndefined(); // Flags cannot be caller-saved
+ State.apply(MCCFIInstruction::createUndefined(
+ nullptr,
+ MCRI->getDwarfRegNum(MCRI->getProgramCounter(),
+ false))); // TODO for now, we don't care about the PC
+ // TODO
+ auto LastRow = State.getLastRow();
+ assert(LastRow && "there should be at least one row");
+ // TODO assert that CFA is there, and based on register.
+ // TODO
+
+ State.apply(MCCFIInstruction::createOffset(
+ nullptr, LastRow->getCFAValue().getRegister(),
+ 0)); // sp's old value is CFA
+
+ State.apply(MCCFIInstruction::createUndefined(
+ nullptr, MCRI->getDwarfRegNum(EMCIA->getFlagsReg(),
+ false))); // Flags cannot be caller-saved
// Applying the prologue after default assumptions to overwrite them.
for (auto &&PrologueCFIDirective : PrologueCFIDirectives) {
@@ -108,11 +119,13 @@ void CFIAnalysis::update(const MCInst &Inst,
const MCInstrDesc &MCInstInfo = MCII.get(Inst.getOpcode());
CFIState AfterState(State);
for (auto &&CFIDirective : CFIDirectives)
- if (!AfterState.apply(CFIDirective))
- Context.reportWarning(
- CFIDirective.getLoc(),
- "I don't support this CFI directive, I assume this does nothing "
- "(which will probably break other things)");
+ AfterState.apply(CFIDirective);
+
+ //! if (!AfterState.apply(CFIDirective))
+ //! Context->reportWarning(
+ //! CFIDirective.getLoc(),
+ //! "I don't support this CFI directive, I assume this does nothing "
+ //! "(which will probably break other things)");
std::set<DWARFRegType> Writes, Reads;
for (unsigned I = 0; I < MCInstInfo.NumImplicitUses; I++)
@@ -136,29 +149,45 @@ void CFIAnalysis::update(const MCInst &Inst,
checkCFADiff(Inst, State, AfterState, Reads, Writes);
- for (auto &&[Reg, RegState] : State.RegisterCFIStates) {
- assert(AfterState.RegisterCFIStates.count(Reg) &&
- "Registers' state should not be deleted by CFI instruction.");
- checkRegDiff(Inst, Reg, State, AfterState, RegState,
- AfterState.RegisterCFIStates[Reg], Reads, Writes);
+ for (auto [LLVMReg, _] : getAllSuperRegs()) {
+ DWARFRegType Reg = MCRI->getDwarfRegNum(LLVMReg, false);
+
+ auto PrevUnwindLoc =
+ State.getLastRow()->getRegisterLocations().getRegisterLocation(Reg);
+ auto NextUnwindLoc =
+ AfterState.getLastRow()->getRegisterLocations().getRegisterLocation(
+ Reg);
+
+ // TODO think more if these assertions are OK
+ // TODO maybe change them to error messages.
+ if (!PrevUnwindLoc) {
+ assert(
+ !NextUnwindLoc &&
+ "A CFI directive should not define a new register out of thin air.");
+ continue;
+ }
+ assert(NextUnwindLoc &&
+ "A CFI directive should not delete a register state.");
+
+ checkRegDiff(Inst, Reg, State, AfterState, PrevUnwindLoc.value(),
+ NextUnwindLoc.value(), Reads, Writes);
}
State = AfterState;
}
-void CFIAnalysis::checkRegDiff(const MCInst &Inst, DWARFRegType Reg,
- const CFIState &PrevState,
- const CFIState &NextState,
- const RegisterCFIState &PrevRegState,
- const RegisterCFIState &NextRegState,
- const std::set<DWARFRegType> &Reads,
- const std::set<DWARFRegType> &Writes) {
+void CFIAnalysis::checkRegDiff(
+ const MCInst &Inst, DWARFRegType Reg, const CFIState &PrevState,
+ const CFIState &NextState,
+ const dwarf::UnwindLocation &PrevRegState, // TODO maybe re-name
+ const dwarf::UnwindLocation &NextRegState, // TODO maybe re-name
+ const std::set<DWARFRegType> &Reads, const std::set<DWARFRegType> &Writes) {
auto RegLLVMOpt = MCRI->getLLVMRegNum(Reg, false);
if (RegLLVMOpt == std::nullopt) {
assert(PrevRegState == NextRegState);
return;
}
- MCPhysReg RegLLVM = RegLLVMOpt.value();
+ const char *RegLLVMName = MCRI->getName(RegLLVMOpt.value());
auto &&PrevRefReg =
PrevState.getReferenceRegisterForCallerValueOfRegister(Reg);
@@ -174,35 +203,50 @@ void CFIAnalysis::checkRegDiff(const MCInst &Inst, DWARFRegType Reg,
MCRI->getLLVMRegNum(PrevRefReg.value(), false).value())
: std::nullopt);
+ // TODO Again getting CFA register out of UnwindRow
+ // TODO consider either making it a help function.
+ // TODO Also, again you have to re-look in the assumption
+ // TODO that CFA is depending on another register, maybe
+ // TODO it's not true. And if it's always true, consider
+ // TODO asserting it (maybe in the helper function).
MCPhysReg PrevStateCFARegLLVM =
- MCRI->getLLVMRegNum(PrevState.CFARegister, false).value();
+ MCRI->getLLVMRegNum(PrevState.getLastRow()->getCFAValue().getRegister(),
+ false)
+ .value();
{ // try generate
// Widen
- std::vector<RegisterCFIState> PossibleNextRegStates;
+ std::vector<dwarf::UnwindLocation> PossibleNextRegStates;
{ // stay the same
- bool CanStayTheSame = false;
-
- switch (PrevRegState.RetrieveApproach) {
- case RegisterCFIState::Undefined:
- case RegisterCFIState::OffsetFromCFAVal:
- CanStayTheSame = true;
- break;
- case RegisterCFIState::SameValue:
- case RegisterCFIState::AnotherRegister:
- CanStayTheSame = !Writes.count(PrevRefReg.value());
- break;
- case RegisterCFIState::OffsetFromCFAAddr:
- case RegisterCFIState::Other:
- // cannot be sure
- break;
+ bool CanStayTheSame = true;
+
+ // TODO make sure it has meaning in `Undefined` or `Unspecified` case.
+ // TODO make it smarter, if it's in the memory and the instruction does
+ // TODO not store anything and the register (if any) to access that part
+ // TODO is not changed, then it's OK.
+ if (PrevRegState.getDereference())
+ CanStayTheSame = false;
+
+ if (PrevRefReg && Writes.count(PrevRefReg.value())) {
+ CanStayTheSame = false;
+ }
+
+ if (PrevRegState.getLocation() == dwarf::UnwindLocation::DWARFExpr) {
+ // TODO this can be solved more precise, by looking into the expression,
+ // TODO finding registers that are used and checking if the instruction
+ // TODO is changing them or not.
+ CanStayTheSame = false;
}
if (CanStayTheSame)
PossibleNextRegStates.push_back(PrevRegState);
}
+ // TODO In this stage of program, there is not possible next stages, it's
+ // TODO either the same or nothing. The maybe I have to refactor it back to
+ // TODO the primitive design. And when got the semantic info, get back to
+ // TODO this code.
for (auto &&PossibleNextRegState : PossibleNextRegStates) {
if (PossibleNextRegState == NextRegState) {
// Everything is ok
@@ -211,19 +255,19 @@ void CFIAnalysis::checkRegDiff(const MCInst &Inst, DWARFRegType Reg,
}
for (auto &&PossibleNextRegState : PossibleNextRegStates) {
- if (PossibleNextRegState.RetrieveApproach !=
- NextRegState.RetrieveApproach)
+ if (PossibleNextRegState.getLocation() != NextRegState.getLocation())
continue;
- if (PossibleNextRegState.RetrieveApproach ==
- RegisterCFIState::OffsetFromCFAAddr) {
- Context.reportError(
+ // TODO again, as said above, does this happen in the current primitive
+ // TODO design?
+ if (PossibleNextRegState.getLocation() ==
+ dwarf::UnwindLocation::CFAPlusOffset) {
+ Context->reportError(
Inst.getLoc(),
- formatv(
- "Expected caller's value of reg#{0} should be at offset {1} "
- "of CFA but the CFI directives say it's in {2}",
- RegLLVM, PossibleNextRegState.Info.OffsetFromCFA,
- NextRegState.Info.OffsetFromCFA));
+ formatv("Expected %{0} unwinding rule should be [CFA + {1}] but "
+ "based CFI directives are [CFA + {2}]",
+ RegLLVMName, PossibleNextRegState.getOffset(),
+ NextRegState.getOffset()));
}
}
}
@@ -232,18 +276,19 @@ void CFIAnalysis::checkRegDiff(const MCInst &Inst, DWARFRegType Reg,
// it falls back into read/write checks.
if (PrevRegState == NextRegState) {
- switch (PrevRegState.RetrieveApproach) {
- case RegisterCFIState::SameValue:
- case RegisterCFIState::AnotherRegister:
+ switch (PrevRegState.getLocation()) {
+ case dwarf::UnwindLocation::Same:
+ case dwarf::UnwindLocation::RegPlusOffset:
if (Writes.count(PrevRefReg.value())) {
- Context.reportError(
+ Context->reportError(
Inst.getLoc(),
- formatv("Reg#{0} caller's value is in reg#{1} which is changed "
- "by this instruction, but not changed in CFI directives",
- RegLLVM, PrevRefRegLLVM.value()));
+ formatv("This instruction changes %{1}, that %{0} unwinding rule "
+ "uses, but there is no CFI directives about it",
+ RegLLVMName, MCRI->getName(PrevRefRegLLVM.value())));
return;
}
break;
+ // TODO think about what to do with expressions here.
default:
// Everything may be ok
break;
@@ -251,22 +296,21 @@ void CFIAnalysis::checkRegDiff(const MCInst &Inst, DWARFRegType Reg,
return;
}
- if (PrevRegState.RetrieveApproach == NextRegState.RetrieveApproach) {
+ if (PrevRegState.getLocation() == NextRegState.getLocation()) {
// Everything may be ok
return;
}
- if (PrevRegState.RetrieveApproach == RegisterCFIState::Undefined) {
- Context.reportError(Inst.getLoc(),
- "Cannot change a register CFI information from "
- "undefined to something else.");
+ if (PrevRegState.getLocation() == dwarf::UnwindLocation::Undefined) {
+ Context->reportError(
+ Inst.getLoc(),
+ "Changed %{0} unwinding rule from `undefined` to something else");
return;
}
- Context.reportWarning(Inst.getLoc(),
- formatv("The reg#{0} CFI state is changed, but I "
- "don't have any idea how.",
- RegLLVM));
+ Context->reportWarning(
+ Inst.getLoc(),
+ formatv("Unknown change happened to %{0} unwinding rule", RegLLVMName));
// Everything may be ok
return;
}
@@ -275,16 +319,27 @@ void CFIAnalysis::checkCFADiff(const MCInst &Inst, const CFIState &PrevState,
const CFIState &NextState,
const std::set<DWARFRegType> &Reads,
const std::set<DWARFRegType> &Writes) {
+ // TODO again getting the CFA register in the bad way.
+ const DWARFRegType PrevCFAReg =
+ PrevState.getLastRow()->getCFAValue().getRegister();
+ const int32_t PrevCFAOffset =
+ PrevState.getLastRow()->getCFAValue().getOffset();
+
+ const DWARFRegType NextCFAReg =
+ NextState.getLastRow()->getCFAValue().getRegister();
+ const int32_t NextCFAOffset =
+ NextState.getLastRow()->getCFAValue().getOffset();
+
const char *PrevCFARegName =
- MCRI->getName(MCRI->getLLVMRegNum(PrevState.CFARegister, false).value());
+ MCRI->getName(MCRI->getLLVMRegNum(PrevCFAReg, false /* TODO */).value());
- if (PrevState.CFARegister == NextState.CFARegister) {
- if (PrevState.CFAOffset == NextState.CFAOffset) {
- if (Writes.count(PrevState.CFARegister)) {
- Context.reportError(
+ if (PrevCFAReg == NextCFAReg) {
+ if (PrevCFAOffset == NextCFAOffset) {
+ if (Writes.count(PrevCFAReg)) {
+ Context->reportError(
Inst.getLoc(),
- formatv("Missing CFI directive for the CFA offset adjustment. CFA "
- "register ({0}) is modified by this instruction.",
+ formatv("This instruction modifies CFA register (%{0}) "
+ "but CFA rule is not changed",
PrevCFARegName));
return;
}
@@ -294,11 +349,11 @@ void CFIAnalysis::checkCFADiff(const MCInst &Inst, const CFIState &PrevState,
}
// The offset is changed.
- if (!Writes.count(PrevState.CFARegister)) {
- Context.reportError(
+ if (!Writes.count(PrevCFAReg)) {
+ Context->reportError(
Inst.getLoc(),
- formatv("Wrong adjustment to CFA offset. CFA register ({0}) is not "
- "modified by this instruction.",
+ formatv("This instruction does not modifies CFA register (%{0}) "
+ "but CFA rule is changed",
PrevCFARegName));
}
diff --git a/llvm/lib/MCCFIAnalysis/CFIAnalysisMCStreamer.cpp b/llvm/lib/MCCFIAnalysis/CFIAnalysisMCStreamer.cpp
index 43855a4d75dc2..a2b5e308883d6 100644
--- a/llvm/lib/MCCFIAnalysis/CFIAnalysisMCStreamer.cpp
+++ b/llvm/lib/MCCFIAnalysis/CFIAnalysisMCStreamer.cpp
@@ -71,7 +71,7 @@ void CFIAnalysisMCStreamer::feedCFIA() {
CFIAs.back().update(LastInstruction.value(), CFIDirectives);
} else {
- CFIAs.emplace_back(getContext(), MCII, MCIA.get(), CFIDirectives);
+ CFIAs.emplace_back(&getContext(), MCII, MCIA.get(), CFIDirectives);
}
}
diff --git a/llvm/lib/MCCFIAnalysis/CFIState.cpp b/llvm/lib/MCCFIAnalysis/CFIState.cpp
index 4f4a6e168bef6..2d65d325cb22d 100644
--- a/llvm/lib/MCCFIAnalysis/CFIState.cpp
+++ b/llvm/lib/MCCFIAnalysis/CFIState.cpp
@@ -1,25 +1,88 @@
// TODO check what includes to keep and what to remove
#include "llvm/MCCFIAnalysis/CFIState.h"
-#include "llvm/ADT/DenseMap.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
#include "llvm/MC/MCDwarf.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormatVariadic.h"
#include <cassert>
-#include <cstdint>
#include <optional>
-#include <string>
using namespace llvm;
-dwarf::CFIProgram llvm::convertMC2DWARF(MCContext &Context,
- MCCFIInstruction CFIDirective,
- int64_t CFAOffset) {
+CFIState::CFIState(const CFIState &Other) : Context(Other.Context) {
+ // TODO maybe remove it
+ State = Other.State;
+}
+
+CFIState &CFIState::operator=(const CFIState &Other) {
+ // TODO maybe remove it
+ if (this != &Other) {
+ State = Other.State;
+ Context = Other.Context;
+ }
+
+ return *this;
+}
+
+std::optional<DWARFRegType>
+CFIState::getReferenceRegisterForCallerValueOfRegister(DWARFRegType Reg) const {
+ // TODO maybe move it the Location class
+ auto LastRow = getLastRow();
+ assert(LastRow && "The state is empty.");
+
+ auto UnwinLoc = LastRow->getRegisterLocations().getRegisterLocation(Reg);
+ assert(UnwinLoc &&
+ "The register should be tracked inside the register states");
+
+ switch (UnwinLoc->getLocation()) {
+ case dwarf::UnwindLocation::Location::Undefined:
+ case dwarf::UnwindLocation::Location::Constant:
+ case dwarf::UnwindLocation::Location::Unspecified:
+ // TODO here should look into expr and find the registers, but for now it's
+ // TODO like this:
+ case dwarf::UnwindLocation::Location::DWARFExpr:
+ return std::nullopt;
+ case dwarf::UnwindLocation::Location::Same:
+ return Reg;
+ case dwarf::UnwindLocation::Location::RegPlusOffset:
+ return UnwinLoc->getRegister();
+ case dwarf::UnwindLocation::Location::CFAPlusOffset:
+ // TODO check if it's ok to assume CFA is always depending on other
+ // TODO register, if yes assert it here!
+ return LastRow->getCFAValue().getRegister();
+ }
+}
+
+void CFIState::apply(const MCCFIInstruction &CFIDirective) {
+ auto DwarfOperations = convertMC2DWARF(CFIDirective);
+ if (!DwarfOperations) {
+ Context->reportError(
+ CFIDirective.getLoc(),
+ "couldn't apply this directive to the unwinding information state");
+ }
+
+ auto &&LastRow = getLastRow();
+ dwarf::UnwindRow Row = LastRow ? LastRow.value() : dwarf::UnwindRow();
+ if (Error Err = State.parseRows(DwarfOperations.value(), Row, nullptr)) {
+ // ! FIXME what should I do with this error?
+ Context->reportError(
+ CFIDirective.getLoc(),
+ formatv("could not parse this CFI directive due to: {0}",
+ toString(std::move(Err))));
+ assert(false);
+ }
+ State.insertRow(Row);
+}
+
+std::optional<dwarf::CFIProgram>
+CFIState::convertMC2DWARF(MCCFIInstruction CFIDirective) {
//! FIXME, this way of instantiating CFI program does not look right, either
//! refactor CFIProgram to not depend on the Code/Data Alignment or add a new
//! type that is independent from this and is also feedable to UnwindTable.
- auto DwarfOperations =
- dwarf::CFIProgram(0, 0, Context.getTargetTriple().getArch());
+ auto DwarfOperations = dwarf::CFIProgram(
+ 1 /* TODO */, 1 /* TODO */, Context->getTargetTriple().getArch());
switch (CFIDirective.getOperation()) {
case MCCFIInstruction::OpSameValue:
@@ -42,7 +105,7 @@ dwarf::CFIProgram llvm::convertMC2DWARF(MCContext &Context,
CFIDirective.getRegister());
break;
case MCCFIInstruction::OpDefCfaRegister:
- DwarfOperations.addInstruction(dwarf::DW_CFA_def_cfa,
+ DwarfOperations.addInstruction(dwarf::DW_CFA_def_cfa_register,
CFIDirective.getRegister());
break;
case MCCFIInstruction::OpDefCfaOffset:
@@ -55,13 +118,20 @@ dwarf::CFIProgram llvm::convertMC2DWARF(MCContext &Context,
CFIDirective.getOffset());
break;
case MCCFIInstruction::OpRelOffset:
- DwarfOperations.addInstruction(dwarf::DW_CFA_offset,
- CFIDirective.getRegister(),
- CFIDirective.getOffset() - CFAOffset);
+ if (!getLastRow()) // TODO maybe replace it with assert
+ return std::nullopt;
+
+ DwarfOperations.addInstruction(
+ dwarf::DW_CFA_offset, CFIDirective.getRegister(),
+ CFIDirective.getOffset() - getLastRow()->getCFAValue().getOffset());
break;
case MCCFIInstruction::OpAdjustCfaOffset:
+ if (!getLastRow()) // TODO maybe replace it with assert
+ return std::nullopt;
+
DwarfOperations.addInstruction(dwarf::DW_CFA_def_cfa_offset,
- CFIDirective.getOffset() + CFAOffset);
+ CFIDirective.getOffset() +
+ getLastRow()->getCFAValue().getOffset());
break;
case MCCFIInstruction::OpEscape:
// TODO It's now feasible but for now, I ignore it
@@ -107,187 +177,11 @@ dwarf::CFIProgram llvm::convertMC2DWARF(MCContext &Context,
return DwarfOperations;
}
-using DWARFRegType = int64_t;
-
-std::string RegisterCFIState::dump() {
- switch (RetrieveApproach) {
- case Undefined:
- return "undefined";
- case SameValue:
- return "same value";
- case AnotherRegister:
- return formatv("stored in another register, which is reg#{0}",
- Info.Register);
- case OffsetFromCFAAddr:
- return formatv("offset {0} from CFA", Info.OffsetFromCFA);
- case OffsetFromCFAVal:
- return formatv("CFA value + {0}", Info.OffsetFromCFA);
- case Other:
- return "other";
- }
-}
-
-bool RegisterCFIState::operator==(const RegisterCFIState &OtherState) const {
- if (RetrieveApproach != OtherState.RetrieveApproach)
- return false;
-
- switch (RetrieveApproach) {
- case Undefined:
- case SameValue:
- case Other:
- return true;
- case AnotherRegister:
- return Info.Register == OtherState.Info.Register;
- case OffsetFromCFAAddr:
- case OffsetFromCFAVal:
- return Info.OffsetFromCFA == OtherState.Info.OffsetFromCFA;
- }
-}
-
-bool RegisterCFIState::operator!=(const RegisterCFIState &OtherState) const {
- return !(*this == OtherState);
-}
-
-RegisterCFIState RegisterCFIState::createUndefined() {
- RegisterCFIState State;
- State.RetrieveApproach = Undefined;
-
- return State;
-}
-
-RegisterCFIState RegisterCFIState::createSameValue() {
- RegisterCFIState State;
- State.RetrieveApproach = SameValue;
-
- return State;
-}
-
-RegisterCFIState
-RegisterCFIState::createAnotherRegister(DWARFRegType Register) {
- RegisterCFIState State;
- State.RetrieveApproach = AnotherRegister;
- State.Info.Register = Register;
-
- return State;
-}
-
-RegisterCFIState RegisterCFIState::createOffsetFromCFAAddr(int OffsetFromCFA) {
- RegisterCFIState State;
- State.RetrieveApproach = OffsetFromCFAAddr;
- State.Info.OffsetFromCFA = OffsetFromCFA;
-
- return State;
-}
-
-RegisterCFIState RegisterCFIState::createOffsetFromCFAVal(int OffsetFromCFA) {
- RegisterCFIState State;
- State.RetrieveApproach = OffsetFromCFAVal;
- State.Info.OffsetFromCFA = OffsetFromCFA;
-
- return State;
-}
-
-RegisterCFIState RegisterCFIState::createOther() {
- RegisterCFIState State;
- State.RetrieveApproach = Other;
-
- return State;
-}
-
-CFIState::CFIState() : CFARegister(-1), CFAOffset(-1) {}
-
-CFIState::CFIState(const CFIState &Other) {
- CFARegister = Other.CFARegister;
- CFAOffset = Other.CFAOffset;
- RegisterCFIStates = Other.RegisterCFIStates;
-}
-
-CFIState &CFIState::operator=(const CFIState &Other) {
- if (this != &Other) {
- CFARegister = Other.CFARegister;
- CFAOffset = Other.CFAOffset;
- RegisterCFIStates = Other.RegisterCFIStates;
- }
-
- return *this;
-}
-
-CFIState::CFIState(DWARFRegType CFARegister, int CFIOffset)
- : CFARegister(CFARegister), CFAOffset(CFIOffset) {}
-
-std::optional<DWARFRegType>
-CFIState::getReferenceRegisterForCallerValueOfRegister(DWARFRegType Reg) const {
- assert(RegisterCFIStates.count(Reg) &&
- "The register should be tracked inside the register states");
- auto &&RegState = RegisterCFIStates.at(Reg);
- switch (RegState.RetrieveApproach) {
- case RegisterCFIState::Undefined:
- case RegisterCFIState::Other:
+std::optional<dwarf::UnwindRow> CFIState::getLastRow() const {
+ if (!State.size())
return std::nullopt;
- case RegisterCFIState::SameValue:
- return Reg;
- case RegisterCFIState::AnotherRegister:
- return RegState.Info.Register;
- case RegisterCFIState::OffsetFromCFAAddr:
- case RegisterCFIState::OffsetFromCFAVal:
- return CFARegister;
- }
-}
-bool CFIState::apply(const MCCFIInstruction &CFIDirective) {
- switch (CFIDirective.getOperation()) {
- case MCCFIInstruction::OpDefCfaRegister:
- CFARegister = CFIDirective.getRegister();
- break;
- case MCCFIInstruction::OpDefCfaOffset:
- CFAOffset = CFIDirective.getOffset();
- break;
- case MCCFIInstruction::OpAdjustCfaOffset:
- CFAOffset += CFIDirective.getOffset();
- break;
- case MCCFIInstruction::OpDefCfa:
- CFARegister = CFIDirective.getRegister();
- CFAOffset = CFIDirective.getOffset();
- break;
- case MCCFIInstruction::OpOffset:
- RegisterCFIStates[CFIDirective.getRegister()] =
- RegisterCFIState::createOffsetFromCFAAddr(CFIDirective.getOffset());
- break;
- case MCCFIInstruction::OpRegister:
- RegisterCFIStates[CFIDirective.getRegister()] =
- RegisterCFIState::createAnotherRegister(CFIDirective.getRegister2());
- break;
- case MCCFIInstruction::OpRelOffset:
- RegisterCFIStates[CFIDirective.getRegister()] =
- RegisterCFIState::createOffsetFromCFAAddr(CFIDirective.getOffset() -
- CFAOffset);
- break;
- case MCCFIInstruction::OpUndefined:
- RegisterCFIStates[CFIDirective.getRegister()] =
- RegisterCFIState::createUndefined();
- break;
- case MCCFIInstruction::OpSameValue:
- RegisterCFIStates[CFIDirective.getRegister()] =
- RegisterCFIState::createSameValue();
- break;
- case MCCFIInstruction::OpValOffset:
- RegisterCFIStates[CFIDirective.getRegister()] =
- RegisterCFIState::createOffsetFromCFAVal(CFIDirective.getOffset());
- break;
- case MCCFIInstruction::OpRestoreState:
- case MCCFIInstruction::OpRememberState:
- case MCCFIInstruction::OpLLVMDefAspaceCfa:
- case MCCFIInstruction::OpRestore:
- case MCCFIInstruction::OpEscape:
- case MCCFIInstruction::OpWindowSave:
- case MCCFIInstruction::OpNegateRAState:
- case MCCFIInstruction::OpNegateRAStateWithPC:
- case MCCFIInstruction::OpGnuArgsSize:
- case MCCFIInstruction::OpLabel:
- // These instructions are not supported.
- return false;
- break;
- }
-
- return true;
-}
+ //! FIXME too dirty
+ auto &&it = State.end();
+ return *--it;
+}
\ No newline at end of file
diff --git a/llvm/test/tools/llvm-mc/cfi-validation/single-func-cfa-mistake.s b/llvm/test/tools/llvm-mc/cfi-validation/single-func-cfa-mistake.s
index eb55ff6b378e8..1e9ffecbed81b 100644
--- a/llvm/test/tools/llvm-mc/cfi-validation/single-func-cfa-mistake.s
+++ b/llvm/test/tools/llvm-mc/cfi-validation/single-func-cfa-mistake.s
@@ -1,4 +1,4 @@
-# RUN: not llvm-mc %s --validate-cfi --filetype=null 2>&1 \
+# RUN: llvm-mc %s --validate-cfi --filetype=null 2>&1 \
# RUN: | FileCheck %s
.text
.globl f
@@ -9,7 +9,7 @@ f:
.cfi_undefined %rax
pushq %rbp
- # CHECK: error: Expected CFA [reg: 61, offset: 16] but got [reg: 61, offset: 17]
+ # CHECK: warning: Unknown change happened to %RBP unwinding rule
.cfi_def_cfa_offset 17
.cfi_offset %rbp, -16
diff --git a/llvm/test/tools/llvm-mc/cfi-validation/single-func-missed-cfi-directive.s b/llvm/test/tools/llvm-mc/cfi-validation/single-func-missed-cfi-directive.s
index 044c0bbf88eb6..bacc78c146cc1 100644
--- a/llvm/test/tools/llvm-mc/cfi-validation/single-func-missed-cfi-directive.s
+++ b/llvm/test/tools/llvm-mc/cfi-validation/single-func-missed-cfi-directive.s
@@ -12,7 +12,7 @@ f:
.cfi_def_cfa_offset 16
movq %rsp, %rbp
- # CHECK: error: Reg#52 caller's value is in reg#52 which is changed by this instruction, but not changed in CFI directives
+ # CHECK: error: This instruction changes %RBP, that %RBP unwinding rule uses, but there is no CFI directives about it
.cfi_def_cfa_register %rbp
movl %edi, -4(%rbp)
@@ -22,6 +22,7 @@ f:
addl $10, %eax
popq %rbp
+ # CHECK: error: This instruction changes %RBP, that %RBP unwinding rule uses, but there is no CFI directives about it
.cfi_def_cfa %rsp, 8
retq
diff --git a/llvm/test/tools/llvm-mc/cfi-validation/spill-two-reg-reversed.s b/llvm/test/tools/llvm-mc/cfi-validation/spill-two-reg-reversed.s
index d7baf3e871e87..30e74e5b159e7 100644
--- a/llvm/test/tools/llvm-mc/cfi-validation/spill-two-reg-reversed.s
+++ b/llvm/test/tools/llvm-mc/cfi-validation/spill-two-reg-reversed.s
@@ -11,31 +11,35 @@ _start:
.cfi_same_value %rsi
pushq %rbp
+ # CHECK: warning: Unknown change happened to %RBP unwinding rule
.cfi_adjust_cfa_offset 8
.cfi_offset %rbp, -16
movq %rsp, %rbp
pushq %rdi
+ # CHECK: warning: Unknown change happened to %RDI unwinding rule
.cfi_adjust_cfa_offset 8
.cfi_rel_offset %rdi, 0
pushq %rsi
+ # CHECK: warning: Unknown change happened to %RSI unwinding rule
.cfi_adjust_cfa_offset 8
.cfi_rel_offset %rsi, 0
popq %rsi
- # CHECK: warning: The reg#55 CFI state is changed
+ # CHECK: warning: Unknown change happened to %RDI unwinding rule
.cfi_adjust_cfa_offset -8
.cfi_same_value %rdi
popq %rdi
- # CHECK: warning: The reg#60 CFI state is changed
- # CHECK: Reg#55 caller's value is in reg#55 which is changed by this instruction, but not changed in CFI directives
+ # CHECK: error: This instruction changes %RDI, that %RDI unwinding rule uses, but there is no CFI directives about it
+ # CHECK: warning: Unknown change happened to %RSI unwinding rule
.cfi_adjust_cfa_offset -8
.cfi_same_value %rsi
popq %rbp
+ # CHECK: warning: Unknown change happened to %RBP unwinding rule
.cfi_adjust_cfa_offset -8
.cfi_same_value %rbp
diff --git a/llvm/test/tools/llvm-mc/cfi-validation/update-with-no-cfi.s b/llvm/test/tools/llvm-mc/cfi-validation/update-with-no-cfi.s
index 1384d8a864608..ebf4bf4ed5472 100644
--- a/llvm/test/tools/llvm-mc/cfi-validation/update-with-no-cfi.s
+++ b/llvm/test/tools/llvm-mc/cfi-validation/update-with-no-cfi.s
@@ -12,16 +12,16 @@ f:
.cfi_same_value %rdx
movq $10, %rax
- # CHECK: error: Reg#51 caller's value is in reg#51 which is changed by this instruction, but not changed in CFI directives
+ # CHECK: error: This instruction changes %RAX, that %RAX unwinding rule uses, but there is no CFI directives about it
movq $10, %rbx
- # CHECK: error: Reg#53 caller's value is in reg#53 which is changed by this instruction, but not changed in CFI directives
+ # CHECK: error: This instruction changes %RBX, that %RBX unwinding rule uses, but there is no CFI directives about it
movq $10, %rcx
- # CHECK: error: Reg#54 caller's value is in reg#54 which is changed by this instruction, but not changed in CFI directives
+ # CHECK: error: This instruction changes %RCX, that %RCX unwinding rule uses, but there is no CFI directives about it
movq $10, %rdx
- # CHECK: error: Reg#56 caller's value is in reg#56 which is changed by this instruction, but not changed in CFI directives
+ # CHECK: error: This instruction changes %RDX, that %RDX unwinding rule uses, but there is no CFI directives about it
retq
>From 6b727ec9eb95fe74d7facbd4288cafcac9e65126 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Tue, 17 Jun 2025 18:21:50 +0000
Subject: [PATCH 33/58] Make CFI analysis available both EH and Debug frames
---
llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h | 3 +-
llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp | 38 +++++++++----------
.../MCCFIAnalysis/CFIAnalysisMCStreamer.cpp | 3 +-
3 files changed, 22 insertions(+), 22 deletions(-)
diff --git a/llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h b/llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h
index 9642a3fafabb6..46e2c0a2c0656 100644
--- a/llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h
+++ b/llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h
@@ -27,6 +27,7 @@ class CFIAnalysis {
MCRegisterInfo const *MCRI;
std::unique_ptr<ExtendedMCInstrAnalysis> EMCIA;
CFIState State;
+ bool IsEH;
private:
// The CFI analysis only keeps track and cares about super registers, not the
@@ -44,7 +45,7 @@ class CFIAnalysis {
public:
CFIAnalysis(MCContext *Context, MCInstrInfo const &MCII,
- MCInstrAnalysis *MCIA,
+ MCInstrAnalysis *MCIA, bool IsEH,
ArrayRef<MCCFIInstruction> PrologueCFIDirectives);
void update(const MCInst &Inst, ArrayRef<MCCFIInstruction> CFIDirectives);
diff --git a/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp b/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp
index 80403c341707c..7e07d846860dc 100644
--- a/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp
+++ b/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp
@@ -67,18 +67,17 @@ MCPhysReg CFIAnalysis::getSuperReg(MCPhysReg Reg) {
}
CFIAnalysis::CFIAnalysis(MCContext *Context, MCInstrInfo const &MCII,
- MCInstrAnalysis *MCIA,
+ MCInstrAnalysis *MCIA, bool IsEH,
ArrayRef<MCCFIInstruction> PrologueCFIDirectives)
: Context(Context), MCII(MCII), MCRI(Context->getRegisterInfo()),
- State(Context) {
+ State(Context), IsEH(IsEH) {
EMCIA.reset(new ExtendedMCInstrAnalysis(Context, MCII, MCIA));
- // TODO check what should be passed as EH? I am putting false everywhere.
for (auto &&[Reg, RegClass] : getAllSuperRegs()) {
if (MCRI->get(Reg).IsArtificial || MCRI->get(Reg).IsConstant)
continue;
- DWARFRegType DwarfReg = MCRI->getDwarfRegNum(Reg, false);
+ DWARFRegType DwarfReg = MCRI->getDwarfRegNum(Reg, IsEH);
// TODO is it OK to create fake CFI directives for doing this?
State.apply(MCCFIInstruction::createSameValue(nullptr, DwarfReg));
}
@@ -93,7 +92,7 @@ CFIAnalysis::CFIAnalysis(MCContext *Context, MCInstrInfo const &MCII,
State.apply(MCCFIInstruction::createUndefined(
nullptr,
MCRI->getDwarfRegNum(MCRI->getProgramCounter(),
- false))); // TODO for now, we don't care about the PC
+ IsEH))); // TODO for now, we don't care about the PC
// TODO
auto LastRow = State.getLastRow();
assert(LastRow && "there should be at least one row");
@@ -106,7 +105,7 @@ CFIAnalysis::CFIAnalysis(MCContext *Context, MCInstrInfo const &MCII,
State.apply(MCCFIInstruction::createUndefined(
nullptr, MCRI->getDwarfRegNum(EMCIA->getFlagsReg(),
- false))); // Flags cannot be caller-saved
+ IsEH))); // Flags cannot be caller-saved
// Applying the prologue after default assumptions to overwrite them.
for (auto &&PrologueCFIDirective : PrologueCFIDirectives) {
@@ -129,28 +128,27 @@ void CFIAnalysis::update(const MCInst &Inst,
std::set<DWARFRegType> Writes, Reads;
for (unsigned I = 0; I < MCInstInfo.NumImplicitUses; I++)
- Reads.insert(MCRI->getDwarfRegNum(
- getSuperReg(MCInstInfo.implicit_uses()[I]), false));
+ Reads.insert(
+ MCRI->getDwarfRegNum(getSuperReg(MCInstInfo.implicit_uses()[I]), IsEH));
for (unsigned I = 0; I < MCInstInfo.NumImplicitDefs; I++)
- Writes.insert(MCRI->getDwarfRegNum(
- getSuperReg(MCInstInfo.implicit_defs()[I]), false));
+ Writes.insert(
+ MCRI->getDwarfRegNum(getSuperReg(MCInstInfo.implicit_defs()[I]), IsEH));
for (unsigned I = 0; I < Inst.getNumOperands(); I++) {
auto &&Operand = Inst.getOperand(I);
if (Operand.isReg()) {
if (I < MCInstInfo.getNumDefs())
Writes.insert(
- MCRI->getDwarfRegNum(getSuperReg(Operand.getReg()), false));
+ MCRI->getDwarfRegNum(getSuperReg(Operand.getReg()), IsEH));
else if (Operand.getReg())
- Reads.insert(
- MCRI->getDwarfRegNum(getSuperReg(Operand.getReg()), false));
+ Reads.insert(MCRI->getDwarfRegNum(getSuperReg(Operand.getReg()), IsEH));
}
}
checkCFADiff(Inst, State, AfterState, Reads, Writes);
for (auto [LLVMReg, _] : getAllSuperRegs()) {
- DWARFRegType Reg = MCRI->getDwarfRegNum(LLVMReg, false);
+ DWARFRegType Reg = MCRI->getDwarfRegNum(LLVMReg, IsEH);
auto PrevUnwindLoc =
State.getLastRow()->getRegisterLocations().getRegisterLocation(Reg);
@@ -182,7 +180,7 @@ void CFIAnalysis::checkRegDiff(
const dwarf::UnwindLocation &PrevRegState, // TODO maybe re-name
const dwarf::UnwindLocation &NextRegState, // TODO maybe re-name
const std::set<DWARFRegType> &Reads, const std::set<DWARFRegType> &Writes) {
- auto RegLLVMOpt = MCRI->getLLVMRegNum(Reg, false);
+ auto RegLLVMOpt = MCRI->getLLVMRegNum(Reg, IsEH);
if (RegLLVMOpt == std::nullopt) {
assert(PrevRegState == NextRegState);
return;
@@ -195,12 +193,12 @@ void CFIAnalysis::checkRegDiff(
std::optional<MCPhysReg> PrevRefRegLLVM =
(PrevRefReg != std::nullopt
? std::make_optional(
- MCRI->getLLVMRegNum(PrevRefReg.value(), false).value())
+ MCRI->getLLVMRegNum(PrevRefReg.value(), IsEH).value())
: std::nullopt);
std::optional<MCPhysReg> NextRefRegLLVM =
(PrevRefReg != std::nullopt
? std::make_optional(
- MCRI->getLLVMRegNum(PrevRefReg.value(), false).value())
+ MCRI->getLLVMRegNum(PrevRefReg.value(), IsEH).value())
: std::nullopt);
// TODO Again getting CFA register out of UnwindRow
@@ -211,7 +209,7 @@ void CFIAnalysis::checkRegDiff(
// TODO asserting it (maybe in the helper function).
MCPhysReg PrevStateCFARegLLVM =
MCRI->getLLVMRegNum(PrevState.getLastRow()->getCFAValue().getRegister(),
- false)
+ IsEH)
.value();
{ // try generate
@@ -244,7 +242,7 @@ void CFIAnalysis::checkRegDiff(
}
// TODO In this stage of program, there is not possible next stages, it's
- // TODO either the same or nothing. The maybe I have to refactor it back to
+ // TODO either the same or nothing. Then maybe I have to refactor it back to
// TODO the primitive design. And when got the semantic info, get back to
// TODO this code.
for (auto &&PossibleNextRegState : PossibleNextRegStates) {
@@ -331,7 +329,7 @@ void CFIAnalysis::checkCFADiff(const MCInst &Inst, const CFIState &PrevState,
NextState.getLastRow()->getCFAValue().getOffset();
const char *PrevCFARegName =
- MCRI->getName(MCRI->getLLVMRegNum(PrevCFAReg, false /* TODO */).value());
+ MCRI->getName(MCRI->getLLVMRegNum(PrevCFAReg, IsEH).value());
if (PrevCFAReg == NextCFAReg) {
if (PrevCFAOffset == NextCFAOffset) {
diff --git a/llvm/lib/MCCFIAnalysis/CFIAnalysisMCStreamer.cpp b/llvm/lib/MCCFIAnalysis/CFIAnalysisMCStreamer.cpp
index a2b5e308883d6..822f7c3d61089 100644
--- a/llvm/lib/MCCFIAnalysis/CFIAnalysisMCStreamer.cpp
+++ b/llvm/lib/MCCFIAnalysis/CFIAnalysisMCStreamer.cpp
@@ -71,7 +71,8 @@ void CFIAnalysisMCStreamer::feedCFIA() {
CFIAs.back().update(LastInstruction.value(), CFIDirectives);
} else {
- CFIAs.emplace_back(&getContext(), MCII, MCIA.get(), CFIDirectives);
+ CFIAs.emplace_back(&getContext(), MCII, MCIA.get(),
+ false /* TODO should put isEH here */, CFIDirectives);
}
}
>From 580b1fc50e4fcc0e2d43db3e19ad94e263400c77 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Wed, 18 Jun 2025 22:43:31 +0000
Subject: [PATCH 34/58] Remove ExtendedMCA
---
llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h | 3 --
.../MCCFIAnalysis/ExtendedMCInstrAnalysis.h | 28 -------------------
llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp | 8 +-----
3 files changed, 1 insertion(+), 38 deletions(-)
delete mode 100644 llvm/include/llvm/MCCFIAnalysis/ExtendedMCInstrAnalysis.h
diff --git a/llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h b/llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h
index 46e2c0a2c0656..32b02b67093a0 100644
--- a/llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h
+++ b/llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h
@@ -2,7 +2,6 @@
#define LLVM_TOOLS_LLVM_MC_CFI_ANALYSIS_H
#include "CFIState.h"
-#include "ExtendedMCInstrAnalysis.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
@@ -16,7 +15,6 @@
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/TargetRegistry.h"
-#include <memory>
#include <set>
namespace llvm {
@@ -25,7 +23,6 @@ class CFIAnalysis {
MCContext *Context;
MCInstrInfo const &MCII;
MCRegisterInfo const *MCRI;
- std::unique_ptr<ExtendedMCInstrAnalysis> EMCIA;
CFIState State;
bool IsEH;
diff --git a/llvm/include/llvm/MCCFIAnalysis/ExtendedMCInstrAnalysis.h b/llvm/include/llvm/MCCFIAnalysis/ExtendedMCInstrAnalysis.h
deleted file mode 100644
index 12d6227922a2b..0000000000000
--- a/llvm/include/llvm/MCCFIAnalysis/ExtendedMCInstrAnalysis.h
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef LLVM_TOOLS_LLVM_MC_EXTENDED_MC_INSTR_ANALYSIS_H
-#define LLVM_TOOLS_LLVM_MC_EXTENDED_MC_INSTR_ANALYSIS_H
-
-#include "llvm/MC/MCContext.h"
-#include "llvm/MC/MCDwarf.h"
-#include "llvm/MC/MCExpr.h"
-#include "llvm/MC/MCInstrInfo.h"
-#include "llvm/MC/MCRegister.h"
-#include "llvm/MC/MCStreamer.h"
-#include "llvm/MC/TargetRegistry.h"
-
-namespace llvm {
-
-// TODO remove this class entirely
-class ExtendedMCInstrAnalysis {
-private:
-public:
- ExtendedMCInstrAnalysis(MCContext *Context, MCInstrInfo const &MCII,
- MCInstrAnalysis *MCIA) {}
-
- /// Extra semantic information needed from MC layer:
-
- MCPhysReg getFlagsReg() const { return 57; }
-};
-
-} // namespace llvm
-
-#endif
\ No newline at end of file
diff --git a/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp b/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp
index 7e07d846860dc..82eb119e208bc 100644
--- a/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp
+++ b/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp
@@ -16,7 +16,6 @@
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/MCCFIAnalysis/CFIState.h"
-#include "llvm/MCCFIAnalysis/ExtendedMCInstrAnalysis.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormatVariadic.h"
@@ -43,7 +42,7 @@ CFIAnalysis::getAllSuperRegs() {
for (auto &&RegClass : MCRI->regclasses()) {
for (unsigned I = 0; I < RegClass.getNumRegs(); I++) {
MCPhysReg Reg = RegClass.getRegister(I);
- if (!isSuperReg(Reg))
+ if (!isSuperReg(Reg) || MCRI->isArtificial(Reg) || MCRI->isConstant(Reg))
continue;
SuperRegs[Reg] = &RegClass;
}
@@ -71,7 +70,6 @@ CFIAnalysis::CFIAnalysis(MCContext *Context, MCInstrInfo const &MCII,
ArrayRef<MCCFIInstruction> PrologueCFIDirectives)
: Context(Context), MCII(MCII), MCRI(Context->getRegisterInfo()),
State(Context), IsEH(IsEH) {
- EMCIA.reset(new ExtendedMCInstrAnalysis(Context, MCII, MCIA));
for (auto &&[Reg, RegClass] : getAllSuperRegs()) {
if (MCRI->get(Reg).IsArtificial || MCRI->get(Reg).IsConstant)
@@ -103,10 +101,6 @@ CFIAnalysis::CFIAnalysis(MCContext *Context, MCInstrInfo const &MCII,
nullptr, LastRow->getCFAValue().getRegister(),
0)); // sp's old value is CFA
- State.apply(MCCFIInstruction::createUndefined(
- nullptr, MCRI->getDwarfRegNum(EMCIA->getFlagsReg(),
- IsEH))); // Flags cannot be caller-saved
-
// Applying the prologue after default assumptions to overwrite them.
for (auto &&PrologueCFIDirective : PrologueCFIDirectives) {
State.apply(PrologueCFIDirective);
>From 7f4daf84dc87d1a634bffd8f753167c1d0ea3aef Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Fri, 20 Jun 2025 02:40:30 +0000
Subject: [PATCH 35/58] Use UnwindRow as state and record the UnwindHistory
---
llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h | 22 ++---
llvm/include/llvm/MCCFIAnalysis/CFIState.h | 38 ---------
.../llvm/MCCFIAnalysis/UnwindInfoHistory.h | 31 +++++++
llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp | 85 +++++++++----------
llvm/lib/MCCFIAnalysis/CMakeLists.txt | 2 +-
.../{CFIState.cpp => UnwindInfoHistory.cpp} | 74 ++++++----------
6 files changed, 114 insertions(+), 138 deletions(-)
delete mode 100644 llvm/include/llvm/MCCFIAnalysis/CFIState.h
create mode 100644 llvm/include/llvm/MCCFIAnalysis/UnwindInfoHistory.h
rename llvm/lib/MCCFIAnalysis/{CFIState.cpp => UnwindInfoHistory.cpp} (74%)
diff --git a/llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h b/llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h
index 32b02b67093a0..e150392ceb77c 100644
--- a/llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h
+++ b/llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h
@@ -1,7 +1,7 @@
#ifndef LLVM_TOOLS_LLVM_MC_CFI_ANALYSIS_H
#define LLVM_TOOLS_LLVM_MC_CFI_ANALYSIS_H
-#include "CFIState.h"
+#include "UnwindInfoHistory.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
@@ -23,7 +23,7 @@ class CFIAnalysis {
MCContext *Context;
MCInstrInfo const &MCII;
MCRegisterInfo const *MCRI;
- CFIState State;
+ UnwindInfoHistory State;
bool IsEH;
private:
@@ -49,19 +49,21 @@ class CFIAnalysis {
private:
void checkRegDiff(
- const MCInst &Inst, DWARFRegType Reg, const CFIState &PrevState,
- const CFIState &NextState,
+ const MCInst &Inst, UnwindInfoHistory::DWARFRegType Reg,
+ const dwarf::UnwindTable::const_iterator &PrevState,
+ const dwarf::UnwindTable::const_iterator &NextState,
const dwarf::UnwindLocation
&PrevRegState, // TODO maybe should get them from prev next state
const dwarf::UnwindLocation
&NextRegState, // TODO themselves instead of by arguments.
- const std::set<DWARFRegType> &Reads,
- const std::set<DWARFRegType> &Writes);
+ const std::set<UnwindInfoHistory::DWARFRegType> &Reads,
+ const std::set<UnwindInfoHistory::DWARFRegType> &Writes);
- void checkCFADiff(const MCInst &Inst, const CFIState &PrevState,
- const CFIState &NextState,
- const std::set<DWARFRegType> &Reads,
- const std::set<DWARFRegType> &Writes);
+ void checkCFADiff(const MCInst &Inst,
+ const dwarf::UnwindTable::const_iterator &PrevState,
+ const dwarf::UnwindTable::const_iterator &NextState,
+ const std::set<UnwindInfoHistory::DWARFRegType> &Reads,
+ const std::set<UnwindInfoHistory::DWARFRegType> &Writes);
};
} // namespace llvm
diff --git a/llvm/include/llvm/MCCFIAnalysis/CFIState.h b/llvm/include/llvm/MCCFIAnalysis/CFIState.h
deleted file mode 100644
index 7da036c0009e8..0000000000000
--- a/llvm/include/llvm/MCCFIAnalysis/CFIState.h
+++ /dev/null
@@ -1,38 +0,0 @@
-#ifndef LLVM_TOOLS_LLVM_MC_CFI_STATE_H
-#define LLVM_TOOLS_LLVM_MC_CFI_STATE_H
-
-#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
-#include "llvm/MC/MCContext.h"
-#include "llvm/MC/MCDwarf.h"
-#include <optional>
-namespace llvm {
-
-using DWARFRegType = int64_t;
-
-class CFIState {
-private:
- MCContext *Context;
- // TODO the choice is questionable, should the state be the Table? or just a
- // TODO row? In the current code we are using only the last row.
- dwarf::UnwindTable State;
-
-public:
- std::optional<dwarf::UnwindRow>
- getLastRow() const; // TODO maybe move it UnwindRow
-
- CFIState(MCContext *Context) : Context(Context) {};
- CFIState(const CFIState &Other);
- CFIState &operator=(const CFIState &Other);
-
- std::optional<DWARFRegType>
- getReferenceRegisterForCallerValueOfRegister(DWARFRegType Reg) const;
-
- void apply(const MCCFIInstruction &CFIDirective);
-
-private:
- std::optional<dwarf::CFIProgram> convertMC2DWARF(
- MCCFIInstruction CFIDirective); // TODO maybe move it somewhere else
-};
-} // namespace llvm
-
-#endif
\ No newline at end of file
diff --git a/llvm/include/llvm/MCCFIAnalysis/UnwindInfoHistory.h b/llvm/include/llvm/MCCFIAnalysis/UnwindInfoHistory.h
new file mode 100644
index 0000000000000..9a792e1f5f39e
--- /dev/null
+++ b/llvm/include/llvm/MCCFIAnalysis/UnwindInfoHistory.h
@@ -0,0 +1,31 @@
+#ifndef LLVM_TOOLS_LLVM_MC_CFI_STATE_H
+#define LLVM_TOOLS_LLVM_MC_CFI_STATE_H
+
+#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDwarf.h"
+#include <optional>
+namespace llvm {
+
+class UnwindInfoHistory {
+public:
+ using DWARFRegType = uint32_t;
+
+ UnwindInfoHistory(MCContext *Context) : Context(Context) {};
+
+ static std::optional<DWARFRegType>
+ getReferenceRegisterForUnwindInfoOfRegister(
+ const dwarf::UnwindTable::const_iterator &UnwindRow, DWARFRegType Reg);
+
+ std::optional<dwarf::UnwindTable::const_iterator> getCurrentUnwindRow() const;
+ void update(const MCCFIInstruction &CFIDirective);
+
+private:
+ MCContext *Context;
+ dwarf::UnwindTable Table;
+
+ std::optional<dwarf::CFIProgram> convert(MCCFIInstruction CFIDirective);
+};
+} // namespace llvm
+
+#endif
\ No newline at end of file
diff --git a/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp b/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp
index 82eb119e208bc..dc4cda0bbe83d 100644
--- a/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp
+++ b/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp
@@ -15,12 +15,11 @@
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/TargetRegistry.h"
-#include "llvm/MCCFIAnalysis/CFIState.h"
+#include "llvm/MCCFIAnalysis/UnwindInfoHistory.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormatVariadic.h"
#include <cstdint>
-#include <memory>
#include <optional>
#include <set>
@@ -75,44 +74,44 @@ CFIAnalysis::CFIAnalysis(MCContext *Context, MCInstrInfo const &MCII,
if (MCRI->get(Reg).IsArtificial || MCRI->get(Reg).IsConstant)
continue;
- DWARFRegType DwarfReg = MCRI->getDwarfRegNum(Reg, IsEH);
+ UnwindInfoHistory::DWARFRegType DwarfReg = MCRI->getDwarfRegNum(Reg, IsEH);
// TODO is it OK to create fake CFI directives for doing this?
- State.apply(MCCFIInstruction::createSameValue(nullptr, DwarfReg));
+ State.update(MCCFIInstruction::createSameValue(nullptr, DwarfReg));
}
for (auto &&InitialFrameStateCFIDirective :
Context->getAsmInfo()->getInitialFrameState()) {
- State.apply(InitialFrameStateCFIDirective);
+ State.update(InitialFrameStateCFIDirective);
}
// TODO these are temporay added to make things work.
// Setup the basic information:
- State.apply(MCCFIInstruction::createUndefined(
+ State.update(MCCFIInstruction::createUndefined(
nullptr,
MCRI->getDwarfRegNum(MCRI->getProgramCounter(),
IsEH))); // TODO for now, we don't care about the PC
// TODO
- auto LastRow = State.getLastRow();
+ auto LastRow = State.getCurrentUnwindRow();
assert(LastRow && "there should be at least one row");
// TODO assert that CFA is there, and based on register.
// TODO
- State.apply(MCCFIInstruction::createOffset(
- nullptr, LastRow->getCFAValue().getRegister(),
+ State.update(MCCFIInstruction::createOffset(
+ nullptr, LastRow.value()->getCFAValue().getRegister(),
0)); // sp's old value is CFA
// Applying the prologue after default assumptions to overwrite them.
for (auto &&PrologueCFIDirective : PrologueCFIDirectives) {
- State.apply(PrologueCFIDirective);
+ State.update(PrologueCFIDirective);
}
}
void CFIAnalysis::update(const MCInst &Inst,
ArrayRef<MCCFIInstruction> CFIDirectives) {
const MCInstrDesc &MCInstInfo = MCII.get(Inst.getOpcode());
- CFIState AfterState(State);
+ auto PrevUnwindRow = State.getCurrentUnwindRow().value();
for (auto &&CFIDirective : CFIDirectives)
- AfterState.apply(CFIDirective);
+ State.update(CFIDirective);
//! if (!AfterState.apply(CFIDirective))
//! Context->reportWarning(
@@ -120,7 +119,7 @@ void CFIAnalysis::update(const MCInst &Inst,
//! "I don't support this CFI directive, I assume this does nothing "
//! "(which will probably break other things)");
- std::set<DWARFRegType> Writes, Reads;
+ std::set<UnwindInfoHistory::DWARFRegType> Writes, Reads;
for (unsigned I = 0; I < MCInstInfo.NumImplicitUses; I++)
Reads.insert(
MCRI->getDwarfRegNum(getSuperReg(MCInstInfo.implicit_uses()[I]), IsEH));
@@ -139,16 +138,18 @@ void CFIAnalysis::update(const MCInst &Inst,
}
}
- checkCFADiff(Inst, State, AfterState, Reads, Writes);
+ checkCFADiff(Inst, PrevUnwindRow, State.getCurrentUnwindRow().value(), Reads,
+ Writes);
for (auto [LLVMReg, _] : getAllSuperRegs()) {
- DWARFRegType Reg = MCRI->getDwarfRegNum(LLVMReg, IsEH);
+ UnwindInfoHistory::DWARFRegType Reg = MCRI->getDwarfRegNum(LLVMReg, IsEH);
auto PrevUnwindLoc =
- State.getLastRow()->getRegisterLocations().getRegisterLocation(Reg);
- auto NextUnwindLoc =
- AfterState.getLastRow()->getRegisterLocations().getRegisterLocation(
- Reg);
+ PrevUnwindRow->getRegisterLocations().getRegisterLocation(Reg);
+ auto NextUnwindLoc = State.getCurrentUnwindRow()
+ .value()
+ ->getRegisterLocations()
+ .getRegisterLocation(Reg);
// TODO think more if these assertions are OK
// TODO maybe change them to error messages.
@@ -161,19 +162,19 @@ void CFIAnalysis::update(const MCInst &Inst,
assert(NextUnwindLoc &&
"A CFI directive should not delete a register state.");
- checkRegDiff(Inst, Reg, State, AfterState, PrevUnwindLoc.value(),
- NextUnwindLoc.value(), Reads, Writes);
+ checkRegDiff(Inst, Reg, PrevUnwindRow, State.getCurrentUnwindRow().value(),
+ PrevUnwindLoc.value(), NextUnwindLoc.value(), Reads, Writes);
}
-
- State = AfterState;
}
void CFIAnalysis::checkRegDiff(
- const MCInst &Inst, DWARFRegType Reg, const CFIState &PrevState,
- const CFIState &NextState,
+ const MCInst &Inst, UnwindInfoHistory::DWARFRegType Reg,
+ const dwarf::UnwindTable::const_iterator &PrevState,
+ const dwarf::UnwindTable::const_iterator &NextState,
const dwarf::UnwindLocation &PrevRegState, // TODO maybe re-name
const dwarf::UnwindLocation &NextRegState, // TODO maybe re-name
- const std::set<DWARFRegType> &Reads, const std::set<DWARFRegType> &Writes) {
+ const std::set<UnwindInfoHistory::DWARFRegType> &Reads,
+ const std::set<UnwindInfoHistory::DWARFRegType> &Writes) {
auto RegLLVMOpt = MCRI->getLLVMRegNum(Reg, IsEH);
if (RegLLVMOpt == std::nullopt) {
assert(PrevRegState == NextRegState);
@@ -182,7 +183,8 @@ void CFIAnalysis::checkRegDiff(
const char *RegLLVMName = MCRI->getName(RegLLVMOpt.value());
auto &&PrevRefReg =
- PrevState.getReferenceRegisterForCallerValueOfRegister(Reg);
+ UnwindInfoHistory::getReferenceRegisterForUnwindInfoOfRegister(PrevState,
+ Reg);
std::optional<MCPhysReg> PrevRefRegLLVM =
(PrevRefReg != std::nullopt
@@ -202,9 +204,7 @@ void CFIAnalysis::checkRegDiff(
// TODO it's not true. And if it's always true, consider
// TODO asserting it (maybe in the helper function).
MCPhysReg PrevStateCFARegLLVM =
- MCRI->getLLVMRegNum(PrevState.getLastRow()->getCFAValue().getRegister(),
- IsEH)
- .value();
+ MCRI->getLLVMRegNum(PrevState->getCFAValue().getRegister(), IsEH).value();
{ // try generate
// Widen
@@ -307,20 +307,19 @@ void CFIAnalysis::checkRegDiff(
return;
}
-void CFIAnalysis::checkCFADiff(const MCInst &Inst, const CFIState &PrevState,
- const CFIState &NextState,
- const std::set<DWARFRegType> &Reads,
- const std::set<DWARFRegType> &Writes) {
+void CFIAnalysis::checkCFADiff(
+ const MCInst &Inst, const dwarf::UnwindTable::const_iterator &PrevState,
+ const dwarf::UnwindTable::const_iterator &NextState,
+ const std::set<UnwindInfoHistory::DWARFRegType> &Reads,
+ const std::set<UnwindInfoHistory::DWARFRegType> &Writes) {
// TODO again getting the CFA register in the bad way.
- const DWARFRegType PrevCFAReg =
- PrevState.getLastRow()->getCFAValue().getRegister();
- const int32_t PrevCFAOffset =
- PrevState.getLastRow()->getCFAValue().getOffset();
-
- const DWARFRegType NextCFAReg =
- NextState.getLastRow()->getCFAValue().getRegister();
- const int32_t NextCFAOffset =
- NextState.getLastRow()->getCFAValue().getOffset();
+ const UnwindInfoHistory::DWARFRegType PrevCFAReg =
+ PrevState->getCFAValue().getRegister();
+ const int32_t PrevCFAOffset = PrevState->getCFAValue().getOffset();
+
+ const UnwindInfoHistory::DWARFRegType NextCFAReg =
+ NextState->getCFAValue().getRegister();
+ const int32_t NextCFAOffset = NextState->getCFAValue().getOffset();
const char *PrevCFARegName =
MCRI->getName(MCRI->getLLVMRegNum(PrevCFAReg, IsEH).value());
diff --git a/llvm/lib/MCCFIAnalysis/CMakeLists.txt b/llvm/lib/MCCFIAnalysis/CMakeLists.txt
index 15622132de7d4..b4a5da108de5b 100644
--- a/llvm/lib/MCCFIAnalysis/CMakeLists.txt
+++ b/llvm/lib/MCCFIAnalysis/CMakeLists.txt
@@ -1,5 +1,5 @@
add_llvm_component_library(LLVMMCCFIAnalysis
- CFIState.cpp
+ UnwindInfoHistory.cpp
CFIAnalysisMCStreamer.cpp
CFIAnalysis.cpp
diff --git a/llvm/lib/MCCFIAnalysis/CFIState.cpp b/llvm/lib/MCCFIAnalysis/UnwindInfoHistory.cpp
similarity index 74%
rename from llvm/lib/MCCFIAnalysis/CFIState.cpp
rename to llvm/lib/MCCFIAnalysis/UnwindInfoHistory.cpp
index 2d65d325cb22d..cc164aabfb1eb 100644
--- a/llvm/lib/MCCFIAnalysis/CFIState.cpp
+++ b/llvm/lib/MCCFIAnalysis/UnwindInfoHistory.cpp
@@ -1,5 +1,5 @@
// TODO check what includes to keep and what to remove
-#include "llvm/MCCFIAnalysis/CFIState.h"
+#include "llvm/MCCFIAnalysis/UnwindInfoHistory.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
#include "llvm/MC/MCDwarf.h"
@@ -11,28 +11,18 @@
using namespace llvm;
-CFIState::CFIState(const CFIState &Other) : Context(Other.Context) {
- // TODO maybe remove it
- State = Other.State;
-}
-
-CFIState &CFIState::operator=(const CFIState &Other) {
- // TODO maybe remove it
- if (this != &Other) {
- State = Other.State;
- Context = Other.Context;
- }
+std::optional<dwarf::UnwindTable::const_iterator>
+UnwindInfoHistory::getCurrentUnwindRow() const {
+ if (!Table.size())
+ return std::nullopt;
- return *this;
+ return --Table.end();
}
-std::optional<DWARFRegType>
-CFIState::getReferenceRegisterForCallerValueOfRegister(DWARFRegType Reg) const {
- // TODO maybe move it the Location class
- auto LastRow = getLastRow();
- assert(LastRow && "The state is empty.");
-
- auto UnwinLoc = LastRow->getRegisterLocations().getRegisterLocation(Reg);
+std::optional<UnwindInfoHistory::DWARFRegType>
+UnwindInfoHistory::getReferenceRegisterForUnwindInfoOfRegister(
+ const dwarf::UnwindTable::const_iterator &UnwindRow, DWARFRegType Reg) {
+ auto UnwinLoc = UnwindRow->getRegisterLocations().getRegisterLocation(Reg);
assert(UnwinLoc &&
"The register should be tracked inside the register states");
@@ -40,9 +30,8 @@ CFIState::getReferenceRegisterForCallerValueOfRegister(DWARFRegType Reg) const {
case dwarf::UnwindLocation::Location::Undefined:
case dwarf::UnwindLocation::Location::Constant:
case dwarf::UnwindLocation::Location::Unspecified:
- // TODO here should look into expr and find the registers, but for now it's
- // TODO like this:
case dwarf::UnwindLocation::Location::DWARFExpr:
+ // TODO here should look into expr and find the registers.
return std::nullopt;
case dwarf::UnwindLocation::Location::Same:
return Reg;
@@ -51,33 +40,33 @@ CFIState::getReferenceRegisterForCallerValueOfRegister(DWARFRegType Reg) const {
case dwarf::UnwindLocation::Location::CFAPlusOffset:
// TODO check if it's ok to assume CFA is always depending on other
// TODO register, if yes assert it here!
- return LastRow->getCFAValue().getRegister();
+ return UnwindRow->getCFAValue().getRegister();
}
}
-void CFIState::apply(const MCCFIInstruction &CFIDirective) {
- auto DwarfOperations = convertMC2DWARF(CFIDirective);
+void UnwindInfoHistory::update(const MCCFIInstruction &CFIDirective) {
+ auto DwarfOperations = convert(CFIDirective);
if (!DwarfOperations) {
Context->reportError(
CFIDirective.getLoc(),
"couldn't apply this directive to the unwinding information state");
}
- auto &&LastRow = getLastRow();
- dwarf::UnwindRow Row = LastRow ? LastRow.value() : dwarf::UnwindRow();
- if (Error Err = State.parseRows(DwarfOperations.value(), Row, nullptr)) {
- // ! FIXME what should I do with this error?
+ auto LastRow = getCurrentUnwindRow();
+ dwarf::UnwindRow Row =
+ LastRow.has_value() ? *(LastRow.value()) : dwarf::UnwindRow();
+ if (Error Err = Table.parseRows(DwarfOperations.value(), Row, nullptr)) {
Context->reportError(
CFIDirective.getLoc(),
formatv("could not parse this CFI directive due to: {0}",
toString(std::move(Err))));
assert(false);
}
- State.insertRow(Row);
+ Table.insertRow(Row);
}
std::optional<dwarf::CFIProgram>
-CFIState::convertMC2DWARF(MCCFIInstruction CFIDirective) {
+UnwindInfoHistory::convert(MCCFIInstruction CFIDirective) {
//! FIXME, this way of instantiating CFI program does not look right, either
//! refactor CFIProgram to not depend on the Code/Data Alignment or add a new
//! type that is independent from this and is also feedable to UnwindTable.
@@ -118,20 +107,22 @@ CFIState::convertMC2DWARF(MCCFIInstruction CFIDirective) {
CFIDirective.getOffset());
break;
case MCCFIInstruction::OpRelOffset:
- if (!getLastRow()) // TODO maybe replace it with assert
+ if (!getCurrentUnwindRow()) // TODO maybe replace it with assert
return std::nullopt;
DwarfOperations.addInstruction(
dwarf::DW_CFA_offset, CFIDirective.getRegister(),
- CFIDirective.getOffset() - getLastRow()->getCFAValue().getOffset());
+ CFIDirective.getOffset() -
+ getCurrentUnwindRow().value()->getCFAValue().getOffset());
break;
case MCCFIInstruction::OpAdjustCfaOffset:
- if (!getLastRow()) // TODO maybe replace it with assert
+ if (!getCurrentUnwindRow()) // TODO maybe replace it with assert
return std::nullopt;
- DwarfOperations.addInstruction(dwarf::DW_CFA_def_cfa_offset,
- CFIDirective.getOffset() +
- getLastRow()->getCFAValue().getOffset());
+ DwarfOperations.addInstruction(
+ dwarf::DW_CFA_def_cfa_offset,
+ CFIDirective.getOffset() +
+ getCurrentUnwindRow().value()->getCFAValue().getOffset());
break;
case MCCFIInstruction::OpEscape:
// TODO It's now feasible but for now, I ignore it
@@ -176,12 +167,3 @@ CFIState::convertMC2DWARF(MCCFIInstruction CFIDirective) {
return DwarfOperations;
}
-
-std::optional<dwarf::UnwindRow> CFIState::getLastRow() const {
- if (!State.size())
- return std::nullopt;
-
- //! FIXME too dirty
- auto &&it = State.end();
- return *--it;
-}
\ No newline at end of file
>From cece662935621a47db131cd5c6d5b7b424222d17 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Fri, 20 Jun 2025 23:43:51 +0000
Subject: [PATCH 36/58] Make CFA access easier
---
llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h | 35 +-
.../llvm/MCCFIAnalysis/UnwindInfoHistory.h | 9 +-
llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp | 313 +++++++++---------
llvm/lib/MCCFIAnalysis/UnwindInfoHistory.cpp | 29 +-
4 files changed, 176 insertions(+), 210 deletions(-)
diff --git a/llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h b/llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h
index e150392ceb77c..ac921e40ededf 100644
--- a/llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h
+++ b/llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h
@@ -29,11 +29,11 @@ class CFIAnalysis {
private:
// The CFI analysis only keeps track and cares about super registers, not the
// subregisters. All reads to/writes from subregisters and considered the same
- // operation to super registers. Other operations like loading and stores are
- // considered only if they are exactly doing the operation to or from a super
- // register.
- // As en example, if you spill a sub register to stack, the CFI analysis does
- // not consider that a register spilling.
+ // operation to super registers.
+ // TODO Other operations like loading and stores are considered only if they
+ // TODO are exactly doing the operation to or from a super register. As an
+ // TODO example, if you spill a sub register to stack, the CFI analysis does
+ // TODO not consider that a register spilling.
bool isSuperReg(MCPhysReg Reg);
SmallVector<std::pair<MCPhysReg, MCRegisterClass const *>> getAllSuperRegs();
@@ -48,22 +48,19 @@ class CFIAnalysis {
void update(const MCInst &Inst, ArrayRef<MCCFIInstruction> CFIDirectives);
private:
- void checkRegDiff(
- const MCInst &Inst, UnwindInfoHistory::DWARFRegType Reg,
- const dwarf::UnwindTable::const_iterator &PrevState,
- const dwarf::UnwindTable::const_iterator &NextState,
- const dwarf::UnwindLocation
- &PrevRegState, // TODO maybe should get them from prev next state
- const dwarf::UnwindLocation
- &NextRegState, // TODO themselves instead of by arguments.
- const std::set<UnwindInfoHistory::DWARFRegType> &Reads,
- const std::set<UnwindInfoHistory::DWARFRegType> &Writes);
+ void checkRegDiff(const MCInst &Inst, DWARFRegType Reg,
+ const dwarf::UnwindTable::const_iterator &PrevRow,
+ const dwarf::UnwindTable::const_iterator &NextRow,
+ const dwarf::UnwindLocation &PrevRegLoc,
+ const dwarf::UnwindLocation &NextRegLoc,
+ const std::set<DWARFRegType> &Reads,
+ const std::set<DWARFRegType> &Writes);
void checkCFADiff(const MCInst &Inst,
- const dwarf::UnwindTable::const_iterator &PrevState,
- const dwarf::UnwindTable::const_iterator &NextState,
- const std::set<UnwindInfoHistory::DWARFRegType> &Reads,
- const std::set<UnwindInfoHistory::DWARFRegType> &Writes);
+ const dwarf::UnwindTable::const_iterator &PrevRow,
+ const dwarf::UnwindTable::const_iterator &NextRow,
+ const std::set<DWARFRegType> &Reads,
+ const std::set<DWARFRegType> &Writes);
};
} // namespace llvm
diff --git a/llvm/include/llvm/MCCFIAnalysis/UnwindInfoHistory.h b/llvm/include/llvm/MCCFIAnalysis/UnwindInfoHistory.h
index 9a792e1f5f39e..1f357e0e8fc55 100644
--- a/llvm/include/llvm/MCCFIAnalysis/UnwindInfoHistory.h
+++ b/llvm/include/llvm/MCCFIAnalysis/UnwindInfoHistory.h
@@ -4,19 +4,16 @@
#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDwarf.h"
+#include <cstdint>
#include <optional>
namespace llvm {
+using DWARFRegType = uint32_t;
+
class UnwindInfoHistory {
public:
- using DWARFRegType = uint32_t;
-
UnwindInfoHistory(MCContext *Context) : Context(Context) {};
- static std::optional<DWARFRegType>
- getReferenceRegisterForUnwindInfoOfRegister(
- const dwarf::UnwindTable::const_iterator &UnwindRow, DWARFRegType Reg);
-
std::optional<dwarf::UnwindTable::const_iterator> getCurrentUnwindRow() const;
void update(const MCCFIInstruction &CFIDirective);
diff --git a/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp b/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp
index dc4cda0bbe83d..5ac88cf56ec5c 100644
--- a/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp
+++ b/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp
@@ -18,6 +18,7 @@
#include "llvm/MCCFIAnalysis/UnwindInfoHistory.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
#include "llvm/Support/FormatVariadic.h"
#include <cstdint>
#include <optional>
@@ -25,6 +26,49 @@
using namespace llvm;
+struct CFARegOffsetInfo {
+ DWARFRegType Reg;
+ int64_t Offset;
+
+ CFARegOffsetInfo(DWARFRegType Reg, int64_t Offset)
+ : Reg(Reg), Offset(Offset) {}
+};
+
+static std::optional<CFARegOffsetInfo>
+getCFARegOffsetInfo(const dwarf::UnwindTable::const_iterator &UnwindRow) {
+ auto CFALocation = UnwindRow->getCFAValue();
+ if (CFALocation.getLocation() !=
+ dwarf::UnwindLocation::Location::RegPlusOffset) {
+ return std::nullopt;
+ }
+
+ return CFARegOffsetInfo(CFALocation.getRegister(), CFALocation.getOffset());
+}
+
+static std::optional<DWARFRegType> getReferenceRegisterForUnwindInfoOfRegister(
+ const dwarf::UnwindTable::const_iterator &UnwindRow, DWARFRegType Reg) {
+ auto UnwinLoc = UnwindRow->getRegisterLocations().getRegisterLocation(Reg);
+ assert(UnwinLoc &&
+ "The register should be tracked inside the register states");
+
+ switch (UnwinLoc->getLocation()) {
+ case dwarf::UnwindLocation::Location::Undefined:
+ case dwarf::UnwindLocation::Location::Constant:
+ case dwarf::UnwindLocation::Location::Unspecified:
+ case dwarf::UnwindLocation::Location::DWARFExpr:
+ // TODO here should look into expr and find the registers.
+ return std::nullopt;
+ case dwarf::UnwindLocation::Location::Same:
+ return Reg;
+ case dwarf::UnwindLocation::Location::RegPlusOffset:
+ return UnwinLoc->getRegister();
+ case dwarf::UnwindLocation::Location::CFAPlusOffset:
+ // TODO check if it's ok to assume CFA is always depending on other
+ // TODO register, if yes assert it here!
+ return UnwindRow->getCFAValue().getRegister();
+ }
+}
+
// TODO remove it, it's just for debug purposes.
void printUntilNextLine(const char *Str) {
for (int I = 0; Str[I] != '\0' && Str[I] != '\n'; I++)
@@ -70,35 +114,37 @@ CFIAnalysis::CFIAnalysis(MCContext *Context, MCInstrInfo const &MCII,
: Context(Context), MCII(MCII), MCRI(Context->getRegisterInfo()),
State(Context), IsEH(IsEH) {
+ // TODO These all should be handled by setting .cfi_same_value for only callee
+ // TODO saved registers inside `getInitialFrameState`. Instead now what's
+ // TODO happening is that the analysis .cfi_same_value all the registers and
+ // TODO remove PC (undefined), and RSP (CFA) from them.
for (auto &&[Reg, RegClass] : getAllSuperRegs()) {
if (MCRI->get(Reg).IsArtificial || MCRI->get(Reg).IsConstant)
continue;
- UnwindInfoHistory::DWARFRegType DwarfReg = MCRI->getDwarfRegNum(Reg, IsEH);
- // TODO is it OK to create fake CFI directives for doing this?
+ DWARFRegType DwarfReg = MCRI->getDwarfRegNum(Reg, IsEH);
State.update(MCCFIInstruction::createSameValue(nullptr, DwarfReg));
}
+ State.update(MCCFIInstruction::createUndefined(
+ nullptr, MCRI->getDwarfRegNum(MCRI->getProgramCounter(), IsEH)));
+
for (auto &&InitialFrameStateCFIDirective :
Context->getAsmInfo()->getInitialFrameState()) {
State.update(InitialFrameStateCFIDirective);
}
- // TODO these are temporay added to make things work.
- // Setup the basic information:
- State.update(MCCFIInstruction::createUndefined(
- nullptr,
- MCRI->getDwarfRegNum(MCRI->getProgramCounter(),
- IsEH))); // TODO for now, we don't care about the PC
- // TODO
- auto LastRow = State.getCurrentUnwindRow();
- assert(LastRow && "there should be at least one row");
- // TODO assert that CFA is there, and based on register.
- // TODO
-
- State.update(MCCFIInstruction::createOffset(
- nullptr, LastRow.value()->getCFAValue().getRegister(),
- 0)); // sp's old value is CFA
+ auto MaybeLastRow = State.getCurrentUnwindRow();
+ assert(MaybeLastRow && "there should be at least one row");
+ auto LastRow = *MaybeLastRow;
+
+ auto MaybeCFA = getCFARegOffsetInfo(LastRow);
+ assert(MaybeCFA &&
+ "the CFA information should be describable in [Reg + Offset] in here");
+ auto CFA = *MaybeCFA;
+
+ State.update(MCCFIInstruction::createOffset(nullptr, CFA.Reg,
+ 0)); // sp's old value is CFA
// Applying the prologue after default assumptions to overwrite them.
for (auto &&PrologueCFIDirective : PrologueCFIDirectives) {
@@ -109,17 +155,16 @@ CFIAnalysis::CFIAnalysis(MCContext *Context, MCInstrInfo const &MCII,
void CFIAnalysis::update(const MCInst &Inst,
ArrayRef<MCCFIInstruction> CFIDirectives) {
const MCInstrDesc &MCInstInfo = MCII.get(Inst.getOpcode());
- auto PrevUnwindRow = State.getCurrentUnwindRow().value();
+
+ auto MaybePrevUnwindRow = State.getCurrentUnwindRow();
+ assert(MaybePrevUnwindRow && "The analysis should have initialized the "
+ "history with at least one row by now");
+ auto PrevUnwindRow = MaybePrevUnwindRow.value();
+
for (auto &&CFIDirective : CFIDirectives)
State.update(CFIDirective);
- //! if (!AfterState.apply(CFIDirective))
- //! Context->reportWarning(
- //! CFIDirective.getLoc(),
- //! "I don't support this CFI directive, I assume this does nothing "
- //! "(which will probably break other things)");
-
- std::set<UnwindInfoHistory::DWARFRegType> Writes, Reads;
+ std::set<DWARFRegType> Writes, Reads;
for (unsigned I = 0; I < MCInstInfo.NumImplicitUses; I++)
Reads.insert(
MCRI->getDwarfRegNum(getSuperReg(MCInstInfo.implicit_uses()[I]), IsEH));
@@ -138,140 +183,70 @@ void CFIAnalysis::update(const MCInst &Inst,
}
}
- checkCFADiff(Inst, PrevUnwindRow, State.getCurrentUnwindRow().value(), Reads,
- Writes);
+ auto MaybeCurrentUnwindRow = State.getCurrentUnwindRow();
+ assert(MaybeCurrentUnwindRow &&
+ "Prev row existed, so should the current row.");
+ auto CurrentUnwindRow = *MaybeCurrentUnwindRow;
+
+ checkCFADiff(Inst, PrevUnwindRow, CurrentUnwindRow, Reads, Writes);
for (auto [LLVMReg, _] : getAllSuperRegs()) {
- UnwindInfoHistory::DWARFRegType Reg = MCRI->getDwarfRegNum(LLVMReg, IsEH);
+ DWARFRegType Reg = MCRI->getDwarfRegNum(LLVMReg, IsEH);
- auto PrevUnwindLoc =
+ auto MaybePrevUnwindLoc =
PrevUnwindRow->getRegisterLocations().getRegisterLocation(Reg);
- auto NextUnwindLoc = State.getCurrentUnwindRow()
- .value()
- ->getRegisterLocations()
- .getRegisterLocation(Reg);
-
- // TODO think more if these assertions are OK
- // TODO maybe change them to error messages.
- if (!PrevUnwindLoc) {
- assert(
- !NextUnwindLoc &&
- "A CFI directive should not define a new register out of thin air.");
+ auto MaybeNextUnwindLoc =
+ CurrentUnwindRow->getRegisterLocations().getRegisterLocation(Reg);
+
+ if (!MaybePrevUnwindLoc) {
+ assert(!MaybeNextUnwindLoc && "The register unwind info suddenly "
+ "appeared here, ignoring this change");
continue;
}
- assert(NextUnwindLoc &&
- "A CFI directive should not delete a register state.");
- checkRegDiff(Inst, Reg, PrevUnwindRow, State.getCurrentUnwindRow().value(),
- PrevUnwindLoc.value(), NextUnwindLoc.value(), Reads, Writes);
+ assert(MaybeNextUnwindLoc && "The register unwind info suddenly vanished "
+ "here, ignoring this change");
+
+ auto PrevUnwindLoc = MaybePrevUnwindLoc.value();
+ auto NextUnwindLoc = MaybeNextUnwindLoc.value();
+
+ checkRegDiff(Inst, Reg, PrevUnwindRow, CurrentUnwindRow, PrevUnwindLoc,
+ NextUnwindLoc, Reads, Writes);
}
}
void CFIAnalysis::checkRegDiff(
- const MCInst &Inst, UnwindInfoHistory::DWARFRegType Reg,
- const dwarf::UnwindTable::const_iterator &PrevState,
- const dwarf::UnwindTable::const_iterator &NextState,
- const dwarf::UnwindLocation &PrevRegState, // TODO maybe re-name
- const dwarf::UnwindLocation &NextRegState, // TODO maybe re-name
- const std::set<UnwindInfoHistory::DWARFRegType> &Reads,
- const std::set<UnwindInfoHistory::DWARFRegType> &Writes) {
- auto RegLLVMOpt = MCRI->getLLVMRegNum(Reg, IsEH);
- if (RegLLVMOpt == std::nullopt) {
- assert(PrevRegState == NextRegState);
+ const MCInst &Inst, DWARFRegType Reg,
+ const dwarf::UnwindTable::const_iterator &PrevRow,
+ const dwarf::UnwindTable::const_iterator &NextRow,
+ const dwarf::UnwindLocation &PrevRegLoc,
+ const dwarf::UnwindLocation &NextRegLoc,
+ const std::set<DWARFRegType> &Reads, const std::set<DWARFRegType> &Writes) {
+ auto MaybeRegLLVM = MCRI->getLLVMRegNum(Reg, IsEH);
+ if (!MaybeRegLLVM) {
+ assert(PrevRegLoc == NextRegLoc &&
+ "The dwarf register does not have a LLVM number, so the unwind info "
+ "for it should not change");
return;
}
- const char *RegLLVMName = MCRI->getName(RegLLVMOpt.value());
- auto &&PrevRefReg =
- UnwindInfoHistory::getReferenceRegisterForUnwindInfoOfRegister(PrevState,
- Reg);
+ const char *RegLLVMName = MCRI->getName(MaybeRegLLVM.value());
+
+ auto &&MaybePrevRefReg =
+ getReferenceRegisterForUnwindInfoOfRegister(PrevRow, Reg);
std::optional<MCPhysReg> PrevRefRegLLVM =
- (PrevRefReg != std::nullopt
- ? std::make_optional(
- MCRI->getLLVMRegNum(PrevRefReg.value(), IsEH).value())
- : std::nullopt);
+ (MaybePrevRefReg ? MCRI->getLLVMRegNum(MaybePrevRefReg.value(), IsEH)
+ : std::nullopt);
std::optional<MCPhysReg> NextRefRegLLVM =
- (PrevRefReg != std::nullopt
- ? std::make_optional(
- MCRI->getLLVMRegNum(PrevRefReg.value(), IsEH).value())
- : std::nullopt);
-
- // TODO Again getting CFA register out of UnwindRow
- // TODO consider either making it a help function.
- // TODO Also, again you have to re-look in the assumption
- // TODO that CFA is depending on another register, maybe
- // TODO it's not true. And if it's always true, consider
- // TODO asserting it (maybe in the helper function).
- MCPhysReg PrevStateCFARegLLVM =
- MCRI->getLLVMRegNum(PrevState->getCFAValue().getRegister(), IsEH).value();
-
- { // try generate
- // Widen
- std::vector<dwarf::UnwindLocation> PossibleNextRegStates;
-
- { // stay the same
- bool CanStayTheSame = true;
-
- // TODO make sure it has meaning in `Undefined` or `Unspecified` case.
- // TODO make it smarter, if it's in the memory and the instruction does
- // TODO not store anything and the register (if any) to access that part
- // TODO is not changed, then it's OK.
- if (PrevRegState.getDereference())
- CanStayTheSame = false;
-
- if (PrevRefReg && Writes.count(PrevRefReg.value())) {
- CanStayTheSame = false;
- }
-
- if (PrevRegState.getLocation() == dwarf::UnwindLocation::DWARFExpr) {
- // TODO this can be solved more precise, by looking into the expression,
- // TODO finding registers that are used and checking if the instruction
- // TODO is changing them or not.
- CanStayTheSame = false;
- }
-
- if (CanStayTheSame)
- PossibleNextRegStates.push_back(PrevRegState);
- }
+ (MaybePrevRefReg ? MCRI->getLLVMRegNum(MaybePrevRefReg.value(), IsEH)
+ : std::nullopt);
- // TODO In this stage of program, there is not possible next stages, it's
- // TODO either the same or nothing. Then maybe I have to refactor it back to
- // TODO the primitive design. And when got the semantic info, get back to
- // TODO this code.
- for (auto &&PossibleNextRegState : PossibleNextRegStates) {
- if (PossibleNextRegState == NextRegState) {
- // Everything is ok
- return;
- }
- }
-
- for (auto &&PossibleNextRegState : PossibleNextRegStates) {
- if (PossibleNextRegState.getLocation() != NextRegState.getLocation())
- continue;
-
- // TODO again, as said above, does this happen in the current primitive
- // TODO design?
- if (PossibleNextRegState.getLocation() ==
- dwarf::UnwindLocation::CFAPlusOffset) {
- Context->reportError(
- Inst.getLoc(),
- formatv("Expected %{0} unwinding rule should be [CFA + {1}] but "
- "based CFI directives are [CFA + {2}]",
- RegLLVMName, PossibleNextRegState.getOffset(),
- NextRegState.getOffset()));
- }
- }
- }
- // Either couldn't generate, or the programmer changed the state to
- // something that couldn't be matched to any of the generated states. So
- // it falls back into read/write checks.
-
- if (PrevRegState == NextRegState) {
- switch (PrevRegState.getLocation()) {
+ if (PrevRegLoc == NextRegLoc) {
+ switch (PrevRegLoc.getLocation()) {
case dwarf::UnwindLocation::Same:
case dwarf::UnwindLocation::RegPlusOffset:
- if (Writes.count(PrevRefReg.value())) {
+ if (Writes.count(MaybePrevRefReg.value())) {
Context->reportError(
Inst.getLoc(),
formatv("This instruction changes %{1}, that %{0} unwinding rule "
@@ -281,6 +256,9 @@ void CFIAnalysis::checkRegDiff(
}
break;
// TODO think about what to do with expressions here.
+ // TODO the expressions be solved more precise, by looking into the
+ // TODO expression, finding registers that are used and checking if the
+ // TODO instruction is changing them or not.
default:
// Everything may be ok
break;
@@ -288,12 +266,12 @@ void CFIAnalysis::checkRegDiff(
return;
}
- if (PrevRegState.getLocation() == NextRegState.getLocation()) {
+ if (PrevRegLoc.getLocation() == NextRegLoc.getLocation()) {
// Everything may be ok
return;
}
- if (PrevRegState.getLocation() == dwarf::UnwindLocation::Undefined) {
+ if (PrevRegLoc.getLocation() == dwarf::UnwindLocation::Undefined) {
Context->reportError(
Inst.getLoc(),
"Changed %{0} unwinding rule from `undefined` to something else");
@@ -308,25 +286,42 @@ void CFIAnalysis::checkRegDiff(
}
void CFIAnalysis::checkCFADiff(
- const MCInst &Inst, const dwarf::UnwindTable::const_iterator &PrevState,
- const dwarf::UnwindTable::const_iterator &NextState,
- const std::set<UnwindInfoHistory::DWARFRegType> &Reads,
- const std::set<UnwindInfoHistory::DWARFRegType> &Writes) {
- // TODO again getting the CFA register in the bad way.
- const UnwindInfoHistory::DWARFRegType PrevCFAReg =
- PrevState->getCFAValue().getRegister();
- const int32_t PrevCFAOffset = PrevState->getCFAValue().getOffset();
-
- const UnwindInfoHistory::DWARFRegType NextCFAReg =
- NextState->getCFAValue().getRegister();
- const int32_t NextCFAOffset = NextState->getCFAValue().getOffset();
+ const MCInst &Inst, const dwarf::UnwindTable::const_iterator &PrevRow,
+ const dwarf::UnwindTable::const_iterator &NextRow,
+ const std::set<DWARFRegType> &Reads, const std::set<DWARFRegType> &Writes) {
+
+ auto MaybePrevCFA = getCFARegOffsetInfo(PrevRow);
+ auto MaybeNextCFA = getCFARegOffsetInfo(NextRow);
+
+ if (!MaybePrevCFA) {
+ if (MaybeNextCFA) {
+ Context->reportWarning(
+ Inst.getLoc(),
+ "CFA rule changed to [reg + offset], not checking the change");
+ return;
+ }
+
+ Context->reportWarning(Inst.getLoc(),
+ "CFA rule is not [reg + offset], not checking it");
+ return;
+ }
+
+ if (!MaybeNextCFA) {
+ Context->reportWarning(
+ Inst.getLoc(),
+ "CFA rule changed from [reg + offset], not checking the change");
+ return;
+ }
+
+ auto PrevCFA = *MaybePrevCFA;
+ auto NextCFA = *MaybeNextCFA;
const char *PrevCFARegName =
- MCRI->getName(MCRI->getLLVMRegNum(PrevCFAReg, IsEH).value());
+ MCRI->getName(MCRI->getLLVMRegNum(PrevCFA.Reg, IsEH).value());
- if (PrevCFAReg == NextCFAReg) {
- if (PrevCFAOffset == NextCFAOffset) {
- if (Writes.count(PrevCFAReg)) {
+ if (PrevCFA.Reg == NextCFA.Reg) {
+ if (PrevCFA.Offset == NextCFA.Offset) {
+ if (Writes.count(PrevCFA.Reg)) {
Context->reportError(
Inst.getLoc(),
formatv("This instruction modifies CFA register (%{0}) "
@@ -338,9 +333,9 @@ void CFIAnalysis::checkCFADiff(
// Everything is ok!
return;
}
- // The offset is changed.
- if (!Writes.count(PrevCFAReg)) {
+ // The offset is changed.
+ if (!Writes.count(PrevCFA.Reg)) {
Context->reportError(
Inst.getLoc(),
formatv("This instruction does not modifies CFA register (%{0}) "
diff --git a/llvm/lib/MCCFIAnalysis/UnwindInfoHistory.cpp b/llvm/lib/MCCFIAnalysis/UnwindInfoHistory.cpp
index cc164aabfb1eb..f44ac07bc0acb 100644
--- a/llvm/lib/MCCFIAnalysis/UnwindInfoHistory.cpp
+++ b/llvm/lib/MCCFIAnalysis/UnwindInfoHistory.cpp
@@ -19,31 +19,6 @@ UnwindInfoHistory::getCurrentUnwindRow() const {
return --Table.end();
}
-std::optional<UnwindInfoHistory::DWARFRegType>
-UnwindInfoHistory::getReferenceRegisterForUnwindInfoOfRegister(
- const dwarf::UnwindTable::const_iterator &UnwindRow, DWARFRegType Reg) {
- auto UnwinLoc = UnwindRow->getRegisterLocations().getRegisterLocation(Reg);
- assert(UnwinLoc &&
- "The register should be tracked inside the register states");
-
- switch (UnwinLoc->getLocation()) {
- case dwarf::UnwindLocation::Location::Undefined:
- case dwarf::UnwindLocation::Location::Constant:
- case dwarf::UnwindLocation::Location::Unspecified:
- case dwarf::UnwindLocation::Location::DWARFExpr:
- // TODO here should look into expr and find the registers.
- return std::nullopt;
- case dwarf::UnwindLocation::Location::Same:
- return Reg;
- case dwarf::UnwindLocation::Location::RegPlusOffset:
- return UnwinLoc->getRegister();
- case dwarf::UnwindLocation::Location::CFAPlusOffset:
- // TODO check if it's ok to assume CFA is always depending on other
- // TODO register, if yes assert it here!
- return UnwindRow->getCFAValue().getRegister();
- }
-}
-
void UnwindInfoHistory::update(const MCCFIInstruction &CFIDirective) {
auto DwarfOperations = convert(CFIDirective);
if (!DwarfOperations) {
@@ -60,7 +35,9 @@ void UnwindInfoHistory::update(const MCCFIInstruction &CFIDirective) {
CFIDirective.getLoc(),
formatv("could not parse this CFI directive due to: {0}",
toString(std::move(Err))));
- assert(false);
+
+ // Proceed the analysis by ignoring this CFI directive.
+ return;
}
Table.insertRow(Row);
}
>From fa0505bf459de28efb0d44d409118dcc00a44fdf Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Sat, 21 Jun 2025 00:15:14 +0000
Subject: [PATCH 37/58] Rename CFI to Unwind info analysis
---
.../MCCFIAnalysis/CFIAnalysisMCStreamer.h | 5 ++---
.../{CFIAnalysis.h => UnwindInfoAnalysis.h} | 8 +++----
llvm/lib/MCCFIAnalysis/CMakeLists.txt | 2 +-
...CFIAnalysis.cpp => UnwindInfoAnalysis.cpp} | 22 +++++++++----------
4 files changed, 18 insertions(+), 19 deletions(-)
rename llvm/include/llvm/MCCFIAnalysis/{CFIAnalysis.h => UnwindInfoAnalysis.h} (90%)
rename llvm/lib/MCCFIAnalysis/{CFIAnalysis.cpp => UnwindInfoAnalysis.cpp} (95%)
diff --git a/llvm/include/llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h b/llvm/include/llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h
index 895457bda3703..be1fede55b612 100644
--- a/llvm/include/llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h
+++ b/llvm/include/llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h
@@ -1,8 +1,7 @@
#ifndef LLVM_TOOLS_LLVM_MC_CFI_ANALYSIS_MC_STREAMER_H
#define LLVM_TOOLS_LLVM_MC_CFI_ANALYSIS_MC_STREAMER_H
-#include "CFIAnalysis.h"
-#include "llvm/ADT/ArrayRef.h"
+#include "UnwindInfoAnalysis.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDwarf.h"
#include "llvm/MC/MCInstrAnalysis.h"
@@ -32,7 +31,7 @@ class CFIAnalysisMCStreamer : public MCStreamer {
CFIDirectivesState(int FrameIndex, int InstructionIndex);
} LastCFIDirectivesState;
std::vector<int> FrameIndices;
- std::vector<CFIAnalysis> CFIAs;
+ std::vector<UnwindInfoAnalysis> CFIAs;
struct ICFI {
MCInst Instruction;
diff --git a/llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h b/llvm/include/llvm/MCCFIAnalysis/UnwindInfoAnalysis.h
similarity index 90%
rename from llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h
rename to llvm/include/llvm/MCCFIAnalysis/UnwindInfoAnalysis.h
index ac921e40ededf..5c38439039fcb 100644
--- a/llvm/include/llvm/MCCFIAnalysis/CFIAnalysis.h
+++ b/llvm/include/llvm/MCCFIAnalysis/UnwindInfoAnalysis.h
@@ -19,7 +19,7 @@
namespace llvm {
-class CFIAnalysis {
+class UnwindInfoAnalysis {
MCContext *Context;
MCInstrInfo const &MCII;
MCRegisterInfo const *MCRI;
@@ -41,9 +41,9 @@ class CFIAnalysis {
MCPhysReg getSuperReg(MCPhysReg Reg);
public:
- CFIAnalysis(MCContext *Context, MCInstrInfo const &MCII,
- MCInstrAnalysis *MCIA, bool IsEH,
- ArrayRef<MCCFIInstruction> PrologueCFIDirectives);
+ UnwindInfoAnalysis(MCContext *Context, MCInstrInfo const &MCII,
+ MCInstrAnalysis *MCIA, bool IsEH,
+ ArrayRef<MCCFIInstruction> PrologueCFIDirectives);
void update(const MCInst &Inst, ArrayRef<MCCFIInstruction> CFIDirectives);
diff --git a/llvm/lib/MCCFIAnalysis/CMakeLists.txt b/llvm/lib/MCCFIAnalysis/CMakeLists.txt
index b4a5da108de5b..28329a5653f77 100644
--- a/llvm/lib/MCCFIAnalysis/CMakeLists.txt
+++ b/llvm/lib/MCCFIAnalysis/CMakeLists.txt
@@ -1,7 +1,7 @@
add_llvm_component_library(LLVMMCCFIAnalysis
UnwindInfoHistory.cpp
CFIAnalysisMCStreamer.cpp
- CFIAnalysis.cpp
+ UnwindInfoAnalysis.cpp
ADDITIONAL_HEADER_DIRS
${LLVM_MAIN_INCLUDE_DIR}/llvm/MCA
diff --git a/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp b/llvm/lib/MCCFIAnalysis/UnwindInfoAnalysis.cpp
similarity index 95%
rename from llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp
rename to llvm/lib/MCCFIAnalysis/UnwindInfoAnalysis.cpp
index 5ac88cf56ec5c..1bebbffde5cce 100644
--- a/llvm/lib/MCCFIAnalysis/CFIAnalysis.cpp
+++ b/llvm/lib/MCCFIAnalysis/UnwindInfoAnalysis.cpp
@@ -1,4 +1,4 @@
-#include "llvm/MCCFIAnalysis/CFIAnalysis.h"
+#include "llvm/MCCFIAnalysis/UnwindInfoAnalysis.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
@@ -75,12 +75,12 @@ void printUntilNextLine(const char *Str) {
dbgs() << Str[I];
}
-bool CFIAnalysis::isSuperReg(MCPhysReg Reg) {
+bool UnwindInfoAnalysis::isSuperReg(MCPhysReg Reg) {
return MCRI->superregs(Reg).empty();
}
SmallVector<std::pair<MCPhysReg, MCRegisterClass const *>>
-CFIAnalysis::getAllSuperRegs() {
+UnwindInfoAnalysis::getAllSuperRegs() {
std::map<MCPhysReg, MCRegisterClass const *> SuperRegs;
for (auto &&RegClass : MCRI->regclasses()) {
for (unsigned I = 0; I < RegClass.getNumRegs(); I++) {
@@ -97,7 +97,7 @@ CFIAnalysis::getAllSuperRegs() {
return SuperRegWithClass;
}
-MCPhysReg CFIAnalysis::getSuperReg(MCPhysReg Reg) {
+MCPhysReg UnwindInfoAnalysis::getSuperReg(MCPhysReg Reg) {
if (isSuperReg(Reg))
return Reg;
for (auto SuperReg : MCRI->superregs(Reg)) {
@@ -108,9 +108,9 @@ MCPhysReg CFIAnalysis::getSuperReg(MCPhysReg Reg) {
llvm_unreachable("Should either be a super reg, or have a super reg");
}
-CFIAnalysis::CFIAnalysis(MCContext *Context, MCInstrInfo const &MCII,
- MCInstrAnalysis *MCIA, bool IsEH,
- ArrayRef<MCCFIInstruction> PrologueCFIDirectives)
+UnwindInfoAnalysis::UnwindInfoAnalysis(
+ MCContext *Context, MCInstrInfo const &MCII, MCInstrAnalysis *MCIA,
+ bool IsEH, ArrayRef<MCCFIInstruction> PrologueCFIDirectives)
: Context(Context), MCII(MCII), MCRI(Context->getRegisterInfo()),
State(Context), IsEH(IsEH) {
@@ -152,8 +152,8 @@ CFIAnalysis::CFIAnalysis(MCContext *Context, MCInstrInfo const &MCII,
}
}
-void CFIAnalysis::update(const MCInst &Inst,
- ArrayRef<MCCFIInstruction> CFIDirectives) {
+void UnwindInfoAnalysis::update(const MCInst &Inst,
+ ArrayRef<MCCFIInstruction> CFIDirectives) {
const MCInstrDesc &MCInstInfo = MCII.get(Inst.getOpcode());
auto MaybePrevUnwindRow = State.getCurrentUnwindRow();
@@ -215,7 +215,7 @@ void CFIAnalysis::update(const MCInst &Inst,
}
}
-void CFIAnalysis::checkRegDiff(
+void UnwindInfoAnalysis::checkRegDiff(
const MCInst &Inst, DWARFRegType Reg,
const dwarf::UnwindTable::const_iterator &PrevRow,
const dwarf::UnwindTable::const_iterator &NextRow,
@@ -285,7 +285,7 @@ void CFIAnalysis::checkRegDiff(
return;
}
-void CFIAnalysis::checkCFADiff(
+void UnwindInfoAnalysis::checkCFADiff(
const MCInst &Inst, const dwarf::UnwindTable::const_iterator &PrevRow,
const dwarf::UnwindTable::const_iterator &NextRow,
const std::set<DWARFRegType> &Reads, const std::set<DWARFRegType> &Writes) {
>From ff81fa22e98e71af45f1074bc601274e87ed7167 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Sat, 21 Jun 2025 00:52:02 +0000
Subject: [PATCH 38/58] Remove MCInstrAnalysis from UnwindInfo analysis
---
llvm/include/llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h | 1 -
llvm/include/llvm/MCCFIAnalysis/UnwindInfoAnalysis.h | 3 +--
llvm/lib/MCCFIAnalysis/CFIAnalysisMCStreamer.cpp | 6 +++---
llvm/lib/MCCFIAnalysis/UnwindInfoAnalysis.cpp | 4 ++--
4 files changed, 6 insertions(+), 8 deletions(-)
diff --git a/llvm/include/llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h b/llvm/include/llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h
index be1fede55b612..60e7dcbe53331 100644
--- a/llvm/include/llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h
+++ b/llvm/include/llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h
@@ -21,7 +21,6 @@ namespace llvm {
// TODO receiver.
class CFIAnalysisMCStreamer : public MCStreamer {
MCInstrInfo const &MCII;
- std::unique_ptr<MCInstrAnalysis> MCIA;
struct CFIDirectivesState {
int DirectiveIndex;
diff --git a/llvm/include/llvm/MCCFIAnalysis/UnwindInfoAnalysis.h b/llvm/include/llvm/MCCFIAnalysis/UnwindInfoAnalysis.h
index 5c38439039fcb..acf5ec2139307 100644
--- a/llvm/include/llvm/MCCFIAnalysis/UnwindInfoAnalysis.h
+++ b/llvm/include/llvm/MCCFIAnalysis/UnwindInfoAnalysis.h
@@ -41,8 +41,7 @@ class UnwindInfoAnalysis {
MCPhysReg getSuperReg(MCPhysReg Reg);
public:
- UnwindInfoAnalysis(MCContext *Context, MCInstrInfo const &MCII,
- MCInstrAnalysis *MCIA, bool IsEH,
+ UnwindInfoAnalysis(MCContext *Context, MCInstrInfo const &MCII, bool IsEH,
ArrayRef<MCCFIInstruction> PrologueCFIDirectives);
void update(const MCInst &Inst, ArrayRef<MCCFIInstruction> CFIDirectives);
diff --git a/llvm/lib/MCCFIAnalysis/CFIAnalysisMCStreamer.cpp b/llvm/lib/MCCFIAnalysis/CFIAnalysisMCStreamer.cpp
index 822f7c3d61089..b7b5e1fd37905 100644
--- a/llvm/lib/MCCFIAnalysis/CFIAnalysisMCStreamer.cpp
+++ b/llvm/lib/MCCFIAnalysis/CFIAnalysisMCStreamer.cpp
@@ -71,7 +71,7 @@ void CFIAnalysisMCStreamer::feedCFIA() {
CFIAs.back().update(LastInstruction.value(), CFIDirectives);
} else {
- CFIAs.emplace_back(&getContext(), MCII, MCIA.get(),
+ CFIAs.emplace_back(&getContext(), MCII,
false /* TODO should put isEH here */, CFIDirectives);
}
}
@@ -79,8 +79,8 @@ void CFIAnalysisMCStreamer::feedCFIA() {
CFIAnalysisMCStreamer::CFIAnalysisMCStreamer(
MCContext &Context, const MCInstrInfo &MCII,
std::unique_ptr<MCInstrAnalysis> MCIA)
- : MCStreamer(Context), MCII(MCII), MCIA(std::move(MCIA)),
- LastCFIDirectivesState(), LastInstruction(std::nullopt) {
+ : MCStreamer(Context), MCII(MCII), LastCFIDirectivesState(),
+ LastInstruction(std::nullopt) {
FrameIndices.push_back(-1);
}
diff --git a/llvm/lib/MCCFIAnalysis/UnwindInfoAnalysis.cpp b/llvm/lib/MCCFIAnalysis/UnwindInfoAnalysis.cpp
index 1bebbffde5cce..263c5e280498b 100644
--- a/llvm/lib/MCCFIAnalysis/UnwindInfoAnalysis.cpp
+++ b/llvm/lib/MCCFIAnalysis/UnwindInfoAnalysis.cpp
@@ -109,8 +109,8 @@ MCPhysReg UnwindInfoAnalysis::getSuperReg(MCPhysReg Reg) {
}
UnwindInfoAnalysis::UnwindInfoAnalysis(
- MCContext *Context, MCInstrInfo const &MCII, MCInstrAnalysis *MCIA,
- bool IsEH, ArrayRef<MCCFIInstruction> PrologueCFIDirectives)
+ MCContext *Context, MCInstrInfo const &MCII, bool IsEH,
+ ArrayRef<MCCFIInstruction> PrologueCFIDirectives)
: Context(Context), MCII(MCII), MCRI(Context->getRegisterInfo()),
State(Context), IsEH(IsEH) {
>From 0cf499edb13d77d90692eea70cf6f06f923d1acf Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Sat, 21 Jun 2025 22:14:38 +0000
Subject: [PATCH 39/58] Remove redundant definitions and fields from
CFIAnalysis streamer
---
.../MCCFIAnalysis/CFIAnalysisMCStreamer.h | 32 ++---
.../MCCFIAnalysis/CFIAnalysisMCStreamer.cpp | 130 ++++++++----------
llvm/tools/llvm-mc/llvm-mc.cpp | 6 +-
3 files changed, 66 insertions(+), 102 deletions(-)
diff --git a/llvm/include/llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h b/llvm/include/llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h
index 60e7dcbe53331..f2c791a2addaf 100644
--- a/llvm/include/llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h
+++ b/llvm/include/llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h
@@ -4,11 +4,9 @@
#include "UnwindInfoAnalysis.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDwarf.h"
-#include "llvm/MC/MCInstrAnalysis.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCStreamer.h"
#include <cstdio>
-#include <memory>
#include <optional>
namespace llvm {
@@ -19,35 +17,23 @@ namespace llvm {
// TODO one by one. Also in each function unit, an instruction with associated
// TODO directives should be emitted. The analysis should be run by the
// TODO receiver.
-class CFIAnalysisMCStreamer : public MCStreamer {
+class FunctionUnitStreamer : public MCStreamer {
MCInstrInfo const &MCII;
- struct CFIDirectivesState {
- int DirectiveIndex;
-
- CFIDirectivesState();
-
- CFIDirectivesState(int FrameIndex, int InstructionIndex);
- } LastCFIDirectivesState;
- std::vector<int> FrameIndices;
- std::vector<UnwindInfoAnalysis> CFIAs;
-
- struct ICFI {
- MCInst Instruction;
- std::pair<unsigned, unsigned> CFIDirectivesRange;
-
- ICFI(MCInst Instruction, std::pair<unsigned, unsigned> CFIDirectives);
- };
+ std::vector<unsigned> FrameIndices;
+ std::vector<UnwindInfoAnalysis> UIAs;
+ unsigned LastDirectiveIndex;
std::optional<MCInst> LastInstruction;
- std::pair<unsigned, unsigned> getCFIDirectivesRange();
+ void updateUIA();
- void feedCFIA();
+ std::pair<unsigned, unsigned> updateDirectivesRange();
public:
- CFIAnalysisMCStreamer(MCContext &Context, const MCInstrInfo &MCII,
- std::unique_ptr<MCInstrAnalysis> MCIA);
+ FunctionUnitStreamer(MCContext &Context, const MCInstrInfo &MCII)
+ : MCStreamer(Context), MCII(MCII), LastDirectiveIndex(0),
+ LastInstruction(std::nullopt) {}
bool hasRawTextSupport() const override { return true; }
void emitRawTextImpl(StringRef String) override {}
diff --git a/llvm/lib/MCCFIAnalysis/CFIAnalysisMCStreamer.cpp b/llvm/lib/MCCFIAnalysis/CFIAnalysisMCStreamer.cpp
index b7b5e1fd37905..827560aa28f1d 100644
--- a/llvm/lib/MCCFIAnalysis/CFIAnalysisMCStreamer.cpp
+++ b/llvm/lib/MCCFIAnalysis/CFIAnalysisMCStreamer.cpp
@@ -3,110 +3,92 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDwarf.h"
-#include "llvm/MC/MCInstrAnalysis.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCStreamer.h"
#include <cstdio>
-#include <memory>
#include <optional>
using namespace llvm;
-CFIAnalysisMCStreamer::CFIDirectivesState::CFIDirectivesState()
- : DirectiveIndex(0) {}
-
-CFIAnalysisMCStreamer::CFIDirectivesState::CFIDirectivesState(
- int FrameIndex, int InstructionIndex)
- : DirectiveIndex(InstructionIndex) {}
-
-CFIAnalysisMCStreamer::ICFI::ICFI(MCInst Instruction,
- std::pair<unsigned, unsigned> CFIDirectives)
- : Instruction(Instruction), CFIDirectivesRange(CFIDirectives) {}
-
-std::pair<unsigned, unsigned> CFIAnalysisMCStreamer::getCFIDirectivesRange() {
- auto DwarfFrameInfos = getDwarfFrameInfos();
- int FrameIndex = FrameIndices.back();
- auto CurrentCFIDirectiveState =
- hasUnfinishedDwarfFrameInfo()
- ? CFIDirectivesState(FrameIndex,
- DwarfFrameInfos[FrameIndex].Instructions.size())
- : CFIDirectivesState();
- assert(CurrentCFIDirectiveState.DirectiveIndex >=
- LastCFIDirectivesState.DirectiveIndex);
+std::pair<unsigned, unsigned> FunctionUnitStreamer::updateDirectivesRange() {
+ auto Frames = getDwarfFrameInfos();
+ unsigned CurrentCFIDirectiveIndex = 0;
+ if (hasUnfinishedDwarfFrameInfo()) {
+ assert(!FrameIndices.empty() && "FunctionUnitStreamer frame indices should "
+ "be synced with MCStreamer's");
+ assert(FrameIndices.back() < Frames.size());
+ CurrentCFIDirectiveIndex = Frames[FrameIndices.back()].Instructions.size();
+ }
- std::pair<unsigned, unsigned> CFIDirectivesRange(
- LastCFIDirectivesState.DirectiveIndex,
- CurrentCFIDirectiveState.DirectiveIndex);
- LastCFIDirectivesState = CurrentCFIDirectiveState;
+ assert(CurrentCFIDirectiveIndex >= LastDirectiveIndex);
+ std::pair<unsigned, unsigned> CFIDirectivesRange(LastDirectiveIndex,
+ CurrentCFIDirectiveIndex);
+ LastDirectiveIndex = CurrentCFIDirectiveIndex;
return CFIDirectivesRange;
}
-void CFIAnalysisMCStreamer::feedCFIA() {
- auto FrameIndex = FrameIndices.back();
- if (FrameIndex < 0) {
- // TODO Maybe this corner case causes bugs, when the programmer did a
- // mistake in the startproc, endprocs and also made a mistake in not
- // adding cfi directives for a instruction. Then this would cause to
- // ignore the instruction.
- auto CFIDirectivesRange = getCFIDirectivesRange();
- assert(!LastInstruction ||
- CFIDirectivesRange.first == CFIDirectivesRange.second);
+void FunctionUnitStreamer::updateUIA() {
+ if (FrameIndices.empty()) {
+ auto CFIDirectivesRange = updateDirectivesRange();
+ assert(CFIDirectivesRange.first == CFIDirectivesRange.second &&
+ "CFI directives should be in some frame");
return;
}
- const auto *LastDwarfFrameInfo = &getDwarfFrameInfos()[FrameIndex];
+ const auto *LastFrame = &getDwarfFrameInfos()[FrameIndices.back()];
- auto CFIDirectivesRange = getCFIDirectivesRange();
- ArrayRef<MCCFIInstruction> CFIDirectives;
- if (CFIDirectivesRange.first < CFIDirectivesRange.second) {
- CFIDirectives =
- ArrayRef<MCCFIInstruction>(LastDwarfFrameInfo->Instructions);
- CFIDirectives = CFIDirectives.drop_front(CFIDirectivesRange.first)
- .drop_back(LastDwarfFrameInfo->Instructions.size() -
- CFIDirectivesRange.second);
+ auto DirectivesRange = updateDirectivesRange();
+ ArrayRef<MCCFIInstruction> Directives;
+ if (DirectivesRange.first < DirectivesRange.second) {
+ Directives = ArrayRef<MCCFIInstruction>(LastFrame->Instructions);
+ Directives =
+ Directives.drop_front(DirectivesRange.first)
+ .drop_back(LastFrame->Instructions.size() - DirectivesRange.second);
}
- if (LastInstruction != std::nullopt) {
- assert(!CFIAs.empty());
-
- CFIAs.back().update(LastInstruction.value(), CFIDirectives);
+ if (LastInstruction) {
+ assert(!UIAs.empty() && "If the instruction is in a frame, there should be "
+ "a analysis instantiated for it");
+ UIAs.back().update(LastInstruction.value(), Directives);
} else {
- CFIAs.emplace_back(&getContext(), MCII,
- false /* TODO should put isEH here */, CFIDirectives);
+ assert(!DirectivesRange.first &&
+ "An analysis should be created at the begining of a frame");
+ UIAs.emplace_back(&getContext(), MCII,
+ false /* TODO should put isEH here */, Directives);
}
}
-CFIAnalysisMCStreamer::CFIAnalysisMCStreamer(
- MCContext &Context, const MCInstrInfo &MCII,
- std::unique_ptr<MCInstrAnalysis> MCIA)
- : MCStreamer(Context), MCII(MCII), LastCFIDirectivesState(),
- LastInstruction(std::nullopt) {
- FrameIndices.push_back(-1);
-}
-
-void CFIAnalysisMCStreamer::emitInstruction(const MCInst &Inst,
- const MCSubtargetInfo &STI) {
- feedCFIA();
+void FunctionUnitStreamer::emitInstruction(const MCInst &Inst,
+ const MCSubtargetInfo &STI) {
+ updateUIA();
LastInstruction = Inst;
}
-void CFIAnalysisMCStreamer::emitCFIStartProcImpl(MCDwarfFrameInfo &Frame) {
- feedCFIA();
+void FunctionUnitStreamer::emitCFIStartProcImpl(MCDwarfFrameInfo &Frame) {
+ updateUIA();
FrameIndices.push_back(getNumFrameInfos());
LastInstruction = std::nullopt;
- LastCFIDirectivesState.DirectiveIndex = 0;
+ LastDirectiveIndex = 0;
MCStreamer::emitCFIStartProcImpl(Frame);
}
-void CFIAnalysisMCStreamer::emitCFIEndProcImpl(MCDwarfFrameInfo &CurFrame) {
- feedCFIA();
- // TODO this will break if the input frame are malformed.
+void FunctionUnitStreamer::emitCFIEndProcImpl(MCDwarfFrameInfo &CurFrame) {
+ updateUIA();
+
+ assert(!FrameIndices.empty() && "There should be at least one frame to pop");
FrameIndices.pop_back();
- CFIAs.pop_back();
+
+ assert(!UIAs.empty() && "There should be an analysis for each frame");
+ UIAs.pop_back();
+
LastInstruction = std::nullopt;
- auto FrameIndex = FrameIndices.back();
- LastCFIDirectivesState.DirectiveIndex =
- FrameIndex >= 0 ? getDwarfFrameInfos()[FrameIndex].Instructions.size()
- : 0;
+ LastDirectiveIndex = 0;
+ if (!FrameIndices.empty()) {
+ auto DwarfFrameInfos = getDwarfFrameInfos();
+ assert(FrameIndices.back() < DwarfFrameInfos.size());
+
+ LastDirectiveIndex =
+ DwarfFrameInfos[FrameIndices.back()].Instructions.size();
+ }
MCStreamer::emitCFIEndProcImpl(CurFrame);
}
diff --git a/llvm/tools/llvm-mc/llvm-mc.cpp b/llvm/tools/llvm-mc/llvm-mc.cpp
index c2852298aacb6..eb1a9da56de9d 100644
--- a/llvm/tools/llvm-mc/llvm-mc.cpp
+++ b/llvm/tools/llvm-mc/llvm-mc.cpp
@@ -524,14 +524,10 @@ int main(int argc, char **argv) {
std::unique_ptr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo());
assert(MCII && "Unable to create instruction info!");
- std::unique_ptr<MCInstrAnalysis> MCIA(
- TheTarget->createMCInstrAnalysis(MCII.get()));
- assert(MCIA && "Unable to create instruction analysis!");
-
std::unique_ptr<MCInstPrinter> IP;
if (ValidateCFI) {
assert(FileType == OFT_Null);
- auto *CFIAMCS = new CFIAnalysisMCStreamer(Ctx, *MCII, std::move(MCIA));
+ auto *CFIAMCS = new FunctionUnitStreamer(Ctx, *MCII);
TheTarget->createNullTargetStreamer(*CFIAMCS);
Str.reset(CFIAMCS);
} else if (FileType == OFT_AssemblyFile) {
>From 969f86f987309467e4f818a03f8c39b3acb3ae65 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Sat, 21 Jun 2025 22:36:09 +0000
Subject: [PATCH 40/58] Rename CFIAnalysisStreamer to FunctionUnitStreamer
---
...IAnalysisMCStreamer.h => FunctionUnitStreamer.h} | 13 +++++++------
llvm/lib/MCCFIAnalysis/CMakeLists.txt | 2 +-
...lysisMCStreamer.cpp => FunctionUnitStreamer.cpp} | 2 +-
llvm/tools/llvm-mc/llvm-mc.cpp | 2 +-
4 files changed, 10 insertions(+), 9 deletions(-)
rename llvm/include/llvm/MCCFIAnalysis/{CFIAnalysisMCStreamer.h => FunctionUnitStreamer.h} (79%)
rename llvm/lib/MCCFIAnalysis/{CFIAnalysisMCStreamer.cpp => FunctionUnitStreamer.cpp} (98%)
diff --git a/llvm/include/llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h b/llvm/include/llvm/MCCFIAnalysis/FunctionUnitStreamer.h
similarity index 79%
rename from llvm/include/llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h
rename to llvm/include/llvm/MCCFIAnalysis/FunctionUnitStreamer.h
index f2c791a2addaf..164e810d1b667 100644
--- a/llvm/include/llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h
+++ b/llvm/include/llvm/MCCFIAnalysis/FunctionUnitStreamer.h
@@ -11,12 +11,13 @@
namespace llvm {
-// TODO Now the design is that the streamer, make instances of the analysis and
-// TODO run the analysis on the instruction, but instead the streamer should
-// TODO divide the program into function units, and then emit the function units
-// TODO one by one. Also in each function unit, an instruction with associated
-// TODO directives should be emitted. The analysis should be run by the
-// TODO receiver.
+// ? Now the design is that the streamer, make instances of the analysis and
+// ? run the analysis on the instruction, I suspect that instead the streamer
+// ? should divide the program into function units, and then emit the function
+// ? units one by one. Also in each function unit, an instruction with
+// ? associated directives should be emitted. Furthermore, there should be a
+// ? receiver of these function units, that receive them and run a new analysis
+// ? on them.
class FunctionUnitStreamer : public MCStreamer {
MCInstrInfo const &MCII;
diff --git a/llvm/lib/MCCFIAnalysis/CMakeLists.txt b/llvm/lib/MCCFIAnalysis/CMakeLists.txt
index 28329a5653f77..3662f3e5a53e1 100644
--- a/llvm/lib/MCCFIAnalysis/CMakeLists.txt
+++ b/llvm/lib/MCCFIAnalysis/CMakeLists.txt
@@ -1,6 +1,6 @@
add_llvm_component_library(LLVMMCCFIAnalysis
+ FunctionUnitStreamer.cpp
UnwindInfoHistory.cpp
- CFIAnalysisMCStreamer.cpp
UnwindInfoAnalysis.cpp
ADDITIONAL_HEADER_DIRS
diff --git a/llvm/lib/MCCFIAnalysis/CFIAnalysisMCStreamer.cpp b/llvm/lib/MCCFIAnalysis/FunctionUnitStreamer.cpp
similarity index 98%
rename from llvm/lib/MCCFIAnalysis/CFIAnalysisMCStreamer.cpp
rename to llvm/lib/MCCFIAnalysis/FunctionUnitStreamer.cpp
index 827560aa28f1d..d455c8692aab6 100644
--- a/llvm/lib/MCCFIAnalysis/CFIAnalysisMCStreamer.cpp
+++ b/llvm/lib/MCCFIAnalysis/FunctionUnitStreamer.cpp
@@ -1,5 +1,5 @@
-#include "llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h"
+#include "llvm/MCCFIAnalysis/FunctionUnitStreamer.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDwarf.h"
diff --git a/llvm/tools/llvm-mc/llvm-mc.cpp b/llvm/tools/llvm-mc/llvm-mc.cpp
index eb1a9da56de9d..52363927d6668 100644
--- a/llvm/tools/llvm-mc/llvm-mc.cpp
+++ b/llvm/tools/llvm-mc/llvm-mc.cpp
@@ -14,7 +14,6 @@
#include "Disassembler.h"
#include "llvm/MC/MCAsmBackend.h"
#include "llvm/MC/MCAsmInfo.h"
-#include "llvm/MCCFIAnalysis/CFIAnalysisMCStreamer.h"
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCInstPrinter.h"
@@ -30,6 +29,7 @@
#include "llvm/MC/MCTargetOptions.h"
#include "llvm/MC/MCTargetOptionsCommandFlags.h"
#include "llvm/MC/TargetRegistry.h"
+#include "llvm/MCCFIAnalysis/FunctionUnitStreamer.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Compression.h"
#include "llvm/Support/FileUtilities.h"
>From c57ed1440112b8f011494872b38c3015add6b718 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Mon, 23 Jun 2025 18:00:02 +0000
Subject: [PATCH 41/58] Test function unit streamer functionalities
---
.../llvm-mc/cfi-validation/empty-section.s | 9 +++++++
.../cfi-validation/multiple-sections.s | 26 +++++++++++++++++++
2 files changed, 35 insertions(+)
create mode 100644 llvm/test/tools/llvm-mc/cfi-validation/empty-section.s
create mode 100644 llvm/test/tools/llvm-mc/cfi-validation/multiple-sections.s
diff --git a/llvm/test/tools/llvm-mc/cfi-validation/empty-section.s b/llvm/test/tools/llvm-mc/cfi-validation/empty-section.s
new file mode 100644
index 0000000000000..849e49f5cba35
--- /dev/null
+++ b/llvm/test/tools/llvm-mc/cfi-validation/empty-section.s
@@ -0,0 +1,9 @@
+# RUN: llvm-mc %s --validate-cfi --filetype=null 2>&1
+.text
+ .globl f
+ .type f, @function
+f:
+ .cfi_startproc
+.Lfunc_end0:
+ .size f, .Lfunc_end0-f
+ .cfi_endproc
\ No newline at end of file
diff --git a/llvm/test/tools/llvm-mc/cfi-validation/multiple-sections.s b/llvm/test/tools/llvm-mc/cfi-validation/multiple-sections.s
new file mode 100644
index 0000000000000..a045c94841435
--- /dev/null
+++ b/llvm/test/tools/llvm-mc/cfi-validation/multiple-sections.s
@@ -0,0 +1,26 @@
+# RUN: not llvm-mc %s --validate-cfi --filetype=null 2>&1 \
+# RUN: | FileCheck %s
+.text
+ .globl f
+ .type f, @function
+f:
+ .cfi_startproc
+ pushq %rax
+ # CHECK: error: This instruction modifies CFA register (%RSP) but CFA rule is not changed
+ pushq %rax
+ .cfi_def_cfa %rbp, -24
+ pushq %rax
+ .cfi_endproc
+
+ .cfi_startproc
+ pushq %rax
+ # CHECK: error: This instruction modifies CFA register (%RSP) but CFA rule is not changed
+ pushq %rax
+ .cfi_def_cfa %rbp, -24
+ pushq %rax
+ .cfi_endproc
+
+ retq
+
+.Lfunc_end0:
+ .size f, .Lfunc_end0-f
\ No newline at end of file
>From 0a8f747e63ec2831bd36a4988ab4308ffd5c7e39 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Tue, 24 Jun 2025 00:46:44 +0000
Subject: [PATCH 42/58] Fix the CFIProgram usage temporary
---
llvm/include/llvm/DebugInfo/DWARF/DWARFCFIProgram.h | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFCFIProgram.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFCFIProgram.h
index 1d89ac3578c10..0badfab89c839 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFCFIProgram.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFCFIProgram.h
@@ -112,7 +112,8 @@ class CFIProgram {
/// above. This is indexed by opcode.
LLVM_ABI static ArrayRef<OperandType[MaxOperands]> getOperandTypes();
-private:
+//! FIX me, making these methods public to be usable inside the UnwindInfoAnalysis
+// private:
std::vector<Instruction> Instructions;
const uint64_t CodeAlignmentFactor;
const int64_t DataAlignmentFactor;
>From 48472ac62adac26ae174f83e6dd4e465b5fb6f7f Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Tue, 24 Jun 2025 03:24:32 +0000
Subject: [PATCH 43/58] Minimize check reg diff arguments
---
.../llvm/MCCFIAnalysis/UnwindInfoAnalysis.h | 2 -
llvm/lib/MCCFIAnalysis/UnwindInfoAnalysis.cpp | 39 +++++++++----------
2 files changed, 18 insertions(+), 23 deletions(-)
diff --git a/llvm/include/llvm/MCCFIAnalysis/UnwindInfoAnalysis.h b/llvm/include/llvm/MCCFIAnalysis/UnwindInfoAnalysis.h
index acf5ec2139307..66c22cd6e16d1 100644
--- a/llvm/include/llvm/MCCFIAnalysis/UnwindInfoAnalysis.h
+++ b/llvm/include/llvm/MCCFIAnalysis/UnwindInfoAnalysis.h
@@ -50,8 +50,6 @@ class UnwindInfoAnalysis {
void checkRegDiff(const MCInst &Inst, DWARFRegType Reg,
const dwarf::UnwindTable::const_iterator &PrevRow,
const dwarf::UnwindTable::const_iterator &NextRow,
- const dwarf::UnwindLocation &PrevRegLoc,
- const dwarf::UnwindLocation &NextRegLoc,
const std::set<DWARFRegType> &Reads,
const std::set<DWARFRegType> &Writes);
diff --git a/llvm/lib/MCCFIAnalysis/UnwindInfoAnalysis.cpp b/llvm/lib/MCCFIAnalysis/UnwindInfoAnalysis.cpp
index 263c5e280498b..2f26374a12572 100644
--- a/llvm/lib/MCCFIAnalysis/UnwindInfoAnalysis.cpp
+++ b/llvm/lib/MCCFIAnalysis/UnwindInfoAnalysis.cpp
@@ -193,25 +193,7 @@ void UnwindInfoAnalysis::update(const MCInst &Inst,
for (auto [LLVMReg, _] : getAllSuperRegs()) {
DWARFRegType Reg = MCRI->getDwarfRegNum(LLVMReg, IsEH);
- auto MaybePrevUnwindLoc =
- PrevUnwindRow->getRegisterLocations().getRegisterLocation(Reg);
- auto MaybeNextUnwindLoc =
- CurrentUnwindRow->getRegisterLocations().getRegisterLocation(Reg);
-
- if (!MaybePrevUnwindLoc) {
- assert(!MaybeNextUnwindLoc && "The register unwind info suddenly "
- "appeared here, ignoring this change");
- continue;
- }
-
- assert(MaybeNextUnwindLoc && "The register unwind info suddenly vanished "
- "here, ignoring this change");
-
- auto PrevUnwindLoc = MaybePrevUnwindLoc.value();
- auto NextUnwindLoc = MaybeNextUnwindLoc.value();
-
- checkRegDiff(Inst, Reg, PrevUnwindRow, CurrentUnwindRow, PrevUnwindLoc,
- NextUnwindLoc, Reads, Writes);
+ checkRegDiff(Inst, Reg, PrevUnwindRow, CurrentUnwindRow, Reads, Writes);
}
}
@@ -219,9 +201,24 @@ void UnwindInfoAnalysis::checkRegDiff(
const MCInst &Inst, DWARFRegType Reg,
const dwarf::UnwindTable::const_iterator &PrevRow,
const dwarf::UnwindTable::const_iterator &NextRow,
- const dwarf::UnwindLocation &PrevRegLoc,
- const dwarf::UnwindLocation &NextRegLoc,
const std::set<DWARFRegType> &Reads, const std::set<DWARFRegType> &Writes) {
+ auto MaybePrevUnwindLoc =
+ PrevRow->getRegisterLocations().getRegisterLocation(Reg);
+ auto MaybeNextUnwindLoc =
+ NextRow->getRegisterLocations().getRegisterLocation(Reg);
+
+ if (!MaybePrevUnwindLoc) {
+ assert(!MaybeNextUnwindLoc && "The register unwind info suddenly "
+ "appeared here, ignoring this change");
+ return;
+ }
+
+ assert(MaybeNextUnwindLoc && "The register unwind info suddenly vanished "
+ "here, ignoring this change");
+
+ auto PrevRegLoc = MaybePrevUnwindLoc.value();
+ auto NextRegLoc = MaybeNextUnwindLoc.value();
+
auto MaybeRegLLVM = MCRI->getLLVMRegNum(Reg, IsEH);
if (!MaybeRegLLVM) {
assert(PrevRegLoc == NextRegLoc &&
>From 9b09b49e974d861cf663221c4f79bf8a6e0018a0 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Tue, 24 Jun 2025 18:53:26 +0000
Subject: [PATCH 44/58] Move `FunctionUnitStreamer` analysis calls to a
different class called `FunctionUnitAnalyzer`.
Define `FunctionUnitUnwindInfoAnalyzer` that executes the Analysis during the stream.
The main reasons for doing this is:
- This is compatible with other use cases of `MCStreamer` implementers (e.g. `MCAsmStreamer` and `MCAssembler`).
- This approach result in on the fly analysis, if it was implemented like `RecordStreamer`, then all the instruction of the whole program have to be copied and be stored in the memory.
---
.../llvm/MCCFIAnalysis/FunctionUnitAnalyzer.h | 36 +++++++++++++++++++
.../llvm/MCCFIAnalysis/FunctionUnitStreamer.h | 26 ++++++--------
.../FunctionUnitUnwindInfoAnalyzer.h | 30 ++++++++++++++++
llvm/lib/MCCFIAnalysis/CMakeLists.txt | 2 ++
.../MCCFIAnalysis/FunctionUnitAnalyzer.cpp | 13 +++++++
.../MCCFIAnalysis/FunctionUnitStreamer.cpp | 21 +++++------
.../FunctionUnitUnwindInfoAnalyzer.cpp | 20 +++++++++++
llvm/tools/llvm-mc/llvm-mc.cpp | 10 ++++--
8 files changed, 126 insertions(+), 32 deletions(-)
create mode 100644 llvm/include/llvm/MCCFIAnalysis/FunctionUnitAnalyzer.h
create mode 100644 llvm/include/llvm/MCCFIAnalysis/FunctionUnitUnwindInfoAnalyzer.h
create mode 100644 llvm/lib/MCCFIAnalysis/FunctionUnitAnalyzer.cpp
create mode 100644 llvm/lib/MCCFIAnalysis/FunctionUnitUnwindInfoAnalyzer.cpp
diff --git a/llvm/include/llvm/MCCFIAnalysis/FunctionUnitAnalyzer.h b/llvm/include/llvm/MCCFIAnalysis/FunctionUnitAnalyzer.h
new file mode 100644
index 0000000000000..aa0eb13e016be
--- /dev/null
+++ b/llvm/include/llvm/MCCFIAnalysis/FunctionUnitAnalyzer.h
@@ -0,0 +1,36 @@
+#ifndef LLVM_MC_CFI_ANALYSIS_FUNCTION_UNIT_ANALYZER_H
+#define LLVM_MC_CFI_ANALYSIS_FUNCTION_UNIT_ANALYZER_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include <cstdio>
+
+namespace llvm {
+
+class MCCFIInstruction;
+class MCContext;
+class MCInst;
+
+class FunctionUnitAnalyzer {
+private:
+ MCContext &Context;
+
+public:
+ FunctionUnitAnalyzer(const FunctionUnitAnalyzer &) = delete;
+ FunctionUnitAnalyzer &operator=(const FunctionUnitAnalyzer &) = delete;
+ virtual ~FunctionUnitAnalyzer();
+
+ FunctionUnitAnalyzer(MCContext &Context) : Context(Context) {}
+
+ MCContext &getContext() const { return Context; }
+
+ virtual void startFunctionUnit(bool IsEH,
+ ArrayRef<MCCFIInstruction> Prologue);
+ virtual void
+ emitInstructionAndDirectives(const MCInst &Inst,
+ ArrayRef<MCCFIInstruction> Directives);
+ virtual void finishFunctionUnit();
+};
+
+} // namespace llvm
+
+#endif
\ No newline at end of file
diff --git a/llvm/include/llvm/MCCFIAnalysis/FunctionUnitStreamer.h b/llvm/include/llvm/MCCFIAnalysis/FunctionUnitStreamer.h
index 164e810d1b667..fa104b15a330c 100644
--- a/llvm/include/llvm/MCCFIAnalysis/FunctionUnitStreamer.h
+++ b/llvm/include/llvm/MCCFIAnalysis/FunctionUnitStreamer.h
@@ -1,40 +1,34 @@
#ifndef LLVM_TOOLS_LLVM_MC_CFI_ANALYSIS_MC_STREAMER_H
#define LLVM_TOOLS_LLVM_MC_CFI_ANALYSIS_MC_STREAMER_H
-#include "UnwindInfoAnalysis.h"
+#include "FunctionUnitAnalyzer.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDwarf.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCStreamer.h"
#include <cstdio>
+#include <memory>
#include <optional>
namespace llvm {
-// ? Now the design is that the streamer, make instances of the analysis and
-// ? run the analysis on the instruction, I suspect that instead the streamer
-// ? should divide the program into function units, and then emit the function
-// ? units one by one. Also in each function unit, an instruction with
-// ? associated directives should be emitted. Furthermore, there should be a
-// ? receiver of these function units, that receive them and run a new analysis
-// ? on them.
class FunctionUnitStreamer : public MCStreamer {
- MCInstrInfo const &MCII;
-
std::vector<unsigned> FrameIndices;
- std::vector<UnwindInfoAnalysis> UIAs;
unsigned LastDirectiveIndex;
std::optional<MCInst> LastInstruction;
-
- void updateUIA();
+ std::unique_ptr<FunctionUnitAnalyzer> Analyzer;
std::pair<unsigned, unsigned> updateDirectivesRange();
+ void updateAnalyzer();
public:
- FunctionUnitStreamer(MCContext &Context, const MCInstrInfo &MCII)
- : MCStreamer(Context), MCII(MCII), LastDirectiveIndex(0),
- LastInstruction(std::nullopt) {}
+ FunctionUnitStreamer(MCContext &Context,
+ std::unique_ptr<FunctionUnitAnalyzer> Analyzer)
+ : MCStreamer(Context), LastDirectiveIndex(0),
+ LastInstruction(std::nullopt), Analyzer(std::move(Analyzer)) {
+ assert(this->Analyzer && "Analyzer should not be null");
+ }
bool hasRawTextSupport() const override { return true; }
void emitRawTextImpl(StringRef String) override {}
diff --git a/llvm/include/llvm/MCCFIAnalysis/FunctionUnitUnwindInfoAnalyzer.h b/llvm/include/llvm/MCCFIAnalysis/FunctionUnitUnwindInfoAnalyzer.h
new file mode 100644
index 0000000000000..a48e7c90409cb
--- /dev/null
+++ b/llvm/include/llvm/MCCFIAnalysis/FunctionUnitUnwindInfoAnalyzer.h
@@ -0,0 +1,30 @@
+#ifndef LLVM_MC_CFI_ANALYSIS_FUNCTION_UNIT_UNWIND_INFO_ANALYZER_H
+#define LLVM_MC_CFI_ANALYSIS_FUNCTION_UNIT_UNWIND_INFO_ANALYZER_H
+
+#include "FunctionUnitAnalyzer.h"
+#include "UnwindInfoAnalysis.h"
+#include "llvm/ADT/ArrayRef.h"
+#include <cstdio>
+
+namespace llvm {
+
+class FunctionUnitUnwindInfoAnalyzer : public FunctionUnitAnalyzer {
+private:
+ std::vector<UnwindInfoAnalysis> UIAs;
+ MCInstrInfo const &MCII;
+
+public:
+ FunctionUnitUnwindInfoAnalyzer(MCContext &Context, const MCInstrInfo &MCII)
+ : FunctionUnitAnalyzer(Context), MCII(MCII) {}
+
+ void startFunctionUnit(bool IsEH,
+ ArrayRef<MCCFIInstruction> Prologue) override;
+ void
+ emitInstructionAndDirectives(const MCInst &Inst,
+ ArrayRef<MCCFIInstruction> Directives) override;
+ void finishFunctionUnit() override;
+};
+
+} // namespace llvm
+
+#endif
\ No newline at end of file
diff --git a/llvm/lib/MCCFIAnalysis/CMakeLists.txt b/llvm/lib/MCCFIAnalysis/CMakeLists.txt
index 3662f3e5a53e1..756cbeae22c33 100644
--- a/llvm/lib/MCCFIAnalysis/CMakeLists.txt
+++ b/llvm/lib/MCCFIAnalysis/CMakeLists.txt
@@ -1,5 +1,7 @@
add_llvm_component_library(LLVMMCCFIAnalysis
+ FunctionUnitAnalyzer.cpp
FunctionUnitStreamer.cpp
+ FunctionUnitUnwindInfoAnalyzer.cpp
UnwindInfoHistory.cpp
UnwindInfoAnalysis.cpp
diff --git a/llvm/lib/MCCFIAnalysis/FunctionUnitAnalyzer.cpp b/llvm/lib/MCCFIAnalysis/FunctionUnitAnalyzer.cpp
new file mode 100644
index 0000000000000..1a40c1285e263
--- /dev/null
+++ b/llvm/lib/MCCFIAnalysis/FunctionUnitAnalyzer.cpp
@@ -0,0 +1,13 @@
+#include "llvm/MCCFIAnalysis/FunctionUnitAnalyzer.h"
+
+using namespace llvm;
+
+FunctionUnitAnalyzer::~FunctionUnitAnalyzer() = default;
+
+void FunctionUnitAnalyzer::startFunctionUnit(
+ bool IsEH, ArrayRef<MCCFIInstruction> Prologue) {}
+
+void FunctionUnitAnalyzer::emitInstructionAndDirectives(
+ const MCInst &Inst, ArrayRef<MCCFIInstruction> Directives) {}
+
+void FunctionUnitAnalyzer::finishFunctionUnit() {}
\ No newline at end of file
diff --git a/llvm/lib/MCCFIAnalysis/FunctionUnitStreamer.cpp b/llvm/lib/MCCFIAnalysis/FunctionUnitStreamer.cpp
index d455c8692aab6..72d900b380040 100644
--- a/llvm/lib/MCCFIAnalysis/FunctionUnitStreamer.cpp
+++ b/llvm/lib/MCCFIAnalysis/FunctionUnitStreamer.cpp
@@ -27,7 +27,7 @@ std::pair<unsigned, unsigned> FunctionUnitStreamer::updateDirectivesRange() {
return CFIDirectivesRange;
}
-void FunctionUnitStreamer::updateUIA() {
+void FunctionUnitStreamer::updateAnalyzer() {
if (FrameIndices.empty()) {
auto CFIDirectivesRange = updateDirectivesRange();
assert(CFIDirectivesRange.first == CFIDirectivesRange.second &&
@@ -47,25 +47,21 @@ void FunctionUnitStreamer::updateUIA() {
}
if (LastInstruction) {
- assert(!UIAs.empty() && "If the instruction is in a frame, there should be "
- "a analysis instantiated for it");
- UIAs.back().update(LastInstruction.value(), Directives);
+ Analyzer->emitInstructionAndDirectives(LastInstruction.value(), Directives);
} else {
- assert(!DirectivesRange.first &&
- "An analysis should be created at the begining of a frame");
- UIAs.emplace_back(&getContext(), MCII,
- false /* TODO should put isEH here */, Directives);
+ Analyzer->startFunctionUnit(false /* TODO should put isEH here */,
+ Directives);
}
}
void FunctionUnitStreamer::emitInstruction(const MCInst &Inst,
const MCSubtargetInfo &STI) {
- updateUIA();
+ updateAnalyzer();
LastInstruction = Inst;
}
void FunctionUnitStreamer::emitCFIStartProcImpl(MCDwarfFrameInfo &Frame) {
- updateUIA();
+ updateAnalyzer();
FrameIndices.push_back(getNumFrameInfos());
LastInstruction = std::nullopt;
LastDirectiveIndex = 0;
@@ -73,13 +69,12 @@ void FunctionUnitStreamer::emitCFIStartProcImpl(MCDwarfFrameInfo &Frame) {
}
void FunctionUnitStreamer::emitCFIEndProcImpl(MCDwarfFrameInfo &CurFrame) {
- updateUIA();
+ updateAnalyzer();
assert(!FrameIndices.empty() && "There should be at least one frame to pop");
FrameIndices.pop_back();
- assert(!UIAs.empty() && "There should be an analysis for each frame");
- UIAs.pop_back();
+ Analyzer->finishFunctionUnit();
LastInstruction = std::nullopt;
LastDirectiveIndex = 0;
diff --git a/llvm/lib/MCCFIAnalysis/FunctionUnitUnwindInfoAnalyzer.cpp b/llvm/lib/MCCFIAnalysis/FunctionUnitUnwindInfoAnalyzer.cpp
new file mode 100644
index 0000000000000..021d3ec9e07cb
--- /dev/null
+++ b/llvm/lib/MCCFIAnalysis/FunctionUnitUnwindInfoAnalyzer.cpp
@@ -0,0 +1,20 @@
+#include "llvm/MCCFIAnalysis/FunctionUnitUnwindInfoAnalyzer.h"
+
+using namespace llvm;
+
+void FunctionUnitUnwindInfoAnalyzer::startFunctionUnit(
+ bool IsEH, ArrayRef<MCCFIInstruction> Prologue) {
+ UIAs.emplace_back(&getContext(), MCII, IsEH, Prologue);
+}
+
+void FunctionUnitUnwindInfoAnalyzer::emitInstructionAndDirectives(
+ const MCInst &Inst, ArrayRef<MCCFIInstruction> Directives) {
+ assert(!UIAs.empty() && "If the instruction is in a frame, there should be "
+ "a analysis instantiated for it");
+ UIAs.back().update(Inst, Directives);
+}
+
+void FunctionUnitUnwindInfoAnalyzer::finishFunctionUnit() {
+ assert(!UIAs.empty() && "There should be an analysis for each frame");
+ UIAs.pop_back();
+}
\ No newline at end of file
diff --git a/llvm/tools/llvm-mc/llvm-mc.cpp b/llvm/tools/llvm-mc/llvm-mc.cpp
index 52363927d6668..d8ff252685c88 100644
--- a/llvm/tools/llvm-mc/llvm-mc.cpp
+++ b/llvm/tools/llvm-mc/llvm-mc.cpp
@@ -30,6 +30,7 @@
#include "llvm/MC/MCTargetOptionsCommandFlags.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/MCCFIAnalysis/FunctionUnitStreamer.h"
+#include "llvm/MCCFIAnalysis/FunctionUnitUnwindInfoAnalyzer.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Compression.h"
#include "llvm/Support/FileUtilities.h"
@@ -524,12 +525,15 @@ int main(int argc, char **argv) {
std::unique_ptr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo());
assert(MCII && "Unable to create instruction info!");
+ std::unique_ptr<FunctionUnitUnwindInfoAnalyzer> FUUIA(
+ new FunctionUnitUnwindInfoAnalyzer(Ctx, *MCII));
+
std::unique_ptr<MCInstPrinter> IP;
if (ValidateCFI) {
assert(FileType == OFT_Null);
- auto *CFIAMCS = new FunctionUnitStreamer(Ctx, *MCII);
- TheTarget->createNullTargetStreamer(*CFIAMCS);
- Str.reset(CFIAMCS);
+ auto *FUS = new FunctionUnitStreamer(Ctx, std::move(FUUIA));
+ TheTarget->createNullTargetStreamer(*FUS);
+ Str.reset(FUS);
} else if (FileType == OFT_AssemblyFile) {
IP.reset(TheTarget->createMCInstPrinter(
Triple(TripleName), OutputAsmVariant, *MAI, *MCII, *MRI));
>From 7576857d697a2a8a4e87ed0023fa44d703c5e904 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Tue, 24 Jun 2025 21:07:49 +0000
Subject: [PATCH 45/58] Rename the library to UnwindInfoChecker
---
.../FunctionUnitAnalyzer.h | 0
.../FunctionUnitStreamer.h | 0
.../FunctionUnitUnwindInfoAnalyzer.h | 0
.../{MCCFIAnalysis => UnwindInfoChecker}/UnwindInfoAnalysis.h | 0
.../{MCCFIAnalysis => UnwindInfoChecker}/UnwindInfoHistory.h | 0
llvm/lib/CMakeLists.txt | 2 +-
llvm/lib/{MCCFIAnalysis => UnwindInfoChecker}/CMakeLists.txt | 2 +-
.../FunctionUnitAnalyzer.cpp | 2 +-
.../FunctionUnitStreamer.cpp | 2 +-
.../FunctionUnitUnwindInfoAnalyzer.cpp | 2 +-
.../UnwindInfoAnalysis.cpp | 4 ++--
.../UnwindInfoHistory.cpp | 2 +-
llvm/tools/llvm-mc/CMakeLists.txt | 2 +-
llvm/tools/llvm-mc/llvm-mc.cpp | 4 ++--
14 files changed, 11 insertions(+), 11 deletions(-)
rename llvm/include/llvm/{MCCFIAnalysis => UnwindInfoChecker}/FunctionUnitAnalyzer.h (100%)
rename llvm/include/llvm/{MCCFIAnalysis => UnwindInfoChecker}/FunctionUnitStreamer.h (100%)
rename llvm/include/llvm/{MCCFIAnalysis => UnwindInfoChecker}/FunctionUnitUnwindInfoAnalyzer.h (100%)
rename llvm/include/llvm/{MCCFIAnalysis => UnwindInfoChecker}/UnwindInfoAnalysis.h (100%)
rename llvm/include/llvm/{MCCFIAnalysis => UnwindInfoChecker}/UnwindInfoHistory.h (100%)
rename llvm/lib/{MCCFIAnalysis => UnwindInfoChecker}/CMakeLists.txt (83%)
rename llvm/lib/{MCCFIAnalysis => UnwindInfoChecker}/FunctionUnitAnalyzer.cpp (86%)
rename llvm/lib/{MCCFIAnalysis => UnwindInfoChecker}/FunctionUnitStreamer.cpp (98%)
rename llvm/lib/{MCCFIAnalysis => UnwindInfoChecker}/FunctionUnitUnwindInfoAnalyzer.cpp (90%)
rename llvm/lib/{MCCFIAnalysis => UnwindInfoChecker}/UnwindInfoAnalysis.cpp (99%)
rename llvm/lib/{MCCFIAnalysis => UnwindInfoChecker}/UnwindInfoHistory.cpp (99%)
diff --git a/llvm/include/llvm/MCCFIAnalysis/FunctionUnitAnalyzer.h b/llvm/include/llvm/UnwindInfoChecker/FunctionUnitAnalyzer.h
similarity index 100%
rename from llvm/include/llvm/MCCFIAnalysis/FunctionUnitAnalyzer.h
rename to llvm/include/llvm/UnwindInfoChecker/FunctionUnitAnalyzer.h
diff --git a/llvm/include/llvm/MCCFIAnalysis/FunctionUnitStreamer.h b/llvm/include/llvm/UnwindInfoChecker/FunctionUnitStreamer.h
similarity index 100%
rename from llvm/include/llvm/MCCFIAnalysis/FunctionUnitStreamer.h
rename to llvm/include/llvm/UnwindInfoChecker/FunctionUnitStreamer.h
diff --git a/llvm/include/llvm/MCCFIAnalysis/FunctionUnitUnwindInfoAnalyzer.h b/llvm/include/llvm/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.h
similarity index 100%
rename from llvm/include/llvm/MCCFIAnalysis/FunctionUnitUnwindInfoAnalyzer.h
rename to llvm/include/llvm/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.h
diff --git a/llvm/include/llvm/MCCFIAnalysis/UnwindInfoAnalysis.h b/llvm/include/llvm/UnwindInfoChecker/UnwindInfoAnalysis.h
similarity index 100%
rename from llvm/include/llvm/MCCFIAnalysis/UnwindInfoAnalysis.h
rename to llvm/include/llvm/UnwindInfoChecker/UnwindInfoAnalysis.h
diff --git a/llvm/include/llvm/MCCFIAnalysis/UnwindInfoHistory.h b/llvm/include/llvm/UnwindInfoChecker/UnwindInfoHistory.h
similarity index 100%
rename from llvm/include/llvm/MCCFIAnalysis/UnwindInfoHistory.h
rename to llvm/include/llvm/UnwindInfoChecker/UnwindInfoHistory.h
diff --git a/llvm/lib/CMakeLists.txt b/llvm/lib/CMakeLists.txt
index 08b68aee46efd..63c2203c7caef 100644
--- a/llvm/lib/CMakeLists.txt
+++ b/llvm/lib/CMakeLists.txt
@@ -24,7 +24,7 @@ add_subdirectory(Analysis)
add_subdirectory(LTO)
add_subdirectory(MC)
add_subdirectory(MCA)
-add_subdirectory(MCCFIAnalysis)
+add_subdirectory(UnwindInfoChecker)
add_subdirectory(ObjCopy)
add_subdirectory(Object)
add_subdirectory(ObjectYAML)
diff --git a/llvm/lib/MCCFIAnalysis/CMakeLists.txt b/llvm/lib/UnwindInfoChecker/CMakeLists.txt
similarity index 83%
rename from llvm/lib/MCCFIAnalysis/CMakeLists.txt
rename to llvm/lib/UnwindInfoChecker/CMakeLists.txt
index 756cbeae22c33..c1ae214d2dc78 100644
--- a/llvm/lib/MCCFIAnalysis/CMakeLists.txt
+++ b/llvm/lib/UnwindInfoChecker/CMakeLists.txt
@@ -1,4 +1,4 @@
-add_llvm_component_library(LLVMMCCFIAnalysis
+add_llvm_component_library(LLVMUnwindInfoChecker
FunctionUnitAnalyzer.cpp
FunctionUnitStreamer.cpp
FunctionUnitUnwindInfoAnalyzer.cpp
diff --git a/llvm/lib/MCCFIAnalysis/FunctionUnitAnalyzer.cpp b/llvm/lib/UnwindInfoChecker/FunctionUnitAnalyzer.cpp
similarity index 86%
rename from llvm/lib/MCCFIAnalysis/FunctionUnitAnalyzer.cpp
rename to llvm/lib/UnwindInfoChecker/FunctionUnitAnalyzer.cpp
index 1a40c1285e263..5b269db4ae141 100644
--- a/llvm/lib/MCCFIAnalysis/FunctionUnitAnalyzer.cpp
+++ b/llvm/lib/UnwindInfoChecker/FunctionUnitAnalyzer.cpp
@@ -1,4 +1,4 @@
-#include "llvm/MCCFIAnalysis/FunctionUnitAnalyzer.h"
+#include "llvm/UnwindInfoChecker/FunctionUnitAnalyzer.h"
using namespace llvm;
diff --git a/llvm/lib/MCCFIAnalysis/FunctionUnitStreamer.cpp b/llvm/lib/UnwindInfoChecker/FunctionUnitStreamer.cpp
similarity index 98%
rename from llvm/lib/MCCFIAnalysis/FunctionUnitStreamer.cpp
rename to llvm/lib/UnwindInfoChecker/FunctionUnitStreamer.cpp
index 72d900b380040..74b7eec12acf0 100644
--- a/llvm/lib/MCCFIAnalysis/FunctionUnitStreamer.cpp
+++ b/llvm/lib/UnwindInfoChecker/FunctionUnitStreamer.cpp
@@ -1,5 +1,5 @@
-#include "llvm/MCCFIAnalysis/FunctionUnitStreamer.h"
+#include "llvm/UnwindInfoChecker/FunctionUnitStreamer.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDwarf.h"
diff --git a/llvm/lib/MCCFIAnalysis/FunctionUnitUnwindInfoAnalyzer.cpp b/llvm/lib/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.cpp
similarity index 90%
rename from llvm/lib/MCCFIAnalysis/FunctionUnitUnwindInfoAnalyzer.cpp
rename to llvm/lib/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.cpp
index 021d3ec9e07cb..d37509298c9b6 100644
--- a/llvm/lib/MCCFIAnalysis/FunctionUnitUnwindInfoAnalyzer.cpp
+++ b/llvm/lib/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.cpp
@@ -1,4 +1,4 @@
-#include "llvm/MCCFIAnalysis/FunctionUnitUnwindInfoAnalyzer.h"
+#include "llvm/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.h"
using namespace llvm;
diff --git a/llvm/lib/MCCFIAnalysis/UnwindInfoAnalysis.cpp b/llvm/lib/UnwindInfoChecker/UnwindInfoAnalysis.cpp
similarity index 99%
rename from llvm/lib/MCCFIAnalysis/UnwindInfoAnalysis.cpp
rename to llvm/lib/UnwindInfoChecker/UnwindInfoAnalysis.cpp
index 2f26374a12572..afb6af1be17a0 100644
--- a/llvm/lib/MCCFIAnalysis/UnwindInfoAnalysis.cpp
+++ b/llvm/lib/UnwindInfoChecker/UnwindInfoAnalysis.cpp
@@ -1,4 +1,4 @@
-#include "llvm/MCCFIAnalysis/UnwindInfoAnalysis.h"
+#include "llvm/UnwindInfoChecker/UnwindInfoAnalysis.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
@@ -15,11 +15,11 @@
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/TargetRegistry.h"
-#include "llvm/MCCFIAnalysis/UnwindInfoHistory.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/FormatVariadic.h"
+#include "llvm/UnwindInfoChecker/UnwindInfoHistory.h"
#include <cstdint>
#include <optional>
#include <set>
diff --git a/llvm/lib/MCCFIAnalysis/UnwindInfoHistory.cpp b/llvm/lib/UnwindInfoChecker/UnwindInfoHistory.cpp
similarity index 99%
rename from llvm/lib/MCCFIAnalysis/UnwindInfoHistory.cpp
rename to llvm/lib/UnwindInfoChecker/UnwindInfoHistory.cpp
index f44ac07bc0acb..9ee0be1770e99 100644
--- a/llvm/lib/MCCFIAnalysis/UnwindInfoHistory.cpp
+++ b/llvm/lib/UnwindInfoChecker/UnwindInfoHistory.cpp
@@ -1,5 +1,5 @@
// TODO check what includes to keep and what to remove
-#include "llvm/MCCFIAnalysis/UnwindInfoHistory.h"
+#include "llvm/UnwindInfoChecker/UnwindInfoHistory.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
#include "llvm/MC/MCDwarf.h"
diff --git a/llvm/tools/llvm-mc/CMakeLists.txt b/llvm/tools/llvm-mc/CMakeLists.txt
index 83c40d1cd2122..c7e62156a9e68 100644
--- a/llvm/tools/llvm-mc/CMakeLists.txt
+++ b/llvm/tools/llvm-mc/CMakeLists.txt
@@ -4,10 +4,10 @@ set(LLVM_LINK_COMPONENTS
AllTargetsDisassemblers
AllTargetsInfos
MC
- MCCFIAnalysis
MCParser
Support
TargetParser
+ UnwindInfoChecker
)
add_llvm_tool(llvm-mc
diff --git a/llvm/tools/llvm-mc/llvm-mc.cpp b/llvm/tools/llvm-mc/llvm-mc.cpp
index d8ff252685c88..a0f5998d3f8fd 100644
--- a/llvm/tools/llvm-mc/llvm-mc.cpp
+++ b/llvm/tools/llvm-mc/llvm-mc.cpp
@@ -29,8 +29,6 @@
#include "llvm/MC/MCTargetOptions.h"
#include "llvm/MC/MCTargetOptionsCommandFlags.h"
#include "llvm/MC/TargetRegistry.h"
-#include "llvm/MCCFIAnalysis/FunctionUnitStreamer.h"
-#include "llvm/MCCFIAnalysis/FunctionUnitUnwindInfoAnalyzer.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Compression.h"
#include "llvm/Support/FileUtilities.h"
@@ -44,6 +42,8 @@
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/TargetParser/Host.h"
+#include "llvm/UnwindInfoChecker/FunctionUnitStreamer.h"
+#include "llvm/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.h"
#include <memory>
#include <optional>
>From 374f144d25ead473c47fd76d0faffa0dd7877522 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Tue, 24 Jun 2025 21:32:51 +0000
Subject: [PATCH 46/58] Fix the header guards
---
llvm/include/llvm/UnwindInfoChecker/FunctionUnitAnalyzer.h | 4 ++--
llvm/include/llvm/UnwindInfoChecker/FunctionUnitStreamer.h | 4 ++--
.../llvm/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.h | 4 ++--
llvm/include/llvm/UnwindInfoChecker/UnwindInfoAnalysis.h | 4 ++--
llvm/include/llvm/UnwindInfoChecker/UnwindInfoHistory.h | 4 ++--
5 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/llvm/include/llvm/UnwindInfoChecker/FunctionUnitAnalyzer.h b/llvm/include/llvm/UnwindInfoChecker/FunctionUnitAnalyzer.h
index aa0eb13e016be..8798620833b3f 100644
--- a/llvm/include/llvm/UnwindInfoChecker/FunctionUnitAnalyzer.h
+++ b/llvm/include/llvm/UnwindInfoChecker/FunctionUnitAnalyzer.h
@@ -1,5 +1,5 @@
-#ifndef LLVM_MC_CFI_ANALYSIS_FUNCTION_UNIT_ANALYZER_H
-#define LLVM_MC_CFI_ANALYSIS_FUNCTION_UNIT_ANALYZER_H
+#ifndef LLVM_UNWINDINFOCHECKER_FUNCTIONUNITANALYZER_H
+#define LLVM_UNWINDINFOCHECKER_FUNCTIONUNITANALYZER_H
#include "llvm/ADT/ArrayRef.h"
#include <cstdio>
diff --git a/llvm/include/llvm/UnwindInfoChecker/FunctionUnitStreamer.h b/llvm/include/llvm/UnwindInfoChecker/FunctionUnitStreamer.h
index fa104b15a330c..7546a7b172525 100644
--- a/llvm/include/llvm/UnwindInfoChecker/FunctionUnitStreamer.h
+++ b/llvm/include/llvm/UnwindInfoChecker/FunctionUnitStreamer.h
@@ -1,5 +1,5 @@
-#ifndef LLVM_TOOLS_LLVM_MC_CFI_ANALYSIS_MC_STREAMER_H
-#define LLVM_TOOLS_LLVM_MC_CFI_ANALYSIS_MC_STREAMER_H
+#ifndef LLVM_UNWINDINFOCHECKER_FUNCTIONUNITSTREAMER_H
+#define LLVM_UNWINDINFOCHECKER_FUNCTIONUNITSTREAMER_H
#include "FunctionUnitAnalyzer.h"
#include "llvm/MC/MCContext.h"
diff --git a/llvm/include/llvm/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.h b/llvm/include/llvm/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.h
index a48e7c90409cb..ccb5e16cb5bbf 100644
--- a/llvm/include/llvm/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.h
+++ b/llvm/include/llvm/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.h
@@ -1,5 +1,5 @@
-#ifndef LLVM_MC_CFI_ANALYSIS_FUNCTION_UNIT_UNWIND_INFO_ANALYZER_H
-#define LLVM_MC_CFI_ANALYSIS_FUNCTION_UNIT_UNWIND_INFO_ANALYZER_H
+#ifndef LLVM_UNWINDINFOCHECKER_FUNCTIONUNITUNWINDINFOANALYZER_H
+#define LLVM_UNWINDINFOCHECKER_FUNCTIONUNITUNWINDINFOANALYZER_H
#include "FunctionUnitAnalyzer.h"
#include "UnwindInfoAnalysis.h"
diff --git a/llvm/include/llvm/UnwindInfoChecker/UnwindInfoAnalysis.h b/llvm/include/llvm/UnwindInfoChecker/UnwindInfoAnalysis.h
index 66c22cd6e16d1..438f9c10c581a 100644
--- a/llvm/include/llvm/UnwindInfoChecker/UnwindInfoAnalysis.h
+++ b/llvm/include/llvm/UnwindInfoChecker/UnwindInfoAnalysis.h
@@ -1,5 +1,5 @@
-#ifndef LLVM_TOOLS_LLVM_MC_CFI_ANALYSIS_H
-#define LLVM_TOOLS_LLVM_MC_CFI_ANALYSIS_H
+#ifndef LLVM_UNWINDINFOCHECKER_UNWINDINFOANALYSIS_H
+#define LLVM_UNWINDINFOCHECKER_UNWINDINFOANALYSIS_H
#include "UnwindInfoHistory.h"
#include "llvm/ADT/ArrayRef.h"
diff --git a/llvm/include/llvm/UnwindInfoChecker/UnwindInfoHistory.h b/llvm/include/llvm/UnwindInfoChecker/UnwindInfoHistory.h
index 1f357e0e8fc55..3df26df5ca424 100644
--- a/llvm/include/llvm/UnwindInfoChecker/UnwindInfoHistory.h
+++ b/llvm/include/llvm/UnwindInfoChecker/UnwindInfoHistory.h
@@ -1,5 +1,5 @@
-#ifndef LLVM_TOOLS_LLVM_MC_CFI_STATE_H
-#define LLVM_TOOLS_LLVM_MC_CFI_STATE_H
+#ifndef LLVM_UNWINDINFOCHECKER_UNWINDINFOHISTORY_H
+#define LLVM_UNWINDINFOCHECKER_UNWINDINFOHISTORY_H
#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
#include "llvm/MC/MCContext.h"
>From e42907f0aba11dff2292ec1f4cb2b91c815e7a8f Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Tue, 24 Jun 2025 22:13:45 +0000
Subject: [PATCH 47/58] Add file headers
---
.../llvm/UnwindInfoChecker/FunctionUnitAnalyzer.h | 12 ++++++++++++
.../llvm/UnwindInfoChecker/FunctionUnitStreamer.h | 12 ++++++++++++
.../FunctionUnitUnwindInfoAnalyzer.h | 12 ++++++++++++
.../llvm/UnwindInfoChecker/UnwindInfoAnalysis.h | 12 ++++++++++++
.../llvm/UnwindInfoChecker/UnwindInfoHistory.h | 12 ++++++++++++
llvm/lib/UnwindInfoChecker/FunctionUnitAnalyzer.cpp | 8 ++++++++
llvm/lib/UnwindInfoChecker/FunctionUnitStreamer.cpp | 7 +++++++
.../FunctionUnitUnwindInfoAnalyzer.cpp | 8 ++++++++
llvm/lib/UnwindInfoChecker/UnwindInfoAnalysis.cpp | 8 ++++++++
llvm/lib/UnwindInfoChecker/UnwindInfoHistory.cpp | 9 ++++++++-
10 files changed, 99 insertions(+), 1 deletion(-)
diff --git a/llvm/include/llvm/UnwindInfoChecker/FunctionUnitAnalyzer.h b/llvm/include/llvm/UnwindInfoChecker/FunctionUnitAnalyzer.h
index 8798620833b3f..2df320babcd38 100644
--- a/llvm/include/llvm/UnwindInfoChecker/FunctionUnitAnalyzer.h
+++ b/llvm/include/llvm/UnwindInfoChecker/FunctionUnitAnalyzer.h
@@ -1,3 +1,15 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// This file declares FunctionUnitAnalyzer class.
+///
+//===----------------------------------------------------------------------===//
+
#ifndef LLVM_UNWINDINFOCHECKER_FUNCTIONUNITANALYZER_H
#define LLVM_UNWINDINFOCHECKER_FUNCTIONUNITANALYZER_H
diff --git a/llvm/include/llvm/UnwindInfoChecker/FunctionUnitStreamer.h b/llvm/include/llvm/UnwindInfoChecker/FunctionUnitStreamer.h
index 7546a7b172525..517f82a4bb588 100644
--- a/llvm/include/llvm/UnwindInfoChecker/FunctionUnitStreamer.h
+++ b/llvm/include/llvm/UnwindInfoChecker/FunctionUnitStreamer.h
@@ -1,3 +1,15 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// This file declares FunctionUnitStreamer class.
+///
+//===----------------------------------------------------------------------===//
+
#ifndef LLVM_UNWINDINFOCHECKER_FUNCTIONUNITSTREAMER_H
#define LLVM_UNWINDINFOCHECKER_FUNCTIONUNITSTREAMER_H
diff --git a/llvm/include/llvm/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.h b/llvm/include/llvm/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.h
index ccb5e16cb5bbf..4e9b27d8da0ca 100644
--- a/llvm/include/llvm/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.h
+++ b/llvm/include/llvm/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.h
@@ -1,3 +1,15 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// This file declares FunctionUnitUnwindInfoAnalyzer class.
+///
+//===----------------------------------------------------------------------===//
+
#ifndef LLVM_UNWINDINFOCHECKER_FUNCTIONUNITUNWINDINFOANALYZER_H
#define LLVM_UNWINDINFOCHECKER_FUNCTIONUNITUNWINDINFOANALYZER_H
diff --git a/llvm/include/llvm/UnwindInfoChecker/UnwindInfoAnalysis.h b/llvm/include/llvm/UnwindInfoChecker/UnwindInfoAnalysis.h
index 438f9c10c581a..18d6f9c887b9a 100644
--- a/llvm/include/llvm/UnwindInfoChecker/UnwindInfoAnalysis.h
+++ b/llvm/include/llvm/UnwindInfoChecker/UnwindInfoAnalysis.h
@@ -1,3 +1,15 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// This file declares UnwindInfoAnalysis class.
+///
+//===----------------------------------------------------------------------===//
+
#ifndef LLVM_UNWINDINFOCHECKER_UNWINDINFOANALYSIS_H
#define LLVM_UNWINDINFOCHECKER_UNWINDINFOANALYSIS_H
diff --git a/llvm/include/llvm/UnwindInfoChecker/UnwindInfoHistory.h b/llvm/include/llvm/UnwindInfoChecker/UnwindInfoHistory.h
index 3df26df5ca424..8b454aa0ac539 100644
--- a/llvm/include/llvm/UnwindInfoChecker/UnwindInfoHistory.h
+++ b/llvm/include/llvm/UnwindInfoChecker/UnwindInfoHistory.h
@@ -1,3 +1,15 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// This file declares UnwindInfoHistory class.
+///
+//===----------------------------------------------------------------------===//
+
#ifndef LLVM_UNWINDINFOCHECKER_UNWINDINFOHISTORY_H
#define LLVM_UNWINDINFOCHECKER_UNWINDINFOHISTORY_H
diff --git a/llvm/lib/UnwindInfoChecker/FunctionUnitAnalyzer.cpp b/llvm/lib/UnwindInfoChecker/FunctionUnitAnalyzer.cpp
index 5b269db4ae141..7f6a06850bd7f 100644
--- a/llvm/lib/UnwindInfoChecker/FunctionUnitAnalyzer.cpp
+++ b/llvm/lib/UnwindInfoChecker/FunctionUnitAnalyzer.cpp
@@ -1,3 +1,11 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
#include "llvm/UnwindInfoChecker/FunctionUnitAnalyzer.h"
using namespace llvm;
diff --git a/llvm/lib/UnwindInfoChecker/FunctionUnitStreamer.cpp b/llvm/lib/UnwindInfoChecker/FunctionUnitStreamer.cpp
index 74b7eec12acf0..c58339a0d978d 100644
--- a/llvm/lib/UnwindInfoChecker/FunctionUnitStreamer.cpp
+++ b/llvm/lib/UnwindInfoChecker/FunctionUnitStreamer.cpp
@@ -1,3 +1,10 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
#include "llvm/UnwindInfoChecker/FunctionUnitStreamer.h"
#include "llvm/ADT/ArrayRef.h"
diff --git a/llvm/lib/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.cpp b/llvm/lib/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.cpp
index d37509298c9b6..808d0658d3f9c 100644
--- a/llvm/lib/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.cpp
+++ b/llvm/lib/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.cpp
@@ -1,3 +1,11 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
#include "llvm/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.h"
using namespace llvm;
diff --git a/llvm/lib/UnwindInfoChecker/UnwindInfoAnalysis.cpp b/llvm/lib/UnwindInfoChecker/UnwindInfoAnalysis.cpp
index afb6af1be17a0..c5093dd3aa771 100644
--- a/llvm/lib/UnwindInfoChecker/UnwindInfoAnalysis.cpp
+++ b/llvm/lib/UnwindInfoChecker/UnwindInfoAnalysis.cpp
@@ -1,3 +1,11 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
#include "llvm/UnwindInfoChecker/UnwindInfoAnalysis.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
diff --git a/llvm/lib/UnwindInfoChecker/UnwindInfoHistory.cpp b/llvm/lib/UnwindInfoChecker/UnwindInfoHistory.cpp
index 9ee0be1770e99..77ed6122c3dfd 100644
--- a/llvm/lib/UnwindInfoChecker/UnwindInfoHistory.cpp
+++ b/llvm/lib/UnwindInfoChecker/UnwindInfoHistory.cpp
@@ -1,4 +1,11 @@
-// TODO check what includes to keep and what to remove
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
#include "llvm/UnwindInfoChecker/UnwindInfoHistory.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
>From 37858ef3dd1f132387037b9e431e20c1b1020d3f Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Tue, 24 Jun 2025 22:24:37 +0000
Subject: [PATCH 48/58] Resolve warnings
---
llvm/lib/UnwindInfoChecker/UnwindInfoAnalysis.cpp | 9 ---------
1 file changed, 9 deletions(-)
diff --git a/llvm/lib/UnwindInfoChecker/UnwindInfoAnalysis.cpp b/llvm/lib/UnwindInfoChecker/UnwindInfoAnalysis.cpp
index c5093dd3aa771..78a29e0d2dd79 100644
--- a/llvm/lib/UnwindInfoChecker/UnwindInfoAnalysis.cpp
+++ b/llvm/lib/UnwindInfoChecker/UnwindInfoAnalysis.cpp
@@ -9,7 +9,6 @@
#include "llvm/UnwindInfoChecker/UnwindInfoAnalysis.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Twine.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
#include "llvm/MC/MCAsmInfo.h"
@@ -23,9 +22,7 @@
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/TargetRegistry.h"
-#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/Format.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/UnwindInfoChecker/UnwindInfoHistory.h"
#include <cstdint>
@@ -77,12 +74,6 @@ static std::optional<DWARFRegType> getReferenceRegisterForUnwindInfoOfRegister(
}
}
-// TODO remove it, it's just for debug purposes.
-void printUntilNextLine(const char *Str) {
- for (int I = 0; Str[I] != '\0' && Str[I] != '\n'; I++)
- dbgs() << Str[I];
-}
-
bool UnwindInfoAnalysis::isSuperReg(MCPhysReg Reg) {
return MCRI->superregs(Reg).empty();
}
>From b8cdef68539eb378bedbbb30d1955a0f5f87f9e4 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Wed, 25 Jun 2025 03:46:34 +0000
Subject: [PATCH 49/58] Refactor UnwindInfoAnalysis
---
.../UnwindInfoChecker/FunctionUnitAnalyzer.h | 1 +
.../UnwindInfoChecker/FunctionUnitStreamer.h | 1 +
.../FunctionUnitUnwindInfoAnalyzer.h | 1 +
.../UnwindInfoChecker/UnwindInfoAnalysis.h | 30 +-
.../UnwindInfoChecker/UnwindInfoHistory.h | 9 +-
llvm/lib/UnwindInfoChecker/Registers.h | 68 ++++
.../UnwindInfoChecker/UnwindInfoAnalysis.cpp | 321 ++++++++----------
.../UnwindInfoChecker/UnwindInfoHistory.cpp | 6 +-
8 files changed, 223 insertions(+), 214 deletions(-)
create mode 100644 llvm/lib/UnwindInfoChecker/Registers.h
diff --git a/llvm/include/llvm/UnwindInfoChecker/FunctionUnitAnalyzer.h b/llvm/include/llvm/UnwindInfoChecker/FunctionUnitAnalyzer.h
index 2df320babcd38..e7791e1b59f14 100644
--- a/llvm/include/llvm/UnwindInfoChecker/FunctionUnitAnalyzer.h
+++ b/llvm/include/llvm/UnwindInfoChecker/FunctionUnitAnalyzer.h
@@ -6,6 +6,7 @@
//
//===----------------------------------------------------------------------===//
///
+/// \file
/// This file declares FunctionUnitAnalyzer class.
///
//===----------------------------------------------------------------------===//
diff --git a/llvm/include/llvm/UnwindInfoChecker/FunctionUnitStreamer.h b/llvm/include/llvm/UnwindInfoChecker/FunctionUnitStreamer.h
index 517f82a4bb588..f161c22fa9880 100644
--- a/llvm/include/llvm/UnwindInfoChecker/FunctionUnitStreamer.h
+++ b/llvm/include/llvm/UnwindInfoChecker/FunctionUnitStreamer.h
@@ -6,6 +6,7 @@
//
//===----------------------------------------------------------------------===//
///
+/// \file
/// This file declares FunctionUnitStreamer class.
///
//===----------------------------------------------------------------------===//
diff --git a/llvm/include/llvm/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.h b/llvm/include/llvm/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.h
index 4e9b27d8da0ca..b5cff539e8e08 100644
--- a/llvm/include/llvm/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.h
+++ b/llvm/include/llvm/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.h
@@ -6,6 +6,7 @@
//
//===----------------------------------------------------------------------===//
///
+/// \file
/// This file declares FunctionUnitUnwindInfoAnalyzer class.
///
//===----------------------------------------------------------------------===//
diff --git a/llvm/include/llvm/UnwindInfoChecker/UnwindInfoAnalysis.h b/llvm/include/llvm/UnwindInfoChecker/UnwindInfoAnalysis.h
index 18d6f9c887b9a..7b60745fea826 100644
--- a/llvm/include/llvm/UnwindInfoChecker/UnwindInfoAnalysis.h
+++ b/llvm/include/llvm/UnwindInfoChecker/UnwindInfoAnalysis.h
@@ -6,6 +6,7 @@
//
//===----------------------------------------------------------------------===//
///
+/// \file
/// This file declares UnwindInfoAnalysis class.
///
//===----------------------------------------------------------------------===//
@@ -22,7 +23,6 @@
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstrInfo.h"
-#include "llvm/MC/MCRegister.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
@@ -35,41 +35,27 @@ class UnwindInfoAnalysis {
MCContext *Context;
MCInstrInfo const &MCII;
MCRegisterInfo const *MCRI;
- UnwindInfoHistory State;
+ UnwindInfoState State;
bool IsEH;
-private:
- // The CFI analysis only keeps track and cares about super registers, not the
- // subregisters. All reads to/writes from subregisters and considered the same
- // operation to super registers.
- // TODO Other operations like loading and stores are considered only if they
- // TODO are exactly doing the operation to or from a super register. As an
- // TODO example, if you spill a sub register to stack, the CFI analysis does
- // TODO not consider that a register spilling.
- bool isSuperReg(MCPhysReg Reg);
-
- SmallVector<std::pair<MCPhysReg, MCRegisterClass const *>> getAllSuperRegs();
-
- MCPhysReg getSuperReg(MCPhysReg Reg);
-
public:
UnwindInfoAnalysis(MCContext *Context, MCInstrInfo const &MCII, bool IsEH,
- ArrayRef<MCCFIInstruction> PrologueCFIDirectives);
+ ArrayRef<MCCFIInstruction> Prologue);
void update(const MCInst &Inst, ArrayRef<MCCFIInstruction> CFIDirectives);
private:
- void checkRegDiff(const MCInst &Inst, DWARFRegType Reg,
+ void checkRegDiff(const MCInst &Inst, DWARFRegNum Reg,
const dwarf::UnwindTable::const_iterator &PrevRow,
const dwarf::UnwindTable::const_iterator &NextRow,
- const std::set<DWARFRegType> &Reads,
- const std::set<DWARFRegType> &Writes);
+ const std::set<DWARFRegNum> &Reads,
+ const std::set<DWARFRegNum> &Writes);
void checkCFADiff(const MCInst &Inst,
const dwarf::UnwindTable::const_iterator &PrevRow,
const dwarf::UnwindTable::const_iterator &NextRow,
- const std::set<DWARFRegType> &Reads,
- const std::set<DWARFRegType> &Writes);
+ const std::set<DWARFRegNum> &Reads,
+ const std::set<DWARFRegNum> &Writes);
};
} // namespace llvm
diff --git a/llvm/include/llvm/UnwindInfoChecker/UnwindInfoHistory.h b/llvm/include/llvm/UnwindInfoChecker/UnwindInfoHistory.h
index 8b454aa0ac539..8bad58ca31428 100644
--- a/llvm/include/llvm/UnwindInfoChecker/UnwindInfoHistory.h
+++ b/llvm/include/llvm/UnwindInfoChecker/UnwindInfoHistory.h
@@ -6,7 +6,8 @@
//
//===----------------------------------------------------------------------===//
///
-/// This file declares UnwindInfoHistory class.
+/// \file
+/// This file declares UnwindInfoState class.
///
//===----------------------------------------------------------------------===//
@@ -20,11 +21,11 @@
#include <optional>
namespace llvm {
-using DWARFRegType = uint32_t;
+using DWARFRegNum = uint32_t;
-class UnwindInfoHistory {
+class UnwindInfoState {
public:
- UnwindInfoHistory(MCContext *Context) : Context(Context) {};
+ UnwindInfoState(MCContext *Context) : Context(Context) {};
std::optional<dwarf::UnwindTable::const_iterator> getCurrentUnwindRow() const;
void update(const MCCFIInstruction &CFIDirective);
diff --git a/llvm/lib/UnwindInfoChecker/Registers.h b/llvm/lib/UnwindInfoChecker/Registers.h
new file mode 100644
index 0000000000000..f661ae0d211fc
--- /dev/null
+++ b/llvm/lib/UnwindInfoChecker/Registers.h
@@ -0,0 +1,68 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains helper functions to find and list registers that are
+/// tracked by the unwinding information checker.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_UNWINDINFOCHECKER_REGISTERS_H
+#define LLVM_UNWINDINFOCHECKER_REGISTERS_H
+
+#include "llvm/MC/MCRegister.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include <iterator>
+
+namespace llvm {
+
+/// This analysis only keeps track and cares about super registers, not the
+/// subregisters. All reads from/writes to subregisters are considered the
+/// same operation to super registers.
+inline bool isSuperReg(const MCRegisterInfo *MCRI, MCPhysReg Reg) {
+ return MCRI->superregs(Reg).empty();
+}
+
+inline SmallVector<MCPhysReg> getSuperRegs(const MCRegisterInfo *MCRI) {
+ SmallVector<MCPhysReg> SuperRegs;
+ for (auto &&RegClass : MCRI->regclasses()) {
+ for (unsigned I = 0; I < RegClass.getNumRegs(); I++) {
+ MCPhysReg Reg = RegClass.getRegister(I);
+ if (isSuperReg(MCRI, Reg))
+ SuperRegs.push_back(Reg);
+ }
+ }
+
+ std::sort(SuperRegs.begin(), SuperRegs.end());
+ SuperRegs.resize(std::distance(
+ SuperRegs.begin(), std::unique(SuperRegs.begin(), SuperRegs.end())));
+ return SuperRegs;
+}
+
+inline SmallVector<MCPhysReg> getTrackingRegs(const MCRegisterInfo *MCRI) {
+ SmallVector<MCPhysReg> TrackingRegs;
+ for (auto Reg : getSuperRegs(MCRI))
+ if (!MCRI->isArtificial(Reg) && !MCRI->isConstant(Reg))
+ TrackingRegs.push_back(Reg);
+ return TrackingRegs;
+}
+
+inline MCPhysReg getSuperReg(const MCRegisterInfo *MCRI, MCPhysReg Reg) {
+ if (isSuperReg(MCRI, Reg))
+ return Reg;
+ for (auto SuperReg : MCRI->superregs(Reg)) {
+ if (isSuperReg(MCRI, SuperReg))
+ return SuperReg;
+ }
+
+ llvm_unreachable("Should either be a super reg, or have a super reg");
+}
+
+} // namespace llvm
+
+#endif
\ No newline at end of file
diff --git a/llvm/lib/UnwindInfoChecker/UnwindInfoAnalysis.cpp b/llvm/lib/UnwindInfoChecker/UnwindInfoAnalysis.cpp
index 78a29e0d2dd79..99952a6db3f4c 100644
--- a/llvm/lib/UnwindInfoChecker/UnwindInfoAnalysis.cpp
+++ b/llvm/lib/UnwindInfoChecker/UnwindInfoAnalysis.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/UnwindInfoChecker/UnwindInfoAnalysis.h"
+#include "Registers.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Twine.h"
@@ -32,10 +33,10 @@
using namespace llvm;
struct CFARegOffsetInfo {
- DWARFRegType Reg;
+ DWARFRegNum Reg;
int64_t Offset;
- CFARegOffsetInfo(DWARFRegType Reg, int64_t Offset)
+ CFARegOffsetInfo(DWARFRegNum Reg, int64_t Offset)
: Reg(Reg), Offset(Offset) {}
};
@@ -50,13 +51,15 @@ getCFARegOffsetInfo(const dwarf::UnwindTable::const_iterator &UnwindRow) {
return CFARegOffsetInfo(CFALocation.getRegister(), CFALocation.getOffset());
}
-static std::optional<DWARFRegType> getReferenceRegisterForUnwindInfoOfRegister(
- const dwarf::UnwindTable::const_iterator &UnwindRow, DWARFRegType Reg) {
- auto UnwinLoc = UnwindRow->getRegisterLocations().getRegisterLocation(Reg);
- assert(UnwinLoc &&
+static std::optional<DWARFRegNum>
+getUnwindRuleRefReg(const dwarf::UnwindTable::const_iterator &UnwindRow,
+ DWARFRegNum Reg) {
+ auto MaybeLoc = UnwindRow->getRegisterLocations().getRegisterLocation(Reg);
+ assert(MaybeLoc &&
"The register should be tracked inside the register states");
+ auto Loc = *MaybeLoc;
- switch (UnwinLoc->getLocation()) {
+ switch (Loc.getLocation()) {
case dwarf::UnwindLocation::Location::Undefined:
case dwarf::UnwindLocation::Location::Constant:
case dwarf::UnwindLocation::Location::Unspecified:
@@ -66,65 +69,34 @@ static std::optional<DWARFRegType> getReferenceRegisterForUnwindInfoOfRegister(
case dwarf::UnwindLocation::Location::Same:
return Reg;
case dwarf::UnwindLocation::Location::RegPlusOffset:
- return UnwinLoc->getRegister();
+ return Loc.getRegister();
case dwarf::UnwindLocation::Location::CFAPlusOffset:
- // TODO check if it's ok to assume CFA is always depending on other
- // TODO register, if yes assert it here!
- return UnwindRow->getCFAValue().getRegister();
- }
-}
-
-bool UnwindInfoAnalysis::isSuperReg(MCPhysReg Reg) {
- return MCRI->superregs(Reg).empty();
-}
-
-SmallVector<std::pair<MCPhysReg, MCRegisterClass const *>>
-UnwindInfoAnalysis::getAllSuperRegs() {
- std::map<MCPhysReg, MCRegisterClass const *> SuperRegs;
- for (auto &&RegClass : MCRI->regclasses()) {
- for (unsigned I = 0; I < RegClass.getNumRegs(); I++) {
- MCPhysReg Reg = RegClass.getRegister(I);
- if (!isSuperReg(Reg) || MCRI->isArtificial(Reg) || MCRI->isConstant(Reg))
- continue;
- SuperRegs[Reg] = &RegClass;
- }
- }
-
- SmallVector<std::pair<MCPhysReg, MCRegisterClass const *>> SuperRegWithClass;
- for (auto &&[Reg, RegClass] : SuperRegs)
- SuperRegWithClass.emplace_back(Reg, RegClass);
- return SuperRegWithClass;
-}
-
-MCPhysReg UnwindInfoAnalysis::getSuperReg(MCPhysReg Reg) {
- if (isSuperReg(Reg))
- return Reg;
- for (auto SuperReg : MCRI->superregs(Reg)) {
- if (isSuperReg(SuperReg))
- return SuperReg;
+ auto MaybeCFA = getCFARegOffsetInfo(UnwindRow);
+ if (MaybeCFA)
+ return MaybeCFA->Reg;
+ return std::nullopt;
}
-
- llvm_unreachable("Should either be a super reg, or have a super reg");
}
-UnwindInfoAnalysis::UnwindInfoAnalysis(
- MCContext *Context, MCInstrInfo const &MCII, bool IsEH,
- ArrayRef<MCCFIInstruction> PrologueCFIDirectives)
+UnwindInfoAnalysis::UnwindInfoAnalysis(MCContext *Context,
+ MCInstrInfo const &MCII, bool IsEH,
+ ArrayRef<MCCFIInstruction> Prologue)
: Context(Context), MCII(MCII), MCRI(Context->getRegisterInfo()),
State(Context), IsEH(IsEH) {
- // TODO These all should be handled by setting .cfi_same_value for only callee
- // TODO saved registers inside `getInitialFrameState`. Instead now what's
- // TODO happening is that the analysis .cfi_same_value all the registers and
- // TODO remove PC (undefined), and RSP (CFA) from them.
- for (auto &&[Reg, RegClass] : getAllSuperRegs()) {
- if (MCRI->get(Reg).IsArtificial || MCRI->get(Reg).IsConstant)
+ for (auto LLVMReg : getTrackingRegs(MCRI)) {
+ if (MCRI->get(LLVMReg).IsArtificial || MCRI->get(LLVMReg).IsConstant)
continue;
- DWARFRegType DwarfReg = MCRI->getDwarfRegNum(Reg, IsEH);
- State.update(MCCFIInstruction::createSameValue(nullptr, DwarfReg));
+ DWARFRegNum Reg = MCRI->getDwarfRegNum(LLVMReg, IsEH);
+ // TODO this should be `undefined` instead of `same_value`, but because
+ // initial frame state doesn't have any directives about callee saved
+ // registers, every register is tracked. After initial frame state is
+ // corrected, this should be changed.
+ State.update(MCCFIInstruction::createSameValue(nullptr, Reg));
}
+ // TODO Ignoring PC should be in initial frame state.
State.update(MCCFIInstruction::createUndefined(
nullptr, MCRI->getDwarfRegNum(MCRI->getProgramCounter(), IsEH)));
@@ -133,21 +105,20 @@ UnwindInfoAnalysis::UnwindInfoAnalysis(
State.update(InitialFrameStateCFIDirective);
}
- auto MaybeLastRow = State.getCurrentUnwindRow();
- assert(MaybeLastRow && "there should be at least one row");
- auto LastRow = *MaybeLastRow;
-
- auto MaybeCFA = getCFARegOffsetInfo(LastRow);
+ auto MaybeCurrentRow = State.getCurrentUnwindRow();
+ assert(MaybeCurrentRow && "there should be at least one row");
+ auto MaybeCFA = getCFARegOffsetInfo(*MaybeCurrentRow);
assert(MaybeCFA &&
"the CFA information should be describable in [Reg + Offset] in here");
auto CFA = *MaybeCFA;
- State.update(MCCFIInstruction::createOffset(nullptr, CFA.Reg,
- 0)); // sp's old value is CFA
+ // TODO CFA register callee value is CFA's value, this should be in initial
+ // frame state.
+ State.update(MCCFIInstruction::createOffset(nullptr, CFA.Reg, 0));
// Applying the prologue after default assumptions to overwrite them.
- for (auto &&PrologueCFIDirective : PrologueCFIDirectives) {
- State.update(PrologueCFIDirective);
+ for (auto &&Directive : Prologue) {
+ State.update(Directive);
}
}
@@ -155,145 +126,133 @@ void UnwindInfoAnalysis::update(const MCInst &Inst,
ArrayRef<MCCFIInstruction> CFIDirectives) {
const MCInstrDesc &MCInstInfo = MCII.get(Inst.getOpcode());
- auto MaybePrevUnwindRow = State.getCurrentUnwindRow();
- assert(MaybePrevUnwindRow && "The analysis should have initialized the "
- "history with at least one row by now");
- auto PrevUnwindRow = MaybePrevUnwindRow.value();
+ auto MaybePrevRow = State.getCurrentUnwindRow();
+ assert(MaybePrevRow && "The analysis should have initialized the "
+ "history with at least one row by now");
+ auto PrevRow = MaybePrevRow.value();
- for (auto &&CFIDirective : CFIDirectives)
- State.update(CFIDirective);
+ for (auto &&Directive : CFIDirectives)
+ State.update(Directive);
- std::set<DWARFRegType> Writes, Reads;
+ std::set<DWARFRegNum> Writes, Reads;
for (unsigned I = 0; I < MCInstInfo.NumImplicitUses; I++)
- Reads.insert(
- MCRI->getDwarfRegNum(getSuperReg(MCInstInfo.implicit_uses()[I]), IsEH));
+ Reads.insert(MCRI->getDwarfRegNum(
+ getSuperReg(MCRI, MCInstInfo.implicit_uses()[I]), IsEH));
for (unsigned I = 0; I < MCInstInfo.NumImplicitDefs; I++)
- Writes.insert(
- MCRI->getDwarfRegNum(getSuperReg(MCInstInfo.implicit_defs()[I]), IsEH));
+ Writes.insert(MCRI->getDwarfRegNum(
+ getSuperReg(MCRI, MCInstInfo.implicit_defs()[I]), IsEH));
for (unsigned I = 0; I < Inst.getNumOperands(); I++) {
- auto &&Operand = Inst.getOperand(I);
- if (Operand.isReg()) {
+ auto &&Op = Inst.getOperand(I);
+ if (Op.isReg()) {
if (I < MCInstInfo.getNumDefs())
Writes.insert(
- MCRI->getDwarfRegNum(getSuperReg(Operand.getReg()), IsEH));
- else if (Operand.getReg())
- Reads.insert(MCRI->getDwarfRegNum(getSuperReg(Operand.getReg()), IsEH));
+ MCRI->getDwarfRegNum(getSuperReg(MCRI, Op.getReg()), IsEH));
+ else if (Op.getReg())
+ Reads.insert(
+ MCRI->getDwarfRegNum(getSuperReg(MCRI, Op.getReg()), IsEH));
}
}
- auto MaybeCurrentUnwindRow = State.getCurrentUnwindRow();
- assert(MaybeCurrentUnwindRow &&
- "Prev row existed, so should the current row.");
- auto CurrentUnwindRow = *MaybeCurrentUnwindRow;
+ auto MaybeNextRow = State.getCurrentUnwindRow();
+ assert(MaybeNextRow && "Prev row existed, so should the current row.");
+ auto NextRow = *MaybeNextRow;
- checkCFADiff(Inst, PrevUnwindRow, CurrentUnwindRow, Reads, Writes);
+ checkCFADiff(Inst, PrevRow, NextRow, Reads, Writes);
- for (auto [LLVMReg, _] : getAllSuperRegs()) {
- DWARFRegType Reg = MCRI->getDwarfRegNum(LLVMReg, IsEH);
+ for (auto LLVMReg : getTrackingRegs(MCRI)) {
+ DWARFRegNum Reg = MCRI->getDwarfRegNum(LLVMReg, IsEH);
- checkRegDiff(Inst, Reg, PrevUnwindRow, CurrentUnwindRow, Reads, Writes);
+ checkRegDiff(Inst, Reg, PrevRow, NextRow, Reads, Writes);
}
}
void UnwindInfoAnalysis::checkRegDiff(
- const MCInst &Inst, DWARFRegType Reg,
+ const MCInst &Inst, DWARFRegNum Reg,
const dwarf::UnwindTable::const_iterator &PrevRow,
const dwarf::UnwindTable::const_iterator &NextRow,
- const std::set<DWARFRegType> &Reads, const std::set<DWARFRegType> &Writes) {
- auto MaybePrevUnwindLoc =
- PrevRow->getRegisterLocations().getRegisterLocation(Reg);
- auto MaybeNextUnwindLoc =
- NextRow->getRegisterLocations().getRegisterLocation(Reg);
-
- if (!MaybePrevUnwindLoc) {
- assert(!MaybeNextUnwindLoc && "The register unwind info suddenly "
- "appeared here, ignoring this change");
+ const std::set<DWARFRegNum> &Reads, const std::set<DWARFRegNum> &Writes) {
+ auto MaybePrevLoc = PrevRow->getRegisterLocations().getRegisterLocation(Reg);
+ auto MaybeNextLoc = NextRow->getRegisterLocations().getRegisterLocation(Reg);
+
+ if (!MaybePrevLoc) {
+ assert(!MaybeNextLoc && "The register unwind info suddenly "
+ "appeared here, ignoring this change");
return;
}
- assert(MaybeNextUnwindLoc && "The register unwind info suddenly vanished "
- "here, ignoring this change");
+ assert(MaybeNextLoc && "The register unwind info suddenly vanished "
+ "here, ignoring this change");
- auto PrevRegLoc = MaybePrevUnwindLoc.value();
- auto NextRegLoc = MaybeNextUnwindLoc.value();
+ auto PrevLoc = MaybePrevLoc.value();
+ auto NextLoc = MaybeNextLoc.value();
- auto MaybeRegLLVM = MCRI->getLLVMRegNum(Reg, IsEH);
- if (!MaybeRegLLVM) {
- assert(PrevRegLoc == NextRegLoc &&
+ auto MaybeLLVMReg = MCRI->getLLVMRegNum(Reg, IsEH);
+ if (!MaybeLLVMReg) {
+ assert(PrevLoc == NextLoc &&
"The dwarf register does not have a LLVM number, so the unwind info "
"for it should not change");
return;
}
+ const char *RegName = MCRI->getName(*MaybeLLVMReg);
- const char *RegLLVMName = MCRI->getName(MaybeRegLLVM.value());
-
- auto &&MaybePrevRefReg =
- getReferenceRegisterForUnwindInfoOfRegister(PrevRow, Reg);
-
- std::optional<MCPhysReg> PrevRefRegLLVM =
- (MaybePrevRefReg ? MCRI->getLLVMRegNum(MaybePrevRefReg.value(), IsEH)
- : std::nullopt);
- std::optional<MCPhysReg> NextRefRegLLVM =
+ auto &&MaybePrevRefReg = getUnwindRuleRefReg(PrevRow, Reg);
+ std::optional<MCPhysReg> PrevRefLLVMReg =
(MaybePrevRefReg ? MCRI->getLLVMRegNum(MaybePrevRefReg.value(), IsEH)
: std::nullopt);
- if (PrevRegLoc == NextRegLoc) {
- switch (PrevRegLoc.getLocation()) {
- case dwarf::UnwindLocation::Same:
- case dwarf::UnwindLocation::RegPlusOffset:
- if (Writes.count(MaybePrevRefReg.value())) {
- Context->reportError(
- Inst.getLoc(),
- formatv("This instruction changes %{1}, that %{0} unwinding rule "
- "uses, but there is no CFI directives about it",
- RegLLVMName, MCRI->getName(PrevRefRegLLVM.value())));
- return;
- }
- break;
- // TODO think about what to do with expressions here.
- // TODO the expressions be solved more precise, by looking into the
- // TODO expression, finding registers that are used and checking if the
- // TODO instruction is changing them or not.
- default:
- // Everything may be ok
- break;
+ if (!(PrevLoc == NextLoc)) {
+ if (PrevLoc.getLocation() == NextLoc.getLocation()) {
+ Context->reportWarning(
+ Inst.getLoc(),
+ formatv("unknown change happened to %{0} unwinding rule values",
+ RegName));
+ //! FIXME Check if the register is changed or not
+ return;
}
- return;
- }
-
- if (PrevRegLoc.getLocation() == NextRegLoc.getLocation()) {
- // Everything may be ok
- return;
- }
- if (PrevRegLoc.getLocation() == dwarf::UnwindLocation::Undefined) {
- Context->reportError(
+ Context->reportWarning(
Inst.getLoc(),
- "Changed %{0} unwinding rule from `undefined` to something else");
+ formatv("unknown change happened to %{0} unwinding rule structure",
+ RegName));
return;
}
- Context->reportWarning(
- Inst.getLoc(),
- formatv("Unknown change happened to %{0} unwinding rule", RegLLVMName));
- // Everything may be ok
- return;
+ switch (PrevLoc.getLocation()) {
+ case dwarf::UnwindLocation::Same:
+ case dwarf::UnwindLocation::RegPlusOffset:
+ if (Writes.count(MaybePrevRefReg.value())) {
+ Context->reportError(
+ Inst.getLoc(),
+ formatv("changed %{1}, that %{0} unwinding rule "
+ "uses, but there is no CFI directives about it",
+ RegName, MCRI->getName(*PrevRefLLVMReg)));
+ return;
+ }
+ break;
+ case dwarf::UnwindLocation::DWARFExpr:
+ // TODO Expressions are not supported yet, but if wanted to be supported,
+ // all the registers used in an expression should extracted and checked if
+ // the instruction modifies them or not.
+ default:
+ // Everything may be ok
+ break;
+ }
}
void UnwindInfoAnalysis::checkCFADiff(
const MCInst &Inst, const dwarf::UnwindTable::const_iterator &PrevRow,
const dwarf::UnwindTable::const_iterator &NextRow,
- const std::set<DWARFRegType> &Reads, const std::set<DWARFRegType> &Writes) {
+ const std::set<DWARFRegNum> &Reads, const std::set<DWARFRegNum> &Writes) {
auto MaybePrevCFA = getCFARegOffsetInfo(PrevRow);
auto MaybeNextCFA = getCFARegOffsetInfo(NextRow);
if (!MaybePrevCFA) {
if (MaybeNextCFA) {
- Context->reportWarning(
- Inst.getLoc(),
- "CFA rule changed to [reg + offset], not checking the change");
+ Context->reportWarning(Inst.getLoc(),
+ "CFA rule changed to [reg + offset], this "
+ "transition will not be checked");
return;
}
@@ -303,46 +262,38 @@ void UnwindInfoAnalysis::checkCFADiff(
}
if (!MaybeNextCFA) {
- Context->reportWarning(
- Inst.getLoc(),
- "CFA rule changed from [reg + offset], not checking the change");
+ Context->reportWarning(Inst.getLoc(),
+ "CFA rule changed from [reg + offset], this "
+ "transition will not be checked");
return;
}
auto PrevCFA = *MaybePrevCFA;
auto NextCFA = *MaybeNextCFA;
- const char *PrevCFARegName =
- MCRI->getName(MCRI->getLLVMRegNum(PrevCFA.Reg, IsEH).value());
-
- if (PrevCFA.Reg == NextCFA.Reg) {
- if (PrevCFA.Offset == NextCFA.Offset) {
- if (Writes.count(PrevCFA.Reg)) {
- Context->reportError(
- Inst.getLoc(),
- formatv("This instruction modifies CFA register (%{0}) "
- "but CFA rule is not changed",
- PrevCFARegName));
- return;
- }
-
- // Everything is ok!
- return;
- }
+ auto MaybeLLVMReg = MCRI->getLLVMRegNum(PrevCFA.Reg, IsEH);
+ const char *PrevCFARegName = MaybeLLVMReg ? MCRI->getName(*MaybeLLVMReg) : "";
- // The offset is changed.
- if (!Writes.count(PrevCFA.Reg)) {
- Context->reportError(
- Inst.getLoc(),
- formatv("This instruction does not modifies CFA register (%{0}) "
- "but CFA rule is changed",
- PrevCFARegName));
- }
-
- // The CFA register value is changed, and the offset is changed as well,
- // everything may be ok.
+ if (PrevCFA.Reg != NextCFA.Reg) {
+ //! FIXME warn here
return;
}
- // The CFA register is changed, everything may be ok.
+ if (PrevCFA.Offset == NextCFA.Offset) {
+ if (!Writes.count(PrevCFA.Reg))
+ return;
+ Context->reportError(
+ Inst.getLoc(),
+ formatv("modified CFA register (%{0}) but not changed CFA rule",
+ PrevCFARegName));
+ }
+
+ // The offset is changed.
+ if (Writes.count(PrevCFA.Reg))
+ return;
+
+ Context->reportError(
+ Inst.getLoc(),
+ formatv("did not modify CFA register (%{0}) but changed CFA rule",
+ PrevCFARegName));
}
diff --git a/llvm/lib/UnwindInfoChecker/UnwindInfoHistory.cpp b/llvm/lib/UnwindInfoChecker/UnwindInfoHistory.cpp
index 77ed6122c3dfd..19bb5f9f175a3 100644
--- a/llvm/lib/UnwindInfoChecker/UnwindInfoHistory.cpp
+++ b/llvm/lib/UnwindInfoChecker/UnwindInfoHistory.cpp
@@ -19,14 +19,14 @@
using namespace llvm;
std::optional<dwarf::UnwindTable::const_iterator>
-UnwindInfoHistory::getCurrentUnwindRow() const {
+UnwindInfoState::getCurrentUnwindRow() const {
if (!Table.size())
return std::nullopt;
return --Table.end();
}
-void UnwindInfoHistory::update(const MCCFIInstruction &CFIDirective) {
+void UnwindInfoState::update(const MCCFIInstruction &CFIDirective) {
auto DwarfOperations = convert(CFIDirective);
if (!DwarfOperations) {
Context->reportError(
@@ -50,7 +50,7 @@ void UnwindInfoHistory::update(const MCCFIInstruction &CFIDirective) {
}
std::optional<dwarf::CFIProgram>
-UnwindInfoHistory::convert(MCCFIInstruction CFIDirective) {
+UnwindInfoState::convert(MCCFIInstruction CFIDirective) {
//! FIXME, this way of instantiating CFI program does not look right, either
//! refactor CFIProgram to not depend on the Code/Data Alignment or add a new
//! type that is independent from this and is also feedable to UnwindTable.
>From c1538d37b692af846446f19e680a91e5089eff96 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Wed, 25 Jun 2025 03:47:04 +0000
Subject: [PATCH 50/58] Move tests to UnwindInfoChecker folder
---
.../cfi-validation => UnwindInfoChecker/X86}/empty-section.s | 0
.../cfi-validation => UnwindInfoChecker/X86}/multiple-sections.s | 0
.../X86}/single-func-cfa-mistake.s | 0
.../X86}/single-func-missed-cfi-directive.s | 0
.../cfi-validation => UnwindInfoChecker/X86}/single-func.s | 0
.../X86}/spill-two-reg-reversed.s | 0
.../cfi-validation => UnwindInfoChecker/X86}/spill-two-reg.s | 0
.../cfi-validation => UnwindInfoChecker/X86}/update-with-no-cfi.s | 0
8 files changed, 0 insertions(+), 0 deletions(-)
rename llvm/test/{tools/llvm-mc/cfi-validation => UnwindInfoChecker/X86}/empty-section.s (100%)
rename llvm/test/{tools/llvm-mc/cfi-validation => UnwindInfoChecker/X86}/multiple-sections.s (100%)
rename llvm/test/{tools/llvm-mc/cfi-validation => UnwindInfoChecker/X86}/single-func-cfa-mistake.s (100%)
rename llvm/test/{tools/llvm-mc/cfi-validation => UnwindInfoChecker/X86}/single-func-missed-cfi-directive.s (100%)
rename llvm/test/{tools/llvm-mc/cfi-validation => UnwindInfoChecker/X86}/single-func.s (100%)
rename llvm/test/{tools/llvm-mc/cfi-validation => UnwindInfoChecker/X86}/spill-two-reg-reversed.s (100%)
rename llvm/test/{tools/llvm-mc/cfi-validation => UnwindInfoChecker/X86}/spill-two-reg.s (100%)
rename llvm/test/{tools/llvm-mc/cfi-validation => UnwindInfoChecker/X86}/update-with-no-cfi.s (100%)
diff --git a/llvm/test/tools/llvm-mc/cfi-validation/empty-section.s b/llvm/test/UnwindInfoChecker/X86/empty-section.s
similarity index 100%
rename from llvm/test/tools/llvm-mc/cfi-validation/empty-section.s
rename to llvm/test/UnwindInfoChecker/X86/empty-section.s
diff --git a/llvm/test/tools/llvm-mc/cfi-validation/multiple-sections.s b/llvm/test/UnwindInfoChecker/X86/multiple-sections.s
similarity index 100%
rename from llvm/test/tools/llvm-mc/cfi-validation/multiple-sections.s
rename to llvm/test/UnwindInfoChecker/X86/multiple-sections.s
diff --git a/llvm/test/tools/llvm-mc/cfi-validation/single-func-cfa-mistake.s b/llvm/test/UnwindInfoChecker/X86/single-func-cfa-mistake.s
similarity index 100%
rename from llvm/test/tools/llvm-mc/cfi-validation/single-func-cfa-mistake.s
rename to llvm/test/UnwindInfoChecker/X86/single-func-cfa-mistake.s
diff --git a/llvm/test/tools/llvm-mc/cfi-validation/single-func-missed-cfi-directive.s b/llvm/test/UnwindInfoChecker/X86/single-func-missed-cfi-directive.s
similarity index 100%
rename from llvm/test/tools/llvm-mc/cfi-validation/single-func-missed-cfi-directive.s
rename to llvm/test/UnwindInfoChecker/X86/single-func-missed-cfi-directive.s
diff --git a/llvm/test/tools/llvm-mc/cfi-validation/single-func.s b/llvm/test/UnwindInfoChecker/X86/single-func.s
similarity index 100%
rename from llvm/test/tools/llvm-mc/cfi-validation/single-func.s
rename to llvm/test/UnwindInfoChecker/X86/single-func.s
diff --git a/llvm/test/tools/llvm-mc/cfi-validation/spill-two-reg-reversed.s b/llvm/test/UnwindInfoChecker/X86/spill-two-reg-reversed.s
similarity index 100%
rename from llvm/test/tools/llvm-mc/cfi-validation/spill-two-reg-reversed.s
rename to llvm/test/UnwindInfoChecker/X86/spill-two-reg-reversed.s
diff --git a/llvm/test/tools/llvm-mc/cfi-validation/spill-two-reg.s b/llvm/test/UnwindInfoChecker/X86/spill-two-reg.s
similarity index 100%
rename from llvm/test/tools/llvm-mc/cfi-validation/spill-two-reg.s
rename to llvm/test/UnwindInfoChecker/X86/spill-two-reg.s
diff --git a/llvm/test/tools/llvm-mc/cfi-validation/update-with-no-cfi.s b/llvm/test/UnwindInfoChecker/X86/update-with-no-cfi.s
similarity index 100%
rename from llvm/test/tools/llvm-mc/cfi-validation/update-with-no-cfi.s
rename to llvm/test/UnwindInfoChecker/X86/update-with-no-cfi.s
>From 88952b038f722a8f326abdb9295e0aec0f2fc6b7 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Wed, 25 Jun 2025 03:49:47 +0000
Subject: [PATCH 51/58] Rename UnwindHistory to UnwindState
---
llvm/include/llvm/UnwindInfoChecker/UnwindInfoAnalysis.h | 2 +-
.../{UnwindInfoHistory.h => UnwindInfoState.h} | 4 ++--
llvm/lib/UnwindInfoChecker/CMakeLists.txt | 2 +-
llvm/lib/UnwindInfoChecker/UnwindInfoAnalysis.cpp | 2 +-
.../{UnwindInfoHistory.cpp => UnwindInfoState.cpp} | 2 +-
5 files changed, 6 insertions(+), 6 deletions(-)
rename llvm/include/llvm/UnwindInfoChecker/{UnwindInfoHistory.h => UnwindInfoState.h} (91%)
rename llvm/lib/UnwindInfoChecker/{UnwindInfoHistory.cpp => UnwindInfoState.cpp} (99%)
diff --git a/llvm/include/llvm/UnwindInfoChecker/UnwindInfoAnalysis.h b/llvm/include/llvm/UnwindInfoChecker/UnwindInfoAnalysis.h
index 7b60745fea826..954dc6a4a8edb 100644
--- a/llvm/include/llvm/UnwindInfoChecker/UnwindInfoAnalysis.h
+++ b/llvm/include/llvm/UnwindInfoChecker/UnwindInfoAnalysis.h
@@ -14,7 +14,7 @@
#ifndef LLVM_UNWINDINFOCHECKER_UNWINDINFOANALYSIS_H
#define LLVM_UNWINDINFOCHECKER_UNWINDINFOANALYSIS_H
-#include "UnwindInfoHistory.h"
+#include "UnwindInfoState.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
diff --git a/llvm/include/llvm/UnwindInfoChecker/UnwindInfoHistory.h b/llvm/include/llvm/UnwindInfoChecker/UnwindInfoState.h
similarity index 91%
rename from llvm/include/llvm/UnwindInfoChecker/UnwindInfoHistory.h
rename to llvm/include/llvm/UnwindInfoChecker/UnwindInfoState.h
index 8bad58ca31428..d2e4a3d36252b 100644
--- a/llvm/include/llvm/UnwindInfoChecker/UnwindInfoHistory.h
+++ b/llvm/include/llvm/UnwindInfoChecker/UnwindInfoState.h
@@ -11,8 +11,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_UNWINDINFOCHECKER_UNWINDINFOHISTORY_H
-#define LLVM_UNWINDINFOCHECKER_UNWINDINFOHISTORY_H
+#ifndef LLVM_UNWINDINFOCHECKER_UNWINDINFOSTATE_H
+#define LLVM_UNWINDINFOCHECKER_UNWINDINFOSTATE_H
#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
#include "llvm/MC/MCContext.h"
diff --git a/llvm/lib/UnwindInfoChecker/CMakeLists.txt b/llvm/lib/UnwindInfoChecker/CMakeLists.txt
index c1ae214d2dc78..2b93c1acf4642 100644
--- a/llvm/lib/UnwindInfoChecker/CMakeLists.txt
+++ b/llvm/lib/UnwindInfoChecker/CMakeLists.txt
@@ -2,8 +2,8 @@ add_llvm_component_library(LLVMUnwindInfoChecker
FunctionUnitAnalyzer.cpp
FunctionUnitStreamer.cpp
FunctionUnitUnwindInfoAnalyzer.cpp
- UnwindInfoHistory.cpp
UnwindInfoAnalysis.cpp
+ UnwindInfoState.cpp
ADDITIONAL_HEADER_DIRS
${LLVM_MAIN_INCLUDE_DIR}/llvm/MCA
diff --git a/llvm/lib/UnwindInfoChecker/UnwindInfoAnalysis.cpp b/llvm/lib/UnwindInfoChecker/UnwindInfoAnalysis.cpp
index 99952a6db3f4c..23e3b68ef91ae 100644
--- a/llvm/lib/UnwindInfoChecker/UnwindInfoAnalysis.cpp
+++ b/llvm/lib/UnwindInfoChecker/UnwindInfoAnalysis.cpp
@@ -25,7 +25,7 @@
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormatVariadic.h"
-#include "llvm/UnwindInfoChecker/UnwindInfoHistory.h"
+#include "llvm/UnwindInfoChecker/UnwindInfoState.h"
#include <cstdint>
#include <optional>
#include <set>
diff --git a/llvm/lib/UnwindInfoChecker/UnwindInfoHistory.cpp b/llvm/lib/UnwindInfoChecker/UnwindInfoState.cpp
similarity index 99%
rename from llvm/lib/UnwindInfoChecker/UnwindInfoHistory.cpp
rename to llvm/lib/UnwindInfoChecker/UnwindInfoState.cpp
index 19bb5f9f175a3..b310f915ab610 100644
--- a/llvm/lib/UnwindInfoChecker/UnwindInfoHistory.cpp
+++ b/llvm/lib/UnwindInfoChecker/UnwindInfoState.cpp
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/UnwindInfoChecker/UnwindInfoHistory.h"
+#include "llvm/UnwindInfoChecker/UnwindInfoState.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
#include "llvm/MC/MCDwarf.h"
>From 017d89086eb17e9ef2a6634c7425dac8c57f1561 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Wed, 25 Jun 2025 03:53:46 +0000
Subject: [PATCH 52/58] Make different methods to add instruction public
---
.../include/llvm/DebugInfo/DWARF/DWARFCFIProgram.h | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFCFIProgram.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFCFIProgram.h
index 0badfab89c839..5613a3e21f5ae 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFCFIProgram.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFCFIProgram.h
@@ -112,13 +112,6 @@ class CFIProgram {
/// above. This is indexed by opcode.
LLVM_ABI static ArrayRef<OperandType[MaxOperands]> getOperandTypes();
-//! FIX me, making these methods public to be usable inside the UnwindInfoAnalysis
-// private:
- std::vector<Instruction> Instructions;
- const uint64_t CodeAlignmentFactor;
- const int64_t DataAlignmentFactor;
- Triple::ArchType Arch;
-
/// Convenience method to add a new instruction with the given opcode.
void addInstruction(uint8_t Opcode) {
Instructions.push_back(Instruction(Opcode));
@@ -145,6 +138,13 @@ class CFIProgram {
Instructions.back().Ops.push_back(Operand2);
Instructions.back().Ops.push_back(Operand3);
}
+
+private:
+ std::vector<Instruction> Instructions;
+ const uint64_t CodeAlignmentFactor;
+ const int64_t DataAlignmentFactor;
+ Triple::ArchType Arch;
+
};
} // end namespace dwarf
>From 76b96ddfb97bd487534313a899f0ad7d630b4182 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Wed, 25 Jun 2025 03:59:50 +0000
Subject: [PATCH 53/58] Revert bolt change
---
bolt/lib/Utils/CommandLineOpts.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/bolt/lib/Utils/CommandLineOpts.cpp b/bolt/lib/Utils/CommandLineOpts.cpp
index d4d6dbcb72aac..5635da476451d 100644
--- a/bolt/lib/Utils/CommandLineOpts.cpp
+++ b/bolt/lib/Utils/CommandLineOpts.cpp
@@ -202,7 +202,7 @@ cl::opt<bool> Lite("lite", cl::desc("skip processing of cold functions"),
cl::cat(BoltCategory));
cl::opt<std::string>
-OutputFilename("ooo",
+OutputFilename("o",
cl::desc("<output file>"),
cl::Optional,
cl::cat(BoltOutputCategory));
>From 60689b3daa172495a01278b2133aa8875d44d708 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Wed, 25 Jun 2025 04:00:54 +0000
Subject: [PATCH 54/58] Revert bolt changes
---
bolt/include/bolt/Core/MCPlusBuilder.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/bolt/include/bolt/Core/MCPlusBuilder.h b/bolt/include/bolt/Core/MCPlusBuilder.h
index c168f06762c0d..804100db80793 100644
--- a/bolt/include/bolt/Core/MCPlusBuilder.h
+++ b/bolt/include/bolt/Core/MCPlusBuilder.h
@@ -1164,7 +1164,7 @@ class MCPlusBuilder {
return false;
}
- /// Use \p Input1 or \p Input2 as the current value for the input
+ /// Use \p Input1 or Input2 as the current value for the input
/// register and put in \p Output the changes incurred by executing
/// \p Inst. Return false if it was not possible to perform the
/// evaluation. evaluateStackOffsetExpr is restricted to operations
>From 5b3475bc46a15019265f28d23de349b9f1f10977 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Wed, 25 Jun 2025 04:10:01 +0000
Subject: [PATCH 55/58] Change UnwindTable to RowContainer
---
llvm/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h | 1 -
llvm/include/llvm/UnwindInfoChecker/UnwindInfoState.h | 2 +-
llvm/lib/UnwindInfoChecker/UnwindInfoState.cpp | 5 +++--
3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h
index c87abb010f039..f1c5392e29925 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h
@@ -334,7 +334,6 @@ class UnwindTable {
assert(Index < size());
return Rows[Index];
}
- void insertRow(UnwindRow Row) { Rows.push_back(Row); }
/// Dump the UnwindTable to the stream.
///
diff --git a/llvm/include/llvm/UnwindInfoChecker/UnwindInfoState.h b/llvm/include/llvm/UnwindInfoChecker/UnwindInfoState.h
index d2e4a3d36252b..decf7f84f05b2 100644
--- a/llvm/include/llvm/UnwindInfoChecker/UnwindInfoState.h
+++ b/llvm/include/llvm/UnwindInfoChecker/UnwindInfoState.h
@@ -32,7 +32,7 @@ class UnwindInfoState {
private:
MCContext *Context;
- dwarf::UnwindTable Table;
+ dwarf::UnwindTable::RowContainer Table;
std::optional<dwarf::CFIProgram> convert(MCCFIInstruction CFIDirective);
};
diff --git a/llvm/lib/UnwindInfoChecker/UnwindInfoState.cpp b/llvm/lib/UnwindInfoChecker/UnwindInfoState.cpp
index b310f915ab610..4d8dd1e0283bb 100644
--- a/llvm/lib/UnwindInfoChecker/UnwindInfoState.cpp
+++ b/llvm/lib/UnwindInfoChecker/UnwindInfoState.cpp
@@ -37,7 +37,8 @@ void UnwindInfoState::update(const MCCFIInstruction &CFIDirective) {
auto LastRow = getCurrentUnwindRow();
dwarf::UnwindRow Row =
LastRow.has_value() ? *(LastRow.value()) : dwarf::UnwindRow();
- if (Error Err = Table.parseRows(DwarfOperations.value(), Row, nullptr)) {
+ if (Error Err =
+ parseRows(DwarfOperations.value(), Row, nullptr).moveInto(Table)) {
Context->reportError(
CFIDirective.getLoc(),
formatv("could not parse this CFI directive due to: {0}",
@@ -46,7 +47,7 @@ void UnwindInfoState::update(const MCCFIInstruction &CFIDirective) {
// Proceed the analysis by ignoring this CFI directive.
return;
}
- Table.insertRow(Row);
+ Table.push_back(Row);
}
std::optional<dwarf::CFIProgram>
>From 6bcc0ccd75404eb6aa3993774a5651b98b05a02f Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Wed, 25 Jun 2025 04:32:57 +0000
Subject: [PATCH 56/58] Refactor UnwindInfoState
---
.../lib/UnwindInfoChecker/UnwindInfoState.cpp | 113 ++++++++----------
1 file changed, 50 insertions(+), 63 deletions(-)
diff --git a/llvm/lib/UnwindInfoChecker/UnwindInfoState.cpp b/llvm/lib/UnwindInfoChecker/UnwindInfoState.cpp
index 4d8dd1e0283bb..72fa2dc21fc22 100644
--- a/llvm/lib/UnwindInfoChecker/UnwindInfoState.cpp
+++ b/llvm/lib/UnwindInfoChecker/UnwindInfoState.cpp
@@ -26,21 +26,21 @@ UnwindInfoState::getCurrentUnwindRow() const {
return --Table.end();
}
-void UnwindInfoState::update(const MCCFIInstruction &CFIDirective) {
- auto DwarfOperations = convert(CFIDirective);
- if (!DwarfOperations) {
+void UnwindInfoState::update(const MCCFIInstruction &Directive) {
+ auto MaybeCFIP = convert(Directive);
+ if (!MaybeCFIP) {
Context->reportError(
- CFIDirective.getLoc(),
+ Directive.getLoc(),
"couldn't apply this directive to the unwinding information state");
}
+ auto CFIP = *MaybeCFIP;
- auto LastRow = getCurrentUnwindRow();
+ auto MaybeLastRow = getCurrentUnwindRow();
dwarf::UnwindRow Row =
- LastRow.has_value() ? *(LastRow.value()) : dwarf::UnwindRow();
- if (Error Err =
- parseRows(DwarfOperations.value(), Row, nullptr).moveInto(Table)) {
+ MaybeLastRow.has_value() ? *(MaybeLastRow.value()) : dwarf::UnwindRow();
+ if (Error Err = parseRows(CFIP, Row, nullptr).moveInto(Table)) {
Context->reportError(
- CFIDirective.getLoc(),
+ Directive.getLoc(),
formatv("could not parse this CFI directive due to: {0}",
toString(std::move(Err))));
@@ -51,104 +51,91 @@ void UnwindInfoState::update(const MCCFIInstruction &CFIDirective) {
}
std::optional<dwarf::CFIProgram>
-UnwindInfoState::convert(MCCFIInstruction CFIDirective) {
- //! FIXME, this way of instantiating CFI program does not look right, either
- //! refactor CFIProgram to not depend on the Code/Data Alignment or add a new
- //! type that is independent from this and is also feedable to UnwindTable.
- auto DwarfOperations = dwarf::CFIProgram(
- 1 /* TODO */, 1 /* TODO */, Context->getTargetTriple().getArch());
+UnwindInfoState::convert(MCCFIInstruction Directive) {
+ auto CFIP = dwarf::CFIProgram(
+ /* CodeAlignmentFactor */ 1, /* DataAlignmentFactor */ 1,
+ Context->getTargetTriple().getArch());
- switch (CFIDirective.getOperation()) {
+ auto MaybeCurrentRow = getCurrentUnwindRow();
+ switch (Directive.getOperation()) {
case MCCFIInstruction::OpSameValue:
- DwarfOperations.addInstruction(dwarf::DW_CFA_same_value,
- CFIDirective.getRegister());
+ CFIP.addInstruction(dwarf::DW_CFA_same_value, Directive.getRegister());
break;
case MCCFIInstruction::OpRememberState:
- DwarfOperations.addInstruction(dwarf::DW_CFA_remember_state);
+ CFIP.addInstruction(dwarf::DW_CFA_remember_state);
break;
case MCCFIInstruction::OpRestoreState:
- DwarfOperations.addInstruction(dwarf::DW_CFA_restore_state);
+ CFIP.addInstruction(dwarf::DW_CFA_restore_state);
break;
case MCCFIInstruction::OpOffset:
- DwarfOperations.addInstruction(dwarf::DW_CFA_offset,
- CFIDirective.getRegister(),
- CFIDirective.getOffset());
+ CFIP.addInstruction(dwarf::DW_CFA_offset, Directive.getRegister(),
+ Directive.getOffset());
break;
case MCCFIInstruction::OpLLVMDefAspaceCfa:
- DwarfOperations.addInstruction(dwarf::DW_CFA_LLVM_def_aspace_cfa,
- CFIDirective.getRegister());
+ CFIP.addInstruction(dwarf::DW_CFA_LLVM_def_aspace_cfa,
+ Directive.getRegister());
break;
case MCCFIInstruction::OpDefCfaRegister:
- DwarfOperations.addInstruction(dwarf::DW_CFA_def_cfa_register,
- CFIDirective.getRegister());
+ CFIP.addInstruction(dwarf::DW_CFA_def_cfa_register,
+ Directive.getRegister());
break;
case MCCFIInstruction::OpDefCfaOffset:
- DwarfOperations.addInstruction(dwarf::DW_CFA_def_cfa_offset,
- CFIDirective.getOffset());
+ CFIP.addInstruction(dwarf::DW_CFA_def_cfa_offset, Directive.getOffset());
break;
case MCCFIInstruction::OpDefCfa:
- DwarfOperations.addInstruction(dwarf::DW_CFA_def_cfa,
- CFIDirective.getRegister(),
- CFIDirective.getOffset());
+ CFIP.addInstruction(dwarf::DW_CFA_def_cfa, Directive.getRegister(),
+ Directive.getOffset());
break;
case MCCFIInstruction::OpRelOffset:
- if (!getCurrentUnwindRow()) // TODO maybe replace it with assert
- return std::nullopt;
+ assert(
+ MaybeCurrentRow &&
+ "Cannot define relative offset to a non-existing CFA unwinding rule");
- DwarfOperations.addInstruction(
- dwarf::DW_CFA_offset, CFIDirective.getRegister(),
- CFIDirective.getOffset() -
- getCurrentUnwindRow().value()->getCFAValue().getOffset());
+ CFIP.addInstruction(dwarf::DW_CFA_offset, Directive.getRegister(),
+ Directive.getOffset() -
+ (*MaybeCurrentRow)->getCFAValue().getOffset());
break;
case MCCFIInstruction::OpAdjustCfaOffset:
- if (!getCurrentUnwindRow()) // TODO maybe replace it with assert
- return std::nullopt;
+ assert(MaybeCurrentRow &&
+ "Cannot adjust CFA offset of a non-existing CFA unwinding rule");
- DwarfOperations.addInstruction(
- dwarf::DW_CFA_def_cfa_offset,
- CFIDirective.getOffset() +
- getCurrentUnwindRow().value()->getCFAValue().getOffset());
+ CFIP.addInstruction(dwarf::DW_CFA_def_cfa_offset,
+ Directive.getOffset() +
+ (*MaybeCurrentRow)->getCFAValue().getOffset());
break;
case MCCFIInstruction::OpEscape:
- // TODO It's now feasible but for now, I ignore it
+ // TODO DWARFExpressions are not supported yet.
break;
case MCCFIInstruction::OpRestore:
- DwarfOperations.addInstruction(dwarf::DW_CFA_restore);
+ CFIP.addInstruction(dwarf::DW_CFA_restore);
break;
case MCCFIInstruction::OpUndefined:
- DwarfOperations.addInstruction(dwarf::DW_CFA_undefined,
- CFIDirective.getRegister());
+ CFIP.addInstruction(dwarf::DW_CFA_undefined, Directive.getRegister());
break;
case MCCFIInstruction::OpRegister:
- DwarfOperations.addInstruction(dwarf::DW_CFA_register,
- CFIDirective.getRegister(),
- CFIDirective.getRegister2());
+ CFIP.addInstruction(dwarf::DW_CFA_register, Directive.getRegister(),
+ Directive.getRegister2());
break;
case MCCFIInstruction::OpWindowSave:
- // TODO make sure these are the same.
- DwarfOperations.addInstruction(dwarf::DW_CFA_GNU_window_save);
+ CFIP.addInstruction(dwarf::DW_CFA_GNU_window_save);
break;
case MCCFIInstruction::OpNegateRAState:
- // TODO make sure these are the same.
- DwarfOperations.addInstruction(dwarf::DW_CFA_AARCH64_negate_ra_state);
+ CFIP.addInstruction(dwarf::DW_CFA_AARCH64_negate_ra_state);
break;
case MCCFIInstruction::OpNegateRAStateWithPC:
- // TODO make sure these are the same.
- DwarfOperations.addInstruction(
- dwarf::DW_CFA_AARCH64_negate_ra_state_with_pc);
+ CFIP.addInstruction(dwarf::DW_CFA_AARCH64_negate_ra_state_with_pc);
break;
case MCCFIInstruction::OpGnuArgsSize:
- DwarfOperations.addInstruction(dwarf::DW_CFA_GNU_args_size);
+ CFIP.addInstruction(dwarf::DW_CFA_GNU_args_size);
break;
case MCCFIInstruction::OpLabel:
// TODO, I don't know what it is, I have to implement it.
break;
case MCCFIInstruction::OpValOffset:
- DwarfOperations.addInstruction(dwarf::DW_CFA_val_offset,
- CFIDirective.getRegister(),
- CFIDirective.getOffset());
+ CFIP.addInstruction(dwarf::DW_CFA_val_offset, Directive.getRegister(),
+ Directive.getOffset());
break;
}
- return DwarfOperations;
+ return CFIP;
}
>From 439c1d0083eb8742ce16e9d171a6c02258e52dbe Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Wed, 25 Jun 2025 04:43:12 +0000
Subject: [PATCH 57/58] Revert unnecessary changes to llvm-mc
---
llvm/tools/llvm-mc/llvm-mc.cpp | 31 ++++++++++++++++---------------
1 file changed, 16 insertions(+), 15 deletions(-)
diff --git a/llvm/tools/llvm-mc/llvm-mc.cpp b/llvm/tools/llvm-mc/llvm-mc.cpp
index a0f5998d3f8fd..a23a69c4f0b39 100644
--- a/llvm/tools/llvm-mc/llvm-mc.cpp
+++ b/llvm/tools/llvm-mc/llvm-mc.cpp
@@ -17,7 +17,6 @@
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCInstPrinter.h"
-#include "llvm/MC/MCInstrAnalysis.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCObjectFileInfo.h"
#include "llvm/MC/MCObjectWriter.h"
@@ -26,7 +25,6 @@
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
-#include "llvm/MC/MCTargetOptions.h"
#include "llvm/MC/MCTargetOptionsCommandFlags.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/CommandLine.h"
@@ -39,13 +37,10 @@
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/ToolOutputFile.h"
#include "llvm/Support/WithColor.h"
-#include "llvm/Target/TargetMachine.h"
-#include "llvm/Target/TargetOptions.h"
#include "llvm/TargetParser/Host.h"
#include "llvm/UnwindInfoChecker/FunctionUnitStreamer.h"
#include "llvm/UnwindInfoChecker/FunctionUnitUnwindInfoAnalyzer.h"
#include <memory>
-#include <optional>
using namespace llvm;
@@ -122,7 +117,11 @@ static cl::opt<unsigned> CommentColumn("comment-column",
cl::desc("Asm comments indentation"),
cl::init(40));
-enum OutputFileType { OFT_Null, OFT_AssemblyFile, OFT_ObjectFile };
+enum OutputFileType {
+ OFT_Null,
+ OFT_AssemblyFile,
+ OFT_ObjectFile
+};
static cl::opt<OutputFileType>
FileType("filetype", cl::init(OFT_AssemblyFile),
cl::desc("Choose an output file type:"),
@@ -249,8 +248,8 @@ static const Target *GetTarget(const char *ProgName) {
// Get the target specific parser.
std::string Error;
- const Target *TheTarget =
- TargetRegistry::lookupTarget(ArchName, TheTriple, Error);
+ const Target *TheTarget = TargetRegistry::lookupTarget(ArchName, TheTriple,
+ Error);
if (!TheTarget) {
WithColor::error(errs(), ProgName) << Error;
return nullptr;
@@ -261,8 +260,8 @@ static const Target *GetTarget(const char *ProgName) {
return TheTarget;
}
-static std::unique_ptr<ToolOutputFile>
-GetOutputStream(StringRef Path, sys::fs::OpenFlags Flags) {
+static std::unique_ptr<ToolOutputFile> GetOutputStream(StringRef Path,
+ sys::fs::OpenFlags Flags) {
std::error_code EC;
auto Out = std::make_unique<ToolOutputFile>(Path, EC, Flags);
if (EC) {
@@ -286,12 +285,13 @@ static void setDwarfDebugFlags(int argc, char **argv) {
static std::string DwarfDebugProducer;
static void setDwarfDebugProducer() {
- if (!getenv("DEBUG_PRODUCER"))
+ if(!getenv("DEBUG_PRODUCER"))
return;
DwarfDebugProducer += getenv("DEBUG_PRODUCER");
}
-static int AsLexInput(SourceMgr &SrcMgr, MCAsmInfo &MAI, raw_ostream &OS) {
+static int AsLexInput(SourceMgr &SrcMgr, MCAsmInfo &MAI,
+ raw_ostream &OS) {
AsmLexer Lexer(MAI);
Lexer.setBuffer(SrcMgr.getMemoryBuffer(SrcMgr.getMainFileID())->getBuffer());
@@ -308,7 +308,7 @@ static int AsLexInput(SourceMgr &SrcMgr, MCAsmInfo &MAI, raw_ostream &OS) {
}
static int fillCommandLineSymbols(MCAsmParser &Parser) {
- for (auto &I : DefineSymbol) {
+ for (auto &I: DefineSymbol) {
auto Pair = StringRef(I).split('=');
auto Sym = Pair.first;
auto Val = Pair.second;
@@ -332,7 +332,8 @@ static int AssembleInput(const char *ProgName, const Target *TheTarget,
SourceMgr &SrcMgr, MCContext &Ctx, MCStreamer &Str,
MCAsmInfo &MAI, MCSubtargetInfo &STI,
MCInstrInfo &MCII, MCTargetOptions const &MCOptions) {
- std::unique_ptr<MCAsmParser> Parser(createMCAsmParser(SrcMgr, Ctx, Str, MAI));
+ std::unique_ptr<MCAsmParser> Parser(
+ createMCAsmParser(SrcMgr, Ctx, Str, MAI));
std::unique_ptr<MCTargetAsmParser> TAP(
TheTarget->createMCAsmParser(STI, *Parser, MCII, MCOptions));
@@ -343,7 +344,7 @@ static int AssembleInput(const char *ProgName, const Target *TheTarget,
}
int SymbolResult = fillCommandLineSymbols(*Parser);
- if (SymbolResult)
+ if(SymbolResult)
return SymbolResult;
Parser->setShowParsedOperands(ShowInstOperands);
Parser->setTargetParser(*TAP);
>From dfddfea2ed5d68821004a5d979fa026a3b2ac915 Mon Sep 17 00:00:00 2001
From: Amirhossein Pashaeehir <amirhosseinp at google.com>
Date: Wed, 25 Jun 2025 05:00:03 +0000
Subject: [PATCH 58/58] Lint
---
llvm/include/llvm/DebugInfo/DWARF/DWARFCFIProgram.h | 1 -
1 file changed, 1 deletion(-)
diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFCFIProgram.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFCFIProgram.h
index 5613a3e21f5ae..79a2be7ef2584 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFCFIProgram.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFCFIProgram.h
@@ -144,7 +144,6 @@ class CFIProgram {
const uint64_t CodeAlignmentFactor;
const int64_t DataAlignmentFactor;
Triple::ArchType Arch;
-
};
} // end namespace dwarf
More information about the llvm-commits
mailing list