summaryrefslogtreecommitdiffstats
path: root/llvm/lib/CodeGen/MIRVRegNamerUtils.cpp
blob: 8b17f78e0bcf9c0990592c71d49c2151ac25c17d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
//===---------- MIRVRegNamerUtils.cpp - MIR VReg Renaming Utilities -------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "MIRVRegNamerUtils.h"
#include "llvm/Support/Debug.h"

using namespace llvm;

#define DEBUG_TYPE "mir-vregnamer-utils"

using VRegRenameMap = std::map<unsigned, unsigned>;

bool VRegRenamer::doVRegRenaming(const VRegRenameMap &VRM) {
  bool Changed = false;

  for (const auto &E : VRM) {
    Changed = Changed || !MRI.reg_empty(E.first);
    MRI.replaceRegWith(E.first, E.second);
  }

  return Changed;
}

VRegRenameMap
VRegRenamer::getVRegRenameMap(const std::vector<NamedVReg> &VRegs) {

  StringMap<unsigned> VRegNameCollisionMap;

  auto GetUniqueVRegName = [&VRegNameCollisionMap](const NamedVReg &Reg) {
    if (VRegNameCollisionMap.find(Reg.getName()) == VRegNameCollisionMap.end())
      VRegNameCollisionMap[Reg.getName()] = 0;
    const unsigned Counter = ++VRegNameCollisionMap[Reg.getName()];
    return Reg.getName() + "__" + std::to_string(Counter);
  };

  VRegRenameMap VRM;
  for (const auto &VReg : VRegs) {
    const unsigned Reg = VReg.getReg();
    VRM[Reg] = createVirtualRegisterWithLowerName(Reg, GetUniqueVRegName(VReg));
  }
  return VRM;
}

std::string VRegRenamer::getInstructionOpcodeHash(MachineInstr &MI) {
  std::string S;
  raw_string_ostream OS(S);

  // Gets a hashable artifact from a given MachineOperand (ie an unsigned).
  auto GetHashableMO = [this](const MachineOperand &MO) -> unsigned {
    if (MO.isImm())
      return MO.getImm();
    if (MO.isTargetIndex())
      return MO.getOffset() | (MO.getTargetFlags() << 16);
    if (MO.isReg() && Register::isVirtualRegister(MO.getReg()))
      return MRI.getVRegDef(MO.getReg())->getOpcode();
    if (MO.isReg())
      return MO.getReg();
    // TODO:
    // We could explicitly handle all the types of the MachineOperand,
    // here but we can just return a common number until we find a
    // compelling test case where this is bad. The only side effect here
    // is contributing to a hash collision but there's enough information
    // (Opcodes,other registers etc) that this will likely not be a problem.
    return 0;
  };

  SmallVector<unsigned, 16> MIOperands = {MI.getOpcode(), MI.getFlags()};
  llvm::transform(MI.uses(), std::back_inserter(MIOperands), GetHashableMO);

  for (const auto *Op : MI.memoperands()) {
    MIOperands.push_back((unsigned)Op->getSize());
    MIOperands.push_back((unsigned)Op->getFlags());
    MIOperands.push_back((unsigned)Op->getOffset());
    MIOperands.push_back((unsigned)Op->getOrdering());
    MIOperands.push_back((unsigned)Op->getAddrSpace());
    MIOperands.push_back((unsigned)Op->getSyncScopeID());
    MIOperands.push_back((unsigned)Op->getBaseAlignment());
    MIOperands.push_back((unsigned)Op->getFailureOrdering());
  }

  auto HashMI = hash_combine_range(MIOperands.begin(), MIOperands.end());
  return std::to_string(HashMI).substr(0, 5);
}

unsigned VRegRenamer::createVirtualRegister(unsigned VReg) {
  assert(Register::isVirtualRegister(VReg) && "Expected Virtual Registers");
  std::string Name = getInstructionOpcodeHash(*MRI.getVRegDef(VReg));
  return createVirtualRegisterWithLowerName(VReg, Name);
}

bool VRegRenamer::renameInstsInMBB(MachineBasicBlock *MBB) {
  std::vector<NamedVReg> VRegs;
  std::string Prefix = "bb" + std::to_string(CurrentBBNumber) + "_";
  for (MachineInstr &Candidate : *MBB) {
    // Don't rename stores/branches.
    if (Candidate.mayStore() || Candidate.isBranch())
      continue;
    if (!Candidate.getNumOperands())
      continue;
    // Look for instructions that define VRegs in operand 0.
    MachineOperand &MO = Candidate.getOperand(0);
    // Avoid non regs, instructions defining physical regs.
    if (!MO.isReg() || !Register::isVirtualRegister(MO.getReg()))
      continue;
    VRegs.push_back(
        NamedVReg(MO.getReg(), Prefix + getInstructionOpcodeHash(Candidate)));
  }

  return VRegs.size() ? doVRegRenaming(getVRegRenameMap(VRegs)) : false;
}

unsigned VRegRenamer::createVirtualRegisterWithLowerName(unsigned VReg,
                                                         StringRef Name) {
  std::string LowerName = Name.lower();
  const TargetRegisterClass *RC = MRI.getRegClassOrNull(VReg);
  return RC ? MRI.createVirtualRegister(RC, LowerName)
            : MRI.createGenericVirtualRegister(MRI.getType(VReg), LowerName);
}
OpenPOWER on IntegriCloud