Skip to content

Commit 5e82ee5

Browse files
[RISCV][llvm-mca] Use LMUL Instruments to provide more accurate reports on RISCV
On x86 and AArch, SIMD instructions encode all of the scheduling information in the instruction itself. For example, VADD.I16 q0, q1, q2 is a neon instruction that operates on 16-bit integer elements stored in 128-bit Q registers, which leads to eight 16-bit lanes in parallel. This kind of information impacts how the instruction takes to execute and what dependencies this may cause. On RISCV however, the data that impacts scheduling is encoded in CSR registers such as vtype or vl, in addition with the instruction itself. But MCA does not track or use the data in these registers. This patch fixes this problem by introducing Instruments into MCA. * Replace `CodeRegions` with `AnalysisRegions` * Add `Instrument` and `InstrumentManager` * Add `InstrumentRegions` * Add RISCV Instrument and `InstrumentManager` * Parse `Instruments` in driver * Use instruments to override schedule class * RISCV use lmul instrument to override schedule class * Fix unit tests to pass empty instruments * Add -ignore-im clopt to disable this change Differential Revision: https://reviews.llvm.org/D137440
1 parent 2fb3e3c commit 5e82ee5

18 files changed

+969
-130
lines changed

llvm/docs/CommandGuide/llvm-mca.rst

Lines changed: 118 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,12 @@ option specifies "``-``", then the output will also be sent to standard output.
227227
detect any custom hazards or make any post processing modifications to
228228
instructions.
229229

230+
.. option:: -disable-im
231+
232+
Force usage of the generic InstrumentManager rather than using the target
233+
specific implementation. The generic class creates Instruments that provide
234+
no extra information, and InstrumentManager never overrides the default
235+
schedule class for a given instruction.
230236

231237
EXIT STATUS
232238
-----------
@@ -238,9 +244,9 @@ USING MARKERS TO ANALYZE SPECIFIC CODE BLOCKS
238244
---------------------------------------------
239245
:program:`llvm-mca` allows for the optional usage of special code comments to
240246
mark regions of the assembly code to be analyzed. A comment starting with
241-
substring ``LLVM-MCA-BEGIN`` marks the beginning of a code region. A comment
242-
starting with substring ``LLVM-MCA-END`` marks the end of a code region. For
243-
example:
247+
substring ``LLVM-MCA-BEGIN`` marks the beginning of an analysis region. A
248+
comment starting with substring ``LLVM-MCA-END`` marks the end of a region.
249+
For example:
244250

245251
.. code-block:: none
246252
@@ -251,9 +257,9 @@ example:
251257
If no user-defined region is specified, then :program:`llvm-mca` assumes a
252258
default region which contains every instruction in the input file. Every region
253259
is analyzed in isolation, and the final performance report is the union of all
254-
the reports generated for every code region.
260+
the reports generated for every analysis region.
255261

256-
Code regions can have names. For example:
262+
Analysis regions can have names. For example:
257263

258264
.. code-block:: none
259265
@@ -315,6 +321,91 @@ assembly is equivalent to the assembly generated in the absence of markers.
315321
The `Clang options to emit optimization reports <https://clang.llvm.org/docs/UsersManual.html#options-to-emit-optimization-reports>`_
316322
can also help in detecting missed optimizations.
317323

324+
INSTRUMENT REGIONS
325+
------------------
326+
327+
An InstrumentRegion describes a region of assembly code guarded by
328+
special LLVM-MCA comment directives.
329+
330+
.. code-block:: none
331+
332+
# LLVM-MCA-<INSTRUMENT_TYPE> <data>
333+
... ## asm
334+
335+
where `INSTRUMENT_TYPE` is a type defined by the target and expects
336+
to use `data`.
337+
338+
A comment starting with substring `LLVM-MCA-<INSTRUMENT_TYPE>`
339+
brings data into scope for llvm-mca to use in its analysis for
340+
all following instructions.
341+
342+
If a comment with the same `INSTRUMENT_TYPE` is found later in the
343+
instruction list, then the original InstrumentRegion will be
344+
automatically ended, and a new InstrumentRegion will begin.
345+
346+
If there are comments containing the different `INSTRUMENT_TYPE`,
347+
then both data sets remain available. In contrast with an AnalysisRegion,
348+
an InstrumentRegion does not need a comment to end the region.
349+
350+
Comments that are prefixed with `LLVM-MCA-` but do not correspond to
351+
a valid `INSTRUMENT_TYPE` for the target cause an error, except for
352+
`BEGIN` and `END`, since those correspond to AnalysisRegions. Comments
353+
that do not start with `LLVM-MCA-` are ignored by :program `llvm-mca`.
354+
355+
An instruction (a MCInst) is added to an InstrumentRegion R only
356+
if its location is in range [R.RangeStart, R.RangeEnd].
357+
358+
On RISCV targets, vector instructions have different behaviour depending
359+
on the LMUL. Code can be instrumented with a comment that takes the
360+
following form:
361+
362+
.. code-block:: none
363+
364+
# LLVM-MCA-RISCV-LMUL <M1|M2|M4|M8|MF2|MF4|MF8>
365+
366+
The RISCV InstrumentManager will override the schedule class for vector
367+
instructions to use the scheduling behaviour of its pseudo-instruction
368+
which is LMUL dependent. It makes sense to place RISCV instrument
369+
comments directly after `vset{i}vl{i}` instructions, although
370+
they can be placed anywhere in the program.
371+
372+
Example of program with no call to `vset{i}vl{i}`:
373+
374+
.. code-block:: none
375+
376+
# LLVM-MCA-RISCV-LMUL M2
377+
vadd.vv v2, v2, v2
378+
379+
Example of program with call to `vset{i}vl{i}`:
380+
381+
.. code-block:: none
382+
383+
vsetvli zero, a0, e8, m1, tu, mu
384+
# LLVM-MCA-RISCV-LMUL M1
385+
vadd.vv v2, v2, v2
386+
387+
Example of program with multiple calls to `vset{i}vl{i}`:
388+
389+
.. code-block:: none
390+
391+
vsetvli zero, a0, e8, m1, tu, mu
392+
# LLVM-MCA-RISCV-LMUL M1
393+
vadd.vv v2, v2, v2
394+
vsetvli zero, a0, e8, m8, tu, mu
395+
# LLVM-MCA-RISCV-LMUL M8
396+
vadd.vv v2, v2, v2
397+
398+
Example of program with call to `vsetvl`:
399+
400+
.. code-block:: none
401+
402+
vsetvl rd, rs1, rs2
403+
# LLVM-MCA-RISCV-LMUL M1
404+
vadd.vv v12, v12, v12
405+
vsetvl rd, rs1, rs2
406+
# LLVM-MCA-RISCV-LMUL M4
407+
vadd.vv v12, v12, v12
408+
318409
HOW LLVM-MCA WORKS
319410
------------------
320411

@@ -1024,6 +1115,28 @@ already have one, refer to an existing implementation to see how to set it
10241115
up. The classes are implemented within the target specific backend (for
10251116
example `/llvm/lib/Target/AMDGPU/MCA/`) so that they can access backend symbols.
10261117

1118+
Instrument Manager
1119+
""""""""""""""""""""""""""""""""""""
1120+
On certain architectures, scheduling information for certain instructions
1121+
do not contain all of the information required to identify the most precise
1122+
schedule class. For example, data that can have an impact on scheduling can
1123+
be stored in CSR registers.
1124+
1125+
One example of this is on RISCV, where values in registers such as `vtype`
1126+
and `vl` change the scheduling behaviour of vector instructions. Since MCA
1127+
does not keep track of the values in registers, instrument comments can
1128+
be used to specify these values.
1129+
1130+
InstrumentManager's main function is `getSchedClassID()` which has access
1131+
to the MCInst and all of the instruments that are active for that MCInst.
1132+
This function can use the instruments to override the schedule class of
1133+
the MCInst.
1134+
1135+
On RISCV, instrument comments containing LMUL information are used
1136+
by `getSchedClassID()` to map a vector instruction and the active
1137+
LMUL to the scheduling class of the pseudo-instruction that describes
1138+
that base instruction and the active LMUL.
1139+
10271140
Custom Views
10281141
""""""""""""""""""""""""""""""""""""
10291142
:program:`llvm-mca` comes with several Views such as the Timeline View and

llvm/include/llvm/MC/TargetRegistry.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ class TargetOptions;
6060
namespace mca {
6161
class CustomBehaviour;
6262
class InstrPostProcess;
63+
class InstrumentManager;
6364
struct SourceMgr;
6465
} // namespace mca
6566

@@ -134,6 +135,9 @@ mca::CustomBehaviour *createCustomBehaviour(const MCSubtargetInfo &STI,
134135
mca::InstrPostProcess *createInstrPostProcess(const MCSubtargetInfo &STI,
135136
const MCInstrInfo &MCII);
136137

138+
mca::InstrumentManager *createInstrumentManager(const MCSubtargetInfo &STI,
139+
const MCInstrInfo &MCII);
140+
137141
/// Target - Wrapper for Target specific information.
138142
///
139143
/// For registration purposes, this is a POD type so that targets can be
@@ -245,6 +249,10 @@ class Target {
245249
mca::InstrPostProcess *(*)(const MCSubtargetInfo &STI,
246250
const MCInstrInfo &MCII);
247251

252+
using InstrumentManagerCtorTy =
253+
mca::InstrumentManager *(*)(const MCSubtargetInfo &STI,
254+
const MCInstrInfo &MCII);
255+
248256
private:
249257
/// Next - The next registered target in the linked list, maintained by the
250258
/// TargetRegistry.
@@ -354,6 +362,10 @@ class Target {
354362
/// InstrPostProcess, if registered (default = nullptr).
355363
InstrPostProcessCtorTy InstrPostProcessCtorFn = nullptr;
356364

365+
/// InstrumentManagerCtorFn - Construction function for this target's
366+
/// InstrumentManager, if registered (default = nullptr).
367+
InstrumentManagerCtorTy InstrumentManagerCtorFn = nullptr;
368+
357369
public:
358370
Target() = default;
359371

@@ -706,6 +718,17 @@ class Target {
706718
return nullptr;
707719
}
708720

721+
/// createInstrumentManager - Create a target specific
722+
/// InstrumentManager. This class is used by llvm-mca and requires
723+
/// backend functionality.
724+
mca::InstrumentManager *
725+
createInstrumentManager(const MCSubtargetInfo &STI,
726+
const MCInstrInfo &MCII) const {
727+
if (InstrumentManagerCtorFn)
728+
return InstrumentManagerCtorFn(STI, MCII);
729+
return nullptr;
730+
}
731+
709732
/// @}
710733
};
711734

@@ -1078,6 +1101,21 @@ struct TargetRegistry {
10781101
T.InstrPostProcessCtorFn = Fn;
10791102
}
10801103

1104+
/// RegisterInstrumentManager - Register an InstrumentManager
1105+
/// implementation for the given target.
1106+
///
1107+
/// Clients are responsible for ensuring that registration doesn't occur
1108+
/// while another thread is attempting to access the registry. Typically
1109+
/// this is done by initializing all targets at program startup.
1110+
///
1111+
/// @param T - The target being registered.
1112+
/// @param Fn - A function to construct an InstrumentManager for the
1113+
/// target.
1114+
static void RegisterInstrumentManager(Target &T,
1115+
Target::InstrumentManagerCtorTy Fn) {
1116+
T.InstrumentManagerCtorFn = Fn;
1117+
}
1118+
10811119
/// @}
10821120
};
10831121

llvm/include/llvm/MCA/CustomBehaviour.h

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#ifndef LLVM_MCA_CUSTOMBEHAVIOUR_H
1919
#define LLVM_MCA_CUSTOMBEHAVIOUR_H
2020

21+
#include "llvm/ADT/SmallVector.h"
2122
#include "llvm/MC/MCInst.h"
2223
#include "llvm/MC/MCInstrInfo.h"
2324
#include "llvm/MC/MCSubtargetInfo.h"
@@ -114,6 +115,61 @@ class CustomBehaviour {
114115
getEndViews(llvm::MCInstPrinter &IP, llvm::ArrayRef<llvm::MCInst> Insts);
115116
};
116117

118+
class Instrument {
119+
/// The description of Instrument kind
120+
const StringRef Desc;
121+
122+
/// The instrumentation data
123+
const StringRef Data;
124+
125+
public:
126+
Instrument(StringRef Desc, StringRef Data) : Desc(Desc), Data(Data) {}
127+
128+
Instrument() = default;
129+
130+
virtual ~Instrument() = default;
131+
132+
StringRef getDesc() const { return Desc; }
133+
StringRef getData() const { return Data; }
134+
};
135+
136+
using SharedInstrument = std::shared_ptr<Instrument>;
137+
138+
/// This class allows targets to optionally customize the logic that resolves
139+
/// scheduling class IDs. Targets can use information encoded in Instrument
140+
/// objects to make more informed scheduling decisions.
141+
class InstrumentManager {
142+
protected:
143+
const MCSubtargetInfo &STI;
144+
const MCInstrInfo &MCII;
145+
146+
public:
147+
InstrumentManager(const MCSubtargetInfo &STI, const MCInstrInfo &MCII)
148+
: STI(STI), MCII(MCII) {}
149+
150+
virtual ~InstrumentManager() = default;
151+
152+
/// Returns true if llvm-mca should ignore instruments.
153+
virtual bool shouldIgnoreInstruments() const { return true; }
154+
155+
// Returns true if this supports processing Instrument with
156+
// Instrument.Desc equal to Type
157+
virtual bool supportsInstrumentType(StringRef Type) const { return false; }
158+
159+
/// Allocate an Instrument, and return a shared pointer to it.
160+
virtual SharedInstrument createInstrument(StringRef Desc, StringRef Data);
161+
162+
/// Given an MCInst and a vector of Instrument, a target can
163+
/// return a SchedClassID. This can be used by a subtarget to return a
164+
/// PseudoInstruction SchedClassID instead of the one that belongs to the
165+
/// BaseInstruction This can be useful when a BaseInstruction does not convey
166+
/// the correct scheduling information without additional data. By default,
167+
/// it returns the SchedClassID that belongs to MCI.
168+
virtual unsigned
169+
getSchedClassID(const MCInstrInfo &MCII, const MCInst &MCI,
170+
const SmallVector<SharedInstrument> &IVec) const;
171+
};
172+
117173
} // namespace mca
118174
} // namespace llvm
119175

llvm/include/llvm/MCA/InstrBuilder.h

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "llvm/MC/MCInstrInfo.h"
2020
#include "llvm/MC/MCRegisterInfo.h"
2121
#include "llvm/MC/MCSubtargetInfo.h"
22+
#include "llvm/MCA/CustomBehaviour.h"
2223
#include "llvm/MCA/Instruction.h"
2324
#include "llvm/MCA/Support.h"
2425
#include "llvm/Support/Error.h"
@@ -62,10 +63,18 @@ class InstrBuilder {
6263
const MCInstrInfo &MCII;
6364
const MCRegisterInfo &MRI;
6465
const MCInstrAnalysis *MCIA;
66+
const InstrumentManager &IM;
6567
SmallVector<uint64_t, 8> ProcResourceMasks;
6668

67-
DenseMap<unsigned short, std::unique_ptr<const InstrDesc>> Descriptors;
68-
DenseMap<const MCInst *, std::unique_ptr<const InstrDesc>> VariantDescriptors;
69+
// Key is the MCI.Opcode and SchedClassID the describe the value InstrDesc
70+
DenseMap<std::pair<unsigned short, unsigned>,
71+
std::unique_ptr<const InstrDesc>>
72+
Descriptors;
73+
74+
// Key is the MCIInst and SchedClassID the describe the value InstrDesc
75+
DenseMap<std::pair<const MCInst *, unsigned>,
76+
std::unique_ptr<const InstrDesc>>
77+
VariantDescriptors;
6978

7079
bool FirstCallInst;
7180
bool FirstReturnInst;
@@ -74,8 +83,12 @@ class InstrBuilder {
7483
llvm::function_ref<Instruction *(const InstrDesc &)>;
7584
InstRecycleCallback InstRecycleCB;
7685

77-
Expected<const InstrDesc &> createInstrDescImpl(const MCInst &MCI);
78-
Expected<const InstrDesc &> getOrCreateInstrDesc(const MCInst &MCI);
86+
Expected<const InstrDesc &>
87+
createInstrDescImpl(const MCInst &MCI,
88+
const SmallVector<SharedInstrument> &IVec);
89+
Expected<const InstrDesc &>
90+
getOrCreateInstrDesc(const MCInst &MCI,
91+
const SmallVector<SharedInstrument> &IVec);
7992

8093
InstrBuilder(const InstrBuilder &) = delete;
8194
InstrBuilder &operator=(const InstrBuilder &) = delete;
@@ -86,7 +99,8 @@ class InstrBuilder {
8699

87100
public:
88101
InstrBuilder(const MCSubtargetInfo &STI, const MCInstrInfo &MCII,
89-
const MCRegisterInfo &RI, const MCInstrAnalysis *IA);
102+
const MCRegisterInfo &RI, const MCInstrAnalysis *IA,
103+
const InstrumentManager &IM);
90104

91105
void clear() {
92106
Descriptors.clear();
@@ -99,7 +113,9 @@ class InstrBuilder {
99113
/// or null if there isn't any.
100114
void setInstRecycleCallback(InstRecycleCallback CB) { InstRecycleCB = CB; }
101115

102-
Expected<std::unique_ptr<Instruction>> createInstruction(const MCInst &MCI);
116+
Expected<std::unique_ptr<Instruction>>
117+
createInstruction(const MCInst &MCI,
118+
const SmallVector<SharedInstrument> &IVec);
103119
};
104120
} // namespace mca
105121
} // namespace llvm

llvm/lib/MCA/CustomBehaviour.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,5 +42,16 @@ CustomBehaviour::getEndViews(llvm::MCInstPrinter &IP,
4242
return std::vector<std::unique_ptr<View>>();
4343
}
4444

45+
SharedInstrument InstrumentManager::createInstrument(llvm::StringRef Desc,
46+
llvm::StringRef Data) {
47+
return std::make_shared<Instrument>(Desc, Data);
48+
}
49+
50+
unsigned InstrumentManager::getSchedClassID(
51+
const MCInstrInfo &MCII, const MCInst &MCI,
52+
const llvm::SmallVector<SharedInstrument> &IVec) const {
53+
return MCII.get(MCI.getOpcode()).getSchedClass();
54+
}
55+
4556
} // namespace mca
4657
} // namespace llvm

0 commit comments

Comments
 (0)