MIRVRegNamerUtils.cpp revision 360784
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
12using namespace llvm;
13
14#define DEBUG_TYPE "mir-vregnamer-utils"
15
16using VRegRenameMap = std::map<unsigned, unsigned>;
17
18bool 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
29VRegRenameMap
30VRegRenamer::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
49std::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
123unsigned 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
129bool 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
150unsigned 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