xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/RISCV/MCA/RISCVCustomBehaviour.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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"
1606c3fb27SDimitry Andric #include "RISCV.h"
17bdd1243dSDimitry Andric #include "TargetInfo/RISCVTargetInfo.h"
18bdd1243dSDimitry Andric #include "llvm/MC/TargetRegistry.h"
19bdd1243dSDimitry Andric #include "llvm/Support/Debug.h"
20bdd1243dSDimitry Andric 
21bdd1243dSDimitry Andric #define DEBUG_TYPE "llvm-mca-riscv-custombehaviour"
22bdd1243dSDimitry Andric 
23bdd1243dSDimitry Andric namespace llvm {
24bdd1243dSDimitry Andric namespace mca {
25bdd1243dSDimitry Andric 
26bdd1243dSDimitry Andric const llvm::StringRef RISCVLMULInstrument::DESC_NAME = "RISCV-LMUL";
27bdd1243dSDimitry Andric 
28bdd1243dSDimitry Andric bool RISCVLMULInstrument::isDataValid(llvm::StringRef Data) {
29bdd1243dSDimitry Andric   // Return true if not one of the valid LMUL strings
30bdd1243dSDimitry Andric   return StringSwitch<bool>(Data)
31bdd1243dSDimitry Andric       .Cases("M1", "M2", "M4", "M8", "MF2", "MF4", "MF8", true)
32bdd1243dSDimitry Andric       .Default(false);
33bdd1243dSDimitry Andric }
34bdd1243dSDimitry Andric 
35bdd1243dSDimitry Andric uint8_t RISCVLMULInstrument::getLMUL() const {
36bdd1243dSDimitry Andric   // assertion prevents us from needing llvm_unreachable in the StringSwitch
37bdd1243dSDimitry Andric   // below
38bdd1243dSDimitry Andric   assert(isDataValid(getData()) &&
39bdd1243dSDimitry Andric          "Cannot get LMUL because invalid Data value");
4006c3fb27SDimitry Andric   // These are the LMUL values that are used in RISC-V tablegen
41bdd1243dSDimitry Andric   return StringSwitch<uint8_t>(getData())
42bdd1243dSDimitry Andric       .Case("M1", 0b000)
43bdd1243dSDimitry Andric       .Case("M2", 0b001)
44bdd1243dSDimitry Andric       .Case("M4", 0b010)
45bdd1243dSDimitry Andric       .Case("M8", 0b011)
465f757f3fSDimitry Andric       .Case("MF2", 0b111)
47bdd1243dSDimitry Andric       .Case("MF4", 0b110)
485f757f3fSDimitry Andric       .Case("MF8", 0b101);
49bdd1243dSDimitry Andric }
50bdd1243dSDimitry Andric 
5106c3fb27SDimitry Andric const llvm::StringRef RISCVSEWInstrument::DESC_NAME = "RISCV-SEW";
5206c3fb27SDimitry Andric 
5306c3fb27SDimitry Andric bool RISCVSEWInstrument::isDataValid(llvm::StringRef Data) {
5406c3fb27SDimitry Andric   // Return true if not one of the valid SEW strings
5506c3fb27SDimitry Andric   return StringSwitch<bool>(Data)
5606c3fb27SDimitry Andric       .Cases("E8", "E16", "E32", "E64", true)
5706c3fb27SDimitry Andric       .Default(false);
58bdd1243dSDimitry Andric }
59bdd1243dSDimitry Andric 
6006c3fb27SDimitry Andric uint8_t RISCVSEWInstrument::getSEW() const {
6106c3fb27SDimitry Andric   // assertion prevents us from needing llvm_unreachable in the StringSwitch
6206c3fb27SDimitry Andric   // below
6306c3fb27SDimitry Andric   assert(isDataValid(getData()) && "Cannot get SEW because invalid Data value");
6406c3fb27SDimitry Andric   // These are the LMUL values that are used in RISC-V tablegen
6506c3fb27SDimitry Andric   return StringSwitch<uint8_t>(getData())
6606c3fb27SDimitry Andric       .Case("E8", 8)
6706c3fb27SDimitry Andric       .Case("E16", 16)
6806c3fb27SDimitry Andric       .Case("E32", 32)
6906c3fb27SDimitry Andric       .Case("E64", 64);
7006c3fb27SDimitry Andric }
7106c3fb27SDimitry Andric 
7206c3fb27SDimitry Andric bool RISCVInstrumentManager::supportsInstrumentType(
7306c3fb27SDimitry Andric     llvm::StringRef Type) const {
7406c3fb27SDimitry Andric   return Type == RISCVLMULInstrument::DESC_NAME ||
7506c3fb27SDimitry Andric          Type == RISCVSEWInstrument::DESC_NAME;
7606c3fb27SDimitry Andric }
7706c3fb27SDimitry Andric 
7806c3fb27SDimitry Andric UniqueInstrument
79bdd1243dSDimitry Andric RISCVInstrumentManager::createInstrument(llvm::StringRef Desc,
80bdd1243dSDimitry Andric                                          llvm::StringRef Data) {
8106c3fb27SDimitry Andric   if (Desc == RISCVLMULInstrument::DESC_NAME) {
8206c3fb27SDimitry Andric     if (!RISCVLMULInstrument::isDataValid(Data)) {
83bdd1243dSDimitry Andric       LLVM_DEBUG(dbgs() << "RVCB: Bad data for instrument kind " << Desc << ": "
84bdd1243dSDimitry Andric                         << Data << '\n');
85bdd1243dSDimitry Andric       return nullptr;
86bdd1243dSDimitry Andric     }
8706c3fb27SDimitry Andric     return std::make_unique<RISCVLMULInstrument>(Data);
8806c3fb27SDimitry Andric   }
8906c3fb27SDimitry Andric 
9006c3fb27SDimitry Andric   if (Desc == RISCVSEWInstrument::DESC_NAME) {
9106c3fb27SDimitry Andric     if (!RISCVSEWInstrument::isDataValid(Data)) {
9206c3fb27SDimitry Andric       LLVM_DEBUG(dbgs() << "RVCB: Bad data for instrument kind " << Desc << ": "
9306c3fb27SDimitry Andric                         << Data << '\n');
9406c3fb27SDimitry Andric       return nullptr;
9506c3fb27SDimitry Andric     }
9606c3fb27SDimitry Andric     return std::make_unique<RISCVSEWInstrument>(Data);
9706c3fb27SDimitry Andric   }
9806c3fb27SDimitry Andric 
9906c3fb27SDimitry Andric   LLVM_DEBUG(dbgs() << "RVCB: Unknown instrumentation Desc: " << Desc << '\n');
10006c3fb27SDimitry Andric   return nullptr;
10106c3fb27SDimitry Andric }
10206c3fb27SDimitry Andric 
10306c3fb27SDimitry Andric SmallVector<UniqueInstrument>
10406c3fb27SDimitry Andric RISCVInstrumentManager::createInstruments(const MCInst &Inst) {
10506c3fb27SDimitry Andric   if (Inst.getOpcode() == RISCV::VSETVLI ||
10606c3fb27SDimitry Andric       Inst.getOpcode() == RISCV::VSETIVLI) {
10706c3fb27SDimitry Andric     LLVM_DEBUG(dbgs() << "RVCB: Found VSETVLI and creating instrument for it: "
10806c3fb27SDimitry Andric                       << Inst << "\n");
10906c3fb27SDimitry Andric     unsigned VTypeI = Inst.getOperand(2).getImm();
11006c3fb27SDimitry Andric     RISCVII::VLMUL VLMUL = RISCVVType::getVLMUL(VTypeI);
11106c3fb27SDimitry Andric 
11206c3fb27SDimitry Andric     StringRef LMUL;
11306c3fb27SDimitry Andric     switch (VLMUL) {
11406c3fb27SDimitry Andric     case RISCVII::LMUL_1:
11506c3fb27SDimitry Andric       LMUL = "M1";
11606c3fb27SDimitry Andric       break;
11706c3fb27SDimitry Andric     case RISCVII::LMUL_2:
11806c3fb27SDimitry Andric       LMUL = "M2";
11906c3fb27SDimitry Andric       break;
12006c3fb27SDimitry Andric     case RISCVII::LMUL_4:
12106c3fb27SDimitry Andric       LMUL = "M4";
12206c3fb27SDimitry Andric       break;
12306c3fb27SDimitry Andric     case RISCVII::LMUL_8:
12406c3fb27SDimitry Andric       LMUL = "M8";
12506c3fb27SDimitry Andric       break;
12606c3fb27SDimitry Andric     case RISCVII::LMUL_F2:
12706c3fb27SDimitry Andric       LMUL = "MF2";
12806c3fb27SDimitry Andric       break;
12906c3fb27SDimitry Andric     case RISCVII::LMUL_F4:
13006c3fb27SDimitry Andric       LMUL = "MF4";
13106c3fb27SDimitry Andric       break;
13206c3fb27SDimitry Andric     case RISCVII::LMUL_F8:
13306c3fb27SDimitry Andric       LMUL = "MF8";
13406c3fb27SDimitry Andric       break;
13506c3fb27SDimitry Andric     case RISCVII::LMUL_RESERVED:
13606c3fb27SDimitry Andric       llvm_unreachable("Cannot create instrument for LMUL_RESERVED");
13706c3fb27SDimitry Andric     }
13806c3fb27SDimitry Andric     SmallVector<UniqueInstrument> Instruments;
13906c3fb27SDimitry Andric     Instruments.emplace_back(
14006c3fb27SDimitry Andric         createInstrument(RISCVLMULInstrument::DESC_NAME, LMUL));
14106c3fb27SDimitry Andric 
14206c3fb27SDimitry Andric     unsigned SEW = RISCVVType::getSEW(VTypeI);
14306c3fb27SDimitry Andric     StringRef SEWStr;
14406c3fb27SDimitry Andric     switch (SEW) {
14506c3fb27SDimitry Andric     case 8:
14606c3fb27SDimitry Andric       SEWStr = "E8";
14706c3fb27SDimitry Andric       break;
14806c3fb27SDimitry Andric     case 16:
14906c3fb27SDimitry Andric       SEWStr = "E16";
15006c3fb27SDimitry Andric       break;
15106c3fb27SDimitry Andric     case 32:
15206c3fb27SDimitry Andric       SEWStr = "E32";
15306c3fb27SDimitry Andric       break;
15406c3fb27SDimitry Andric     case 64:
15506c3fb27SDimitry Andric       SEWStr = "E64";
15606c3fb27SDimitry Andric       break;
15706c3fb27SDimitry Andric     default:
15806c3fb27SDimitry Andric       llvm_unreachable("Cannot create instrument for SEW");
15906c3fb27SDimitry Andric     }
16006c3fb27SDimitry Andric     Instruments.emplace_back(
16106c3fb27SDimitry Andric         createInstrument(RISCVSEWInstrument::DESC_NAME, SEWStr));
16206c3fb27SDimitry Andric 
16306c3fb27SDimitry Andric     return Instruments;
16406c3fb27SDimitry Andric   }
16506c3fb27SDimitry Andric   return SmallVector<UniqueInstrument>();
166bdd1243dSDimitry Andric }
167bdd1243dSDimitry Andric 
1685f757f3fSDimitry Andric static std::pair<uint8_t, uint8_t>
169*1db9f3b2SDimitry Andric getEEWAndEMUL(unsigned Opcode, RISCVII::VLMUL LMUL, uint8_t SEW) {
1705f757f3fSDimitry Andric   uint8_t EEW;
1715f757f3fSDimitry Andric   switch (Opcode) {
1725f757f3fSDimitry Andric   case RISCV::VLM_V:
1735f757f3fSDimitry Andric   case RISCV::VSM_V:
1745f757f3fSDimitry Andric   case RISCV::VLE8_V:
1755f757f3fSDimitry Andric   case RISCV::VSE8_V:
176*1db9f3b2SDimitry Andric   case RISCV::VLSE8_V:
177*1db9f3b2SDimitry Andric   case RISCV::VSSE8_V:
1785f757f3fSDimitry Andric     EEW = 8;
1795f757f3fSDimitry Andric     break;
1805f757f3fSDimitry Andric   case RISCV::VLE16_V:
1815f757f3fSDimitry Andric   case RISCV::VSE16_V:
182*1db9f3b2SDimitry Andric   case RISCV::VLSE16_V:
183*1db9f3b2SDimitry Andric   case RISCV::VSSE16_V:
1845f757f3fSDimitry Andric     EEW = 16;
1855f757f3fSDimitry Andric     break;
1865f757f3fSDimitry Andric   case RISCV::VLE32_V:
1875f757f3fSDimitry Andric   case RISCV::VSE32_V:
188*1db9f3b2SDimitry Andric   case RISCV::VLSE32_V:
189*1db9f3b2SDimitry Andric   case RISCV::VSSE32_V:
1905f757f3fSDimitry Andric     EEW = 32;
1915f757f3fSDimitry Andric     break;
1925f757f3fSDimitry Andric   case RISCV::VLE64_V:
1935f757f3fSDimitry Andric   case RISCV::VSE64_V:
194*1db9f3b2SDimitry Andric   case RISCV::VLSE64_V:
195*1db9f3b2SDimitry Andric   case RISCV::VSSE64_V:
1965f757f3fSDimitry Andric     EEW = 64;
1975f757f3fSDimitry Andric     break;
1985f757f3fSDimitry Andric   default:
199*1db9f3b2SDimitry Andric     llvm_unreachable("Could not determine EEW from Opcode");
2005f757f3fSDimitry Andric   }
2015f757f3fSDimitry Andric 
2025f757f3fSDimitry Andric   auto EMUL = RISCVVType::getSameRatioLMUL(SEW, LMUL, EEW);
2035f757f3fSDimitry Andric   if (!EEW)
2045f757f3fSDimitry Andric     llvm_unreachable("Invalid SEW or LMUL for new ratio");
2055f757f3fSDimitry Andric   return std::make_pair(EEW, *EMUL);
2065f757f3fSDimitry Andric }
2075f757f3fSDimitry Andric 
208*1db9f3b2SDimitry Andric bool opcodeHasEEWAndEMULInfo(unsigned short Opcode) {
209*1db9f3b2SDimitry Andric   return Opcode == RISCV::VLM_V || Opcode == RISCV::VSM_V ||
210*1db9f3b2SDimitry Andric          Opcode == RISCV::VLE8_V || Opcode == RISCV::VSE8_V ||
211*1db9f3b2SDimitry Andric          Opcode == RISCV::VLE16_V || Opcode == RISCV::VSE16_V ||
212*1db9f3b2SDimitry Andric          Opcode == RISCV::VLE32_V || Opcode == RISCV::VSE32_V ||
213*1db9f3b2SDimitry Andric          Opcode == RISCV::VLE64_V || Opcode == RISCV::VSE64_V ||
214*1db9f3b2SDimitry Andric          Opcode == RISCV::VLSE8_V || Opcode == RISCV::VSSE8_V ||
215*1db9f3b2SDimitry Andric          Opcode == RISCV::VLSE16_V || Opcode == RISCV::VSSE16_V ||
216*1db9f3b2SDimitry Andric          Opcode == RISCV::VLSE32_V || Opcode == RISCV::VSSE32_V ||
217*1db9f3b2SDimitry Andric          Opcode == RISCV::VLSE64_V || Opcode == RISCV::VSSE64_V;
218*1db9f3b2SDimitry Andric }
219*1db9f3b2SDimitry Andric 
220bdd1243dSDimitry Andric unsigned RISCVInstrumentManager::getSchedClassID(
221bdd1243dSDimitry Andric     const MCInstrInfo &MCII, const MCInst &MCI,
22206c3fb27SDimitry Andric     const llvm::SmallVector<Instrument *> &IVec) const {
223bdd1243dSDimitry Andric   unsigned short Opcode = MCI.getOpcode();
224bdd1243dSDimitry Andric   unsigned SchedClassID = MCII.get(Opcode).getSchedClass();
225bdd1243dSDimitry Andric 
2265f757f3fSDimitry Andric   // Unpack all possible RISC-V instruments from IVec.
22706c3fb27SDimitry Andric   RISCVLMULInstrument *LI = nullptr;
22806c3fb27SDimitry Andric   RISCVSEWInstrument *SI = nullptr;
22906c3fb27SDimitry Andric   for (auto &I : IVec) {
23006c3fb27SDimitry Andric     if (I->getDesc() == RISCVLMULInstrument::DESC_NAME)
23106c3fb27SDimitry Andric       LI = static_cast<RISCVLMULInstrument *>(I);
23206c3fb27SDimitry Andric     else if (I->getDesc() == RISCVSEWInstrument::DESC_NAME)
23306c3fb27SDimitry Andric       SI = static_cast<RISCVSEWInstrument *>(I);
23406c3fb27SDimitry Andric   }
23506c3fb27SDimitry Andric 
23606c3fb27SDimitry Andric   // Need LMUL or LMUL, SEW in order to override opcode. If no LMUL is provided,
23706c3fb27SDimitry Andric   // then no option to override.
23806c3fb27SDimitry Andric   if (!LI) {
23906c3fb27SDimitry Andric     LLVM_DEBUG(
24006c3fb27SDimitry Andric         dbgs() << "RVCB: Did not use instrumentation to override Opcode.\n");
24106c3fb27SDimitry Andric     return SchedClassID;
24206c3fb27SDimitry Andric   }
24306c3fb27SDimitry Andric   uint8_t LMUL = LI->getLMUL();
24406c3fb27SDimitry Andric 
24506c3fb27SDimitry Andric   // getBaseInfo works with (Opcode, LMUL, 0) if no SEW instrument,
24606c3fb27SDimitry Andric   // or (Opcode, LMUL, SEW) if SEW instrument is active, and depends on LMUL
24706c3fb27SDimitry Andric   // and SEW, or (Opcode, LMUL, 0) if does not depend on SEW.
24806c3fb27SDimitry Andric   uint8_t SEW = SI ? SI->getSEW() : 0;
2495f757f3fSDimitry Andric 
2505f757f3fSDimitry Andric   const RISCVVInversePseudosTable::PseudoInfo *RVV = nullptr;
251*1db9f3b2SDimitry Andric   if (opcodeHasEEWAndEMULInfo(Opcode)) {
2525f757f3fSDimitry Andric     RISCVII::VLMUL VLMUL = static_cast<RISCVII::VLMUL>(LMUL);
253*1db9f3b2SDimitry Andric     auto [EEW, EMUL] = getEEWAndEMUL(Opcode, VLMUL, SEW);
2545f757f3fSDimitry Andric     RVV = RISCVVInversePseudosTable::getBaseInfo(Opcode, EMUL, EEW);
2555f757f3fSDimitry Andric   } else {
25606c3fb27SDimitry Andric     // Check if it depends on LMUL and SEW
2575f757f3fSDimitry Andric     RVV = RISCVVInversePseudosTable::getBaseInfo(Opcode, LMUL, SEW);
25806c3fb27SDimitry Andric     // Check if it depends only on LMUL
25906c3fb27SDimitry Andric     if (!RVV)
26006c3fb27SDimitry Andric       RVV = RISCVVInversePseudosTable::getBaseInfo(Opcode, LMUL, 0);
2615f757f3fSDimitry Andric   }
26206c3fb27SDimitry Andric 
263bdd1243dSDimitry Andric   // Not a RVV instr
264bdd1243dSDimitry Andric   if (!RVV) {
265bdd1243dSDimitry Andric     LLVM_DEBUG(
26606c3fb27SDimitry Andric         dbgs() << "RVCB: Could not find PseudoInstruction for Opcode "
26706c3fb27SDimitry Andric                << MCII.getName(Opcode)
26806c3fb27SDimitry Andric                << ", LMUL=" << (LI ? LI->getData() : "Unspecified")
26906c3fb27SDimitry Andric                << ", SEW=" << (SI ? SI->getData() : "Unspecified")
270bdd1243dSDimitry Andric                << ". Ignoring instrumentation and using original SchedClassID="
271bdd1243dSDimitry Andric                << SchedClassID << '\n');
272bdd1243dSDimitry Andric     return SchedClassID;
273bdd1243dSDimitry Andric   }
274bdd1243dSDimitry Andric 
275bdd1243dSDimitry Andric   // Override using pseudo
276bdd1243dSDimitry Andric   LLVM_DEBUG(dbgs() << "RVCB: Found Pseudo Instruction for Opcode "
27706c3fb27SDimitry Andric                     << MCII.getName(Opcode) << ", LMUL=" << LI->getData()
27806c3fb27SDimitry Andric                     << ", SEW=" << (SI ? SI->getData() : "Unspecified")
279bdd1243dSDimitry Andric                     << ". Overriding original SchedClassID=" << SchedClassID
280bdd1243dSDimitry Andric                     << " with " << MCII.getName(RVV->Pseudo) << '\n');
281bdd1243dSDimitry Andric   return MCII.get(RVV->Pseudo).getSchedClass();
282bdd1243dSDimitry Andric }
283bdd1243dSDimitry Andric 
284bdd1243dSDimitry Andric } // namespace mca
285bdd1243dSDimitry Andric } // namespace llvm
286bdd1243dSDimitry Andric 
287bdd1243dSDimitry Andric using namespace llvm;
288bdd1243dSDimitry Andric using namespace mca;
289bdd1243dSDimitry Andric 
290bdd1243dSDimitry Andric static InstrumentManager *
291bdd1243dSDimitry Andric createRISCVInstrumentManager(const MCSubtargetInfo &STI,
292bdd1243dSDimitry Andric                              const MCInstrInfo &MCII) {
293bdd1243dSDimitry Andric   return new RISCVInstrumentManager(STI, MCII);
294bdd1243dSDimitry Andric }
295bdd1243dSDimitry Andric 
29606c3fb27SDimitry Andric /// Extern function to initialize the targets for the RISC-V backend
297bdd1243dSDimitry Andric extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVTargetMCA() {
298bdd1243dSDimitry Andric   TargetRegistry::RegisterInstrumentManager(getTheRISCV32Target(),
299bdd1243dSDimitry Andric                                             createRISCVInstrumentManager);
300bdd1243dSDimitry Andric   TargetRegistry::RegisterInstrumentManager(getTheRISCV64Target(),
301bdd1243dSDimitry Andric                                             createRISCVInstrumentManager);
302bdd1243dSDimitry Andric }
303