1 //===---------- MIRVRegNamerUtils.cpp - MIR VReg Renaming Utilities -------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "MIRVRegNamerUtils.h"
10 #include "llvm/CodeGen/MachineRegisterInfo.h"
11 #include "llvm/CodeGen/MachineStableHash.h"
12 #include "llvm/IR/Constants.h"
16 #define DEBUG_TYPE "mir-vregnamer-utils"
19 UseStableNamerHash("mir-vreg-namer-use-stable-hash", cl::init(false),
21 cl::desc("Use Stable Hashing for MIR VReg Renaming"));
23 using VRegRenameMap
= std::map
<unsigned, unsigned>;
25 bool VRegRenamer::doVRegRenaming(const VRegRenameMap
&VRM
) {
28 for (const auto &E
: VRM
) {
29 Changed
= Changed
|| !MRI
.reg_empty(E
.first
);
30 MRI
.replaceRegWith(E
.first
, E
.second
);
37 VRegRenamer::getVRegRenameMap(const std::vector
<NamedVReg
> &VRegs
) {
39 StringMap
<unsigned> VRegNameCollisionMap
;
41 auto GetUniqueVRegName
= [&VRegNameCollisionMap
](const NamedVReg
&Reg
) {
42 const unsigned Counter
= ++VRegNameCollisionMap
[Reg
.getName()];
43 return Reg
.getName() + "__" + std::to_string(Counter
);
47 for (const auto &VReg
: VRegs
) {
48 const unsigned Reg
= VReg
.getReg();
49 VRM
[Reg
] = createVirtualRegisterWithLowerName(Reg
, GetUniqueVRegName(VReg
));
54 std::string
VRegRenamer::getInstructionOpcodeHash(MachineInstr
&MI
) {
56 raw_string_ostream
OS(S
);
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);
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
:
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();
81 case MachineOperand::MO_Immediate
:
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
);
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.
96 // TODO: Handle the following Index/ID/Predicate 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
:
102 // In the cases below we havn't found a way to produce an artifact that will
103 // result in a stable hash, in most cases because they are pointers. We want
104 // 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
:
117 llvm_unreachable("Unexpected MachineOperandType.");
120 SmallVector
<unsigned, 16> MIOperands
= {MI
.getOpcode(), MI
.getFlags()};
121 llvm::transform(MI
.uses(), std::back_inserter(MIOperands
), GetHashableMO
);
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());
134 auto HashMI
= hash_combine_range(MIOperands
.begin(), MIOperands
.end());
135 OS
<< format_hex_no_prefix(HashMI
, 16, true);
139 unsigned VRegRenamer::createVirtualRegister(unsigned VReg
) {
140 assert(Register::isVirtualRegister(VReg
) && "Expected Virtual Registers");
141 std::string Name
= getInstructionOpcodeHash(*MRI
.getVRegDef(VReg
));
142 return createVirtualRegisterWithLowerName(VReg
, Name
);
145 bool 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())
152 if (!Candidate
.getNumOperands())
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())
160 NamedVReg(MO
.getReg(), Prefix
+ getInstructionOpcodeHash(Candidate
)));
163 return VRegs
.size() ? doVRegRenaming(getVRegRenameMap(VRegs
)) : false;
166 unsigned VRegRenamer::createVirtualRegisterWithLowerName(unsigned VReg
,
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
);