xref: /freebsd/contrib/llvm-project/llvm/lib/Target/RISCV/MCA/RISCVCustomBehaviour.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
1 //===------------------- RISCVCustomBehaviour.cpp ---------------*-C++ -* -===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 /// \file
9 ///
10 /// This file implements methods from the RISCVCustomBehaviour class.
11 ///
12 //===----------------------------------------------------------------------===//
13 
14 #include "RISCVCustomBehaviour.h"
15 #include "MCTargetDesc/RISCVMCTargetDesc.h"
16 #include "RISCV.h"
17 #include "TargetInfo/RISCVTargetInfo.h"
18 #include "llvm/MC/TargetRegistry.h"
19 #include "llvm/Support/Compiler.h"
20 #include "llvm/Support/Debug.h"
21 
22 #define DEBUG_TYPE "llvm-mca-riscv-custombehaviour"
23 
24 namespace llvm::RISCV {
25 struct VXMemOpInfo {
26   unsigned Log2IdxEEW : 3;
27   unsigned IsOrdered : 1;
28   unsigned IsStore : 1;
29   unsigned NF : 4;
30   unsigned BaseInstr;
31 };
32 
33 #define GET_RISCVBaseVXMemOpTable_IMPL
34 #include "RISCVGenSearchableTables.inc"
35 } // namespace llvm::RISCV
36 
37 namespace llvm {
38 namespace mca {
39 
40 const llvm::StringRef RISCVLMULInstrument::DESC_NAME = "RISCV-LMUL";
41 
isDataValid(llvm::StringRef Data)42 bool RISCVLMULInstrument::isDataValid(llvm::StringRef Data) {
43   // Return true if not one of the valid LMUL strings
44   return StringSwitch<bool>(Data)
45       .Cases("M1", "M2", "M4", "M8", "MF2", "MF4", "MF8", true)
46       .Default(false);
47 }
48 
getLMUL() const49 uint8_t RISCVLMULInstrument::getLMUL() const {
50   // assertion prevents us from needing llvm_unreachable in the StringSwitch
51   // below
52   assert(isDataValid(getData()) &&
53          "Cannot get LMUL because invalid Data value");
54   // These are the LMUL values that are used in RISC-V tablegen
55   return StringSwitch<uint8_t>(getData())
56       .Case("M1", 0b000)
57       .Case("M2", 0b001)
58       .Case("M4", 0b010)
59       .Case("M8", 0b011)
60       .Case("MF2", 0b111)
61       .Case("MF4", 0b110)
62       .Case("MF8", 0b101);
63 }
64 
65 const llvm::StringRef RISCVSEWInstrument::DESC_NAME = "RISCV-SEW";
66 
isDataValid(llvm::StringRef Data)67 bool RISCVSEWInstrument::isDataValid(llvm::StringRef Data) {
68   // Return true if not one of the valid SEW strings
69   return StringSwitch<bool>(Data)
70       .Cases("E8", "E16", "E32", "E64", true)
71       .Default(false);
72 }
73 
getSEW() const74 uint8_t RISCVSEWInstrument::getSEW() const {
75   // assertion prevents us from needing llvm_unreachable in the StringSwitch
76   // below
77   assert(isDataValid(getData()) && "Cannot get SEW because invalid Data value");
78   // These are the LMUL values that are used in RISC-V tablegen
79   return StringSwitch<uint8_t>(getData())
80       .Case("E8", 8)
81       .Case("E16", 16)
82       .Case("E32", 32)
83       .Case("E64", 64);
84 }
85 
supportsInstrumentType(llvm::StringRef Type) const86 bool RISCVInstrumentManager::supportsInstrumentType(
87     llvm::StringRef Type) const {
88   return Type == RISCVLMULInstrument::DESC_NAME ||
89          Type == RISCVSEWInstrument::DESC_NAME;
90 }
91 
92 UniqueInstrument
createInstrument(llvm::StringRef Desc,llvm::StringRef Data)93 RISCVInstrumentManager::createInstrument(llvm::StringRef Desc,
94                                          llvm::StringRef Data) {
95   if (Desc == RISCVLMULInstrument::DESC_NAME) {
96     if (!RISCVLMULInstrument::isDataValid(Data)) {
97       LLVM_DEBUG(dbgs() << "RVCB: Bad data for instrument kind " << Desc << ": "
98                         << Data << '\n');
99       return nullptr;
100     }
101     return std::make_unique<RISCVLMULInstrument>(Data);
102   }
103 
104   if (Desc == RISCVSEWInstrument::DESC_NAME) {
105     if (!RISCVSEWInstrument::isDataValid(Data)) {
106       LLVM_DEBUG(dbgs() << "RVCB: Bad data for instrument kind " << Desc << ": "
107                         << Data << '\n');
108       return nullptr;
109     }
110     return std::make_unique<RISCVSEWInstrument>(Data);
111   }
112 
113   LLVM_DEBUG(dbgs() << "RVCB: Unknown instrumentation Desc: " << Desc << '\n');
114   return nullptr;
115 }
116 
117 SmallVector<UniqueInstrument>
createInstruments(const MCInst & Inst)118 RISCVInstrumentManager::createInstruments(const MCInst &Inst) {
119   if (Inst.getOpcode() == RISCV::VSETVLI ||
120       Inst.getOpcode() == RISCV::VSETIVLI) {
121     LLVM_DEBUG(dbgs() << "RVCB: Found VSETVLI and creating instrument for it: "
122                       << Inst << "\n");
123     unsigned VTypeI = Inst.getOperand(2).getImm();
124     RISCVVType::VLMUL VLMUL = RISCVVType::getVLMUL(VTypeI);
125 
126     StringRef LMUL;
127     switch (VLMUL) {
128     case RISCVVType::LMUL_1:
129       LMUL = "M1";
130       break;
131     case RISCVVType::LMUL_2:
132       LMUL = "M2";
133       break;
134     case RISCVVType::LMUL_4:
135       LMUL = "M4";
136       break;
137     case RISCVVType::LMUL_8:
138       LMUL = "M8";
139       break;
140     case RISCVVType::LMUL_F2:
141       LMUL = "MF2";
142       break;
143     case RISCVVType::LMUL_F4:
144       LMUL = "MF4";
145       break;
146     case RISCVVType::LMUL_F8:
147       LMUL = "MF8";
148       break;
149     case RISCVVType::LMUL_RESERVED:
150       llvm_unreachable("Cannot create instrument for LMUL_RESERVED");
151     }
152     SmallVector<UniqueInstrument> Instruments;
153     Instruments.emplace_back(
154         createInstrument(RISCVLMULInstrument::DESC_NAME, LMUL));
155 
156     unsigned SEW = RISCVVType::getSEW(VTypeI);
157     StringRef SEWStr;
158     switch (SEW) {
159     case 8:
160       SEWStr = "E8";
161       break;
162     case 16:
163       SEWStr = "E16";
164       break;
165     case 32:
166       SEWStr = "E32";
167       break;
168     case 64:
169       SEWStr = "E64";
170       break;
171     default:
172       llvm_unreachable("Cannot create instrument for SEW");
173     }
174     Instruments.emplace_back(
175         createInstrument(RISCVSEWInstrument::DESC_NAME, SEWStr));
176 
177     return Instruments;
178   }
179   return SmallVector<UniqueInstrument>();
180 }
181 
182 static std::pair<uint8_t, uint8_t>
getEEWAndEMUL(unsigned Opcode,RISCVVType::VLMUL LMUL,uint8_t SEW)183 getEEWAndEMUL(unsigned Opcode, RISCVVType::VLMUL LMUL, uint8_t SEW) {
184   uint8_t EEW;
185   switch (Opcode) {
186   case RISCV::VLM_V:
187   case RISCV::VSM_V:
188   case RISCV::VLE8_V:
189   case RISCV::VSE8_V:
190   case RISCV::VLSE8_V:
191   case RISCV::VSSE8_V:
192     EEW = 8;
193     break;
194   case RISCV::VLE16_V:
195   case RISCV::VSE16_V:
196   case RISCV::VLSE16_V:
197   case RISCV::VSSE16_V:
198     EEW = 16;
199     break;
200   case RISCV::VLE32_V:
201   case RISCV::VSE32_V:
202   case RISCV::VLSE32_V:
203   case RISCV::VSSE32_V:
204     EEW = 32;
205     break;
206   case RISCV::VLE64_V:
207   case RISCV::VSE64_V:
208   case RISCV::VLSE64_V:
209   case RISCV::VSSE64_V:
210     EEW = 64;
211     break;
212   default:
213     llvm_unreachable("Could not determine EEW from Opcode");
214   }
215 
216   auto EMUL = RISCVVType::getSameRatioLMUL(SEW, LMUL, EEW);
217   if (!EEW)
218     llvm_unreachable("Invalid SEW or LMUL for new ratio");
219   return std::make_pair(EEW, *EMUL);
220 }
221 
opcodeHasEEWAndEMULInfo(unsigned short Opcode)222 static bool opcodeHasEEWAndEMULInfo(unsigned short Opcode) {
223   return Opcode == RISCV::VLM_V || Opcode == RISCV::VSM_V ||
224          Opcode == RISCV::VLE8_V || Opcode == RISCV::VSE8_V ||
225          Opcode == RISCV::VLE16_V || Opcode == RISCV::VSE16_V ||
226          Opcode == RISCV::VLE32_V || Opcode == RISCV::VSE32_V ||
227          Opcode == RISCV::VLE64_V || Opcode == RISCV::VSE64_V ||
228          Opcode == RISCV::VLSE8_V || Opcode == RISCV::VSSE8_V ||
229          Opcode == RISCV::VLSE16_V || Opcode == RISCV::VSSE16_V ||
230          Opcode == RISCV::VLSE32_V || Opcode == RISCV::VSSE32_V ||
231          Opcode == RISCV::VLSE64_V || Opcode == RISCV::VSSE64_V;
232 }
233 
getSchedClassID(const MCInstrInfo & MCII,const MCInst & MCI,const llvm::SmallVector<Instrument * > & IVec) const234 unsigned RISCVInstrumentManager::getSchedClassID(
235     const MCInstrInfo &MCII, const MCInst &MCI,
236     const llvm::SmallVector<Instrument *> &IVec) const {
237   unsigned short Opcode = MCI.getOpcode();
238   unsigned SchedClassID = MCII.get(Opcode).getSchedClass();
239 
240   // Unpack all possible RISC-V instruments from IVec.
241   RISCVLMULInstrument *LI = nullptr;
242   RISCVSEWInstrument *SI = nullptr;
243   for (auto &I : IVec) {
244     if (I->getDesc() == RISCVLMULInstrument::DESC_NAME)
245       LI = static_cast<RISCVLMULInstrument *>(I);
246     else if (I->getDesc() == RISCVSEWInstrument::DESC_NAME)
247       SI = static_cast<RISCVSEWInstrument *>(I);
248   }
249 
250   // Need LMUL or LMUL, SEW in order to override opcode. If no LMUL is provided,
251   // then no option to override.
252   if (!LI) {
253     LLVM_DEBUG(
254         dbgs() << "RVCB: Did not use instrumentation to override Opcode.\n");
255     return SchedClassID;
256   }
257   uint8_t LMUL = LI->getLMUL();
258 
259   // getBaseInfo works with (Opcode, LMUL, 0) if no SEW instrument,
260   // or (Opcode, LMUL, SEW) if SEW instrument is active, and depends on LMUL
261   // and SEW, or (Opcode, LMUL, 0) if does not depend on SEW.
262   uint8_t SEW = SI ? SI->getSEW() : 0;
263 
264   std::optional<unsigned> VPOpcode;
265   if (const auto *VXMO = RISCV::getVXMemOpInfo(Opcode)) {
266     // Calculate the expected index EMUL. For indexed operations,
267     // the DataEEW and DataEMUL are equal to SEW and LMUL, respectively.
268     unsigned IndexEMUL = ((1 << VXMO->Log2IdxEEW) * LMUL) / SEW;
269 
270     if (!VXMO->NF) {
271       // Indexed Load / Store.
272       if (VXMO->IsStore) {
273         if (const auto *VXP = RISCV::getVSXPseudo(
274                 /*Masked=*/0, VXMO->IsOrdered, VXMO->Log2IdxEEW, LMUL,
275                 IndexEMUL))
276           VPOpcode = VXP->Pseudo;
277       } else {
278         if (const auto *VXP = RISCV::getVLXPseudo(
279                 /*Masked=*/0, VXMO->IsOrdered, VXMO->Log2IdxEEW, LMUL,
280                 IndexEMUL))
281           VPOpcode = VXP->Pseudo;
282       }
283     } else {
284       // Segmented Indexed Load / Store.
285       if (VXMO->IsStore) {
286         if (const auto *VXP =
287                 RISCV::getVSXSEGPseudo(VXMO->NF, /*Masked=*/0, VXMO->IsOrdered,
288                                        VXMO->Log2IdxEEW, LMUL, IndexEMUL))
289           VPOpcode = VXP->Pseudo;
290       } else {
291         if (const auto *VXP =
292                 RISCV::getVLXSEGPseudo(VXMO->NF, /*Masked=*/0, VXMO->IsOrdered,
293                                        VXMO->Log2IdxEEW, LMUL, IndexEMUL))
294           VPOpcode = VXP->Pseudo;
295       }
296     }
297   } else if (opcodeHasEEWAndEMULInfo(Opcode)) {
298     RISCVVType::VLMUL VLMUL = static_cast<RISCVVType::VLMUL>(LMUL);
299     auto [EEW, EMUL] = getEEWAndEMUL(Opcode, VLMUL, SEW);
300     if (const auto *RVV =
301             RISCVVInversePseudosTable::getBaseInfo(Opcode, EMUL, EEW))
302       VPOpcode = RVV->Pseudo;
303   } else {
304     // Check if it depends on LMUL and SEW
305     const auto *RVV = RISCVVInversePseudosTable::getBaseInfo(Opcode, LMUL, SEW);
306     // Check if it depends only on LMUL
307     if (!RVV)
308       RVV = RISCVVInversePseudosTable::getBaseInfo(Opcode, LMUL, 0);
309 
310     if (RVV)
311       VPOpcode = RVV->Pseudo;
312   }
313 
314   // Not a RVV instr
315   if (!VPOpcode) {
316     LLVM_DEBUG(
317         dbgs() << "RVCB: Could not find PseudoInstruction for Opcode "
318                << MCII.getName(Opcode)
319                << ", LMUL=" << (LI ? LI->getData() : "Unspecified")
320                << ", SEW=" << (SI ? SI->getData() : "Unspecified")
321                << ". Ignoring instrumentation and using original SchedClassID="
322                << SchedClassID << '\n');
323     return SchedClassID;
324   }
325 
326   // Override using pseudo
327   LLVM_DEBUG(dbgs() << "RVCB: Found Pseudo Instruction for Opcode "
328                     << MCII.getName(Opcode) << ", LMUL=" << LI->getData()
329                     << ", SEW=" << (SI ? SI->getData() : "Unspecified")
330                     << ". Overriding original SchedClassID=" << SchedClassID
331                     << " with " << MCII.getName(*VPOpcode) << '\n');
332   return MCII.get(*VPOpcode).getSchedClass();
333 }
334 
335 } // namespace mca
336 } // namespace llvm
337 
338 using namespace llvm;
339 using namespace mca;
340 
341 static InstrumentManager *
createRISCVInstrumentManager(const MCSubtargetInfo & STI,const MCInstrInfo & MCII)342 createRISCVInstrumentManager(const MCSubtargetInfo &STI,
343                              const MCInstrInfo &MCII) {
344   return new RISCVInstrumentManager(STI, MCII);
345 }
346 
347 /// Extern function to initialize the targets for the RISC-V backend
348 extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void
LLVMInitializeRISCVTargetMCA()349 LLVMInitializeRISCVTargetMCA() {
350   TargetRegistry::RegisterInstrumentManager(getTheRISCV32Target(),
351                                             createRISCVInstrumentManager);
352   TargetRegistry::RegisterInstrumentManager(getTheRISCV64Target(),
353                                             createRISCVInstrumentManager);
354 }
355