blob: ccfc4565d3a9bc0ba27c2b2f38534d89f7b2d327 [file] [log] [blame]
//===---------- MIRVRegNamerUtils.cpp - MIR VReg Renaming Utilities -------===//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "MIRVRegNamerUtils.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/MachineStableHash.h"
#include "llvm/IR/Constants.h"
using namespace llvm;
#define DEBUG_TYPE "mir-vregnamer-utils"
static cl::opt<bool>
UseStableNamerHash("mir-vreg-namer-use-stable-hash", cl::init(false),
cl::desc("Use Stable Hashing for MIR VReg Renaming"));
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;
VRegRenamer::getVRegRenameMap(const std::vector<NamedVReg> &VRegs) {
StringMap<unsigned> VRegNameCollisionMap;
auto GetUniqueVRegName = [&VRegNameCollisionMap](const NamedVReg &Reg) {
if (!VRegNameCollisionMap.contains(Reg.getName()))
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);
if (UseStableNamerHash) {
auto Hash = stableHashValue(MI, /* HashVRegs */ true,
/* HashConstantPoolIndices */ true,
/* HashMemOperands */ true);
assert(Hash && "Expected non-zero Hash");
OS << format_hex_no_prefix(Hash, 16, true);
return OS.str();
// Gets a hashable artifact from a given MachineOperand (ie an unsigned).
auto GetHashableMO = [this](const MachineOperand &MO) -> unsigned {
switch (MO.getType()) {
case MachineOperand::MO_CImmediate:
return hash_combine(MO.getType(), MO.getTargetFlags(),
case MachineOperand::MO_FPImmediate:
return hash_combine(
MO.getType(), MO.getTargetFlags(),
case MachineOperand::MO_Register:
if (MO.getReg().isVirtual())
return MRI.getVRegDef(MO.getReg())->getOpcode();
return MO.getReg();
case MachineOperand::MO_Immediate:
return MO.getImm();
case MachineOperand::MO_TargetIndex:
return MO.getOffset() | (MO.getTargetFlags() << 16);
case MachineOperand::MO_FrameIndex:
case MachineOperand::MO_ConstantPoolIndex:
case MachineOperand::MO_JumpTableIndex:
return llvm::hash_value(MO);
// 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.
// TODO: Handle the following Index/ID/Predicate cases. They can
// be hashed on in a stable manner.
case MachineOperand::MO_CFIIndex:
case MachineOperand::MO_IntrinsicID:
case MachineOperand::MO_Predicate:
// In the cases below we havn't found a way to produce an artifact that will
// result in a stable hash, in most cases because they are pointers. We want
// stable hashes because we want the hash to be the same run to run.
case MachineOperand::MO_MachineBasicBlock:
case MachineOperand::MO_ExternalSymbol:
case MachineOperand::MO_GlobalAddress:
case MachineOperand::MO_BlockAddress:
case MachineOperand::MO_RegisterMask:
case MachineOperand::MO_RegisterLiveOut:
case MachineOperand::MO_Metadata:
case MachineOperand::MO_MCSymbol:
case MachineOperand::MO_ShuffleMask:
case MachineOperand::MO_DbgInstrRef:
return 0;
llvm_unreachable("Unexpected MachineOperandType.");
SmallVector<unsigned, 16> MIOperands = {MI.getOpcode(), MI.getFlags()};
llvm::transform(MI.uses(), std::back_inserter(MIOperands), GetHashableMO);
for (const auto *Op : MI.memoperands()) {
auto HashMI = hash_combine_range(MIOperands.begin(), MIOperands.end());
OS << format_hex_no_prefix(HashMI, 16, true);
return OS.str();
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())
if (!Candidate.getNumOperands())
// Look for instructions that define VRegs in operand 0.
MachineOperand &MO = Candidate.getOperand(0);
// Avoid non regs, instructions defining physical regs.
if (!MO.isReg() || !MO.getReg().isVirtual())
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);