1 // -*- mode: C++; c-file-style: "cc-mode" -*-
2 //*************************************************************************
3 // DESCRIPTION: Verilator: Hashed common code into functions
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 "V3Global.h"
21 #include "V3DupFinder.h"
22 #include "V3Ast.h"
23 #include "V3File.h"
24 
25 #include <algorithm>
26 #include <iomanip>
27 #include <map>
28 #include <memory>
29 
30 //######################################################################
31 // V3DupFinder class functions
32 
findDuplicate(AstNode * nodep,V3DupFinderUserSame * checkp)33 V3DupFinder::iterator V3DupFinder::findDuplicate(AstNode* nodep, V3DupFinderUserSame* checkp) {
34     const auto& er = equal_range(m_hasher(nodep));
35     for (iterator it = er.first; it != er.second; ++it) {
36         AstNode* const node2p = it->second;
37         if (nodep == node2p) continue;  // Same node is not a duplicate
38         if (checkp && !checkp->isSame(nodep, node2p)) continue;  // User says it is not a duplicate
39         if (!nodep->sameTree(node2p)) continue;  // Not the same trees
40         // Found duplicate!
41         return it;
42     }
43     return end();
44 }
45 
dumpFile(const string & filename,bool tree)46 void V3DupFinder::dumpFile(const string& filename, bool tree) {
47     const std::unique_ptr<std::ofstream> logp{V3File::new_ofstream(filename)};
48     if (logp->fail()) v3fatal("Can't write " << filename);
49 
50     std::unordered_map<int, int> dist;
51 
52     V3Hash lasthash;
53     int num_in_bucket = 0;
54     for (auto it = cbegin(); true; ++it) {
55         if (it == cend() || lasthash != it->first) {
56             if (it != cend()) lasthash = it->first;
57             if (num_in_bucket) {
58                 if (dist.find(num_in_bucket) == dist.end()) {
59                     dist.emplace(num_in_bucket, 1);
60                 } else {
61                     ++dist[num_in_bucket];
62                 }
63             }
64             num_in_bucket = 0;
65         }
66         if (it == cend()) break;
67         num_in_bucket++;
68     }
69     *logp << "\n*** STATS:\n\n";
70     *logp << "    #InBucket   Occurrences\n";
71     for (const auto& i : dist) {
72         *logp << "    " << std::setw(9) << i.first << "  " << std::setw(12) << i.second << '\n';
73     }
74 
75     *logp << "\n*** Dump:\n\n";
76     for (const auto& it : *this) {
77         if (lasthash != it.first) {
78             lasthash = it.first;
79             *logp << "    " << it.first << '\n';
80         }
81         *logp << "\t" << it.second << '\n';
82         // Dumping the entire tree may make nearly N^2 sized dumps,
83         // because the nodes under this one may also be in the hash table!
84         if (tree) it.second->dumpTree(*logp, "    ");
85     }
86 }
87 
dumpFilePrefixed(const string & nameComment,bool tree)88 void V3DupFinder::dumpFilePrefixed(const string& nameComment, bool tree) {
89     if (v3Global.opt.dumpTree()) {  //
90         dumpFile(v3Global.debugFilename(nameComment) + ".hash", tree);
91     }
92 }
93