18bcb0991SDimitry Andric //===---------- MIRVRegNamerUtils.cpp - MIR VReg Renaming Utilities -------===// 28bcb0991SDimitry Andric // 38bcb0991SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 48bcb0991SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 58bcb0991SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 68bcb0991SDimitry Andric // 78bcb0991SDimitry Andric //===----------------------------------------------------------------------===// 88bcb0991SDimitry Andric 98bcb0991SDimitry Andric #include "MIRVRegNamerUtils.h" 105ffd83dbSDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 11e8d8bef9SDimitry Andric #include "llvm/CodeGen/MachineStableHash.h" 125ffd83dbSDimitry Andric #include "llvm/IR/Constants.h" 138bcb0991SDimitry Andric 148bcb0991SDimitry Andric using namespace llvm; 158bcb0991SDimitry Andric 168bcb0991SDimitry Andric #define DEBUG_TYPE "mir-vregnamer-utils" 178bcb0991SDimitry Andric 18e8d8bef9SDimitry Andric static cl::opt<bool> 19e8d8bef9SDimitry Andric UseStableNamerHash("mir-vreg-namer-use-stable-hash", cl::init(false), 20e8d8bef9SDimitry Andric cl::Hidden, 21e8d8bef9SDimitry Andric cl::desc("Use Stable Hashing for MIR VReg Renaming")); 22e8d8bef9SDimitry Andric 23480093f4SDimitry Andric using VRegRenameMap = std::map<unsigned, unsigned>; 248bcb0991SDimitry Andric 25480093f4SDimitry Andric bool VRegRenamer::doVRegRenaming(const VRegRenameMap &VRM) { 26480093f4SDimitry Andric bool Changed = false; 278bcb0991SDimitry Andric 28480093f4SDimitry Andric for (const auto &E : VRM) { 29480093f4SDimitry Andric Changed = Changed || !MRI.reg_empty(E.first); 30480093f4SDimitry Andric MRI.replaceRegWith(E.first, E.second); 318bcb0991SDimitry Andric } 328bcb0991SDimitry Andric 33480093f4SDimitry Andric return Changed; 348bcb0991SDimitry Andric } 35480093f4SDimitry Andric 36480093f4SDimitry Andric VRegRenameMap 37480093f4SDimitry Andric VRegRenamer::getVRegRenameMap(const std::vector<NamedVReg> &VRegs) { 38480093f4SDimitry Andric 39480093f4SDimitry Andric StringMap<unsigned> VRegNameCollisionMap; 40480093f4SDimitry Andric 41480093f4SDimitry Andric auto GetUniqueVRegName = [&VRegNameCollisionMap](const NamedVReg &Reg) { 4206c3fb27SDimitry Andric if (!VRegNameCollisionMap.contains(Reg.getName())) 43480093f4SDimitry Andric VRegNameCollisionMap[Reg.getName()] = 0; 44480093f4SDimitry Andric const unsigned Counter = ++VRegNameCollisionMap[Reg.getName()]; 45480093f4SDimitry Andric return Reg.getName() + "__" + std::to_string(Counter); 468bcb0991SDimitry Andric }; 478bcb0991SDimitry Andric 48480093f4SDimitry Andric VRegRenameMap VRM; 49480093f4SDimitry Andric for (const auto &VReg : VRegs) { 50480093f4SDimitry Andric const unsigned Reg = VReg.getReg(); 51480093f4SDimitry Andric VRM[Reg] = createVirtualRegisterWithLowerName(Reg, GetUniqueVRegName(VReg)); 528bcb0991SDimitry Andric } 53480093f4SDimitry Andric return VRM; 548bcb0991SDimitry Andric } 558bcb0991SDimitry Andric 56480093f4SDimitry Andric std::string VRegRenamer::getInstructionOpcodeHash(MachineInstr &MI) { 578bcb0991SDimitry Andric std::string S; 588bcb0991SDimitry Andric raw_string_ostream OS(S); 59480093f4SDimitry Andric 60e8d8bef9SDimitry Andric if (UseStableNamerHash) { 61e8d8bef9SDimitry Andric auto Hash = stableHashValue(MI, /* HashVRegs */ true, 62e8d8bef9SDimitry Andric /* HashConstantPoolIndices */ true, 63e8d8bef9SDimitry Andric /* HashMemOperands */ true); 64e8d8bef9SDimitry Andric assert(Hash && "Expected non-zero Hash"); 65bdd1243dSDimitry Andric OS << format_hex_no_prefix(Hash, 16, true); 66bdd1243dSDimitry Andric return OS.str(); 67e8d8bef9SDimitry Andric } 68e8d8bef9SDimitry Andric 69480093f4SDimitry Andric // Gets a hashable artifact from a given MachineOperand (ie an unsigned). 70480093f4SDimitry Andric auto GetHashableMO = [this](const MachineOperand &MO) -> unsigned { 71480093f4SDimitry Andric switch (MO.getType()) { 72480093f4SDimitry Andric case MachineOperand::MO_CImmediate: 73480093f4SDimitry Andric return hash_combine(MO.getType(), MO.getTargetFlags(), 74480093f4SDimitry Andric MO.getCImm()->getZExtValue()); 75480093f4SDimitry Andric case MachineOperand::MO_FPImmediate: 76480093f4SDimitry Andric return hash_combine( 77480093f4SDimitry Andric MO.getType(), MO.getTargetFlags(), 78480093f4SDimitry Andric MO.getFPImm()->getValueAPF().bitcastToAPInt().getZExtValue()); 79480093f4SDimitry Andric case MachineOperand::MO_Register: 80bdd1243dSDimitry Andric if (MO.getReg().isVirtual()) 81480093f4SDimitry Andric return MRI.getVRegDef(MO.getReg())->getOpcode(); 82480093f4SDimitry Andric return MO.getReg(); 83480093f4SDimitry Andric case MachineOperand::MO_Immediate: 84480093f4SDimitry Andric return MO.getImm(); 85480093f4SDimitry Andric case MachineOperand::MO_TargetIndex: 86480093f4SDimitry Andric return MO.getOffset() | (MO.getTargetFlags() << 16); 87480093f4SDimitry Andric case MachineOperand::MO_FrameIndex: 885ffd83dbSDimitry Andric case MachineOperand::MO_ConstantPoolIndex: 895ffd83dbSDimitry Andric case MachineOperand::MO_JumpTableIndex: 90480093f4SDimitry Andric return llvm::hash_value(MO); 91480093f4SDimitry Andric 92480093f4SDimitry Andric // We could explicitly handle all the types of the MachineOperand, 93480093f4SDimitry Andric // here but we can just return a common number until we find a 94480093f4SDimitry Andric // compelling test case where this is bad. The only side effect here 95480093f4SDimitry Andric // is contributing to a hash collision but there's enough information 96480093f4SDimitry Andric // (Opcodes,other registers etc) that this will likely not be a problem. 97480093f4SDimitry Andric 98480093f4SDimitry Andric // TODO: Handle the following Index/ID/Predicate cases. They can 99480093f4SDimitry Andric // be hashed on in a stable manner. 100480093f4SDimitry Andric case MachineOperand::MO_CFIIndex: 101480093f4SDimitry Andric case MachineOperand::MO_IntrinsicID: 102480093f4SDimitry Andric case MachineOperand::MO_Predicate: 103480093f4SDimitry Andric 104480093f4SDimitry Andric // In the cases below we havn't found a way to produce an artifact that will 105480093f4SDimitry Andric // result in a stable hash, in most cases because they are pointers. We want 106480093f4SDimitry Andric // stable hashes because we want the hash to be the same run to run. 107480093f4SDimitry Andric case MachineOperand::MO_MachineBasicBlock: 108480093f4SDimitry Andric case MachineOperand::MO_ExternalSymbol: 109480093f4SDimitry Andric case MachineOperand::MO_GlobalAddress: 110480093f4SDimitry Andric case MachineOperand::MO_BlockAddress: 111480093f4SDimitry Andric case MachineOperand::MO_RegisterMask: 112480093f4SDimitry Andric case MachineOperand::MO_RegisterLiveOut: 113480093f4SDimitry Andric case MachineOperand::MO_Metadata: 114480093f4SDimitry Andric case MachineOperand::MO_MCSymbol: 115480093f4SDimitry Andric case MachineOperand::MO_ShuffleMask: 116bdd1243dSDimitry Andric case MachineOperand::MO_DbgInstrRef: 117480093f4SDimitry Andric return 0; 118480093f4SDimitry Andric } 119480093f4SDimitry Andric llvm_unreachable("Unexpected MachineOperandType."); 120480093f4SDimitry Andric }; 121480093f4SDimitry Andric 122480093f4SDimitry Andric SmallVector<unsigned, 16> MIOperands = {MI.getOpcode(), MI.getFlags()}; 123480093f4SDimitry Andric llvm::transform(MI.uses(), std::back_inserter(MIOperands), GetHashableMO); 124480093f4SDimitry Andric 125480093f4SDimitry Andric for (const auto *Op : MI.memoperands()) { 126*0fca6ea1SDimitry Andric MIOperands.push_back((unsigned)Op->getSize().getValue()); 127480093f4SDimitry Andric MIOperands.push_back((unsigned)Op->getFlags()); 128480093f4SDimitry Andric MIOperands.push_back((unsigned)Op->getOffset()); 129fe6060f1SDimitry Andric MIOperands.push_back((unsigned)Op->getSuccessOrdering()); 130480093f4SDimitry Andric MIOperands.push_back((unsigned)Op->getAddrSpace()); 131480093f4SDimitry Andric MIOperands.push_back((unsigned)Op->getSyncScopeID()); 1325ffd83dbSDimitry Andric MIOperands.push_back((unsigned)Op->getBaseAlign().value()); 133480093f4SDimitry Andric MIOperands.push_back((unsigned)Op->getFailureOrdering()); 1348bcb0991SDimitry Andric } 1358bcb0991SDimitry Andric 136480093f4SDimitry Andric auto HashMI = hash_combine_range(MIOperands.begin(), MIOperands.end()); 137bdd1243dSDimitry Andric OS << format_hex_no_prefix(HashMI, 16, true); 138bdd1243dSDimitry Andric return OS.str(); 139480093f4SDimitry Andric } 140480093f4SDimitry Andric 141480093f4SDimitry Andric unsigned VRegRenamer::createVirtualRegister(unsigned VReg) { 142480093f4SDimitry Andric assert(Register::isVirtualRegister(VReg) && "Expected Virtual Registers"); 143480093f4SDimitry Andric std::string Name = getInstructionOpcodeHash(*MRI.getVRegDef(VReg)); 144480093f4SDimitry Andric return createVirtualRegisterWithLowerName(VReg, Name); 145480093f4SDimitry Andric } 146480093f4SDimitry Andric 147480093f4SDimitry Andric bool VRegRenamer::renameInstsInMBB(MachineBasicBlock *MBB) { 148480093f4SDimitry Andric std::vector<NamedVReg> VRegs; 149480093f4SDimitry Andric std::string Prefix = "bb" + std::to_string(CurrentBBNumber) + "_"; 150480093f4SDimitry Andric for (MachineInstr &Candidate : *MBB) { 151480093f4SDimitry Andric // Don't rename stores/branches. 152480093f4SDimitry Andric if (Candidate.mayStore() || Candidate.isBranch()) 153480093f4SDimitry Andric continue; 154480093f4SDimitry Andric if (!Candidate.getNumOperands()) 155480093f4SDimitry Andric continue; 156480093f4SDimitry Andric // Look for instructions that define VRegs in operand 0. 157480093f4SDimitry Andric MachineOperand &MO = Candidate.getOperand(0); 158480093f4SDimitry Andric // Avoid non regs, instructions defining physical regs. 159bdd1243dSDimitry Andric if (!MO.isReg() || !MO.getReg().isVirtual()) 160480093f4SDimitry Andric continue; 161480093f4SDimitry Andric VRegs.push_back( 162480093f4SDimitry Andric NamedVReg(MO.getReg(), Prefix + getInstructionOpcodeHash(Candidate))); 163480093f4SDimitry Andric } 164480093f4SDimitry Andric 165480093f4SDimitry Andric return VRegs.size() ? doVRegRenaming(getVRegRenameMap(VRegs)) : false; 166480093f4SDimitry Andric } 167480093f4SDimitry Andric 168480093f4SDimitry Andric unsigned VRegRenamer::createVirtualRegisterWithLowerName(unsigned VReg, 169480093f4SDimitry Andric StringRef Name) { 170480093f4SDimitry Andric std::string LowerName = Name.lower(); 171480093f4SDimitry Andric const TargetRegisterClass *RC = MRI.getRegClassOrNull(VReg); 172480093f4SDimitry Andric return RC ? MRI.createVirtualRegister(RC, LowerName) 173480093f4SDimitry Andric : MRI.createGenericVirtualRegister(MRI.getType(VReg), LowerName); 1748bcb0991SDimitry Andric } 175