Files
clang-p2996/llvm/lib/Target/RISCV/RISCVInsertReadWriteCSR.cpp
Craig Topper 014390d937 [RISCV] Implement cross basic block VXRM write insertion. (#70382)
This adds a new pass to insert VXRM writes for vector instructions. With
the goal of avoiding redundant writes.

The pass does 2 dataflow algorithms. The first is a forward data flow to
calculate where a VXRM value is available. The second is a backwards
dataflow to determine where a VXRM value is anticipated.

Finally, we use the results of these two dataflows to insert VXRM writes
where a value is anticipated, but not available.

The pass does not split critical edges so we aren't always able to
eliminate all redundancy.

The pass will only insert vxrm writes on paths that always require it.
2023-11-02 14:09:27 -07:00

113 lines
3.4 KiB
C++

//===-- RISCVInsertReadWriteCSR.cpp - Insert Read/Write of RISC-V CSR -----===//
//
// 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
//
//===----------------------------------------------------------------------===//
// This file implements the machine function pass to insert read/write of CSR-s
// of the RISC-V instructions.
//
// Currently the pass implements:
// -Writing and saving frm before an RVV floating-point instruction with a
// static rounding mode and restores the value after.
//
//===----------------------------------------------------------------------===//
#include "MCTargetDesc/RISCVBaseInfo.h"
#include "RISCV.h"
#include "RISCVSubtarget.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
using namespace llvm;
#define DEBUG_TYPE "riscv-insert-read-write-csr"
#define RISCV_INSERT_READ_WRITE_CSR_NAME "RISC-V Insert Read/Write CSR Pass"
namespace {
class RISCVInsertReadWriteCSR : public MachineFunctionPass {
const TargetInstrInfo *TII;
public:
static char ID;
RISCVInsertReadWriteCSR() : MachineFunctionPass(ID) {
initializeRISCVInsertReadWriteCSRPass(*PassRegistry::getPassRegistry());
}
bool runOnMachineFunction(MachineFunction &MF) override;
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesCFG();
MachineFunctionPass::getAnalysisUsage(AU);
}
StringRef getPassName() const override {
return RISCV_INSERT_READ_WRITE_CSR_NAME;
}
private:
bool emitWriteRoundingMode(MachineBasicBlock &MBB);
};
} // end anonymous namespace
char RISCVInsertReadWriteCSR::ID = 0;
INITIALIZE_PASS(RISCVInsertReadWriteCSR, DEBUG_TYPE,
RISCV_INSERT_READ_WRITE_CSR_NAME, false, false)
// This function also swaps frm and restores it when encountering an RVV
// floating point instruction with a static rounding mode.
bool RISCVInsertReadWriteCSR::emitWriteRoundingMode(MachineBasicBlock &MBB) {
bool Changed = false;
for (MachineInstr &MI : MBB) {
int FRMIdx = RISCVII::getFRMOpNum(MI.getDesc());
if (FRMIdx < 0)
continue;
unsigned FRMImm = MI.getOperand(FRMIdx).getImm();
// The value is a hint to this pass to not alter the frm value.
if (FRMImm == RISCVFPRndMode::DYN)
continue;
Changed = true;
// Save
MachineRegisterInfo *MRI = &MBB.getParent()->getRegInfo();
Register SavedFRM = MRI->createVirtualRegister(&RISCV::GPRRegClass);
BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(RISCV::SwapFRMImm),
SavedFRM)
.addImm(FRMImm);
MI.addOperand(MachineOperand::CreateReg(RISCV::FRM, /*IsDef*/ false,
/*IsImp*/ true));
// Restore
MachineInstrBuilder MIB =
BuildMI(*MBB.getParent(), {}, TII->get(RISCV::WriteFRM))
.addReg(SavedFRM);
MBB.insertAfter(MI, MIB);
}
return Changed;
}
bool RISCVInsertReadWriteCSR::runOnMachineFunction(MachineFunction &MF) {
// Skip if the vector extension is not enabled.
const RISCVSubtarget &ST = MF.getSubtarget<RISCVSubtarget>();
if (!ST.hasVInstructions())
return false;
TII = ST.getInstrInfo();
bool Changed = false;
for (MachineBasicBlock &MBB : MF)
Changed |= emitWriteRoundingMode(MBB);
return Changed;
}
FunctionPass *llvm::createRISCVInsertReadWriteCSRPass() {
return new RISCVInsertReadWriteCSR();
}