LLVM 24.0.0git
RISCVVMV0Elimination.cpp
Go to the documentation of this file.
1//===- RISCVVMV0Elimination.cpp - VMV0 Elimination -----------------------===//
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// Mask operands in vector pseudos have to be in v0. We select them as a virtual
10// register in the singleton vmv0 register class instead of copying them to $v0
11// straight away, to make optimizing masks easier.
12//
13// However register coalescing may end up coleascing copies into vmv0, resulting
14// in instructions with multiple uses of vmv0 that the register allocator can't
15// allocate:
16//
17// %x:vrnov0 = PseudoVADD_VV_M1_MASK %0:vrnov0, %1:vr, %2:vmv0, %3:vmv0, ...
18//
19// To avoid this, this pass replaces any uses* of vmv0 with copies to $v0 before
20// register coalescing and allocation:
21//
22// %x:vrnov0 = PseudoVADD_VV_M1_MASK %0:vrnov0, %1:vr, %2:vr, %3:vmv0, ...
23// ->
24// $v0 = COPY %3:vr
25// %x:vrnov0 = PseudoVADD_VV_M1_MASK %0:vrnov0, %1:vr, %2:vr, $0, ...
26//
27// * The only uses of vmv0 left behind are when used for inline asm with the vm
28// constraint.
29//
30//===---------------------------------------------------------------------===//
31
32#include "RISCV.h"
33#include "RISCVSubtarget.h"
36#include "llvm/IR/Analysis.h"
37#ifndef NDEBUG
39#endif
41
42using namespace llvm;
43
44#define DEBUG_TYPE "riscv-vmv0-elimination"
45
46namespace {
47
48class RISCVVMV0EliminationLegacy : public MachineFunctionPass {
49public:
50 static char ID;
51 RISCVVMV0EliminationLegacy() : MachineFunctionPass(ID) {}
52
53 bool runOnMachineFunction(MachineFunction &MF) override;
54
55 void getAnalysisUsage(AnalysisUsage &AU) const override {
56 AU.setPreservesCFG();
58 }
59
60 MachineFunctionProperties getRequiredProperties() const override {
61 // TODO: We could move this closer to regalloc, out of SSA, which would
62 // allow scheduling past mask operands. We would need to preserve live
63 // intervals.
64 return MachineFunctionProperties().setIsSSA();
65 }
66};
67
68} // namespace
69
70char RISCVVMV0EliminationLegacy::ID = 0;
71
72INITIALIZE_PASS(RISCVVMV0EliminationLegacy, DEBUG_TYPE,
73 "RISC-V VMV0 Elimination", false, false)
74
76 return new RISCVVMV0EliminationLegacy();
77}
78
79static bool isVMV0(const MCOperandInfo &MCOI) {
80 return MCOI.RegClass == RISCV::VMV0RegClassID;
81}
82
84 // Skip if the vector extension is not enabled.
86 if (!ST->hasVInstructions())
87 return false;
88
90 const TargetInstrInfo *TII = ST->getInstrInfo();
91
92#ifndef NDEBUG
93 // Assert that we won't clobber any existing reads of v0 where we need to
94 // insert copies.
95 const TargetRegisterInfo *TRI = MRI.getTargetRegisterInfo();
97 for (MachineBasicBlock *MBB : RPOT) {
98 bool V0Clobbered = false;
99 for (MachineInstr &MI : *MBB) {
100 assert(!(MI.readsRegister(RISCV::V0, TRI) && V0Clobbered) &&
101 "Inserting a copy to v0 would clobber a read");
102 if (MI.modifiesRegister(RISCV::V0, TRI))
103 V0Clobbered = false;
104
105 if (any_of(MI.getDesc().operands(), isVMV0))
106 V0Clobbered = true;
107 }
108
109 assert(!(V0Clobbered &&
110 any_of(MBB->successors(),
111 [](auto *Succ) { return Succ->isLiveIn(RISCV::V0); })) &&
112 "Clobbered a v0 used in a successor");
113 }
114#endif
115
116 bool MadeChange = false;
118
119 // For any instruction with a vmv0 operand, replace it with a copy to v0.
120 for (MachineBasicBlock &MBB : MF) {
121 for (MachineInstr &MI : MBB) {
122 assert(count_if(MI.getDesc().operands(), isVMV0) < 2 &&
123 "Expected only one or zero vmv0 operands");
124
125 for (auto [OpNo, MCOI] : enumerate(MI.getDesc().operands())) {
126 if (isVMV0(MCOI)) {
127 MachineOperand &MO = MI.getOperand(OpNo);
128 Register Src = MO.getReg();
129 assert(MO.isUse() && MO.getSubReg() == RISCV::NoSubRegister &&
130 Src.isVirtual() && "vmv0 use in unexpected form");
131
132 // Peek through a single copy to match what isel does.
133 if (MachineInstr *SrcMI = MRI.getVRegDef(Src);
134 SrcMI->isCopy() && SrcMI->getOperand(1).getReg().isVirtual() &&
135 SrcMI->getOperand(1).getSubReg() == RISCV::NoSubRegister) {
136 // Delete any dead copys to vmv0 to avoid allocating them.
137 if (MRI.hasOneNonDBGUse(Src))
138 DeadCopies.push_back(SrcMI);
139 Src = SrcMI->getOperand(1).getReg();
140 }
141
142 BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(RISCV::COPY), RISCV::V0)
143 .addReg(Src);
144
145 MO.setReg(RISCV::V0);
146 MadeChange = true;
147 break;
148 }
149 }
150 }
151 }
152
153 for (MachineInstr *MI : DeadCopies)
154 MI->eraseFromParent();
155
156 if (!MadeChange)
157 return false;
158
159 // Now that any constraints requiring vmv0 are gone, eliminate any uses of
160 // vmv0 by recomputing the reg class.
161 // The only remaining uses should be around inline asm.
162 for (MachineBasicBlock &MBB : MF) {
163 for (MachineInstr &MI : MBB) {
164 for (MachineOperand &MO : MI.uses()) {
165 if (MO.isReg() && MO.getReg().isVirtual() &&
166 MRI.getRegClass(MO.getReg()) == &RISCV::VMV0RegClass) {
167 MRI.recomputeRegClass(MO.getReg());
168 assert((MRI.getRegClass(MO.getReg()) != &RISCV::VMV0RegClass ||
169 MI.isInlineAsm() ||
170 MRI.getVRegDef(MO.getReg())->isInlineAsm()) &&
171 "Non-inline-asm use of vmv0 left behind");
172 }
173 }
174 }
175 }
176
177 return true;
178}
179
180bool RISCVVMV0EliminationLegacy::runOnMachineFunction(MachineFunction &MF) {
181 return runVMV0Elimination(MF);
182}
183
184PreservedAnalyses
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock & MBB
#define DEBUG_TYPE
const HexagonInstrInfo * TII
#define _
IRTranslator LLVM IR MI
Register const TargetRegisterInfo * TRI
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
This file builds on the ADT/GraphTraits.h file to build a generic graph post order iterator.
MachineRegisterInfo & MRI
static bool runVMV0Elimination(MachineFunction &MF)
static bool isVMV0(const MCOperandInfo &MCOI)
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: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
This holds information about one operand of a machine instruction, indicating the register class for ...
Definition MCInstrDesc.h:88
An RAII based helper class to modify MachineFunctionProperties when running pass.
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.
Properties which a MachineFunction may have at a given point in time.
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.
Representation of each machine instruction.
MachineOperand class - Representation of each machine instruction operand.
unsigned getSubReg() const
LLVM_ABI void setReg(Register Reg)
Change the register this operand corresponds to.
Register getReg() const
getReg - Returns the register number.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
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)
Wrapper class representing virtual and physical registers.
Definition Register.h:20
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
TargetInstrInfo - Interface to description of machine instruction set.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
Pass manager infrastructure for declaring and invalidating analyses.
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.
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
Definition STLExtras.h:2570
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1762
FunctionPass * createRISCVVMV0EliminationLegacyPass()
auto count_if(R &&Range, UnaryPredicate P)
Wrapper function around std::count_if to count the number of times an element satisfying a given pred...
Definition STLExtras.h:2035