1 //===---------- MIRVRegNamerUtils.cpp - MIR VReg Renaming Utilities -------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "MIRVRegNamerUtils.h"
10 #include "llvm/Support/Debug.h"
14 #define DEBUG_TYPE "mir-vregnamer-utils"
18 // TypedVReg and VRType are used to tell the renamer what to do at points in a
19 // sequence of values to be renamed. A TypedVReg can either contain
20 // an actual VReg, a FrameIndex, or it could just be a barrier for the next
21 // candidate (side-effecting instruction). This tells the renamer to increment
22 // to the next vreg name, or to skip modulo some skip-gap value.
23 enum VRType
{ RSE_Reg
= 0, RSE_FrameIndex
, RSE_NewCandidate
};
29 TypedVReg(Register Reg
) : Type(RSE_Reg
), Reg(Reg
) {}
30 TypedVReg(VRType Type
) : Type(Type
), Reg(~0U) {
31 assert(Type
!= RSE_Reg
&& "Expected a non-Register Type.");
34 bool isReg() const { return Type
== RSE_Reg
; }
35 bool isFrameIndex() const { return Type
== RSE_FrameIndex
; }
36 bool isCandidate() const { return Type
== RSE_NewCandidate
; }
38 VRType
getType() const { return Type
; }
39 Register
getReg() const {
40 assert(this->isReg() && "Expected a virtual or physical Register.");
45 /// Here we find our candidates. What makes an interesting candidate?
46 /// A candidate for a canonicalization tree root is normally any kind of
47 /// instruction that causes side effects such as a store to memory or a copy to
48 /// a physical register or a return instruction. We use these as an expression
49 /// tree root that we walk in order to build a canonical walk which should
50 /// result in canonical vreg renaming.
51 std::vector
<MachineInstr
*> populateCandidates(MachineBasicBlock
*MBB
) {
52 std::vector
<MachineInstr
*> Candidates
;
53 MachineRegisterInfo
&MRI
= MBB
->getParent()->getRegInfo();
55 for (auto II
= MBB
->begin(), IE
= MBB
->end(); II
!= IE
; ++II
) {
56 MachineInstr
*MI
= &*II
;
58 bool DoesMISideEffect
= false;
60 if (MI
->getNumOperands() > 0 && MI
->getOperand(0).isReg()) {
61 const Register Dst
= MI
->getOperand(0).getReg();
62 DoesMISideEffect
|= !Register::isVirtualRegister(Dst
);
64 for (auto UI
= MRI
.use_begin(Dst
); UI
!= MRI
.use_end(); ++UI
) {
67 DoesMISideEffect
|= (UI
->getParent()->getParent() != MI
->getParent());
71 if (!MI
->mayStore() && !MI
->isBranch() && !DoesMISideEffect
)
74 LLVM_DEBUG(dbgs() << "Found Candidate: "; MI
->dump(););
75 Candidates
.push_back(MI
);
81 void doCandidateWalk(std::vector
<TypedVReg
> &VRegs
,
82 std::queue
<TypedVReg
> &RegQueue
,
83 std::vector
<MachineInstr
*> &VisitedMIs
,
84 const MachineBasicBlock
*MBB
) {
86 const MachineFunction
&MF
= *MBB
->getParent();
87 const MachineRegisterInfo
&MRI
= MF
.getRegInfo();
89 while (!RegQueue
.empty()) {
91 auto TReg
= RegQueue
.front();
94 if (TReg
.isFrameIndex()) {
95 LLVM_DEBUG(dbgs() << "Popping frame index.\n";);
96 VRegs
.push_back(TypedVReg(RSE_FrameIndex
));
100 assert(TReg
.isReg() && "Expected vreg or physreg.");
101 Register Reg
= TReg
.getReg();
103 if (Register::isVirtualRegister(Reg
)) {
105 dbgs() << "Popping vreg ";
106 MRI
.def_begin(Reg
)->dump();
110 if (!llvm::any_of(VRegs
, [&](const TypedVReg
&TR
) {
111 return TR
.isReg() && TR
.getReg() == Reg
;
113 VRegs
.push_back(TypedVReg(Reg
));
116 LLVM_DEBUG(dbgs() << "Popping physreg.\n";);
117 VRegs
.push_back(TypedVReg(Reg
));
121 for (auto RI
= MRI
.def_begin(Reg
), RE
= MRI
.def_end(); RI
!= RE
; ++RI
) {
122 MachineInstr
*Def
= RI
->getParent();
124 if (Def
->getParent() != MBB
)
127 if (llvm::any_of(VisitedMIs
,
128 [&](const MachineInstr
*VMI
) { return Def
== VMI
; })) {
133 dbgs() << "\n========================\n";
134 dbgs() << "Visited MI: ";
136 dbgs() << "BB Name: " << Def
->getParent()->getName() << "\n";
137 dbgs() << "\n========================\n";
139 VisitedMIs
.push_back(Def
);
140 for (unsigned I
= 1, E
= Def
->getNumOperands(); I
!= E
; ++I
) {
142 MachineOperand
&MO
= Def
->getOperand(I
);
144 LLVM_DEBUG(dbgs() << "Pushing frame index.\n";);
145 RegQueue
.push(TypedVReg(RSE_FrameIndex
));
150 RegQueue
.push(TypedVReg(MO
.getReg()));
156 std::map
<unsigned, unsigned>
157 getVRegRenameMap(const std::vector
<TypedVReg
> &VRegs
,
158 const std::vector
<Register
> &renamedInOtherBB
,
159 MachineRegisterInfo
&MRI
, NamedVRegCursor
&NVC
) {
160 std::map
<unsigned, unsigned> VRegRenameMap
;
161 bool FirstCandidate
= true;
163 for (auto &vreg
: VRegs
) {
164 if (vreg
.isFrameIndex()) {
165 // We skip one vreg for any frame index because there is a good chance
166 // (especially when comparing SelectionDAG to GlobalISel generated MIR)
167 // that in the other file we are just getting an incoming vreg that comes
168 // from a copy from a frame index. So it's safe to skip by one.
169 unsigned LastRenameReg
= NVC
.incrementVirtualVReg();
171 LLVM_DEBUG(dbgs() << "Skipping rename for FI " << LastRenameReg
<< "\n";);
173 } else if (vreg
.isCandidate()) {
175 // After the first candidate, for every subsequent candidate, we skip mod
176 // 10 registers so that the candidates are more likely to start at the
177 // same vreg number making it more likely that the canonical walk from the
178 // candidate insruction. We don't need to skip from the first candidate of
179 // the BasicBlock because we already skip ahead several vregs for each BB.
180 unsigned LastRenameReg
= NVC
.getVirtualVReg();
182 NVC
.incrementVirtualVReg(LastRenameReg
% 10);
183 FirstCandidate
= false;
185 } else if (!Register::isVirtualRegister(vreg
.getReg())) {
186 unsigned LastRenameReg
= NVC
.incrementVirtualVReg();
189 dbgs() << "Skipping rename for Phys Reg " << LastRenameReg
<< "\n";
194 auto Reg
= vreg
.getReg();
195 if (llvm::find(renamedInOtherBB
, Reg
) != renamedInOtherBB
.end()) {
196 LLVM_DEBUG(dbgs() << "Vreg " << Reg
197 << " already renamed in other BB.\n";);
201 auto Rename
= NVC
.createVirtualRegister(Reg
);
203 if (VRegRenameMap
.find(Reg
) == VRegRenameMap
.end()) {
204 LLVM_DEBUG(dbgs() << "Mapping vreg ";);
205 if (MRI
.reg_begin(Reg
) != MRI
.reg_end()) {
206 LLVM_DEBUG(auto foo
= &*MRI
.reg_begin(Reg
); foo
->dump(););
208 LLVM_DEBUG(dbgs() << Reg
;);
210 LLVM_DEBUG(dbgs() << " to ";);
211 if (MRI
.reg_begin(Rename
) != MRI
.reg_end()) {
212 LLVM_DEBUG(auto foo
= &*MRI
.reg_begin(Rename
); foo
->dump(););
214 LLVM_DEBUG(dbgs() << Rename
;);
216 LLVM_DEBUG(dbgs() << "\n";);
218 VRegRenameMap
.insert(std::pair
<unsigned, unsigned>(Reg
, Rename
));
222 return VRegRenameMap
;
225 bool doVRegRenaming(std::vector
<Register
> &renamedInOtherBB
,
226 const std::map
<unsigned, unsigned> &VRegRenameMap
,
227 MachineRegisterInfo
&MRI
) {
228 bool Changed
= false;
229 for (auto I
= VRegRenameMap
.begin(), E
= VRegRenameMap
.end(); I
!= E
; ++I
) {
231 auto VReg
= I
->first
;
232 auto Rename
= I
->second
;
234 renamedInOtherBB
.push_back(Rename
);
236 std::vector
<MachineOperand
*> RenameMOs
;
237 for (auto &MO
: MRI
.reg_operands(VReg
)) {
238 RenameMOs
.push_back(&MO
);
241 for (auto *MO
: RenameMOs
) {
246 MO
->setIsKill(false);
253 bool renameVRegs(MachineBasicBlock
*MBB
,
254 std::vector
<Register
> &renamedInOtherBB
,
255 NamedVRegCursor
&NVC
) {
256 bool Changed
= false;
257 MachineFunction
&MF
= *MBB
->getParent();
258 MachineRegisterInfo
&MRI
= MF
.getRegInfo();
260 std::vector
<MachineInstr
*> Candidates
= populateCandidates(MBB
);
261 std::vector
<MachineInstr
*> VisitedMIs
;
262 llvm::copy(Candidates
, std::back_inserter(VisitedMIs
));
264 std::vector
<TypedVReg
> VRegs
;
265 for (auto candidate
: Candidates
) {
266 VRegs
.push_back(TypedVReg(RSE_NewCandidate
));
268 std::queue
<TypedVReg
> RegQueue
;
270 // Here we walk the vreg operands of a non-root node along our walk.
271 // The root nodes are the original candidates (stores normally).
272 // These are normally not the root nodes (except for the case of copies to
273 // physical registers).
274 for (unsigned i
= 1; i
< candidate
->getNumOperands(); i
++) {
275 if (candidate
->mayStore() || candidate
->isBranch())
278 MachineOperand
&MO
= candidate
->getOperand(i
);
279 if (!(MO
.isReg() && Register::isVirtualRegister(MO
.getReg())))
282 LLVM_DEBUG(dbgs() << "Enqueue register"; MO
.dump(); dbgs() << "\n";);
283 RegQueue
.push(TypedVReg(MO
.getReg()));
286 // Here we walk the root candidates. We start from the 0th operand because
287 // the root is normally a store to a vreg.
288 for (unsigned i
= 0; i
< candidate
->getNumOperands(); i
++) {
290 if (!candidate
->mayStore() && !candidate
->isBranch())
293 MachineOperand
&MO
= candidate
->getOperand(i
);
295 // TODO: Do we want to only add vregs here?
296 if (!MO
.isReg() && !MO
.isFI())
299 LLVM_DEBUG(dbgs() << "Enqueue Reg/FI"; MO
.dump(); dbgs() << "\n";);
301 RegQueue
.push(MO
.isReg() ? TypedVReg(MO
.getReg())
302 : TypedVReg(RSE_FrameIndex
));
305 doCandidateWalk(VRegs
, RegQueue
, VisitedMIs
, MBB
);
308 // If we have populated no vregs to rename then bail.
309 // The rest of this function does the vreg remaping.
310 if (VRegs
.size() == 0)
313 auto VRegRenameMap
= getVRegRenameMap(VRegs
, renamedInOtherBB
, MRI
, NVC
);
314 Changed
|= doVRegRenaming(renamedInOtherBB
, VRegRenameMap
, MRI
);
317 } // anonymous namespace
319 void NamedVRegCursor::skipVRegs() {
320 unsigned VRegGapIndex
= 1;
321 if (!virtualVRegNumber
) {
323 virtualVRegNumber
= MRI
.createIncompleteVirtualRegister();
325 const unsigned VR_GAP
= (++VRegGapIndex
* SkipGapSize
);
327 unsigned I
= virtualVRegNumber
;
328 const unsigned E
= (((I
+ VR_GAP
) / VR_GAP
) + 1) * VR_GAP
;
330 virtualVRegNumber
= E
;
333 unsigned NamedVRegCursor::createVirtualRegister(unsigned VReg
) {
334 if (!virtualVRegNumber
)
337 raw_string_ostream
OS(S
);
338 OS
<< "namedVReg" << (virtualVRegNumber
& ~0x80000000);
341 if (auto RC
= MRI
.getRegClassOrNull(VReg
))
342 return MRI
.createVirtualRegister(RC
, OS
.str());
343 return MRI
.createGenericVirtualRegister(MRI
.getType(VReg
), OS
.str());
346 bool NamedVRegCursor::renameVRegs(MachineBasicBlock
*MBB
) {
347 return ::renameVRegs(MBB
, RenamedInOtherBB
, *this);