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