summaryrefslogtreecommitdiffstats
path: root/llvm/lib/CodeGen/MIRVRegNamerUtils.cpp
blob: 0596234986cd3447ae7f32f239902769a710d401 (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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
//===---------- 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"

bool VRegRenamer::doVRegRenaming(
    const std::map<unsigned, unsigned> &VRegRenameMap) {
  bool Changed = false;
  for (auto I = VRegRenameMap.begin(), E = VRegRenameMap.end(); I != E; ++I) {

    auto VReg = I->first;
    auto Rename = I->second;

    std::vector<MachineOperand *> RenameMOs;
    for (auto &MO : MRI.reg_operands(VReg)) {
      RenameMOs.push_back(&MO);
    }

    for (auto *MO : RenameMOs) {
      Changed = true;
      MO->setReg(Rename);

      if (!MO->isDef())
        MO->setIsKill(false);
    }
  }

  return Changed;
}

std::map<unsigned, unsigned>
VRegRenamer::getVRegRenameMap(const std::vector<NamedVReg> &VRegs) {
  std::map<unsigned, unsigned> VRegRenameMap;

  std::map<std::string, unsigned> VRegNameCollisionMap;

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

  for (auto &Vreg : VRegs) {
    auto Reg = Vreg.getReg();
    assert(Register::isVirtualRegister(Reg) &&
           "Expecting Virtual Registers Only");
    auto NewNameForReg = GetUniqueVRegName(Vreg);
    auto Rename = createVirtualRegisterWithName(Reg, NewNameForReg);

    VRegRenameMap.insert(std::pair<unsigned, unsigned>(Reg, Rename));
  }
  return VRegRenameMap;
}

std::string VRegRenamer::getInstructionOpcodeHash(MachineInstr &MI) {
  std::string S;
  raw_string_ostream OS(S);
  auto HashOperand = [this](const MachineOperand &MO) -> unsigned {
    if (MO.isImm())
      return MO.getImm();
    if (MO.isTargetIndex())
      return MO.getOffset() | (MO.getTargetFlags() << 16);
    if (MO.isReg()) {
      return Register::isVirtualRegister(MO.getReg())
                 ? MRI.getVRegDef(MO.getReg())->getOpcode()
                 : (unsigned)MO.getReg();
    }
    // 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 collission but there's enough information
    // (Opcodes,other registers etc) that this will likely not be a problem.
    return 0;
  };
  SmallVector<unsigned, 16> MIOperands;
  MIOperands.push_back(MI.getOpcode());
  for (auto &Op : MI.uses()) {
    MIOperands.push_back(HashOperand(Op));
  }
  auto HashMI = hash_combine_range(MIOperands.begin(), MIOperands.end());
  return std::to_string(HashMI).substr(0, 5);
}

unsigned VRegRenamer::createVirtualRegister(unsigned VReg) {
  return createVirtualRegisterWithName(
      VReg, getInstructionOpcodeHash(*MRI.getVRegDef(VReg)));
}

bool VRegRenamer::renameInstsInMBB(MachineBasicBlock *MBB) {
  std::vector<NamedVReg> VRegs;
  std::string Prefix = "bb" + std::to_string(getCurrentBBNumber()) + "_";
  for (auto &MII : *MBB) {
    MachineInstr &Candidate = MII;
    // 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)));
  }

  // If we have populated no vregs to rename then bail.
  // The rest of this function does the vreg remaping.
  if (VRegs.size() == 0)
    return false;

  auto VRegRenameMap = getVRegRenameMap(VRegs);
  return doVRegRenaming(VRegRenameMap);
}

bool VRegRenamer::renameVRegs(MachineBasicBlock *MBB, unsigned BBNum) {
  CurrentBBNumber = BBNum;
  return renameInstsInMBB(MBB);
}

unsigned VRegRenamer::createVirtualRegisterWithName(unsigned VReg,
                                                    const std::string &Name) {
  std::string Temp(Name);
  std::transform(Temp.begin(), Temp.end(), Temp.begin(), ::tolower);
  if (auto RC = MRI.getRegClassOrNull(VReg))
    return MRI.createVirtualRegister(RC, Temp);
  return MRI.createGenericVirtualRegister(MRI.getType(VReg), Name);
}
OpenPOWER on IntegriCloud