1 //===------------------- RISCVCustomBehaviour.cpp ---------------*-C++ -* -===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
10 /// This file implements methods from the RISCVCustomBehaviour class.
12 //===----------------------------------------------------------------------===//
14 #include "RISCVCustomBehaviour.h"
15 #include "MCTargetDesc/RISCVMCTargetDesc.h"
17 #include "TargetInfo/RISCVTargetInfo.h"
18 #include "llvm/MC/TargetRegistry.h"
19 #include "llvm/Support/Debug.h"
21 #define DEBUG_TYPE "llvm-mca-riscv-custombehaviour"
23 // This brings in a table with primary key of
24 // base instruction opcode and lmul and maps
25 // to the opcode of the pseudo instruction.
26 namespace RISCVVInversePseudosTable
{
28 using namespace llvm::RISCV
;
37 #define GET_RISCVVInversePseudosTable_IMPL
38 #define GET_RISCVVInversePseudosTable_DECL
39 #include "RISCVGenSearchableTables.inc"
41 } // end namespace RISCVVInversePseudosTable
46 const llvm::StringRef
RISCVLMULInstrument::DESC_NAME
= "RISCV-LMUL";
48 bool RISCVLMULInstrument::isDataValid(llvm::StringRef Data
) {
49 // Return true if not one of the valid LMUL strings
50 return StringSwitch
<bool>(Data
)
51 .Cases("M1", "M2", "M4", "M8", "MF2", "MF4", "MF8", true)
55 uint8_t RISCVLMULInstrument::getLMUL() const {
56 // assertion prevents us from needing llvm_unreachable in the StringSwitch
58 assert(isDataValid(getData()) &&
59 "Cannot get LMUL because invalid Data value");
60 // These are the LMUL values that are used in RISC-V tablegen
61 return StringSwitch
<uint8_t>(getData())
71 const llvm::StringRef
RISCVSEWInstrument::DESC_NAME
= "RISCV-SEW";
73 bool RISCVSEWInstrument::isDataValid(llvm::StringRef Data
) {
74 // Return true if not one of the valid SEW strings
75 return StringSwitch
<bool>(Data
)
76 .Cases("E8", "E16", "E32", "E64", true)
80 uint8_t RISCVSEWInstrument::getSEW() const {
81 // assertion prevents us from needing llvm_unreachable in the StringSwitch
83 assert(isDataValid(getData()) && "Cannot get SEW because invalid Data value");
84 // These are the LMUL values that are used in RISC-V tablegen
85 return StringSwitch
<uint8_t>(getData())
92 bool RISCVInstrumentManager::supportsInstrumentType(
93 llvm::StringRef Type
) const {
94 return Type
== RISCVLMULInstrument::DESC_NAME
||
95 Type
== RISCVSEWInstrument::DESC_NAME
;
99 RISCVInstrumentManager::createInstrument(llvm::StringRef Desc
,
100 llvm::StringRef Data
) {
101 if (Desc
== RISCVLMULInstrument::DESC_NAME
) {
102 if (!RISCVLMULInstrument::isDataValid(Data
)) {
103 LLVM_DEBUG(dbgs() << "RVCB: Bad data for instrument kind " << Desc
<< ": "
107 return std::make_unique
<RISCVLMULInstrument
>(Data
);
110 if (Desc
== RISCVSEWInstrument::DESC_NAME
) {
111 if (!RISCVSEWInstrument::isDataValid(Data
)) {
112 LLVM_DEBUG(dbgs() << "RVCB: Bad data for instrument kind " << Desc
<< ": "
116 return std::make_unique
<RISCVSEWInstrument
>(Data
);
119 LLVM_DEBUG(dbgs() << "RVCB: Unknown instrumentation Desc: " << Desc
<< '\n');
123 SmallVector
<UniqueInstrument
>
124 RISCVInstrumentManager::createInstruments(const MCInst
&Inst
) {
125 if (Inst
.getOpcode() == RISCV::VSETVLI
||
126 Inst
.getOpcode() == RISCV::VSETIVLI
) {
127 LLVM_DEBUG(dbgs() << "RVCB: Found VSETVLI and creating instrument for it: "
129 unsigned VTypeI
= Inst
.getOperand(2).getImm();
130 RISCVII::VLMUL VLMUL
= RISCVVType::getVLMUL(VTypeI
);
134 case RISCVII::LMUL_1
:
137 case RISCVII::LMUL_2
:
140 case RISCVII::LMUL_4
:
143 case RISCVII::LMUL_8
:
146 case RISCVII::LMUL_F2
:
149 case RISCVII::LMUL_F4
:
152 case RISCVII::LMUL_F8
:
155 case RISCVII::LMUL_RESERVED
:
156 llvm_unreachable("Cannot create instrument for LMUL_RESERVED");
158 SmallVector
<UniqueInstrument
> Instruments
;
159 Instruments
.emplace_back(
160 createInstrument(RISCVLMULInstrument::DESC_NAME
, LMUL
));
162 unsigned SEW
= RISCVVType::getSEW(VTypeI
);
178 llvm_unreachable("Cannot create instrument for SEW");
180 Instruments
.emplace_back(
181 createInstrument(RISCVSEWInstrument::DESC_NAME
, SEWStr
));
185 return SmallVector
<UniqueInstrument
>();
188 static std::pair
<uint8_t, uint8_t>
189 getEEWAndEMULForUnitStrideLoadStore(unsigned Opcode
, RISCVII::VLMUL LMUL
,
212 llvm_unreachable("Opcode is not a vector unit stride load nor store");
215 auto EMUL
= RISCVVType::getSameRatioLMUL(SEW
, LMUL
, EEW
);
217 llvm_unreachable("Invalid SEW or LMUL for new ratio");
218 return std::make_pair(EEW
, *EMUL
);
221 unsigned RISCVInstrumentManager::getSchedClassID(
222 const MCInstrInfo
&MCII
, const MCInst
&MCI
,
223 const llvm::SmallVector
<Instrument
*> &IVec
) const {
224 unsigned short Opcode
= MCI
.getOpcode();
225 unsigned SchedClassID
= MCII
.get(Opcode
).getSchedClass();
227 // Unpack all possible RISC-V instruments from IVec.
228 RISCVLMULInstrument
*LI
= nullptr;
229 RISCVSEWInstrument
*SI
= nullptr;
230 for (auto &I
: IVec
) {
231 if (I
->getDesc() == RISCVLMULInstrument::DESC_NAME
)
232 LI
= static_cast<RISCVLMULInstrument
*>(I
);
233 else if (I
->getDesc() == RISCVSEWInstrument::DESC_NAME
)
234 SI
= static_cast<RISCVSEWInstrument
*>(I
);
237 // Need LMUL or LMUL, SEW in order to override opcode. If no LMUL is provided,
238 // then no option to override.
241 dbgs() << "RVCB: Did not use instrumentation to override Opcode.\n");
244 uint8_t LMUL
= LI
->getLMUL();
246 // getBaseInfo works with (Opcode, LMUL, 0) if no SEW instrument,
247 // or (Opcode, LMUL, SEW) if SEW instrument is active, and depends on LMUL
248 // and SEW, or (Opcode, LMUL, 0) if does not depend on SEW.
249 uint8_t SEW
= SI
? SI
->getSEW() : 0;
251 const RISCVVInversePseudosTable::PseudoInfo
*RVV
= nullptr;
252 if (Opcode
== RISCV::VLM_V
|| Opcode
== RISCV::VSM_V
||
253 Opcode
== RISCV::VLE8_V
|| Opcode
== RISCV::VSE8_V
||
254 Opcode
== RISCV::VLE16_V
|| Opcode
== RISCV::VSE16_V
||
255 Opcode
== RISCV::VLE32_V
|| Opcode
== RISCV::VSE32_V
||
256 Opcode
== RISCV::VLE64_V
|| Opcode
== RISCV::VSE64_V
) {
257 RISCVII::VLMUL VLMUL
= static_cast<RISCVII::VLMUL
>(LMUL
);
258 auto [EEW
, EMUL
] = getEEWAndEMULForUnitStrideLoadStore(Opcode
, VLMUL
, SEW
);
259 RVV
= RISCVVInversePseudosTable::getBaseInfo(Opcode
, EMUL
, EEW
);
261 // Check if it depends on LMUL and SEW
262 RVV
= RISCVVInversePseudosTable::getBaseInfo(Opcode
, LMUL
, SEW
);
263 // Check if it depends only on LMUL
265 RVV
= RISCVVInversePseudosTable::getBaseInfo(Opcode
, LMUL
, 0);
271 dbgs() << "RVCB: Could not find PseudoInstruction for Opcode "
272 << MCII
.getName(Opcode
)
273 << ", LMUL=" << (LI
? LI
->getData() : "Unspecified")
274 << ", SEW=" << (SI
? SI
->getData() : "Unspecified")
275 << ". Ignoring instrumentation and using original SchedClassID="
276 << SchedClassID
<< '\n');
280 // Override using pseudo
281 LLVM_DEBUG(dbgs() << "RVCB: Found Pseudo Instruction for Opcode "
282 << MCII
.getName(Opcode
) << ", LMUL=" << LI
->getData()
283 << ", SEW=" << (SI
? SI
->getData() : "Unspecified")
284 << ". Overriding original SchedClassID=" << SchedClassID
285 << " with " << MCII
.getName(RVV
->Pseudo
) << '\n');
286 return MCII
.get(RVV
->Pseudo
).getSchedClass();
292 using namespace llvm
;
295 static InstrumentManager
*
296 createRISCVInstrumentManager(const MCSubtargetInfo
&STI
,
297 const MCInstrInfo
&MCII
) {
298 return new RISCVInstrumentManager(STI
, MCII
);
301 /// Extern function to initialize the targets for the RISC-V backend
302 extern "C" LLVM_EXTERNAL_VISIBILITY
void LLVMInitializeRISCVTargetMCA() {
303 TargetRegistry::RegisterInstrumentManager(getTheRISCV32Target(),
304 createRISCVInstrumentManager
);
305 TargetRegistry::RegisterInstrumentManager(getTheRISCV64Target(),
306 createRISCVInstrumentManager
);