xref: /freebsd-src/contrib/llvm-project/llvm/lib/CodeGen/MachineStableHash.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
1e8d8bef9SDimitry Andric //===- lib/CodeGen/MachineStableHash.cpp ----------------------------------===//
2e8d8bef9SDimitry Andric //
3e8d8bef9SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e8d8bef9SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e8d8bef9SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e8d8bef9SDimitry Andric //
7e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===//
8e8d8bef9SDimitry Andric //
9e8d8bef9SDimitry Andric // Stable hashing for MachineInstr and MachineOperand. Useful or getting a
10e8d8bef9SDimitry Andric // hash across runs, modules, etc.
11e8d8bef9SDimitry Andric //
12e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===//
13e8d8bef9SDimitry Andric 
14e8d8bef9SDimitry Andric #include "llvm/CodeGen/MachineStableHash.h"
1581ad6265SDimitry Andric #include "llvm/ADT/APFloat.h"
1681ad6265SDimitry Andric #include "llvm/ADT/APInt.h"
1781ad6265SDimitry Andric #include "llvm/ADT/ArrayRef.h"
1881ad6265SDimitry Andric #include "llvm/ADT/DenseMapInfo.h"
1981ad6265SDimitry Andric #include "llvm/ADT/Hashing.h"
2081ad6265SDimitry Andric #include "llvm/ADT/STLExtras.h"
2181ad6265SDimitry Andric #include "llvm/ADT/SmallVector.h"
22e8d8bef9SDimitry Andric #include "llvm/ADT/Statistic.h"
2381ad6265SDimitry Andric #include "llvm/ADT/ilist_iterator.h"
2481ad6265SDimitry Andric #include "llvm/ADT/iterator_range.h"
2581ad6265SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h"
2681ad6265SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
27e8d8bef9SDimitry Andric #include "llvm/CodeGen/MachineInstr.h"
2881ad6265SDimitry Andric #include "llvm/CodeGen/MachineInstrBundleIterator.h"
2981ad6265SDimitry Andric #include "llvm/CodeGen/MachineMemOperand.h"
30e8d8bef9SDimitry Andric #include "llvm/CodeGen/MachineOperand.h"
31e8d8bef9SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
3281ad6265SDimitry Andric #include "llvm/CodeGen/Register.h"
33e8d8bef9SDimitry Andric #include "llvm/CodeGen/StableHashing.h"
34e8d8bef9SDimitry Andric #include "llvm/Config/llvm-config.h"
35e8d8bef9SDimitry Andric #include "llvm/IR/Constants.h"
3681ad6265SDimitry Andric #include "llvm/MC/MCSymbol.h"
3781ad6265SDimitry Andric #include "llvm/Support/Alignment.h"
3881ad6265SDimitry Andric #include "llvm/Support/ErrorHandling.h"
39e8d8bef9SDimitry Andric 
40e8d8bef9SDimitry Andric #define DEBUG_TYPE "machine-stable-hash"
41e8d8bef9SDimitry Andric 
42e8d8bef9SDimitry Andric using namespace llvm;
43e8d8bef9SDimitry Andric 
44e8d8bef9SDimitry Andric STATISTIC(StableHashBailingMachineBasicBlock,
45e8d8bef9SDimitry Andric           "Number of encountered unsupported MachineOperands that were "
46e8d8bef9SDimitry Andric           "MachineBasicBlocks while computing stable hashes");
47e8d8bef9SDimitry Andric STATISTIC(StableHashBailingConstantPoolIndex,
48e8d8bef9SDimitry Andric           "Number of encountered unsupported MachineOperands that were "
49e8d8bef9SDimitry Andric           "ConstantPoolIndex while computing stable hashes");
50e8d8bef9SDimitry Andric STATISTIC(StableHashBailingTargetIndexNoName,
51e8d8bef9SDimitry Andric           "Number of encountered unsupported MachineOperands that were "
52e8d8bef9SDimitry Andric           "TargetIndex with no name");
53e8d8bef9SDimitry Andric STATISTIC(StableHashBailingGlobalAddress,
54e8d8bef9SDimitry Andric           "Number of encountered unsupported MachineOperands that were "
55e8d8bef9SDimitry Andric           "GlobalAddress while computing stable hashes");
56e8d8bef9SDimitry Andric STATISTIC(StableHashBailingBlockAddress,
57e8d8bef9SDimitry Andric           "Number of encountered unsupported MachineOperands that were "
58e8d8bef9SDimitry Andric           "BlockAddress while computing stable hashes");
59e8d8bef9SDimitry Andric STATISTIC(StableHashBailingMetadataUnsupported,
60e8d8bef9SDimitry Andric           "Number of encountered unsupported MachineOperands that were "
61e8d8bef9SDimitry Andric           "Metadata of an unsupported kind while computing stable hashes");
62e8d8bef9SDimitry Andric 
63e8d8bef9SDimitry Andric stable_hash llvm::stableHashValue(const MachineOperand &MO) {
64e8d8bef9SDimitry Andric   switch (MO.getType()) {
65e8d8bef9SDimitry Andric   case MachineOperand::MO_Register:
66*bdd1243dSDimitry Andric     if (MO.getReg().isVirtual()) {
67e8d8bef9SDimitry Andric       const MachineRegisterInfo &MRI = MO.getParent()->getMF()->getRegInfo();
6881ad6265SDimitry Andric       SmallVector<unsigned> DefOpcodes;
6981ad6265SDimitry Andric       for (auto &Def : MRI.def_instructions(MO.getReg()))
7081ad6265SDimitry Andric         DefOpcodes.push_back(Def.getOpcode());
7181ad6265SDimitry Andric       return hash_combine_range(DefOpcodes.begin(), DefOpcodes.end());
72e8d8bef9SDimitry Andric     }
73e8d8bef9SDimitry Andric 
74e8d8bef9SDimitry Andric     // Register operands don't have target flags.
75e8d8bef9SDimitry Andric     return stable_hash_combine(MO.getType(), MO.getReg(), MO.getSubReg(),
76e8d8bef9SDimitry Andric                                MO.isDef());
77e8d8bef9SDimitry Andric   case MachineOperand::MO_Immediate:
78e8d8bef9SDimitry Andric     return stable_hash_combine(MO.getType(), MO.getTargetFlags(), MO.getImm());
79e8d8bef9SDimitry Andric   case MachineOperand::MO_CImmediate:
80e8d8bef9SDimitry Andric   case MachineOperand::MO_FPImmediate: {
81e8d8bef9SDimitry Andric     auto Val = MO.isCImm() ? MO.getCImm()->getValue()
82e8d8bef9SDimitry Andric                            : MO.getFPImm()->getValueAPF().bitcastToAPInt();
83e8d8bef9SDimitry Andric     auto ValHash =
84e8d8bef9SDimitry Andric         stable_hash_combine_array(Val.getRawData(), Val.getNumWords());
85e8d8bef9SDimitry Andric     return hash_combine(MO.getType(), MO.getTargetFlags(), ValHash);
86e8d8bef9SDimitry Andric   }
87e8d8bef9SDimitry Andric 
88e8d8bef9SDimitry Andric   case MachineOperand::MO_MachineBasicBlock:
89e8d8bef9SDimitry Andric     StableHashBailingMachineBasicBlock++;
90e8d8bef9SDimitry Andric     return 0;
91e8d8bef9SDimitry Andric   case MachineOperand::MO_ConstantPoolIndex:
92e8d8bef9SDimitry Andric     StableHashBailingConstantPoolIndex++;
93e8d8bef9SDimitry Andric     return 0;
94e8d8bef9SDimitry Andric   case MachineOperand::MO_BlockAddress:
95e8d8bef9SDimitry Andric     StableHashBailingBlockAddress++;
96e8d8bef9SDimitry Andric     return 0;
97e8d8bef9SDimitry Andric   case MachineOperand::MO_Metadata:
98e8d8bef9SDimitry Andric     StableHashBailingMetadataUnsupported++;
99e8d8bef9SDimitry Andric     return 0;
100e8d8bef9SDimitry Andric   case MachineOperand::MO_GlobalAddress:
101e8d8bef9SDimitry Andric     StableHashBailingGlobalAddress++;
102e8d8bef9SDimitry Andric     return 0;
103e8d8bef9SDimitry Andric   case MachineOperand::MO_TargetIndex: {
104e8d8bef9SDimitry Andric     if (const char *Name = MO.getTargetIndexName())
105e8d8bef9SDimitry Andric       return stable_hash_combine(MO.getType(), MO.getTargetFlags(),
106e8d8bef9SDimitry Andric                                  stable_hash_combine_string(Name),
107e8d8bef9SDimitry Andric                                  MO.getOffset());
108e8d8bef9SDimitry Andric     StableHashBailingTargetIndexNoName++;
109e8d8bef9SDimitry Andric     return 0;
110e8d8bef9SDimitry Andric   }
111e8d8bef9SDimitry Andric 
112e8d8bef9SDimitry Andric   case MachineOperand::MO_FrameIndex:
113e8d8bef9SDimitry Andric   case MachineOperand::MO_JumpTableIndex:
114e8d8bef9SDimitry Andric     return stable_hash_combine(MO.getType(), MO.getTargetFlags(),
115e8d8bef9SDimitry Andric                                MO.getIndex());
116e8d8bef9SDimitry Andric 
117e8d8bef9SDimitry Andric   case MachineOperand::MO_ExternalSymbol:
118e8d8bef9SDimitry Andric     return hash_combine(MO.getType(), MO.getTargetFlags(), MO.getOffset(),
119e8d8bef9SDimitry Andric                         stable_hash_combine_string(MO.getSymbolName()));
120e8d8bef9SDimitry Andric 
121e8d8bef9SDimitry Andric   case MachineOperand::MO_RegisterMask:
122*bdd1243dSDimitry Andric   case MachineOperand::MO_RegisterLiveOut: {
123*bdd1243dSDimitry Andric     if (const MachineInstr *MI = MO.getParent()) {
124*bdd1243dSDimitry Andric       if (const MachineBasicBlock *MBB = MI->getParent()) {
125*bdd1243dSDimitry Andric         if (const MachineFunction *MF = MBB->getParent()) {
126*bdd1243dSDimitry Andric           const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo();
127*bdd1243dSDimitry Andric           unsigned RegMaskSize =
128*bdd1243dSDimitry Andric               MachineOperand::getRegMaskSize(TRI->getNumRegs());
129*bdd1243dSDimitry Andric           const uint32_t *RegMask = MO.getRegMask();
130*bdd1243dSDimitry Andric           std::vector<llvm::stable_hash> RegMaskHashes(RegMask,
131*bdd1243dSDimitry Andric                                                        RegMask + RegMaskSize);
132*bdd1243dSDimitry Andric           return hash_combine(MO.getType(), MO.getTargetFlags(),
133*bdd1243dSDimitry Andric                               stable_hash_combine_array(RegMaskHashes.data(),
134*bdd1243dSDimitry Andric                                                         RegMaskHashes.size()));
135*bdd1243dSDimitry Andric         }
136*bdd1243dSDimitry Andric       }
137*bdd1243dSDimitry Andric     }
138*bdd1243dSDimitry Andric 
139*bdd1243dSDimitry Andric     assert(0 && "MachineOperand not associated with any MachineFunction");
140*bdd1243dSDimitry Andric     return hash_combine(MO.getType(), MO.getTargetFlags());
141*bdd1243dSDimitry Andric   }
142e8d8bef9SDimitry Andric 
143e8d8bef9SDimitry Andric   case MachineOperand::MO_ShuffleMask: {
144e8d8bef9SDimitry Andric     std::vector<llvm::stable_hash> ShuffleMaskHashes;
145e8d8bef9SDimitry Andric 
146e8d8bef9SDimitry Andric     llvm::transform(
147e8d8bef9SDimitry Andric         MO.getShuffleMask(), std::back_inserter(ShuffleMaskHashes),
148e8d8bef9SDimitry Andric         [](int S) -> llvm::stable_hash { return llvm::stable_hash(S); });
149e8d8bef9SDimitry Andric 
150e8d8bef9SDimitry Andric     return hash_combine(MO.getType(), MO.getTargetFlags(),
151e8d8bef9SDimitry Andric                         stable_hash_combine_array(ShuffleMaskHashes.data(),
152e8d8bef9SDimitry Andric                                                   ShuffleMaskHashes.size()));
153e8d8bef9SDimitry Andric   }
154e8d8bef9SDimitry Andric   case MachineOperand::MO_MCSymbol: {
155e8d8bef9SDimitry Andric     auto SymbolName = MO.getMCSymbol()->getName();
156e8d8bef9SDimitry Andric     return hash_combine(MO.getType(), MO.getTargetFlags(),
157e8d8bef9SDimitry Andric                         stable_hash_combine_string(SymbolName));
158e8d8bef9SDimitry Andric   }
159e8d8bef9SDimitry Andric   case MachineOperand::MO_CFIIndex:
160e8d8bef9SDimitry Andric     return stable_hash_combine(MO.getType(), MO.getTargetFlags(),
161e8d8bef9SDimitry Andric                                MO.getCFIIndex());
162e8d8bef9SDimitry Andric   case MachineOperand::MO_IntrinsicID:
163e8d8bef9SDimitry Andric     return stable_hash_combine(MO.getType(), MO.getTargetFlags(),
164e8d8bef9SDimitry Andric                                MO.getIntrinsicID());
165e8d8bef9SDimitry Andric   case MachineOperand::MO_Predicate:
166e8d8bef9SDimitry Andric     return stable_hash_combine(MO.getType(), MO.getTargetFlags(),
167e8d8bef9SDimitry Andric                                MO.getPredicate());
168*bdd1243dSDimitry Andric   case MachineOperand::MO_DbgInstrRef:
169*bdd1243dSDimitry Andric     return stable_hash_combine(MO.getType(), MO.getInstrRefInstrIndex(),
170*bdd1243dSDimitry Andric                                MO.getInstrRefOpIndex());
171e8d8bef9SDimitry Andric   }
172e8d8bef9SDimitry Andric   llvm_unreachable("Invalid machine operand type");
173e8d8bef9SDimitry Andric }
174e8d8bef9SDimitry Andric 
175e8d8bef9SDimitry Andric /// A stable hash value for machine instructions.
176e8d8bef9SDimitry Andric /// Returns 0 if no stable hash could be computed.
177e8d8bef9SDimitry Andric /// The hashing and equality testing functions ignore definitions so this is
178e8d8bef9SDimitry Andric /// useful for CSE, etc.
179e8d8bef9SDimitry Andric stable_hash llvm::stableHashValue(const MachineInstr &MI, bool HashVRegs,
180e8d8bef9SDimitry Andric                                   bool HashConstantPoolIndices,
181e8d8bef9SDimitry Andric                                   bool HashMemOperands) {
182e8d8bef9SDimitry Andric   // Build up a buffer of hash code components.
183e8d8bef9SDimitry Andric   SmallVector<stable_hash, 16> HashComponents;
184e8d8bef9SDimitry Andric   HashComponents.reserve(MI.getNumOperands() + MI.getNumMemOperands() + 2);
185e8d8bef9SDimitry Andric   HashComponents.push_back(MI.getOpcode());
186e8d8bef9SDimitry Andric   HashComponents.push_back(MI.getFlags());
187e8d8bef9SDimitry Andric   for (const MachineOperand &MO : MI.operands()) {
188*bdd1243dSDimitry Andric     if (!HashVRegs && MO.isReg() && MO.isDef() && MO.getReg().isVirtual())
189e8d8bef9SDimitry Andric       continue; // Skip virtual register defs.
190e8d8bef9SDimitry Andric 
191e8d8bef9SDimitry Andric     if (MO.isCPI()) {
192e8d8bef9SDimitry Andric       HashComponents.push_back(stable_hash_combine(
193e8d8bef9SDimitry Andric           MO.getType(), MO.getTargetFlags(), MO.getIndex()));
194e8d8bef9SDimitry Andric       continue;
195e8d8bef9SDimitry Andric     }
196e8d8bef9SDimitry Andric 
197e8d8bef9SDimitry Andric     stable_hash StableHash = stableHashValue(MO);
198e8d8bef9SDimitry Andric     if (!StableHash)
199e8d8bef9SDimitry Andric       return 0;
200e8d8bef9SDimitry Andric     HashComponents.push_back(StableHash);
201e8d8bef9SDimitry Andric   }
202e8d8bef9SDimitry Andric 
203e8d8bef9SDimitry Andric   for (const auto *Op : MI.memoperands()) {
204e8d8bef9SDimitry Andric     if (!HashMemOperands)
205e8d8bef9SDimitry Andric       break;
206e8d8bef9SDimitry Andric     HashComponents.push_back(static_cast<unsigned>(Op->getSize()));
207e8d8bef9SDimitry Andric     HashComponents.push_back(static_cast<unsigned>(Op->getFlags()));
208e8d8bef9SDimitry Andric     HashComponents.push_back(static_cast<unsigned>(Op->getOffset()));
209fe6060f1SDimitry Andric     HashComponents.push_back(static_cast<unsigned>(Op->getSuccessOrdering()));
210e8d8bef9SDimitry Andric     HashComponents.push_back(static_cast<unsigned>(Op->getAddrSpace()));
211e8d8bef9SDimitry Andric     HashComponents.push_back(static_cast<unsigned>(Op->getSyncScopeID()));
212e8d8bef9SDimitry Andric     HashComponents.push_back(static_cast<unsigned>(Op->getBaseAlign().value()));
213e8d8bef9SDimitry Andric     HashComponents.push_back(static_cast<unsigned>(Op->getFailureOrdering()));
214e8d8bef9SDimitry Andric   }
215e8d8bef9SDimitry Andric 
216e8d8bef9SDimitry Andric   return stable_hash_combine_range(HashComponents.begin(),
217e8d8bef9SDimitry Andric                                    HashComponents.end());
218e8d8bef9SDimitry Andric }
21981ad6265SDimitry Andric 
22081ad6265SDimitry Andric stable_hash llvm::stableHashValue(const MachineBasicBlock &MBB) {
22181ad6265SDimitry Andric   SmallVector<stable_hash> HashComponents;
22281ad6265SDimitry Andric   // TODO: Hash more stuff like block alignment and branch probabilities.
223fcaf7f86SDimitry Andric   for (const auto &MI : MBB)
22481ad6265SDimitry Andric     HashComponents.push_back(stableHashValue(MI));
22581ad6265SDimitry Andric   return stable_hash_combine_range(HashComponents.begin(),
22681ad6265SDimitry Andric                                    HashComponents.end());
22781ad6265SDimitry Andric }
22881ad6265SDimitry Andric 
22981ad6265SDimitry Andric stable_hash llvm::stableHashValue(const MachineFunction &MF) {
23081ad6265SDimitry Andric   SmallVector<stable_hash> HashComponents;
23181ad6265SDimitry Andric   // TODO: Hash lots more stuff like function alignment and stack objects.
232fcaf7f86SDimitry Andric   for (const auto &MBB : MF)
23381ad6265SDimitry Andric     HashComponents.push_back(stableHashValue(MBB));
23481ad6265SDimitry Andric   return stable_hash_combine_range(HashComponents.begin(),
23581ad6265SDimitry Andric                                    HashComponents.end());
23681ad6265SDimitry Andric }
237