@@ -24,61 +24,93 @@ namespace {
24
24
// by the MergeFunctions pass.
25
25
26
26
class StructuralHashImpl {
27
- uint64_t Hash = 4 ;
27
+ stable_hash Hash = 4 ;
28
28
29
- void hash (uint64_t V) { Hash = hashing::detail::hash_16_bytes (Hash, V); }
29
+ bool DetailedHash;
30
+
31
+ // This random value acts as a block header, as otherwise the partition of
32
+ // opcodes into BBs wouldn't affect the hash, only the order of the opcodes.
33
+ static constexpr stable_hash BlockHeaderHash = 45798 ;
34
+ static constexpr stable_hash FunctionHeaderHash = 0x62642d6b6b2d6b72 ;
35
+ static constexpr stable_hash GlobalHeaderHash = 23456 ;
30
36
31
37
// This will produce different values on 32-bit and 64-bit systens as
32
38
// hash_combine returns a size_t. However, this is only used for
33
39
// detailed hashing which, in-tree, only needs to distinguish between
34
40
// differences in functions.
35
- template <typename T> void hashArbitaryType (const T &V) {
36
- hash (hash_combine (V));
41
+ // TODO: This is not stable.
42
+ template <typename T> stable_hash hashArbitaryType (const T &V) {
43
+ return hash_combine (V);
37
44
}
38
45
39
- void hashType (Type *ValueType) {
40
- hash (ValueType->getTypeID ());
46
+ stable_hash hashType (Type *ValueType) {
47
+ SmallVector<stable_hash> Hashes;
48
+ Hashes.emplace_back (ValueType->getTypeID ());
41
49
if (ValueType->isIntegerTy ())
42
- hash (ValueType->getIntegerBitWidth ());
50
+ Hashes.emplace_back (ValueType->getIntegerBitWidth ());
51
+ return stable_hash_combine (Hashes);
43
52
}
44
53
45
54
public:
46
- StructuralHashImpl () = default ;
47
-
48
- void updateOperand (Value *Operand) {
49
- hashType (Operand->getType ());
50
-
51
- // The cases enumerated below are not exhaustive and are only aimed to
52
- // get decent coverage over the function.
53
- if (ConstantInt *ConstInt = dyn_cast<ConstantInt>(Operand)) {
54
- hashArbitaryType (ConstInt->getValue ());
55
- } else if (ConstantFP *ConstFP = dyn_cast<ConstantFP>(Operand)) {
56
- hashArbitaryType (ConstFP->getValue ());
57
- } else if (Argument *Arg = dyn_cast<Argument>(Operand)) {
58
- hash (Arg->getArgNo ());
59
- } else if (Function *Func = dyn_cast<Function>(Operand)) {
55
+ StructuralHashImpl () = delete ;
56
+ explicit StructuralHashImpl (bool DetailedHash) : DetailedHash(DetailedHash) {}
57
+
58
+ stable_hash hashConstant (Constant *C) {
59
+ SmallVector<stable_hash> Hashes;
60
+ // TODO: hashArbitaryType() is not stable.
61
+ if (ConstantInt *ConstInt = dyn_cast<ConstantInt>(C)) {
62
+ Hashes.emplace_back (hashArbitaryType (ConstInt->getValue ()));
63
+ } else if (ConstantFP *ConstFP = dyn_cast<ConstantFP>(C)) {
64
+ Hashes.emplace_back (hashArbitaryType (ConstFP->getValue ()));
65
+ } else if (Function *Func = dyn_cast<Function>(C)) {
60
66
// Hashing the name will be deterministic as LLVM's hashing infrastructure
61
67
// has explicit support for hashing strings and will not simply hash
62
68
// the pointer.
63
- hashArbitaryType (Func->getName ());
69
+ Hashes. emplace_back ( hashArbitaryType (Func->getName () ));
64
70
}
71
+
72
+ return stable_hash_combine (Hashes);
73
+ }
74
+
75
+ stable_hash hashValue (Value *V) {
76
+ // Check constant and return its hash.
77
+ Constant *C = dyn_cast<Constant>(V);
78
+ if (C)
79
+ return hashConstant (C);
80
+
81
+ // Hash argument number.
82
+ SmallVector<stable_hash> Hashes;
83
+ if (Argument *Arg = dyn_cast<Argument>(V))
84
+ Hashes.emplace_back (Arg->getArgNo ());
85
+
86
+ return stable_hash_combine (Hashes);
65
87
}
66
88
67
- void updateInstruction (const Instruction &Inst, bool DetailedHash) {
68
- hash (Inst.getOpcode ());
89
+ stable_hash hashOperand (Value *Operand) {
90
+ SmallVector<stable_hash> Hashes;
91
+ Hashes.emplace_back (hashType (Operand->getType ()));
92
+ Hashes.emplace_back (hashValue (Operand));
93
+ return stable_hash_combine (Hashes);
94
+ }
95
+
96
+ stable_hash hashInstruction (const Instruction &Inst) {
97
+ SmallVector<stable_hash> Hashes;
98
+ Hashes.emplace_back (Inst.getOpcode ());
69
99
70
100
if (!DetailedHash)
71
- return ;
101
+ return stable_hash_combine (Hashes) ;
72
102
73
- hashType (Inst.getType ());
103
+ Hashes. emplace_back ( hashType (Inst.getType () ));
74
104
75
105
// Handle additional properties of specific instructions that cause
76
106
// semantic differences in the IR.
77
107
if (const auto *ComparisonInstruction = dyn_cast<CmpInst>(&Inst))
78
- hash (ComparisonInstruction->getPredicate ());
108
+ Hashes. emplace_back (ComparisonInstruction->getPredicate ());
79
109
80
110
for (const auto &Op : Inst.operands ())
81
- updateOperand (Op);
111
+ Hashes.emplace_back (hashOperand (Op));
112
+
113
+ return stable_hash_combine (Hashes);
82
114
}
83
115
84
116
// A function hash is calculated by considering only the number of arguments
@@ -97,15 +129,17 @@ class StructuralHashImpl {
97
129
// expensive checks for pass modification status). When modifying this
98
130
// function, most changes should be gated behind an option and enabled
99
131
// selectively.
100
- void update (const Function &F, bool DetailedHash ) {
132
+ void update (const Function &F) {
101
133
// Declarations don't affect analyses.
102
134
if (F.isDeclaration ())
103
135
return ;
104
136
105
- hash (0x62642d6b6b2d6b72 ); // Function header
137
+ SmallVector<stable_hash> Hashes;
138
+ Hashes.emplace_back (Hash);
139
+ Hashes.emplace_back (FunctionHeaderHash);
106
140
107
- hash (F.isVarArg ());
108
- hash (F.arg_size ());
141
+ Hashes. emplace_back (F.isVarArg ());
142
+ Hashes. emplace_back (F.arg_size ());
109
143
110
144
SmallVector<const BasicBlock *, 8 > BBs;
111
145
SmallPtrSet<const BasicBlock *, 16 > VisitedBBs;
@@ -118,17 +152,17 @@ class StructuralHashImpl {
118
152
while (!BBs.empty ()) {
119
153
const BasicBlock *BB = BBs.pop_back_val ();
120
154
121
- // This random value acts as a block header, as otherwise the partition of
122
- // opcodes into BBs wouldn't affect the hash, only the order of the
123
- // opcodes
124
- hash (45798 );
155
+ Hashes.emplace_back (BlockHeaderHash);
125
156
for (auto &Inst : *BB)
126
- updateInstruction ( Inst, DetailedHash );
157
+ Hashes. emplace_back ( hashInstruction ( Inst) );
127
158
128
159
for (const BasicBlock *Succ : successors (BB))
129
160
if (VisitedBBs.insert (Succ).second )
130
161
BBs.push_back (Succ);
131
162
}
163
+
164
+ // Update the combined hash in place.
165
+ Hash = stable_hash_combine (Hashes);
132
166
}
133
167
134
168
void update (const GlobalVariable &GV) {
@@ -137,30 +171,35 @@ class StructuralHashImpl {
137
171
// we ignore anything with the `.llvm` prefix
138
172
if (GV.isDeclaration () || GV.getName ().starts_with (" llvm." ))
139
173
return ;
140
- hash (23456 ); // Global header
141
- hash (GV.getValueType ()->getTypeID ());
174
+ SmallVector<stable_hash> Hashes;
175
+ Hashes.emplace_back (Hash);
176
+ Hashes.emplace_back (GlobalHeaderHash);
177
+ Hashes.emplace_back (GV.getValueType ()->getTypeID ());
178
+
179
+ // Update the combined hash in place.
180
+ Hash = stable_hash_combine (Hashes);
142
181
}
143
182
144
- void update (const Module &M, bool DetailedHash ) {
183
+ void update (const Module &M) {
145
184
for (const GlobalVariable &GV : M.globals ())
146
185
update (GV);
147
186
for (const Function &F : M)
148
- update (F, DetailedHash );
187
+ update (F);
149
188
}
150
189
151
190
uint64_t getHash () const { return Hash; }
152
191
};
153
192
154
193
} // namespace
155
194
156
- IRHash llvm::StructuralHash (const Function &F, bool DetailedHash) {
157
- StructuralHashImpl H;
158
- H.update (F, DetailedHash );
195
+ stable_hash llvm::StructuralHash (const Function &F, bool DetailedHash) {
196
+ StructuralHashImpl H (DetailedHash) ;
197
+ H.update (F);
159
198
return H.getHash ();
160
199
}
161
200
162
- IRHash llvm::StructuralHash (const Module &M, bool DetailedHash) {
163
- StructuralHashImpl H;
164
- H.update (M, DetailedHash );
201
+ stable_hash llvm::StructuralHash (const Module &M, bool DetailedHash) {
202
+ StructuralHashImpl H (DetailedHash) ;
203
+ H.update (M);
165
204
return H.getHash ();
166
205
}
0 commit comments