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