Skip to content

Commit aa94f41

Browse files
[MCA] New option -scheduling-info
Outputs micro ops, latency, bypass latency, throughput, llvm opcode name, used resources and parsed assembly instruction with comments. This option is used better check scheduling info when TableGen is modified. Information like Throughput (not reverse throughput) and bypass latency help to compare with micro architecture documentation. LLVM Opcode name help to find right instruction regexp to fix TableGen Scheduling Info. Example: Input: abs D20, D11 // ABS <V><d>, <V><n> \\ ASIMD arith, basic \\ 1 2 2 4.0 V1UnitV Output: 1 2 2 4.00 V1UnitV ABSv1i64 abs d20, d11 // ABS <V><d>, <V><n> \\ ASIMD arith, basic \\ 1 2 2 4.0 V1UnitV
1 parent 24f0901 commit aa94f41

File tree

7 files changed

+4127
-3867
lines changed

7 files changed

+4127
-3867
lines changed

llvm/docs/CommandGuide/llvm-mca.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,20 @@ option specifies "``-``", then the output will also be sent to standard output.
170170
Enable extra scheduler statistics. This view collects and analyzes instruction
171171
issue events. This view is disabled by default.
172172

173+
.. option:: -scheduling-info
174+
175+
Enable scheduling info view. This view reports scheduling information defined
176+
in LLVM target description in the form:
177+
uOps | Latency | Bypass Latency | Throughput | LLVM OpcodeName | Resources
178+
units | assembly instruction and its comment (// or /* */) if defined.
179+
It allows to compare scheduling info with architecture documents and fix them
180+
in target description by fixing InstrRW for the reported LLVM opcode.
181+
Scheduling information can be defined in the same order in each instruction
182+
comments to check easily reported and reference scheduling information.
183+
Suggested information in comment:
184+
``// <architecture instruction form> \\ <scheduling documentation title> \\
185+
<uOps>, <Latency>, <Bypass Latency>, <Throughput>, <Resources units>``
186+
173187
.. option:: -retire-stats
174188

175189
Enable extra retire control unit statistics. This view is disabled by default.

llvm/include/llvm/MC/MCSchedule.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,10 @@ struct MCSchedModel {
402402
static unsigned getForwardingDelayCycles(ArrayRef<MCReadAdvanceEntry> Entries,
403403
unsigned WriteResourceIdx = 0);
404404

405+
/// Returns the bypass delay cycle for the maximum latency write cycle
406+
static unsigned getBypassDelayCycles(const MCSubtargetInfo &STI,
407+
const MCSchedClassDesc &SCDesc);
408+
405409
/// Returns the default initialized model.
406410
static const MCSchedModel Default;
407411
};

llvm/lib/MC/MCSchedule.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,3 +174,39 @@ MCSchedModel::getForwardingDelayCycles(ArrayRef<MCReadAdvanceEntry> Entries,
174174

175175
return std::abs(DelayCycles);
176176
}
177+
178+
unsigned MCSchedModel::getBypassDelayCycles(const MCSubtargetInfo &STI,
179+
const MCSchedClassDesc &SCDesc) {
180+
181+
ArrayRef<MCReadAdvanceEntry> Entries = STI.getReadAdvanceEntries(SCDesc);
182+
if (Entries.empty())
183+
return 0;
184+
185+
unsigned Latency = 0;
186+
unsigned MaxLatency = 0;
187+
unsigned WriteResourceID = 0;
188+
unsigned DefEnd = SCDesc.NumWriteLatencyEntries;
189+
190+
for (unsigned DefIdx = 0; DefIdx != DefEnd; ++DefIdx) {
191+
// Lookup the definition's write latency in SubtargetInfo.
192+
const MCWriteLatencyEntry *WLEntry =
193+
STI.getWriteLatencyEntry(&SCDesc, DefIdx);
194+
unsigned Cycles = (unsigned)WLEntry->Cycles;
195+
// Invalid latency. Consider 0 cycle latency
196+
if (WLEntry->Cycles < 0)
197+
Cycles = 0;
198+
if (Cycles > Latency) {
199+
MaxLatency = Cycles;
200+
WriteResourceID = WLEntry->WriteResourceID;
201+
}
202+
Latency = MaxLatency;
203+
}
204+
205+
for (const MCReadAdvanceEntry &E : Entries) {
206+
if (E.WriteResourceID == WriteResourceID)
207+
return E.Cycles;
208+
}
209+
210+
// Unable to find WriteResourceID in MCReadAdvanceEntry Entries
211+
return 0;
212+
}

llvm/test/tools/llvm-mca/AArch64/Neoverse/V1-sve-instructions.s

Lines changed: 3891 additions & 3858 deletions
Large diffs are not rendered by default.

llvm/tools/llvm-mca/Views/InstructionInfoView.cpp

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,122 @@
1414
#include "Views/InstructionInfoView.h"
1515
#include "llvm/Support/FormattedStream.h"
1616
#include "llvm/Support/JSON.h"
17+
#include "llvm/Support/WithColor.h"
1718

1819
namespace llvm {
1920
namespace mca {
2021

22+
void InstructionInfoView::getComment(const MCInst &MCI,
23+
std::string &CommentString) const {
24+
StringRef s = MCI.getLoc().getPointer();
25+
std::string InstrStr;
26+
size_t pos = 0, pos_cmt = 0;
27+
28+
// Recognized comments are after assembly instructions on the same line.
29+
// It is usefull to add in comment scheduling information from architecture
30+
// specification.
31+
// '#' comment mark is not supported by llvm-mca
32+
33+
CommentString = "";
34+
if ((pos = s.find("\n")) != std::string::npos) {
35+
InstrStr = s.substr(0, pos);
36+
// C style comment
37+
if (((pos_cmt = InstrStr.find("/*")) != std::string::npos) &&
38+
((pos = InstrStr.find("*/")) != std::string::npos)) {
39+
CommentString = InstrStr.substr(pos_cmt, pos);
40+
return;
41+
}
42+
// C++ style comment
43+
if ((pos_cmt = InstrStr.find("//")) != std::string::npos) {
44+
CommentString = InstrStr.substr(pos_cmt, pos);
45+
return;
46+
}
47+
}
48+
return;
49+
}
50+
51+
void InstructionInfoView::printSchedulingInfoView(raw_ostream &OS) const {
52+
std::string Buffer;
53+
std::string CommentString;
54+
raw_string_ostream TempStream(Buffer);
55+
formatted_raw_ostream FOS(TempStream);
56+
57+
ArrayRef<MCInst> Source = getSource();
58+
if (!Source.size())
59+
return;
60+
61+
IIVDVec IIVD(Source.size());
62+
collectData(IIVD);
63+
64+
FOS << "\n\nResources:\n";
65+
const MCSchedModel &SM = getSubTargetInfo().getSchedModel();
66+
for (unsigned I = 1, ResourceIndex = 0, E = SM.getNumProcResourceKinds();
67+
I < E; ++I) {
68+
const MCProcResourceDesc &ProcResource = *SM.getProcResource(I);
69+
unsigned NumUnits = ProcResource.NumUnits;
70+
// Skip invalid resources with zero units.
71+
if (!NumUnits)
72+
continue;
73+
74+
FOS << '[' << ResourceIndex << ']';
75+
FOS.PadToColumn(6);
76+
FOS << "- " << ProcResource.Name << ':' << NumUnits;
77+
if (ProcResource.SubUnitsIdxBegin) {
78+
FOS.PadToColumn(20);
79+
for (unsigned U = 0; U < NumUnits; ++U) {
80+
FOS << SM.getProcResource(ProcResource.SubUnitsIdxBegin[U])->Name;
81+
if ((U + 1) < NumUnits) {
82+
FOS << ", ";
83+
}
84+
}
85+
}
86+
FOS << '\n';
87+
ResourceIndex++;
88+
}
89+
90+
FOS << "\n\nScheduling Info:\n";
91+
FOS << "[1]: #uOps\n[2]: Latency\n[3]: Bypass Latency\n"
92+
<< "[4]: Throughput\n[5]: Resources\n"
93+
<< "[6]: LLVM OpcodeName\n[7]: Instruction\n"
94+
<< "[8]: Comment if any\n\n";
95+
96+
// paddings for each scheduling info output. Start at [2]
97+
std::vector<unsigned> paddings = {7, 12, 18, 27, 94, 113, 150};
98+
for (unsigned i = 0; i < paddings.size(); i++) {
99+
FOS << "[" << i + 1 << "]";
100+
FOS.PadToColumn(paddings[i]);
101+
}
102+
FOS << "[" << paddings.size() + 1 << "]\n";
103+
104+
for (const auto &[Index, IIVDEntry, Inst] : enumerate(IIVD, Source)) {
105+
getComment(Inst, CommentString);
106+
107+
FOS << " " << IIVDEntry.NumMicroOpcodes;
108+
FOS.PadToColumn(paddings[0]);
109+
FOS << " " << IIVDEntry.Latency;
110+
FOS.PadToColumn(paddings[1]);
111+
FOS << " " << IIVDEntry.Bypass;
112+
FOS.PadToColumn(paddings[2]);
113+
if (IIVDEntry.RThroughput) {
114+
double RT = 1.0 / *IIVDEntry.RThroughput;
115+
FOS << " " << format("%.2f", RT);
116+
} else {
117+
FOS << " -";
118+
}
119+
FOS.PadToColumn(paddings[3]);
120+
FOS << " " << IIVDEntry.Resources;
121+
FOS.PadToColumn(paddings[4]);
122+
FOS << " " << IIVDEntry.OpcodeName;
123+
FOS.PadToColumn(paddings[5]);
124+
FOS << " " << printInstructionString(Inst);
125+
FOS.PadToColumn(paddings[6]);
126+
FOS << CommentString << '\n';
127+
}
128+
129+
FOS.flush();
130+
OS << Buffer;
131+
}
132+
21133
void InstructionInfoView::printView(raw_ostream &OS) const {
22134
std::string Buffer;
23135
raw_string_ostream TempStream(Buffer);
@@ -29,6 +141,18 @@ void InstructionInfoView::printView(raw_ostream &OS) const {
29141
IIVDVec IIVD(Source.size());
30142
collectData(IIVD);
31143

144+
if (PrintSchedulingInfo) {
145+
if (PrintEncodings)
146+
WithColor::warning()
147+
<< "No encodings printed when -scheduling-info option enabled.\n";
148+
if (PrintBarriers)
149+
WithColor::warning()
150+
<< "No barrier printed when -scheduling-info option enabled.\n";
151+
152+
printSchedulingInfoView(OS);
153+
return;
154+
}
155+
32156
TempStream << "\n\nInstruction Info:\n";
33157
TempStream << "[1]: #uOps\n[2]: Latency\n[3]: RThroughput\n"
34158
<< "[4]: MayLoad\n[5]: MayStore\n[6]: HasSideEffects (U)\n";
@@ -141,6 +265,34 @@ void InstructionInfoView::collectData(
141265
IIVDEntry.mayLoad = MCDesc.mayLoad();
142266
IIVDEntry.mayStore = MCDesc.mayStore();
143267
IIVDEntry.hasUnmodeledSideEffects = MCDesc.hasUnmodeledSideEffects();
268+
269+
if (PrintSchedulingInfo) {
270+
// Get latency with bypass
271+
IIVDEntry.Bypass =
272+
IIVDEntry.Latency - MCSchedModel::getBypassDelayCycles(STI, SCDesc);
273+
IIVDEntry.OpcodeName = (std::string)MCII.getName(Inst.getOpcode());
274+
raw_string_ostream TempStream(IIVDEntry.Resources);
275+
const MCWriteProcResEntry *Index = STI.getWriteProcResBegin(&SCDesc);
276+
const MCWriteProcResEntry *Last = STI.getWriteProcResEnd(&SCDesc);
277+
auto sep = "";
278+
for (; Index != Last; ++Index) {
279+
if (!Index->ReleaseAtCycle)
280+
continue;
281+
const MCProcResourceDesc *MCProc =
282+
SM.getProcResource(Index->ProcResourceIdx);
283+
if (Index->ReleaseAtCycle > 1) {
284+
// Output ReleaseAtCycle between [] if not 1 (default)
285+
// This is to be able to evaluate throughput.
286+
// See getReciprocalThroughput in MCSchedule.cpp
287+
// TODO: report AcquireAtCycle to check this scheduling info.
288+
TempStream << sep << format("%s[%d]", MCProc->Name, Index->ReleaseAtCycle);
289+
} else {
290+
TempStream << sep << format("%s", MCProc->Name);
291+
}
292+
sep = ",";
293+
}
294+
TempStream.flush();
295+
}
144296
}
145297
}
146298

llvm/tools/llvm-mca/Views/InstructionInfoView.h

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ class InstructionInfoView : public InstructionView {
5656
CodeEmitter &CE;
5757
bool PrintEncodings;
5858
bool PrintBarriers;
59+
bool PrintSchedulingInfo;
5960
using UniqueInst = std::unique_ptr<Instruction>;
6061
ArrayRef<UniqueInst> LoweredInsts;
6162
const InstrumentManager &IM;
@@ -65,29 +66,43 @@ class InstructionInfoView : public InstructionView {
6566

6667
struct InstructionInfoViewData {
6768
unsigned NumMicroOpcodes = 0;
69+
// Latency + ForwardingDelayCycles: negative ReadAdvance
6870
unsigned Latency = 0;
71+
// ReadAvance Bypasses cycles: Latency - ReadAdvance (positive value)
72+
unsigned Bypass = 0;
6973
std::optional<double> RThroughput = 0.0;
7074
bool mayLoad = false;
7175
bool mayStore = false;
7276
bool hasUnmodeledSideEffects = false;
77+
std::string OpcodeName = "";
78+
std::string Resources = "";
7379
};
7480
using IIVDVec = SmallVector<InstructionInfoViewData, 16>;
7581

7682
/// Place the data into the array of InstructionInfoViewData IIVD.
7783
void collectData(MutableArrayRef<InstructionInfoViewData> IIVD) const;
7884

85+
/// Extract comment (//, /* */) from the source assembly placed just after
86+
/// instruction.
87+
void getComment(const llvm::MCInst &Inst, std::string &CommentString) const;
88+
/// Print Scheduling Info to avoid mixing too much options
89+
void printSchedulingInfoView(raw_ostream &OS) const;
90+
7991
public:
8092
InstructionInfoView(const llvm::MCSubtargetInfo &ST,
8193
const llvm::MCInstrInfo &II, CodeEmitter &C,
8294
bool ShouldPrintEncodings, llvm::ArrayRef<llvm::MCInst> S,
8395
llvm::MCInstPrinter &IP,
8496
ArrayRef<UniqueInst> LoweredInsts,
85-
bool ShouldPrintBarriers, const InstrumentManager &IM,
86-
const InstToInstrumentsT &InstToInstruments)
97+
bool ShouldPrintBarriers, bool ShouldPrintSchedulingInfo,
98+
const InstrumentManager &IM,
99+
const InstToInstrumentsT &InstToInstruments)
87100
: InstructionView(ST, IP, S), MCII(II), CE(C),
88101
PrintEncodings(ShouldPrintEncodings),
89-
PrintBarriers(ShouldPrintBarriers), LoweredInsts(LoweredInsts), IM(IM),
90-
InstToInstruments(InstToInstruments) {}
102+
PrintBarriers(ShouldPrintBarriers),
103+
PrintSchedulingInfo(ShouldPrintSchedulingInfo),
104+
LoweredInsts(LoweredInsts), IM(IM),
105+
InstToInstruments(InstToInstruments) {}
91106

92107
void printView(llvm::raw_ostream &OS) const override;
93108
StringRef getNameAsString() const override { return "InstructionInfoView"; }

llvm/tools/llvm-mca/llvm-mca.cpp

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,11 @@ static cl::opt<bool> ShowBarriers(
259259
cl::desc("Print memory barrier information in the instruction info view"),
260260
cl::cat(ViewOptions), cl::init(false));
261261

262+
static cl::opt<bool> ShowSchedulingInfo(
263+
"scheduling-info",
264+
cl::desc("Print the instruction scheduling information in the instruction info view"),
265+
cl::cat(ViewOptions), cl::init(false));
266+
262267
static cl::opt<bool> DisableCustomBehaviour(
263268
"disable-cb",
264269
cl::desc(
@@ -678,12 +683,13 @@ int main(int argc, char **argv) {
678683

679684
// Create the views for this pipeline, execute, and emit a report.
680685
if (PrintInstructionInfoView) {
681-
Printer.addView(std::make_unique<mca::InstructionInfoView>(
682-
*STI, *MCII, CE, ShowEncoding, Insts, *IP, LoweredSequence,
683-
ShowBarriers, *IM, InstToInstruments));
686+
Printer.addView(std::make_unique<mca::InstructionInfoView>(
687+
*STI, *MCII, CE, ShowEncoding, Insts, *IP, LoweredSequence,
688+
ShowBarriers, ShowSchedulingInfo, *IM, InstToInstruments));
684689
}
690+
685691
Printer.addView(
686-
std::make_unique<mca::ResourcePressureView>(*STI, *IP, Insts));
692+
std::make_unique<mca::ResourcePressureView>(*STI, *IP, Insts));
687693

688694
if (!runPipeline(*P))
689695
return 1;
@@ -757,7 +763,7 @@ int main(int argc, char **argv) {
757763
if (PrintInstructionInfoView)
758764
Printer.addView(std::make_unique<mca::InstructionInfoView>(
759765
*STI, *MCII, CE, ShowEncoding, Insts, *IP, LoweredSequence,
760-
ShowBarriers, *IM, InstToInstruments));
766+
ShowBarriers, ShowSchedulingInfo, *IM, InstToInstruments));
761767

762768
// Fetch custom Views that are to be placed after the InstructionInfoView.
763769
// Refer to the comment paired with the CB->getStartViews(*IP, Insts); line

0 commit comments

Comments
 (0)