[llvm] [llvm][AsmPrinter] Add an option to print instruction latencies (PR #113243)
Jon Roelofs via llvm-commits
llvm-commits at lists.llvm.org
Fri Oct 25 11:03:03 PDT 2024
https://github.com/jroelofs updated https://github.com/llvm/llvm-project/pull/113243
>From eede159a4a5d7787e116f1f853125daf5ab4be5b Mon Sep 17 00:00:00 2001
From: Jon Roelofs <jonathan_roelofs at apple.com>
Date: Mon, 21 Oct 2024 17:52:35 -0700
Subject: [PATCH 1/8] [llvm][AsmPrinter] Add an option to print instruction
latencies
... matching what we have in the disassembler. This isn't turned on by default
since several of the scheduling models are not completely accurate, and we
don't want to be misleading.
---
llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 94 +++++++++++++++++++++-
llvm/test/CodeGen/AArch64/latency.ll | 10 +++
2 files changed, 102 insertions(+), 2 deletions(-)
create mode 100644 llvm/test/CodeGen/AArch64/latency.ll
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index 327e7f7f8a1ed8..015c4cc3d4b721 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -162,6 +162,13 @@ static cl::opt<bool> EmitJumpTableSizesSection(
cl::desc("Emit a section containing jump table addresses and sizes"),
cl::Hidden, cl::init(false));
+// This isn't turned on by default, since several of the scheduling models are
+// not completely accurate, and we don't want to be misleading.
+static cl::opt<bool> PrintLatency(
+ "asm-print-latency",
+ cl::desc("Print instruction latencies as verbose asm comments."),
+ cl::Hidden, cl::init(false));
+
STATISTIC(EmittedInsts, "Number of machine instrs printed");
char AsmPrinter::ID = 0;
@@ -1080,8 +1087,78 @@ void AsmPrinter::emitFunctionEntryLabel() {
}
}
+/// Gets latency information for \p Inst from the itinerary
+/// scheduling model.
+/// \return The maximum expected latency over all the operands or -1
+/// if no information is available.
+static int getItineraryLatency(const MachineInstr &MI,
+ const MachineFunction *MF,
+ const MCSubtargetInfo *STI) {
+ const int NoInformationAvailable = -1;
+ const TargetInstrInfo *TII = MF->getSubtarget().getInstrInfo();
+
+ // Check if we have a CPU to get the itinerary information.
+ if (STI->getCPU().empty())
+ return NoInformationAvailable;
+
+ // Get itinerary information.
+ InstrItineraryData IID = STI->getInstrItineraryForCPU(STI->getCPU());
+ // Get the scheduling class of the requested instruction.
+ const MCInstrDesc &Desc = TII->get(MI.getOpcode());
+ unsigned SCClass = Desc.getSchedClass();
+
+ unsigned Latency = 0;
+
+ for (unsigned Idx = 0, IdxEnd = MI.getNumOperands(); Idx != IdxEnd; ++Idx)
+ if (std::optional<unsigned> OperCycle = IID.getOperandCycle(SCClass, Idx))
+ Latency = std::max(Latency, *OperCycle);
+
+ return (int)Latency;
+}
+
+/// Gets latency information for \p Inst.
+/// \return The maximum expected latency over all the definitions or -1
+/// if no information is available.
+static int getLatency(const MachineInstr &MI, const MCSubtargetInfo *STI) {
+ const MCSchedModel SCModel = STI->getSchedModel();
+ const int NoInformationAvailable = -1;
+
+ const MachineFunction *MF = MI.getMF();
+ if (!MF)
+ return NoInformationAvailable;
+
+ // Check if we have a scheduling model for instructions.
+ if (!SCModel.hasInstrSchedModel())
+ // Try to fall back to the itinerary model if the scheduling model doesn't
+ // have a scheduling table. Note the default does not have a table.
+ return getItineraryLatency(MI, MF, STI);
+
+ // Get the scheduling class of the requested instruction.
+ const TargetInstrInfo *TII = MF->getSubtarget().getInstrInfo();
+ const MCInstrDesc &Desc = TII->get(MI.getOpcode());
+ unsigned SCClass = Desc.getSchedClass();
+ const MCSchedClassDesc *SCDesc = SCModel.getSchedClassDesc(SCClass);
+ // Resolving the variant SchedClass requires an MI to pass to
+ // SubTargetInfo::resolveSchedClass.
+ if (!SCDesc || !SCDesc->isValid() || SCDesc->isVariant())
+ return NoInformationAvailable;
+
+ // Compute output latency.
+ int16_t Latency = 0;
+ for (unsigned DefIdx = 0, DefEnd = SCDesc->NumWriteLatencyEntries;
+ DefIdx != DefEnd; ++DefIdx) {
+ // Lookup the definition's write latency in SubtargetInfo.
+ const MCWriteLatencyEntry *WLEntry =
+ STI->getWriteLatencyEntry(SCDesc, DefIdx);
+ Latency = std::max(Latency, WLEntry->Cycles);
+ }
+
+ return Latency;
+}
+
/// emitComments - Pretty-print comments for instructions.
-static void emitComments(const MachineInstr &MI, raw_ostream &CommentOS) {
+static void emitComments(const MachineInstr &MI, const MCSubtargetInfo *STI,
+ raw_ostream &CommentOS) {
const MachineFunction *MF = MI.getMF();
const TargetInstrInfo *TII = MF->getSubtarget().getInstrInfo();
@@ -1109,6 +1186,13 @@ static void emitComments(const MachineInstr &MI, raw_ostream &CommentOS) {
// Check for spill-induced copies
if (MI.getAsmPrinterFlag(MachineInstr::ReloadReuse))
CommentOS << " Reload Reuse\n";
+
+ if (PrintLatency) {
+ int Latency = getLatency(MI, STI);
+ // Report only interesting latencies.
+ if (1 < Latency)
+ CommentOS << " Latency: " << Latency << "\n";
+ }
}
/// emitImplicitDef - This method emits the specified machine instruction
@@ -1750,6 +1834,12 @@ void AsmPrinter::emitFunctionBody() {
int NumInstsInFunction = 0;
bool IsEHa = MMI->getModule()->getModuleFlag("eh-asynch");
+ const MCSubtargetInfo *STI = nullptr;
+ if (this->MF)
+ STI = &getSubtargetInfo();
+ else
+ STI = TM.getMCSubtargetInfo();
+
bool CanDoExtraAnalysis = ORE->allowExtraAnalysis(DEBUG_TYPE);
for (auto &MBB : *MF) {
// Print a label for the basic block.
@@ -1773,7 +1863,7 @@ void AsmPrinter::emitFunctionBody() {
Handler->beginInstruction(&MI);
if (isVerbose())
- emitComments(MI, OutStreamer->getCommentOS());
+ emitComments(MI, STI, OutStreamer->getCommentOS());
switch (MI.getOpcode()) {
case TargetOpcode::CFI_INSTRUCTION:
diff --git a/llvm/test/CodeGen/AArch64/latency.ll b/llvm/test/CodeGen/AArch64/latency.ll
new file mode 100644
index 00000000000000..b722eec3e2571a
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/latency.ll
@@ -0,0 +1,10 @@
+; RUN: llc -mtriple=arm64-apple-ios %s -o - -mcpu=cyclone -asm-print-latency=1 | FileCheck %s --match-full-lines --check-prefix=ON
+; RUN: llc -mtriple=arm64-apple-ios %s -o - -mcpu=cyclone -asm-print-latency=0 | FileCheck %s --match-full-lines --check-prefix=OFF
+; RUN: llc -mtriple=arm64-apple-ios %s -o - -mcpu=cyclone | FileCheck %s --match-full-lines --check-prefix=OFF
+
+define <4 x i64> @load_v4i64(ptr %ptr){
+; ON: ldp q0, q1, [x0] ; Latency: 4
+; OFF: ldp q0, q1, [x0]
+ %a = load <4 x i64>, ptr %ptr
+ ret <4 x i64> %a
+}
>From 62131f6e4685510daca04685e99ed3994b8a485e Mon Sep 17 00:00:00 2001
From: Jon Roelofs <jonathan_roelofs at apple.com>
Date: Tue, 22 Oct 2024 19:08:08 -0700
Subject: [PATCH 2/8] add a test for a cpu with itineraries
---
llvm/test/CodeGen/ARM/latency.ll | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
create mode 100644 llvm/test/CodeGen/ARM/latency.ll
diff --git a/llvm/test/CodeGen/ARM/latency.ll b/llvm/test/CodeGen/ARM/latency.ll
new file mode 100644
index 00000000000000..ada6254666fdef
--- /dev/null
+++ b/llvm/test/CodeGen/ARM/latency.ll
@@ -0,0 +1,16 @@
+; RUN: llc -mtriple=thumb-none-eabi %s -o - -mcpu=cortex-m0 -asm-print-latency=1 | FileCheck %s --match-full-lines --check-prefix=ON
+; RUN: llc -mtriple=thumb-none-eabi %s -o - -mcpu=cortex-m0 -asm-print-latency=0 | FileCheck %s --match-full-lines --check-prefix=OFF
+; RUN: llc -mtriple=thumb-none-eabi %s -o - -mcpu=cortex-m0 | FileCheck %s --match-full-lines --check-prefix=OFF
+
+define i64 @load_i64(ptr %ptr){
+; ON: ldr r2, [r0] @ Latency: 4
+; ON: ldr r1, [r0, #4] @ Latency: 4
+; ON: mov r0, r2 @ Latency: 2
+; ON: bx lr
+; OFF: ldr r2, [r0]
+; OFF: ldr r1, [r0, #4]
+; OFF: mov r0, r2
+; OFf: bx lr
+ %a = load i64, ptr %ptr
+ ret i64 %a
+}
>From 1aa5800f247a460dd252633711aa8fb5826d4b7d Mon Sep 17 00:00:00 2001
From: Jon Roelofs <jonathan_roelofs at apple.com>
Date: Tue, 22 Oct 2024 19:18:57 -0700
Subject: [PATCH 3/8] use MCSchedModel::computeInstrLatency
---
llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 37 +++++++--------------
llvm/lib/MC/MCDisassembler/Disassembler.cpp | 2 +-
2 files changed, 13 insertions(+), 26 deletions(-)
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index 015c4cc3d4b721..e6e3a668c6070b 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -1091,15 +1091,14 @@ void AsmPrinter::emitFunctionEntryLabel() {
/// scheduling model.
/// \return The maximum expected latency over all the operands or -1
/// if no information is available.
-static int getItineraryLatency(const MachineInstr &MI,
+static std::optional<int> getItineraryLatency(const MachineInstr &MI,
const MachineFunction *MF,
const MCSubtargetInfo *STI) {
- const int NoInformationAvailable = -1;
const TargetInstrInfo *TII = MF->getSubtarget().getInstrInfo();
// Check if we have a CPU to get the itinerary information.
if (STI->getCPU().empty())
- return NoInformationAvailable;
+ return std::nullopt;
// Get itinerary information.
InstrItineraryData IID = STI->getInstrItineraryForCPU(STI->getCPU());
@@ -1113,14 +1112,14 @@ static int getItineraryLatency(const MachineInstr &MI,
if (std::optional<unsigned> OperCycle = IID.getOperandCycle(SCClass, Idx))
Latency = std::max(Latency, *OperCycle);
- return (int)Latency;
+ return int(Latency);
}
/// Gets latency information for \p Inst.
/// \return The maximum expected latency over all the definitions or -1
/// if no information is available.
-static int getLatency(const MachineInstr &MI, const MCSubtargetInfo *STI) {
- const MCSchedModel SCModel = STI->getSchedModel();
+static std::optional<int> getLatency(const MachineInstr &MI, const MCSubtargetInfo *STI) {
+ const MCSchedModel &SCModel = STI->getSchedModel();
const int NoInformationAvailable = -1;
const MachineFunction *MF = MI.getMF();
@@ -1137,22 +1136,9 @@ static int getLatency(const MachineInstr &MI, const MCSubtargetInfo *STI) {
const TargetInstrInfo *TII = MF->getSubtarget().getInstrInfo();
const MCInstrDesc &Desc = TII->get(MI.getOpcode());
unsigned SCClass = Desc.getSchedClass();
- const MCSchedClassDesc *SCDesc = SCModel.getSchedClassDesc(SCClass);
- // Resolving the variant SchedClass requires an MI to pass to
- // SubTargetInfo::resolveSchedClass.
- if (!SCDesc || !SCDesc->isValid() || SCDesc->isVariant())
+ int Latency = SCModel.computeInstrLatency(*STI, SCClass);
+ if (Latency <= 0)
return NoInformationAvailable;
-
- // Compute output latency.
- int16_t Latency = 0;
- for (unsigned DefIdx = 0, DefEnd = SCDesc->NumWriteLatencyEntries;
- DefIdx != DefEnd; ++DefIdx) {
- // Lookup the definition's write latency in SubtargetInfo.
- const MCWriteLatencyEntry *WLEntry =
- STI->getWriteLatencyEntry(SCDesc, DefIdx);
- Latency = std::max(Latency, WLEntry->Cycles);
- }
-
return Latency;
}
@@ -1188,10 +1174,11 @@ static void emitComments(const MachineInstr &MI, const MCSubtargetInfo *STI,
CommentOS << " Reload Reuse\n";
if (PrintLatency) {
- int Latency = getLatency(MI, STI);
- // Report only interesting latencies.
- if (1 < Latency)
- CommentOS << " Latency: " << Latency << "\n";
+ if (auto Latency = getLatency(MI, STI)) {
+ // Report only interesting latencies.
+ if (1 < *Latency)
+ CommentOS << " Latency: " << *Latency << "\n";
+ }
}
}
diff --git a/llvm/lib/MC/MCDisassembler/Disassembler.cpp b/llvm/lib/MC/MCDisassembler/Disassembler.cpp
index 5e5a163c290244..fbe487d8da0786 100644
--- a/llvm/lib/MC/MCDisassembler/Disassembler.cpp
+++ b/llvm/lib/MC/MCDisassembler/Disassembler.cpp
@@ -195,7 +195,7 @@ static int getItineraryLatency(LLVMDisasmContext *DC, const MCInst &Inst) {
static int getLatency(LLVMDisasmContext *DC, const MCInst &Inst) {
// Try to compute scheduling information.
const MCSubtargetInfo *STI = DC->getSubtargetInfo();
- const MCSchedModel SCModel = STI->getSchedModel();
+ const MCSchedModel &SCModel = STI->getSchedModel();
const int NoInformationAvailable = -1;
// Check if we have a scheduling model for instructions.
>From 9c59ee34d26d52e594139a0ffc583dba409d239e Mon Sep 17 00:00:00 2001
From: Jon Roelofs <jonathan_roelofs at apple.com>
Date: Tue, 22 Oct 2024 19:23:50 -0700
Subject: [PATCH 4/8] simplify both implementations
---
llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 5 ++---
llvm/lib/MC/MCDisassembler/Disassembler.cpp | 23 +++------------------
2 files changed, 5 insertions(+), 23 deletions(-)
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index e6e3a668c6070b..48d6577db6f6d0 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -1120,11 +1120,10 @@ static std::optional<int> getItineraryLatency(const MachineInstr &MI,
/// if no information is available.
static std::optional<int> getLatency(const MachineInstr &MI, const MCSubtargetInfo *STI) {
const MCSchedModel &SCModel = STI->getSchedModel();
- const int NoInformationAvailable = -1;
const MachineFunction *MF = MI.getMF();
if (!MF)
- return NoInformationAvailable;
+ return std::nullopt;
// Check if we have a scheduling model for instructions.
if (!SCModel.hasInstrSchedModel())
@@ -1138,7 +1137,7 @@ static std::optional<int> getLatency(const MachineInstr &MI, const MCSubtargetIn
unsigned SCClass = Desc.getSchedClass();
int Latency = SCModel.computeInstrLatency(*STI, SCClass);
if (Latency <= 0)
- return NoInformationAvailable;
+ return std::nullopt;
return Latency;
}
diff --git a/llvm/lib/MC/MCDisassembler/Disassembler.cpp b/llvm/lib/MC/MCDisassembler/Disassembler.cpp
index fbe487d8da0786..b99ab7d1511123 100644
--- a/llvm/lib/MC/MCDisassembler/Disassembler.cpp
+++ b/llvm/lib/MC/MCDisassembler/Disassembler.cpp
@@ -186,7 +186,7 @@ static int getItineraryLatency(LLVMDisasmContext *DC, const MCInst &Inst) {
if (std::optional<unsigned> OperCycle = IID.getOperandCycle(SCClass, Idx))
Latency = std::max(Latency, *OperCycle);
- return (int)Latency;
+ return int(Latency);
}
/// Gets latency information for \p Inst, based on \p DC information.
@@ -196,7 +196,6 @@ static int getLatency(LLVMDisasmContext *DC, const MCInst &Inst) {
// Try to compute scheduling information.
const MCSubtargetInfo *STI = DC->getSubtargetInfo();
const MCSchedModel &SCModel = STI->getSchedModel();
- const int NoInformationAvailable = -1;
// Check if we have a scheduling model for instructions.
if (!SCModel.hasInstrSchedModel())
@@ -205,25 +204,9 @@ static int getLatency(LLVMDisasmContext *DC, const MCInst &Inst) {
return getItineraryLatency(DC, Inst);
// Get the scheduling class of the requested instruction.
- const MCInstrDesc& Desc = DC->getInstrInfo()->get(Inst.getOpcode());
+ const MCInstrDesc &Desc = DC->getInstrInfo()->get(Inst.getOpcode());
unsigned SCClass = Desc.getSchedClass();
- const MCSchedClassDesc *SCDesc = SCModel.getSchedClassDesc(SCClass);
- // Resolving the variant SchedClass requires an MI to pass to
- // SubTargetInfo::resolveSchedClass.
- if (!SCDesc || !SCDesc->isValid() || SCDesc->isVariant())
- return NoInformationAvailable;
-
- // Compute output latency.
- int16_t Latency = 0;
- for (unsigned DefIdx = 0, DefEnd = SCDesc->NumWriteLatencyEntries;
- DefIdx != DefEnd; ++DefIdx) {
- // Lookup the definition's write latency in SubtargetInfo.
- const MCWriteLatencyEntry *WLEntry = STI->getWriteLatencyEntry(SCDesc,
- DefIdx);
- Latency = std::max(Latency, WLEntry->Cycles);
- }
-
- return Latency;
+ return SCModel.computeInstrLatency(*STI, SCClass);
}
/// Emits latency information in DC->CommentStream for \p Inst, based
>From cbab0b3fbf614d37be23eaff5d3180cddd0c78b5 Mon Sep 17 00:00:00 2001
From: Jon Roelofs <jonathan_roelofs at apple.com>
Date: Tue, 22 Oct 2024 19:28:42 -0700
Subject: [PATCH 5/8] clang-format
---
llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index 48d6577db6f6d0..3c19f535a9b66f 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -1092,8 +1092,8 @@ void AsmPrinter::emitFunctionEntryLabel() {
/// \return The maximum expected latency over all the operands or -1
/// if no information is available.
static std::optional<int> getItineraryLatency(const MachineInstr &MI,
- const MachineFunction *MF,
- const MCSubtargetInfo *STI) {
+ const MachineFunction *MF,
+ const MCSubtargetInfo *STI) {
const TargetInstrInfo *TII = MF->getSubtarget().getInstrInfo();
// Check if we have a CPU to get the itinerary information.
@@ -1118,7 +1118,8 @@ static std::optional<int> getItineraryLatency(const MachineInstr &MI,
/// Gets latency information for \p Inst.
/// \return The maximum expected latency over all the definitions or -1
/// if no information is available.
-static std::optional<int> getLatency(const MachineInstr &MI, const MCSubtargetInfo *STI) {
+static std::optional<int> getLatency(const MachineInstr &MI,
+ const MCSubtargetInfo *STI) {
const MCSchedModel &SCModel = STI->getSchedModel();
const MachineFunction *MF = MI.getMF();
>From 9dd7fe55bb044dec55abdfe76354cb286680af96 Mon Sep 17 00:00:00 2001
From: Jon Roelofs <jonathan_roelofs at apple.com>
Date: Thu, 24 Oct 2024 16:00:37 -0700
Subject: [PATCH 6/8] make the two impls even closer to 'the same'
---
llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 32 +++++++++---------
llvm/lib/MC/MCDisassembler/Disassembler.cpp | 37 ++++++++++++---------
2 files changed, 37 insertions(+), 32 deletions(-)
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index 3c19f535a9b66f..c5045381271ab0 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -1091,19 +1091,19 @@ void AsmPrinter::emitFunctionEntryLabel() {
/// scheduling model.
/// \return The maximum expected latency over all the operands or -1
/// if no information is available.
-static std::optional<int> getItineraryLatency(const MachineInstr &MI,
- const MachineFunction *MF,
- const MCSubtargetInfo *STI) {
- const TargetInstrInfo *TII = MF->getSubtarget().getInstrInfo();
+static std::optional<int> getItineraryLatency(const MCSubtargetInfo *STI,
+ const MCInstrInfo *MCII,
+ const MachineInstr &MI) {
+ llvm::StringRef CPU = STI->getCPU();
// Check if we have a CPU to get the itinerary information.
- if (STI->getCPU().empty())
+ if (CPU.empty())
return std::nullopt;
// Get itinerary information.
- InstrItineraryData IID = STI->getInstrItineraryForCPU(STI->getCPU());
+ InstrItineraryData IID = STI->getInstrItineraryForCPU(CPU);
// Get the scheduling class of the requested instruction.
- const MCInstrDesc &Desc = TII->get(MI.getOpcode());
+ const MCInstrDesc &Desc = MCII->get(MI.getOpcode());
unsigned SCClass = Desc.getSchedClass();
unsigned Latency = 0;
@@ -1118,23 +1118,20 @@ static std::optional<int> getItineraryLatency(const MachineInstr &MI,
/// Gets latency information for \p Inst.
/// \return The maximum expected latency over all the definitions or -1
/// if no information is available.
-static std::optional<int> getLatency(const MachineInstr &MI,
- const MCSubtargetInfo *STI) {
+static std::optional<int> getLatency(const MCSubtargetInfo *STI,
+ const MCInstrInfo *MCII,
+ const MachineInstr &MI) {
+ // Try to compute scheduling information.
const MCSchedModel &SCModel = STI->getSchedModel();
- const MachineFunction *MF = MI.getMF();
- if (!MF)
- return std::nullopt;
-
// Check if we have a scheduling model for instructions.
if (!SCModel.hasInstrSchedModel())
// Try to fall back to the itinerary model if the scheduling model doesn't
// have a scheduling table. Note the default does not have a table.
- return getItineraryLatency(MI, MF, STI);
+ return getItineraryLatency(STI, MCII, MI);
// Get the scheduling class of the requested instruction.
- const TargetInstrInfo *TII = MF->getSubtarget().getInstrInfo();
- const MCInstrDesc &Desc = TII->get(MI.getOpcode());
+ const MCInstrDesc &Desc = MCII->get(MI.getOpcode());
unsigned SCClass = Desc.getSchedClass();
int Latency = SCModel.computeInstrLatency(*STI, SCClass);
if (Latency <= 0)
@@ -1174,7 +1171,8 @@ static void emitComments(const MachineInstr &MI, const MCSubtargetInfo *STI,
CommentOS << " Reload Reuse\n";
if (PrintLatency) {
- if (auto Latency = getLatency(MI, STI)) {
+ const TargetInstrInfo *TII = MF->getSubtarget().getInstrInfo();
+ if (auto Latency = getLatency(STI, TII, MI)) {
// Report only interesting latencies.
if (1 < *Latency)
CommentOS << " Latency: " << *Latency << "\n";
diff --git a/llvm/lib/MC/MCDisassembler/Disassembler.cpp b/llvm/lib/MC/MCDisassembler/Disassembler.cpp
index b99ab7d1511123..2d155fa212a36e 100644
--- a/llvm/lib/MC/MCDisassembler/Disassembler.cpp
+++ b/llvm/lib/MC/MCDisassembler/Disassembler.cpp
@@ -166,18 +166,19 @@ static void emitComments(LLVMDisasmContext *DC,
/// scheduling model, based on \p DC information.
/// \return The maximum expected latency over all the operands or -1
/// if no information is available.
-static int getItineraryLatency(LLVMDisasmContext *DC, const MCInst &Inst) {
- const int NoInformationAvailable = -1;
+static std::optional<int> getItineraryLatency(const MCSubtargetInfo *STI,
+ const MCInstrInfo *MCII,
+ const MCInst &Inst) {
+ llvm::StringRef CPU = STI->getCPU();
// Check if we have a CPU to get the itinerary information.
- if (DC->getCPU().empty())
- return NoInformationAvailable;
+ if (CPU.empty())
+ return std::nullopt;
// Get itinerary information.
- const MCSubtargetInfo *STI = DC->getSubtargetInfo();
- InstrItineraryData IID = STI->getInstrItineraryForCPU(DC->getCPU());
+ InstrItineraryData IID = STI->getInstrItineraryForCPU(CPU);
// Get the scheduling class of the requested instruction.
- const MCInstrDesc& Desc = DC->getInstrInfo()->get(Inst.getOpcode());
+ const MCInstrDesc& Desc = MCII->get(Inst.getOpcode());
unsigned SCClass = Desc.getSchedClass();
unsigned Latency = 0;
@@ -192,33 +193,39 @@ static int getItineraryLatency(LLVMDisasmContext *DC, const MCInst &Inst) {
/// Gets latency information for \p Inst, based on \p DC information.
/// \return The maximum expected latency over all the definitions or -1
/// if no information is available.
-static int getLatency(LLVMDisasmContext *DC, const MCInst &Inst) {
+static std::optional<int> getLatency(const MCSubtargetInfo *STI, const MCInstrInfo *MCII, const MCInst &Inst) {
// Try to compute scheduling information.
- const MCSubtargetInfo *STI = DC->getSubtargetInfo();
const MCSchedModel &SCModel = STI->getSchedModel();
// Check if we have a scheduling model for instructions.
if (!SCModel.hasInstrSchedModel())
// Try to fall back to the itinerary model if the scheduling model doesn't
// have a scheduling table. Note the default does not have a table.
- return getItineraryLatency(DC, Inst);
+ return getItineraryLatency(STI, MCII, Inst);
// Get the scheduling class of the requested instruction.
- const MCInstrDesc &Desc = DC->getInstrInfo()->get(Inst.getOpcode());
+ const MCInstrDesc &Desc = MCII->get(Inst.getOpcode());
unsigned SCClass = Desc.getSchedClass();
- return SCModel.computeInstrLatency(*STI, SCClass);
+ int Latency = SCModel.computeInstrLatency(*STI, SCClass);
+ if (Latency <= 0)
+ return std::nullopt;
+ return Latency;
}
/// Emits latency information in DC->CommentStream for \p Inst, based
/// on the information available in \p DC.
static void emitLatency(LLVMDisasmContext *DC, const MCInst &Inst) {
- int Latency = getLatency(DC, Inst);
+ const MCSubtargetInfo *STI = DC->getSubtargetInfo();
+ const MCInstrInfo *MCII = DC->getInstrInfo();
+ std::optional<int> Latency = getLatency(STI, MCII, Inst);
+ if (!Latency)
+ return;
// Report only interesting latencies.
- if (Latency < 2)
+ if (*Latency < 2)
return;
- DC->CommentStream << "Latency: " << Latency << '\n';
+ DC->CommentStream << "Latency: " << *Latency << '\n';
}
//
>From d4efbdbd53c57a27b7e35a1749fae34b739437df Mon Sep 17 00:00:00 2001
From: Jon Roelofs <jonathan_roelofs at apple.com>
Date: Fri, 25 Oct 2024 09:54:15 -0700
Subject: [PATCH 7/8] move disassembler's latency calculation into MCSchedule
---
llvm/lib/MC/MCDisassembler/Disassembler.cpp | 59 ++-------------------
llvm/lib/MC/MCSchedule.cpp | 35 ++++++++++++
2 files changed, 39 insertions(+), 55 deletions(-)
diff --git a/llvm/lib/MC/MCDisassembler/Disassembler.cpp b/llvm/lib/MC/MCDisassembler/Disassembler.cpp
index 2d155fa212a36e..9369051008f47c 100644
--- a/llvm/lib/MC/MCDisassembler/Disassembler.cpp
+++ b/llvm/lib/MC/MCDisassembler/Disassembler.cpp
@@ -162,70 +162,19 @@ static void emitComments(LLVMDisasmContext *DC,
DC->CommentsToEmit.clear();
}
-/// Gets latency information for \p Inst from the itinerary
-/// scheduling model, based on \p DC information.
-/// \return The maximum expected latency over all the operands or -1
-/// if no information is available.
-static std::optional<int> getItineraryLatency(const MCSubtargetInfo *STI,
- const MCInstrInfo *MCII,
- const MCInst &Inst) {
- llvm::StringRef CPU = STI->getCPU();
-
- // Check if we have a CPU to get the itinerary information.
- if (CPU.empty())
- return std::nullopt;
-
- // Get itinerary information.
- InstrItineraryData IID = STI->getInstrItineraryForCPU(CPU);
- // Get the scheduling class of the requested instruction.
- const MCInstrDesc& Desc = MCII->get(Inst.getOpcode());
- unsigned SCClass = Desc.getSchedClass();
-
- unsigned Latency = 0;
-
- for (unsigned Idx = 0, IdxEnd = Inst.getNumOperands(); Idx != IdxEnd; ++Idx)
- if (std::optional<unsigned> OperCycle = IID.getOperandCycle(SCClass, Idx))
- Latency = std::max(Latency, *OperCycle);
-
- return int(Latency);
-}
-
-/// Gets latency information for \p Inst, based on \p DC information.
-/// \return The maximum expected latency over all the definitions or -1
-/// if no information is available.
-static std::optional<int> getLatency(const MCSubtargetInfo *STI, const MCInstrInfo *MCII, const MCInst &Inst) {
- // Try to compute scheduling information.
- const MCSchedModel &SCModel = STI->getSchedModel();
-
- // Check if we have a scheduling model for instructions.
- if (!SCModel.hasInstrSchedModel())
- // Try to fall back to the itinerary model if the scheduling model doesn't
- // have a scheduling table. Note the default does not have a table.
- return getItineraryLatency(STI, MCII, Inst);
-
- // Get the scheduling class of the requested instruction.
- const MCInstrDesc &Desc = MCII->get(Inst.getOpcode());
- unsigned SCClass = Desc.getSchedClass();
- int Latency = SCModel.computeInstrLatency(*STI, SCClass);
- if (Latency <= 0)
- return std::nullopt;
- return Latency;
-}
-
/// Emits latency information in DC->CommentStream for \p Inst, based
/// on the information available in \p DC.
static void emitLatency(LLVMDisasmContext *DC, const MCInst &Inst) {
const MCSubtargetInfo *STI = DC->getSubtargetInfo();
const MCInstrInfo *MCII = DC->getInstrInfo();
- std::optional<int> Latency = getLatency(STI, MCII, Inst);
- if (!Latency)
- return;
+ const MCSchedModel &SCModel = STI->getSchedModel();
+ int Latency = SCModel.computeInstrLatency(*STI, *MCII, Inst);
// Report only interesting latencies.
- if (*Latency < 2)
+ if (Latency < 2)
return;
- DC->CommentStream << "Latency: " << *Latency << '\n';
+ DC->CommentStream << "Latency: " << Latency << '\n';
}
//
diff --git a/llvm/lib/MC/MCSchedule.cpp b/llvm/lib/MC/MCSchedule.cpp
index 4f7125864c5a01..c0e0fa49eccad9 100644
--- a/llvm/lib/MC/MCSchedule.cpp
+++ b/llvm/lib/MC/MCSchedule.cpp
@@ -66,9 +66,44 @@ int MCSchedModel::computeInstrLatency(const MCSubtargetInfo &STI,
llvm_unreachable("unsupported variant scheduling class");
}
+/// Gets latency information for \p Inst from the itinerary
+/// scheduling model.
+/// \return The maximum expected latency over all the operands or -1
+/// if no information is available.
+static int getItineraryLatency(const MCSubtargetInfo &STI,
+ const MCInstrInfo &MCII, const MCInst &Inst) {
+ static const int NoInformationAvailable = -1;
+
+ llvm::StringRef CPU = STI.getCPU();
+
+ // Check if we have a CPU to get the itinerary information.
+ if (CPU.empty())
+ return NoInformationAvailable;
+
+ // Get itinerary information.
+ InstrItineraryData IID = STI.getInstrItineraryForCPU(CPU);
+ // Get the scheduling class of the requested instruction.
+ const MCInstrDesc &Desc = MCII.get(Inst.getOpcode());
+ unsigned SCClass = Desc.getSchedClass();
+
+ unsigned Latency = 0;
+
+ for (unsigned Idx = 0, IdxEnd = Inst.getNumOperands(); Idx != IdxEnd; ++Idx)
+ if (std::optional<unsigned> OperCycle = IID.getOperandCycle(SCClass, Idx))
+ Latency = std::max(Latency, *OperCycle);
+
+ return int(Latency);
+}
+
int MCSchedModel::computeInstrLatency(const MCSubtargetInfo &STI,
const MCInstrInfo &MCII,
const MCInst &Inst) const {
+ // Check if we have a scheduling model for instructions.
+ if (!hasInstrSchedModel())
+ // Try to fall back to the itinerary model if the scheduling model doesn't
+ // have a scheduling table. Note the default does not have a table.
+ return getItineraryLatency(STI, MCII, Inst);
+
unsigned SchedClass = MCII.get(Inst.getOpcode()).getSchedClass();
const MCSchedClassDesc *SCDesc = getSchedClassDesc(SchedClass);
if (!SCDesc->isValid())
>From 7622e083b7734666e6cf12ddca7911ea2a1d830a Mon Sep 17 00:00:00 2001
From: Jon Roelofs <jonathan_roelofs at apple.com>
Date: Fri, 25 Oct 2024 11:02:30 -0700
Subject: [PATCH 8/8] unify getLatency between Disassembler / AsmPrinter
---
llvm/include/llvm/MC/MCSchedule.h | 72 +++++++++++++++++++++-
llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 65 +++----------------
llvm/lib/MC/MCSchedule.cpp | 53 +---------------
3 files changed, 81 insertions(+), 109 deletions(-)
diff --git a/llvm/include/llvm/MC/MCSchedule.h b/llvm/include/llvm/MC/MCSchedule.h
index 5a6471ac1c892a..6adb83a0ecda93 100644
--- a/llvm/include/llvm/MC/MCSchedule.h
+++ b/llvm/include/llvm/MC/MCSchedule.h
@@ -14,9 +14,11 @@
#ifndef LLVM_MC_MCSCHEDULE_H
#define LLVM_MC_MCSCHEDULE_H
-#include "llvm/Config/llvm-config.h"
-#include "llvm/Support/DataTypes.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/MC/MCInstrDesc.h"
+#include "llvm/Support/ErrorHandling.h"
#include <cassert>
+#include <optional>
namespace llvm {
@@ -25,6 +27,7 @@ struct InstrItinerary;
class MCSubtargetInfo;
class MCInstrInfo;
class MCInst;
+class MCInstrDesc;
class InstrItineraryData;
/// Define a kind of processor resource that will be modeled by the scheduler.
@@ -369,9 +372,15 @@ struct MCSchedModel {
const MCSchedClassDesc &SCDesc);
int computeInstrLatency(const MCSubtargetInfo &STI, unsigned SClass) const;
+
int computeInstrLatency(const MCSubtargetInfo &STI, const MCInstrInfo &MCII,
const MCInst &Inst) const;
+ template <typename MCSubtargetInfo, typename MCInstrInfo,
+ typename InstrItineraryData, typename MCInstOrMachineInstr>
+ int computeInstrLatency(const MCSubtargetInfo &STI, const MCInstrInfo &MCII,
+ const MCInstOrMachineInstr &Inst) const;
+
// Returns the reciprocal throughput information from a MCSchedClassDesc.
static double
getReciprocalThroughput(const MCSubtargetInfo &STI,
@@ -393,6 +402,65 @@ struct MCSchedModel {
static const MCSchedModel Default;
};
+// The first three are only template'd arguments so we can get away with leaving
+// them as incomplete types below. The third is a template over
+// MCInst/MachineInstr so as to avoid a layering violation here that would make
+// the MC layer depend on CodeGen.
+template <typename MCSubtargetInfo, typename MCInstrInfo,
+ typename InstrItineraryData, typename MCInstOrMachineInstr>
+int MCSchedModel::computeInstrLatency(const MCSubtargetInfo &STI,
+ const MCInstrInfo &MCII,
+ const MCInstOrMachineInstr &Inst) const {
+ static const int NoInformationAvailable = -1;
+ // Check if we have a scheduling model for instructions.
+ if (!hasInstrSchedModel()) {
+ // Try to fall back to the itinerary model if the scheduling model doesn't
+ // have a scheduling table. Note the default does not have a table.
+
+ llvm::StringRef CPU = STI.getCPU();
+
+ // Check if we have a CPU to get the itinerary information.
+ if (CPU.empty())
+ return NoInformationAvailable;
+
+ // Get itinerary information.
+ InstrItineraryData IID = STI.getInstrItineraryForCPU(CPU);
+ // Get the scheduling class of the requested instruction.
+ const MCInstrDesc &Desc = MCII.get(Inst.getOpcode());
+ unsigned SCClass = Desc.getSchedClass();
+
+ unsigned Latency = 0;
+
+ for (unsigned Idx = 0, IdxEnd = Inst.getNumOperands(); Idx != IdxEnd; ++Idx)
+ if (std::optional<unsigned> OperCycle = IID.getOperandCycle(SCClass, Idx))
+ Latency = std::max(Latency, *OperCycle);
+
+ return int(Latency);
+ }
+
+ unsigned SchedClass = MCII.get(Inst.getOpcode()).getSchedClass();
+ const MCSchedClassDesc *SCDesc = getSchedClassDesc(SchedClass);
+ if (!SCDesc->isValid())
+ return 0;
+
+ if constexpr (std::is_same_v<MCInstOrMachineInstr, MCInst>) {
+ unsigned CPUID = getProcessorID();
+ while (SCDesc->isVariant()) {
+ SchedClass =
+ STI.resolveVariantSchedClass(SchedClass, &Inst, &MCII, CPUID);
+ SCDesc = getSchedClassDesc(SchedClass);
+ }
+
+ if (SchedClass)
+ return MCSchedModel::computeInstrLatency(STI, *SCDesc);
+
+ llvm_unreachable("unsupported variant scheduling class");
+ } else if (SchedClass)
+ return MCSchedModel::computeInstrLatency(STI, SchedClass);
+
+ return NoInformationAvailable;
+}
+
} // namespace llvm
#endif
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index c5045381271ab0..b1e15e492d230a 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -91,6 +91,7 @@
#include "llvm/MC/MCDirectives.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCSchedule.h"
#include "llvm/MC/MCSection.h"
#include "llvm/MC/MCSectionCOFF.h"
#include "llvm/MC/MCSectionELF.h"
@@ -1087,58 +1088,6 @@ void AsmPrinter::emitFunctionEntryLabel() {
}
}
-/// Gets latency information for \p Inst from the itinerary
-/// scheduling model.
-/// \return The maximum expected latency over all the operands or -1
-/// if no information is available.
-static std::optional<int> getItineraryLatency(const MCSubtargetInfo *STI,
- const MCInstrInfo *MCII,
- const MachineInstr &MI) {
- llvm::StringRef CPU = STI->getCPU();
-
- // Check if we have a CPU to get the itinerary information.
- if (CPU.empty())
- return std::nullopt;
-
- // Get itinerary information.
- InstrItineraryData IID = STI->getInstrItineraryForCPU(CPU);
- // Get the scheduling class of the requested instruction.
- const MCInstrDesc &Desc = MCII->get(MI.getOpcode());
- unsigned SCClass = Desc.getSchedClass();
-
- unsigned Latency = 0;
-
- for (unsigned Idx = 0, IdxEnd = MI.getNumOperands(); Idx != IdxEnd; ++Idx)
- if (std::optional<unsigned> OperCycle = IID.getOperandCycle(SCClass, Idx))
- Latency = std::max(Latency, *OperCycle);
-
- return int(Latency);
-}
-
-/// Gets latency information for \p Inst.
-/// \return The maximum expected latency over all the definitions or -1
-/// if no information is available.
-static std::optional<int> getLatency(const MCSubtargetInfo *STI,
- const MCInstrInfo *MCII,
- const MachineInstr &MI) {
- // Try to compute scheduling information.
- const MCSchedModel &SCModel = STI->getSchedModel();
-
- // Check if we have a scheduling model for instructions.
- if (!SCModel.hasInstrSchedModel())
- // Try to fall back to the itinerary model if the scheduling model doesn't
- // have a scheduling table. Note the default does not have a table.
- return getItineraryLatency(STI, MCII, MI);
-
- // Get the scheduling class of the requested instruction.
- const MCInstrDesc &Desc = MCII->get(MI.getOpcode());
- unsigned SCClass = Desc.getSchedClass();
- int Latency = SCModel.computeInstrLatency(*STI, SCClass);
- if (Latency <= 0)
- return std::nullopt;
- return Latency;
-}
-
/// emitComments - Pretty-print comments for instructions.
static void emitComments(const MachineInstr &MI, const MCSubtargetInfo *STI,
raw_ostream &CommentOS) {
@@ -1172,11 +1121,13 @@ static void emitComments(const MachineInstr &MI, const MCSubtargetInfo *STI,
if (PrintLatency) {
const TargetInstrInfo *TII = MF->getSubtarget().getInstrInfo();
- if (auto Latency = getLatency(STI, TII, MI)) {
- // Report only interesting latencies.
- if (1 < *Latency)
- CommentOS << " Latency: " << *Latency << "\n";
- }
+ const MCSchedModel &SCModel = STI->getSchedModel();
+ int Latency = SCModel.computeInstrLatency<MCSubtargetInfo, MCInstrInfo,
+ InstrItineraryData, MachineInstr>(
+ *STI, *TII, MI);
+ // Report only interesting latencies.
+ if (1 < Latency)
+ CommentOS << " Latency: " << Latency << "\n";
}
}
diff --git a/llvm/lib/MC/MCSchedule.cpp b/llvm/lib/MC/MCSchedule.cpp
index c0e0fa49eccad9..acc0711a0652e4 100644
--- a/llvm/lib/MC/MCSchedule.cpp
+++ b/llvm/lib/MC/MCSchedule.cpp
@@ -66,59 +66,12 @@ int MCSchedModel::computeInstrLatency(const MCSubtargetInfo &STI,
llvm_unreachable("unsupported variant scheduling class");
}
-/// Gets latency information for \p Inst from the itinerary
-/// scheduling model.
-/// \return The maximum expected latency over all the operands or -1
-/// if no information is available.
-static int getItineraryLatency(const MCSubtargetInfo &STI,
- const MCInstrInfo &MCII, const MCInst &Inst) {
- static const int NoInformationAvailable = -1;
-
- llvm::StringRef CPU = STI.getCPU();
-
- // Check if we have a CPU to get the itinerary information.
- if (CPU.empty())
- return NoInformationAvailable;
-
- // Get itinerary information.
- InstrItineraryData IID = STI.getInstrItineraryForCPU(CPU);
- // Get the scheduling class of the requested instruction.
- const MCInstrDesc &Desc = MCII.get(Inst.getOpcode());
- unsigned SCClass = Desc.getSchedClass();
-
- unsigned Latency = 0;
-
- for (unsigned Idx = 0, IdxEnd = Inst.getNumOperands(); Idx != IdxEnd; ++Idx)
- if (std::optional<unsigned> OperCycle = IID.getOperandCycle(SCClass, Idx))
- Latency = std::max(Latency, *OperCycle);
-
- return int(Latency);
-}
-
int MCSchedModel::computeInstrLatency(const MCSubtargetInfo &STI,
const MCInstrInfo &MCII,
const MCInst &Inst) const {
- // Check if we have a scheduling model for instructions.
- if (!hasInstrSchedModel())
- // Try to fall back to the itinerary model if the scheduling model doesn't
- // have a scheduling table. Note the default does not have a table.
- return getItineraryLatency(STI, MCII, Inst);
-
- unsigned SchedClass = MCII.get(Inst.getOpcode()).getSchedClass();
- const MCSchedClassDesc *SCDesc = getSchedClassDesc(SchedClass);
- if (!SCDesc->isValid())
- return 0;
-
- unsigned CPUID = getProcessorID();
- while (SCDesc->isVariant()) {
- SchedClass = STI.resolveVariantSchedClass(SchedClass, &Inst, &MCII, CPUID);
- SCDesc = getSchedClassDesc(SchedClass);
- }
-
- if (SchedClass)
- return MCSchedModel::computeInstrLatency(STI, *SCDesc);
-
- llvm_unreachable("unsupported variant scheduling class");
+ return MCSchedModel::computeInstrLatency<MCSubtargetInfo, MCInstrInfo,
+ InstrItineraryData, MCInst>(
+ STI, MCII, Inst);
}
double
More information about the llvm-commits
mailing list