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
isDataValid(llvm::StringRef Data)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
getLMUL() const35bdd1243dSDimitry 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
isDataValid(llvm::StringRef Data)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
getSEW() const6006c3fb27SDimitry 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
supportsInstrumentType(llvm::StringRef Type) const7206c3fb27SDimitry 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
createInstrument(llvm::StringRef Desc,llvm::StringRef Data)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>
createInstruments(const MCInst & Inst)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>
getEEWAndEMUL(unsigned Opcode,RISCVII::VLMUL LMUL,uint8_t SEW)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
opcodeHasEEWAndEMULInfo(unsigned short Opcode)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
getSchedClassID(const MCInstrInfo & MCII,const MCInst & MCI,const llvm::SmallVector<Instrument * > & IVec) const220bdd1243dSDimitry 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 *
createRISCVInstrumentManager(const MCSubtargetInfo & STI,const MCInstrInfo & MCII)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
LLVMInitializeRISCVTargetMCA()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