@@ -33,9 +33,25 @@ class HasherVisitor final : public VNVisitorConst {
33
33
// STATE
34
34
V3Hash m_hash; // Hash value accumulator
35
35
const bool m_cacheInUser4; // Use user4 to cache each V3Hash?
36
+ std::set<AstNode*> m_visited; // Keeps track of some visited nodes to prevent
37
+ // infinite recursion
36
38
37
39
// METHODS
38
40
41
+ void guardRecursion (AstNode* const nodep, std::function<void ()>&& f) {
42
+ // Guard against infinite recursion if there's no caching
43
+ // Otherwise caching does the same but faster
44
+ if (!m_cacheInUser4) {
45
+ bool isOnStack = false ;
46
+ if (m_visited.find (nodep) != m_visited.end ()) {
47
+ m_hash += V3Hash{nodep->name ()};
48
+ return ;
49
+ }
50
+ m_visited.insert (nodep);
51
+ }
52
+ f ();
53
+ }
54
+
39
55
V3Hash hashNodeAndIterate (AstNode* nodep, bool hashDType, bool hashChildren,
40
56
std::function<void ()>&& f) {
41
57
// See comments in visit(AstCFunc) about this breaking recursion
@@ -410,14 +426,16 @@ class HasherVisitor final : public VNVisitorConst {
410
426
});
411
427
}
412
428
void visit (AstCFunc* nodep) override {
413
- m_hash += hashNodeAndIterate (nodep, HASH_DTYPE, HASH_CHILDREN, [this , nodep]() { //
414
- // We might be in a recursive function, if so on *second* call
415
- // here we need to break what would be an infinite loop.
416
- nodep->user4 (V3Hash{1 }.value ()); // Set this "first" call
417
- // So that a second call will then exit hashNodeAndIterate
418
- // Having a constant in the hash just means the recursion will
419
- // end, it shouldn't change the CFunc having a unique hash itself.
420
- m_hash += nodep->isLoose ();
429
+ guardRecursion (nodep, [this , nodep]() { //
430
+ m_hash += hashNodeAndIterate (nodep, HASH_DTYPE, HASH_CHILDREN, [this , nodep]() { //
431
+ // We might be in a recursive function, if so on *second* call
432
+ // here we need to break what would be an infinite loop.
433
+ if (m_cacheInUser4) nodep->user4 (V3Hash{1 }.value ()); // Set this "first" call
434
+ // So that a second call will then exit hashNodeAndIterate
435
+ // Having a constant in the hash just means the recursion will
436
+ // end, it shouldn't change the CFunc having a unique hash itself.
437
+ m_hash += nodep->isLoose ();
438
+ });
421
439
});
422
440
}
423
441
void visit (AstVar* nodep) override {
@@ -469,8 +487,12 @@ class HasherVisitor final : public VNVisitorConst {
469
487
[this , nodep]() { m_hash += nodep->name (); });
470
488
}
471
489
void visit (AstNodeFTask* nodep) override {
472
- m_hash += hashNodeAndIterate (nodep, HASH_DTYPE, HASH_CHILDREN, [this , nodep]() { //
473
- m_hash += nodep->name ();
490
+ guardRecursion (nodep, [this , nodep]() { //
491
+ m_hash += hashNodeAndIterate (nodep, HASH_DTYPE, HASH_CHILDREN, [this , nodep]() { //
492
+ m_hash += nodep->name ();
493
+ // See comments in AstCFunc
494
+ if (m_cacheInUser4) nodep->user4 (V3Hash{1 }.value ());
495
+ });
474
496
});
475
497
}
476
498
void visit (AstModport* nodep) override {
0 commit comments