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