1bdd1243dSDimitry Andric //===------------------- RISCVCustomBehaviour.cpp ---------------*-C++ -* -===// 2bdd1243dSDimitry Andric // 3bdd1243dSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4bdd1243dSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5bdd1243dSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6bdd1243dSDimitry Andric // 7bdd1243dSDimitry Andric //===----------------------------------------------------------------------===// 8bdd1243dSDimitry Andric /// \file 9bdd1243dSDimitry Andric /// 10bdd1243dSDimitry Andric /// This file implements methods from the RISCVCustomBehaviour class. 11bdd1243dSDimitry Andric /// 12bdd1243dSDimitry Andric //===----------------------------------------------------------------------===// 13bdd1243dSDimitry Andric 14bdd1243dSDimitry Andric #include "RISCVCustomBehaviour.h" 15bdd1243dSDimitry Andric #include "MCTargetDesc/RISCVMCTargetDesc.h" 1606c3fb27SDimitry Andric #include "RISCV.h" 17bdd1243dSDimitry Andric #include "TargetInfo/RISCVTargetInfo.h" 18bdd1243dSDimitry Andric #include "llvm/MC/TargetRegistry.h" 19bdd1243dSDimitry Andric #include "llvm/Support/Debug.h" 20bdd1243dSDimitry Andric 21bdd1243dSDimitry Andric #define DEBUG_TYPE "llvm-mca-riscv-custombehaviour" 22bdd1243dSDimitry Andric 23bdd1243dSDimitry Andric // This brings in a table with primary key of 24bdd1243dSDimitry Andric // base instruction opcode and lmul and maps 25bdd1243dSDimitry Andric // to the opcode of the pseudo instruction. 26bdd1243dSDimitry Andric namespace RISCVVInversePseudosTable { 27bdd1243dSDimitry Andric using namespace llvm; 28bdd1243dSDimitry Andric using namespace llvm::RISCV; 29bdd1243dSDimitry Andric 30bdd1243dSDimitry Andric struct PseudoInfo { 31bdd1243dSDimitry Andric uint16_t Pseudo; 32bdd1243dSDimitry Andric uint16_t BaseInstr; 33bdd1243dSDimitry Andric uint8_t VLMul; 3406c3fb27SDimitry Andric uint8_t SEW; 35bdd1243dSDimitry Andric }; 36bdd1243dSDimitry Andric 37bdd1243dSDimitry Andric #define GET_RISCVVInversePseudosTable_IMPL 38bdd1243dSDimitry Andric #define GET_RISCVVInversePseudosTable_DECL 39bdd1243dSDimitry Andric #include "RISCVGenSearchableTables.inc" 40bdd1243dSDimitry Andric 41bdd1243dSDimitry Andric } // end namespace RISCVVInversePseudosTable 42bdd1243dSDimitry Andric 43bdd1243dSDimitry Andric namespace llvm { 44bdd1243dSDimitry Andric namespace mca { 45bdd1243dSDimitry Andric 46bdd1243dSDimitry Andric const llvm::StringRef RISCVLMULInstrument::DESC_NAME = "RISCV-LMUL"; 47bdd1243dSDimitry Andric 48bdd1243dSDimitry Andric bool RISCVLMULInstrument::isDataValid(llvm::StringRef Data) { 49bdd1243dSDimitry Andric // Return true if not one of the valid LMUL strings 50bdd1243dSDimitry Andric return StringSwitch<bool>(Data) 51bdd1243dSDimitry Andric .Cases("M1", "M2", "M4", "M8", "MF2", "MF4", "MF8", true) 52bdd1243dSDimitry Andric .Default(false); 53bdd1243dSDimitry Andric } 54bdd1243dSDimitry Andric 55bdd1243dSDimitry Andric uint8_t RISCVLMULInstrument::getLMUL() const { 56bdd1243dSDimitry Andric // assertion prevents us from needing llvm_unreachable in the StringSwitch 57bdd1243dSDimitry Andric // below 58bdd1243dSDimitry Andric assert(isDataValid(getData()) && 59bdd1243dSDimitry Andric "Cannot get LMUL because invalid Data value"); 6006c3fb27SDimitry Andric // These are the LMUL values that are used in RISC-V tablegen 61bdd1243dSDimitry Andric return StringSwitch<uint8_t>(getData()) 62bdd1243dSDimitry Andric .Case("M1", 0b000) 63bdd1243dSDimitry Andric .Case("M2", 0b001) 64bdd1243dSDimitry Andric .Case("M4", 0b010) 65bdd1243dSDimitry Andric .Case("M8", 0b011) 665f757f3fSDimitry Andric .Case("MF2", 0b111) 67bdd1243dSDimitry Andric .Case("MF4", 0b110) 685f757f3fSDimitry Andric .Case("MF8", 0b101); 69bdd1243dSDimitry Andric } 70bdd1243dSDimitry Andric 7106c3fb27SDimitry Andric const llvm::StringRef RISCVSEWInstrument::DESC_NAME = "RISCV-SEW"; 7206c3fb27SDimitry Andric 7306c3fb27SDimitry Andric bool RISCVSEWInstrument::isDataValid(llvm::StringRef Data) { 7406c3fb27SDimitry Andric // Return true if not one of the valid SEW strings 7506c3fb27SDimitry Andric return StringSwitch<bool>(Data) 7606c3fb27SDimitry Andric .Cases("E8", "E16", "E32", "E64", true) 7706c3fb27SDimitry Andric .Default(false); 78bdd1243dSDimitry Andric } 79bdd1243dSDimitry Andric 8006c3fb27SDimitry Andric uint8_t RISCVSEWInstrument::getSEW() const { 8106c3fb27SDimitry Andric // assertion prevents us from needing llvm_unreachable in the StringSwitch 8206c3fb27SDimitry Andric // below 8306c3fb27SDimitry Andric assert(isDataValid(getData()) && "Cannot get SEW because invalid Data value"); 8406c3fb27SDimitry Andric // These are the LMUL values that are used in RISC-V tablegen 8506c3fb27SDimitry Andric return StringSwitch<uint8_t>(getData()) 8606c3fb27SDimitry Andric .Case("E8", 8) 8706c3fb27SDimitry Andric .Case("E16", 16) 8806c3fb27SDimitry Andric .Case("E32", 32) 8906c3fb27SDimitry Andric .Case("E64", 64); 9006c3fb27SDimitry Andric } 9106c3fb27SDimitry Andric 9206c3fb27SDimitry Andric bool RISCVInstrumentManager::supportsInstrumentType( 9306c3fb27SDimitry Andric llvm::StringRef Type) const { 9406c3fb27SDimitry Andric return Type == RISCVLMULInstrument::DESC_NAME || 9506c3fb27SDimitry Andric Type == RISCVSEWInstrument::DESC_NAME; 9606c3fb27SDimitry Andric } 9706c3fb27SDimitry Andric 9806c3fb27SDimitry Andric UniqueInstrument 99bdd1243dSDimitry Andric RISCVInstrumentManager::createInstrument(llvm::StringRef Desc, 100bdd1243dSDimitry Andric llvm::StringRef Data) { 10106c3fb27SDimitry Andric if (Desc == RISCVLMULInstrument::DESC_NAME) { 10206c3fb27SDimitry Andric if (!RISCVLMULInstrument::isDataValid(Data)) { 103bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "RVCB: Bad data for instrument kind " << Desc << ": " 104bdd1243dSDimitry Andric << Data << '\n'); 105bdd1243dSDimitry Andric return nullptr; 106bdd1243dSDimitry Andric } 10706c3fb27SDimitry Andric return std::make_unique<RISCVLMULInstrument>(Data); 10806c3fb27SDimitry Andric } 10906c3fb27SDimitry Andric 11006c3fb27SDimitry Andric if (Desc == RISCVSEWInstrument::DESC_NAME) { 11106c3fb27SDimitry Andric if (!RISCVSEWInstrument::isDataValid(Data)) { 11206c3fb27SDimitry Andric LLVM_DEBUG(dbgs() << "RVCB: Bad data for instrument kind " << Desc << ": " 11306c3fb27SDimitry Andric << Data << '\n'); 11406c3fb27SDimitry Andric return nullptr; 11506c3fb27SDimitry Andric } 11606c3fb27SDimitry Andric return std::make_unique<RISCVSEWInstrument>(Data); 11706c3fb27SDimitry Andric } 11806c3fb27SDimitry Andric 11906c3fb27SDimitry Andric LLVM_DEBUG(dbgs() << "RVCB: Unknown instrumentation Desc: " << Desc << '\n'); 12006c3fb27SDimitry Andric return nullptr; 12106c3fb27SDimitry Andric } 12206c3fb27SDimitry Andric 12306c3fb27SDimitry Andric SmallVector<UniqueInstrument> 12406c3fb27SDimitry Andric RISCVInstrumentManager::createInstruments(const MCInst &Inst) { 12506c3fb27SDimitry Andric if (Inst.getOpcode() == RISCV::VSETVLI || 12606c3fb27SDimitry Andric Inst.getOpcode() == RISCV::VSETIVLI) { 12706c3fb27SDimitry Andric LLVM_DEBUG(dbgs() << "RVCB: Found VSETVLI and creating instrument for it: " 12806c3fb27SDimitry Andric << Inst << "\n"); 12906c3fb27SDimitry Andric unsigned VTypeI = Inst.getOperand(2).getImm(); 13006c3fb27SDimitry Andric RISCVII::VLMUL VLMUL = RISCVVType::getVLMUL(VTypeI); 13106c3fb27SDimitry Andric 13206c3fb27SDimitry Andric StringRef LMUL; 13306c3fb27SDimitry Andric switch (VLMUL) { 13406c3fb27SDimitry Andric case RISCVII::LMUL_1: 13506c3fb27SDimitry Andric LMUL = "M1"; 13606c3fb27SDimitry Andric break; 13706c3fb27SDimitry Andric case RISCVII::LMUL_2: 13806c3fb27SDimitry Andric LMUL = "M2"; 13906c3fb27SDimitry Andric break; 14006c3fb27SDimitry Andric case RISCVII::LMUL_4: 14106c3fb27SDimitry Andric LMUL = "M4"; 14206c3fb27SDimitry Andric break; 14306c3fb27SDimitry Andric case RISCVII::LMUL_8: 14406c3fb27SDimitry Andric LMUL = "M8"; 14506c3fb27SDimitry Andric break; 14606c3fb27SDimitry Andric case RISCVII::LMUL_F2: 14706c3fb27SDimitry Andric LMUL = "MF2"; 14806c3fb27SDimitry Andric break; 14906c3fb27SDimitry Andric case RISCVII::LMUL_F4: 15006c3fb27SDimitry Andric LMUL = "MF4"; 15106c3fb27SDimitry Andric break; 15206c3fb27SDimitry Andric case RISCVII::LMUL_F8: 15306c3fb27SDimitry Andric LMUL = "MF8"; 15406c3fb27SDimitry Andric break; 15506c3fb27SDimitry Andric case RISCVII::LMUL_RESERVED: 15606c3fb27SDimitry Andric llvm_unreachable("Cannot create instrument for LMUL_RESERVED"); 15706c3fb27SDimitry Andric } 15806c3fb27SDimitry Andric SmallVector<UniqueInstrument> Instruments; 15906c3fb27SDimitry Andric Instruments.emplace_back( 16006c3fb27SDimitry Andric createInstrument(RISCVLMULInstrument::DESC_NAME, LMUL)); 16106c3fb27SDimitry Andric 16206c3fb27SDimitry Andric unsigned SEW = RISCVVType::getSEW(VTypeI); 16306c3fb27SDimitry Andric StringRef SEWStr; 16406c3fb27SDimitry Andric switch (SEW) { 16506c3fb27SDimitry Andric case 8: 16606c3fb27SDimitry Andric SEWStr = "E8"; 16706c3fb27SDimitry Andric break; 16806c3fb27SDimitry Andric case 16: 16906c3fb27SDimitry Andric SEWStr = "E16"; 17006c3fb27SDimitry Andric break; 17106c3fb27SDimitry Andric case 32: 17206c3fb27SDimitry Andric SEWStr = "E32"; 17306c3fb27SDimitry Andric break; 17406c3fb27SDimitry Andric case 64: 17506c3fb27SDimitry Andric SEWStr = "E64"; 17606c3fb27SDimitry Andric break; 17706c3fb27SDimitry Andric default: 17806c3fb27SDimitry Andric llvm_unreachable("Cannot create instrument for SEW"); 17906c3fb27SDimitry Andric } 18006c3fb27SDimitry Andric Instruments.emplace_back( 18106c3fb27SDimitry Andric createInstrument(RISCVSEWInstrument::DESC_NAME, SEWStr)); 18206c3fb27SDimitry Andric 18306c3fb27SDimitry Andric return Instruments; 18406c3fb27SDimitry Andric } 18506c3fb27SDimitry Andric return SmallVector<UniqueInstrument>(); 186bdd1243dSDimitry Andric } 187bdd1243dSDimitry Andric 1885f757f3fSDimitry Andric static std::pair<uint8_t, uint8_t> 189*1db9f3b2SDimitry Andric getEEWAndEMUL(unsigned Opcode, RISCVII::VLMUL LMUL, uint8_t SEW) { 1905f757f3fSDimitry Andric uint8_t EEW; 1915f757f3fSDimitry Andric switch (Opcode) { 1925f757f3fSDimitry Andric case RISCV::VLM_V: 1935f757f3fSDimitry Andric case RISCV::VSM_V: 1945f757f3fSDimitry Andric case RISCV::VLE8_V: 1955f757f3fSDimitry Andric case RISCV::VSE8_V: 196*1db9f3b2SDimitry Andric case RISCV::VLSE8_V: 197*1db9f3b2SDimitry Andric case RISCV::VSSE8_V: 1985f757f3fSDimitry Andric EEW = 8; 1995f757f3fSDimitry Andric break; 2005f757f3fSDimitry Andric case RISCV::VLE16_V: 2015f757f3fSDimitry Andric case RISCV::VSE16_V: 202*1db9f3b2SDimitry Andric case RISCV::VLSE16_V: 203*1db9f3b2SDimitry Andric case RISCV::VSSE16_V: 2045f757f3fSDimitry Andric EEW = 16; 2055f757f3fSDimitry Andric break; 2065f757f3fSDimitry Andric case RISCV::VLE32_V: 2075f757f3fSDimitry Andric case RISCV::VSE32_V: 208*1db9f3b2SDimitry Andric case RISCV::VLSE32_V: 209*1db9f3b2SDimitry Andric case RISCV::VSSE32_V: 2105f757f3fSDimitry Andric EEW = 32; 2115f757f3fSDimitry Andric break; 2125f757f3fSDimitry Andric case RISCV::VLE64_V: 2135f757f3fSDimitry Andric case RISCV::VSE64_V: 214*1db9f3b2SDimitry Andric case RISCV::VLSE64_V: 215*1db9f3b2SDimitry Andric case RISCV::VSSE64_V: 2165f757f3fSDimitry Andric EEW = 64; 2175f757f3fSDimitry Andric break; 2185f757f3fSDimitry Andric default: 219*1db9f3b2SDimitry Andric llvm_unreachable("Could not determine EEW from Opcode"); 2205f757f3fSDimitry Andric } 2215f757f3fSDimitry Andric 2225f757f3fSDimitry Andric auto EMUL = RISCVVType::getSameRatioLMUL(SEW, LMUL, EEW); 2235f757f3fSDimitry Andric if (!EEW) 2245f757f3fSDimitry Andric llvm_unreachable("Invalid SEW or LMUL for new ratio"); 2255f757f3fSDimitry Andric return std::make_pair(EEW, *EMUL); 2265f757f3fSDimitry Andric } 2275f757f3fSDimitry Andric 228*1db9f3b2SDimitry Andric bool opcodeHasEEWAndEMULInfo(unsigned short Opcode) { 229*1db9f3b2SDimitry Andric return Opcode == RISCV::VLM_V || Opcode == RISCV::VSM_V || 230*1db9f3b2SDimitry Andric Opcode == RISCV::VLE8_V || Opcode == RISCV::VSE8_V || 231*1db9f3b2SDimitry Andric Opcode == RISCV::VLE16_V || Opcode == RISCV::VSE16_V || 232*1db9f3b2SDimitry Andric Opcode == RISCV::VLE32_V || Opcode == RISCV::VSE32_V || 233*1db9f3b2SDimitry Andric Opcode == RISCV::VLE64_V || Opcode == RISCV::VSE64_V || 234*1db9f3b2SDimitry Andric Opcode == RISCV::VLSE8_V || Opcode == RISCV::VSSE8_V || 235*1db9f3b2SDimitry Andric Opcode == RISCV::VLSE16_V || Opcode == RISCV::VSSE16_V || 236*1db9f3b2SDimitry Andric Opcode == RISCV::VLSE32_V || Opcode == RISCV::VSSE32_V || 237*1db9f3b2SDimitry Andric Opcode == RISCV::VLSE64_V || Opcode == RISCV::VSSE64_V; 238*1db9f3b2SDimitry Andric } 239*1db9f3b2SDimitry Andric 240bdd1243dSDimitry Andric unsigned RISCVInstrumentManager::getSchedClassID( 241bdd1243dSDimitry Andric const MCInstrInfo &MCII, const MCInst &MCI, 24206c3fb27SDimitry Andric const llvm::SmallVector<Instrument *> &IVec) const { 243bdd1243dSDimitry Andric unsigned short Opcode = MCI.getOpcode(); 244bdd1243dSDimitry Andric unsigned SchedClassID = MCII.get(Opcode).getSchedClass(); 245bdd1243dSDimitry Andric 2465f757f3fSDimitry Andric // Unpack all possible RISC-V instruments from IVec. 24706c3fb27SDimitry Andric RISCVLMULInstrument *LI = nullptr; 24806c3fb27SDimitry Andric RISCVSEWInstrument *SI = nullptr; 24906c3fb27SDimitry Andric for (auto &I : IVec) { 25006c3fb27SDimitry Andric if (I->getDesc() == RISCVLMULInstrument::DESC_NAME) 25106c3fb27SDimitry Andric LI = static_cast<RISCVLMULInstrument *>(I); 25206c3fb27SDimitry Andric else if (I->getDesc() == RISCVSEWInstrument::DESC_NAME) 25306c3fb27SDimitry Andric SI = static_cast<RISCVSEWInstrument *>(I); 25406c3fb27SDimitry Andric } 25506c3fb27SDimitry Andric 25606c3fb27SDimitry Andric // Need LMUL or LMUL, SEW in order to override opcode. If no LMUL is provided, 25706c3fb27SDimitry Andric // then no option to override. 25806c3fb27SDimitry Andric if (!LI) { 25906c3fb27SDimitry Andric LLVM_DEBUG( 26006c3fb27SDimitry Andric dbgs() << "RVCB: Did not use instrumentation to override Opcode.\n"); 26106c3fb27SDimitry Andric return SchedClassID; 26206c3fb27SDimitry Andric } 26306c3fb27SDimitry Andric uint8_t LMUL = LI->getLMUL(); 26406c3fb27SDimitry Andric 26506c3fb27SDimitry Andric // getBaseInfo works with (Opcode, LMUL, 0) if no SEW instrument, 26606c3fb27SDimitry Andric // or (Opcode, LMUL, SEW) if SEW instrument is active, and depends on LMUL 26706c3fb27SDimitry Andric // and SEW, or (Opcode, LMUL, 0) if does not depend on SEW. 26806c3fb27SDimitry Andric uint8_t SEW = SI ? SI->getSEW() : 0; 2695f757f3fSDimitry Andric 2705f757f3fSDimitry Andric const RISCVVInversePseudosTable::PseudoInfo *RVV = nullptr; 271*1db9f3b2SDimitry Andric if (opcodeHasEEWAndEMULInfo(Opcode)) { 2725f757f3fSDimitry Andric RISCVII::VLMUL VLMUL = static_cast<RISCVII::VLMUL>(LMUL); 273*1db9f3b2SDimitry Andric auto [EEW, EMUL] = getEEWAndEMUL(Opcode, VLMUL, SEW); 2745f757f3fSDimitry Andric RVV = RISCVVInversePseudosTable::getBaseInfo(Opcode, EMUL, EEW); 2755f757f3fSDimitry Andric } else { 27606c3fb27SDimitry Andric // Check if it depends on LMUL and SEW 2775f757f3fSDimitry Andric RVV = RISCVVInversePseudosTable::getBaseInfo(Opcode, LMUL, SEW); 27806c3fb27SDimitry Andric // Check if it depends only on LMUL 27906c3fb27SDimitry Andric if (!RVV) 28006c3fb27SDimitry Andric RVV = RISCVVInversePseudosTable::getBaseInfo(Opcode, LMUL, 0); 2815f757f3fSDimitry Andric } 28206c3fb27SDimitry Andric 283bdd1243dSDimitry Andric // Not a RVV instr 284bdd1243dSDimitry Andric if (!RVV) { 285bdd1243dSDimitry Andric LLVM_DEBUG( 28606c3fb27SDimitry Andric dbgs() << "RVCB: Could not find PseudoInstruction for Opcode " 28706c3fb27SDimitry Andric << MCII.getName(Opcode) 28806c3fb27SDimitry Andric << ", LMUL=" << (LI ? LI->getData() : "Unspecified") 28906c3fb27SDimitry Andric << ", SEW=" << (SI ? SI->getData() : "Unspecified") 290bdd1243dSDimitry Andric << ". Ignoring instrumentation and using original SchedClassID=" 291bdd1243dSDimitry Andric << SchedClassID << '\n'); 292bdd1243dSDimitry Andric return SchedClassID; 293bdd1243dSDimitry Andric } 294bdd1243dSDimitry Andric 295bdd1243dSDimitry Andric // Override using pseudo 296bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "RVCB: Found Pseudo Instruction for Opcode " 29706c3fb27SDimitry Andric << MCII.getName(Opcode) << ", LMUL=" << LI->getData() 29806c3fb27SDimitry Andric << ", SEW=" << (SI ? SI->getData() : "Unspecified") 299bdd1243dSDimitry Andric << ". Overriding original SchedClassID=" << SchedClassID 300bdd1243dSDimitry Andric << " with " << MCII.getName(RVV->Pseudo) << '\n'); 301bdd1243dSDimitry Andric return MCII.get(RVV->Pseudo).getSchedClass(); 302bdd1243dSDimitry Andric } 303bdd1243dSDimitry Andric 304bdd1243dSDimitry Andric } // namespace mca 305bdd1243dSDimitry Andric } // namespace llvm 306bdd1243dSDimitry Andric 307bdd1243dSDimitry Andric using namespace llvm; 308bdd1243dSDimitry Andric using namespace mca; 309bdd1243dSDimitry Andric 310bdd1243dSDimitry Andric static InstrumentManager * 311bdd1243dSDimitry Andric createRISCVInstrumentManager(const MCSubtargetInfo &STI, 312bdd1243dSDimitry Andric const MCInstrInfo &MCII) { 313bdd1243dSDimitry Andric return new RISCVInstrumentManager(STI, MCII); 314bdd1243dSDimitry Andric } 315bdd1243dSDimitry Andric 31606c3fb27SDimitry Andric /// Extern function to initialize the targets for the RISC-V backend 317bdd1243dSDimitry Andric extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVTargetMCA() { 318bdd1243dSDimitry Andric TargetRegistry::RegisterInstrumentManager(getTheRISCV32Target(), 319bdd1243dSDimitry Andric createRISCVInstrumentManager); 320bdd1243dSDimitry Andric TargetRegistry::RegisterInstrumentManager(getTheRISCV64Target(), 321bdd1243dSDimitry Andric createRISCVInstrumentManager); 322bdd1243dSDimitry Andric } 323