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