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