355 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8/// \file9///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/Compiler.h"20#include "llvm/Support/Debug.h"21#include "llvm/Support/DebugLog.h"22 23#define DEBUG_TYPE "llvm-mca-riscv-custombehaviour"24 25namespace llvm::RISCV {26struct VXMemOpInfo {27 unsigned Log2IdxEEW : 3;28 unsigned IsOrdered : 1;29 unsigned IsStore : 1;30 unsigned NF : 4;31 unsigned BaseInstr;32};33 34#define GET_RISCVBaseVXMemOpTable_IMPL35#include "RISCVGenSearchableTables.inc"36} // namespace llvm::RISCV37 38namespace llvm {39namespace mca {40 41const llvm::StringRef RISCVLMULInstrument::DESC_NAME = "RISCV-LMUL";42 43bool RISCVLMULInstrument::isDataValid(llvm::StringRef Data) {44 // Return true if not one of the valid LMUL strings45 return StringSwitch<bool>(Data)46 .Cases({"M1", "M2", "M4", "M8", "MF2", "MF4", "MF8"}, true)47 .Default(false);48}49 50uint8_t RISCVLMULInstrument::getLMUL() const {51 // assertion prevents us from needing llvm_unreachable in the StringSwitch52 // below53 assert(isDataValid(getData()) &&54 "Cannot get LMUL because invalid Data value");55 // These are the LMUL values that are used in RISC-V tablegen56 return StringSwitch<uint8_t>(getData())57 .Case("M1", 0b000)58 .Case("M2", 0b001)59 .Case("M4", 0b010)60 .Case("M8", 0b011)61 .Case("MF2", 0b111)62 .Case("MF4", 0b110)63 .Case("MF8", 0b101);64}65 66const llvm::StringRef RISCVSEWInstrument::DESC_NAME = "RISCV-SEW";67 68bool RISCVSEWInstrument::isDataValid(llvm::StringRef Data) {69 // Return true if not one of the valid SEW strings70 return StringSwitch<bool>(Data)71 .Cases({"E8", "E16", "E32", "E64"}, true)72 .Default(false);73}74 75uint8_t RISCVSEWInstrument::getSEW() const {76 // assertion prevents us from needing llvm_unreachable in the StringSwitch77 // below78 assert(isDataValid(getData()) && "Cannot get SEW because invalid Data value");79 // These are the LMUL values that are used in RISC-V tablegen80 return StringSwitch<uint8_t>(getData())81 .Case("E8", 8)82 .Case("E16", 16)83 .Case("E32", 32)84 .Case("E64", 64);85}86 87bool RISCVInstrumentManager::supportsInstrumentType(88 llvm::StringRef Type) const {89 return Type == RISCVLMULInstrument::DESC_NAME ||90 Type == RISCVSEWInstrument::DESC_NAME ||91 InstrumentManager::supportsInstrumentType(Type);92}93 94UniqueInstrument95RISCVInstrumentManager::createInstrument(llvm::StringRef Desc,96 llvm::StringRef Data) {97 if (Desc == RISCVLMULInstrument::DESC_NAME) {98 if (!RISCVLMULInstrument::isDataValid(Data)) {99 LDBG() << "RVCB: Bad data for instrument kind " << Desc << ": " << Data100 << '\n';101 return nullptr;102 }103 return std::make_unique<RISCVLMULInstrument>(Data);104 }105 106 if (Desc == RISCVSEWInstrument::DESC_NAME) {107 if (!RISCVSEWInstrument::isDataValid(Data)) {108 LDBG() << "RVCB: Bad data for instrument kind " << Desc << ": " << Data109 << '\n';110 return nullptr;111 }112 return std::make_unique<RISCVSEWInstrument>(Data);113 }114 115 LDBG() << "RVCB: Creating default instrument for Desc: " << Desc << '\n';116 return InstrumentManager::createInstrument(Desc, Data);117}118 119SmallVector<UniqueInstrument>120RISCVInstrumentManager::createInstruments(const MCInst &Inst) {121 if (Inst.getOpcode() == RISCV::VSETVLI ||122 Inst.getOpcode() == RISCV::VSETIVLI) {123 LDBG() << "RVCB: Found VSETVLI and creating instrument for it: " << Inst124 << "\n";125 unsigned VTypeI = Inst.getOperand(2).getImm();126 RISCVVType::VLMUL VLMUL = RISCVVType::getVLMUL(VTypeI);127 128 StringRef LMUL;129 switch (VLMUL) {130 case RISCVVType::LMUL_1:131 LMUL = "M1";132 break;133 case RISCVVType::LMUL_2:134 LMUL = "M2";135 break;136 case RISCVVType::LMUL_4:137 LMUL = "M4";138 break;139 case RISCVVType::LMUL_8:140 LMUL = "M8";141 break;142 case RISCVVType::LMUL_F2:143 LMUL = "MF2";144 break;145 case RISCVVType::LMUL_F4:146 LMUL = "MF4";147 break;148 case RISCVVType::LMUL_F8:149 LMUL = "MF8";150 break;151 case RISCVVType::LMUL_RESERVED:152 llvm_unreachable("Cannot create instrument for LMUL_RESERVED");153 }154 SmallVector<UniqueInstrument> Instruments;155 Instruments.emplace_back(156 createInstrument(RISCVLMULInstrument::DESC_NAME, LMUL));157 158 unsigned SEW = RISCVVType::getSEW(VTypeI);159 StringRef SEWStr;160 switch (SEW) {161 case 8:162 SEWStr = "E8";163 break;164 case 16:165 SEWStr = "E16";166 break;167 case 32:168 SEWStr = "E32";169 break;170 case 64:171 SEWStr = "E64";172 break;173 default:174 llvm_unreachable("Cannot create instrument for SEW");175 }176 Instruments.emplace_back(177 createInstrument(RISCVSEWInstrument::DESC_NAME, SEWStr));178 179 return Instruments;180 }181 return SmallVector<UniqueInstrument>();182}183 184static std::pair<uint8_t, uint8_t>185getEEWAndEMUL(unsigned Opcode, RISCVVType::VLMUL LMUL, uint8_t SEW) {186 uint8_t EEW;187 switch (Opcode) {188 case RISCV::VLM_V:189 case RISCV::VSM_V:190 case RISCV::VLE8_V:191 case RISCV::VSE8_V:192 case RISCV::VLSE8_V:193 case RISCV::VSSE8_V:194 EEW = 8;195 break;196 case RISCV::VLE16_V:197 case RISCV::VSE16_V:198 case RISCV::VLSE16_V:199 case RISCV::VSSE16_V:200 EEW = 16;201 break;202 case RISCV::VLE32_V:203 case RISCV::VSE32_V:204 case RISCV::VLSE32_V:205 case RISCV::VSSE32_V:206 EEW = 32;207 break;208 case RISCV::VLE64_V:209 case RISCV::VSE64_V:210 case RISCV::VLSE64_V:211 case RISCV::VSSE64_V:212 EEW = 64;213 break;214 default:215 llvm_unreachable("Could not determine EEW from Opcode");216 }217 218 auto EMUL = RISCVVType::getSameRatioLMUL(SEW, LMUL, EEW);219 if (!EEW)220 llvm_unreachable("Invalid SEW or LMUL for new ratio");221 return std::make_pair(EEW, *EMUL);222}223 224static bool opcodeHasEEWAndEMULInfo(unsigned short Opcode) {225 return Opcode == RISCV::VLM_V || Opcode == RISCV::VSM_V ||226 Opcode == RISCV::VLE8_V || Opcode == RISCV::VSE8_V ||227 Opcode == RISCV::VLE16_V || Opcode == RISCV::VSE16_V ||228 Opcode == RISCV::VLE32_V || Opcode == RISCV::VSE32_V ||229 Opcode == RISCV::VLE64_V || Opcode == RISCV::VSE64_V ||230 Opcode == RISCV::VLSE8_V || Opcode == RISCV::VSSE8_V ||231 Opcode == RISCV::VLSE16_V || Opcode == RISCV::VSSE16_V ||232 Opcode == RISCV::VLSE32_V || Opcode == RISCV::VSSE32_V ||233 Opcode == RISCV::VLSE64_V || Opcode == RISCV::VSSE64_V;234}235 236unsigned RISCVInstrumentManager::getSchedClassID(237 const MCInstrInfo &MCII, const MCInst &MCI,238 const llvm::SmallVector<Instrument *> &IVec) const {239 unsigned short Opcode = MCI.getOpcode();240 unsigned SchedClassID = MCII.get(Opcode).getSchedClass();241 242 // Unpack all possible RISC-V instruments from IVec.243 RISCVLMULInstrument *LI = nullptr;244 RISCVSEWInstrument *SI = nullptr;245 for (auto &I : IVec) {246 if (I->getDesc() == RISCVLMULInstrument::DESC_NAME)247 LI = static_cast<RISCVLMULInstrument *>(I);248 else if (I->getDesc() == RISCVSEWInstrument::DESC_NAME)249 SI = static_cast<RISCVSEWInstrument *>(I);250 }251 252 // Need LMUL or LMUL, SEW in order to override opcode. If no LMUL is provided,253 // then no option to override.254 if (!LI) {255 LDBG() << "RVCB: Did not use instrumentation to override Opcode.\n";256 return SchedClassID;257 }258 uint8_t LMUL = LI->getLMUL();259 260 // getBaseInfo works with (Opcode, LMUL, 0) if no SEW instrument,261 // or (Opcode, LMUL, SEW) if SEW instrument is active, and depends on LMUL262 // and SEW, or (Opcode, LMUL, 0) if does not depend on SEW.263 uint8_t SEW = SI ? SI->getSEW() : 0;264 265 std::optional<unsigned> VPOpcode;266 if (const auto *VXMO = RISCV::getVXMemOpInfo(Opcode)) {267 // Calculate the expected index EMUL. For indexed operations,268 // the DataEEW and DataEMUL are equal to SEW and LMUL, respectively.269 unsigned IndexEMUL = ((1 << VXMO->Log2IdxEEW) * LMUL) / SEW;270 271 if (!VXMO->NF) {272 // Indexed Load / Store.273 if (VXMO->IsStore) {274 if (const auto *VXP = RISCV::getVSXPseudo(275 /*Masked=*/0, VXMO->IsOrdered, VXMO->Log2IdxEEW, LMUL,276 IndexEMUL))277 VPOpcode = VXP->Pseudo;278 } else {279 if (const auto *VXP = RISCV::getVLXPseudo(280 /*Masked=*/0, VXMO->IsOrdered, VXMO->Log2IdxEEW, LMUL,281 IndexEMUL))282 VPOpcode = VXP->Pseudo;283 }284 } else {285 // Segmented Indexed Load / Store.286 if (VXMO->IsStore) {287 if (const auto *VXP =288 RISCV::getVSXSEGPseudo(VXMO->NF, /*Masked=*/0, VXMO->IsOrdered,289 VXMO->Log2IdxEEW, LMUL, IndexEMUL))290 VPOpcode = VXP->Pseudo;291 } else {292 if (const auto *VXP =293 RISCV::getVLXSEGPseudo(VXMO->NF, /*Masked=*/0, VXMO->IsOrdered,294 VXMO->Log2IdxEEW, LMUL, IndexEMUL))295 VPOpcode = VXP->Pseudo;296 }297 }298 } else if (opcodeHasEEWAndEMULInfo(Opcode)) {299 RISCVVType::VLMUL VLMUL = static_cast<RISCVVType::VLMUL>(LMUL);300 auto [EEW, EMUL] = getEEWAndEMUL(Opcode, VLMUL, SEW);301 if (const auto *RVV =302 RISCVVInversePseudosTable::getBaseInfo(Opcode, EMUL, EEW))303 VPOpcode = RVV->Pseudo;304 } else {305 // Check if it depends on LMUL and SEW306 const auto *RVV = RISCVVInversePseudosTable::getBaseInfo(Opcode, LMUL, SEW);307 // Check if it depends only on LMUL308 if (!RVV)309 RVV = RISCVVInversePseudosTable::getBaseInfo(Opcode, LMUL, 0);310 311 if (RVV)312 VPOpcode = RVV->Pseudo;313 }314 315 // Not a RVV instr316 if (!VPOpcode) {317 LDBG() << "RVCB: Could not find PseudoInstruction for Opcode "318 << MCII.getName(Opcode)319 << ", LMUL=" << (LI ? LI->getData() : "Unspecified")320 << ", SEW=" << (SI ? SI->getData() : "Unspecified")321 << ". Ignoring instrumentation and using original SchedClassID="322 << SchedClassID << '\n';323 return SchedClassID;324 }325 326 // Override using pseudo327 LDBG() << "RVCB: Found Pseudo Instruction for Opcode " << MCII.getName(Opcode)328 << ", LMUL=" << LI->getData()329 << ", SEW=" << (SI ? SI->getData() : "Unspecified")330 << ". Overriding original SchedClassID=" << SchedClassID << " with "331 << MCII.getName(*VPOpcode) << '\n';332 return MCII.get(*VPOpcode).getSchedClass();333}334 335} // namespace mca336} // namespace llvm337 338using namespace llvm;339using namespace mca;340 341static InstrumentManager *342createRISCVInstrumentManager(const MCSubtargetInfo &STI,343 const MCInstrInfo &MCII) {344 return new RISCVInstrumentManager(STI, MCII);345}346 347/// Extern function to initialize the targets for the RISC-V backend348extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void349LLVMInitializeRISCVTargetMCA() {350 TargetRegistry::RegisterInstrumentManager(getTheRISCV32Target(),351 createRISCVInstrumentManager);352 TargetRegistry::RegisterInstrumentManager(getTheRISCV64Target(),353 createRISCVInstrumentManager);354}355