1 //===---------- MIRVRegNamerUtils.cpp - MIR VReg Renaming Utilities -------===//
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 #include "MIRVRegNamerUtils.h"
10 #include "llvm/Support/Debug.h"
11 
12 using namespace llvm;
13 
14 #define DEBUG_TYPE "mir-vregnamer-utils"
15 
16 bool VRegRenamer::doVRegRenaming(
17     const std::map<unsigned, unsigned> &VRegRenameMap) {
18   bool Changed = false;
19   for (auto I = VRegRenameMap.begin(), E = VRegRenameMap.end(); I != E; ++I) {
20 
21     auto VReg = I->first;
22     auto Rename = I->second;
23 
24     std::vector<MachineOperand *> RenameMOs;
25     for (auto &MO : MRI.reg_operands(VReg)) {
26       RenameMOs.push_back(&MO);
27     }
28 
29     for (auto *MO : RenameMOs) {
30       Changed = true;
31       MO->setReg(Rename);
32 
33       if (!MO->isDef())
34         MO->setIsKill(false);
35     }
36   }
37 
38   return Changed;
39 }
40 
41 std::map<unsigned, unsigned>
42 VRegRenamer::getVRegRenameMap(const std::vector<NamedVReg> &VRegs) {
43   std::map<unsigned, unsigned> VRegRenameMap;
44 
45   std::map<std::string, unsigned> VRegNameCollisionMap;
46 
47   auto GetUniqueVRegName =
48       [&VRegNameCollisionMap](const NamedVReg &Reg) -> std::string {
49     auto It = VRegNameCollisionMap.find(Reg.getName());
50     unsigned Counter = 0;
51     if (It != VRegNameCollisionMap.end()) {
52       Counter = It->second;
53     }
54     ++Counter;
55     VRegNameCollisionMap[Reg.getName()] = Counter;
56     return Reg.getName() + "__" + std::to_string(Counter);
57   };
58 
59   for (auto &Vreg : VRegs) {
60     auto Reg = Vreg.getReg();
61     assert(Register::isVirtualRegister(Reg) &&
62            "Expecting Virtual Registers Only");
63     auto NewNameForReg = GetUniqueVRegName(Vreg);
64     auto Rename = createVirtualRegisterWithName(Reg, NewNameForReg);
65 
66     VRegRenameMap.insert(std::pair<unsigned, unsigned>(Reg, Rename));
67   }
68   return VRegRenameMap;
69 }
70 
71 std::string VRegRenamer::getInstructionOpcodeHash(MachineInstr &MI) {
72   std::string S;
73   raw_string_ostream OS(S);
74   auto HashOperand = [this](const MachineOperand &MO) -> unsigned {
75     if (MO.isImm())
76       return MO.getImm();
77     if (MO.isTargetIndex())
78       return MO.getOffset() | (MO.getTargetFlags() << 16);
79     if (MO.isReg()) {
80       return Register::isVirtualRegister(MO.getReg())
81                  ? MRI.getVRegDef(MO.getReg())->getOpcode()
82                  : (unsigned)MO.getReg();
83     }
84     // We could explicitly handle all the types of the MachineOperand,
85     // here but we can just return a common number until we find a
86     // compelling test case where this is bad. The only side effect here
87     // is contributing to a hash collission but there's enough information
88     // (Opcodes,other registers etc) that this will likely not be a problem.
89     return 0;
90   };
91   SmallVector<unsigned, 16> MIOperands;
92   MIOperands.push_back(MI.getOpcode());
93   for (auto &Op : MI.uses()) {
94     MIOperands.push_back(HashOperand(Op));
95   }
96   auto HashMI = hash_combine_range(MIOperands.begin(), MIOperands.end());
97   return std::to_string(HashMI).substr(0, 5);
98 }
99 
100 unsigned VRegRenamer::createVirtualRegister(unsigned VReg) {
101   return createVirtualRegisterWithName(
102       VReg, getInstructionOpcodeHash(*MRI.getVRegDef(VReg)));
103 }
104 
105 bool VRegRenamer::renameInstsInMBB(MachineBasicBlock *MBB) {
106   std::vector<NamedVReg> VRegs;
107   std::string Prefix = "bb" + std::to_string(getCurrentBBNumber()) + "_";
108   for (auto &MII : *MBB) {
109     MachineInstr &Candidate = MII;
110     // Don't rename stores/branches.
111     if (Candidate.mayStore() || Candidate.isBranch())
112       continue;
113     if (!Candidate.getNumOperands())
114       continue;
115     // Look for instructions that define VRegs in operand 0.
116     MachineOperand &MO = Candidate.getOperand(0);
117     // Avoid non regs, instructions defining physical regs.
118     if (!MO.isReg() || !Register::isVirtualRegister(MO.getReg()))
119       continue;
120     VRegs.push_back(
121         NamedVReg(MO.getReg(), Prefix + getInstructionOpcodeHash(Candidate)));
122   }
123 
124   // If we have populated no vregs to rename then bail.
125   // The rest of this function does the vreg remaping.
126   if (VRegs.size() == 0)
127     return false;
128 
129   auto VRegRenameMap = getVRegRenameMap(VRegs);
130   return doVRegRenaming(VRegRenameMap);
131 }
132 
133 bool VRegRenamer::renameVRegs(MachineBasicBlock *MBB, unsigned BBNum) {
134   CurrentBBNumber = BBNum;
135   return renameInstsInMBB(MBB);
136 }
137 
138 unsigned VRegRenamer::createVirtualRegisterWithName(unsigned VReg,
139                                                     const std::string &Name) {
140   std::string Temp(Name);
141   std::transform(Temp.begin(), Temp.end(), Temp.begin(), ::tolower);
142   if (auto RC = MRI.getRegClassOrNull(VReg))
143     return MRI.createVirtualRegister(RC, Temp);
144   return MRI.createGenericVirtualRegister(MRI.getType(VReg), Name);
145 }
146