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"
15e8d8bef9SDimitry Andric #include "llvm/ADT/FoldingSet.h"
16e8d8bef9SDimitry Andric #include "llvm/ADT/Statistic.h"
17e8d8bef9SDimitry Andric #include "llvm/ADT/StringExtras.h"
18e8d8bef9SDimitry Andric #include "llvm/Analysis/Loads.h"
19e8d8bef9SDimitry Andric #include "llvm/Analysis/MemoryLocation.h"
20e8d8bef9SDimitry Andric #include "llvm/CodeGen/MIRFormatter.h"
21e8d8bef9SDimitry Andric #include "llvm/CodeGen/MIRPrinter.h"
22e8d8bef9SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h"
23e8d8bef9SDimitry Andric #include "llvm/CodeGen/MachineInstr.h"
24e8d8bef9SDimitry Andric #include "llvm/CodeGen/MachineJumpTableInfo.h"
25e8d8bef9SDimitry Andric #include "llvm/CodeGen/MachineOperand.h"
26e8d8bef9SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
27e8d8bef9SDimitry Andric #include "llvm/CodeGen/StableHashing.h"
28e8d8bef9SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h"
29e8d8bef9SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h"
30e8d8bef9SDimitry Andric #include "llvm/Config/llvm-config.h"
31e8d8bef9SDimitry Andric #include "llvm/IR/Constants.h"
32e8d8bef9SDimitry Andric #include "llvm/IR/IRPrintingPasses.h"
33e8d8bef9SDimitry Andric #include "llvm/IR/Instructions.h"
34e8d8bef9SDimitry Andric #include "llvm/IR/ModuleSlotTracker.h"
35e8d8bef9SDimitry Andric #include "llvm/MC/MCDwarf.h"
36e8d8bef9SDimitry Andric #include "llvm/Target/TargetIntrinsicInfo.h"
37e8d8bef9SDimitry Andric #include "llvm/Target/TargetMachine.h"
38e8d8bef9SDimitry Andric 
39e8d8bef9SDimitry Andric #define DEBUG_TYPE "machine-stable-hash"
40e8d8bef9SDimitry Andric 
41e8d8bef9SDimitry Andric using namespace llvm;
42e8d8bef9SDimitry Andric 
43e8d8bef9SDimitry Andric STATISTIC(StableHashBailingMachineBasicBlock,
44e8d8bef9SDimitry Andric           "Number of encountered unsupported MachineOperands that were "
45e8d8bef9SDimitry Andric           "MachineBasicBlocks while computing stable hashes");
46e8d8bef9SDimitry Andric STATISTIC(StableHashBailingConstantPoolIndex,
47e8d8bef9SDimitry Andric           "Number of encountered unsupported MachineOperands that were "
48e8d8bef9SDimitry Andric           "ConstantPoolIndex while computing stable hashes");
49e8d8bef9SDimitry Andric STATISTIC(StableHashBailingTargetIndexNoName,
50e8d8bef9SDimitry Andric           "Number of encountered unsupported MachineOperands that were "
51e8d8bef9SDimitry Andric           "TargetIndex with no name");
52e8d8bef9SDimitry Andric STATISTIC(StableHashBailingGlobalAddress,
53e8d8bef9SDimitry Andric           "Number of encountered unsupported MachineOperands that were "
54e8d8bef9SDimitry Andric           "GlobalAddress while computing stable hashes");
55e8d8bef9SDimitry Andric STATISTIC(StableHashBailingBlockAddress,
56e8d8bef9SDimitry Andric           "Number of encountered unsupported MachineOperands that were "
57e8d8bef9SDimitry Andric           "BlockAddress while computing stable hashes");
58e8d8bef9SDimitry Andric STATISTIC(StableHashBailingMetadataUnsupported,
59e8d8bef9SDimitry Andric           "Number of encountered unsupported MachineOperands that were "
60e8d8bef9SDimitry Andric           "Metadata of an unsupported kind while computing stable hashes");
61e8d8bef9SDimitry Andric 
62e8d8bef9SDimitry Andric stable_hash llvm::stableHashValue(const MachineOperand &MO) {
63e8d8bef9SDimitry Andric   switch (MO.getType()) {
64e8d8bef9SDimitry Andric   case MachineOperand::MO_Register:
65e8d8bef9SDimitry Andric     if (Register::isVirtualRegister(MO.getReg())) {
66e8d8bef9SDimitry Andric       const MachineRegisterInfo &MRI = MO.getParent()->getMF()->getRegInfo();
67e8d8bef9SDimitry Andric       return MRI.getVRegDef(MO.getReg())->getOpcode();
68e8d8bef9SDimitry Andric     }
69e8d8bef9SDimitry Andric 
70e8d8bef9SDimitry Andric     // Register operands don't have target flags.
71e8d8bef9SDimitry Andric     return stable_hash_combine(MO.getType(), MO.getReg(), MO.getSubReg(),
72e8d8bef9SDimitry Andric                                MO.isDef());
73e8d8bef9SDimitry Andric   case MachineOperand::MO_Immediate:
74e8d8bef9SDimitry Andric     return stable_hash_combine(MO.getType(), MO.getTargetFlags(), MO.getImm());
75e8d8bef9SDimitry Andric   case MachineOperand::MO_CImmediate:
76e8d8bef9SDimitry Andric   case MachineOperand::MO_FPImmediate: {
77e8d8bef9SDimitry Andric     auto Val = MO.isCImm() ? MO.getCImm()->getValue()
78e8d8bef9SDimitry Andric                            : MO.getFPImm()->getValueAPF().bitcastToAPInt();
79e8d8bef9SDimitry Andric     auto ValHash =
80e8d8bef9SDimitry Andric         stable_hash_combine_array(Val.getRawData(), Val.getNumWords());
81e8d8bef9SDimitry Andric     return hash_combine(MO.getType(), MO.getTargetFlags(), ValHash);
82e8d8bef9SDimitry Andric   }
83e8d8bef9SDimitry Andric 
84e8d8bef9SDimitry Andric   case MachineOperand::MO_MachineBasicBlock:
85e8d8bef9SDimitry Andric     StableHashBailingMachineBasicBlock++;
86e8d8bef9SDimitry Andric     return 0;
87e8d8bef9SDimitry Andric   case MachineOperand::MO_ConstantPoolIndex:
88e8d8bef9SDimitry Andric     StableHashBailingConstantPoolIndex++;
89e8d8bef9SDimitry Andric     return 0;
90e8d8bef9SDimitry Andric   case MachineOperand::MO_BlockAddress:
91e8d8bef9SDimitry Andric     StableHashBailingBlockAddress++;
92e8d8bef9SDimitry Andric     return 0;
93e8d8bef9SDimitry Andric   case MachineOperand::MO_Metadata:
94e8d8bef9SDimitry Andric     StableHashBailingMetadataUnsupported++;
95e8d8bef9SDimitry Andric     return 0;
96e8d8bef9SDimitry Andric   case MachineOperand::MO_GlobalAddress:
97e8d8bef9SDimitry Andric     StableHashBailingGlobalAddress++;
98e8d8bef9SDimitry Andric     return 0;
99e8d8bef9SDimitry Andric   case MachineOperand::MO_TargetIndex: {
100e8d8bef9SDimitry Andric     if (const char *Name = MO.getTargetIndexName())
101e8d8bef9SDimitry Andric       return stable_hash_combine(MO.getType(), MO.getTargetFlags(),
102e8d8bef9SDimitry Andric                                  stable_hash_combine_string(Name),
103e8d8bef9SDimitry Andric                                  MO.getOffset());
104e8d8bef9SDimitry Andric     StableHashBailingTargetIndexNoName++;
105e8d8bef9SDimitry Andric     return 0;
106e8d8bef9SDimitry Andric   }
107e8d8bef9SDimitry Andric 
108e8d8bef9SDimitry Andric   case MachineOperand::MO_FrameIndex:
109e8d8bef9SDimitry Andric   case MachineOperand::MO_JumpTableIndex:
110e8d8bef9SDimitry Andric     return stable_hash_combine(MO.getType(), MO.getTargetFlags(),
111e8d8bef9SDimitry Andric                                MO.getIndex());
112e8d8bef9SDimitry Andric 
113e8d8bef9SDimitry Andric   case MachineOperand::MO_ExternalSymbol:
114e8d8bef9SDimitry Andric     return hash_combine(MO.getType(), MO.getTargetFlags(), MO.getOffset(),
115e8d8bef9SDimitry Andric                         stable_hash_combine_string(MO.getSymbolName()));
116e8d8bef9SDimitry Andric 
117e8d8bef9SDimitry Andric   case MachineOperand::MO_RegisterMask:
118e8d8bef9SDimitry Andric   case MachineOperand::MO_RegisterLiveOut:
119e8d8bef9SDimitry Andric     return hash_combine(MO.getType(), MO.getTargetFlags(), MO.getRegMask());
120e8d8bef9SDimitry Andric 
121e8d8bef9SDimitry Andric   case MachineOperand::MO_ShuffleMask: {
122e8d8bef9SDimitry Andric     std::vector<llvm::stable_hash> ShuffleMaskHashes;
123e8d8bef9SDimitry Andric 
124e8d8bef9SDimitry Andric     llvm::transform(
125e8d8bef9SDimitry Andric         MO.getShuffleMask(), std::back_inserter(ShuffleMaskHashes),
126e8d8bef9SDimitry Andric         [](int S) -> llvm::stable_hash { return llvm::stable_hash(S); });
127e8d8bef9SDimitry Andric 
128e8d8bef9SDimitry Andric     return hash_combine(MO.getType(), MO.getTargetFlags(),
129e8d8bef9SDimitry Andric                         stable_hash_combine_array(ShuffleMaskHashes.data(),
130e8d8bef9SDimitry Andric                                                   ShuffleMaskHashes.size()));
131e8d8bef9SDimitry Andric   }
132e8d8bef9SDimitry Andric   case MachineOperand::MO_MCSymbol: {
133e8d8bef9SDimitry Andric     auto SymbolName = MO.getMCSymbol()->getName();
134e8d8bef9SDimitry Andric     return hash_combine(MO.getType(), MO.getTargetFlags(),
135e8d8bef9SDimitry Andric                         stable_hash_combine_string(SymbolName));
136e8d8bef9SDimitry Andric   }
137e8d8bef9SDimitry Andric   case MachineOperand::MO_CFIIndex:
138e8d8bef9SDimitry Andric     return stable_hash_combine(MO.getType(), MO.getTargetFlags(),
139e8d8bef9SDimitry Andric                                MO.getCFIIndex());
140e8d8bef9SDimitry Andric   case MachineOperand::MO_IntrinsicID:
141e8d8bef9SDimitry Andric     return stable_hash_combine(MO.getType(), MO.getTargetFlags(),
142e8d8bef9SDimitry Andric                                MO.getIntrinsicID());
143e8d8bef9SDimitry Andric   case MachineOperand::MO_Predicate:
144e8d8bef9SDimitry Andric     return stable_hash_combine(MO.getType(), MO.getTargetFlags(),
145e8d8bef9SDimitry Andric                                MO.getPredicate());
146e8d8bef9SDimitry Andric   }
147e8d8bef9SDimitry Andric   llvm_unreachable("Invalid machine operand type");
148e8d8bef9SDimitry Andric }
149e8d8bef9SDimitry Andric 
150e8d8bef9SDimitry Andric /// A stable hash value for machine instructions.
151e8d8bef9SDimitry Andric /// Returns 0 if no stable hash could be computed.
152e8d8bef9SDimitry Andric /// The hashing and equality testing functions ignore definitions so this is
153e8d8bef9SDimitry Andric /// useful for CSE, etc.
154e8d8bef9SDimitry Andric stable_hash llvm::stableHashValue(const MachineInstr &MI, bool HashVRegs,
155e8d8bef9SDimitry Andric                                   bool HashConstantPoolIndices,
156e8d8bef9SDimitry Andric                                   bool HashMemOperands) {
157e8d8bef9SDimitry Andric   // Build up a buffer of hash code components.
158e8d8bef9SDimitry Andric   SmallVector<stable_hash, 16> HashComponents;
159e8d8bef9SDimitry Andric   HashComponents.reserve(MI.getNumOperands() + MI.getNumMemOperands() + 2);
160e8d8bef9SDimitry Andric   HashComponents.push_back(MI.getOpcode());
161e8d8bef9SDimitry Andric   HashComponents.push_back(MI.getFlags());
162e8d8bef9SDimitry Andric   for (const MachineOperand &MO : MI.operands()) {
163e8d8bef9SDimitry Andric     if (!HashVRegs && MO.isReg() && MO.isDef() &&
164e8d8bef9SDimitry Andric         Register::isVirtualRegister(MO.getReg()))
165e8d8bef9SDimitry Andric       continue; // Skip virtual register defs.
166e8d8bef9SDimitry Andric 
167e8d8bef9SDimitry Andric     if (MO.isCPI()) {
168e8d8bef9SDimitry Andric       HashComponents.push_back(stable_hash_combine(
169e8d8bef9SDimitry Andric           MO.getType(), MO.getTargetFlags(), MO.getIndex()));
170e8d8bef9SDimitry Andric       continue;
171e8d8bef9SDimitry Andric     }
172e8d8bef9SDimitry Andric 
173e8d8bef9SDimitry Andric     stable_hash StableHash = stableHashValue(MO);
174e8d8bef9SDimitry Andric     if (!StableHash)
175e8d8bef9SDimitry Andric       return 0;
176e8d8bef9SDimitry Andric     HashComponents.push_back(StableHash);
177e8d8bef9SDimitry Andric   }
178e8d8bef9SDimitry Andric 
179e8d8bef9SDimitry Andric   for (const auto *Op : MI.memoperands()) {
180e8d8bef9SDimitry Andric     if (!HashMemOperands)
181e8d8bef9SDimitry Andric       break;
182e8d8bef9SDimitry Andric     HashComponents.push_back(static_cast<unsigned>(Op->getSize()));
183e8d8bef9SDimitry Andric     HashComponents.push_back(static_cast<unsigned>(Op->getFlags()));
184e8d8bef9SDimitry Andric     HashComponents.push_back(static_cast<unsigned>(Op->getOffset()));
185e8d8bef9SDimitry Andric     HashComponents.push_back(static_cast<unsigned>(Op->getOrdering()));
186e8d8bef9SDimitry Andric     HashComponents.push_back(static_cast<unsigned>(Op->getAddrSpace()));
187e8d8bef9SDimitry Andric     HashComponents.push_back(static_cast<unsigned>(Op->getSyncScopeID()));
188e8d8bef9SDimitry Andric     HashComponents.push_back(static_cast<unsigned>(Op->getBaseAlign().value()));
189e8d8bef9SDimitry Andric     HashComponents.push_back(static_cast<unsigned>(Op->getFailureOrdering()));
190e8d8bef9SDimitry Andric   }
191e8d8bef9SDimitry Andric 
192e8d8bef9SDimitry Andric   return stable_hash_combine_range(HashComponents.begin(),
193e8d8bef9SDimitry Andric                                    HashComponents.end());
194e8d8bef9SDimitry Andric }
195