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 getEEWAndEMULForUnitStrideLoadStore(unsigned Opcode, RISCVII::VLMUL LMUL, 190 uint8_t SEW) { 191 uint8_t EEW; 192 switch (Opcode) { 193 case RISCV::VLM_V: 194 case RISCV::VSM_V: 195 case RISCV::VLE8_V: 196 case RISCV::VSE8_V: 197 EEW = 8; 198 break; 199 case RISCV::VLE16_V: 200 case RISCV::VSE16_V: 201 EEW = 16; 202 break; 203 case RISCV::VLE32_V: 204 case RISCV::VSE32_V: 205 EEW = 32; 206 break; 207 case RISCV::VLE64_V: 208 case RISCV::VSE64_V: 209 EEW = 64; 210 break; 211 default: 212 llvm_unreachable("Opcode is not a vector unit stride load nor store"); 213 } 214 215 auto EMUL = RISCVVType::getSameRatioLMUL(SEW, LMUL, EEW); 216 if (!EEW) 217 llvm_unreachable("Invalid SEW or LMUL for new ratio"); 218 return std::make_pair(EEW, *EMUL); 219 } 220 221 unsigned RISCVInstrumentManager::getSchedClassID( 222 const MCInstrInfo &MCII, const MCInst &MCI, 223 const llvm::SmallVector<Instrument *> &IVec) const { 224 unsigned short Opcode = MCI.getOpcode(); 225 unsigned SchedClassID = MCII.get(Opcode).getSchedClass(); 226 227 // Unpack all possible RISC-V instruments from IVec. 228 RISCVLMULInstrument *LI = nullptr; 229 RISCVSEWInstrument *SI = nullptr; 230 for (auto &I : IVec) { 231 if (I->getDesc() == RISCVLMULInstrument::DESC_NAME) 232 LI = static_cast<RISCVLMULInstrument *>(I); 233 else if (I->getDesc() == RISCVSEWInstrument::DESC_NAME) 234 SI = static_cast<RISCVSEWInstrument *>(I); 235 } 236 237 // Need LMUL or LMUL, SEW in order to override opcode. If no LMUL is provided, 238 // then no option to override. 239 if (!LI) { 240 LLVM_DEBUG( 241 dbgs() << "RVCB: Did not use instrumentation to override Opcode.\n"); 242 return SchedClassID; 243 } 244 uint8_t LMUL = LI->getLMUL(); 245 246 // getBaseInfo works with (Opcode, LMUL, 0) if no SEW instrument, 247 // or (Opcode, LMUL, SEW) if SEW instrument is active, and depends on LMUL 248 // and SEW, or (Opcode, LMUL, 0) if does not depend on SEW. 249 uint8_t SEW = SI ? SI->getSEW() : 0; 250 251 const RISCVVInversePseudosTable::PseudoInfo *RVV = nullptr; 252 if (Opcode == RISCV::VLM_V || Opcode == RISCV::VSM_V || 253 Opcode == RISCV::VLE8_V || Opcode == RISCV::VSE8_V || 254 Opcode == RISCV::VLE16_V || Opcode == RISCV::VSE16_V || 255 Opcode == RISCV::VLE32_V || Opcode == RISCV::VSE32_V || 256 Opcode == RISCV::VLE64_V || Opcode == RISCV::VSE64_V) { 257 RISCVII::VLMUL VLMUL = static_cast<RISCVII::VLMUL>(LMUL); 258 auto [EEW, EMUL] = getEEWAndEMULForUnitStrideLoadStore(Opcode, VLMUL, SEW); 259 RVV = RISCVVInversePseudosTable::getBaseInfo(Opcode, EMUL, EEW); 260 } else { 261 // Check if it depends on LMUL and SEW 262 RVV = RISCVVInversePseudosTable::getBaseInfo(Opcode, LMUL, SEW); 263 // Check if it depends only on LMUL 264 if (!RVV) 265 RVV = RISCVVInversePseudosTable::getBaseInfo(Opcode, LMUL, 0); 266 } 267 268 // Not a RVV instr 269 if (!RVV) { 270 LLVM_DEBUG( 271 dbgs() << "RVCB: Could not find PseudoInstruction for Opcode " 272 << MCII.getName(Opcode) 273 << ", LMUL=" << (LI ? LI->getData() : "Unspecified") 274 << ", SEW=" << (SI ? SI->getData() : "Unspecified") 275 << ". Ignoring instrumentation and using original SchedClassID=" 276 << SchedClassID << '\n'); 277 return SchedClassID; 278 } 279 280 // Override using pseudo 281 LLVM_DEBUG(dbgs() << "RVCB: Found Pseudo Instruction for Opcode " 282 << MCII.getName(Opcode) << ", LMUL=" << LI->getData() 283 << ", SEW=" << (SI ? SI->getData() : "Unspecified") 284 << ". Overriding original SchedClassID=" << SchedClassID 285 << " with " << MCII.getName(RVV->Pseudo) << '\n'); 286 return MCII.get(RVV->Pseudo).getSchedClass(); 287 } 288 289 } // namespace mca 290 } // namespace llvm 291 292 using namespace llvm; 293 using namespace mca; 294 295 static InstrumentManager * 296 createRISCVInstrumentManager(const MCSubtargetInfo &STI, 297 const MCInstrInfo &MCII) { 298 return new RISCVInstrumentManager(STI, MCII); 299 } 300 301 /// Extern function to initialize the targets for the RISC-V backend 302 extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVTargetMCA() { 303 TargetRegistry::RegisterInstrumentManager(getTheRISCV32Target(), 304 createRISCVInstrumentManager); 305 TargetRegistry::RegisterInstrumentManager(getTheRISCV64Target(), 306 createRISCVInstrumentManager); 307 } 308