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" 16*06c3fb27SDimitry Andric #include "RISCV.h" 17bdd1243dSDimitry Andric #include "RISCVInstrInfo.h" 18bdd1243dSDimitry Andric #include "TargetInfo/RISCVTargetInfo.h" 19bdd1243dSDimitry Andric #include "llvm/MC/TargetRegistry.h" 20bdd1243dSDimitry Andric #include "llvm/Support/Debug.h" 21bdd1243dSDimitry Andric 22bdd1243dSDimitry Andric #define DEBUG_TYPE "llvm-mca-riscv-custombehaviour" 23bdd1243dSDimitry Andric 24bdd1243dSDimitry Andric // This brings in a table with primary key of 25bdd1243dSDimitry Andric // base instruction opcode and lmul and maps 26bdd1243dSDimitry Andric // to the opcode of the pseudo instruction. 27bdd1243dSDimitry Andric namespace RISCVVInversePseudosTable { 28bdd1243dSDimitry Andric using namespace llvm; 29bdd1243dSDimitry Andric using namespace llvm::RISCV; 30bdd1243dSDimitry Andric 31bdd1243dSDimitry Andric struct PseudoInfo { 32bdd1243dSDimitry Andric uint16_t Pseudo; 33bdd1243dSDimitry Andric uint16_t BaseInstr; 34bdd1243dSDimitry Andric uint8_t VLMul; 35*06c3fb27SDimitry Andric uint8_t SEW; 36bdd1243dSDimitry Andric }; 37bdd1243dSDimitry Andric 38bdd1243dSDimitry Andric #define GET_RISCVVInversePseudosTable_IMPL 39bdd1243dSDimitry Andric #define GET_RISCVVInversePseudosTable_DECL 40bdd1243dSDimitry Andric #include "RISCVGenSearchableTables.inc" 41bdd1243dSDimitry Andric 42bdd1243dSDimitry Andric } // end namespace RISCVVInversePseudosTable 43bdd1243dSDimitry Andric 44bdd1243dSDimitry Andric namespace llvm { 45bdd1243dSDimitry Andric namespace mca { 46bdd1243dSDimitry Andric 47bdd1243dSDimitry Andric const llvm::StringRef RISCVLMULInstrument::DESC_NAME = "RISCV-LMUL"; 48bdd1243dSDimitry Andric 49bdd1243dSDimitry Andric bool RISCVLMULInstrument::isDataValid(llvm::StringRef Data) { 50bdd1243dSDimitry Andric // Return true if not one of the valid LMUL strings 51bdd1243dSDimitry Andric return StringSwitch<bool>(Data) 52bdd1243dSDimitry Andric .Cases("M1", "M2", "M4", "M8", "MF2", "MF4", "MF8", true) 53bdd1243dSDimitry Andric .Default(false); 54bdd1243dSDimitry Andric } 55bdd1243dSDimitry Andric 56bdd1243dSDimitry Andric uint8_t RISCVLMULInstrument::getLMUL() const { 57bdd1243dSDimitry Andric // assertion prevents us from needing llvm_unreachable in the StringSwitch 58bdd1243dSDimitry Andric // below 59bdd1243dSDimitry Andric assert(isDataValid(getData()) && 60bdd1243dSDimitry Andric "Cannot get LMUL because invalid Data value"); 61*06c3fb27SDimitry Andric // These are the LMUL values that are used in RISC-V tablegen 62bdd1243dSDimitry Andric return StringSwitch<uint8_t>(getData()) 63bdd1243dSDimitry Andric .Case("M1", 0b000) 64bdd1243dSDimitry Andric .Case("M2", 0b001) 65bdd1243dSDimitry Andric .Case("M4", 0b010) 66bdd1243dSDimitry Andric .Case("M8", 0b011) 67bdd1243dSDimitry Andric .Case("MF2", 0b101) 68bdd1243dSDimitry Andric .Case("MF4", 0b110) 69bdd1243dSDimitry Andric .Case("MF8", 0b111); 70bdd1243dSDimitry Andric } 71bdd1243dSDimitry Andric 72*06c3fb27SDimitry Andric const llvm::StringRef RISCVSEWInstrument::DESC_NAME = "RISCV-SEW"; 73*06c3fb27SDimitry Andric 74*06c3fb27SDimitry Andric bool RISCVSEWInstrument::isDataValid(llvm::StringRef Data) { 75*06c3fb27SDimitry Andric // Return true if not one of the valid SEW strings 76*06c3fb27SDimitry Andric return StringSwitch<bool>(Data) 77*06c3fb27SDimitry Andric .Cases("E8", "E16", "E32", "E64", true) 78*06c3fb27SDimitry Andric .Default(false); 79bdd1243dSDimitry Andric } 80bdd1243dSDimitry Andric 81*06c3fb27SDimitry Andric uint8_t RISCVSEWInstrument::getSEW() const { 82*06c3fb27SDimitry Andric // assertion prevents us from needing llvm_unreachable in the StringSwitch 83*06c3fb27SDimitry Andric // below 84*06c3fb27SDimitry Andric assert(isDataValid(getData()) && "Cannot get SEW because invalid Data value"); 85*06c3fb27SDimitry Andric // These are the LMUL values that are used in RISC-V tablegen 86*06c3fb27SDimitry Andric return StringSwitch<uint8_t>(getData()) 87*06c3fb27SDimitry Andric .Case("E8", 8) 88*06c3fb27SDimitry Andric .Case("E16", 16) 89*06c3fb27SDimitry Andric .Case("E32", 32) 90*06c3fb27SDimitry Andric .Case("E64", 64); 91*06c3fb27SDimitry Andric } 92*06c3fb27SDimitry Andric 93*06c3fb27SDimitry Andric bool RISCVInstrumentManager::supportsInstrumentType( 94*06c3fb27SDimitry Andric llvm::StringRef Type) const { 95*06c3fb27SDimitry Andric return Type == RISCVLMULInstrument::DESC_NAME || 96*06c3fb27SDimitry Andric Type == RISCVSEWInstrument::DESC_NAME; 97*06c3fb27SDimitry Andric } 98*06c3fb27SDimitry Andric 99*06c3fb27SDimitry Andric UniqueInstrument 100bdd1243dSDimitry Andric RISCVInstrumentManager::createInstrument(llvm::StringRef Desc, 101bdd1243dSDimitry Andric llvm::StringRef Data) { 102*06c3fb27SDimitry Andric if (Desc == RISCVLMULInstrument::DESC_NAME) { 103*06c3fb27SDimitry Andric if (!RISCVLMULInstrument::isDataValid(Data)) { 104bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "RVCB: Bad data for instrument kind " << Desc << ": " 105bdd1243dSDimitry Andric << Data << '\n'); 106bdd1243dSDimitry Andric return nullptr; 107bdd1243dSDimitry Andric } 108*06c3fb27SDimitry Andric return std::make_unique<RISCVLMULInstrument>(Data); 109*06c3fb27SDimitry Andric } 110*06c3fb27SDimitry Andric 111*06c3fb27SDimitry Andric if (Desc == RISCVSEWInstrument::DESC_NAME) { 112*06c3fb27SDimitry Andric if (!RISCVSEWInstrument::isDataValid(Data)) { 113*06c3fb27SDimitry Andric LLVM_DEBUG(dbgs() << "RVCB: Bad data for instrument kind " << Desc << ": " 114*06c3fb27SDimitry Andric << Data << '\n'); 115*06c3fb27SDimitry Andric return nullptr; 116*06c3fb27SDimitry Andric } 117*06c3fb27SDimitry Andric return std::make_unique<RISCVSEWInstrument>(Data); 118*06c3fb27SDimitry Andric } 119*06c3fb27SDimitry Andric 120*06c3fb27SDimitry Andric LLVM_DEBUG(dbgs() << "RVCB: Unknown instrumentation Desc: " << Desc << '\n'); 121*06c3fb27SDimitry Andric return nullptr; 122*06c3fb27SDimitry Andric } 123*06c3fb27SDimitry Andric 124*06c3fb27SDimitry Andric SmallVector<UniqueInstrument> 125*06c3fb27SDimitry Andric RISCVInstrumentManager::createInstruments(const MCInst &Inst) { 126*06c3fb27SDimitry Andric if (Inst.getOpcode() == RISCV::VSETVLI || 127*06c3fb27SDimitry Andric Inst.getOpcode() == RISCV::VSETIVLI) { 128*06c3fb27SDimitry Andric LLVM_DEBUG(dbgs() << "RVCB: Found VSETVLI and creating instrument for it: " 129*06c3fb27SDimitry Andric << Inst << "\n"); 130*06c3fb27SDimitry Andric unsigned VTypeI = Inst.getOperand(2).getImm(); 131*06c3fb27SDimitry Andric RISCVII::VLMUL VLMUL = RISCVVType::getVLMUL(VTypeI); 132*06c3fb27SDimitry Andric 133*06c3fb27SDimitry Andric StringRef LMUL; 134*06c3fb27SDimitry Andric switch (VLMUL) { 135*06c3fb27SDimitry Andric case RISCVII::LMUL_1: 136*06c3fb27SDimitry Andric LMUL = "M1"; 137*06c3fb27SDimitry Andric break; 138*06c3fb27SDimitry Andric case RISCVII::LMUL_2: 139*06c3fb27SDimitry Andric LMUL = "M2"; 140*06c3fb27SDimitry Andric break; 141*06c3fb27SDimitry Andric case RISCVII::LMUL_4: 142*06c3fb27SDimitry Andric LMUL = "M4"; 143*06c3fb27SDimitry Andric break; 144*06c3fb27SDimitry Andric case RISCVII::LMUL_8: 145*06c3fb27SDimitry Andric LMUL = "M8"; 146*06c3fb27SDimitry Andric break; 147*06c3fb27SDimitry Andric case RISCVII::LMUL_F2: 148*06c3fb27SDimitry Andric LMUL = "MF2"; 149*06c3fb27SDimitry Andric break; 150*06c3fb27SDimitry Andric case RISCVII::LMUL_F4: 151*06c3fb27SDimitry Andric LMUL = "MF4"; 152*06c3fb27SDimitry Andric break; 153*06c3fb27SDimitry Andric case RISCVII::LMUL_F8: 154*06c3fb27SDimitry Andric LMUL = "MF8"; 155*06c3fb27SDimitry Andric break; 156*06c3fb27SDimitry Andric case RISCVII::LMUL_RESERVED: 157*06c3fb27SDimitry Andric llvm_unreachable("Cannot create instrument for LMUL_RESERVED"); 158*06c3fb27SDimitry Andric } 159*06c3fb27SDimitry Andric SmallVector<UniqueInstrument> Instruments; 160*06c3fb27SDimitry Andric Instruments.emplace_back( 161*06c3fb27SDimitry Andric createInstrument(RISCVLMULInstrument::DESC_NAME, LMUL)); 162*06c3fb27SDimitry Andric 163*06c3fb27SDimitry Andric unsigned SEW = RISCVVType::getSEW(VTypeI); 164*06c3fb27SDimitry Andric StringRef SEWStr; 165*06c3fb27SDimitry Andric switch (SEW) { 166*06c3fb27SDimitry Andric case 8: 167*06c3fb27SDimitry Andric SEWStr = "E8"; 168*06c3fb27SDimitry Andric break; 169*06c3fb27SDimitry Andric case 16: 170*06c3fb27SDimitry Andric SEWStr = "E16"; 171*06c3fb27SDimitry Andric break; 172*06c3fb27SDimitry Andric case 32: 173*06c3fb27SDimitry Andric SEWStr = "E32"; 174*06c3fb27SDimitry Andric break; 175*06c3fb27SDimitry Andric case 64: 176*06c3fb27SDimitry Andric SEWStr = "E64"; 177*06c3fb27SDimitry Andric break; 178*06c3fb27SDimitry Andric default: 179*06c3fb27SDimitry Andric llvm_unreachable("Cannot create instrument for SEW"); 180*06c3fb27SDimitry Andric } 181*06c3fb27SDimitry Andric Instruments.emplace_back( 182*06c3fb27SDimitry Andric createInstrument(RISCVSEWInstrument::DESC_NAME, SEWStr)); 183*06c3fb27SDimitry Andric 184*06c3fb27SDimitry Andric return Instruments; 185*06c3fb27SDimitry Andric } 186*06c3fb27SDimitry Andric return SmallVector<UniqueInstrument>(); 187bdd1243dSDimitry Andric } 188bdd1243dSDimitry Andric 189bdd1243dSDimitry Andric unsigned RISCVInstrumentManager::getSchedClassID( 190bdd1243dSDimitry Andric const MCInstrInfo &MCII, const MCInst &MCI, 191*06c3fb27SDimitry Andric const llvm::SmallVector<Instrument *> &IVec) const { 192bdd1243dSDimitry Andric unsigned short Opcode = MCI.getOpcode(); 193bdd1243dSDimitry Andric unsigned SchedClassID = MCII.get(Opcode).getSchedClass(); 194bdd1243dSDimitry Andric 195*06c3fb27SDimitry Andric // Unpack all possible RISCV instruments from IVec. 196*06c3fb27SDimitry Andric RISCVLMULInstrument *LI = nullptr; 197*06c3fb27SDimitry Andric RISCVSEWInstrument *SI = nullptr; 198*06c3fb27SDimitry Andric for (auto &I : IVec) { 199*06c3fb27SDimitry Andric if (I->getDesc() == RISCVLMULInstrument::DESC_NAME) 200*06c3fb27SDimitry Andric LI = static_cast<RISCVLMULInstrument *>(I); 201*06c3fb27SDimitry Andric else if (I->getDesc() == RISCVSEWInstrument::DESC_NAME) 202*06c3fb27SDimitry Andric SI = static_cast<RISCVSEWInstrument *>(I); 203*06c3fb27SDimitry Andric } 204*06c3fb27SDimitry Andric 205*06c3fb27SDimitry Andric // Need LMUL or LMUL, SEW in order to override opcode. If no LMUL is provided, 206*06c3fb27SDimitry Andric // then no option to override. 207*06c3fb27SDimitry Andric if (!LI) { 208*06c3fb27SDimitry Andric LLVM_DEBUG( 209*06c3fb27SDimitry Andric dbgs() << "RVCB: Did not use instrumentation to override Opcode.\n"); 210*06c3fb27SDimitry Andric return SchedClassID; 211*06c3fb27SDimitry Andric } 212*06c3fb27SDimitry Andric uint8_t LMUL = LI->getLMUL(); 213*06c3fb27SDimitry Andric 214*06c3fb27SDimitry Andric // getBaseInfo works with (Opcode, LMUL, 0) if no SEW instrument, 215*06c3fb27SDimitry Andric // or (Opcode, LMUL, SEW) if SEW instrument is active, and depends on LMUL 216*06c3fb27SDimitry Andric // and SEW, or (Opcode, LMUL, 0) if does not depend on SEW. 217*06c3fb27SDimitry Andric uint8_t SEW = SI ? SI->getSEW() : 0; 218*06c3fb27SDimitry Andric // Check if it depends on LMUL and SEW 219bdd1243dSDimitry Andric const RISCVVInversePseudosTable::PseudoInfo *RVV = 220*06c3fb27SDimitry Andric RISCVVInversePseudosTable::getBaseInfo(Opcode, LMUL, SEW); 221*06c3fb27SDimitry Andric // Check if it depends only on LMUL 222*06c3fb27SDimitry Andric if (!RVV) 223*06c3fb27SDimitry Andric RVV = RISCVVInversePseudosTable::getBaseInfo(Opcode, LMUL, 0); 224*06c3fb27SDimitry Andric 225bdd1243dSDimitry Andric // Not a RVV instr 226bdd1243dSDimitry Andric if (!RVV) { 227bdd1243dSDimitry Andric LLVM_DEBUG( 228*06c3fb27SDimitry Andric dbgs() << "RVCB: Could not find PseudoInstruction for Opcode " 229*06c3fb27SDimitry Andric << MCII.getName(Opcode) 230*06c3fb27SDimitry Andric << ", LMUL=" << (LI ? LI->getData() : "Unspecified") 231*06c3fb27SDimitry Andric << ", SEW=" << (SI ? SI->getData() : "Unspecified") 232bdd1243dSDimitry Andric << ". Ignoring instrumentation and using original SchedClassID=" 233bdd1243dSDimitry Andric << SchedClassID << '\n'); 234bdd1243dSDimitry Andric return SchedClassID; 235bdd1243dSDimitry Andric } 236bdd1243dSDimitry Andric 237bdd1243dSDimitry Andric // Override using pseudo 238bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "RVCB: Found Pseudo Instruction for Opcode " 239*06c3fb27SDimitry Andric << MCII.getName(Opcode) << ", LMUL=" << LI->getData() 240*06c3fb27SDimitry Andric << ", SEW=" << (SI ? SI->getData() : "Unspecified") 241bdd1243dSDimitry Andric << ". Overriding original SchedClassID=" << SchedClassID 242bdd1243dSDimitry Andric << " with " << MCII.getName(RVV->Pseudo) << '\n'); 243bdd1243dSDimitry Andric return MCII.get(RVV->Pseudo).getSchedClass(); 244bdd1243dSDimitry Andric } 245bdd1243dSDimitry Andric 246bdd1243dSDimitry Andric } // namespace mca 247bdd1243dSDimitry Andric } // namespace llvm 248bdd1243dSDimitry Andric 249bdd1243dSDimitry Andric using namespace llvm; 250bdd1243dSDimitry Andric using namespace mca; 251bdd1243dSDimitry Andric 252bdd1243dSDimitry Andric static InstrumentManager * 253bdd1243dSDimitry Andric createRISCVInstrumentManager(const MCSubtargetInfo &STI, 254bdd1243dSDimitry Andric const MCInstrInfo &MCII) { 255bdd1243dSDimitry Andric return new RISCVInstrumentManager(STI, MCII); 256bdd1243dSDimitry Andric } 257bdd1243dSDimitry Andric 258*06c3fb27SDimitry Andric /// Extern function to initialize the targets for the RISC-V backend 259bdd1243dSDimitry Andric extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVTargetMCA() { 260bdd1243dSDimitry Andric TargetRegistry::RegisterInstrumentManager(getTheRISCV32Target(), 261bdd1243dSDimitry Andric createRISCVInstrumentManager); 262bdd1243dSDimitry Andric TargetRegistry::RegisterInstrumentManager(getTheRISCV64Target(), 263bdd1243dSDimitry Andric createRISCVInstrumentManager); 264bdd1243dSDimitry Andric } 265