173 lines · cpp
1//===---------- MIRVRegNamerUtils.cpp - MIR VReg Renaming Utilities -------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "MIRVRegNamerUtils.h"10#include "llvm/CodeGen/MachineRegisterInfo.h"11#include "llvm/CodeGen/MachineStableHash.h"12#include "llvm/IR/Constants.h"13 14using namespace llvm;15 16#define DEBUG_TYPE "mir-vregnamer-utils"17 18static cl::opt<bool>19 UseStableNamerHash("mir-vreg-namer-use-stable-hash", cl::init(false),20 cl::Hidden,21 cl::desc("Use Stable Hashing for MIR VReg Renaming"));22 23using VRegRenameMap = std::map<Register, Register>;24 25bool VRegRenamer::doVRegRenaming(const VRegRenameMap &VRM) {26 bool Changed = false;27 28 for (const auto &E : VRM) {29 Changed = Changed || !MRI.reg_empty(E.first);30 MRI.replaceRegWith(E.first, E.second);31 }32 33 return Changed;34}35 36VRegRenameMap37VRegRenamer::getVRegRenameMap(const std::vector<NamedVReg> &VRegs) {38 39 StringMap<unsigned> VRegNameCollisionMap;40 41 auto GetUniqueVRegName = [&VRegNameCollisionMap](const NamedVReg &Reg) {42 const unsigned Counter = ++VRegNameCollisionMap[Reg.getName()];43 return Reg.getName() + "__" + std::to_string(Counter);44 };45 46 VRegRenameMap VRM;47 for (const auto &VReg : VRegs) {48 const Register Reg = VReg.getReg();49 VRM[Reg] = createVirtualRegisterWithLowerName(Reg, GetUniqueVRegName(VReg));50 }51 return VRM;52}53 54std::string VRegRenamer::getInstructionOpcodeHash(MachineInstr &MI) {55 std::string S;56 raw_string_ostream OS(S);57 58 if (UseStableNamerHash) {59 auto Hash = stableHashValue(MI, /* HashVRegs */ true,60 /* HashConstantPoolIndices */ true,61 /* HashMemOperands */ true);62 assert(Hash && "Expected non-zero Hash");63 OS << format_hex_no_prefix(Hash, 16, true);64 return OS.str();65 }66 67 // Gets a hashable artifact from a given MachineOperand (ie an unsigned).68 auto GetHashableMO = [this](const MachineOperand &MO) -> unsigned {69 switch (MO.getType()) {70 case MachineOperand::MO_CImmediate:71 return hash_combine(MO.getType(), MO.getTargetFlags(),72 MO.getCImm()->getZExtValue());73 case MachineOperand::MO_FPImmediate:74 return hash_combine(75 MO.getType(), MO.getTargetFlags(),76 MO.getFPImm()->getValueAPF().bitcastToAPInt().getZExtValue());77 case MachineOperand::MO_Register:78 if (MO.getReg().isVirtual())79 return MRI.getVRegDef(MO.getReg())->getOpcode();80 return MO.getReg().id();81 case MachineOperand::MO_Immediate:82 return MO.getImm();83 case MachineOperand::MO_TargetIndex:84 return MO.getOffset() | (MO.getTargetFlags() << 16);85 case MachineOperand::MO_FrameIndex:86 case MachineOperand::MO_ConstantPoolIndex:87 case MachineOperand::MO_JumpTableIndex:88 return llvm::hash_value(MO);89 90 // We could explicitly handle all the types of the MachineOperand,91 // here but we can just return a common number until we find a92 // compelling test case where this is bad. The only side effect here93 // is contributing to a hash collision but there's enough information94 // (Opcodes,other registers etc) that this will likely not be a problem.95 96 // TODO: Handle the following Index/ID/Predicate cases. They can97 // be hashed on in a stable manner.98 case MachineOperand::MO_CFIIndex:99 case MachineOperand::MO_IntrinsicID:100 case MachineOperand::MO_Predicate:101 102 // In the cases below we havn't found a way to produce an artifact that will103 // result in a stable hash, in most cases because they are pointers. We want104 // stable hashes because we want the hash to be the same run to run.105 case MachineOperand::MO_MachineBasicBlock:106 case MachineOperand::MO_ExternalSymbol:107 case MachineOperand::MO_GlobalAddress:108 case MachineOperand::MO_BlockAddress:109 case MachineOperand::MO_RegisterMask:110 case MachineOperand::MO_RegisterLiveOut:111 case MachineOperand::MO_Metadata:112 case MachineOperand::MO_MCSymbol:113 case MachineOperand::MO_ShuffleMask:114 case MachineOperand::MO_DbgInstrRef:115 return 0;116 }117 llvm_unreachable("Unexpected MachineOperandType.");118 };119 120 SmallVector<unsigned, 16> MIOperands = {MI.getOpcode(), MI.getFlags()};121 llvm::transform(MI.uses(), std::back_inserter(MIOperands), GetHashableMO);122 123 for (const auto *Op : MI.memoperands()) {124 MIOperands.push_back((unsigned)Op->getSize().getValue());125 MIOperands.push_back((unsigned)Op->getFlags());126 MIOperands.push_back((unsigned)Op->getOffset());127 MIOperands.push_back((unsigned)Op->getSuccessOrdering());128 MIOperands.push_back((unsigned)Op->getAddrSpace());129 MIOperands.push_back((unsigned)Op->getSyncScopeID());130 MIOperands.push_back((unsigned)Op->getBaseAlign().value());131 MIOperands.push_back((unsigned)Op->getFailureOrdering());132 }133 134 auto HashMI = hash_combine_range(MIOperands);135 OS << format_hex_no_prefix(HashMI, 16, true);136 return OS.str();137}138 139Register VRegRenamer::createVirtualRegister(Register VReg) {140 assert(VReg.isVirtual() && "Expected Virtual Registers");141 std::string Name = getInstructionOpcodeHash(*MRI.getVRegDef(VReg));142 return createVirtualRegisterWithLowerName(VReg, Name);143}144 145bool VRegRenamer::renameInstsInMBB(MachineBasicBlock *MBB) {146 std::vector<NamedVReg> VRegs;147 std::string Prefix = "bb" + std::to_string(CurrentBBNumber) + "_";148 for (MachineInstr &Candidate : *MBB) {149 // Don't rename stores/branches.150 if (Candidate.mayStore() || Candidate.isBranch())151 continue;152 if (!Candidate.getNumOperands())153 continue;154 // Look for instructions that define VRegs in operand 0.155 MachineOperand &MO = Candidate.getOperand(0);156 // Avoid non regs, instructions defining physical regs.157 if (!MO.isReg() || !MO.getReg().isVirtual())158 continue;159 VRegs.push_back(160 NamedVReg(MO.getReg(), Prefix + getInstructionOpcodeHash(Candidate)));161 }162 163 return !VRegs.empty() ? doVRegRenaming(getVRegRenameMap(VRegs)) : false;164}165 166Register VRegRenamer::createVirtualRegisterWithLowerName(Register VReg,167 StringRef Name) {168 std::string LowerName = Name.lower();169 const TargetRegisterClass *RC = MRI.getRegClassOrNull(VReg);170 return RC ? MRI.createVirtualRegister(RC, LowerName)171 : MRI.createGenericVirtualRegister(MRI.getType(VReg), LowerName);172}173