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 "RISCVInstrInfo.h"
17 #include "TargetInfo/RISCVTargetInfo.h"
18 #include "llvm/MC/TargetRegistry.h"
19 #include "llvm/Support/Debug.h"
20 
21 #define DEBUG_TYPE "llvm-mca-riscv-custombehaviour"
22 
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 {
27 using namespace llvm;
28 using namespace llvm::RISCV;
29 
30 struct PseudoInfo {
31   uint16_t Pseudo;
32   uint16_t BaseInstr;
33   uint8_t VLMul;
34 };
35 
36 #define GET_RISCVVInversePseudosTable_IMPL
37 #define GET_RISCVVInversePseudosTable_DECL
38 #include "RISCVGenSearchableTables.inc"
39 
40 } // end namespace RISCVVInversePseudosTable
41 
42 namespace llvm {
43 namespace mca {
44 
45 const llvm::StringRef RISCVLMULInstrument::DESC_NAME = "RISCV-LMUL";
46 
47 bool RISCVLMULInstrument::isDataValid(llvm::StringRef Data) {
48   // Return true if not one of the valid LMUL strings
49   return StringSwitch<bool>(Data)
50       .Cases("M1", "M2", "M4", "M8", "MF2", "MF4", "MF8", true)
51       .Default(false);
52 }
53 
54 uint8_t RISCVLMULInstrument::getLMUL() const {
55   // assertion prevents us from needing llvm_unreachable in the StringSwitch
56   // below
57   assert(isDataValid(getData()) &&
58          "Cannot get LMUL because invalid Data value");
59   // These are the LMUL values that are used in RISCV tablegen
60   return StringSwitch<uint8_t>(getData())
61       .Case("M1", 0b000)
62       .Case("M2", 0b001)
63       .Case("M4", 0b010)
64       .Case("M8", 0b011)
65       .Case("MF2", 0b101)
66       .Case("MF4", 0b110)
67       .Case("MF8", 0b111);
68 }
69 
70 bool RISCVInstrumentManager::supportsInstrumentType(
71     llvm::StringRef Type) const {
72   // Currently, only support for RISCVLMULInstrument type
73   return Type == RISCVLMULInstrument::DESC_NAME;
74 }
75 
76 SharedInstrument
77 RISCVInstrumentManager::createInstrument(llvm::StringRef Desc,
78                                          llvm::StringRef Data) {
79   if (Desc != RISCVLMULInstrument::DESC_NAME) {
80     LLVM_DEBUG(dbgs() << "RVCB: Unknown instrumentation Desc: " << Desc
81                       << '\n');
82     return nullptr;
83   }
84   if (RISCVLMULInstrument::isDataValid(Data)) {
85     LLVM_DEBUG(dbgs() << "RVCB: Bad data for instrument kind " << Desc << ": "
86                       << Data << '\n');
87     return nullptr;
88   }
89   return std::make_shared<RISCVLMULInstrument>(Data);
90 }
91 
92 unsigned RISCVInstrumentManager::getSchedClassID(
93     const MCInstrInfo &MCII, const MCInst &MCI,
94     const llvm::SmallVector<SharedInstrument> &IVec) const {
95   unsigned short Opcode = MCI.getOpcode();
96   unsigned SchedClassID = MCII.get(Opcode).getSchedClass();
97 
98   for (const auto &I : IVec) {
99     // Unknown Instrument kind
100     if (I->getDesc() == RISCVLMULInstrument::DESC_NAME) {
101       uint8_t LMUL = static_cast<RISCVLMULInstrument *>(I.get())->getLMUL();
102       const RISCVVInversePseudosTable::PseudoInfo *RVV =
103           RISCVVInversePseudosTable::getBaseInfo(Opcode, LMUL);
104       // Not a RVV instr
105       if (!RVV) {
106         LLVM_DEBUG(
107             dbgs()
108             << "RVCB: Could not find PseudoInstruction for Opcode "
109             << MCII.getName(Opcode) << ", LMUL=" << I->getData()
110             << ". Ignoring instrumentation and using original SchedClassID="
111             << SchedClassID << '\n');
112         return SchedClassID;
113       }
114 
115       // Override using pseudo
116       LLVM_DEBUG(dbgs() << "RVCB: Found Pseudo Instruction for Opcode "
117                         << MCII.getName(Opcode) << ", LMUL=" << I->getData()
118                         << ". Overriding original SchedClassID=" << SchedClassID
119                         << " with " << MCII.getName(RVV->Pseudo) << '\n');
120       return MCII.get(RVV->Pseudo).getSchedClass();
121     }
122   }
123 
124   // Unknown Instrument kind
125   LLVM_DEBUG(
126       dbgs() << "RVCB: Did not use instrumentation to override Opcode.\n");
127   return SchedClassID;
128 }
129 
130 } // namespace mca
131 } // namespace llvm
132 
133 using namespace llvm;
134 using namespace mca;
135 
136 static InstrumentManager *
137 createRISCVInstrumentManager(const MCSubtargetInfo &STI,
138                              const MCInstrInfo &MCII) {
139   return new RISCVInstrumentManager(STI, MCII);
140 }
141 
142 /// Extern function to initialize the targets for the RISCV backend
143 extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVTargetMCA() {
144   TargetRegistry::RegisterInstrumentManager(getTheRISCV32Target(),
145                                             createRISCVInstrumentManager);
146   TargetRegistry::RegisterInstrumentManager(getTheRISCV64Target(),
147                                             createRISCVInstrumentManager);
148 }
149