xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/RISCV/MCA/RISCVCustomBehaviour.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
1bdd1243dSDimitry Andric //===------------------- RISCVCustomBehaviour.cpp ---------------*-C++ -* -===//
2bdd1243dSDimitry Andric //
3bdd1243dSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4bdd1243dSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5bdd1243dSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6bdd1243dSDimitry Andric //
7bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
8bdd1243dSDimitry Andric /// \file
9bdd1243dSDimitry Andric ///
10bdd1243dSDimitry Andric /// This file implements methods from the RISCVCustomBehaviour class.
11bdd1243dSDimitry Andric ///
12bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
13bdd1243dSDimitry Andric 
14bdd1243dSDimitry Andric #include "RISCVCustomBehaviour.h"
15bdd1243dSDimitry Andric #include "MCTargetDesc/RISCVMCTargetDesc.h"
16*06c3fb27SDimitry Andric #include "RISCV.h"
17bdd1243dSDimitry Andric #include "RISCVInstrInfo.h"
18bdd1243dSDimitry Andric #include "TargetInfo/RISCVTargetInfo.h"
19bdd1243dSDimitry Andric #include "llvm/MC/TargetRegistry.h"
20bdd1243dSDimitry Andric #include "llvm/Support/Debug.h"
21bdd1243dSDimitry Andric 
22bdd1243dSDimitry Andric #define DEBUG_TYPE "llvm-mca-riscv-custombehaviour"
23bdd1243dSDimitry Andric 
24bdd1243dSDimitry Andric // This brings in a table with primary key of
25bdd1243dSDimitry Andric // base instruction opcode and lmul and maps
26bdd1243dSDimitry Andric // to the opcode of the pseudo instruction.
27bdd1243dSDimitry Andric namespace RISCVVInversePseudosTable {
28bdd1243dSDimitry Andric using namespace llvm;
29bdd1243dSDimitry Andric using namespace llvm::RISCV;
30bdd1243dSDimitry Andric 
31bdd1243dSDimitry Andric struct PseudoInfo {
32bdd1243dSDimitry Andric   uint16_t Pseudo;
33bdd1243dSDimitry Andric   uint16_t BaseInstr;
34bdd1243dSDimitry Andric   uint8_t VLMul;
35*06c3fb27SDimitry Andric   uint8_t SEW;
36bdd1243dSDimitry Andric };
37bdd1243dSDimitry Andric 
38bdd1243dSDimitry Andric #define GET_RISCVVInversePseudosTable_IMPL
39bdd1243dSDimitry Andric #define GET_RISCVVInversePseudosTable_DECL
40bdd1243dSDimitry Andric #include "RISCVGenSearchableTables.inc"
41bdd1243dSDimitry Andric 
42bdd1243dSDimitry Andric } // end namespace RISCVVInversePseudosTable
43bdd1243dSDimitry Andric 
44bdd1243dSDimitry Andric namespace llvm {
45bdd1243dSDimitry Andric namespace mca {
46bdd1243dSDimitry Andric 
47bdd1243dSDimitry Andric const llvm::StringRef RISCVLMULInstrument::DESC_NAME = "RISCV-LMUL";
48bdd1243dSDimitry Andric 
49bdd1243dSDimitry Andric bool RISCVLMULInstrument::isDataValid(llvm::StringRef Data) {
50bdd1243dSDimitry Andric   // Return true if not one of the valid LMUL strings
51bdd1243dSDimitry Andric   return StringSwitch<bool>(Data)
52bdd1243dSDimitry Andric       .Cases("M1", "M2", "M4", "M8", "MF2", "MF4", "MF8", true)
53bdd1243dSDimitry Andric       .Default(false);
54bdd1243dSDimitry Andric }
55bdd1243dSDimitry Andric 
56bdd1243dSDimitry Andric uint8_t RISCVLMULInstrument::getLMUL() const {
57bdd1243dSDimitry Andric   // assertion prevents us from needing llvm_unreachable in the StringSwitch
58bdd1243dSDimitry Andric   // below
59bdd1243dSDimitry Andric   assert(isDataValid(getData()) &&
60bdd1243dSDimitry Andric          "Cannot get LMUL because invalid Data value");
61*06c3fb27SDimitry Andric   // These are the LMUL values that are used in RISC-V tablegen
62bdd1243dSDimitry Andric   return StringSwitch<uint8_t>(getData())
63bdd1243dSDimitry Andric       .Case("M1", 0b000)
64bdd1243dSDimitry Andric       .Case("M2", 0b001)
65bdd1243dSDimitry Andric       .Case("M4", 0b010)
66bdd1243dSDimitry Andric       .Case("M8", 0b011)
67bdd1243dSDimitry Andric       .Case("MF2", 0b101)
68bdd1243dSDimitry Andric       .Case("MF4", 0b110)
69bdd1243dSDimitry Andric       .Case("MF8", 0b111);
70bdd1243dSDimitry Andric }
71bdd1243dSDimitry Andric 
72*06c3fb27SDimitry Andric const llvm::StringRef RISCVSEWInstrument::DESC_NAME = "RISCV-SEW";
73*06c3fb27SDimitry Andric 
74*06c3fb27SDimitry Andric bool RISCVSEWInstrument::isDataValid(llvm::StringRef Data) {
75*06c3fb27SDimitry Andric   // Return true if not one of the valid SEW strings
76*06c3fb27SDimitry Andric   return StringSwitch<bool>(Data)
77*06c3fb27SDimitry Andric       .Cases("E8", "E16", "E32", "E64", true)
78*06c3fb27SDimitry Andric       .Default(false);
79bdd1243dSDimitry Andric }
80bdd1243dSDimitry Andric 
81*06c3fb27SDimitry Andric uint8_t RISCVSEWInstrument::getSEW() const {
82*06c3fb27SDimitry Andric   // assertion prevents us from needing llvm_unreachable in the StringSwitch
83*06c3fb27SDimitry Andric   // below
84*06c3fb27SDimitry Andric   assert(isDataValid(getData()) && "Cannot get SEW because invalid Data value");
85*06c3fb27SDimitry Andric   // These are the LMUL values that are used in RISC-V tablegen
86*06c3fb27SDimitry Andric   return StringSwitch<uint8_t>(getData())
87*06c3fb27SDimitry Andric       .Case("E8", 8)
88*06c3fb27SDimitry Andric       .Case("E16", 16)
89*06c3fb27SDimitry Andric       .Case("E32", 32)
90*06c3fb27SDimitry Andric       .Case("E64", 64);
91*06c3fb27SDimitry Andric }
92*06c3fb27SDimitry Andric 
93*06c3fb27SDimitry Andric bool RISCVInstrumentManager::supportsInstrumentType(
94*06c3fb27SDimitry Andric     llvm::StringRef Type) const {
95*06c3fb27SDimitry Andric   return Type == RISCVLMULInstrument::DESC_NAME ||
96*06c3fb27SDimitry Andric          Type == RISCVSEWInstrument::DESC_NAME;
97*06c3fb27SDimitry Andric }
98*06c3fb27SDimitry Andric 
99*06c3fb27SDimitry Andric UniqueInstrument
100bdd1243dSDimitry Andric RISCVInstrumentManager::createInstrument(llvm::StringRef Desc,
101bdd1243dSDimitry Andric                                          llvm::StringRef Data) {
102*06c3fb27SDimitry Andric   if (Desc == RISCVLMULInstrument::DESC_NAME) {
103*06c3fb27SDimitry Andric     if (!RISCVLMULInstrument::isDataValid(Data)) {
104bdd1243dSDimitry Andric       LLVM_DEBUG(dbgs() << "RVCB: Bad data for instrument kind " << Desc << ": "
105bdd1243dSDimitry Andric                         << Data << '\n');
106bdd1243dSDimitry Andric       return nullptr;
107bdd1243dSDimitry Andric     }
108*06c3fb27SDimitry Andric     return std::make_unique<RISCVLMULInstrument>(Data);
109*06c3fb27SDimitry Andric   }
110*06c3fb27SDimitry Andric 
111*06c3fb27SDimitry Andric   if (Desc == RISCVSEWInstrument::DESC_NAME) {
112*06c3fb27SDimitry Andric     if (!RISCVSEWInstrument::isDataValid(Data)) {
113*06c3fb27SDimitry Andric       LLVM_DEBUG(dbgs() << "RVCB: Bad data for instrument kind " << Desc << ": "
114*06c3fb27SDimitry Andric                         << Data << '\n');
115*06c3fb27SDimitry Andric       return nullptr;
116*06c3fb27SDimitry Andric     }
117*06c3fb27SDimitry Andric     return std::make_unique<RISCVSEWInstrument>(Data);
118*06c3fb27SDimitry Andric   }
119*06c3fb27SDimitry Andric 
120*06c3fb27SDimitry Andric   LLVM_DEBUG(dbgs() << "RVCB: Unknown instrumentation Desc: " << Desc << '\n');
121*06c3fb27SDimitry Andric   return nullptr;
122*06c3fb27SDimitry Andric }
123*06c3fb27SDimitry Andric 
124*06c3fb27SDimitry Andric SmallVector<UniqueInstrument>
125*06c3fb27SDimitry Andric RISCVInstrumentManager::createInstruments(const MCInst &Inst) {
126*06c3fb27SDimitry Andric   if (Inst.getOpcode() == RISCV::VSETVLI ||
127*06c3fb27SDimitry Andric       Inst.getOpcode() == RISCV::VSETIVLI) {
128*06c3fb27SDimitry Andric     LLVM_DEBUG(dbgs() << "RVCB: Found VSETVLI and creating instrument for it: "
129*06c3fb27SDimitry Andric                       << Inst << "\n");
130*06c3fb27SDimitry Andric     unsigned VTypeI = Inst.getOperand(2).getImm();
131*06c3fb27SDimitry Andric     RISCVII::VLMUL VLMUL = RISCVVType::getVLMUL(VTypeI);
132*06c3fb27SDimitry Andric 
133*06c3fb27SDimitry Andric     StringRef LMUL;
134*06c3fb27SDimitry Andric     switch (VLMUL) {
135*06c3fb27SDimitry Andric     case RISCVII::LMUL_1:
136*06c3fb27SDimitry Andric       LMUL = "M1";
137*06c3fb27SDimitry Andric       break;
138*06c3fb27SDimitry Andric     case RISCVII::LMUL_2:
139*06c3fb27SDimitry Andric       LMUL = "M2";
140*06c3fb27SDimitry Andric       break;
141*06c3fb27SDimitry Andric     case RISCVII::LMUL_4:
142*06c3fb27SDimitry Andric       LMUL = "M4";
143*06c3fb27SDimitry Andric       break;
144*06c3fb27SDimitry Andric     case RISCVII::LMUL_8:
145*06c3fb27SDimitry Andric       LMUL = "M8";
146*06c3fb27SDimitry Andric       break;
147*06c3fb27SDimitry Andric     case RISCVII::LMUL_F2:
148*06c3fb27SDimitry Andric       LMUL = "MF2";
149*06c3fb27SDimitry Andric       break;
150*06c3fb27SDimitry Andric     case RISCVII::LMUL_F4:
151*06c3fb27SDimitry Andric       LMUL = "MF4";
152*06c3fb27SDimitry Andric       break;
153*06c3fb27SDimitry Andric     case RISCVII::LMUL_F8:
154*06c3fb27SDimitry Andric       LMUL = "MF8";
155*06c3fb27SDimitry Andric       break;
156*06c3fb27SDimitry Andric     case RISCVII::LMUL_RESERVED:
157*06c3fb27SDimitry Andric       llvm_unreachable("Cannot create instrument for LMUL_RESERVED");
158*06c3fb27SDimitry Andric     }
159*06c3fb27SDimitry Andric     SmallVector<UniqueInstrument> Instruments;
160*06c3fb27SDimitry Andric     Instruments.emplace_back(
161*06c3fb27SDimitry Andric         createInstrument(RISCVLMULInstrument::DESC_NAME, LMUL));
162*06c3fb27SDimitry Andric 
163*06c3fb27SDimitry Andric     unsigned SEW = RISCVVType::getSEW(VTypeI);
164*06c3fb27SDimitry Andric     StringRef SEWStr;
165*06c3fb27SDimitry Andric     switch (SEW) {
166*06c3fb27SDimitry Andric     case 8:
167*06c3fb27SDimitry Andric       SEWStr = "E8";
168*06c3fb27SDimitry Andric       break;
169*06c3fb27SDimitry Andric     case 16:
170*06c3fb27SDimitry Andric       SEWStr = "E16";
171*06c3fb27SDimitry Andric       break;
172*06c3fb27SDimitry Andric     case 32:
173*06c3fb27SDimitry Andric       SEWStr = "E32";
174*06c3fb27SDimitry Andric       break;
175*06c3fb27SDimitry Andric     case 64:
176*06c3fb27SDimitry Andric       SEWStr = "E64";
177*06c3fb27SDimitry Andric       break;
178*06c3fb27SDimitry Andric     default:
179*06c3fb27SDimitry Andric       llvm_unreachable("Cannot create instrument for SEW");
180*06c3fb27SDimitry Andric     }
181*06c3fb27SDimitry Andric     Instruments.emplace_back(
182*06c3fb27SDimitry Andric         createInstrument(RISCVSEWInstrument::DESC_NAME, SEWStr));
183*06c3fb27SDimitry Andric 
184*06c3fb27SDimitry Andric     return Instruments;
185*06c3fb27SDimitry Andric   }
186*06c3fb27SDimitry Andric   return SmallVector<UniqueInstrument>();
187bdd1243dSDimitry Andric }
188bdd1243dSDimitry Andric 
189bdd1243dSDimitry Andric unsigned RISCVInstrumentManager::getSchedClassID(
190bdd1243dSDimitry Andric     const MCInstrInfo &MCII, const MCInst &MCI,
191*06c3fb27SDimitry Andric     const llvm::SmallVector<Instrument *> &IVec) const {
192bdd1243dSDimitry Andric   unsigned short Opcode = MCI.getOpcode();
193bdd1243dSDimitry Andric   unsigned SchedClassID = MCII.get(Opcode).getSchedClass();
194bdd1243dSDimitry Andric 
195*06c3fb27SDimitry Andric   // Unpack all possible RISCV instruments from IVec.
196*06c3fb27SDimitry Andric   RISCVLMULInstrument *LI = nullptr;
197*06c3fb27SDimitry Andric   RISCVSEWInstrument *SI = nullptr;
198*06c3fb27SDimitry Andric   for (auto &I : IVec) {
199*06c3fb27SDimitry Andric     if (I->getDesc() == RISCVLMULInstrument::DESC_NAME)
200*06c3fb27SDimitry Andric       LI = static_cast<RISCVLMULInstrument *>(I);
201*06c3fb27SDimitry Andric     else if (I->getDesc() == RISCVSEWInstrument::DESC_NAME)
202*06c3fb27SDimitry Andric       SI = static_cast<RISCVSEWInstrument *>(I);
203*06c3fb27SDimitry Andric   }
204*06c3fb27SDimitry Andric 
205*06c3fb27SDimitry Andric   // Need LMUL or LMUL, SEW in order to override opcode. If no LMUL is provided,
206*06c3fb27SDimitry Andric   // then no option to override.
207*06c3fb27SDimitry Andric   if (!LI) {
208*06c3fb27SDimitry Andric     LLVM_DEBUG(
209*06c3fb27SDimitry Andric         dbgs() << "RVCB: Did not use instrumentation to override Opcode.\n");
210*06c3fb27SDimitry Andric     return SchedClassID;
211*06c3fb27SDimitry Andric   }
212*06c3fb27SDimitry Andric   uint8_t LMUL = LI->getLMUL();
213*06c3fb27SDimitry Andric 
214*06c3fb27SDimitry Andric   // getBaseInfo works with (Opcode, LMUL, 0) if no SEW instrument,
215*06c3fb27SDimitry Andric   // or (Opcode, LMUL, SEW) if SEW instrument is active, and depends on LMUL
216*06c3fb27SDimitry Andric   // and SEW, or (Opcode, LMUL, 0) if does not depend on SEW.
217*06c3fb27SDimitry Andric   uint8_t SEW = SI ? SI->getSEW() : 0;
218*06c3fb27SDimitry Andric   // Check if it depends on LMUL and SEW
219bdd1243dSDimitry Andric   const RISCVVInversePseudosTable::PseudoInfo *RVV =
220*06c3fb27SDimitry Andric       RISCVVInversePseudosTable::getBaseInfo(Opcode, LMUL, SEW);
221*06c3fb27SDimitry Andric   // Check if it depends only on LMUL
222*06c3fb27SDimitry Andric   if (!RVV)
223*06c3fb27SDimitry Andric     RVV = RISCVVInversePseudosTable::getBaseInfo(Opcode, LMUL, 0);
224*06c3fb27SDimitry Andric 
225bdd1243dSDimitry Andric   // Not a RVV instr
226bdd1243dSDimitry Andric   if (!RVV) {
227bdd1243dSDimitry Andric     LLVM_DEBUG(
228*06c3fb27SDimitry Andric         dbgs() << "RVCB: Could not find PseudoInstruction for Opcode "
229*06c3fb27SDimitry Andric                << MCII.getName(Opcode)
230*06c3fb27SDimitry Andric                << ", LMUL=" << (LI ? LI->getData() : "Unspecified")
231*06c3fb27SDimitry Andric                << ", SEW=" << (SI ? SI->getData() : "Unspecified")
232bdd1243dSDimitry Andric                << ". Ignoring instrumentation and using original SchedClassID="
233bdd1243dSDimitry Andric                << SchedClassID << '\n');
234bdd1243dSDimitry Andric     return SchedClassID;
235bdd1243dSDimitry Andric   }
236bdd1243dSDimitry Andric 
237bdd1243dSDimitry Andric   // Override using pseudo
238bdd1243dSDimitry Andric   LLVM_DEBUG(dbgs() << "RVCB: Found Pseudo Instruction for Opcode "
239*06c3fb27SDimitry Andric                     << MCII.getName(Opcode) << ", LMUL=" << LI->getData()
240*06c3fb27SDimitry Andric                     << ", SEW=" << (SI ? SI->getData() : "Unspecified")
241bdd1243dSDimitry Andric                     << ". Overriding original SchedClassID=" << SchedClassID
242bdd1243dSDimitry Andric                     << " with " << MCII.getName(RVV->Pseudo) << '\n');
243bdd1243dSDimitry Andric   return MCII.get(RVV->Pseudo).getSchedClass();
244bdd1243dSDimitry Andric }
245bdd1243dSDimitry Andric 
246bdd1243dSDimitry Andric } // namespace mca
247bdd1243dSDimitry Andric } // namespace llvm
248bdd1243dSDimitry Andric 
249bdd1243dSDimitry Andric using namespace llvm;
250bdd1243dSDimitry Andric using namespace mca;
251bdd1243dSDimitry Andric 
252bdd1243dSDimitry Andric static InstrumentManager *
253bdd1243dSDimitry Andric createRISCVInstrumentManager(const MCSubtargetInfo &STI,
254bdd1243dSDimitry Andric                              const MCInstrInfo &MCII) {
255bdd1243dSDimitry Andric   return new RISCVInstrumentManager(STI, MCII);
256bdd1243dSDimitry Andric }
257bdd1243dSDimitry Andric 
258*06c3fb27SDimitry Andric /// Extern function to initialize the targets for the RISC-V backend
259bdd1243dSDimitry Andric extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVTargetMCA() {
260bdd1243dSDimitry Andric   TargetRegistry::RegisterInstrumentManager(getTheRISCV32Target(),
261bdd1243dSDimitry Andric                                             createRISCVInstrumentManager);
262bdd1243dSDimitry Andric   TargetRegistry::RegisterInstrumentManager(getTheRISCV64Target(),
263bdd1243dSDimitry Andric                                             createRISCVInstrumentManager);
264bdd1243dSDimitry Andric }
265