forked from OSchip/llvm-project
146 lines
4.8 KiB
C++
146 lines
4.8 KiB
C++
//===---------- 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);
|
|
}
|