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