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-exception
6//
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(Val: 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(RegNo: E.first);
30 MRI.replaceRegWith(FromReg: E.first, ToReg: E.second);
31 }
32
33 return Changed;
34}
35
36VRegRenameMap
37VRegRenamer::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(val: Counter);
44 };
45
46 VRegRenameMap VRM;
47 for (const auto &VReg : VRegs) {
48 const Register Reg = VReg.getReg();
49 VRM[Reg] = createVirtualRegisterWithLowerName(VReg: Reg, Name: 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(N: Hash, Width: 16, Upper: 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(args: MO.getType(), args: MO.getTargetFlags(),
72 args: MO.getCImm()->getZExtValue());
73 case MachineOperand::MO_FPImmediate:
74 return hash_combine(
75 args: MO.getType(), args: MO.getTargetFlags(),
76 args: MO.getFPImm()->getValueAPF().bitcastToAPInt().getZExtValue());
77 case MachineOperand::MO_Register:
78 if (MO.getReg().isVirtual())
79 return MRI.getVRegDef(Reg: 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 a
92 // compelling test case where this is bad. The only side effect here
93 // is contributing to a hash collision but there's enough information
94 // (Opcodes,other registers etc) that this will likely not be a problem.
95
96 // TODO: Handle the following Index/ID/Predicate/LaneMask cases. They can
97 // be hashed on in a stable manner.
98 case MachineOperand::MO_CFIIndex:
99 case MachineOperand::MO_IntrinsicID:
100 case MachineOperand::MO_Predicate:
101 case MachineOperand::MO_LaneMask:
102
103 // In the cases below we havn't found a way to produce an artifact that will
104 // result in a stable hash, in most cases because they are pointers. We want
105 // stable hashes because we want the hash to be the same run to run.
106 case MachineOperand::MO_MachineBasicBlock:
107 case MachineOperand::MO_ExternalSymbol:
108 case MachineOperand::MO_GlobalAddress:
109 case MachineOperand::MO_BlockAddress:
110 case MachineOperand::MO_RegisterMask:
111 case MachineOperand::MO_RegisterLiveOut:
112 case MachineOperand::MO_Metadata:
113 case MachineOperand::MO_MCSymbol:
114 case MachineOperand::MO_ShuffleMask:
115 case MachineOperand::MO_DbgInstrRef:
116 return 0;
117 }
118 llvm_unreachable("Unexpected MachineOperandType.");
119 };
120
121 SmallVector<unsigned, 16> MIOperands = {MI.getOpcode(), MI.getFlags()};
122 llvm::transform(Range: MI.uses(), d_first: std::back_inserter(x&: MIOperands), F: GetHashableMO);
123
124 for (const auto *Op : MI.memoperands()) {
125 MIOperands.push_back(Elt: (unsigned)Op->getSize().getValue());
126 MIOperands.push_back(Elt: (unsigned)Op->getFlags());
127 MIOperands.push_back(Elt: (unsigned)Op->getOffset());
128 MIOperands.push_back(Elt: (unsigned)Op->getSuccessOrdering());
129 MIOperands.push_back(Elt: (unsigned)Op->getAddrSpace());
130 MIOperands.push_back(Elt: (unsigned)Op->getSyncScopeID());
131 MIOperands.push_back(Elt: (unsigned)Op->getBaseAlign().value());
132 MIOperands.push_back(Elt: (unsigned)Op->getFailureOrdering());
133 }
134
135 auto HashMI = hash_combine_range(R&: MIOperands);
136 OS << format_hex_no_prefix(N: HashMI, Width: 16, Upper: true);
137 return OS.str();
138}
139
140Register VRegRenamer::createVirtualRegister(Register VReg) {
141 assert(VReg.isVirtual() && "Expected Virtual Registers");
142 std::string Name = getInstructionOpcodeHash(MI&: *MRI.getVRegDef(Reg: VReg));
143 return createVirtualRegisterWithLowerName(VReg, Name);
144}
145
146bool VRegRenamer::renameInstsInMBB(MachineBasicBlock *MBB) {
147 std::vector<NamedVReg> VRegs;
148 std::string Prefix = "bb" + std::to_string(val: CurrentBBNumber) + "_";
149 for (MachineInstr &Candidate : *MBB) {
150 // Don't rename stores/branches.
151 if (Candidate.mayStore() || Candidate.isBranch())
152 continue;
153 if (!Candidate.getNumOperands())
154 continue;
155 // Look for instructions that define VRegs.
156 for (MachineOperand &MO : Candidate.all_defs()) {
157 // Avoid physical reg defs.
158 if (!MO.getReg().isVirtual())
159 continue;
160 VRegs.push_back(
161 x: NamedVReg(MO.getReg(), Prefix + getInstructionOpcodeHash(MI&: Candidate)));
162 }
163 }
164
165 return !VRegs.empty() ? doVRegRenaming(VRM: getVRegRenameMap(VRegs)) : false;
166}
167
168Register VRegRenamer::createVirtualRegisterWithLowerName(Register VReg,
169 StringRef Name) {
170 std::string LowerName = Name.lower();
171 const TargetRegisterClass *RC = MRI.getRegClassOrNull(Reg: VReg);
172 return RC ? MRI.createVirtualRegister(RegClass: RC, Name: LowerName)
173 : MRI.createGenericVirtualRegister(Ty: MRI.getType(Reg: VReg), Name: LowerName);
174}
175