@@ -28,6 +28,19 @@ class StructuralHashImpl {
2828
2929 bool DetailedHash;
3030
31+ // / IgnoreOp is a function that returns true if the operand should be ignored.
32+ IgnoreOperandFunc IgnoreOp = nullptr ;
33+ // / A mapping from instruction indices to instruction pointers.
34+ // / The index represents the position of an instruction based on the order in
35+ // / which it is first encountered.
36+ std::unique_ptr<IndexInstrMap> IndexInstruction = nullptr ;
37+ // / A mapping from pairs of instruction indices and operand indices
38+ // / to the hashes of the operands.
39+ std::unique_ptr<IndexOperandHashMapType> IndexOperandHashMap = nullptr ;
40+
41+ // / Assign a unique ID to each Value in the order they are first seen.
42+ DenseMap<const Value *, int > ValueToId;
43+
3144 // This will produce different values on 32-bit and 64-bit systens as
3245 // hash_combine returns a size_t. However, this is only used for
3346 // detailed hashing which, in-tree, only needs to distinguish between
@@ -47,24 +60,140 @@ class StructuralHashImpl {
4760
4861public:
4962 StructuralHashImpl () = delete ;
50- explicit StructuralHashImpl (bool DetailedHash) : DetailedHash(DetailedHash) {}
63+ explicit StructuralHashImpl (bool DetailedHash,
64+ IgnoreOperandFunc IgnoreOp = nullptr )
65+ : DetailedHash(DetailedHash), IgnoreOp(IgnoreOp) {
66+ if (IgnoreOp) {
67+ IndexInstruction = std::make_unique<IndexInstrMap>();
68+ IndexOperandHashMap = std::make_unique<IndexOperandHashMapType>();
69+ }
70+ }
5171
52- stable_hash hashConstant (Constant *C ) {
72+ stable_hash hashAPInt ( const APInt &I ) {
5373 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- // Hashing the name will be deterministic as LLVM's hashing infrastructure
61- // has explicit support for hashing strings and will not simply hash
62- // the pointer.
63- Hashes.emplace_back (hashArbitaryType (Func->getName ()));
74+ Hashes.emplace_back (I.getBitWidth ());
75+ for (unsigned J = 0 ; J < I.getNumWords (); ++J)
76+ Hashes.emplace_back ((I.getRawData ())[J]);
77+ return stable_hash_combine (Hashes);
78+ }
6479
80+ stable_hash hashAPFloat (const APFloat &F) {
81+ SmallVector<stable_hash> Hashes;
82+ const fltSemantics &S = F.getSemantics ();
83+ Hashes.emplace_back (APFloat::semanticsPrecision (S));
84+ Hashes.emplace_back (APFloat::semanticsMaxExponent (S));
85+ Hashes.emplace_back (APFloat::semanticsMinExponent (S));
86+ Hashes.emplace_back (APFloat::semanticsSizeInBits (S));
87+ Hashes.emplace_back (hashAPInt (F.bitcastToAPInt ()));
6588 return stable_hash_combine (Hashes);
6689 }
6790
91+ stable_hash hashGlobalValue (const GlobalValue *GV) {
92+ if (!GV->hasName ())
93+ return 0 ;
94+ return stable_hash_name (GV->getName ());
95+ }
96+
97+ // Compute a hash for a Constant. This function is logically similar to
98+ // FunctionComparator::cmpConstants() in FunctionComparator.cpp, but here
99+ // we're interested in computing a hash rather than comparing two Constants.
100+ // Some of the logic is simplified, e.g, we don't expand GEPOperator.
101+ stable_hash hashConstant (Constant *C) {
102+ SmallVector<stable_hash> Hashes;
103+
104+ Type *Ty = C->getType ();
105+ Hashes.emplace_back (hashType (Ty));
106+
107+ if (C->isNullValue ()) {
108+ Hashes.emplace_back (static_cast <stable_hash>(' N' ));
109+ return stable_hash_combine (Hashes);
110+ }
111+
112+ auto *G = dyn_cast<GlobalValue>(C);
113+ if (G) {
114+ Hashes.emplace_back (hashGlobalValue (G));
115+ return stable_hash_combine (Hashes);
116+ }
117+
118+ if (const auto *Seq = dyn_cast<ConstantDataSequential>(C)) {
119+ Hashes.emplace_back (xxh3_64bits (Seq->getRawDataValues ()));
120+ return stable_hash_combine (Hashes);
121+ }
122+
123+ switch (C->getValueID ()) {
124+ case Value::UndefValueVal:
125+ case Value::PoisonValueVal:
126+ case Value::ConstantTokenNoneVal: {
127+ return stable_hash_combine (Hashes);
128+ }
129+ case Value::ConstantIntVal: {
130+ const APInt &Int = cast<ConstantInt>(C)->getValue ();
131+ Hashes.emplace_back (hashAPInt (Int));
132+ return stable_hash_combine (Hashes);
133+ }
134+ case Value::ConstantFPVal: {
135+ const APFloat &APF = cast<ConstantFP>(C)->getValueAPF ();
136+ Hashes.emplace_back (hashAPFloat (APF));
137+ return stable_hash_combine (Hashes);
138+ }
139+ case Value::ConstantArrayVal: {
140+ const ConstantArray *A = cast<ConstantArray>(C);
141+ uint64_t NumElements = cast<ArrayType>(Ty)->getNumElements ();
142+ Hashes.emplace_back (NumElements);
143+ for (auto &Op : A->operands ()) {
144+ auto H = hashConstant (cast<Constant>(Op));
145+ Hashes.emplace_back (H);
146+ }
147+ return stable_hash_combine (Hashes);
148+ }
149+ case Value::ConstantStructVal: {
150+ const ConstantStruct *S = cast<ConstantStruct>(C);
151+ unsigned NumElements = cast<StructType>(Ty)->getNumElements ();
152+ Hashes.emplace_back (NumElements);
153+ for (auto &Op : S->operands ()) {
154+ auto H = hashConstant (cast<Constant>(Op));
155+ Hashes.emplace_back (H);
156+ }
157+ return stable_hash_combine (Hashes);
158+ }
159+ case Value::ConstantVectorVal: {
160+ const ConstantVector *V = cast<ConstantVector>(C);
161+ unsigned NumElements = cast<FixedVectorType>(Ty)->getNumElements ();
162+ Hashes.emplace_back (NumElements);
163+ for (auto &Op : V->operands ()) {
164+ auto H = hashConstant (cast<Constant>(Op));
165+ Hashes.emplace_back (H);
166+ }
167+ return stable_hash_combine (Hashes);
168+ }
169+ case Value::ConstantExprVal: {
170+ const ConstantExpr *E = cast<ConstantExpr>(C);
171+ unsigned NumOperands = E->getNumOperands ();
172+ Hashes.emplace_back (NumOperands);
173+ for (auto &Op : E->operands ()) {
174+ auto H = hashConstant (cast<Constant>(Op));
175+ Hashes.emplace_back (H);
176+ }
177+ return stable_hash_combine (Hashes);
178+ }
179+ case Value::BlockAddressVal: {
180+ const BlockAddress *BA = cast<BlockAddress>(C);
181+ auto H = hashGlobalValue (BA->getFunction ());
182+ Hashes.emplace_back (H);
183+ return stable_hash_combine (Hashes);
184+ }
185+ case Value::DSOLocalEquivalentVal: {
186+ const auto *Equiv = cast<DSOLocalEquivalent>(C);
187+ auto H = hashGlobalValue (Equiv->getGlobalValue ());
188+ Hashes.emplace_back (H);
189+ return stable_hash_combine (Hashes);
190+ }
191+ default : // Unknown constant, abort.
192+ llvm_unreachable (" Constant ValueID not recognized." );
193+ }
194+ return Hash;
195+ }
196+
68197 stable_hash hashValue (Value *V) {
69198 // Check constant and return its hash.
70199 Constant *C = dyn_cast<Constant>(V);
@@ -76,6 +205,10 @@ class StructuralHashImpl {
76205 if (Argument *Arg = dyn_cast<Argument>(V))
77206 Hashes.emplace_back (Arg->getArgNo ());
78207
208+ // Get an index (an insertion order) for the non-constant value.
209+ auto I = ValueToId.insert ({V, ValueToId.size ()});
210+ Hashes.emplace_back (I.first ->second );
211+
79212 return stable_hash_combine (Hashes);
80213 }
81214
@@ -100,8 +233,20 @@ class StructuralHashImpl {
100233 if (const auto *ComparisonInstruction = dyn_cast<CmpInst>(&Inst))
101234 Hashes.emplace_back (ComparisonInstruction->getPredicate ());
102235
103- for (const auto &Op : Inst.operands ())
104- Hashes.emplace_back (hashOperand (Op));
236+ unsigned InstIdx = 0 ;
237+ if (IndexInstruction) {
238+ InstIdx = IndexInstruction->size ();
239+ IndexInstruction->insert ({InstIdx, const_cast <Instruction *>(&Inst)});
240+ }
241+
242+ for (const auto [OpndIdx, Op] : enumerate(Inst.operands ())) {
243+ auto OpndHash = hashOperand (Op);
244+ if (IgnoreOp && IgnoreOp (&Inst, OpndIdx)) {
245+ assert (IndexOperandHashMap);
246+ IndexOperandHashMap->insert ({{InstIdx, OpndIdx}, OpndHash});
247+ } else
248+ Hashes.emplace_back (OpndHash);
249+ }
105250
106251 return stable_hash_combine (Hashes);
107252 }
@@ -184,6 +329,12 @@ class StructuralHashImpl {
184329 }
185330
186331 uint64_t getHash () const { return Hash; }
332+ std::unique_ptr<IndexInstrMap> getIndexInstrMap () {
333+ return std::move (IndexInstruction);
334+ }
335+ std::unique_ptr<IndexOperandHashMapType> getIndexPairOpndHashMap () {
336+ return std::move (IndexOperandHashMap);
337+ }
187338};
188339
189340} // namespace
@@ -199,3 +350,12 @@ IRHash llvm::StructuralHash(const Module &M, bool DetailedHash) {
199350 H.update (M);
200351 return H.getHash ();
201352}
353+
354+ FunctionHashInfo
355+ llvm::StructuralHashWithDifferences (const Function &F,
356+ IgnoreOperandFunc IgnoreOp) {
357+ StructuralHashImpl H (/* DetailedHash=*/ true , IgnoreOp);
358+ H.update (F);
359+ return FunctionHashInfo (H.getHash (), H.getIndexInstrMap (),
360+ H.getIndexPairOpndHashMap ());
361+ }
0 commit comments