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