xref: /freebsd-src/contrib/llvm-project/llvm/lib/CodeGen/MIRVRegNamerUtils.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
18bcb0991SDimitry Andric //===---------- MIRVRegNamerUtils.cpp - MIR VReg Renaming Utilities -------===//
28bcb0991SDimitry Andric //
38bcb0991SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
48bcb0991SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
58bcb0991SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
68bcb0991SDimitry Andric //
78bcb0991SDimitry Andric //===----------------------------------------------------------------------===//
88bcb0991SDimitry Andric 
98bcb0991SDimitry Andric #include "MIRVRegNamerUtils.h"
105ffd83dbSDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
11e8d8bef9SDimitry Andric #include "llvm/CodeGen/MachineStableHash.h"
125ffd83dbSDimitry Andric #include "llvm/IR/Constants.h"
138bcb0991SDimitry Andric 
148bcb0991SDimitry Andric using namespace llvm;
158bcb0991SDimitry Andric 
168bcb0991SDimitry Andric #define DEBUG_TYPE "mir-vregnamer-utils"
178bcb0991SDimitry Andric 
18e8d8bef9SDimitry Andric static cl::opt<bool>
19e8d8bef9SDimitry Andric     UseStableNamerHash("mir-vreg-namer-use-stable-hash", cl::init(false),
20e8d8bef9SDimitry Andric                        cl::Hidden,
21e8d8bef9SDimitry Andric                        cl::desc("Use Stable Hashing for MIR VReg Renaming"));
22e8d8bef9SDimitry Andric 
23480093f4SDimitry Andric using VRegRenameMap = std::map<unsigned, unsigned>;
248bcb0991SDimitry Andric 
25480093f4SDimitry Andric bool VRegRenamer::doVRegRenaming(const VRegRenameMap &VRM) {
26480093f4SDimitry Andric   bool Changed = false;
278bcb0991SDimitry Andric 
28480093f4SDimitry Andric   for (const auto &E : VRM) {
29480093f4SDimitry Andric     Changed = Changed || !MRI.reg_empty(E.first);
30480093f4SDimitry Andric     MRI.replaceRegWith(E.first, E.second);
318bcb0991SDimitry Andric   }
328bcb0991SDimitry Andric 
33480093f4SDimitry Andric   return Changed;
348bcb0991SDimitry Andric }
35480093f4SDimitry Andric 
36480093f4SDimitry Andric VRegRenameMap
37480093f4SDimitry Andric VRegRenamer::getVRegRenameMap(const std::vector<NamedVReg> &VRegs) {
38480093f4SDimitry Andric 
39480093f4SDimitry Andric   StringMap<unsigned> VRegNameCollisionMap;
40480093f4SDimitry Andric 
41480093f4SDimitry Andric   auto GetUniqueVRegName = [&VRegNameCollisionMap](const NamedVReg &Reg) {
4206c3fb27SDimitry Andric     if (!VRegNameCollisionMap.contains(Reg.getName()))
43480093f4SDimitry Andric       VRegNameCollisionMap[Reg.getName()] = 0;
44480093f4SDimitry Andric     const unsigned Counter = ++VRegNameCollisionMap[Reg.getName()];
45480093f4SDimitry Andric     return Reg.getName() + "__" + std::to_string(Counter);
468bcb0991SDimitry Andric   };
478bcb0991SDimitry Andric 
48480093f4SDimitry Andric   VRegRenameMap VRM;
49480093f4SDimitry Andric   for (const auto &VReg : VRegs) {
50480093f4SDimitry Andric     const unsigned Reg = VReg.getReg();
51480093f4SDimitry Andric     VRM[Reg] = createVirtualRegisterWithLowerName(Reg, GetUniqueVRegName(VReg));
528bcb0991SDimitry Andric   }
53480093f4SDimitry Andric   return VRM;
548bcb0991SDimitry Andric }
558bcb0991SDimitry Andric 
56480093f4SDimitry Andric std::string VRegRenamer::getInstructionOpcodeHash(MachineInstr &MI) {
578bcb0991SDimitry Andric   std::string S;
588bcb0991SDimitry Andric   raw_string_ostream OS(S);
59480093f4SDimitry Andric 
60e8d8bef9SDimitry Andric   if (UseStableNamerHash) {
61e8d8bef9SDimitry Andric     auto Hash = stableHashValue(MI, /* HashVRegs */ true,
62e8d8bef9SDimitry Andric                                 /* HashConstantPoolIndices */ true,
63e8d8bef9SDimitry Andric                                 /* HashMemOperands */ true);
64e8d8bef9SDimitry Andric     assert(Hash && "Expected non-zero Hash");
65bdd1243dSDimitry Andric     OS << format_hex_no_prefix(Hash, 16, true);
66bdd1243dSDimitry Andric     return OS.str();
67e8d8bef9SDimitry Andric   }
68e8d8bef9SDimitry Andric 
69480093f4SDimitry Andric   // Gets a hashable artifact from a given MachineOperand (ie an unsigned).
70480093f4SDimitry Andric   auto GetHashableMO = [this](const MachineOperand &MO) -> unsigned {
71480093f4SDimitry Andric     switch (MO.getType()) {
72480093f4SDimitry Andric     case MachineOperand::MO_CImmediate:
73480093f4SDimitry Andric       return hash_combine(MO.getType(), MO.getTargetFlags(),
74480093f4SDimitry Andric                           MO.getCImm()->getZExtValue());
75480093f4SDimitry Andric     case MachineOperand::MO_FPImmediate:
76480093f4SDimitry Andric       return hash_combine(
77480093f4SDimitry Andric           MO.getType(), MO.getTargetFlags(),
78480093f4SDimitry Andric           MO.getFPImm()->getValueAPF().bitcastToAPInt().getZExtValue());
79480093f4SDimitry Andric     case MachineOperand::MO_Register:
80bdd1243dSDimitry Andric       if (MO.getReg().isVirtual())
81480093f4SDimitry Andric         return MRI.getVRegDef(MO.getReg())->getOpcode();
82480093f4SDimitry Andric       return MO.getReg();
83480093f4SDimitry Andric     case MachineOperand::MO_Immediate:
84480093f4SDimitry Andric       return MO.getImm();
85480093f4SDimitry Andric     case MachineOperand::MO_TargetIndex:
86480093f4SDimitry Andric       return MO.getOffset() | (MO.getTargetFlags() << 16);
87480093f4SDimitry Andric     case MachineOperand::MO_FrameIndex:
885ffd83dbSDimitry Andric     case MachineOperand::MO_ConstantPoolIndex:
895ffd83dbSDimitry Andric     case MachineOperand::MO_JumpTableIndex:
90480093f4SDimitry Andric       return llvm::hash_value(MO);
91480093f4SDimitry Andric 
92480093f4SDimitry Andric     // We could explicitly handle all the types of the MachineOperand,
93480093f4SDimitry Andric     // here but we can just return a common number until we find a
94480093f4SDimitry Andric     // compelling test case where this is bad. The only side effect here
95480093f4SDimitry Andric     // is contributing to a hash collision but there's enough information
96480093f4SDimitry Andric     // (Opcodes,other registers etc) that this will likely not be a problem.
97480093f4SDimitry Andric 
98480093f4SDimitry Andric     // TODO: Handle the following Index/ID/Predicate cases. They can
99480093f4SDimitry Andric     // be hashed on in a stable manner.
100480093f4SDimitry Andric     case MachineOperand::MO_CFIIndex:
101480093f4SDimitry Andric     case MachineOperand::MO_IntrinsicID:
102480093f4SDimitry Andric     case MachineOperand::MO_Predicate:
103480093f4SDimitry Andric 
104480093f4SDimitry Andric     // In the cases below we havn't found a way to produce an artifact that will
105480093f4SDimitry Andric     // result in a stable hash, in most cases because they are pointers. We want
106480093f4SDimitry Andric     // stable hashes because we want the hash to be the same run to run.
107480093f4SDimitry Andric     case MachineOperand::MO_MachineBasicBlock:
108480093f4SDimitry Andric     case MachineOperand::MO_ExternalSymbol:
109480093f4SDimitry Andric     case MachineOperand::MO_GlobalAddress:
110480093f4SDimitry Andric     case MachineOperand::MO_BlockAddress:
111480093f4SDimitry Andric     case MachineOperand::MO_RegisterMask:
112480093f4SDimitry Andric     case MachineOperand::MO_RegisterLiveOut:
113480093f4SDimitry Andric     case MachineOperand::MO_Metadata:
114480093f4SDimitry Andric     case MachineOperand::MO_MCSymbol:
115480093f4SDimitry Andric     case MachineOperand::MO_ShuffleMask:
116bdd1243dSDimitry Andric     case MachineOperand::MO_DbgInstrRef:
117480093f4SDimitry Andric       return 0;
118480093f4SDimitry Andric     }
119480093f4SDimitry Andric     llvm_unreachable("Unexpected MachineOperandType.");
120480093f4SDimitry Andric   };
121480093f4SDimitry Andric 
122480093f4SDimitry Andric   SmallVector<unsigned, 16> MIOperands = {MI.getOpcode(), MI.getFlags()};
123480093f4SDimitry Andric   llvm::transform(MI.uses(), std::back_inserter(MIOperands), GetHashableMO);
124480093f4SDimitry Andric 
125480093f4SDimitry Andric   for (const auto *Op : MI.memoperands()) {
126*0fca6ea1SDimitry Andric     MIOperands.push_back((unsigned)Op->getSize().getValue());
127480093f4SDimitry Andric     MIOperands.push_back((unsigned)Op->getFlags());
128480093f4SDimitry Andric     MIOperands.push_back((unsigned)Op->getOffset());
129fe6060f1SDimitry Andric     MIOperands.push_back((unsigned)Op->getSuccessOrdering());
130480093f4SDimitry Andric     MIOperands.push_back((unsigned)Op->getAddrSpace());
131480093f4SDimitry Andric     MIOperands.push_back((unsigned)Op->getSyncScopeID());
1325ffd83dbSDimitry Andric     MIOperands.push_back((unsigned)Op->getBaseAlign().value());
133480093f4SDimitry Andric     MIOperands.push_back((unsigned)Op->getFailureOrdering());
1348bcb0991SDimitry Andric   }
1358bcb0991SDimitry Andric 
136480093f4SDimitry Andric   auto HashMI = hash_combine_range(MIOperands.begin(), MIOperands.end());
137bdd1243dSDimitry Andric   OS << format_hex_no_prefix(HashMI, 16, true);
138bdd1243dSDimitry Andric   return OS.str();
139480093f4SDimitry Andric }
140480093f4SDimitry Andric 
141480093f4SDimitry Andric unsigned VRegRenamer::createVirtualRegister(unsigned VReg) {
142480093f4SDimitry Andric   assert(Register::isVirtualRegister(VReg) && "Expected Virtual Registers");
143480093f4SDimitry Andric   std::string Name = getInstructionOpcodeHash(*MRI.getVRegDef(VReg));
144480093f4SDimitry Andric   return createVirtualRegisterWithLowerName(VReg, Name);
145480093f4SDimitry Andric }
146480093f4SDimitry Andric 
147480093f4SDimitry Andric bool VRegRenamer::renameInstsInMBB(MachineBasicBlock *MBB) {
148480093f4SDimitry Andric   std::vector<NamedVReg> VRegs;
149480093f4SDimitry Andric   std::string Prefix = "bb" + std::to_string(CurrentBBNumber) + "_";
150480093f4SDimitry Andric   for (MachineInstr &Candidate : *MBB) {
151480093f4SDimitry Andric     // Don't rename stores/branches.
152480093f4SDimitry Andric     if (Candidate.mayStore() || Candidate.isBranch())
153480093f4SDimitry Andric       continue;
154480093f4SDimitry Andric     if (!Candidate.getNumOperands())
155480093f4SDimitry Andric       continue;
156480093f4SDimitry Andric     // Look for instructions that define VRegs in operand 0.
157480093f4SDimitry Andric     MachineOperand &MO = Candidate.getOperand(0);
158480093f4SDimitry Andric     // Avoid non regs, instructions defining physical regs.
159bdd1243dSDimitry Andric     if (!MO.isReg() || !MO.getReg().isVirtual())
160480093f4SDimitry Andric       continue;
161480093f4SDimitry Andric     VRegs.push_back(
162480093f4SDimitry Andric         NamedVReg(MO.getReg(), Prefix + getInstructionOpcodeHash(Candidate)));
163480093f4SDimitry Andric   }
164480093f4SDimitry Andric 
165480093f4SDimitry Andric   return VRegs.size() ? doVRegRenaming(getVRegRenameMap(VRegs)) : false;
166480093f4SDimitry Andric }
167480093f4SDimitry Andric 
168480093f4SDimitry Andric unsigned VRegRenamer::createVirtualRegisterWithLowerName(unsigned VReg,
169480093f4SDimitry Andric                                                          StringRef Name) {
170480093f4SDimitry Andric   std::string LowerName = Name.lower();
171480093f4SDimitry Andric   const TargetRegisterClass *RC = MRI.getRegClassOrNull(VReg);
172480093f4SDimitry Andric   return RC ? MRI.createVirtualRegister(RC, LowerName)
173480093f4SDimitry Andric             : MRI.createGenericVirtualRegister(MRI.getType(VReg), LowerName);
1748bcb0991SDimitry Andric }
175