1b60736ecSDimitry Andric //===- lib/CodeGen/MachineStableHash.cpp ----------------------------------===//
2b60736ecSDimitry Andric //
3b60736ecSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4b60736ecSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5b60736ecSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6b60736ecSDimitry Andric //
7b60736ecSDimitry Andric //===----------------------------------------------------------------------===//
8b60736ecSDimitry Andric //
9b60736ecSDimitry Andric // Stable hashing for MachineInstr and MachineOperand. Useful or getting a
10b60736ecSDimitry Andric // hash across runs, modules, etc.
11b60736ecSDimitry Andric //
12b60736ecSDimitry Andric //===----------------------------------------------------------------------===//
13b60736ecSDimitry Andric
14b60736ecSDimitry Andric #include "llvm/CodeGen/MachineStableHash.h"
15145449b1SDimitry Andric #include "llvm/ADT/APFloat.h"
16145449b1SDimitry Andric #include "llvm/ADT/APInt.h"
17145449b1SDimitry Andric #include "llvm/ADT/Hashing.h"
18145449b1SDimitry Andric #include "llvm/ADT/STLExtras.h"
19145449b1SDimitry Andric #include "llvm/ADT/SmallVector.h"
20b1c73532SDimitry Andric #include "llvm/ADT/StableHashing.h"
21b60736ecSDimitry Andric #include "llvm/ADT/Statistic.h"
22145449b1SDimitry Andric #include "llvm/ADT/ilist_iterator.h"
23145449b1SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h"
24145449b1SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
25b60736ecSDimitry Andric #include "llvm/CodeGen/MachineInstr.h"
26145449b1SDimitry Andric #include "llvm/CodeGen/MachineInstrBundleIterator.h"
27145449b1SDimitry Andric #include "llvm/CodeGen/MachineMemOperand.h"
28b60736ecSDimitry Andric #include "llvm/CodeGen/MachineOperand.h"
29b60736ecSDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
30145449b1SDimitry Andric #include "llvm/CodeGen/Register.h"
31b60736ecSDimitry Andric #include "llvm/Config/llvm-config.h"
32b60736ecSDimitry Andric #include "llvm/IR/Constants.h"
33145449b1SDimitry Andric #include "llvm/MC/MCSymbol.h"
34145449b1SDimitry Andric #include "llvm/Support/Alignment.h"
35145449b1SDimitry Andric #include "llvm/Support/ErrorHandling.h"
36b60736ecSDimitry Andric
37b60736ecSDimitry Andric #define DEBUG_TYPE "machine-stable-hash"
38b60736ecSDimitry Andric
39b60736ecSDimitry Andric using namespace llvm;
40b60736ecSDimitry Andric
41b60736ecSDimitry Andric STATISTIC(StableHashBailingMachineBasicBlock,
42b60736ecSDimitry Andric "Number of encountered unsupported MachineOperands that were "
43b60736ecSDimitry Andric "MachineBasicBlocks while computing stable hashes");
44b60736ecSDimitry Andric STATISTIC(StableHashBailingConstantPoolIndex,
45b60736ecSDimitry Andric "Number of encountered unsupported MachineOperands that were "
46b60736ecSDimitry Andric "ConstantPoolIndex while computing stable hashes");
47b60736ecSDimitry Andric STATISTIC(StableHashBailingTargetIndexNoName,
48b60736ecSDimitry Andric "Number of encountered unsupported MachineOperands that were "
49b60736ecSDimitry Andric "TargetIndex with no name");
50b60736ecSDimitry Andric STATISTIC(StableHashBailingGlobalAddress,
51b60736ecSDimitry Andric "Number of encountered unsupported MachineOperands that were "
52b60736ecSDimitry Andric "GlobalAddress while computing stable hashes");
53b60736ecSDimitry Andric STATISTIC(StableHashBailingBlockAddress,
54b60736ecSDimitry Andric "Number of encountered unsupported MachineOperands that were "
55b60736ecSDimitry Andric "BlockAddress while computing stable hashes");
56b60736ecSDimitry Andric STATISTIC(StableHashBailingMetadataUnsupported,
57b60736ecSDimitry Andric "Number of encountered unsupported MachineOperands that were "
58b60736ecSDimitry Andric "Metadata of an unsupported kind while computing stable hashes");
59b60736ecSDimitry Andric
stableHashValue(const MachineOperand & MO)60b60736ecSDimitry Andric stable_hash llvm::stableHashValue(const MachineOperand &MO) {
61b60736ecSDimitry Andric switch (MO.getType()) {
62b60736ecSDimitry Andric case MachineOperand::MO_Register:
63e3b55780SDimitry Andric if (MO.getReg().isVirtual()) {
64b60736ecSDimitry Andric const MachineRegisterInfo &MRI = MO.getParent()->getMF()->getRegInfo();
65145449b1SDimitry Andric SmallVector<unsigned> DefOpcodes;
66145449b1SDimitry Andric for (auto &Def : MRI.def_instructions(MO.getReg()))
67145449b1SDimitry Andric DefOpcodes.push_back(Def.getOpcode());
68145449b1SDimitry Andric return hash_combine_range(DefOpcodes.begin(), DefOpcodes.end());
69b60736ecSDimitry Andric }
70b60736ecSDimitry Andric
71b60736ecSDimitry Andric // Register operands don't have target flags.
72b60736ecSDimitry Andric return stable_hash_combine(MO.getType(), MO.getReg(), MO.getSubReg(),
73b60736ecSDimitry Andric MO.isDef());
74b60736ecSDimitry Andric case MachineOperand::MO_Immediate:
75b60736ecSDimitry Andric return stable_hash_combine(MO.getType(), MO.getTargetFlags(), MO.getImm());
76b60736ecSDimitry Andric case MachineOperand::MO_CImmediate:
77b60736ecSDimitry Andric case MachineOperand::MO_FPImmediate: {
78b60736ecSDimitry Andric auto Val = MO.isCImm() ? MO.getCImm()->getValue()
79b60736ecSDimitry Andric : MO.getFPImm()->getValueAPF().bitcastToAPInt();
80b60736ecSDimitry Andric auto ValHash =
81b60736ecSDimitry Andric stable_hash_combine_array(Val.getRawData(), Val.getNumWords());
82b60736ecSDimitry Andric return hash_combine(MO.getType(), MO.getTargetFlags(), ValHash);
83b60736ecSDimitry Andric }
84b60736ecSDimitry Andric
85b60736ecSDimitry Andric case MachineOperand::MO_MachineBasicBlock:
86b60736ecSDimitry Andric StableHashBailingMachineBasicBlock++;
87b60736ecSDimitry Andric return 0;
88b60736ecSDimitry Andric case MachineOperand::MO_ConstantPoolIndex:
89b60736ecSDimitry Andric StableHashBailingConstantPoolIndex++;
90b60736ecSDimitry Andric return 0;
91b60736ecSDimitry Andric case MachineOperand::MO_BlockAddress:
92b60736ecSDimitry Andric StableHashBailingBlockAddress++;
93b60736ecSDimitry Andric return 0;
94b60736ecSDimitry Andric case MachineOperand::MO_Metadata:
95b60736ecSDimitry Andric StableHashBailingMetadataUnsupported++;
96b60736ecSDimitry Andric return 0;
97b60736ecSDimitry Andric case MachineOperand::MO_GlobalAddress:
98b60736ecSDimitry Andric StableHashBailingGlobalAddress++;
99b60736ecSDimitry Andric return 0;
100b60736ecSDimitry Andric case MachineOperand::MO_TargetIndex: {
101b60736ecSDimitry Andric if (const char *Name = MO.getTargetIndexName())
102b60736ecSDimitry Andric return stable_hash_combine(MO.getType(), MO.getTargetFlags(),
103b60736ecSDimitry Andric stable_hash_combine_string(Name),
104b60736ecSDimitry Andric MO.getOffset());
105b60736ecSDimitry Andric StableHashBailingTargetIndexNoName++;
106b60736ecSDimitry Andric return 0;
107b60736ecSDimitry Andric }
108b60736ecSDimitry Andric
109b60736ecSDimitry Andric case MachineOperand::MO_FrameIndex:
110b60736ecSDimitry Andric case MachineOperand::MO_JumpTableIndex:
111b60736ecSDimitry Andric return stable_hash_combine(MO.getType(), MO.getTargetFlags(),
112b60736ecSDimitry Andric MO.getIndex());
113b60736ecSDimitry Andric
114b60736ecSDimitry Andric case MachineOperand::MO_ExternalSymbol:
115b60736ecSDimitry Andric return hash_combine(MO.getType(), MO.getTargetFlags(), MO.getOffset(),
116b60736ecSDimitry Andric stable_hash_combine_string(MO.getSymbolName()));
117b60736ecSDimitry Andric
118b60736ecSDimitry Andric case MachineOperand::MO_RegisterMask:
119e3b55780SDimitry Andric case MachineOperand::MO_RegisterLiveOut: {
120e3b55780SDimitry Andric if (const MachineInstr *MI = MO.getParent()) {
121e3b55780SDimitry Andric if (const MachineBasicBlock *MBB = MI->getParent()) {
122e3b55780SDimitry Andric if (const MachineFunction *MF = MBB->getParent()) {
123e3b55780SDimitry Andric const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo();
124e3b55780SDimitry Andric unsigned RegMaskSize =
125e3b55780SDimitry Andric MachineOperand::getRegMaskSize(TRI->getNumRegs());
126e3b55780SDimitry Andric const uint32_t *RegMask = MO.getRegMask();
127e3b55780SDimitry Andric std::vector<llvm::stable_hash> RegMaskHashes(RegMask,
128e3b55780SDimitry Andric RegMask + RegMaskSize);
129e3b55780SDimitry Andric return hash_combine(MO.getType(), MO.getTargetFlags(),
130e3b55780SDimitry Andric stable_hash_combine_array(RegMaskHashes.data(),
131e3b55780SDimitry Andric RegMaskHashes.size()));
132e3b55780SDimitry Andric }
133e3b55780SDimitry Andric }
134e3b55780SDimitry Andric }
135e3b55780SDimitry Andric
136e3b55780SDimitry Andric assert(0 && "MachineOperand not associated with any MachineFunction");
137e3b55780SDimitry Andric return hash_combine(MO.getType(), MO.getTargetFlags());
138e3b55780SDimitry Andric }
139b60736ecSDimitry Andric
140b60736ecSDimitry Andric case MachineOperand::MO_ShuffleMask: {
141b60736ecSDimitry Andric std::vector<llvm::stable_hash> ShuffleMaskHashes;
142b60736ecSDimitry Andric
143b60736ecSDimitry Andric llvm::transform(
144b60736ecSDimitry Andric MO.getShuffleMask(), std::back_inserter(ShuffleMaskHashes),
145b60736ecSDimitry Andric [](int S) -> llvm::stable_hash { return llvm::stable_hash(S); });
146b60736ecSDimitry Andric
147b60736ecSDimitry Andric return hash_combine(MO.getType(), MO.getTargetFlags(),
148b60736ecSDimitry Andric stable_hash_combine_array(ShuffleMaskHashes.data(),
149b60736ecSDimitry Andric ShuffleMaskHashes.size()));
150b60736ecSDimitry Andric }
151b60736ecSDimitry Andric case MachineOperand::MO_MCSymbol: {
152b60736ecSDimitry Andric auto SymbolName = MO.getMCSymbol()->getName();
153b60736ecSDimitry Andric return hash_combine(MO.getType(), MO.getTargetFlags(),
154b60736ecSDimitry Andric stable_hash_combine_string(SymbolName));
155b60736ecSDimitry Andric }
156b60736ecSDimitry Andric case MachineOperand::MO_CFIIndex:
157b60736ecSDimitry Andric return stable_hash_combine(MO.getType(), MO.getTargetFlags(),
158b60736ecSDimitry Andric MO.getCFIIndex());
159b60736ecSDimitry Andric case MachineOperand::MO_IntrinsicID:
160b60736ecSDimitry Andric return stable_hash_combine(MO.getType(), MO.getTargetFlags(),
161b60736ecSDimitry Andric MO.getIntrinsicID());
162b60736ecSDimitry Andric case MachineOperand::MO_Predicate:
163b60736ecSDimitry Andric return stable_hash_combine(MO.getType(), MO.getTargetFlags(),
164b60736ecSDimitry Andric MO.getPredicate());
165e3b55780SDimitry Andric case MachineOperand::MO_DbgInstrRef:
166e3b55780SDimitry Andric return stable_hash_combine(MO.getType(), MO.getInstrRefInstrIndex(),
167e3b55780SDimitry Andric MO.getInstrRefOpIndex());
168b60736ecSDimitry Andric }
169b60736ecSDimitry Andric llvm_unreachable("Invalid machine operand type");
170b60736ecSDimitry Andric }
171b60736ecSDimitry Andric
172b60736ecSDimitry Andric /// A stable hash value for machine instructions.
173b60736ecSDimitry Andric /// Returns 0 if no stable hash could be computed.
174b60736ecSDimitry Andric /// The hashing and equality testing functions ignore definitions so this is
175b60736ecSDimitry Andric /// useful for CSE, etc.
stableHashValue(const MachineInstr & MI,bool HashVRegs,bool HashConstantPoolIndices,bool HashMemOperands)176b60736ecSDimitry Andric stable_hash llvm::stableHashValue(const MachineInstr &MI, bool HashVRegs,
177b60736ecSDimitry Andric bool HashConstantPoolIndices,
178b60736ecSDimitry Andric bool HashMemOperands) {
179b60736ecSDimitry Andric // Build up a buffer of hash code components.
180b60736ecSDimitry Andric SmallVector<stable_hash, 16> HashComponents;
181b60736ecSDimitry Andric HashComponents.reserve(MI.getNumOperands() + MI.getNumMemOperands() + 2);
182b60736ecSDimitry Andric HashComponents.push_back(MI.getOpcode());
183b60736ecSDimitry Andric HashComponents.push_back(MI.getFlags());
184b60736ecSDimitry Andric for (const MachineOperand &MO : MI.operands()) {
185e3b55780SDimitry Andric if (!HashVRegs && MO.isReg() && MO.isDef() && MO.getReg().isVirtual())
186b60736ecSDimitry Andric continue; // Skip virtual register defs.
187b60736ecSDimitry Andric
188b60736ecSDimitry Andric if (MO.isCPI()) {
189b60736ecSDimitry Andric HashComponents.push_back(stable_hash_combine(
190b60736ecSDimitry Andric MO.getType(), MO.getTargetFlags(), MO.getIndex()));
191b60736ecSDimitry Andric continue;
192b60736ecSDimitry Andric }
193b60736ecSDimitry Andric
194b60736ecSDimitry Andric stable_hash StableHash = stableHashValue(MO);
195b60736ecSDimitry Andric if (!StableHash)
196b60736ecSDimitry Andric return 0;
197b60736ecSDimitry Andric HashComponents.push_back(StableHash);
198b60736ecSDimitry Andric }
199b60736ecSDimitry Andric
200b60736ecSDimitry Andric for (const auto *Op : MI.memoperands()) {
201b60736ecSDimitry Andric if (!HashMemOperands)
202b60736ecSDimitry Andric break;
203ac9a064cSDimitry Andric HashComponents.push_back(static_cast<unsigned>(Op->getSize().getValue()));
204b60736ecSDimitry Andric HashComponents.push_back(static_cast<unsigned>(Op->getFlags()));
205b60736ecSDimitry Andric HashComponents.push_back(static_cast<unsigned>(Op->getOffset()));
206344a3780SDimitry Andric HashComponents.push_back(static_cast<unsigned>(Op->getSuccessOrdering()));
207b60736ecSDimitry Andric HashComponents.push_back(static_cast<unsigned>(Op->getAddrSpace()));
208b60736ecSDimitry Andric HashComponents.push_back(static_cast<unsigned>(Op->getSyncScopeID()));
209b60736ecSDimitry Andric HashComponents.push_back(static_cast<unsigned>(Op->getBaseAlign().value()));
210b60736ecSDimitry Andric HashComponents.push_back(static_cast<unsigned>(Op->getFailureOrdering()));
211b60736ecSDimitry Andric }
212b60736ecSDimitry Andric
213b60736ecSDimitry Andric return stable_hash_combine_range(HashComponents.begin(),
214b60736ecSDimitry Andric HashComponents.end());
215b60736ecSDimitry Andric }
216145449b1SDimitry Andric
stableHashValue(const MachineBasicBlock & MBB)217145449b1SDimitry Andric stable_hash llvm::stableHashValue(const MachineBasicBlock &MBB) {
218145449b1SDimitry Andric SmallVector<stable_hash> HashComponents;
219145449b1SDimitry Andric // TODO: Hash more stuff like block alignment and branch probabilities.
2204b4fe385SDimitry Andric for (const auto &MI : MBB)
221145449b1SDimitry Andric HashComponents.push_back(stableHashValue(MI));
222145449b1SDimitry Andric return stable_hash_combine_range(HashComponents.begin(),
223145449b1SDimitry Andric HashComponents.end());
224145449b1SDimitry Andric }
225145449b1SDimitry Andric
stableHashValue(const MachineFunction & MF)226145449b1SDimitry Andric stable_hash llvm::stableHashValue(const MachineFunction &MF) {
227145449b1SDimitry Andric SmallVector<stable_hash> HashComponents;
228145449b1SDimitry Andric // TODO: Hash lots more stuff like function alignment and stack objects.
2294b4fe385SDimitry Andric for (const auto &MBB : MF)
230145449b1SDimitry Andric HashComponents.push_back(stableHashValue(MBB));
231145449b1SDimitry Andric return stable_hash_combine_range(HashComponents.begin(),
232145449b1SDimitry Andric HashComponents.end());
233145449b1SDimitry Andric }
234