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 namespace llvm { 24bdd1243dSDimitry Andric namespace mca { 25bdd1243dSDimitry Andric 26bdd1243dSDimitry Andric const llvm::StringRef RISCVLMULInstrument::DESC_NAME = "RISCV-LMUL"; 27bdd1243dSDimitry Andric 28bdd1243dSDimitry Andric bool RISCVLMULInstrument::isDataValid(llvm::StringRef Data) { 29bdd1243dSDimitry Andric // Return true if not one of the valid LMUL strings 30bdd1243dSDimitry Andric return StringSwitch<bool>(Data) 31bdd1243dSDimitry Andric .Cases("M1", "M2", "M4", "M8", "MF2", "MF4", "MF8", true) 32bdd1243dSDimitry Andric .Default(false); 33bdd1243dSDimitry Andric } 34bdd1243dSDimitry Andric 35bdd1243dSDimitry Andric uint8_t RISCVLMULInstrument::getLMUL() const { 36bdd1243dSDimitry Andric // assertion prevents us from needing llvm_unreachable in the StringSwitch 37bdd1243dSDimitry Andric // below 38bdd1243dSDimitry Andric assert(isDataValid(getData()) && 39bdd1243dSDimitry Andric "Cannot get LMUL because invalid Data value"); 4006c3fb27SDimitry Andric // These are the LMUL values that are used in RISC-V tablegen 41bdd1243dSDimitry Andric return StringSwitch<uint8_t>(getData()) 42bdd1243dSDimitry Andric .Case("M1", 0b000) 43bdd1243dSDimitry Andric .Case("M2", 0b001) 44bdd1243dSDimitry Andric .Case("M4", 0b010) 45bdd1243dSDimitry Andric .Case("M8", 0b011) 465f757f3fSDimitry Andric .Case("MF2", 0b111) 47bdd1243dSDimitry Andric .Case("MF4", 0b110) 485f757f3fSDimitry Andric .Case("MF8", 0b101); 49bdd1243dSDimitry Andric } 50bdd1243dSDimitry Andric 5106c3fb27SDimitry Andric const llvm::StringRef RISCVSEWInstrument::DESC_NAME = "RISCV-SEW"; 5206c3fb27SDimitry Andric 5306c3fb27SDimitry Andric bool RISCVSEWInstrument::isDataValid(llvm::StringRef Data) { 5406c3fb27SDimitry Andric // Return true if not one of the valid SEW strings 5506c3fb27SDimitry Andric return StringSwitch<bool>(Data) 5606c3fb27SDimitry Andric .Cases("E8", "E16", "E32", "E64", true) 5706c3fb27SDimitry Andric .Default(false); 58bdd1243dSDimitry Andric } 59bdd1243dSDimitry Andric 6006c3fb27SDimitry Andric uint8_t RISCVSEWInstrument::getSEW() const { 6106c3fb27SDimitry Andric // assertion prevents us from needing llvm_unreachable in the StringSwitch 6206c3fb27SDimitry Andric // below 6306c3fb27SDimitry Andric assert(isDataValid(getData()) && "Cannot get SEW because invalid Data value"); 6406c3fb27SDimitry Andric // These are the LMUL values that are used in RISC-V tablegen 6506c3fb27SDimitry Andric return StringSwitch<uint8_t>(getData()) 6606c3fb27SDimitry Andric .Case("E8", 8) 6706c3fb27SDimitry Andric .Case("E16", 16) 6806c3fb27SDimitry Andric .Case("E32", 32) 6906c3fb27SDimitry Andric .Case("E64", 64); 7006c3fb27SDimitry Andric } 7106c3fb27SDimitry Andric 7206c3fb27SDimitry Andric bool RISCVInstrumentManager::supportsInstrumentType( 7306c3fb27SDimitry Andric llvm::StringRef Type) const { 7406c3fb27SDimitry Andric return Type == RISCVLMULInstrument::DESC_NAME || 7506c3fb27SDimitry Andric Type == RISCVSEWInstrument::DESC_NAME; 7606c3fb27SDimitry Andric } 7706c3fb27SDimitry Andric 7806c3fb27SDimitry Andric UniqueInstrument 79bdd1243dSDimitry Andric RISCVInstrumentManager::createInstrument(llvm::StringRef Desc, 80bdd1243dSDimitry Andric llvm::StringRef Data) { 8106c3fb27SDimitry Andric if (Desc == RISCVLMULInstrument::DESC_NAME) { 8206c3fb27SDimitry Andric if (!RISCVLMULInstrument::isDataValid(Data)) { 83bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "RVCB: Bad data for instrument kind " << Desc << ": " 84bdd1243dSDimitry Andric << Data << '\n'); 85bdd1243dSDimitry Andric return nullptr; 86bdd1243dSDimitry Andric } 8706c3fb27SDimitry Andric return std::make_unique<RISCVLMULInstrument>(Data); 8806c3fb27SDimitry Andric } 8906c3fb27SDimitry Andric 9006c3fb27SDimitry Andric if (Desc == RISCVSEWInstrument::DESC_NAME) { 9106c3fb27SDimitry Andric if (!RISCVSEWInstrument::isDataValid(Data)) { 9206c3fb27SDimitry Andric LLVM_DEBUG(dbgs() << "RVCB: Bad data for instrument kind " << Desc << ": " 9306c3fb27SDimitry Andric << Data << '\n'); 9406c3fb27SDimitry Andric return nullptr; 9506c3fb27SDimitry Andric } 9606c3fb27SDimitry Andric return std::make_unique<RISCVSEWInstrument>(Data); 9706c3fb27SDimitry Andric } 9806c3fb27SDimitry Andric 9906c3fb27SDimitry Andric LLVM_DEBUG(dbgs() << "RVCB: Unknown instrumentation Desc: " << Desc << '\n'); 10006c3fb27SDimitry Andric return nullptr; 10106c3fb27SDimitry Andric } 10206c3fb27SDimitry Andric 10306c3fb27SDimitry Andric SmallVector<UniqueInstrument> 10406c3fb27SDimitry Andric RISCVInstrumentManager::createInstruments(const MCInst &Inst) { 10506c3fb27SDimitry Andric if (Inst.getOpcode() == RISCV::VSETVLI || 10606c3fb27SDimitry Andric Inst.getOpcode() == RISCV::VSETIVLI) { 10706c3fb27SDimitry Andric LLVM_DEBUG(dbgs() << "RVCB: Found VSETVLI and creating instrument for it: " 10806c3fb27SDimitry Andric << Inst << "\n"); 10906c3fb27SDimitry Andric unsigned VTypeI = Inst.getOperand(2).getImm(); 11006c3fb27SDimitry Andric RISCVII::VLMUL VLMUL = RISCVVType::getVLMUL(VTypeI); 11106c3fb27SDimitry Andric 11206c3fb27SDimitry Andric StringRef LMUL; 11306c3fb27SDimitry Andric switch (VLMUL) { 11406c3fb27SDimitry Andric case RISCVII::LMUL_1: 11506c3fb27SDimitry Andric LMUL = "M1"; 11606c3fb27SDimitry Andric break; 11706c3fb27SDimitry Andric case RISCVII::LMUL_2: 11806c3fb27SDimitry Andric LMUL = "M2"; 11906c3fb27SDimitry Andric break; 12006c3fb27SDimitry Andric case RISCVII::LMUL_4: 12106c3fb27SDimitry Andric LMUL = "M4"; 12206c3fb27SDimitry Andric break; 12306c3fb27SDimitry Andric case RISCVII::LMUL_8: 12406c3fb27SDimitry Andric LMUL = "M8"; 12506c3fb27SDimitry Andric break; 12606c3fb27SDimitry Andric case RISCVII::LMUL_F2: 12706c3fb27SDimitry Andric LMUL = "MF2"; 12806c3fb27SDimitry Andric break; 12906c3fb27SDimitry Andric case RISCVII::LMUL_F4: 13006c3fb27SDimitry Andric LMUL = "MF4"; 13106c3fb27SDimitry Andric break; 13206c3fb27SDimitry Andric case RISCVII::LMUL_F8: 13306c3fb27SDimitry Andric LMUL = "MF8"; 13406c3fb27SDimitry Andric break; 13506c3fb27SDimitry Andric case RISCVII::LMUL_RESERVED: 13606c3fb27SDimitry Andric llvm_unreachable("Cannot create instrument for LMUL_RESERVED"); 13706c3fb27SDimitry Andric } 13806c3fb27SDimitry Andric SmallVector<UniqueInstrument> Instruments; 13906c3fb27SDimitry Andric Instruments.emplace_back( 14006c3fb27SDimitry Andric createInstrument(RISCVLMULInstrument::DESC_NAME, LMUL)); 14106c3fb27SDimitry Andric 14206c3fb27SDimitry Andric unsigned SEW = RISCVVType::getSEW(VTypeI); 14306c3fb27SDimitry Andric StringRef SEWStr; 14406c3fb27SDimitry Andric switch (SEW) { 14506c3fb27SDimitry Andric case 8: 14606c3fb27SDimitry Andric SEWStr = "E8"; 14706c3fb27SDimitry Andric break; 14806c3fb27SDimitry Andric case 16: 14906c3fb27SDimitry Andric SEWStr = "E16"; 15006c3fb27SDimitry Andric break; 15106c3fb27SDimitry Andric case 32: 15206c3fb27SDimitry Andric SEWStr = "E32"; 15306c3fb27SDimitry Andric break; 15406c3fb27SDimitry Andric case 64: 15506c3fb27SDimitry Andric SEWStr = "E64"; 15606c3fb27SDimitry Andric break; 15706c3fb27SDimitry Andric default: 15806c3fb27SDimitry Andric llvm_unreachable("Cannot create instrument for SEW"); 15906c3fb27SDimitry Andric } 16006c3fb27SDimitry Andric Instruments.emplace_back( 16106c3fb27SDimitry Andric createInstrument(RISCVSEWInstrument::DESC_NAME, SEWStr)); 16206c3fb27SDimitry Andric 16306c3fb27SDimitry Andric return Instruments; 16406c3fb27SDimitry Andric } 16506c3fb27SDimitry Andric return SmallVector<UniqueInstrument>(); 166bdd1243dSDimitry Andric } 167bdd1243dSDimitry Andric 1685f757f3fSDimitry Andric static std::pair<uint8_t, uint8_t> 169*1db9f3b2SDimitry Andric getEEWAndEMUL(unsigned Opcode, RISCVII::VLMUL LMUL, uint8_t SEW) { 1705f757f3fSDimitry Andric uint8_t EEW; 1715f757f3fSDimitry Andric switch (Opcode) { 1725f757f3fSDimitry Andric case RISCV::VLM_V: 1735f757f3fSDimitry Andric case RISCV::VSM_V: 1745f757f3fSDimitry Andric case RISCV::VLE8_V: 1755f757f3fSDimitry Andric case RISCV::VSE8_V: 176*1db9f3b2SDimitry Andric case RISCV::VLSE8_V: 177*1db9f3b2SDimitry Andric case RISCV::VSSE8_V: 1785f757f3fSDimitry Andric EEW = 8; 1795f757f3fSDimitry Andric break; 1805f757f3fSDimitry Andric case RISCV::VLE16_V: 1815f757f3fSDimitry Andric case RISCV::VSE16_V: 182*1db9f3b2SDimitry Andric case RISCV::VLSE16_V: 183*1db9f3b2SDimitry Andric case RISCV::VSSE16_V: 1845f757f3fSDimitry Andric EEW = 16; 1855f757f3fSDimitry Andric break; 1865f757f3fSDimitry Andric case RISCV::VLE32_V: 1875f757f3fSDimitry Andric case RISCV::VSE32_V: 188*1db9f3b2SDimitry Andric case RISCV::VLSE32_V: 189*1db9f3b2SDimitry Andric case RISCV::VSSE32_V: 1905f757f3fSDimitry Andric EEW = 32; 1915f757f3fSDimitry Andric break; 1925f757f3fSDimitry Andric case RISCV::VLE64_V: 1935f757f3fSDimitry Andric case RISCV::VSE64_V: 194*1db9f3b2SDimitry Andric case RISCV::VLSE64_V: 195*1db9f3b2SDimitry Andric case RISCV::VSSE64_V: 1965f757f3fSDimitry Andric EEW = 64; 1975f757f3fSDimitry Andric break; 1985f757f3fSDimitry Andric default: 199*1db9f3b2SDimitry Andric llvm_unreachable("Could not determine EEW from Opcode"); 2005f757f3fSDimitry Andric } 2015f757f3fSDimitry Andric 2025f757f3fSDimitry Andric auto EMUL = RISCVVType::getSameRatioLMUL(SEW, LMUL, EEW); 2035f757f3fSDimitry Andric if (!EEW) 2045f757f3fSDimitry Andric llvm_unreachable("Invalid SEW or LMUL for new ratio"); 2055f757f3fSDimitry Andric return std::make_pair(EEW, *EMUL); 2065f757f3fSDimitry Andric } 2075f757f3fSDimitry Andric 208*1db9f3b2SDimitry Andric bool opcodeHasEEWAndEMULInfo(unsigned short Opcode) { 209*1db9f3b2SDimitry Andric return Opcode == RISCV::VLM_V || Opcode == RISCV::VSM_V || 210*1db9f3b2SDimitry Andric Opcode == RISCV::VLE8_V || Opcode == RISCV::VSE8_V || 211*1db9f3b2SDimitry Andric Opcode == RISCV::VLE16_V || Opcode == RISCV::VSE16_V || 212*1db9f3b2SDimitry Andric Opcode == RISCV::VLE32_V || Opcode == RISCV::VSE32_V || 213*1db9f3b2SDimitry Andric Opcode == RISCV::VLE64_V || Opcode == RISCV::VSE64_V || 214*1db9f3b2SDimitry Andric Opcode == RISCV::VLSE8_V || Opcode == RISCV::VSSE8_V || 215*1db9f3b2SDimitry Andric Opcode == RISCV::VLSE16_V || Opcode == RISCV::VSSE16_V || 216*1db9f3b2SDimitry Andric Opcode == RISCV::VLSE32_V || Opcode == RISCV::VSSE32_V || 217*1db9f3b2SDimitry Andric Opcode == RISCV::VLSE64_V || Opcode == RISCV::VSSE64_V; 218*1db9f3b2SDimitry Andric } 219*1db9f3b2SDimitry Andric 220bdd1243dSDimitry Andric unsigned RISCVInstrumentManager::getSchedClassID( 221bdd1243dSDimitry Andric const MCInstrInfo &MCII, const MCInst &MCI, 22206c3fb27SDimitry Andric const llvm::SmallVector<Instrument *> &IVec) const { 223bdd1243dSDimitry Andric unsigned short Opcode = MCI.getOpcode(); 224bdd1243dSDimitry Andric unsigned SchedClassID = MCII.get(Opcode).getSchedClass(); 225bdd1243dSDimitry Andric 2265f757f3fSDimitry Andric // Unpack all possible RISC-V instruments from IVec. 22706c3fb27SDimitry Andric RISCVLMULInstrument *LI = nullptr; 22806c3fb27SDimitry Andric RISCVSEWInstrument *SI = nullptr; 22906c3fb27SDimitry Andric for (auto &I : IVec) { 23006c3fb27SDimitry Andric if (I->getDesc() == RISCVLMULInstrument::DESC_NAME) 23106c3fb27SDimitry Andric LI = static_cast<RISCVLMULInstrument *>(I); 23206c3fb27SDimitry Andric else if (I->getDesc() == RISCVSEWInstrument::DESC_NAME) 23306c3fb27SDimitry Andric SI = static_cast<RISCVSEWInstrument *>(I); 23406c3fb27SDimitry Andric } 23506c3fb27SDimitry Andric 23606c3fb27SDimitry Andric // Need LMUL or LMUL, SEW in order to override opcode. If no LMUL is provided, 23706c3fb27SDimitry Andric // then no option to override. 23806c3fb27SDimitry Andric if (!LI) { 23906c3fb27SDimitry Andric LLVM_DEBUG( 24006c3fb27SDimitry Andric dbgs() << "RVCB: Did not use instrumentation to override Opcode.\n"); 24106c3fb27SDimitry Andric return SchedClassID; 24206c3fb27SDimitry Andric } 24306c3fb27SDimitry Andric uint8_t LMUL = LI->getLMUL(); 24406c3fb27SDimitry Andric 24506c3fb27SDimitry Andric // getBaseInfo works with (Opcode, LMUL, 0) if no SEW instrument, 24606c3fb27SDimitry Andric // or (Opcode, LMUL, SEW) if SEW instrument is active, and depends on LMUL 24706c3fb27SDimitry Andric // and SEW, or (Opcode, LMUL, 0) if does not depend on SEW. 24806c3fb27SDimitry Andric uint8_t SEW = SI ? SI->getSEW() : 0; 2495f757f3fSDimitry Andric 2505f757f3fSDimitry Andric const RISCVVInversePseudosTable::PseudoInfo *RVV = nullptr; 251*1db9f3b2SDimitry Andric if (opcodeHasEEWAndEMULInfo(Opcode)) { 2525f757f3fSDimitry Andric RISCVII::VLMUL VLMUL = static_cast<RISCVII::VLMUL>(LMUL); 253*1db9f3b2SDimitry Andric auto [EEW, EMUL] = getEEWAndEMUL(Opcode, VLMUL, SEW); 2545f757f3fSDimitry Andric RVV = RISCVVInversePseudosTable::getBaseInfo(Opcode, EMUL, EEW); 2555f757f3fSDimitry Andric } else { 25606c3fb27SDimitry Andric // Check if it depends on LMUL and SEW 2575f757f3fSDimitry Andric RVV = RISCVVInversePseudosTable::getBaseInfo(Opcode, LMUL, SEW); 25806c3fb27SDimitry Andric // Check if it depends only on LMUL 25906c3fb27SDimitry Andric if (!RVV) 26006c3fb27SDimitry Andric RVV = RISCVVInversePseudosTable::getBaseInfo(Opcode, LMUL, 0); 2615f757f3fSDimitry Andric } 26206c3fb27SDimitry Andric 263bdd1243dSDimitry Andric // Not a RVV instr 264bdd1243dSDimitry Andric if (!RVV) { 265bdd1243dSDimitry Andric LLVM_DEBUG( 26606c3fb27SDimitry Andric dbgs() << "RVCB: Could not find PseudoInstruction for Opcode " 26706c3fb27SDimitry Andric << MCII.getName(Opcode) 26806c3fb27SDimitry Andric << ", LMUL=" << (LI ? LI->getData() : "Unspecified") 26906c3fb27SDimitry Andric << ", SEW=" << (SI ? SI->getData() : "Unspecified") 270bdd1243dSDimitry Andric << ". Ignoring instrumentation and using original SchedClassID=" 271bdd1243dSDimitry Andric << SchedClassID << '\n'); 272bdd1243dSDimitry Andric return SchedClassID; 273bdd1243dSDimitry Andric } 274bdd1243dSDimitry Andric 275bdd1243dSDimitry Andric // Override using pseudo 276bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "RVCB: Found Pseudo Instruction for Opcode " 27706c3fb27SDimitry Andric << MCII.getName(Opcode) << ", LMUL=" << LI->getData() 27806c3fb27SDimitry Andric << ", SEW=" << (SI ? SI->getData() : "Unspecified") 279bdd1243dSDimitry Andric << ". Overriding original SchedClassID=" << SchedClassID 280bdd1243dSDimitry Andric << " with " << MCII.getName(RVV->Pseudo) << '\n'); 281bdd1243dSDimitry Andric return MCII.get(RVV->Pseudo).getSchedClass(); 282bdd1243dSDimitry Andric } 283bdd1243dSDimitry Andric 284bdd1243dSDimitry Andric } // namespace mca 285bdd1243dSDimitry Andric } // namespace llvm 286bdd1243dSDimitry Andric 287bdd1243dSDimitry Andric using namespace llvm; 288bdd1243dSDimitry Andric using namespace mca; 289bdd1243dSDimitry Andric 290bdd1243dSDimitry Andric static InstrumentManager * 291bdd1243dSDimitry Andric createRISCVInstrumentManager(const MCSubtargetInfo &STI, 292bdd1243dSDimitry Andric const MCInstrInfo &MCII) { 293bdd1243dSDimitry Andric return new RISCVInstrumentManager(STI, MCII); 294bdd1243dSDimitry Andric } 295bdd1243dSDimitry Andric 29606c3fb27SDimitry Andric /// Extern function to initialize the targets for the RISC-V backend 297bdd1243dSDimitry Andric extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVTargetMCA() { 298bdd1243dSDimitry Andric TargetRegistry::RegisterInstrumentManager(getTheRISCV32Target(), 299bdd1243dSDimitry Andric createRISCVInstrumentManager); 300bdd1243dSDimitry Andric TargetRegistry::RegisterInstrumentManager(getTheRISCV64Target(), 301bdd1243dSDimitry Andric createRISCVInstrumentManager); 302bdd1243dSDimitry Andric } 303