1 // -*- mode: C++; c-file-style: "cc-mode" -*-
2 //*************************************************************************
3 // DESCRIPTION: Verilator: AstNode hash computation
4 //
5 // Code available from: https://verilator.org
6 //
7 //*************************************************************************
8 //
9 // Copyright 2003-2021 by Wilson Snyder. This program is free software; you
10 // can redistribute it and/or modify it under the terms of either the GNU
11 // Lesser General Public License Version 3 or the Perl Artistic License
12 // Version 2.0.
13 // SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
14 //
15 //*************************************************************************
16 
17 #include "config_build.h"
18 #include "verilatedos.h"
19 
20 #include "V3Hasher.h"
21 
22 #include <functional>
23 
24 //######################################################################
25 // Visitor that computes node hashes
26 
27 class HasherVisitor final : public AstNVisitor {
28 private:
29     // NODE STATE
30     //  AstNode::user4() -> V3Hash.  Hash value of this node (hash of 0 is illegal)
31     // AstUser4InUse     in V3Hasher.h
32 
33     // STATE
34     V3Hash m_hash;  // Hash value accumulator
35     const bool m_cacheInUser4;  // Use user4 to cache each V3Hash?
36 
37     // METHODS
38     VL_DEBUG_FUNC;  // Declare debug()
39 
hashNodeAndIterate(AstNode * nodep,bool hashDType,bool hashChildren,std::function<void ()> && f)40     V3Hash hashNodeAndIterate(AstNode* nodep, bool hashDType, bool hashChildren,
41                               std::function<void()>&& f) {
42         if (m_cacheInUser4 && nodep->user4()) {
43             return V3Hash(nodep->user4());
44         } else {
45             VL_RESTORER(m_hash);
46             // Reset accumulator
47             m_hash = V3Hash(nodep->type());  // Node type
48             f();  // Node specific hash
49             if (hashDType && nodep != nodep->dtypep()) iterateNull(nodep->dtypep());  // Node dtype
50             if (hashChildren) iterateChildrenConst(nodep);  // Children
51             if (m_cacheInUser4) nodep->user4(m_hash.value());
52             return m_hash;
53         }
54     }
55 
56     // VISITORS
57 
58     constexpr static bool HASH_DTYPE = true;
59     constexpr static bool HASH_CHILDREN = true;
60 
61     // Each visitor below contributes to the hash any node specific content
62     // that is not dependent on either of the following, as these are
63     // included by default by hashNode:
64     // - Node type (as given by AstNode::type())
65     // - Node dtype (unless !hashDType)
66     // - child nodes (unless !hashChildren)
67     //
68     // The hash must be stable, which means in particular it cannot rely on
69     // pointer values, or any other value that might differ between separate
70     // invocations of Verilator over the same design.
71     //
72     // Note there is a circularity problem where some child nodes can back
73     // to their ancestral nodes via member pointers, which can lead to an
74     // infinite traversal. To break this, nodes that are subject to such
75     // referencing and represent code which can reasonably be assumed not to
76     // be equivalent to any other code, are hashed either by name (e.g.:
77     // AstNodeModule), or by unique identifier (e.g.: AstNodeUOrStructDType).
78 
79     //------------------------------------------------------------
80     // AstNode - Warns to help find missing cases
81 
visit(AstNode * nodep)82     virtual void visit(AstNode* nodep) override {
83 #if VL_DEBUG
84         UINFO(0, "%Warning: Hashing node as AstNode: " << nodep << endl);
85 #endif
86         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {});
87     }
88 
89     //------------------------------------------------------------
90     // AstNodeDType
visit(AstNodeArrayDType * nodep)91     virtual void visit(AstNodeArrayDType* nodep) override {
92         m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() {
93             iterateNull(nodep->virtRefDTypep());
94             m_hash += nodep->left();
95             m_hash += nodep->right();
96         });
97     }
visit(AstNodeUOrStructDType * nodep)98     virtual void visit(AstNodeUOrStructDType* nodep) override {
99         m_hash += hashNodeAndIterate(nodep, false, false, [=]() {  //
100             m_hash += nodep->uniqueNum();
101         });
102     }
visit(AstParamTypeDType * nodep)103     virtual void visit(AstParamTypeDType* nodep) override {
104         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {
105             m_hash += nodep->name();
106             m_hash += nodep->varType();
107         });
108     }
visit(AstMemberDType * nodep)109     virtual void visit(AstMemberDType* nodep) override {
110         m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() {  //
111             m_hash += nodep->name();
112         });
113     }
visit(AstDefImplicitDType * nodep)114     virtual void visit(AstDefImplicitDType* nodep) override {
115         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {  //
116             m_hash += nodep->uniqueNum();
117         });
118     }
visit(AstAssocArrayDType * nodep)119     virtual void visit(AstAssocArrayDType* nodep) override {
120         m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() {
121             iterateNull(nodep->virtRefDTypep());
122             iterateNull(nodep->virtRefDType2p());
123         });
124     }
visit(AstDynArrayDType * nodep)125     virtual void visit(AstDynArrayDType* nodep) override {
126         m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() {  //
127             iterateNull(nodep->virtRefDTypep());
128         });
129     }
visit(AstUnsizedArrayDType * nodep)130     virtual void visit(AstUnsizedArrayDType* nodep) override {
131         m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() {  //
132             iterateNull(nodep->virtRefDTypep());
133         });
134     }
visit(AstBasicDType * nodep)135     virtual void visit(AstBasicDType* nodep) override {
136         m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() {
137             m_hash += nodep->keyword();
138             m_hash += nodep->nrange().left();
139             m_hash += nodep->nrange().right();
140         });
141     }
visit(AstConstDType * nodep)142     virtual void visit(AstConstDType* nodep) override {
143         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {  //
144             iterateNull(nodep->virtRefDTypep());
145         });
146     }
visit(AstClassRefDType * nodep)147     virtual void visit(AstClassRefDType* nodep) override {
148         m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() {  //
149             iterateNull(nodep->classp());
150         });
151     }
visit(AstIfaceRefDType * nodep)152     virtual void visit(AstIfaceRefDType* nodep) override {
153         m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() {  //
154             iterateNull(nodep->cellp());
155         });
156     }
visit(AstQueueDType * nodep)157     virtual void visit(AstQueueDType* nodep) override {
158         m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() {  //
159             iterateNull(nodep->virtRefDTypep());
160         });
161     }
visit(AstRefDType * nodep)162     virtual void visit(AstRefDType* nodep) override {
163         m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() {
164             m_hash += nodep->name();
165             iterateNull(nodep->typedefp());
166             iterateNull(nodep->refDTypep());
167         });
168     }
visit(AstVoidDType * nodep)169     virtual void visit(AstVoidDType* nodep) override {
170         m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() {});
171     }
visit(AstEnumDType * nodep)172     virtual void visit(AstEnumDType* nodep) override {
173         m_hash += hashNodeAndIterate(nodep, false, false, [=]() {  //
174             m_hash += nodep->uniqueNum();
175         });
176     }
177 
178     //------------------------------------------------------------
179     // AstNodeMath
visit(AstNodeMath * nodep)180     virtual void visit(AstNodeMath* nodep) override {
181         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {});
182     }
visit(AstConst * nodep)183     virtual void visit(AstConst* nodep) override {
184         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {  //
185             m_hash += nodep->num().toHash();
186         });
187     }
visit(AstNullCheck * nodep)188     virtual void visit(AstNullCheck* nodep) override {
189         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {});
190     }
visit(AstCCast * nodep)191     virtual void visit(AstCCast* nodep) override {
192         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {  //
193             m_hash += nodep->size();
194         });
195     }
visit(AstVarRef * nodep)196     virtual void visit(AstVarRef* nodep) override {
197         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {
198             if (nodep->varScopep()) {
199                 iterateNull(nodep->varScopep());
200             } else {
201                 iterateNull(nodep->varp());
202                 m_hash += nodep->selfPointer();
203             }
204         });
205     }
visit(AstVarXRef * nodep)206     virtual void visit(AstVarXRef* nodep) override {
207         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {
208             iterateNull(nodep->varp());
209             m_hash += nodep->dotted();
210         });
211     }
visit(AstMemberSel * nodep)212     virtual void visit(AstMemberSel* nodep) override {
213         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {  //
214             m_hash += nodep->name();
215         });
216     }
visit(AstFScanF * nodep)217     virtual void visit(AstFScanF* nodep) override {
218         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {  //
219             m_hash += nodep->text();
220         });
221     }
visit(AstSScanF * nodep)222     virtual void visit(AstSScanF* nodep) override {
223         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {  //
224             m_hash += nodep->text();
225         });
226     }
visit(AstTestPlusArgs * nodep)227     virtual void visit(AstTestPlusArgs* nodep) override {
228         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {  //
229             m_hash += nodep->text();
230         });
231     }
visit(AstAddrOfCFunc * nodep)232     virtual void visit(AstAddrOfCFunc* nodep) override {
233         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {  //
234             iterateNull(nodep->funcp());
235         });
236     }
237 
238     //------------------------------------------------------------
239     // AstNodeStmt
visit(AstNodeStmt * nodep)240     virtual void visit(AstNodeStmt* nodep) override {
241         m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() {});
242     }
visit(AstNodeText * nodep)243     virtual void visit(AstNodeText* nodep) override {
244         m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() {  //
245             m_hash += nodep->text();
246         });
247     }
visit(AstNodeCCall * nodep)248     virtual void visit(AstNodeCCall* nodep) override {
249         m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() {  //
250             iterateNull(nodep->funcp());
251         });
252     }
visit(AstNodeFTaskRef * nodep)253     virtual void visit(AstNodeFTaskRef* nodep) override {
254         m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() {
255             iterateNull(nodep->taskp());
256             iterateNull(nodep->classOrPackagep());
257         });
258     }
visit(AstCMethodHard * nodep)259     virtual void visit(AstCMethodHard* nodep) override {
260         m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() {  //
261             m_hash += nodep->name();
262         });
263     }
visit(AstCoverInc * nodep)264     virtual void visit(AstCoverInc* nodep) override {
265         m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() {  //
266             iterateNull(nodep->declp());
267         });
268     }
visit(AstDisplay * nodep)269     virtual void visit(AstDisplay* nodep) override {
270         m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() {  //
271             m_hash += nodep->displayType();
272         });
273     }
visit(AstMonitorOff * nodep)274     virtual void visit(AstMonitorOff* nodep) override {
275         m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() {  //
276             m_hash += nodep->off();
277         });
278     }
visit(AstJumpGo * nodep)279     virtual void visit(AstJumpGo* nodep) override {
280         m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() {  //
281             iterateNull(nodep->labelp());
282         });
283     }
visit(AstTraceInc * nodep)284     virtual void visit(AstTraceInc* nodep) override {
285         m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() {  //
286             iterateNull(nodep->declp());
287         });
288     }
visit(AstNodeCoverOrAssert * nodep)289     virtual void visit(AstNodeCoverOrAssert* nodep) override {
290         m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() {  //
291             m_hash += nodep->name();
292         });
293     }
294 
295     //------------------------------------------------------------
296     // AstNode direct descendents
visit(AstNodeRange * nodep)297     virtual void visit(AstNodeRange* nodep) override {
298         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {});
299     }
visit(AstNodeModule * nodep)300     virtual void visit(AstNodeModule* nodep) override {
301         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, false, [=]() {
302             m_hash += nodep->origName();
303             m_hash += nodep->hierName();
304         });
305     }
visit(AstNodePreSel * nodep)306     virtual void visit(AstNodePreSel* nodep) override {
307         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {});
308     }
visit(AstClassExtends * nodep)309     virtual void visit(AstClassExtends* nodep) override {
310         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {});
311     }
visit(AstSelLoopVars * nodep)312     virtual void visit(AstSelLoopVars* nodep) override {
313         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {});
314     }
visit(AstDefParam * nodep)315     virtual void visit(AstDefParam* nodep) override {
316         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {});
317     }
visit(AstArg * nodep)318     virtual void visit(AstArg* nodep) override {
319         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {});
320     }
visit(AstParseRef * nodep)321     virtual void visit(AstParseRef* nodep) override {
322         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {
323             m_hash += nodep->expect();
324             m_hash += nodep->name();
325         });
326     }
visit(AstClassOrPackageRef * nodep)327     virtual void visit(AstClassOrPackageRef* nodep) override {
328         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {  //
329             iterateNull(nodep->classOrPackageNodep());
330         });
331     }
visit(AstSenItem * nodep)332     virtual void visit(AstSenItem* nodep) override {
333         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {  //
334             m_hash += nodep->edgeType();
335         });
336     }
visit(AstSenTree * nodep)337     virtual void visit(AstSenTree* nodep) override {
338         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {});
339     }
visit(AstSFormatF * nodep)340     virtual void visit(AstSFormatF* nodep) override {
341         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {  //
342             m_hash += nodep->text();
343         });
344     }
visit(AstElabDisplay * nodep)345     virtual void visit(AstElabDisplay* nodep) override {
346         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {  //
347             m_hash += nodep->displayType();
348         });
349     }
visit(AstInitItem * nodep)350     virtual void visit(AstInitItem* nodep) override {
351         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {});
352     }
visit(AstInitArray * nodep)353     virtual void visit(AstInitArray* nodep) override {
354         // Hash unpacked array initializers by value, as the order of initializer nodes does not
355         // matter, and we want semantically equivalent initializers to map to the same hash.
356         const AstUnpackArrayDType* const dtypep = VN_CAST(nodep->dtypep(), UnpackArrayDType);
357         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, /* hashChildren: */ !dtypep, [=]() {
358             if (dtypep) {
359                 const uint32_t size = dtypep->elementsConst();
360                 for (uint32_t n = 0; n < size; ++n) {  //
361                     iterateNull(nodep->getIndexDefaultedValuep(n));
362                 }
363             }
364         });
365     }
visit(AstPragma * nodep)366     virtual void visit(AstPragma* nodep) override {
367         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {  //
368             m_hash += nodep->pragType();
369         });
370     }
visit(AstAttrOf * nodep)371     virtual void visit(AstAttrOf* nodep) override {
372         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {  //
373             m_hash += nodep->attrType();
374         });
375     }
visit(AstNodeFile * nodep)376     virtual void visit(AstNodeFile* nodep) override {
377         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {  //
378             m_hash += nodep->name();
379         });
380     }
visit(AstCFunc * nodep)381     virtual void visit(AstCFunc* nodep) override {
382         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {  //
383             m_hash += nodep->isLoose();
384         });
385     }
visit(AstVar * nodep)386     virtual void visit(AstVar* nodep) override {
387         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {
388             m_hash += nodep->name();
389             m_hash += nodep->varType();
390         });
391     }
visit(AstScope * nodep)392     virtual void visit(AstScope* nodep) override {
393         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, false, [=]() {
394             m_hash += nodep->name();
395             iterateNull(nodep->aboveScopep());
396         });
397     }
visit(AstVarScope * nodep)398     virtual void visit(AstVarScope* nodep) override {
399         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {
400             iterateNull(nodep->varp());
401             iterateNull(nodep->scopep());
402         });
403     }
visit(AstEnumItem * nodep)404     virtual void visit(AstEnumItem* nodep) override {
405         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {  //
406             m_hash += nodep->name();
407         });
408     }
visit(AstTypedef * nodep)409     virtual void visit(AstTypedef* nodep) override {
410         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {  //
411             m_hash += nodep->name();
412         });
413     }
visit(AstTypedefFwd * nodep)414     virtual void visit(AstTypedefFwd* nodep) override {
415         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {  //
416             m_hash += nodep->name();
417         });
418     }
visit(AstActive * nodep)419     virtual void visit(AstActive* nodep) override {
420         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {  //
421             iterateNull(nodep->sensesp());
422         });
423     }
visit(AstCell * nodep)424     virtual void visit(AstCell* nodep) override {
425         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {
426             m_hash += nodep->name();
427             iterateNull(nodep->modp());
428         });
429     }
visit(AstCellInline * nodep)430     virtual void visit(AstCellInline* nodep) override {
431         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {
432             m_hash += nodep->name();
433             iterateNull(nodep->scopep());
434         });
435     }
visit(AstNodeFTask * nodep)436     virtual void visit(AstNodeFTask* nodep) override {
437         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {  //
438             m_hash += nodep->name();
439         });
440     }
visit(AstModport * nodep)441     virtual void visit(AstModport* nodep) override {
442         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {  //
443             m_hash += nodep->name();
444         });
445     }
visit(AstModportVarRef * nodep)446     virtual void visit(AstModportVarRef* nodep) override {
447         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {
448             m_hash += nodep->name();
449             iterateNull(nodep->varp());
450         });
451     }
visit(AstModportFTaskRef * nodep)452     virtual void visit(AstModportFTaskRef* nodep) override {
453         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {
454             m_hash += nodep->name();
455             iterateNull(nodep->ftaskp());
456         });
457     }
visit(AstMTaskBody * nodep)458     virtual void visit(AstMTaskBody* nodep) override {
459         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {});
460     }
visit(AstNodeProcedure * nodep)461     virtual void visit(AstNodeProcedure* nodep) override {
462         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {});
463     }
visit(AstNodeBlock * nodep)464     virtual void visit(AstNodeBlock* nodep) override {
465         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {  //
466             m_hash += nodep->name();
467         });
468     }
visit(AstPin * nodep)469     virtual void visit(AstPin* nodep) override {
470         m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {
471             m_hash += nodep->name();
472             m_hash += nodep->pinNum();
473         });
474     }
475 
476 public:
477     // CONSTRUCTORS
HasherVisitor(AstNode * nodep)478     explicit HasherVisitor(AstNode* nodep)
479         : m_cacheInUser4{true} {
480         iterate(nodep);
481     }
HasherVisitor(const AstNode * nodep)482     explicit HasherVisitor(const AstNode* nodep)
483         : m_cacheInUser4{false} {
484         iterate(const_cast<AstNode*>(nodep));
485     }
finalHash() const486     V3Hash finalHash() const { return m_hash; }
487     virtual ~HasherVisitor() override = default;
488 };
489 
490 //######################################################################
491 // V3Hasher methods
492 
operator ()(AstNode * nodep) const493 V3Hash V3Hasher::operator()(AstNode* nodep) const {
494     if (!nodep->user4()) { HasherVisitor{nodep}; }
495     return V3Hash(nodep->user4());
496 }
497 
uncachedHash(const AstNode * nodep)498 V3Hash V3Hasher::uncachedHash(const AstNode* nodep) {
499     const HasherVisitor visitor{nodep};
500     return visitor.finalHash();
501 }
502