xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVInsertWriteVXRM.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
1*5f757f3fSDimitry Andric //===-- RISCVInsertWriteVXRM.cpp - Insert Write of RISC-V VXRM CSR --------===//
2*5f757f3fSDimitry Andric //
3*5f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*5f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*5f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*5f757f3fSDimitry Andric //
7*5f757f3fSDimitry Andric //===----------------------------------------------------------------------===//
8*5f757f3fSDimitry Andric //
9*5f757f3fSDimitry Andric // This pass inserts writes to the VXRM CSR as needed by vector instructions.
10*5f757f3fSDimitry Andric // Each instruction that uses VXRM carries an operand that contains its required
11*5f757f3fSDimitry Andric // VXRM value. This pass tries to optimize placement to avoid redundant writes
12*5f757f3fSDimitry Andric // to VXRM.
13*5f757f3fSDimitry Andric //
14*5f757f3fSDimitry Andric // This is done using 2 dataflow algorithms. The first is a forward data flow
15*5f757f3fSDimitry Andric // to calculate where a VXRM value is available. The second is a backwards
16*5f757f3fSDimitry Andric // dataflow to determine where a VXRM value is anticipated.
17*5f757f3fSDimitry Andric //
18*5f757f3fSDimitry Andric // Finally, we use the results of these two dataflows to insert VXRM writes
19*5f757f3fSDimitry Andric // where a value is anticipated, but not available.
20*5f757f3fSDimitry Andric //
21*5f757f3fSDimitry Andric // FIXME: This pass does not split critical edges, so there can still be some
22*5f757f3fSDimitry Andric // redundancy.
23*5f757f3fSDimitry Andric //
24*5f757f3fSDimitry Andric // FIXME: If we are willing to have writes that aren't always needed, we could
25*5f757f3fSDimitry Andric // reduce the number of VXRM writes in some cases.
26*5f757f3fSDimitry Andric //===----------------------------------------------------------------------===//
27*5f757f3fSDimitry Andric 
28*5f757f3fSDimitry Andric #include "MCTargetDesc/RISCVBaseInfo.h"
29*5f757f3fSDimitry Andric #include "RISCV.h"
30*5f757f3fSDimitry Andric #include "RISCVSubtarget.h"
31*5f757f3fSDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
32*5f757f3fSDimitry Andric #include <queue>
33*5f757f3fSDimitry Andric 
34*5f757f3fSDimitry Andric using namespace llvm;
35*5f757f3fSDimitry Andric 
36*5f757f3fSDimitry Andric #define DEBUG_TYPE "riscv-insert-write-vxrm"
37*5f757f3fSDimitry Andric #define RISCV_INSERT_WRITE_VXRM_NAME "RISC-V Insert Write VXRM Pass"
38*5f757f3fSDimitry Andric 
39*5f757f3fSDimitry Andric namespace {
40*5f757f3fSDimitry Andric 
41*5f757f3fSDimitry Andric class VXRMInfo {
42*5f757f3fSDimitry Andric   uint8_t VXRMImm = 0;
43*5f757f3fSDimitry Andric 
44*5f757f3fSDimitry Andric   enum : uint8_t {
45*5f757f3fSDimitry Andric     Uninitialized,
46*5f757f3fSDimitry Andric     Static,
47*5f757f3fSDimitry Andric     Unknown,
48*5f757f3fSDimitry Andric   } State = Uninitialized;
49*5f757f3fSDimitry Andric 
50*5f757f3fSDimitry Andric public:
51*5f757f3fSDimitry Andric   VXRMInfo() {}
52*5f757f3fSDimitry Andric 
53*5f757f3fSDimitry Andric   static VXRMInfo getUnknown() {
54*5f757f3fSDimitry Andric     VXRMInfo Info;
55*5f757f3fSDimitry Andric     Info.setUnknown();
56*5f757f3fSDimitry Andric     return Info;
57*5f757f3fSDimitry Andric   }
58*5f757f3fSDimitry Andric 
59*5f757f3fSDimitry Andric   bool isValid() const { return State != Uninitialized; }
60*5f757f3fSDimitry Andric   void setUnknown() { State = Unknown; }
61*5f757f3fSDimitry Andric   bool isUnknown() const { return State == Unknown; }
62*5f757f3fSDimitry Andric 
63*5f757f3fSDimitry Andric   bool isStatic() const { return State == Static; }
64*5f757f3fSDimitry Andric 
65*5f757f3fSDimitry Andric   void setVXRMImm(unsigned Imm) {
66*5f757f3fSDimitry Andric     assert(Imm <= 3 && "Unexpected VXRM value");
67*5f757f3fSDimitry Andric     VXRMImm = Imm;
68*5f757f3fSDimitry Andric     State = Static;
69*5f757f3fSDimitry Andric   }
70*5f757f3fSDimitry Andric   unsigned getVXRMImm() const {
71*5f757f3fSDimitry Andric     assert(isStatic() && VXRMImm <= 3 && "Unexpected state");
72*5f757f3fSDimitry Andric     return VXRMImm;
73*5f757f3fSDimitry Andric   }
74*5f757f3fSDimitry Andric 
75*5f757f3fSDimitry Andric   bool operator==(const VXRMInfo &Other) const {
76*5f757f3fSDimitry Andric     // Uninitialized is only equal to another Uninitialized.
77*5f757f3fSDimitry Andric     if (State != Other.State)
78*5f757f3fSDimitry Andric       return false;
79*5f757f3fSDimitry Andric 
80*5f757f3fSDimitry Andric     if (isStatic())
81*5f757f3fSDimitry Andric       return VXRMImm == Other.VXRMImm;
82*5f757f3fSDimitry Andric 
83*5f757f3fSDimitry Andric     assert((isValid() || isUnknown()) && "Unexpected state");
84*5f757f3fSDimitry Andric     return true;
85*5f757f3fSDimitry Andric   }
86*5f757f3fSDimitry Andric 
87*5f757f3fSDimitry Andric   bool operator!=(const VXRMInfo &Other) const { return !(*this == Other); }
88*5f757f3fSDimitry Andric 
89*5f757f3fSDimitry Andric   // Calculate the VXRMInfo visible to a block assuming this and Other are
90*5f757f3fSDimitry Andric   // both predecessors.
91*5f757f3fSDimitry Andric   VXRMInfo intersect(const VXRMInfo &Other) const {
92*5f757f3fSDimitry Andric     // If the new value isn't valid, ignore it.
93*5f757f3fSDimitry Andric     if (!Other.isValid())
94*5f757f3fSDimitry Andric       return *this;
95*5f757f3fSDimitry Andric 
96*5f757f3fSDimitry Andric     // If this value isn't valid, this must be the first predecessor, use it.
97*5f757f3fSDimitry Andric     if (!isValid())
98*5f757f3fSDimitry Andric       return Other;
99*5f757f3fSDimitry Andric 
100*5f757f3fSDimitry Andric     // If either is unknown, the result is unknown.
101*5f757f3fSDimitry Andric     if (isUnknown() || Other.isUnknown())
102*5f757f3fSDimitry Andric       return VXRMInfo::getUnknown();
103*5f757f3fSDimitry Andric 
104*5f757f3fSDimitry Andric     // If we have an exact match, return this.
105*5f757f3fSDimitry Andric     if (*this == Other)
106*5f757f3fSDimitry Andric       return *this;
107*5f757f3fSDimitry Andric 
108*5f757f3fSDimitry Andric     // Otherwise the result is unknown.
109*5f757f3fSDimitry Andric     return VXRMInfo::getUnknown();
110*5f757f3fSDimitry Andric   }
111*5f757f3fSDimitry Andric 
112*5f757f3fSDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
113*5f757f3fSDimitry Andric   /// Support for debugging, callable in GDB: V->dump()
114*5f757f3fSDimitry Andric   LLVM_DUMP_METHOD void dump() const {
115*5f757f3fSDimitry Andric     print(dbgs());
116*5f757f3fSDimitry Andric     dbgs() << "\n";
117*5f757f3fSDimitry Andric   }
118*5f757f3fSDimitry Andric 
119*5f757f3fSDimitry Andric   void print(raw_ostream &OS) const {
120*5f757f3fSDimitry Andric     OS << '{';
121*5f757f3fSDimitry Andric     if (!isValid())
122*5f757f3fSDimitry Andric       OS << "Uninitialized";
123*5f757f3fSDimitry Andric     else if (isUnknown())
124*5f757f3fSDimitry Andric       OS << "Unknown";
125*5f757f3fSDimitry Andric     else
126*5f757f3fSDimitry Andric       OS << getVXRMImm();
127*5f757f3fSDimitry Andric     OS << '}';
128*5f757f3fSDimitry Andric   }
129*5f757f3fSDimitry Andric #endif
130*5f757f3fSDimitry Andric };
131*5f757f3fSDimitry Andric 
132*5f757f3fSDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
133*5f757f3fSDimitry Andric LLVM_ATTRIBUTE_USED
134*5f757f3fSDimitry Andric inline raw_ostream &operator<<(raw_ostream &OS, const VXRMInfo &V) {
135*5f757f3fSDimitry Andric   V.print(OS);
136*5f757f3fSDimitry Andric   return OS;
137*5f757f3fSDimitry Andric }
138*5f757f3fSDimitry Andric #endif
139*5f757f3fSDimitry Andric 
140*5f757f3fSDimitry Andric struct BlockData {
141*5f757f3fSDimitry Andric   // Indicates if the block uses VXRM. Uninitialized means no use.
142*5f757f3fSDimitry Andric   VXRMInfo VXRMUse;
143*5f757f3fSDimitry Andric 
144*5f757f3fSDimitry Andric   // Indicates the VXRM output from the block. Unitialized means transparent.
145*5f757f3fSDimitry Andric   VXRMInfo VXRMOut;
146*5f757f3fSDimitry Andric 
147*5f757f3fSDimitry Andric   // Keeps track of the available VXRM value at the start of the basic bloc.
148*5f757f3fSDimitry Andric   VXRMInfo AvailableIn;
149*5f757f3fSDimitry Andric 
150*5f757f3fSDimitry Andric   // Keeps track of the available VXRM value at the end of the basic block.
151*5f757f3fSDimitry Andric   VXRMInfo AvailableOut;
152*5f757f3fSDimitry Andric 
153*5f757f3fSDimitry Andric   // Keeps track of what VXRM is anticipated at the start of the basic block.
154*5f757f3fSDimitry Andric   VXRMInfo AnticipatedIn;
155*5f757f3fSDimitry Andric 
156*5f757f3fSDimitry Andric   // Keeps track of what VXRM is anticipated at the end of the basic block.
157*5f757f3fSDimitry Andric   VXRMInfo AnticipatedOut;
158*5f757f3fSDimitry Andric 
159*5f757f3fSDimitry Andric   // Keeps track of whether the block is already in the queue.
160*5f757f3fSDimitry Andric   bool InQueue;
161*5f757f3fSDimitry Andric 
162*5f757f3fSDimitry Andric   BlockData() = default;
163*5f757f3fSDimitry Andric };
164*5f757f3fSDimitry Andric 
165*5f757f3fSDimitry Andric class RISCVInsertWriteVXRM : public MachineFunctionPass {
166*5f757f3fSDimitry Andric   const TargetInstrInfo *TII;
167*5f757f3fSDimitry Andric 
168*5f757f3fSDimitry Andric   std::vector<BlockData> BlockInfo;
169*5f757f3fSDimitry Andric   std::queue<const MachineBasicBlock *> WorkList;
170*5f757f3fSDimitry Andric 
171*5f757f3fSDimitry Andric public:
172*5f757f3fSDimitry Andric   static char ID;
173*5f757f3fSDimitry Andric 
174*5f757f3fSDimitry Andric   RISCVInsertWriteVXRM() : MachineFunctionPass(ID) {}
175*5f757f3fSDimitry Andric 
176*5f757f3fSDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
177*5f757f3fSDimitry Andric 
178*5f757f3fSDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override {
179*5f757f3fSDimitry Andric     AU.setPreservesCFG();
180*5f757f3fSDimitry Andric     MachineFunctionPass::getAnalysisUsage(AU);
181*5f757f3fSDimitry Andric   }
182*5f757f3fSDimitry Andric 
183*5f757f3fSDimitry Andric   StringRef getPassName() const override {
184*5f757f3fSDimitry Andric     return RISCV_INSERT_WRITE_VXRM_NAME;
185*5f757f3fSDimitry Andric   }
186*5f757f3fSDimitry Andric 
187*5f757f3fSDimitry Andric private:
188*5f757f3fSDimitry Andric   bool computeVXRMChanges(const MachineBasicBlock &MBB);
189*5f757f3fSDimitry Andric   void computeAvailable(const MachineBasicBlock &MBB);
190*5f757f3fSDimitry Andric   void computeAnticipated(const MachineBasicBlock &MBB);
191*5f757f3fSDimitry Andric   void emitWriteVXRM(MachineBasicBlock &MBB);
192*5f757f3fSDimitry Andric };
193*5f757f3fSDimitry Andric 
194*5f757f3fSDimitry Andric } // end anonymous namespace
195*5f757f3fSDimitry Andric 
196*5f757f3fSDimitry Andric char RISCVInsertWriteVXRM::ID = 0;
197*5f757f3fSDimitry Andric 
198*5f757f3fSDimitry Andric INITIALIZE_PASS(RISCVInsertWriteVXRM, DEBUG_TYPE, RISCV_INSERT_WRITE_VXRM_NAME,
199*5f757f3fSDimitry Andric                 false, false)
200*5f757f3fSDimitry Andric 
201*5f757f3fSDimitry Andric bool RISCVInsertWriteVXRM::computeVXRMChanges(const MachineBasicBlock &MBB) {
202*5f757f3fSDimitry Andric   BlockData &BBInfo = BlockInfo[MBB.getNumber()];
203*5f757f3fSDimitry Andric 
204*5f757f3fSDimitry Andric   bool NeedVXRMWrite = false;
205*5f757f3fSDimitry Andric   for (const MachineInstr &MI : MBB) {
206*5f757f3fSDimitry Andric     int VXRMIdx = RISCVII::getVXRMOpNum(MI.getDesc());
207*5f757f3fSDimitry Andric     if (VXRMIdx >= 0) {
208*5f757f3fSDimitry Andric       unsigned NewVXRMImm = MI.getOperand(VXRMIdx).getImm();
209*5f757f3fSDimitry Andric 
210*5f757f3fSDimitry Andric       if (!BBInfo.VXRMUse.isValid())
211*5f757f3fSDimitry Andric         BBInfo.VXRMUse.setVXRMImm(NewVXRMImm);
212*5f757f3fSDimitry Andric 
213*5f757f3fSDimitry Andric       BBInfo.VXRMOut.setVXRMImm(NewVXRMImm);
214*5f757f3fSDimitry Andric       NeedVXRMWrite = true;
215*5f757f3fSDimitry Andric       continue;
216*5f757f3fSDimitry Andric     }
217*5f757f3fSDimitry Andric 
218*5f757f3fSDimitry Andric     if (MI.isCall() || MI.isInlineAsm() || MI.modifiesRegister(RISCV::VXRM)) {
219*5f757f3fSDimitry Andric       if (!BBInfo.VXRMUse.isValid())
220*5f757f3fSDimitry Andric         BBInfo.VXRMUse.setUnknown();
221*5f757f3fSDimitry Andric 
222*5f757f3fSDimitry Andric       BBInfo.VXRMOut.setUnknown();
223*5f757f3fSDimitry Andric     }
224*5f757f3fSDimitry Andric   }
225*5f757f3fSDimitry Andric 
226*5f757f3fSDimitry Andric   return NeedVXRMWrite;
227*5f757f3fSDimitry Andric }
228*5f757f3fSDimitry Andric 
229*5f757f3fSDimitry Andric void RISCVInsertWriteVXRM::computeAvailable(const MachineBasicBlock &MBB) {
230*5f757f3fSDimitry Andric   BlockData &BBInfo = BlockInfo[MBB.getNumber()];
231*5f757f3fSDimitry Andric 
232*5f757f3fSDimitry Andric   BBInfo.InQueue = false;
233*5f757f3fSDimitry Andric 
234*5f757f3fSDimitry Andric   VXRMInfo Available;
235*5f757f3fSDimitry Andric   if (MBB.pred_empty()) {
236*5f757f3fSDimitry Andric     Available.setUnknown();
237*5f757f3fSDimitry Andric   } else {
238*5f757f3fSDimitry Andric     for (const MachineBasicBlock *P : MBB.predecessors())
239*5f757f3fSDimitry Andric       Available = Available.intersect(BlockInfo[P->getNumber()].AvailableOut);
240*5f757f3fSDimitry Andric   }
241*5f757f3fSDimitry Andric 
242*5f757f3fSDimitry Andric   // If we don't have any valid available info, wait until we do.
243*5f757f3fSDimitry Andric   if (!Available.isValid())
244*5f757f3fSDimitry Andric     return;
245*5f757f3fSDimitry Andric 
246*5f757f3fSDimitry Andric   if (Available != BBInfo.AvailableIn) {
247*5f757f3fSDimitry Andric     BBInfo.AvailableIn = Available;
248*5f757f3fSDimitry Andric     LLVM_DEBUG(dbgs() << "AvailableIn state of " << printMBBReference(MBB)
249*5f757f3fSDimitry Andric                       << " changed to " << BBInfo.AvailableIn << "\n");
250*5f757f3fSDimitry Andric   }
251*5f757f3fSDimitry Andric 
252*5f757f3fSDimitry Andric   if (BBInfo.VXRMOut.isValid())
253*5f757f3fSDimitry Andric     Available = BBInfo.VXRMOut;
254*5f757f3fSDimitry Andric 
255*5f757f3fSDimitry Andric   if (Available == BBInfo.AvailableOut)
256*5f757f3fSDimitry Andric     return;
257*5f757f3fSDimitry Andric 
258*5f757f3fSDimitry Andric   BBInfo.AvailableOut = Available;
259*5f757f3fSDimitry Andric   LLVM_DEBUG(dbgs() << "AvailableOut state of " << printMBBReference(MBB)
260*5f757f3fSDimitry Andric                     << " changed to " << BBInfo.AvailableOut << "\n");
261*5f757f3fSDimitry Andric 
262*5f757f3fSDimitry Andric   // Add the successors to the work list so that we can propagate.
263*5f757f3fSDimitry Andric   for (MachineBasicBlock *S : MBB.successors()) {
264*5f757f3fSDimitry Andric     if (!BlockInfo[S->getNumber()].InQueue) {
265*5f757f3fSDimitry Andric       BlockInfo[S->getNumber()].InQueue = true;
266*5f757f3fSDimitry Andric       WorkList.push(S);
267*5f757f3fSDimitry Andric     }
268*5f757f3fSDimitry Andric   }
269*5f757f3fSDimitry Andric }
270*5f757f3fSDimitry Andric 
271*5f757f3fSDimitry Andric void RISCVInsertWriteVXRM::computeAnticipated(const MachineBasicBlock &MBB) {
272*5f757f3fSDimitry Andric   BlockData &BBInfo = BlockInfo[MBB.getNumber()];
273*5f757f3fSDimitry Andric 
274*5f757f3fSDimitry Andric   BBInfo.InQueue = false;
275*5f757f3fSDimitry Andric 
276*5f757f3fSDimitry Andric   VXRMInfo Anticipated;
277*5f757f3fSDimitry Andric   if (MBB.succ_empty()) {
278*5f757f3fSDimitry Andric     Anticipated.setUnknown();
279*5f757f3fSDimitry Andric   } else {
280*5f757f3fSDimitry Andric     for (const MachineBasicBlock *S : MBB.successors())
281*5f757f3fSDimitry Andric       Anticipated =
282*5f757f3fSDimitry Andric           Anticipated.intersect(BlockInfo[S->getNumber()].AnticipatedIn);
283*5f757f3fSDimitry Andric   }
284*5f757f3fSDimitry Andric 
285*5f757f3fSDimitry Andric   // If we don't have any valid anticipated info, wait until we do.
286*5f757f3fSDimitry Andric   if (!Anticipated.isValid())
287*5f757f3fSDimitry Andric     return;
288*5f757f3fSDimitry Andric 
289*5f757f3fSDimitry Andric   if (Anticipated != BBInfo.AnticipatedOut) {
290*5f757f3fSDimitry Andric     BBInfo.AnticipatedOut = Anticipated;
291*5f757f3fSDimitry Andric     LLVM_DEBUG(dbgs() << "AnticipatedOut state of " << printMBBReference(MBB)
292*5f757f3fSDimitry Andric                       << " changed to " << BBInfo.AnticipatedOut << "\n");
293*5f757f3fSDimitry Andric   }
294*5f757f3fSDimitry Andric 
295*5f757f3fSDimitry Andric   // If this block reads VXRM, copy it.
296*5f757f3fSDimitry Andric   if (BBInfo.VXRMUse.isValid())
297*5f757f3fSDimitry Andric     Anticipated = BBInfo.VXRMUse;
298*5f757f3fSDimitry Andric 
299*5f757f3fSDimitry Andric   if (Anticipated == BBInfo.AnticipatedIn)
300*5f757f3fSDimitry Andric     return;
301*5f757f3fSDimitry Andric 
302*5f757f3fSDimitry Andric   BBInfo.AnticipatedIn = Anticipated;
303*5f757f3fSDimitry Andric   LLVM_DEBUG(dbgs() << "AnticipatedIn state of " << printMBBReference(MBB)
304*5f757f3fSDimitry Andric                     << " changed to " << BBInfo.AnticipatedIn << "\n");
305*5f757f3fSDimitry Andric 
306*5f757f3fSDimitry Andric   // Add the predecessors to the work list so that we can propagate.
307*5f757f3fSDimitry Andric   for (MachineBasicBlock *P : MBB.predecessors()) {
308*5f757f3fSDimitry Andric     if (!BlockInfo[P->getNumber()].InQueue) {
309*5f757f3fSDimitry Andric       BlockInfo[P->getNumber()].InQueue = true;
310*5f757f3fSDimitry Andric       WorkList.push(P);
311*5f757f3fSDimitry Andric     }
312*5f757f3fSDimitry Andric   }
313*5f757f3fSDimitry Andric }
314*5f757f3fSDimitry Andric 
315*5f757f3fSDimitry Andric void RISCVInsertWriteVXRM::emitWriteVXRM(MachineBasicBlock &MBB) {
316*5f757f3fSDimitry Andric   const BlockData &BBInfo = BlockInfo[MBB.getNumber()];
317*5f757f3fSDimitry Andric 
318*5f757f3fSDimitry Andric   VXRMInfo Info = BBInfo.AvailableIn;
319*5f757f3fSDimitry Andric 
320*5f757f3fSDimitry Andric   // Flag to indicates we need to insert a VXRM write. We want to delay it as
321*5f757f3fSDimitry Andric   // late as possible in this block.
322*5f757f3fSDimitry Andric   bool PendingInsert = false;
323*5f757f3fSDimitry Andric 
324*5f757f3fSDimitry Andric   // Insert VXRM write if anticipated and not available.
325*5f757f3fSDimitry Andric   if (BBInfo.AnticipatedIn.isStatic()) {
326*5f757f3fSDimitry Andric     // If this is the entry block and the value is anticipated, insert.
327*5f757f3fSDimitry Andric     if (MBB.isEntryBlock()) {
328*5f757f3fSDimitry Andric       PendingInsert = true;
329*5f757f3fSDimitry Andric     } else {
330*5f757f3fSDimitry Andric       // Search for any predecessors that wouldn't satisfy our requirement and
331*5f757f3fSDimitry Andric       // insert a write VXRM if needed.
332*5f757f3fSDimitry Andric       // NOTE: If one predecessor is able to provide the requirement, but
333*5f757f3fSDimitry Andric       // another isn't, it means we have a critical edge. The better placement
334*5f757f3fSDimitry Andric       // would be to split the critical edge.
335*5f757f3fSDimitry Andric       for (MachineBasicBlock *P : MBB.predecessors()) {
336*5f757f3fSDimitry Andric         const BlockData &PInfo = BlockInfo[P->getNumber()];
337*5f757f3fSDimitry Andric         // If it's available out of the predecessor, then we're ok.
338*5f757f3fSDimitry Andric         if (PInfo.AvailableOut.isStatic() &&
339*5f757f3fSDimitry Andric             PInfo.AvailableOut.getVXRMImm() ==
340*5f757f3fSDimitry Andric                 BBInfo.AnticipatedIn.getVXRMImm())
341*5f757f3fSDimitry Andric           continue;
342*5f757f3fSDimitry Andric         // If the predecessor anticipates this value for all its succesors,
343*5f757f3fSDimitry Andric         // then a write to VXRM would have already occured before this block is
344*5f757f3fSDimitry Andric         // executed.
345*5f757f3fSDimitry Andric         if (PInfo.AnticipatedOut.isStatic() &&
346*5f757f3fSDimitry Andric             PInfo.AnticipatedOut.getVXRMImm() ==
347*5f757f3fSDimitry Andric                 BBInfo.AnticipatedIn.getVXRMImm())
348*5f757f3fSDimitry Andric           continue;
349*5f757f3fSDimitry Andric         PendingInsert = true;
350*5f757f3fSDimitry Andric         break;
351*5f757f3fSDimitry Andric       }
352*5f757f3fSDimitry Andric     }
353*5f757f3fSDimitry Andric 
354*5f757f3fSDimitry Andric     Info = BBInfo.AnticipatedIn;
355*5f757f3fSDimitry Andric   }
356*5f757f3fSDimitry Andric 
357*5f757f3fSDimitry Andric   for (MachineInstr &MI : MBB) {
358*5f757f3fSDimitry Andric     int VXRMIdx = RISCVII::getVXRMOpNum(MI.getDesc());
359*5f757f3fSDimitry Andric     if (VXRMIdx >= 0) {
360*5f757f3fSDimitry Andric       unsigned NewVXRMImm = MI.getOperand(VXRMIdx).getImm();
361*5f757f3fSDimitry Andric 
362*5f757f3fSDimitry Andric       if (PendingInsert || !Info.isStatic() ||
363*5f757f3fSDimitry Andric           Info.getVXRMImm() != NewVXRMImm) {
364*5f757f3fSDimitry Andric         assert((!PendingInsert ||
365*5f757f3fSDimitry Andric                 (Info.isStatic() && Info.getVXRMImm() == NewVXRMImm)) &&
366*5f757f3fSDimitry Andric                "Pending VXRM insertion mismatch");
367*5f757f3fSDimitry Andric         LLVM_DEBUG(dbgs() << "Inserting before "; MI.print(dbgs()));
368*5f757f3fSDimitry Andric         BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(RISCV::WriteVXRMImm))
369*5f757f3fSDimitry Andric             .addImm(NewVXRMImm);
370*5f757f3fSDimitry Andric         PendingInsert = false;
371*5f757f3fSDimitry Andric       }
372*5f757f3fSDimitry Andric 
373*5f757f3fSDimitry Andric       MI.addOperand(MachineOperand::CreateReg(RISCV::VXRM, /*IsDef*/ false,
374*5f757f3fSDimitry Andric                                               /*IsImp*/ true));
375*5f757f3fSDimitry Andric       Info.setVXRMImm(NewVXRMImm);
376*5f757f3fSDimitry Andric       continue;
377*5f757f3fSDimitry Andric     }
378*5f757f3fSDimitry Andric 
379*5f757f3fSDimitry Andric     if (MI.isCall() || MI.isInlineAsm() || MI.modifiesRegister(RISCV::VXRM))
380*5f757f3fSDimitry Andric       Info.setUnknown();
381*5f757f3fSDimitry Andric   }
382*5f757f3fSDimitry Andric 
383*5f757f3fSDimitry Andric   // If all our successors anticipate a value, do the insert.
384*5f757f3fSDimitry Andric   // NOTE: It's possible that not all predecessors of our successor provide the
385*5f757f3fSDimitry Andric   // correct value. This can occur on critical edges. If we don't split the
386*5f757f3fSDimitry Andric   // critical edge we'll also have a write vxrm in the succesor that is
387*5f757f3fSDimitry Andric   // redundant with this one.
388*5f757f3fSDimitry Andric   if (PendingInsert ||
389*5f757f3fSDimitry Andric       (BBInfo.AnticipatedOut.isStatic() &&
390*5f757f3fSDimitry Andric        (!Info.isStatic() ||
391*5f757f3fSDimitry Andric         Info.getVXRMImm() != BBInfo.AnticipatedOut.getVXRMImm()))) {
392*5f757f3fSDimitry Andric     assert((!PendingInsert ||
393*5f757f3fSDimitry Andric             (Info.isStatic() && BBInfo.AnticipatedOut.isStatic() &&
394*5f757f3fSDimitry Andric              Info.getVXRMImm() == BBInfo.AnticipatedOut.getVXRMImm())) &&
395*5f757f3fSDimitry Andric            "Pending VXRM insertion mismatch");
396*5f757f3fSDimitry Andric     LLVM_DEBUG(dbgs() << "Inserting at end of " << printMBBReference(MBB)
397*5f757f3fSDimitry Andric                       << " changing to " << BBInfo.AnticipatedOut << "\n");
398*5f757f3fSDimitry Andric     BuildMI(MBB, MBB.getFirstTerminator(), DebugLoc(),
399*5f757f3fSDimitry Andric             TII->get(RISCV::WriteVXRMImm))
400*5f757f3fSDimitry Andric         .addImm(BBInfo.AnticipatedOut.getVXRMImm());
401*5f757f3fSDimitry Andric   }
402*5f757f3fSDimitry Andric }
403*5f757f3fSDimitry Andric 
404*5f757f3fSDimitry Andric bool RISCVInsertWriteVXRM::runOnMachineFunction(MachineFunction &MF) {
405*5f757f3fSDimitry Andric   // Skip if the vector extension is not enabled.
406*5f757f3fSDimitry Andric   const RISCVSubtarget &ST = MF.getSubtarget<RISCVSubtarget>();
407*5f757f3fSDimitry Andric   if (!ST.hasVInstructions())
408*5f757f3fSDimitry Andric     return false;
409*5f757f3fSDimitry Andric 
410*5f757f3fSDimitry Andric   TII = ST.getInstrInfo();
411*5f757f3fSDimitry Andric 
412*5f757f3fSDimitry Andric   assert(BlockInfo.empty() && "Expect empty block infos");
413*5f757f3fSDimitry Andric   BlockInfo.resize(MF.getNumBlockIDs());
414*5f757f3fSDimitry Andric 
415*5f757f3fSDimitry Andric   // Phase 1 - collect block information.
416*5f757f3fSDimitry Andric   bool NeedVXRMChange = false;
417*5f757f3fSDimitry Andric   for (const MachineBasicBlock &MBB : MF)
418*5f757f3fSDimitry Andric     NeedVXRMChange |= computeVXRMChanges(MBB);
419*5f757f3fSDimitry Andric 
420*5f757f3fSDimitry Andric   if (!NeedVXRMChange) {
421*5f757f3fSDimitry Andric     BlockInfo.clear();
422*5f757f3fSDimitry Andric     return false;
423*5f757f3fSDimitry Andric   }
424*5f757f3fSDimitry Andric 
425*5f757f3fSDimitry Andric   // Phase 2 - Compute available VXRM using a forward walk.
426*5f757f3fSDimitry Andric   for (const MachineBasicBlock &MBB : MF) {
427*5f757f3fSDimitry Andric     WorkList.push(&MBB);
428*5f757f3fSDimitry Andric     BlockInfo[MBB.getNumber()].InQueue = true;
429*5f757f3fSDimitry Andric   }
430*5f757f3fSDimitry Andric   while (!WorkList.empty()) {
431*5f757f3fSDimitry Andric     const MachineBasicBlock &MBB = *WorkList.front();
432*5f757f3fSDimitry Andric     WorkList.pop();
433*5f757f3fSDimitry Andric     computeAvailable(MBB);
434*5f757f3fSDimitry Andric   }
435*5f757f3fSDimitry Andric 
436*5f757f3fSDimitry Andric   // Phase 3 - Compute anticipated VXRM using a backwards walk.
437*5f757f3fSDimitry Andric   for (const MachineBasicBlock &MBB : llvm::reverse(MF)) {
438*5f757f3fSDimitry Andric     WorkList.push(&MBB);
439*5f757f3fSDimitry Andric     BlockInfo[MBB.getNumber()].InQueue = true;
440*5f757f3fSDimitry Andric   }
441*5f757f3fSDimitry Andric   while (!WorkList.empty()) {
442*5f757f3fSDimitry Andric     const MachineBasicBlock &MBB = *WorkList.front();
443*5f757f3fSDimitry Andric     WorkList.pop();
444*5f757f3fSDimitry Andric     computeAnticipated(MBB);
445*5f757f3fSDimitry Andric   }
446*5f757f3fSDimitry Andric 
447*5f757f3fSDimitry Andric   // Phase 4 - Emit VXRM writes at the earliest place possible.
448*5f757f3fSDimitry Andric   for (MachineBasicBlock &MBB : MF)
449*5f757f3fSDimitry Andric     emitWriteVXRM(MBB);
450*5f757f3fSDimitry Andric 
451*5f757f3fSDimitry Andric   BlockInfo.clear();
452*5f757f3fSDimitry Andric 
453*5f757f3fSDimitry Andric   return true;
454*5f757f3fSDimitry Andric }
455*5f757f3fSDimitry Andric 
456*5f757f3fSDimitry Andric FunctionPass *llvm::createRISCVInsertWriteVXRMPass() {
457*5f757f3fSDimitry Andric   return new RISCVInsertWriteVXRM();
458*5f757f3fSDimitry Andric }
459