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