1028061d4SPuyan Lotfi //===---------- MIRVRegNamerUtils.cpp - MIR VReg Renaming Utilities -------===//
2028061d4SPuyan Lotfi //
3028061d4SPuyan Lotfi // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4028061d4SPuyan Lotfi // See https://llvm.org/LICENSE.txt for license information.
5028061d4SPuyan Lotfi // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6028061d4SPuyan Lotfi //
7028061d4SPuyan Lotfi //===----------------------------------------------------------------------===//
8028061d4SPuyan Lotfi 
9028061d4SPuyan Lotfi #include "MIRVRegNamerUtils.h"
109036fcd2SSimon Pilgrim #include "llvm/CodeGen/MachineRegisterInfo.h"
117fff1fbdSPuyan Lotfi #include "llvm/CodeGen/MachineStableHash.h"
129036fcd2SSimon Pilgrim #include "llvm/IR/Constants.h"
13028061d4SPuyan Lotfi 
14028061d4SPuyan Lotfi using namespace llvm;
15028061d4SPuyan Lotfi 
16028061d4SPuyan Lotfi #define DEBUG_TYPE "mir-vregnamer-utils"
17028061d4SPuyan Lotfi 
187fff1fbdSPuyan Lotfi static cl::opt<bool>
197fff1fbdSPuyan Lotfi     UseStableNamerHash("mir-vreg-namer-use-stable-hash", cl::init(false),
207fff1fbdSPuyan Lotfi                        cl::Hidden,
217fff1fbdSPuyan Lotfi                        cl::desc("Use Stable Hashing for MIR VReg Renaming"));
227fff1fbdSPuyan Lotfi 
23479e3b85SPuyan Lotfi using VRegRenameMap = std::map<unsigned, unsigned>;
24479e3b85SPuyan Lotfi 
doVRegRenaming(const VRegRenameMap & VRM)25479e3b85SPuyan Lotfi bool VRegRenamer::doVRegRenaming(const VRegRenameMap &VRM) {
26028061d4SPuyan Lotfi   bool Changed = false;
27028061d4SPuyan Lotfi 
28479e3b85SPuyan Lotfi   for (const auto &E : VRM) {
29479e3b85SPuyan Lotfi     Changed = Changed || !MRI.reg_empty(E.first);
30479e3b85SPuyan Lotfi     MRI.replaceRegWith(E.first, E.second);
31028061d4SPuyan Lotfi   }
32028061d4SPuyan Lotfi 
33028061d4SPuyan Lotfi   return Changed;
34028061d4SPuyan Lotfi }
35028061d4SPuyan Lotfi 
36479e3b85SPuyan Lotfi VRegRenameMap
getVRegRenameMap(const std::vector<NamedVReg> & VRegs)3772768685SAditya Nandakumar VRegRenamer::getVRegRenameMap(const std::vector<NamedVReg> &VRegs) {
38028061d4SPuyan Lotfi 
39479e3b85SPuyan Lotfi   StringMap<unsigned> VRegNameCollisionMap;
40028061d4SPuyan Lotfi 
41479e3b85SPuyan Lotfi   auto GetUniqueVRegName = [&VRegNameCollisionMap](const NamedVReg &Reg) {
42479e3b85SPuyan Lotfi     if (VRegNameCollisionMap.find(Reg.getName()) == VRegNameCollisionMap.end())
43479e3b85SPuyan Lotfi       VRegNameCollisionMap[Reg.getName()] = 0;
44479e3b85SPuyan Lotfi     const unsigned Counter = ++VRegNameCollisionMap[Reg.getName()];
4572768685SAditya Nandakumar     return Reg.getName() + "__" + std::to_string(Counter);
4672768685SAditya Nandakumar   };
47028061d4SPuyan Lotfi 
48479e3b85SPuyan Lotfi   VRegRenameMap VRM;
49479e3b85SPuyan Lotfi   for (const auto &VReg : VRegs) {
50479e3b85SPuyan Lotfi     const unsigned Reg = VReg.getReg();
51479e3b85SPuyan Lotfi     VRM[Reg] = createVirtualRegisterWithLowerName(Reg, GetUniqueVRegName(VReg));
5272768685SAditya Nandakumar   }
53479e3b85SPuyan Lotfi   return VRM;
54028061d4SPuyan Lotfi }
55028061d4SPuyan Lotfi 
getInstructionOpcodeHash(MachineInstr & MI)5672768685SAditya Nandakumar std::string VRegRenamer::getInstructionOpcodeHash(MachineInstr &MI) {
5772768685SAditya Nandakumar   std::string S;
5872768685SAditya Nandakumar   raw_string_ostream OS(S);
59479e3b85SPuyan Lotfi 
607fff1fbdSPuyan Lotfi   if (UseStableNamerHash) {
617fff1fbdSPuyan Lotfi     auto Hash = stableHashValue(MI, /* HashVRegs */ true,
627fff1fbdSPuyan Lotfi                                 /* HashConstantPoolIndices */ true,
637fff1fbdSPuyan Lotfi                                 /* HashMemOperands */ true);
647fff1fbdSPuyan Lotfi     assert(Hash && "Expected non-zero Hash");
657fff1fbdSPuyan Lotfi     return std::to_string(Hash).substr(0, 5);
667fff1fbdSPuyan Lotfi   }
677fff1fbdSPuyan Lotfi 
68479e3b85SPuyan Lotfi   // Gets a hashable artifact from a given MachineOperand (ie an unsigned).
69479e3b85SPuyan Lotfi   auto GetHashableMO = [this](const MachineOperand &MO) -> unsigned {
70816985c1SPuyan Lotfi     switch (MO.getType()) {
71f63b64c0SPuyan Lotfi     case MachineOperand::MO_CImmediate:
72f63b64c0SPuyan Lotfi       return hash_combine(MO.getType(), MO.getTargetFlags(),
73f63b64c0SPuyan Lotfi                           MO.getCImm()->getZExtValue());
74f63b64c0SPuyan Lotfi     case MachineOperand::MO_FPImmediate:
75f63b64c0SPuyan Lotfi       return hash_combine(
76f63b64c0SPuyan Lotfi           MO.getType(), MO.getTargetFlags(),
77f63b64c0SPuyan Lotfi           MO.getFPImm()->getValueAPF().bitcastToAPInt().getZExtValue());
78816985c1SPuyan Lotfi     case MachineOperand::MO_Register:
79816985c1SPuyan Lotfi       if (Register::isVirtualRegister(MO.getReg()))
80479e3b85SPuyan Lotfi         return MRI.getVRegDef(MO.getReg())->getOpcode();
81479e3b85SPuyan Lotfi       return MO.getReg();
82204dfabfSPuyan Lotfi     case MachineOperand::MO_Immediate:
83204dfabfSPuyan Lotfi       return MO.getImm();
84204dfabfSPuyan Lotfi     case MachineOperand::MO_TargetIndex:
85204dfabfSPuyan Lotfi       return MO.getOffset() | (MO.getTargetFlags() << 16);
86484a7472SPuyan Lotfi     case MachineOperand::MO_FrameIndex:
874b8af31fSPuyan Lotfi     case MachineOperand::MO_ConstantPoolIndex:
88264c07efSPuyan Lotfi     case MachineOperand::MO_JumpTableIndex:
89484a7472SPuyan Lotfi       return llvm::hash_value(MO);
90816985c1SPuyan Lotfi 
9172768685SAditya Nandakumar     // We could explicitly handle all the types of the MachineOperand,
9272768685SAditya Nandakumar     // here but we can just return a common number until we find a
9372768685SAditya Nandakumar     // compelling test case where this is bad. The only side effect here
94479e3b85SPuyan Lotfi     // is contributing to a hash collision but there's enough information
9572768685SAditya Nandakumar     // (Opcodes,other registers etc) that this will likely not be a problem.
96816985c1SPuyan Lotfi 
97204dfabfSPuyan Lotfi     // TODO: Handle the following Index/ID/Predicate cases. They can
98816985c1SPuyan Lotfi     // be hashed on in a stable manner.
99816985c1SPuyan Lotfi     case MachineOperand::MO_CFIIndex:
100816985c1SPuyan Lotfi     case MachineOperand::MO_IntrinsicID:
101816985c1SPuyan Lotfi     case MachineOperand::MO_Predicate:
102816985c1SPuyan Lotfi 
103816985c1SPuyan Lotfi     // In the cases below we havn't found a way to produce an artifact that will
104816985c1SPuyan Lotfi     // result in a stable hash, in most cases because they are pointers. We want
105816985c1SPuyan Lotfi     // stable hashes because we want the hash to be the same run to run.
106816985c1SPuyan Lotfi     case MachineOperand::MO_MachineBasicBlock:
107816985c1SPuyan Lotfi     case MachineOperand::MO_ExternalSymbol:
108816985c1SPuyan Lotfi     case MachineOperand::MO_GlobalAddress:
109816985c1SPuyan Lotfi     case MachineOperand::MO_BlockAddress:
110816985c1SPuyan Lotfi     case MachineOperand::MO_RegisterMask:
111816985c1SPuyan Lotfi     case MachineOperand::MO_RegisterLiveOut:
112816985c1SPuyan Lotfi     case MachineOperand::MO_Metadata:
113816985c1SPuyan Lotfi     case MachineOperand::MO_MCSymbol:
114816985c1SPuyan Lotfi     case MachineOperand::MO_ShuffleMask:
11572768685SAditya Nandakumar       return 0;
116816985c1SPuyan Lotfi     }
117816985c1SPuyan Lotfi     llvm_unreachable("Unexpected MachineOperandType.");
11872768685SAditya Nandakumar   };
119479e3b85SPuyan Lotfi 
120f364686fSPuyan Lotfi   SmallVector<unsigned, 16> MIOperands = {MI.getOpcode(), MI.getFlags()};
121479e3b85SPuyan Lotfi   llvm::transform(MI.uses(), std::back_inserter(MIOperands), GetHashableMO);
122479e3b85SPuyan Lotfi 
123f5b7a468SPuyan Lotfi   for (const auto *Op : MI.memoperands()) {
124f5b7a468SPuyan Lotfi     MIOperands.push_back((unsigned)Op->getSize());
125f5b7a468SPuyan Lotfi     MIOperands.push_back((unsigned)Op->getFlags());
126f5b7a468SPuyan Lotfi     MIOperands.push_back((unsigned)Op->getOffset());
127*74909e4bSEli Friedman     MIOperands.push_back((unsigned)Op->getSuccessOrdering());
128f5b7a468SPuyan Lotfi     MIOperands.push_back((unsigned)Op->getAddrSpace());
129f5b7a468SPuyan Lotfi     MIOperands.push_back((unsigned)Op->getSyncScopeID());
13074eac903SGuillaume Chatelet     MIOperands.push_back((unsigned)Op->getBaseAlign().value());
131f5b7a468SPuyan Lotfi     MIOperands.push_back((unsigned)Op->getFailureOrdering());
132f5b7a468SPuyan Lotfi   }
133f5b7a468SPuyan Lotfi 
13472768685SAditya Nandakumar   auto HashMI = hash_combine_range(MIOperands.begin(), MIOperands.end());
13572768685SAditya Nandakumar   return std::to_string(HashMI).substr(0, 5);
136028061d4SPuyan Lotfi }
137028061d4SPuyan Lotfi 
createVirtualRegister(unsigned VReg)13872768685SAditya Nandakumar unsigned VRegRenamer::createVirtualRegister(unsigned VReg) {
139479e3b85SPuyan Lotfi   assert(Register::isVirtualRegister(VReg) && "Expected Virtual Registers");
140479e3b85SPuyan Lotfi   std::string Name = getInstructionOpcodeHash(*MRI.getVRegDef(VReg));
141479e3b85SPuyan Lotfi   return createVirtualRegisterWithLowerName(VReg, Name);
14272768685SAditya Nandakumar }
14372768685SAditya Nandakumar 
renameInstsInMBB(MachineBasicBlock * MBB)14472768685SAditya Nandakumar bool VRegRenamer::renameInstsInMBB(MachineBasicBlock *MBB) {
14572768685SAditya Nandakumar   std::vector<NamedVReg> VRegs;
146756db63aSPuyan Lotfi   std::string Prefix = "bb" + std::to_string(CurrentBBNumber) + "_";
147479e3b85SPuyan Lotfi   for (MachineInstr &Candidate : *MBB) {
14872768685SAditya Nandakumar     // Don't rename stores/branches.
14972768685SAditya Nandakumar     if (Candidate.mayStore() || Candidate.isBranch())
15072768685SAditya Nandakumar       continue;
15172768685SAditya Nandakumar     if (!Candidate.getNumOperands())
15272768685SAditya Nandakumar       continue;
15372768685SAditya Nandakumar     // Look for instructions that define VRegs in operand 0.
15472768685SAditya Nandakumar     MachineOperand &MO = Candidate.getOperand(0);
15572768685SAditya Nandakumar     // Avoid non regs, instructions defining physical regs.
15672768685SAditya Nandakumar     if (!MO.isReg() || !Register::isVirtualRegister(MO.getReg()))
15772768685SAditya Nandakumar       continue;
15872768685SAditya Nandakumar     VRegs.push_back(
15972768685SAditya Nandakumar         NamedVReg(MO.getReg(), Prefix + getInstructionOpcodeHash(Candidate)));
160028061d4SPuyan Lotfi   }
161028061d4SPuyan Lotfi 
162479e3b85SPuyan Lotfi   return VRegs.size() ? doVRegRenaming(getVRegRenameMap(VRegs)) : false;
163028061d4SPuyan Lotfi }
164028061d4SPuyan Lotfi 
createVirtualRegisterWithLowerName(unsigned VReg,StringRef Name)165479e3b85SPuyan Lotfi unsigned VRegRenamer::createVirtualRegisterWithLowerName(unsigned VReg,
166479e3b85SPuyan Lotfi                                                          StringRef Name) {
167479e3b85SPuyan Lotfi   std::string LowerName = Name.lower();
168479e3b85SPuyan Lotfi   const TargetRegisterClass *RC = MRI.getRegClassOrNull(VReg);
169479e3b85SPuyan Lotfi   return RC ? MRI.createVirtualRegister(RC, LowerName)
170479e3b85SPuyan Lotfi             : MRI.createGenericVirtualRegister(MRI.getType(VReg), LowerName);
171028061d4SPuyan Lotfi }
172