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