1fe013be4SDimitry Andric //===-- RISCVInsertReadWriteCSR.cpp - Insert Read/Write of RISC-V CSR -----===//
2fe013be4SDimitry Andric //
3fe013be4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4fe013be4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5fe013be4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6fe013be4SDimitry Andric //
7fe013be4SDimitry Andric //===----------------------------------------------------------------------===//
8fe013be4SDimitry Andric // This file implements the machine function pass to insert read/write of CSR-s
9fe013be4SDimitry Andric // of the RISC-V instructions.
10fe013be4SDimitry Andric //
11*c9157d92SDimitry Andric // Currently the pass implements:
12*c9157d92SDimitry Andric // -Writing and saving frm before an RVV floating-point instruction with a
13*c9157d92SDimitry Andric //  static rounding mode and restores the value after.
14fe013be4SDimitry Andric //
15fe013be4SDimitry Andric //===----------------------------------------------------------------------===//
16fe013be4SDimitry Andric 
17fe013be4SDimitry Andric #include "MCTargetDesc/RISCVBaseInfo.h"
18fe013be4SDimitry Andric #include "RISCV.h"
19fe013be4SDimitry Andric #include "RISCVSubtarget.h"
20fe013be4SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
21fe013be4SDimitry Andric using namespace llvm;
22fe013be4SDimitry Andric 
23fe013be4SDimitry Andric #define DEBUG_TYPE "riscv-insert-read-write-csr"
24fe013be4SDimitry Andric #define RISCV_INSERT_READ_WRITE_CSR_NAME "RISC-V Insert Read/Write CSR Pass"
25fe013be4SDimitry Andric 
26fe013be4SDimitry Andric namespace {
27fe013be4SDimitry Andric 
28fe013be4SDimitry Andric class RISCVInsertReadWriteCSR : public MachineFunctionPass {
29fe013be4SDimitry Andric   const TargetInstrInfo *TII;
30fe013be4SDimitry Andric 
31fe013be4SDimitry Andric public:
32fe013be4SDimitry Andric   static char ID;
33fe013be4SDimitry Andric 
RISCVInsertReadWriteCSR()34*c9157d92SDimitry Andric   RISCVInsertReadWriteCSR() : MachineFunctionPass(ID) {}
35fe013be4SDimitry Andric 
36fe013be4SDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
37fe013be4SDimitry Andric 
getAnalysisUsage(AnalysisUsage & AU) const38fe013be4SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override {
39fe013be4SDimitry Andric     AU.setPreservesCFG();
40fe013be4SDimitry Andric     MachineFunctionPass::getAnalysisUsage(AU);
41fe013be4SDimitry Andric   }
42fe013be4SDimitry Andric 
getPassName() const43fe013be4SDimitry Andric   StringRef getPassName() const override {
44fe013be4SDimitry Andric     return RISCV_INSERT_READ_WRITE_CSR_NAME;
45fe013be4SDimitry Andric   }
46fe013be4SDimitry Andric 
47fe013be4SDimitry Andric private:
48fe013be4SDimitry Andric   bool emitWriteRoundingMode(MachineBasicBlock &MBB);
49fe013be4SDimitry Andric };
50fe013be4SDimitry Andric 
51fe013be4SDimitry Andric } // end anonymous namespace
52fe013be4SDimitry Andric 
53fe013be4SDimitry Andric char RISCVInsertReadWriteCSR::ID = 0;
54fe013be4SDimitry Andric 
INITIALIZE_PASS(RISCVInsertReadWriteCSR,DEBUG_TYPE,RISCV_INSERT_READ_WRITE_CSR_NAME,false,false)55fe013be4SDimitry Andric INITIALIZE_PASS(RISCVInsertReadWriteCSR, DEBUG_TYPE,
56fe013be4SDimitry Andric                 RISCV_INSERT_READ_WRITE_CSR_NAME, false, false)
57fe013be4SDimitry Andric 
58*c9157d92SDimitry Andric // This function also swaps frm and restores it when encountering an RVV
59*c9157d92SDimitry Andric // floating point instruction with a static rounding mode.
60fe013be4SDimitry Andric bool RISCVInsertReadWriteCSR::emitWriteRoundingMode(MachineBasicBlock &MBB) {
61fe013be4SDimitry Andric   bool Changed = false;
62fe013be4SDimitry Andric   for (MachineInstr &MI : MBB) {
63*c9157d92SDimitry Andric     int FRMIdx = RISCVII::getFRMOpNum(MI.getDesc());
64*c9157d92SDimitry Andric     if (FRMIdx < 0)
65*c9157d92SDimitry Andric       continue;
66fe013be4SDimitry Andric 
67*c9157d92SDimitry Andric     unsigned FRMImm = MI.getOperand(FRMIdx).getImm();
68fe013be4SDimitry Andric 
69fe013be4SDimitry Andric     // The value is a hint to this pass to not alter the frm value.
70fe013be4SDimitry Andric     if (FRMImm == RISCVFPRndMode::DYN)
71fe013be4SDimitry Andric       continue;
72fe013be4SDimitry Andric 
73fe013be4SDimitry Andric     Changed = true;
74fe013be4SDimitry Andric 
75fe013be4SDimitry Andric     // Save
76fe013be4SDimitry Andric     MachineRegisterInfo *MRI = &MBB.getParent()->getRegInfo();
77fe013be4SDimitry Andric     Register SavedFRM = MRI->createVirtualRegister(&RISCV::GPRRegClass);
78fe013be4SDimitry Andric     BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(RISCV::SwapFRMImm),
79fe013be4SDimitry Andric             SavedFRM)
80fe013be4SDimitry Andric         .addImm(FRMImm);
81fe013be4SDimitry Andric     MI.addOperand(MachineOperand::CreateReg(RISCV::FRM, /*IsDef*/ false,
82fe013be4SDimitry Andric                                             /*IsImp*/ true));
83fe013be4SDimitry Andric     // Restore
84fe013be4SDimitry Andric     MachineInstrBuilder MIB =
85fe013be4SDimitry Andric         BuildMI(*MBB.getParent(), {}, TII->get(RISCV::WriteFRM))
86fe013be4SDimitry Andric             .addReg(SavedFRM);
87fe013be4SDimitry Andric     MBB.insertAfter(MI, MIB);
88fe013be4SDimitry Andric   }
89fe013be4SDimitry Andric   return Changed;
90fe013be4SDimitry Andric }
91fe013be4SDimitry Andric 
runOnMachineFunction(MachineFunction & MF)92fe013be4SDimitry Andric bool RISCVInsertReadWriteCSR::runOnMachineFunction(MachineFunction &MF) {
93fe013be4SDimitry Andric   // Skip if the vector extension is not enabled.
94fe013be4SDimitry Andric   const RISCVSubtarget &ST = MF.getSubtarget<RISCVSubtarget>();
95fe013be4SDimitry Andric   if (!ST.hasVInstructions())
96fe013be4SDimitry Andric     return false;
97fe013be4SDimitry Andric 
98fe013be4SDimitry Andric   TII = ST.getInstrInfo();
99fe013be4SDimitry Andric 
100fe013be4SDimitry Andric   bool Changed = false;
101fe013be4SDimitry Andric 
102fe013be4SDimitry Andric   for (MachineBasicBlock &MBB : MF)
103fe013be4SDimitry Andric     Changed |= emitWriteRoundingMode(MBB);
104fe013be4SDimitry Andric 
105fe013be4SDimitry Andric   return Changed;
106fe013be4SDimitry Andric }
107fe013be4SDimitry Andric 
createRISCVInsertReadWriteCSRPass()108fe013be4SDimitry Andric FunctionPass *llvm::createRISCVInsertReadWriteCSRPass() {
109fe013be4SDimitry Andric   return new RISCVInsertReadWriteCSR();
110fe013be4SDimitry Andric }
111