@@ -34,14 +34,18 @@ class StructuralHashImpl {
3434 static constexpr stable_hash FunctionHeaderHash = 0x62642d6b6b2d6b72 ;
3535 static constexpr stable_hash GlobalHeaderHash = 23456 ;
3636
37- // This will produce different values on 32-bit and 64-bit systens as
38- // hash_combine returns a size_t. However, this is only used for
39- // detailed hashing which, in-tree, only needs to distinguish between
40- // differences in functions.
41- // TODO: This is not stable.
42- template <typename T> stable_hash hashArbitaryType (const T &V) {
43- return hash_combine (V);
44- }
37+ // / IgnoreOp is a function that returns true if the operand should be ignored.
38+ IgnoreOperandFunc IgnoreOp = nullptr ;
39+ // / A mapping from instruction indices to instruction pointers.
40+ // / The index represents the position of an instruction based on the order in
41+ // / which it is first encountered.
42+ std::unique_ptr<IndexInstrMap> IndexInstruction = nullptr ;
43+ // / A mapping from pairs of instruction indices and operand indices
44+ // / to the hashes of the operands.
45+ std::unique_ptr<IndexOperandHashMapType> IndexOperandHashMap = nullptr ;
46+
47+ // / Assign a unique ID to each Value in the order they are first seen.
48+ DenseMap<const Value *, int > ValueToId;
4549
4650 stable_hash hashType (Type *ValueType) {
4751 SmallVector<stable_hash> Hashes;
@@ -53,23 +57,95 @@ class StructuralHashImpl {
5357
5458public:
5559 StructuralHashImpl () = delete ;
56- explicit StructuralHashImpl (bool DetailedHash) : DetailedHash(DetailedHash) {}
60+ explicit StructuralHashImpl (bool DetailedHash,
61+ IgnoreOperandFunc IgnoreOp = nullptr )
62+ : DetailedHash(DetailedHash), IgnoreOp(IgnoreOp) {
63+ if (IgnoreOp) {
64+ IndexInstruction = std::make_unique<IndexInstrMap>();
65+ IndexOperandHashMap = std::make_unique<IndexOperandHashMapType>();
66+ }
67+ }
68+
69+ stable_hash hashAPInt (const APInt &I) {
70+ SmallVector<stable_hash> Hashes;
71+ Hashes.emplace_back (I.getBitWidth ());
72+ auto RawVals = ArrayRef<uint64_t >(I.getRawData (), I.getNumWords ());
73+ Hashes.append (RawVals.begin (), RawVals.end ());
74+ return stable_hash_combine (Hashes);
75+ }
76+
77+ stable_hash hashAPFloat (const APFloat &F) {
78+ return hashAPInt (F.bitcastToAPInt ());
79+ }
80+
81+ stable_hash hashGlobalValue (const GlobalValue *GV) {
82+ if (!GV->hasName ())
83+ return 0 ;
84+ return stable_hash_name (GV->getName ());
85+ }
5786
87+ // Compute a hash for a Constant. This function is logically similar to
88+ // FunctionComparator::cmpConstants() in FunctionComparator.cpp, but here
89+ // we're interested in computing a hash rather than comparing two Constants.
90+ // Some of the logic is simplified, e.g, we don't expand GEPOperator.
5891 stable_hash hashConstant (Constant *C) {
5992 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)) {
66- // Hashing the name will be deterministic as LLVM's hashing infrastructure
67- // has explicit support for hashing strings and will not simply hash
68- // the pointer.
69- Hashes.emplace_back (hashArbitaryType (Func->getName ()));
93+
94+ Type *Ty = C->getType ();
95+ Hashes.emplace_back (hashType (Ty));
96+
97+ if (C->isNullValue ()) {
98+ Hashes.emplace_back (static_cast <stable_hash>(' N' ));
99+ return stable_hash_combine (Hashes);
70100 }
71101
72- return stable_hash_combine (Hashes);
102+ if (auto *G = dyn_cast<GlobalValue>(C)) {
103+ Hashes.emplace_back (hashGlobalValue (G));
104+ return stable_hash_combine (Hashes);
105+ }
106+
107+ if (const auto *Seq = dyn_cast<ConstantDataSequential>(C)) {
108+ Hashes.emplace_back (xxh3_64bits (Seq->getRawDataValues ()));
109+ return stable_hash_combine (Hashes);
110+ }
111+
112+ switch (C->getValueID ()) {
113+ case Value::ConstantIntVal: {
114+ const APInt &Int = cast<ConstantInt>(C)->getValue ();
115+ Hashes.emplace_back (hashAPInt (Int));
116+ return stable_hash_combine (Hashes);
117+ }
118+ case Value::ConstantFPVal: {
119+ const APFloat &APF = cast<ConstantFP>(C)->getValueAPF ();
120+ Hashes.emplace_back (hashAPFloat (APF));
121+ return stable_hash_combine (Hashes);
122+ }
123+ case Value::ConstantArrayVal:
124+ case Value::ConstantStructVal:
125+ case Value::ConstantVectorVal:
126+ case Value::ConstantExprVal: {
127+ for (const auto &Op : C->operands ()) {
128+ auto H = hashConstant (cast<Constant>(Op));
129+ Hashes.emplace_back (H);
130+ }
131+ return stable_hash_combine (Hashes);
132+ }
133+ case Value::BlockAddressVal: {
134+ const BlockAddress *BA = cast<BlockAddress>(C);
135+ auto H = hashGlobalValue (BA->getFunction ());
136+ Hashes.emplace_back (H);
137+ return stable_hash_combine (Hashes);
138+ }
139+ case Value::DSOLocalEquivalentVal: {
140+ const auto *Equiv = cast<DSOLocalEquivalent>(C);
141+ auto H = hashGlobalValue (Equiv->getGlobalValue ());
142+ Hashes.emplace_back (H);
143+ return stable_hash_combine (Hashes);
144+ }
145+ default :
146+ // Skip other types of constants for simplicity.
147+ return stable_hash_combine (Hashes);
148+ }
73149 }
74150
75151 stable_hash hashValue (Value *V) {
@@ -83,6 +159,10 @@ class StructuralHashImpl {
83159 if (Argument *Arg = dyn_cast<Argument>(V))
84160 Hashes.emplace_back (Arg->getArgNo ());
85161
162+ // Get an index (an insertion order) for the non-constant value.
163+ auto [It, WasInserted] = ValueToId.try_emplace (V, ValueToId.size ());
164+ Hashes.emplace_back (It->second );
165+
86166 return stable_hash_combine (Hashes);
87167 }
88168
@@ -107,8 +187,20 @@ class StructuralHashImpl {
107187 if (const auto *ComparisonInstruction = dyn_cast<CmpInst>(&Inst))
108188 Hashes.emplace_back (ComparisonInstruction->getPredicate ());
109189
110- for (const auto &Op : Inst.operands ())
111- Hashes.emplace_back (hashOperand (Op));
190+ unsigned InstIdx = 0 ;
191+ if (IndexInstruction) {
192+ InstIdx = IndexInstruction->size ();
193+ IndexInstruction->try_emplace (InstIdx, const_cast <Instruction *>(&Inst));
194+ }
195+
196+ for (const auto [OpndIdx, Op] : enumerate(Inst.operands ())) {
197+ auto OpndHash = hashOperand (Op);
198+ if (IgnoreOp && IgnoreOp (&Inst, OpndIdx)) {
199+ assert (IndexOperandHashMap);
200+ IndexOperandHashMap->try_emplace ({InstIdx, OpndIdx}, OpndHash);
201+ } else
202+ Hashes.emplace_back (OpndHash);
203+ }
112204
113205 return stable_hash_combine (Hashes);
114206 }
@@ -188,6 +280,14 @@ class StructuralHashImpl {
188280 }
189281
190282 uint64_t getHash () const { return Hash; }
283+
284+ std::unique_ptr<IndexInstrMap> getIndexInstrMap () {
285+ return std::move (IndexInstruction);
286+ }
287+
288+ std::unique_ptr<IndexOperandHashMapType> getIndexPairOpndHashMap () {
289+ return std::move (IndexOperandHashMap);
290+ }
191291};
192292
193293} // namespace
@@ -203,3 +303,12 @@ stable_hash llvm::StructuralHash(const Module &M, bool DetailedHash) {
203303 H.update (M);
204304 return H.getHash ();
205305}
306+
307+ FunctionHashInfo
308+ llvm::StructuralHashWithDifferences (const Function &F,
309+ IgnoreOperandFunc IgnoreOp) {
310+ StructuralHashImpl H (/* DetailedHash=*/ true , IgnoreOp);
311+ H.update (F);
312+ return FunctionHashInfo (H.getHash (), H.getIndexInstrMap (),
313+ H.getIndexPairOpndHashMap ());
314+ }
0 commit comments