LLVM 24.0.0git
RISCVInsertWriteVXRM.cpp
Go to the documentation of this file.
1//===-- RISCVInsertWriteVXRM.cpp - Insert Write of RISC-V VXRM 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//
9// This pass inserts writes to the VXRM CSR as needed by vector instructions.
10// Each instruction that uses VXRM carries an operand that contains its required
11// VXRM value. This pass tries to optimize placement to avoid redundant writes
12// to VXRM.
13//
14// This is done using 2 dataflow algorithms. The first is a forward data flow
15// to calculate where a VXRM value is available. The second is a backwards
16// dataflow to determine where a VXRM value is anticipated.
17//
18// Finally, we use the results of these two dataflows to insert VXRM writes
19// where a value is anticipated, but not available.
20//
21// FIXME: This pass does not split critical edges, so there can still be some
22// redundancy.
23//
24// FIXME: If we are willing to have writes that aren't always needed, we could
25// reduce the number of VXRM writes in some cases.
26//===----------------------------------------------------------------------===//
27
29#include "RISCV.h"
30#include "RISCVSubtarget.h"
35#include "llvm/IR/Analysis.h"
36#include <queue>
37
38using namespace llvm;
39
40#define DEBUG_TYPE "riscv-insert-write-vxrm"
41#define RISCV_INSERT_WRITE_VXRM_NAME "RISC-V Insert Write VXRM Pass"
42
43namespace {
44
45class VXRMInfo {
46 uint8_t VXRMImm = 0;
47
48 enum : uint8_t {
50 Static,
51 Unknown,
52 } State = Uninitialized;
53
54public:
55 VXRMInfo() = default;
56
57 static VXRMInfo getUnknown() {
58 VXRMInfo Info;
59 Info.setUnknown();
60 return Info;
61 }
62
63 bool isValid() const { return State != Uninitialized; }
64 void setUnknown() { State = Unknown; }
65 bool isUnknown() const { return State == Unknown; }
66
67 bool isStatic() const { return State == Static; }
68
69 void setVXRMImm(unsigned Imm) {
70 assert(Imm <= 3 && "Unexpected VXRM value");
71 VXRMImm = Imm;
72 State = Static;
73 }
74 unsigned getVXRMImm() const {
75 assert(isStatic() && VXRMImm <= 3 && "Unexpected state");
76 return VXRMImm;
77 }
78
79 bool operator==(const VXRMInfo &Other) const {
80 // Uninitialized is only equal to another Uninitialized.
81 if (State != Other.State)
82 return false;
83
84 if (isStatic())
85 return VXRMImm == Other.VXRMImm;
86
87 assert((isValid() || isUnknown()) && "Unexpected state");
88 return true;
89 }
90
91 bool operator!=(const VXRMInfo &Other) const { return !(*this == Other); }
92
93 // Calculate the VXRMInfo visible to a block assuming this and Other are
94 // both predecessors.
95 VXRMInfo intersect(const VXRMInfo &Other) const {
96 // If the new value isn't valid, ignore it.
97 if (!Other.isValid())
98 return *this;
99
100 // If this value isn't valid, this must be the first predecessor, use it.
101 if (!isValid())
102 return Other;
103
104 // If either is unknown, the result is unknown.
105 if (isUnknown() || Other.isUnknown())
106 return VXRMInfo::getUnknown();
107
108 // If we have an exact match, return this.
109 if (*this == Other)
110 return *this;
111
112 // Otherwise the result is unknown.
113 return VXRMInfo::getUnknown();
114 }
115
116 // Calculate the VXRMInfo visible to a block assuming this and Other
117 // are both predecessors. To allow speculatively running WriteVXRM
118 // we will ignore Unknowns if one of this and Other have valid
119 // WriteVXRM. Rationale: WriteVXRM causes a pipeline flush in some
120 // uarchs and moving it outside loops is very important for some
121 // workloads.
122 VXRMInfo intersectAnticipated(const VXRMInfo &Other) const {
123 // If the new value isn't valid, ignore it.
124 if (!Other.isValid())
125 return *this;
126
127 // If this value isn't valid, this must be the first predecessor, use it.
128 if (!isValid())
129 return Other;
130
131 // If either is unknown, the result is the other one.
132 if (isUnknown())
133 return Other;
134 if (Other.isUnknown())
135 return *this;
136
137 // If we have an exact match, return this.
138 if (*this == Other)
139 return *this;
140
141 // Otherwise the result is unknown.
142 return VXRMInfo::getUnknown();
143 }
144
145#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
146 /// Support for debugging, callable in GDB: V->dump()
147 LLVM_DUMP_METHOD void dump() const {
148 print(dbgs());
149 dbgs() << "\n";
150 }
151
152 void print(raw_ostream &OS) const {
153 OS << '{';
154 if (!isValid())
155 OS << "Uninitialized";
156 else if (isUnknown())
157 OS << "Unknown";
158 else
159 OS << getVXRMImm();
160 OS << '}';
161 }
162#endif
163};
164
165#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
167inline raw_ostream &operator<<(raw_ostream &OS, const VXRMInfo &V) {
168 V.print(OS);
169 return OS;
170}
171#endif
172
173struct BlockData {
174 // Indicates if the block uses VXRM. Uninitialized means no use.
175 VXRMInfo VXRMUse;
176
177 // Indicates the VXRM output from the block. Uninitialized means transparent.
178 VXRMInfo VXRMOut;
179
180 // Keeps track of the available VXRM value at the start of the basic block.
181 VXRMInfo AvailableIn;
182
183 // Keeps track of the available VXRM value at the end of the basic block.
184 VXRMInfo AvailableOut;
185
186 // Keeps track of what VXRM is anticipated at the start of the basic block.
187 VXRMInfo AnticipatedIn;
188
189 // Keeps track of what VXRM is anticipated at the end of the basic block.
190 VXRMInfo AnticipatedOut;
191
192 // Keeps track of whether the block is already in the queue.
193 bool InQueue;
194
195 BlockData() = default;
196};
197
198class RISCVInsertWriteVXRMImpl {
199 const TargetInstrInfo *TII;
200 const MachineLoopInfo *MLI;
201
202 std::vector<BlockData> BlockInfo;
203 std::queue<const MachineBasicBlock *> WorkList;
204
205 bool computeVXRMChanges(const MachineBasicBlock &MBB);
206 void computeAvailable(const MachineBasicBlock &MBB);
207 void computeAnticipated(const MachineFunction &MF,
208 const MachineBasicBlock &MBB);
209 void emitWriteVXRM(MachineBasicBlock &MBB);
210
211public:
212 bool runOnMachineFunction(MachineFunction &MF,
213 function_ref<MachineLoopInfo *()> GetMLI);
214};
215
216class RISCVInsertWriteVXRMLegacy : public MachineFunctionPass {
217public:
218 static char ID;
219
220 RISCVInsertWriteVXRMLegacy() : MachineFunctionPass(ID) {}
221
222 bool runOnMachineFunction(MachineFunction &MF) override;
223
224 void getAnalysisUsage(AnalysisUsage &AU) const override {
225 AU.setPreservesCFG();
228 }
229
230 StringRef getPassName() const override {
232 }
233};
234
235} // end anonymous namespace
236
237char RISCVInsertWriteVXRMLegacy::ID = 0;
238
239INITIALIZE_PASS(RISCVInsertWriteVXRMLegacy, DEBUG_TYPE,
240 RISCV_INSERT_WRITE_VXRM_NAME, false, false)
241
242bool RISCVInsertWriteVXRMImpl::computeVXRMChanges(
244 BlockData &BBInfo = BlockInfo[MBB.getNumber()];
245
246 bool NeedVXRMWrite = false;
247 for (const MachineInstr &MI : MBB) {
248 int VXRMIdx = RISCVII::getVXRMOpNum(MI.getDesc());
249 if (VXRMIdx >= 0 && !RISCVInstrInfo::ignoresVXRM(MI)) {
250 unsigned NewVXRMImm = MI.getOperand(VXRMIdx).getImm();
251
252 if (!BBInfo.VXRMUse.isValid())
253 BBInfo.VXRMUse.setVXRMImm(NewVXRMImm);
254
255 BBInfo.VXRMOut.setVXRMImm(NewVXRMImm);
256 NeedVXRMWrite = true;
257 continue;
258 }
259
260 if (MI.isCall() || MI.isInlineAsm() ||
261 MI.modifiesRegister(RISCV::VXRM, /*TRI=*/nullptr)) {
262 if (!BBInfo.VXRMUse.isValid())
263 BBInfo.VXRMUse.setUnknown();
264
265 BBInfo.VXRMOut.setUnknown();
266 }
267 }
268
269 return NeedVXRMWrite;
270}
271
272void RISCVInsertWriteVXRMImpl::computeAvailable(const MachineBasicBlock &MBB) {
273 BlockData &BBInfo = BlockInfo[MBB.getNumber()];
274
275 BBInfo.InQueue = false;
276
277 VXRMInfo Available;
278 if (MBB.pred_empty()) {
279 Available.setUnknown();
280 } else {
281 for (const MachineBasicBlock *P : MBB.predecessors())
282 Available = Available.intersect(BlockInfo[P->getNumber()].AvailableOut);
283 }
284
285 // If we don't have any valid available info, wait until we do.
286 if (!Available.isValid())
287 return;
288
289 if (Available != BBInfo.AvailableIn) {
290 BBInfo.AvailableIn = Available;
291 LLVM_DEBUG(dbgs() << "AvailableIn state of " << printMBBReference(MBB)
292 << " changed to " << BBInfo.AvailableIn << "\n");
293 }
294
295 if (BBInfo.VXRMOut.isValid())
296 Available = BBInfo.VXRMOut;
297
298 if (Available == BBInfo.AvailableOut)
299 return;
300
301 BBInfo.AvailableOut = Available;
302 LLVM_DEBUG(dbgs() << "AvailableOut state of " << printMBBReference(MBB)
303 << " changed to " << BBInfo.AvailableOut << "\n");
304
305 // Add the successors to the work list so that we can propagate.
306 for (MachineBasicBlock *S : MBB.successors()) {
307 if (!BlockInfo[S->getNumber()].InQueue) {
308 BlockInfo[S->getNumber()].InQueue = true;
309 WorkList.push(S);
310 }
311 }
312}
313
314void RISCVInsertWriteVXRMImpl::computeAnticipated(
315 const MachineFunction &MF, const MachineBasicBlock &MBB) {
316 BlockData &BBInfo = BlockInfo[MBB.getNumber()];
317 const RISCVSubtarget &ST = MF.getSubtarget<RISCVSubtarget>();
318
319 BBInfo.InQueue = false;
320
321 VXRMInfo Anticipated;
322 if (MBB.succ_empty()) {
323 Anticipated.setUnknown();
324 } else {
325 // If VXRM writes are expensive, speculate a write into successors that
326 // don't need it, but only within a loop so that the write can be hoisted
327 // out of the loop. Elsewhere this would just add writes to paths that
328 // don't use VXRM.
329 bool Speculate =
330 ST.hasVXRMPipelineFlush() && (!MLI || MLI->getLoopFor(&MBB));
331 for (const MachineBasicBlock *S : MBB.successors())
332 if (Speculate)
333 Anticipated =
334 Anticipated.intersectAnticipated(BlockInfo[S->getNumber()].AnticipatedIn);
335 else
336 Anticipated =
337 Anticipated.intersect(BlockInfo[S->getNumber()].AnticipatedIn);
338 }
339
340 // If we don't have any valid anticipated info, wait until we do.
341 if (!Anticipated.isValid())
342 return;
343
344 if (Anticipated != BBInfo.AnticipatedOut) {
345 BBInfo.AnticipatedOut = Anticipated;
346 LLVM_DEBUG(dbgs() << "AnticipatedOut state of " << printMBBReference(MBB)
347 << " changed to " << BBInfo.AnticipatedOut << "\n");
348 }
349
350 // If this block reads VXRM, copy it.
351 if (BBInfo.VXRMUse.isValid())
352 Anticipated = BBInfo.VXRMUse;
353
354 if (Anticipated == BBInfo.AnticipatedIn)
355 return;
356
357 BBInfo.AnticipatedIn = Anticipated;
358 LLVM_DEBUG(dbgs() << "AnticipatedIn state of " << printMBBReference(MBB)
359 << " changed to " << BBInfo.AnticipatedIn << "\n");
360
361 // Add the predecessors to the work list so that we can propagate.
362 for (MachineBasicBlock *P : MBB.predecessors()) {
363 if (!BlockInfo[P->getNumber()].InQueue) {
364 BlockInfo[P->getNumber()].InQueue = true;
365 WorkList.push(P);
366 }
367 }
368}
369
370void RISCVInsertWriteVXRMImpl::emitWriteVXRM(MachineBasicBlock &MBB) {
371 const BlockData &BBInfo = BlockInfo[MBB.getNumber()];
372
373 VXRMInfo Info = BBInfo.AvailableIn;
374
375 // Flag to indicates we need to insert a VXRM write. We want to delay it as
376 // late as possible in this block.
377 bool PendingInsert = false;
378
379 // Insert VXRM write if anticipated and not available.
380 if (BBInfo.AnticipatedIn.isStatic()) {
381 // If this is the entry block and the value is anticipated, insert.
382 if (MBB.isEntryBlock()) {
383 PendingInsert = true;
384 } else {
385 // Search for any predecessors that wouldn't satisfy our requirement and
386 // insert a write VXRM if needed.
387 // NOTE: If one predecessor is able to provide the requirement, but
388 // another isn't, it means we have a critical edge. The better placement
389 // would be to split the critical edge.
390 for (MachineBasicBlock *P : MBB.predecessors()) {
391 const BlockData &PInfo = BlockInfo[P->getNumber()];
392 // If it's available out of the predecessor, then we're ok.
393 if (PInfo.AvailableOut.isStatic() &&
394 PInfo.AvailableOut.getVXRMImm() ==
395 BBInfo.AnticipatedIn.getVXRMImm())
396 continue;
397 // If the predecessor anticipates this value for all its successors,
398 // then a write to VXRM would have already occurred before this block is
399 // executed.
400 if (PInfo.AnticipatedOut.isStatic() &&
401 PInfo.AnticipatedOut.getVXRMImm() ==
402 BBInfo.AnticipatedIn.getVXRMImm())
403 continue;
404 PendingInsert = true;
405 break;
406 }
407 }
408
409 Info = BBInfo.AnticipatedIn;
410 }
411
412 for (MachineInstr &MI : MBB) {
413 int VXRMIdx = RISCVII::getVXRMOpNum(MI.getDesc());
414 if (VXRMIdx >= 0 && !RISCVInstrInfo::ignoresVXRM(MI)) {
415 unsigned NewVXRMImm = MI.getOperand(VXRMIdx).getImm();
416
417 if (PendingInsert || !Info.isStatic() ||
418 Info.getVXRMImm() != NewVXRMImm) {
419 assert((!PendingInsert ||
420 (Info.isStatic() && Info.getVXRMImm() == NewVXRMImm)) &&
421 "Pending VXRM insertion mismatch");
422 LLVM_DEBUG(dbgs() << "Inserting before "; MI.print(dbgs()));
423 BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(RISCV::WriteVXRMImm))
424 .addImm(NewVXRMImm);
425 PendingInsert = false;
426 }
427
428 MI.addOperand(MachineOperand::CreateReg(RISCV::VXRM, /*IsDef*/ false,
429 /*IsImp*/ true));
430 Info.setVXRMImm(NewVXRMImm);
431 continue;
432 }
433
434 if (MI.isCall() || MI.isInlineAsm() ||
435 MI.modifiesRegister(RISCV::VXRM, /*TRI=*/nullptr))
436 Info.setUnknown();
437 }
438
439 // If all our successors anticipate a value, do the insert.
440 // NOTE: It's possible that not all predecessors of our successor provide the
441 // correct value. This can occur on critical edges. If we don't split the
442 // critical edge we'll also have a write vxrm in the successor that is
443 // redundant with this one.
444 if (PendingInsert ||
445 (BBInfo.AnticipatedOut.isStatic() &&
446 (!Info.isStatic() ||
447 Info.getVXRMImm() != BBInfo.AnticipatedOut.getVXRMImm()))) {
448 assert((!PendingInsert ||
449 (Info.isStatic() && BBInfo.AnticipatedOut.isStatic() &&
450 Info.getVXRMImm() == BBInfo.AnticipatedOut.getVXRMImm())) &&
451 "Pending VXRM insertion mismatch");
452 LLVM_DEBUG(dbgs() << "Inserting at end of " << printMBBReference(MBB)
453 << " changing to " << BBInfo.AnticipatedOut << "\n");
455 TII->get(RISCV::WriteVXRMImm))
456 .addImm(BBInfo.AnticipatedOut.getVXRMImm());
457 }
458}
459
460bool RISCVInsertWriteVXRMImpl::runOnMachineFunction(
461 MachineFunction &MF, function_ref<MachineLoopInfo *()> GetMLI) {
462 // Skip if the vector extension is not enabled.
463 const RISCVSubtarget &ST = MF.getSubtarget<RISCVSubtarget>();
464 if (!ST.hasVInstructions())
465 return false;
466
467 TII = ST.getInstrInfo();
468 // Loop info is used to limit speculation of VXRM writes. It's available in
469 // optimized pipelines; without it, speculate everywhere.
470 MLI = GetMLI();
471
472 assert(BlockInfo.empty() && "Expect empty block infos");
473 BlockInfo.resize(MF.getNumBlockIDs());
474
475 // Phase 1 - collect block information.
476 bool NeedVXRMChange = false;
477 for (const MachineBasicBlock &MBB : MF)
478 NeedVXRMChange |= computeVXRMChanges(MBB);
479
480 if (!NeedVXRMChange) {
481 BlockInfo.clear();
482 return false;
483 }
484
485 // Phase 2 - Compute available VXRM using a forward walk.
486 for (const MachineBasicBlock &MBB : MF) {
487 WorkList.push(&MBB);
488 BlockInfo[MBB.getNumber()].InQueue = true;
489 }
490 while (!WorkList.empty()) {
491 const MachineBasicBlock &MBB = *WorkList.front();
492 WorkList.pop();
493 computeAvailable(MBB);
494 }
495
496 // Phase 3 - Compute anticipated VXRM using a backwards walk.
497 for (const MachineBasicBlock &MBB : llvm::reverse(MF)) {
498 WorkList.push(&MBB);
499 BlockInfo[MBB.getNumber()].InQueue = true;
500 }
501 while (!WorkList.empty()) {
502 const MachineBasicBlock &MBB = *WorkList.front();
503 WorkList.pop();
504 computeAnticipated(MF, MBB);
505 }
506
507 // Phase 4 - Emit VXRM writes at the earliest place possible.
508 for (MachineBasicBlock &MBB : MF)
509 emitWriteVXRM(MBB);
510
511 BlockInfo.clear();
512
513 return true;
514}
515
517 return new RISCVInsertWriteVXRMLegacy();
518}
519
520bool RISCVInsertWriteVXRMLegacy::runOnMachineFunction(MachineFunction &MF) {
521 RISCVInsertWriteVXRMImpl Impl;
522 return Impl.runOnMachineFunction(MF, [&]() {
523 auto *MLIWrapper = getAnalysisIfAvailable<MachineLoopInfoWrapperPass>();
524 return MLIWrapper ? &MLIWrapper->getLI() : nullptr;
525 });
526}
527
528PreservedAnalyses
531 RISCVInsertWriteVXRMImpl Impl;
532 bool Changed = Impl.runOnMachineFunction(
533 MF, [&]() { return &MFAM.getResult<MachineLoopAnalysis>(MF); });
537}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
aarch64 promote const
uint64_t Imm
MachineBasicBlock & MBB
#define LLVM_ATTRIBUTE_USED
Definition Compiler.h:234
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
Definition Compiler.h:690
@ Available
We know the block is fully available. This is a fixpoint.
Definition GVN.cpp:1233
#define DEBUG_TYPE
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
static Interval intersect(const Interval &I1, const Interval &I2)
#define P(N)
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
#define RISCV_INSERT_WRITE_VXRM_NAME
static bool isValid(const char C)
Returns true if C is a valid mangled character: <0-9a-zA-Z_>.
#define LLVM_DEBUG(...)
Definition Debug.h:119
BlockData()=default
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Represent the analysis usage information of a pass.
AnalysisUsage & addUsedIfAvailable()
Add the specified Pass class to the set of analyses used by this pass.
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
Definition Pass.cpp:280
Represents analyses that only rely on functions' control flow.
Definition Analysis.h:73
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:312
LoopT * getLoopFor(const BlockT *BB) const
Return the inner most loop that BB lives in.
int getNumber() const
MachineBasicBlocks are uniquely numbered at the function level, unless they're not in a MachineFuncti...
LLVM_ABI iterator getFirstTerminator()
Returns an iterator to the first terminator instruction of this basic block.
LLVM_ABI bool isEntryBlock() const
Returns true if this is the entry block of the function.
iterator_range< succ_iterator > successors()
iterator_range< pred_iterator > predecessors()
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.
unsigned getNumBlockIDs() const
getNumBlockIDs - Return the number of MBB ID's allocated.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
Representation of each machine instruction.
Analysis pass that exposes the MachineLoopInfo for a machine function.
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)
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
Definition Analysis.h:151
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
TargetInstrInfo - Interface to description of machine instruction set.
An efficient, type-erasing, non-owning reference to a callable.
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
Pass manager infrastructure for declaring and invalidating analyses.
static int getVXRMOpNum(const MCInstrDesc &Desc)
This is an optimization pass for GlobalISel generic memory operations.
void dump(const SparseBitVector< ElementSize > &LHS, raw_ostream &out)
Printable print(const GCNRegPressure &RP, const GCNSubtarget *ST=nullptr, unsigned DynamicVGPRBlockSize=0)
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
@ Unknown
Not known to have no common set bits.
@ Uninitialized
Definition Threading.h:60
bool operator!=(uint64_t V1, const APInt &V2)
Definition APInt.h:2139
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
bool operator==(const AddressRangeValuePair &LHS, const AddressRangeValuePair &RHS)
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
auto reverse(ContainerTy &&C)
Definition STLExtras.h:408
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
FunctionPass * createRISCVInsertWriteVXRMLegacyPass()
@ Other
Any other memory.
Definition ModRef.h:68
raw_ostream & operator<<(raw_ostream &OS, const APFixedPoint &FX)
LLVM_ABI Printable printMBBReference(const MachineBasicBlock &MBB)
Prints a machine basic block reference.