
This patch adds initial vector extension support to RISC-V's exegesis. The strategy here is to enumerate all RVV _pseudo_ opcodes as their MC opcode counterparts are kind of useless under this circumstance. We also enumerate all possible VTYPE operands in each CodeTemplate configuration. Various of MachineFunction Passes are used for post processing the snippets, like inserting VSETVLI instructions. See https://llvm.org/devmtg/2024-10/slides/techtalk/Hsu-RVV-Exegesis.pdf for more technical details.
130 lines
4.0 KiB
C++
130 lines
4.0 KiB
C++
//===- RISCVExegesisPostprocessing.cpp - Post processing MI for exegesis---===//
|
|
//
|
|
// 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 Pass converts some of the virtual register operands in VSETVLI and FRM
|
|
// pseudos into physical registers.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "RISCV.h"
|
|
#include "RISCVExegesisPasses.h"
|
|
#include "llvm/CodeGen/MachineFunctionPass.h"
|
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
|
#include "llvm/Support/Debug.h"
|
|
|
|
using namespace llvm;
|
|
|
|
#define DEBUG_TYPE "riscv-exegesis-post-processing"
|
|
|
|
namespace {
|
|
struct RISCVExegesisPostprocessing : public MachineFunctionPass {
|
|
static char ID;
|
|
|
|
RISCVExegesisPostprocessing() : MachineFunctionPass(ID) {}
|
|
|
|
bool runOnMachineFunction(MachineFunction &MF) override;
|
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
|
AU.setPreservesCFG();
|
|
MachineFunctionPass::getAnalysisUsage(AU);
|
|
}
|
|
|
|
private:
|
|
// Extremely simple register allocator that picks a register that hasn't
|
|
// been defined or used in this function.
|
|
Register allocateGPRRegister(const MachineFunction &MF,
|
|
const MachineRegisterInfo &MRI);
|
|
|
|
bool processVSETVL(MachineInstr &MI, MachineRegisterInfo &MRI);
|
|
bool processWriteFRM(MachineInstr &MI, MachineRegisterInfo &MRI);
|
|
};
|
|
} // anonymous namespace
|
|
|
|
char RISCVExegesisPostprocessing::ID = 0;
|
|
|
|
bool RISCVExegesisPostprocessing::runOnMachineFunction(MachineFunction &MF) {
|
|
bool Changed = false;
|
|
for (auto &MBB : MF)
|
|
for (auto &MI : MBB) {
|
|
unsigned Opcode = MI.getOpcode();
|
|
switch (Opcode) {
|
|
case RISCV::VSETVLI:
|
|
case RISCV::VSETVL:
|
|
case RISCV::PseudoVSETVLI:
|
|
case RISCV::PseudoVSETVLIX0:
|
|
Changed |= processVSETVL(MI, MF.getRegInfo());
|
|
break;
|
|
case RISCV::SwapFRMImm:
|
|
case RISCV::WriteFRM:
|
|
Changed |= processWriteFRM(MI, MF.getRegInfo());
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (Changed)
|
|
MF.getRegInfo().clearVirtRegs();
|
|
|
|
LLVM_DEBUG(MF.print(dbgs() << "===After RISCVExegesisPostprocessing===\n");
|
|
dbgs() << "\n");
|
|
|
|
return Changed;
|
|
}
|
|
|
|
Register RISCVExegesisPostprocessing::allocateGPRRegister(
|
|
const MachineFunction &MF, const MachineRegisterInfo &MRI) {
|
|
const auto &TRI = *MRI.getTargetRegisterInfo();
|
|
|
|
// We hope to avoid allocating callee-saved registers. And GPRTC
|
|
// happens to account for nearly all caller-saved registers.
|
|
const TargetRegisterClass *GPRClass = TRI.getRegClass(RISCV::GPRTCRegClassID);
|
|
BitVector Candidates = TRI.getAllocatableSet(MF, GPRClass);
|
|
|
|
for (unsigned SetIdx : Candidates.set_bits()) {
|
|
if (MRI.reg_empty(Register(SetIdx)))
|
|
return Register(SetIdx);
|
|
}
|
|
|
|
// All bets are off, assign a fixed one.
|
|
return RISCV::X5;
|
|
}
|
|
|
|
bool RISCVExegesisPostprocessing::processVSETVL(MachineInstr &MI,
|
|
MachineRegisterInfo &MRI) {
|
|
bool Changed = false;
|
|
// Replace both AVL and VL (i.e. the result) operands with physical
|
|
// registers.
|
|
for (unsigned Idx = 0U; Idx < 2; ++Idx)
|
|
if (MI.getOperand(Idx).isReg()) {
|
|
Register RegOp = MI.getOperand(Idx).getReg();
|
|
if (RegOp.isVirtual()) {
|
|
MRI.replaceRegWith(RegOp, allocateGPRRegister(*MI.getMF(), MRI));
|
|
Changed = true;
|
|
}
|
|
}
|
|
|
|
return Changed;
|
|
}
|
|
|
|
bool RISCVExegesisPostprocessing::processWriteFRM(MachineInstr &MI,
|
|
MachineRegisterInfo &MRI) {
|
|
// The virtual register will be the first operand in both SwapFRMImm and
|
|
// WriteFRM.
|
|
Register DestReg = MI.getOperand(0).getReg();
|
|
if (DestReg.isVirtual()) {
|
|
MRI.replaceRegWith(DestReg, allocateGPRRegister(*MI.getMF(), MRI));
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
FunctionPass *llvm::exegesis::createRISCVPostprocessingPass() {
|
|
return new RISCVExegesisPostprocessing();
|
|
}
|