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