xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVInsertReadWriteCSR.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
1*06c3fb27SDimitry Andric //===-- RISCVInsertReadWriteCSR.cpp - Insert Read/Write of RISC-V CSR -----===//
2*06c3fb27SDimitry Andric //
3*06c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*06c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*06c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*06c3fb27SDimitry Andric //
7*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
8*06c3fb27SDimitry Andric // This file implements the machine function pass to insert read/write of CSR-s
9*06c3fb27SDimitry Andric // of the RISC-V instructions.
10*06c3fb27SDimitry Andric //
11*06c3fb27SDimitry Andric // Currently the pass implements naive insertion of a write to vxrm before an
12*06c3fb27SDimitry Andric // RVV fixed-point instruction.
13*06c3fb27SDimitry Andric //
14*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
15*06c3fb27SDimitry Andric 
16*06c3fb27SDimitry Andric #include "MCTargetDesc/RISCVBaseInfo.h"
17*06c3fb27SDimitry Andric #include "RISCV.h"
18*06c3fb27SDimitry Andric #include "RISCVSubtarget.h"
19*06c3fb27SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
20*06c3fb27SDimitry Andric using namespace llvm;
21*06c3fb27SDimitry Andric 
22*06c3fb27SDimitry Andric #define DEBUG_TYPE "riscv-insert-read-write-csr"
23*06c3fb27SDimitry Andric #define RISCV_INSERT_READ_WRITE_CSR_NAME "RISC-V Insert Read/Write CSR Pass"
24*06c3fb27SDimitry Andric 
25*06c3fb27SDimitry Andric namespace {
26*06c3fb27SDimitry Andric 
27*06c3fb27SDimitry Andric class RISCVInsertReadWriteCSR : public MachineFunctionPass {
28*06c3fb27SDimitry Andric   const TargetInstrInfo *TII;
29*06c3fb27SDimitry Andric 
30*06c3fb27SDimitry Andric public:
31*06c3fb27SDimitry Andric   static char ID;
32*06c3fb27SDimitry Andric 
33*06c3fb27SDimitry Andric   RISCVInsertReadWriteCSR() : MachineFunctionPass(ID) {
34*06c3fb27SDimitry Andric     initializeRISCVInsertReadWriteCSRPass(*PassRegistry::getPassRegistry());
35*06c3fb27SDimitry Andric   }
36*06c3fb27SDimitry Andric 
37*06c3fb27SDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
38*06c3fb27SDimitry Andric 
39*06c3fb27SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override {
40*06c3fb27SDimitry Andric     AU.setPreservesCFG();
41*06c3fb27SDimitry Andric     MachineFunctionPass::getAnalysisUsage(AU);
42*06c3fb27SDimitry Andric   }
43*06c3fb27SDimitry Andric 
44*06c3fb27SDimitry Andric   StringRef getPassName() const override {
45*06c3fb27SDimitry Andric     return RISCV_INSERT_READ_WRITE_CSR_NAME;
46*06c3fb27SDimitry Andric   }
47*06c3fb27SDimitry Andric 
48*06c3fb27SDimitry Andric private:
49*06c3fb27SDimitry Andric   bool emitWriteRoundingMode(MachineBasicBlock &MBB);
50*06c3fb27SDimitry Andric };
51*06c3fb27SDimitry Andric 
52*06c3fb27SDimitry Andric } // end anonymous namespace
53*06c3fb27SDimitry Andric 
54*06c3fb27SDimitry Andric char RISCVInsertReadWriteCSR::ID = 0;
55*06c3fb27SDimitry Andric 
56*06c3fb27SDimitry Andric INITIALIZE_PASS(RISCVInsertReadWriteCSR, DEBUG_TYPE,
57*06c3fb27SDimitry Andric                 RISCV_INSERT_READ_WRITE_CSR_NAME, false, false)
58*06c3fb27SDimitry Andric 
59*06c3fb27SDimitry Andric // Returns the index to the rounding mode immediate value if any, otherwise the
60*06c3fb27SDimitry Andric // function will return None.
61*06c3fb27SDimitry Andric static std::optional<unsigned> getRoundModeIdx(const MachineInstr &MI) {
62*06c3fb27SDimitry Andric   uint64_t TSFlags = MI.getDesc().TSFlags;
63*06c3fb27SDimitry Andric   if (!RISCVII::hasRoundModeOp(TSFlags))
64*06c3fb27SDimitry Andric     return std::nullopt;
65*06c3fb27SDimitry Andric 
66*06c3fb27SDimitry Andric   // The operand order
67*06c3fb27SDimitry Andric   // -------------------------------------
68*06c3fb27SDimitry Andric   // | n-1 (if any)   | n-2  | n-3 | n-4 |
69*06c3fb27SDimitry Andric   // | policy         | sew  | vl  | rm  |
70*06c3fb27SDimitry Andric   // -------------------------------------
71*06c3fb27SDimitry Andric   return MI.getNumExplicitOperands() - RISCVII::hasVecPolicyOp(TSFlags) - 3;
72*06c3fb27SDimitry Andric }
73*06c3fb27SDimitry Andric 
74*06c3fb27SDimitry Andric // This function inserts a write to vxrm when encountering an RVV fixed-point
75*06c3fb27SDimitry Andric // instruction.
76*06c3fb27SDimitry Andric bool RISCVInsertReadWriteCSR::emitWriteRoundingMode(MachineBasicBlock &MBB) {
77*06c3fb27SDimitry Andric   bool Changed = false;
78*06c3fb27SDimitry Andric   for (MachineInstr &MI : MBB) {
79*06c3fb27SDimitry Andric     if (auto RoundModeIdx = getRoundModeIdx(MI)) {
80*06c3fb27SDimitry Andric       if (RISCVII::usesVXRM(MI.getDesc().TSFlags)) {
81*06c3fb27SDimitry Andric         unsigned VXRMImm = MI.getOperand(*RoundModeIdx).getImm();
82*06c3fb27SDimitry Andric 
83*06c3fb27SDimitry Andric         Changed = true;
84*06c3fb27SDimitry Andric 
85*06c3fb27SDimitry Andric         BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(RISCV::WriteVXRMImm))
86*06c3fb27SDimitry Andric             .addImm(VXRMImm);
87*06c3fb27SDimitry Andric         MI.addOperand(MachineOperand::CreateReg(RISCV::VXRM, /*IsDef*/ false,
88*06c3fb27SDimitry Andric                                                 /*IsImp*/ true));
89*06c3fb27SDimitry Andric       } else { // FRM
90*06c3fb27SDimitry Andric         unsigned FRMImm = MI.getOperand(*RoundModeIdx).getImm();
91*06c3fb27SDimitry Andric 
92*06c3fb27SDimitry Andric         // The value is a hint to this pass to not alter the frm value.
93*06c3fb27SDimitry Andric         if (FRMImm == RISCVFPRndMode::DYN)
94*06c3fb27SDimitry Andric           continue;
95*06c3fb27SDimitry Andric 
96*06c3fb27SDimitry Andric         Changed = true;
97*06c3fb27SDimitry Andric 
98*06c3fb27SDimitry Andric         // Save
99*06c3fb27SDimitry Andric         MachineRegisterInfo *MRI = &MBB.getParent()->getRegInfo();
100*06c3fb27SDimitry Andric         Register SavedFRM = MRI->createVirtualRegister(&RISCV::GPRRegClass);
101*06c3fb27SDimitry Andric         BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(RISCV::SwapFRMImm),
102*06c3fb27SDimitry Andric                 SavedFRM)
103*06c3fb27SDimitry Andric             .addImm(FRMImm);
104*06c3fb27SDimitry Andric         MI.addOperand(MachineOperand::CreateReg(RISCV::FRM, /*IsDef*/ false,
105*06c3fb27SDimitry Andric                                                 /*IsImp*/ true));
106*06c3fb27SDimitry Andric         // Restore
107*06c3fb27SDimitry Andric         MachineInstrBuilder MIB =
108*06c3fb27SDimitry Andric             BuildMI(*MBB.getParent(), {}, TII->get(RISCV::WriteFRM))
109*06c3fb27SDimitry Andric                 .addReg(SavedFRM);
110*06c3fb27SDimitry Andric         MBB.insertAfter(MI, MIB);
111*06c3fb27SDimitry Andric       }
112*06c3fb27SDimitry Andric     }
113*06c3fb27SDimitry Andric   }
114*06c3fb27SDimitry Andric   return Changed;
115*06c3fb27SDimitry Andric }
116*06c3fb27SDimitry Andric 
117*06c3fb27SDimitry Andric bool RISCVInsertReadWriteCSR::runOnMachineFunction(MachineFunction &MF) {
118*06c3fb27SDimitry Andric   // Skip if the vector extension is not enabled.
119*06c3fb27SDimitry Andric   const RISCVSubtarget &ST = MF.getSubtarget<RISCVSubtarget>();
120*06c3fb27SDimitry Andric   if (!ST.hasVInstructions())
121*06c3fb27SDimitry Andric     return false;
122*06c3fb27SDimitry Andric 
123*06c3fb27SDimitry Andric   TII = ST.getInstrInfo();
124*06c3fb27SDimitry Andric 
125*06c3fb27SDimitry Andric   bool Changed = false;
126*06c3fb27SDimitry Andric 
127*06c3fb27SDimitry Andric   for (MachineBasicBlock &MBB : MF)
128*06c3fb27SDimitry Andric     Changed |= emitWriteRoundingMode(MBB);
129*06c3fb27SDimitry Andric 
130*06c3fb27SDimitry Andric   return Changed;
131*06c3fb27SDimitry Andric }
132*06c3fb27SDimitry Andric 
133*06c3fb27SDimitry Andric FunctionPass *llvm::createRISCVInsertReadWriteCSRPass() {
134*06c3fb27SDimitry Andric   return new RISCVInsertReadWriteCSR();
135*06c3fb27SDimitry Andric }
136