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
isDataValid(llvm::StringRef Data)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
getLMUL() const54 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
supportsInstrumentType(llvm::StringRef Type) const70 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
createInstrument(llvm::StringRef Desc,llvm::StringRef Data)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
getSchedClassID(const MCInstrInfo & MCII,const MCInst & MCI,const llvm::SmallVector<SharedInstrument> & IVec) const92 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 *
createRISCVInstrumentManager(const MCSubtargetInfo & STI,const MCInstrInfo & MCII)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
LLVMInitializeRISCVTargetMCA()143 extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVTargetMCA() {
144 TargetRegistry::RegisterInstrumentManager(getTheRISCV32Target(),
145 createRISCVInstrumentManager);
146 TargetRegistry::RegisterInstrumentManager(getTheRISCV64Target(),
147 createRISCVInstrumentManager);
148 }
149