LLVM 20.0.0git
MIRVRegNamerUtils.cpp
Go to the documentation of this file.
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"
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),
21 cl::desc("Use Stable Hashing for MIR VReg Renaming"));
22
23using VRegRenameMap = std::map<unsigned, unsigned>;
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
37VRegRenamer::getVRegRenameMap(const std::vector<NamedVReg> &VRegs) {
38
39 StringMap<unsigned> VRegNameCollisionMap;
40
41 auto GetUniqueVRegName = [&VRegNameCollisionMap](const NamedVReg &Reg) {
42 if (!VRegNameCollisionMap.contains(Reg.getName()))
43 VRegNameCollisionMap[Reg.getName()] = 0;
44 const unsigned Counter = ++VRegNameCollisionMap[Reg.getName()];
45 return Reg.getName() + "__" + std::to_string(Counter);
46 };
47
48 VRegRenameMap VRM;
49 for (const auto &VReg : VRegs) {
50 const unsigned Reg = VReg.getReg();
51 VRM[Reg] = createVirtualRegisterWithLowerName(Reg, GetUniqueVRegName(VReg));
52 }
53 return VRM;
54}
55
56std::string VRegRenamer::getInstructionOpcodeHash(MachineInstr &MI) {
57 std::string S;
59
61 auto Hash = stableHashValue(MI, /* HashVRegs */ true,
62 /* HashConstantPoolIndices */ true,
63 /* HashMemOperands */ true);
64 assert(Hash && "Expected non-zero Hash");
65 OS << format_hex_no_prefix(Hash, 16, true);
66 return OS.str();
67 }
68
69 // Gets a hashable artifact from a given MachineOperand (ie an unsigned).
70 auto GetHashableMO = [this](const MachineOperand &MO) -> unsigned {
71 switch (MO.getType()) {
73 return hash_combine(MO.getType(), MO.getTargetFlags(),
74 MO.getCImm()->getZExtValue());
76 return hash_combine(
77 MO.getType(), MO.getTargetFlags(),
78 MO.getFPImm()->getValueAPF().bitcastToAPInt().getZExtValue());
80 if (MO.getReg().isVirtual())
81 return MRI.getVRegDef(MO.getReg())->getOpcode();
82 return MO.getReg();
84 return MO.getImm();
86 return MO.getOffset() | (MO.getTargetFlags() << 16);
90 return llvm::hash_value(MO);
91
92 // We could explicitly handle all the types of the MachineOperand,
93 // here but we can just return a common number until we find a
94 // compelling test case where this is bad. The only side effect here
95 // is contributing to a hash collision but there's enough information
96 // (Opcodes,other registers etc) that this will likely not be a problem.
97
98 // TODO: Handle the following Index/ID/Predicate cases. They can
99 // be hashed on in a stable manner.
103
104 // In the cases below we havn't found a way to produce an artifact that will
105 // result in a stable hash, in most cases because they are pointers. We want
106 // stable hashes because we want the hash to be the same run to run.
117 return 0;
118 }
119 llvm_unreachable("Unexpected MachineOperandType.");
120 };
121
122 SmallVector<unsigned, 16> MIOperands = {MI.getOpcode(), MI.getFlags()};
123 llvm::transform(MI.uses(), std::back_inserter(MIOperands), GetHashableMO);
124
125 for (const auto *Op : MI.memoperands()) {
126 MIOperands.push_back((unsigned)Op->getSize().getValue());
127 MIOperands.push_back((unsigned)Op->getFlags());
128 MIOperands.push_back((unsigned)Op->getOffset());
129 MIOperands.push_back((unsigned)Op->getSuccessOrdering());
130 MIOperands.push_back((unsigned)Op->getAddrSpace());
131 MIOperands.push_back((unsigned)Op->getSyncScopeID());
132 MIOperands.push_back((unsigned)Op->getBaseAlign().value());
133 MIOperands.push_back((unsigned)Op->getFailureOrdering());
134 }
135
136 auto HashMI = hash_combine_range(MIOperands.begin(), MIOperands.end());
137 OS << format_hex_no_prefix(HashMI, 16, true);
138 return OS.str();
139}
140
141unsigned VRegRenamer::createVirtualRegister(unsigned VReg) {
142 assert(Register::isVirtualRegister(VReg) && "Expected Virtual Registers");
143 std::string Name = getInstructionOpcodeHash(*MRI.getVRegDef(VReg));
144 return createVirtualRegisterWithLowerName(VReg, Name);
145}
146
147bool VRegRenamer::renameInstsInMBB(MachineBasicBlock *MBB) {
148 std::vector<NamedVReg> VRegs;
149 std::string Prefix = "bb" + std::to_string(CurrentBBNumber) + "_";
150 for (MachineInstr &Candidate : *MBB) {
151 // Don't rename stores/branches.
152 if (Candidate.mayStore() || Candidate.isBranch())
153 continue;
154 if (!Candidate.getNumOperands())
155 continue;
156 // Look for instructions that define VRegs in operand 0.
157 MachineOperand &MO = Candidate.getOperand(0);
158 // Avoid non regs, instructions defining physical regs.
159 if (!MO.isReg() || !MO.getReg().isVirtual())
160 continue;
161 VRegs.push_back(
162 NamedVReg(MO.getReg(), Prefix + getInstructionOpcodeHash(Candidate)));
163 }
164
165 return VRegs.size() ? doVRegRenaming(getVRegRenameMap(VRegs)) : false;
166}
167
168unsigned VRegRenamer::createVirtualRegisterWithLowerName(unsigned VReg,
169 StringRef Name) {
170 std::string LowerName = Name.lower();
171 const TargetRegisterClass *RC = MRI.getRegClassOrNull(VReg);
172 return RC ? MRI.createVirtualRegister(RC, LowerName)
173 : MRI.createGenericVirtualRegister(MRI.getType(VReg), LowerName);
174}
MachineBasicBlock & MBB
This file contains the declarations for the subclasses of Constant, which represent the different fla...
std::string Name
IRTranslator LLVM IR MI
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"))
std::map< unsigned, unsigned > VRegRenameMap
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
raw_pwrite_stream & OS
This class represents an Operation in the Expression.
Representation of each machine instruction.
Definition: MachineInstr.h:69
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
Definition: MachineInstr.h:569
MachineOperand class - Representation of each machine instruction operand.
bool isReg() const
isReg - Tests if this is a MO_Register operand.
Register getReg() const
getReg - Returns the register number.
@ MO_CFIIndex
MCCFIInstruction index.
@ MO_Immediate
Immediate operand.
@ MO_ConstantPoolIndex
Address of indexed Constant in Constant Pool.
@ MO_MCSymbol
MCSymbol reference (for debug/eh info)
@ MO_Predicate
Generic predicate for ISel.
@ MO_GlobalAddress
Address of a global value.
@ MO_RegisterMask
Mask of preserved registers.
@ MO_ShuffleMask
Other IR Constant for ISel (shuffle masks)
@ MO_CImmediate
Immediate >64bit operand.
@ MO_BlockAddress
Address of a basic block.
@ MO_DbgInstrRef
Integer indices referring to an instruction+operand.
@ MO_MachineBasicBlock
MachineBasicBlock reference.
@ MO_FrameIndex
Abstract Stack Frame Index.
@ MO_Register
Register operand.
@ MO_ExternalSymbol
Name of external global symbol.
@ MO_IntrinsicID
Intrinsic ID for ISel.
@ MO_JumpTableIndex
Address of indexed Jump Table for switch.
@ MO_TargetIndex
Target-dependent index+offset operand.
@ MO_Metadata
Metadata reference (for debug info)
@ MO_FPImmediate
Floating-point immediate operand.
@ MO_RegisterLiveOut
Mask of live-out registers.
MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
LLT getType(Register Reg) const
Get the low-level type of Reg or LLT{} if Reg is not a generic (target independent) virtual register.
Register createGenericVirtualRegister(LLT Ty, StringRef Name="")
Create and return a new generic virtual register with low-level type Ty.
const TargetRegisterClass * getRegClassOrNull(Register Reg) const
Return the register class of Reg, or null if Reg has not been assigned a register class yet.
bool reg_empty(Register RegNo) const
reg_empty - Return true if there are no instructions using or defining the specified register (it may...
void replaceRegWith(Register FromReg, Register ToReg)
replaceRegWith - Replace all instances of FromReg with ToReg in the machine function.
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
Definition: Register.h:91
static constexpr bool isVirtualRegister(unsigned Reg)
Return true if the specified register number is in the virtual register namespace.
Definition: Register.h:71
void push_back(const T &Elt)
Definition: SmallVector.h:426
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1209
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
Definition: StringMap.h:128
bool contains(StringRef Key) const
contains - Return true if the element is in the map, false otherwise.
Definition: StringMap.h:273
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
A raw_ostream that writes to an std::string.
Definition: raw_ostream.h:661
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Reg
All possible values of the reg field in the ModR/M byte.
initializer< Ty > init(const Ty &Val)
Definition: CommandLine.h:443
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
hash_code hash_value(const FixedPointSemantics &Val)
Definition: APFixedPoint.h:127
OutputIt transform(R &&Range, OutputIt d_first, UnaryFunction F)
Wrapper function around std::transform to apply a function to a range and store the result elsewhere.
Definition: STLExtras.h:1935
stable_hash stableHashValue(const MachineOperand &MO)
FormattedNumber format_hex_no_prefix(uint64_t N, unsigned Width, bool Upper=false)
format_hex_no_prefix - Output N as a fixed width hexadecimal.
Definition: Format.h:200
hash_code hash_combine(const Ts &...args)
Combine values into a single hash_code.
Definition: Hashing.h:593
hash_code hash_combine_range(InputIteratorT first, InputIteratorT last)
Compute a hash_code for a sequence of values.
Definition: Hashing.h:471