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 using VRegRenameMap = std::map<unsigned, unsigned>;
17
doVRegRenaming(const VRegRenameMap & VRM)18 bool VRegRenamer::doVRegRenaming(const VRegRenameMap &VRM) {
19 bool Changed = false;
20
21 for (const auto &E : VRM) {
22 Changed = Changed || !MRI.reg_empty(E.first);
23 MRI.replaceRegWith(E.first, E.second);
24 }
25
26 return Changed;
27 }
28
29 VRegRenameMap
getVRegRenameMap(const std::vector<NamedVReg> & VRegs)30 VRegRenamer::getVRegRenameMap(const std::vector<NamedVReg> &VRegs) {
31
32 StringMap<unsigned> VRegNameCollisionMap;
33
34 auto GetUniqueVRegName = [&VRegNameCollisionMap](const NamedVReg &Reg) {
35 if (VRegNameCollisionMap.find(Reg.getName()) == VRegNameCollisionMap.end())
36 VRegNameCollisionMap[Reg.getName()] = 0;
37 const unsigned Counter = ++VRegNameCollisionMap[Reg.getName()];
38 return Reg.getName() + "__" + std::to_string(Counter);
39 };
40
41 VRegRenameMap VRM;
42 for (const auto &VReg : VRegs) {
43 const unsigned Reg = VReg.getReg();
44 VRM[Reg] = createVirtualRegisterWithLowerName(Reg, GetUniqueVRegName(VReg));
45 }
46 return VRM;
47 }
48
getInstructionOpcodeHash(MachineInstr & MI)49 std::string VRegRenamer::getInstructionOpcodeHash(MachineInstr &MI) {
50 std::string S;
51 raw_string_ostream OS(S);
52
53 // Gets a hashable artifact from a given MachineOperand (ie an unsigned).
54 auto GetHashableMO = [this](const MachineOperand &MO) -> unsigned {
55 switch (MO.getType()) {
56 case MachineOperand::MO_CImmediate:
57 return hash_combine(MO.getType(), MO.getTargetFlags(),
58 MO.getCImm()->getZExtValue());
59 case MachineOperand::MO_FPImmediate:
60 return hash_combine(
61 MO.getType(), MO.getTargetFlags(),
62 MO.getFPImm()->getValueAPF().bitcastToAPInt().getZExtValue());
63 case MachineOperand::MO_Register:
64 if (Register::isVirtualRegister(MO.getReg()))
65 return MRI.getVRegDef(MO.getReg())->getOpcode();
66 return MO.getReg();
67 case MachineOperand::MO_Immediate:
68 return MO.getImm();
69 case MachineOperand::MO_TargetIndex:
70 return MO.getOffset() | (MO.getTargetFlags() << 16);
71 case MachineOperand::MO_FrameIndex:
72 return llvm::hash_value(MO);
73
74 // We could explicitly handle all the types of the MachineOperand,
75 // here but we can just return a common number until we find a
76 // compelling test case where this is bad. The only side effect here
77 // is contributing to a hash collision but there's enough information
78 // (Opcodes,other registers etc) that this will likely not be a problem.
79
80 // TODO: Handle the following Index/ID/Predicate cases. They can
81 // be hashed on in a stable manner.
82 case MachineOperand::MO_ConstantPoolIndex:
83 case MachineOperand::MO_JumpTableIndex:
84 case MachineOperand::MO_CFIIndex:
85 case MachineOperand::MO_IntrinsicID:
86 case MachineOperand::MO_Predicate:
87
88 // In the cases below we havn't found a way to produce an artifact that will
89 // result in a stable hash, in most cases because they are pointers. We want
90 // stable hashes because we want the hash to be the same run to run.
91 case MachineOperand::MO_MachineBasicBlock:
92 case MachineOperand::MO_ExternalSymbol:
93 case MachineOperand::MO_GlobalAddress:
94 case MachineOperand::MO_BlockAddress:
95 case MachineOperand::MO_RegisterMask:
96 case MachineOperand::MO_RegisterLiveOut:
97 case MachineOperand::MO_Metadata:
98 case MachineOperand::MO_MCSymbol:
99 case MachineOperand::MO_ShuffleMask:
100 return 0;
101 }
102 llvm_unreachable("Unexpected MachineOperandType.");
103 };
104
105 SmallVector<unsigned, 16> MIOperands = {MI.getOpcode(), MI.getFlags()};
106 llvm::transform(MI.uses(), std::back_inserter(MIOperands), GetHashableMO);
107
108 for (const auto *Op : MI.memoperands()) {
109 MIOperands.push_back((unsigned)Op->getSize());
110 MIOperands.push_back((unsigned)Op->getFlags());
111 MIOperands.push_back((unsigned)Op->getOffset());
112 MIOperands.push_back((unsigned)Op->getOrdering());
113 MIOperands.push_back((unsigned)Op->getAddrSpace());
114 MIOperands.push_back((unsigned)Op->getSyncScopeID());
115 MIOperands.push_back((unsigned)Op->getBaseAlignment());
116 MIOperands.push_back((unsigned)Op->getFailureOrdering());
117 }
118
119 auto HashMI = hash_combine_range(MIOperands.begin(), MIOperands.end());
120 return std::to_string(HashMI).substr(0, 5);
121 }
122
createVirtualRegister(unsigned VReg)123 unsigned VRegRenamer::createVirtualRegister(unsigned VReg) {
124 assert(Register::isVirtualRegister(VReg) && "Expected Virtual Registers");
125 std::string Name = getInstructionOpcodeHash(*MRI.getVRegDef(VReg));
126 return createVirtualRegisterWithLowerName(VReg, Name);
127 }
128
renameInstsInMBB(MachineBasicBlock * MBB)129 bool VRegRenamer::renameInstsInMBB(MachineBasicBlock *MBB) {
130 std::vector<NamedVReg> VRegs;
131 std::string Prefix = "bb" + std::to_string(CurrentBBNumber) + "_";
132 for (MachineInstr &Candidate : *MBB) {
133 // Don't rename stores/branches.
134 if (Candidate.mayStore() || Candidate.isBranch())
135 continue;
136 if (!Candidate.getNumOperands())
137 continue;
138 // Look for instructions that define VRegs in operand 0.
139 MachineOperand &MO = Candidate.getOperand(0);
140 // Avoid non regs, instructions defining physical regs.
141 if (!MO.isReg() || !Register::isVirtualRegister(MO.getReg()))
142 continue;
143 VRegs.push_back(
144 NamedVReg(MO.getReg(), Prefix + getInstructionOpcodeHash(Candidate)));
145 }
146
147 return VRegs.size() ? doVRegRenaming(getVRegRenameMap(VRegs)) : false;
148 }
149
createVirtualRegisterWithLowerName(unsigned VReg,StringRef Name)150 unsigned VRegRenamer::createVirtualRegisterWithLowerName(unsigned VReg,
151 StringRef Name) {
152 std::string LowerName = Name.lower();
153 const TargetRegisterClass *RC = MRI.getRegClassOrNull(VReg);
154 return RC ? MRI.createVirtualRegister(RC, LowerName)
155 : MRI.createGenericVirtualRegister(MRI.getType(VReg), LowerName);
156 }
157