1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-23 03:02:36 +01:00
llvm-mirror/lib/CodeGen/MIRVRegNamerUtils.cpp
Puyan Lotfi de3532220a [MIRVRegNamer] Experimental MachineInstr stable hashing (Fowler-Noll-Vo)
This hashing scheme has been useful out of tree, and I want to start
experimenting with it. Specifically I want to experiment on the
MIRVRegNamer, MIRCanononicalizer, and eventually the MachineOutliner.

This diff is a first step, that optionally brings stable hashing to the
MIRVRegNamer (and as a result, the MIRCanonicalizer).  We've tested this
hashing scheme on a lot of MachineOperand types that llvm::hash_value
can not handle in a stable manner.

This stable hashing was also the basis for

"Global Machine Outliner for ThinLTO" in EuroLLVM 2020

http://llvm.org/devmtg/2020-04/talks.html#TechTalk_58

Credits: Kyungwoo Lee, Nikolai Tillmann

Differential Revision: https://reviews.llvm.org/D86952
2020-09-03 16:13:09 -04:00

173 lines
6.6 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/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/MachineStableHash.h"
#include "llvm/IR/Constants.h"
#include "llvm/Support/Debug.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::Hidden,
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;
}
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);
if (UseStableNamerHash) {
auto Hash = stableHashValue(MI, /* HashVRegs */ true,
/* HashConstantPoolIndices */ true,
/* HashMemOperands */ true);
assert(Hash && "Expected non-zero Hash");
return std::to_string(Hash).substr(0, 5);
}
// 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(),
MO.getCImm()->getZExtValue());
case MachineOperand::MO_FPImmediate:
return hash_combine(
MO.getType(), MO.getTargetFlags(),
MO.getFPImm()->getValueAPF().bitcastToAPInt().getZExtValue());
case MachineOperand::MO_Register:
if (Register::isVirtualRegister(MO.getReg()))
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:
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()) {
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->getBaseAlign().value());
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);
}