xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVInsertReadWriteCSR.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
106c3fb27SDimitry Andric //===-- RISCVInsertReadWriteCSR.cpp - Insert Read/Write of RISC-V CSR -----===//
206c3fb27SDimitry Andric //
306c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
506c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606c3fb27SDimitry Andric //
706c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
806c3fb27SDimitry Andric // This file implements the machine function pass to insert read/write of CSR-s
906c3fb27SDimitry Andric // of the RISC-V instructions.
1006c3fb27SDimitry Andric //
11*5f757f3fSDimitry Andric // Currently the pass implements:
12*5f757f3fSDimitry Andric // -Writing and saving frm before an RVV floating-point instruction with a
13*5f757f3fSDimitry Andric //  static rounding mode and restores the value after.
1406c3fb27SDimitry Andric //
1506c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
1606c3fb27SDimitry Andric 
1706c3fb27SDimitry Andric #include "MCTargetDesc/RISCVBaseInfo.h"
1806c3fb27SDimitry Andric #include "RISCV.h"
1906c3fb27SDimitry Andric #include "RISCVSubtarget.h"
2006c3fb27SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
2106c3fb27SDimitry Andric using namespace llvm;
2206c3fb27SDimitry Andric 
2306c3fb27SDimitry Andric #define DEBUG_TYPE "riscv-insert-read-write-csr"
2406c3fb27SDimitry Andric #define RISCV_INSERT_READ_WRITE_CSR_NAME "RISC-V Insert Read/Write CSR Pass"
2506c3fb27SDimitry Andric 
2606c3fb27SDimitry Andric namespace {
2706c3fb27SDimitry Andric 
2806c3fb27SDimitry Andric class RISCVInsertReadWriteCSR : public MachineFunctionPass {
2906c3fb27SDimitry Andric   const TargetInstrInfo *TII;
3006c3fb27SDimitry Andric 
3106c3fb27SDimitry Andric public:
3206c3fb27SDimitry Andric   static char ID;
3306c3fb27SDimitry Andric 
34*5f757f3fSDimitry Andric   RISCVInsertReadWriteCSR() : MachineFunctionPass(ID) {}
3506c3fb27SDimitry Andric 
3606c3fb27SDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
3706c3fb27SDimitry Andric 
3806c3fb27SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override {
3906c3fb27SDimitry Andric     AU.setPreservesCFG();
4006c3fb27SDimitry Andric     MachineFunctionPass::getAnalysisUsage(AU);
4106c3fb27SDimitry Andric   }
4206c3fb27SDimitry Andric 
4306c3fb27SDimitry Andric   StringRef getPassName() const override {
4406c3fb27SDimitry Andric     return RISCV_INSERT_READ_WRITE_CSR_NAME;
4506c3fb27SDimitry Andric   }
4606c3fb27SDimitry Andric 
4706c3fb27SDimitry Andric private:
4806c3fb27SDimitry Andric   bool emitWriteRoundingMode(MachineBasicBlock &MBB);
4906c3fb27SDimitry Andric };
5006c3fb27SDimitry Andric 
5106c3fb27SDimitry Andric } // end anonymous namespace
5206c3fb27SDimitry Andric 
5306c3fb27SDimitry Andric char RISCVInsertReadWriteCSR::ID = 0;
5406c3fb27SDimitry Andric 
5506c3fb27SDimitry Andric INITIALIZE_PASS(RISCVInsertReadWriteCSR, DEBUG_TYPE,
5606c3fb27SDimitry Andric                 RISCV_INSERT_READ_WRITE_CSR_NAME, false, false)
5706c3fb27SDimitry Andric 
58*5f757f3fSDimitry Andric // This function also swaps frm and restores it when encountering an RVV
59*5f757f3fSDimitry Andric // floating point instruction with a static rounding mode.
6006c3fb27SDimitry Andric bool RISCVInsertReadWriteCSR::emitWriteRoundingMode(MachineBasicBlock &MBB) {
6106c3fb27SDimitry Andric   bool Changed = false;
6206c3fb27SDimitry Andric   for (MachineInstr &MI : MBB) {
63*5f757f3fSDimitry Andric     int FRMIdx = RISCVII::getFRMOpNum(MI.getDesc());
64*5f757f3fSDimitry Andric     if (FRMIdx < 0)
65*5f757f3fSDimitry Andric       continue;
6606c3fb27SDimitry Andric 
67*5f757f3fSDimitry Andric     unsigned FRMImm = MI.getOperand(FRMIdx).getImm();
6806c3fb27SDimitry Andric 
6906c3fb27SDimitry Andric     // The value is a hint to this pass to not alter the frm value.
7006c3fb27SDimitry Andric     if (FRMImm == RISCVFPRndMode::DYN)
7106c3fb27SDimitry Andric       continue;
7206c3fb27SDimitry Andric 
7306c3fb27SDimitry Andric     Changed = true;
7406c3fb27SDimitry Andric 
7506c3fb27SDimitry Andric     // Save
7606c3fb27SDimitry Andric     MachineRegisterInfo *MRI = &MBB.getParent()->getRegInfo();
7706c3fb27SDimitry Andric     Register SavedFRM = MRI->createVirtualRegister(&RISCV::GPRRegClass);
7806c3fb27SDimitry Andric     BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(RISCV::SwapFRMImm),
7906c3fb27SDimitry Andric             SavedFRM)
8006c3fb27SDimitry Andric         .addImm(FRMImm);
8106c3fb27SDimitry Andric     MI.addOperand(MachineOperand::CreateReg(RISCV::FRM, /*IsDef*/ false,
8206c3fb27SDimitry Andric                                             /*IsImp*/ true));
8306c3fb27SDimitry Andric     // Restore
8406c3fb27SDimitry Andric     MachineInstrBuilder MIB =
8506c3fb27SDimitry Andric         BuildMI(*MBB.getParent(), {}, TII->get(RISCV::WriteFRM))
8606c3fb27SDimitry Andric             .addReg(SavedFRM);
8706c3fb27SDimitry Andric     MBB.insertAfter(MI, MIB);
8806c3fb27SDimitry Andric   }
8906c3fb27SDimitry Andric   return Changed;
9006c3fb27SDimitry Andric }
9106c3fb27SDimitry Andric 
9206c3fb27SDimitry Andric bool RISCVInsertReadWriteCSR::runOnMachineFunction(MachineFunction &MF) {
9306c3fb27SDimitry Andric   // Skip if the vector extension is not enabled.
9406c3fb27SDimitry Andric   const RISCVSubtarget &ST = MF.getSubtarget<RISCVSubtarget>();
9506c3fb27SDimitry Andric   if (!ST.hasVInstructions())
9606c3fb27SDimitry Andric     return false;
9706c3fb27SDimitry Andric 
9806c3fb27SDimitry Andric   TII = ST.getInstrInfo();
9906c3fb27SDimitry Andric 
10006c3fb27SDimitry Andric   bool Changed = false;
10106c3fb27SDimitry Andric 
10206c3fb27SDimitry Andric   for (MachineBasicBlock &MBB : MF)
10306c3fb27SDimitry Andric     Changed |= emitWriteRoundingMode(MBB);
10406c3fb27SDimitry Andric 
10506c3fb27SDimitry Andric   return Changed;
10606c3fb27SDimitry Andric }
10706c3fb27SDimitry Andric 
10806c3fb27SDimitry Andric FunctionPass *llvm::createRISCVInsertReadWriteCSRPass() {
10906c3fb27SDimitry Andric   return new RISCVInsertReadWriteCSR();
11006c3fb27SDimitry Andric }
111