LLVM 24.0.0git
RISCVInsertReadWriteCSR.cpp
Go to the documentation of this file.
1//===-- RISCVInsertReadWriteCSR.cpp - Insert Read/Write of RISC-V CSR -----===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8// This file implements the machine function pass to insert read/write of CSR-s
9// of the RISC-V instructions.
10//
11// Currently the pass implements:
12// -Writing and saving frm before an RVV floating-point instruction with a
13// static rounding mode and restores the value after.
14//
15//===----------------------------------------------------------------------===//
16
18#include "RISCV.h"
19#include "RISCVSubtarget.h"
21using namespace llvm;
22
23#define DEBUG_TYPE "riscv-insert-read-write-csr"
24#define RISCV_INSERT_READ_WRITE_CSR_NAME "RISC-V Insert Read/Write CSR Pass"
25
26namespace {
27
28class RISCVInsertReadWriteCSR : public MachineFunctionPass {
29 const TargetInstrInfo *TII;
30
31public:
32 static char ID;
33
34 RISCVInsertReadWriteCSR() : MachineFunctionPass(ID) {}
35
36 bool runOnMachineFunction(MachineFunction &MF) override;
37
38 void getAnalysisUsage(AnalysisUsage &AU) const override {
39 AU.setPreservesCFG();
41 }
42
43 StringRef getPassName() const override {
45 }
46
47private:
48 bool emitWriteRoundingMode(MachineBasicBlock &MBB);
49 bool emitWriteRoundingModeOpt(MachineBasicBlock &MBB);
50};
51
52} // end anonymous namespace
53
54char RISCVInsertReadWriteCSR::ID = 0;
55
56INITIALIZE_PASS(RISCVInsertReadWriteCSR, DEBUG_TYPE,
58
59// TODO: Use more accurate rounding mode at the start of MBB.
60bool RISCVInsertReadWriteCSR::emitWriteRoundingModeOpt(MachineBasicBlock &MBB) {
61 bool Changed = false;
62 MachineInstr *LastFRMChanger = nullptr;
63 unsigned CurrentRM = RISCVFPRndMode::DYN;
64 Register SavedFRM;
65
66 for (MachineInstr &MI : MBB) {
67 if (MI.getOpcode() == RISCV::SwapFRMImm ||
68 MI.getOpcode() == RISCV::WriteFRMImm) {
69 CurrentRM = MI.getOperand(0).getImm();
70 SavedFRM = Register();
71 continue;
72 }
73
74 if (MI.getOpcode() == RISCV::WriteFRM) {
75 CurrentRM = RISCVFPRndMode::DYN;
76 SavedFRM = Register();
77 continue;
78 }
79
80 if (MI.isCall() || MI.isInlineAsm() ||
81 MI.readsRegister(RISCV::FRM, /*TRI=*/nullptr)) {
82 // Restore FRM before unknown operations.
83 if (SavedFRM.isValid())
84 BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(RISCV::WriteFRM))
85 .addReg(SavedFRM);
86 CurrentRM = RISCVFPRndMode::DYN;
87 SavedFRM = Register();
88 continue;
89 }
90
91 assert(!MI.modifiesRegister(RISCV::FRM, /*TRI=*/nullptr) &&
92 "Expected that MI could not modify FRM.");
93
94 int FRMIdx = RISCVII::getFRMOpNum(MI.getDesc());
95 if (FRMIdx < 0)
96 continue;
97 unsigned InstrRM = MI.getOperand(FRMIdx).getImm();
98
99 LastFRMChanger = &MI;
100
101 // Make MI implicit use FRM.
102 MI.addOperand(MachineOperand::CreateReg(RISCV::FRM, /*IsDef*/ false,
103 /*IsImp*/ true));
104 Changed = true;
105
106 // Skip if MI uses same rounding mode as FRM.
107 if (InstrRM == CurrentRM)
108 continue;
109
110 if (!SavedFRM.isValid()) {
111 // Save current FRM value to SavedFRM.
112 MachineRegisterInfo *MRI = &MBB.getParent()->getRegInfo();
113 SavedFRM = MRI->createVirtualRegister(&RISCV::GPRRegClass);
114 BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(RISCV::SwapFRMImm), SavedFRM)
115 .addImm(InstrRM);
116 } else {
117 // Don't need to save current FRM when SavedFRM having value.
118 BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(RISCV::WriteFRMImm))
119 .addImm(InstrRM);
120 }
121 CurrentRM = InstrRM;
122 }
123
124 // Restore FRM if needed.
125 if (SavedFRM.isValid()) {
126 assert(LastFRMChanger && "Expected valid pointer.");
127 MachineInstrBuilder MIB =
128 BuildMI(*MBB.getParent(), {}, TII->get(RISCV::WriteFRM))
129 .addReg(SavedFRM);
130 MBB.insertAfter(LastFRMChanger, MIB);
131 }
132
133 return Changed;
134}
135
136// This function also swaps frm and restores it when encountering an RVV
137// floating point instruction with a static rounding mode.
138bool RISCVInsertReadWriteCSR::emitWriteRoundingMode(MachineBasicBlock &MBB) {
139 bool Changed = false;
140 for (MachineInstr &MI : MBB) {
141 int FRMIdx = RISCVII::getFRMOpNum(MI.getDesc());
142 if (FRMIdx < 0)
143 continue;
144
145 unsigned FRMImm = MI.getOperand(FRMIdx).getImm();
146
147 // The value is a hint to this pass to not alter the frm value.
148 if (FRMImm == RISCVFPRndMode::DYN)
149 continue;
150
151 Changed = true;
152
153 // Save
154 MachineRegisterInfo *MRI = &MBB.getParent()->getRegInfo();
155 Register SavedFRM = MRI->createVirtualRegister(&RISCV::GPRRegClass);
156 BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(RISCV::SwapFRMImm),
157 SavedFRM)
158 .addImm(FRMImm);
159 MI.addOperand(MachineOperand::CreateReg(RISCV::FRM, /*IsDef*/ false,
160 /*IsImp*/ true));
161 // Restore
162 MachineInstrBuilder MIB =
163 BuildMI(*MBB.getParent(), {}, TII->get(RISCV::WriteFRM))
164 .addReg(SavedFRM);
165 MBB.insertAfter(MI, MIB);
166 }
167 return Changed;
168}
169
170bool RISCVInsertReadWriteCSR::runOnMachineFunction(MachineFunction &MF) {
171 // Skip if the vector extension is not enabled.
172 const RISCVSubtarget &ST = MF.getSubtarget<RISCVSubtarget>();
173 if (!ST.hasVInstructions())
174 return false;
175
176 TII = ST.getInstrInfo();
177
178 bool Changed = false;
179
180 for (MachineBasicBlock &MBB : MF) {
181 if (!ST.getCLOpts().frm_insert_opt)
182 Changed |= emitWriteRoundingMode(MBB);
183 else
184 Changed |= emitWriteRoundingModeOpt(MBB);
185 }
186
187 return Changed;
188}
189
191 return new RISCVInsertReadWriteCSR();
192}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock & MBB
#define DEBUG_TYPE
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
Promote Memory to Register
Definition Mem2Reg.cpp:110
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
#define RISCV_INSERT_READ_WRITE_CSR_NAME
Represent the analysis usage information of a pass.
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
Definition Pass.cpp:278
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:314
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
iterator insertAfter(iterator I, MachineInstr *MI)
Insert MI into the instruction list after I.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
Representation of each machine instruction.
static MachineOperand CreateReg(Register Reg, bool isDef, bool isImp=false, bool isKill=false, bool isDead=false, bool isUndef=false, bool isEarlyClobber=false, unsigned SubReg=0, bool isDebug=false, bool isInternalRead=false, bool isRenamable=false)
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
Wrapper class representing virtual and physical registers.
Definition Register.h:20
constexpr bool isValid() const
Definition Register.h:112
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
TargetInstrInfo - Interface to description of machine instruction set.
Changed
static int getFRMOpNum(const MCInstrDesc &Desc)
This is an optimization pass for GlobalISel generic memory operations.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
FunctionPass * createRISCVInsertReadWriteCSRPass()