| //===------------------- RISCVCustomBehaviour.cpp ---------------*-C++ -* -===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| /// \file |
| /// |
| /// This file implements methods from the RISCVCustomBehaviour class. |
| /// |
| //===----------------------------------------------------------------------===// |
| |
| #include "RISCVCustomBehaviour.h" |
| #include "MCTargetDesc/RISCVMCTargetDesc.h" |
| #include "RISCV.h" |
| #include "RISCVInstrInfo.h" |
| #include "TargetInfo/RISCVTargetInfo.h" |
| #include "llvm/MC/TargetRegistry.h" |
| #include "llvm/Support/Debug.h" |
| |
| #define DEBUG_TYPE "llvm-mca-riscv-custombehaviour" |
| |
| // This brings in a table with primary key of |
| // base instruction opcode and lmul and maps |
| // to the opcode of the pseudo instruction. |
| namespace RISCVVInversePseudosTable { |
| using namespace llvm; |
| using namespace llvm::RISCV; |
| |
| struct PseudoInfo { |
| uint16_t Pseudo; |
| uint16_t BaseInstr; |
| uint8_t VLMul; |
| uint8_t SEW; |
| }; |
| |
| #define GET_RISCVVInversePseudosTable_IMPL |
| #define GET_RISCVVInversePseudosTable_DECL |
| #include "RISCVGenSearchableTables.inc" |
| |
| } // end namespace RISCVVInversePseudosTable |
| |
| namespace llvm { |
| namespace mca { |
| |
| const llvm::StringRef RISCVLMULInstrument::DESC_NAME = "RISCV-LMUL"; |
| |
| bool RISCVLMULInstrument::isDataValid(llvm::StringRef Data) { |
| // Return true if not one of the valid LMUL strings |
| return StringSwitch<bool>(Data) |
| .Cases("M1", "M2", "M4", "M8", "MF2", "MF4", "MF8", true) |
| .Default(false); |
| } |
| |
| uint8_t RISCVLMULInstrument::getLMUL() const { |
| // assertion prevents us from needing llvm_unreachable in the StringSwitch |
| // below |
| assert(isDataValid(getData()) && |
| "Cannot get LMUL because invalid Data value"); |
| // These are the LMUL values that are used in RISC-V tablegen |
| return StringSwitch<uint8_t>(getData()) |
| .Case("M1", 0b000) |
| .Case("M2", 0b001) |
| .Case("M4", 0b010) |
| .Case("M8", 0b011) |
| .Case("MF2", 0b101) |
| .Case("MF4", 0b110) |
| .Case("MF8", 0b111); |
| } |
| |
| const llvm::StringRef RISCVSEWInstrument::DESC_NAME = "RISCV-SEW"; |
| |
| bool RISCVSEWInstrument::isDataValid(llvm::StringRef Data) { |
| // Return true if not one of the valid SEW strings |
| return StringSwitch<bool>(Data) |
| .Cases("E8", "E16", "E32", "E64", true) |
| .Default(false); |
| } |
| |
| uint8_t RISCVSEWInstrument::getSEW() const { |
| // assertion prevents us from needing llvm_unreachable in the StringSwitch |
| // below |
| assert(isDataValid(getData()) && "Cannot get SEW because invalid Data value"); |
| // These are the LMUL values that are used in RISC-V tablegen |
| return StringSwitch<uint8_t>(getData()) |
| .Case("E8", 8) |
| .Case("E16", 16) |
| .Case("E32", 32) |
| .Case("E64", 64); |
| } |
| |
| bool RISCVInstrumentManager::supportsInstrumentType( |
| llvm::StringRef Type) const { |
| return Type == RISCVLMULInstrument::DESC_NAME || |
| Type == RISCVSEWInstrument::DESC_NAME; |
| } |
| |
| UniqueInstrument |
| RISCVInstrumentManager::createInstrument(llvm::StringRef Desc, |
| llvm::StringRef Data) { |
| if (Desc == RISCVLMULInstrument::DESC_NAME) { |
| if (!RISCVLMULInstrument::isDataValid(Data)) { |
| LLVM_DEBUG(dbgs() << "RVCB: Bad data for instrument kind " << Desc << ": " |
| << Data << '\n'); |
| return nullptr; |
| } |
| return std::make_unique<RISCVLMULInstrument>(Data); |
| } |
| |
| if (Desc == RISCVSEWInstrument::DESC_NAME) { |
| if (!RISCVSEWInstrument::isDataValid(Data)) { |
| LLVM_DEBUG(dbgs() << "RVCB: Bad data for instrument kind " << Desc << ": " |
| << Data << '\n'); |
| return nullptr; |
| } |
| return std::make_unique<RISCVSEWInstrument>(Data); |
| } |
| |
| LLVM_DEBUG(dbgs() << "RVCB: Unknown instrumentation Desc: " << Desc << '\n'); |
| return nullptr; |
| } |
| |
| SmallVector<UniqueInstrument> |
| RISCVInstrumentManager::createInstruments(const MCInst &Inst) { |
| if (Inst.getOpcode() == RISCV::VSETVLI || |
| Inst.getOpcode() == RISCV::VSETIVLI) { |
| LLVM_DEBUG(dbgs() << "RVCB: Found VSETVLI and creating instrument for it: " |
| << Inst << "\n"); |
| unsigned VTypeI = Inst.getOperand(2).getImm(); |
| RISCVII::VLMUL VLMUL = RISCVVType::getVLMUL(VTypeI); |
| |
| StringRef LMUL; |
| switch (VLMUL) { |
| case RISCVII::LMUL_1: |
| LMUL = "M1"; |
| break; |
| case RISCVII::LMUL_2: |
| LMUL = "M2"; |
| break; |
| case RISCVII::LMUL_4: |
| LMUL = "M4"; |
| break; |
| case RISCVII::LMUL_8: |
| LMUL = "M8"; |
| break; |
| case RISCVII::LMUL_F2: |
| LMUL = "MF2"; |
| break; |
| case RISCVII::LMUL_F4: |
| LMUL = "MF4"; |
| break; |
| case RISCVII::LMUL_F8: |
| LMUL = "MF8"; |
| break; |
| case RISCVII::LMUL_RESERVED: |
| llvm_unreachable("Cannot create instrument for LMUL_RESERVED"); |
| } |
| SmallVector<UniqueInstrument> Instruments; |
| Instruments.emplace_back( |
| createInstrument(RISCVLMULInstrument::DESC_NAME, LMUL)); |
| |
| unsigned SEW = RISCVVType::getSEW(VTypeI); |
| StringRef SEWStr; |
| switch (SEW) { |
| case 8: |
| SEWStr = "E8"; |
| break; |
| case 16: |
| SEWStr = "E16"; |
| break; |
| case 32: |
| SEWStr = "E32"; |
| break; |
| case 64: |
| SEWStr = "E64"; |
| break; |
| default: |
| llvm_unreachable("Cannot create instrument for SEW"); |
| } |
| Instruments.emplace_back( |
| createInstrument(RISCVSEWInstrument::DESC_NAME, SEWStr)); |
| |
| return Instruments; |
| } |
| return SmallVector<UniqueInstrument>(); |
| } |
| |
| unsigned RISCVInstrumentManager::getSchedClassID( |
| const MCInstrInfo &MCII, const MCInst &MCI, |
| const llvm::SmallVector<Instrument *> &IVec) const { |
| unsigned short Opcode = MCI.getOpcode(); |
| unsigned SchedClassID = MCII.get(Opcode).getSchedClass(); |
| |
| // Unpack all possible RISCV instruments from IVec. |
| RISCVLMULInstrument *LI = nullptr; |
| RISCVSEWInstrument *SI = nullptr; |
| for (auto &I : IVec) { |
| if (I->getDesc() == RISCVLMULInstrument::DESC_NAME) |
| LI = static_cast<RISCVLMULInstrument *>(I); |
| else if (I->getDesc() == RISCVSEWInstrument::DESC_NAME) |
| SI = static_cast<RISCVSEWInstrument *>(I); |
| } |
| |
| // Need LMUL or LMUL, SEW in order to override opcode. If no LMUL is provided, |
| // then no option to override. |
| if (!LI) { |
| LLVM_DEBUG( |
| dbgs() << "RVCB: Did not use instrumentation to override Opcode.\n"); |
| return SchedClassID; |
| } |
| uint8_t LMUL = LI->getLMUL(); |
| |
| // getBaseInfo works with (Opcode, LMUL, 0) if no SEW instrument, |
| // or (Opcode, LMUL, SEW) if SEW instrument is active, and depends on LMUL |
| // and SEW, or (Opcode, LMUL, 0) if does not depend on SEW. |
| uint8_t SEW = SI ? SI->getSEW() : 0; |
| // Check if it depends on LMUL and SEW |
| const RISCVVInversePseudosTable::PseudoInfo *RVV = |
| RISCVVInversePseudosTable::getBaseInfo(Opcode, LMUL, SEW); |
| // Check if it depends only on LMUL |
| if (!RVV) |
| RVV = RISCVVInversePseudosTable::getBaseInfo(Opcode, LMUL, 0); |
| |
| // Not a RVV instr |
| if (!RVV) { |
| LLVM_DEBUG( |
| dbgs() << "RVCB: Could not find PseudoInstruction for Opcode " |
| << MCII.getName(Opcode) |
| << ", LMUL=" << (LI ? LI->getData() : "Unspecified") |
| << ", SEW=" << (SI ? SI->getData() : "Unspecified") |
| << ". Ignoring instrumentation and using original SchedClassID=" |
| << SchedClassID << '\n'); |
| return SchedClassID; |
| } |
| |
| // Override using pseudo |
| LLVM_DEBUG(dbgs() << "RVCB: Found Pseudo Instruction for Opcode " |
| << MCII.getName(Opcode) << ", LMUL=" << LI->getData() |
| << ", SEW=" << (SI ? SI->getData() : "Unspecified") |
| << ". Overriding original SchedClassID=" << SchedClassID |
| << " with " << MCII.getName(RVV->Pseudo) << '\n'); |
| return MCII.get(RVV->Pseudo).getSchedClass(); |
| } |
| |
| } // namespace mca |
| } // namespace llvm |
| |
| using namespace llvm; |
| using namespace mca; |
| |
| static InstrumentManager * |
| createRISCVInstrumentManager(const MCSubtargetInfo &STI, |
| const MCInstrInfo &MCII) { |
| return new RISCVInstrumentManager(STI, MCII); |
| } |
| |
| /// Extern function to initialize the targets for the RISC-V backend |
| extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVTargetMCA() { |
| TargetRegistry::RegisterInstrumentManager(getTheRISCV32Target(), |
| createRISCVInstrumentManager); |
| TargetRegistry::RegisterInstrumentManager(getTheRISCV64Target(), |
| createRISCVInstrumentManager); |
| } |