mirror of
https://github.com/verilator/verilator.git
synced 2025-04-16 01:26:54 +00:00
Split V3Hashed to V3Hasher and V3DupFinder (#2967)
V3Hasher is responsible for computing AstNode hashes, while V3DupFinder can be used to find duplicate trees based on hashes. Interface of V3DupFinder simplified somewhat. No functional change intended at this point, but hash computation might differ in minor details, this however should have no perceivable effect on output/runtime. Implements (#2964)
This commit is contained in:
parent
a44d2b2570
commit
fd35492226
@ -181,6 +181,7 @@ RAW_OBJS = \
|
||||
V3Depth.o \
|
||||
V3DepthBlock.o \
|
||||
V3Descope.o \
|
||||
V3DupFinder.o \
|
||||
V3EmitC.o \
|
||||
V3EmitCInlines.o \
|
||||
V3EmitCSyms.o \
|
||||
@ -202,7 +203,7 @@ RAW_OBJS = \
|
||||
V3GraphDfa.o \
|
||||
V3GraphPathChecker.o \
|
||||
V3GraphTest.o \
|
||||
V3Hashed.o \
|
||||
V3Hasher.o \
|
||||
V3HierBlock.o \
|
||||
V3Inline.o \
|
||||
V3Inst.o \
|
||||
|
@ -1358,12 +1358,9 @@ public:
|
||||
}
|
||||
// Creating from raw data (sameHash functions)
|
||||
V3Hash() { setBoth(1, 0); }
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
V3Hash(uint32_t val) { setBoth(1, val); }
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
V3Hash(const void* vp) { setBoth(1, cvtToHash(vp)); }
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
V3Hash(const string& name);
|
||||
explicit V3Hash(uint32_t val) { setBoth(1, val); }
|
||||
explicit V3Hash(const void* vp) { setBoth(1, cvtToHash(vp)); }
|
||||
explicit V3Hash(const string& name);
|
||||
V3Hash(V3Hash h1, V3Hash h2) { setBoth(1, h1.hshval() * 31 + h2.hshval()); }
|
||||
V3Hash(V3Hash h1, V3Hash h2, V3Hash h3) {
|
||||
setBoth(1, (h1.hshval() * 31 + h2.hshval()) * 31 + h3.hshval());
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
#include "V3Global.h"
|
||||
#include "V3Combine.h"
|
||||
#include "V3Hashed.h"
|
||||
#include "V3DupFinder.h"
|
||||
#include "V3Stats.h"
|
||||
#include "V3Ast.h"
|
||||
|
||||
@ -114,16 +114,16 @@ private:
|
||||
// NODE STATE
|
||||
// Entire netlist:
|
||||
AstUser3InUse m_user3InUse; // Marks replaced AstCFuncs
|
||||
// AstUser4InUse part of V3Hashed
|
||||
// AstUser4InUse part of V3Hasher in V3DupFinder
|
||||
|
||||
// STATE
|
||||
VDouble0 m_cfuncsCombined; // Statistic tracking
|
||||
CombCallVisitor m_call; // Tracking of function call users
|
||||
V3Hashed m_hashed; // Hash for every CFunc in module
|
||||
V3DupFinder m_dupFinder; // Duplicate finder for CFuncs in module
|
||||
|
||||
// METHODS
|
||||
void walkEmptyFuncs() {
|
||||
for (const auto& itr : m_hashed) {
|
||||
for (const auto& itr : m_dupFinder) {
|
||||
AstCFunc* const oldfuncp = VN_CAST(itr.second, CFunc);
|
||||
UASSERT_OBJ(oldfuncp, itr.second, "Not a CFunc in hash");
|
||||
if (!oldfuncp->emptyBody()) continue;
|
||||
@ -144,14 +144,14 @@ private:
|
||||
void walkDupFuncs() {
|
||||
// Do non-slow first as then favors naming functions based on fast name
|
||||
for (const bool slow : {false, true}) {
|
||||
for (auto newIt = m_hashed.begin(); newIt != m_hashed.end(); ++newIt) {
|
||||
for (auto newIt = m_dupFinder.begin(); newIt != m_dupFinder.end(); ++newIt) {
|
||||
AstCFunc* const newfuncp = VN_CAST(newIt->second, CFunc);
|
||||
UASSERT_OBJ(newfuncp, newIt->second, "Not a CFunc in hash");
|
||||
if (newfuncp->user3()) continue; // Already replaced
|
||||
if (newfuncp->slow() != slow) continue;
|
||||
auto oldIt = newIt;
|
||||
++oldIt; // Skip over current position
|
||||
for (; oldIt != m_hashed.end(); ++oldIt) {
|
||||
for (; oldIt != m_dupFinder.end(); ++oldIt) {
|
||||
AstCFunc* const oldfuncp = VN_CAST(oldIt->second, CFunc);
|
||||
UASSERT_OBJ(oldfuncp, oldIt->second, "Not a CFunc in hash");
|
||||
UASSERT_OBJ(newfuncp != oldfuncp, newfuncp,
|
||||
@ -184,10 +184,10 @@ private:
|
||||
}
|
||||
virtual void visit(AstNodeModule* nodep) override {
|
||||
UINFO(4, " MOD " << nodep << endl);
|
||||
m_hashed.clear();
|
||||
m_dupFinder.clear();
|
||||
// Compute hash of all CFuncs in the module
|
||||
iterateChildren(nodep);
|
||||
if (debug() >= 9) m_hashed.dumpFilePrefixed("combine");
|
||||
if (debug() >= 9) m_dupFinder.dumpFilePrefixed("combine");
|
||||
// Walk the hashes removing empty functions
|
||||
walkEmptyFuncs();
|
||||
// Walk the hashes looking for duplicate functions
|
||||
@ -196,7 +196,7 @@ private:
|
||||
virtual void visit(AstCFunc* nodep) override {
|
||||
if (nodep->dontCombine()) return;
|
||||
// Hash the entire function
|
||||
m_hashed.hashAndInsert(nodep);
|
||||
m_dupFinder.insert(nodep);
|
||||
}
|
||||
|
||||
//--------------------
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
#include "V3Global.h"
|
||||
#include "V3CoverageJoin.h"
|
||||
#include "V3Hashed.h"
|
||||
#include "V3DupFinder.h"
|
||||
#include "V3Stats.h"
|
||||
|
||||
#include <vector>
|
||||
@ -33,10 +33,7 @@
|
||||
class CoverageJoinVisitor final : public AstNVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
// V3Hashed
|
||||
// AstCoverToggle->VarRef::user4() // V3Hashed calculation
|
||||
|
||||
// AstUser4InUse In V3Hashed
|
||||
// AstUser4InUse In V3Hasher via V3DupFinder
|
||||
|
||||
// STATE
|
||||
std::vector<AstCoverToggle*> m_toggleps; // List of of all AstCoverToggle's
|
||||
@ -49,9 +46,9 @@ private:
|
||||
void detectDuplicates() {
|
||||
UINFO(9, "Finding duplicates\n");
|
||||
// Note uses user4
|
||||
V3Hashed hashed; // Duplicate code detection
|
||||
V3DupFinder dupFinder; // Duplicate code detection
|
||||
// Hash all of the original signals we toggle cover
|
||||
for (AstCoverToggle* nodep : m_toggleps) hashed.hashAndInsert(nodep->origp());
|
||||
for (AstCoverToggle* nodep : m_toggleps) dupFinder.insert(nodep->origp());
|
||||
// Find if there are any duplicates
|
||||
for (AstCoverToggle* nodep : m_toggleps) {
|
||||
// nodep->backp() is null if we already detected it's a duplicate and unlinked it.
|
||||
@ -60,10 +57,10 @@ private:
|
||||
// This prevents making chains where a->b, then c->d, then b->c, as we'll
|
||||
// find a->b, a->c, a->d directly.
|
||||
while (true) {
|
||||
const auto dupit = hashed.findDuplicate(nodep->origp());
|
||||
if (dupit == hashed.end()) break;
|
||||
const auto dupit = dupFinder.findDuplicate(nodep->origp());
|
||||
if (dupit == dupFinder.end()) break;
|
||||
//
|
||||
AstNode* duporigp = hashed.iteratorNodep(dupit);
|
||||
AstNode* duporigp = dupit->second;
|
||||
// Note hashed will point to the original variable (what's
|
||||
// duplicated), not the covertoggle, but we need to get back to the
|
||||
// covertoggle which is immediately above, so:
|
||||
@ -82,7 +79,7 @@ private:
|
||||
removep->unlinkFrBack();
|
||||
VL_DO_DANGLING(pushDeletep(removep), removep);
|
||||
// Remove node from comparison so don't hit it again
|
||||
hashed.erase(dupit);
|
||||
dupFinder.erase(dupit);
|
||||
++m_statToggleJoins;
|
||||
}
|
||||
}
|
||||
|
97
src/V3DupFinder.cpp
Normal file
97
src/V3DupFinder.cpp
Normal file
@ -0,0 +1,97 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Hashed common code into functions
|
||||
//
|
||||
// Code available from: https://verilator.org
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2021 by Wilson Snyder. This program is free software; you
|
||||
// can redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3Global.h"
|
||||
#include "V3DupFinder.h"
|
||||
#include "V3Ast.h"
|
||||
#include "V3File.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
//######################################################################
|
||||
// V3DupFinder class functions
|
||||
|
||||
bool V3DupFinder::sameNodes(AstNode* node1p, AstNode* node2p) {
|
||||
return m_hasher(node1p) == m_hasher(node2p) // Same hash
|
||||
&& node1p->sameTree(node2p); // Same tree
|
||||
}
|
||||
|
||||
V3DupFinder::iterator V3DupFinder::findDuplicate(AstNode* nodep, V3DupFinderUserSame* checkp) {
|
||||
const auto& er = equal_range(m_hasher(nodep));
|
||||
for (iterator it = er.first; it != er.second; ++it) {
|
||||
AstNode* const node2p = it->second;
|
||||
if (nodep == node2p) continue; // Same node is not a duplicate
|
||||
if (checkp && !checkp->isSame(nodep, node2p)) continue; // User says it is not a duplicate
|
||||
if (!nodep->sameTree(node2p)) continue; // Not the same trees
|
||||
// Found duplicate!
|
||||
return it;
|
||||
}
|
||||
return end();
|
||||
}
|
||||
|
||||
void V3DupFinder::dumpFile(const string& filename, bool tree) {
|
||||
const std::unique_ptr<std::ofstream> logp(V3File::new_ofstream(filename));
|
||||
if (logp->fail()) v3fatal("Can't write " << filename);
|
||||
|
||||
std::unordered_map<int, int> dist;
|
||||
|
||||
V3Hash lasthash;
|
||||
int num_in_bucket = 0;
|
||||
for (auto it = cbegin(); true; ++it) {
|
||||
if (it == cend() || lasthash != it->first) {
|
||||
if (it != cend()) lasthash = it->first;
|
||||
if (num_in_bucket) {
|
||||
if (dist.find(num_in_bucket) == dist.end()) {
|
||||
dist.emplace(num_in_bucket, 1);
|
||||
} else {
|
||||
++dist[num_in_bucket];
|
||||
}
|
||||
}
|
||||
num_in_bucket = 0;
|
||||
}
|
||||
if (it == cend()) break;
|
||||
num_in_bucket++;
|
||||
}
|
||||
*logp << "\n*** STATS:\n\n";
|
||||
*logp << " #InBucket Occurrences\n";
|
||||
for (const auto& i : dist) {
|
||||
*logp << " " << std::setw(9) << i.first << " " << std::setw(12) << i.second << '\n';
|
||||
}
|
||||
|
||||
*logp << "\n*** Dump:\n\n";
|
||||
for (const auto& it : *this) {
|
||||
if (lasthash != it.first) {
|
||||
lasthash = it.first;
|
||||
*logp << " " << it.first << '\n';
|
||||
}
|
||||
*logp << "\t" << it.second << '\n';
|
||||
// Dumping the entire tree may make nearly N^2 sized dumps,
|
||||
// because the nodes under this one may also be in the hash table!
|
||||
if (tree) it.second->dumpTree(*logp, " ");
|
||||
}
|
||||
}
|
||||
|
||||
void V3DupFinder::dumpFilePrefixed(const string& nameComment, bool tree) {
|
||||
if (v3Global.opt.dumpTree()) { //
|
||||
dumpFile(v3Global.debugFilename(nameComment) + ".hash", tree);
|
||||
}
|
||||
}
|
82
src/V3DupFinder.h
Normal file
82
src/V3DupFinder.h
Normal file
@ -0,0 +1,82 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Hash AST trees to find duplicates
|
||||
//
|
||||
// Code available from: https://verilator.org
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2005-2021 by Wilson Snyder. This program is free software; you
|
||||
// can redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Datastructure for finding duplicate AstNode trees via hashing
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#ifndef VERILATOR_V3DUPFINDER_H_
|
||||
#define VERILATOR_V3DUPFINDER_H_
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3Error.h"
|
||||
#include "V3Ast.h"
|
||||
#include "V3Hasher.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
//============================================================================
|
||||
|
||||
struct V3DupFinderUserSame {
|
||||
// Functor for V3DupFinder::findDuplicate
|
||||
virtual bool isSame(AstNode*, AstNode*) = 0;
|
||||
V3DupFinderUserSame() = default;
|
||||
virtual ~V3DupFinderUserSame() = default;
|
||||
};
|
||||
|
||||
// This really is just a multimap from 'node hash' to 'node pointer', with some minor extensions.
|
||||
class V3DupFinder final : private std::multimap<V3Hash, AstNode*> {
|
||||
using Super = std::multimap<V3Hash, AstNode*>;
|
||||
|
||||
// MEMBERS
|
||||
const V3Hasher m_hasher;
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
V3DupFinder(){};
|
||||
~V3DupFinder() = default;
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
// Expose minimal set of superclass interface
|
||||
using Super::begin;
|
||||
using Super::cbegin;
|
||||
using Super::cend;
|
||||
using Super::clear;
|
||||
using Super::const_iterator;
|
||||
using Super::empty;
|
||||
using Super::end;
|
||||
using Super::erase;
|
||||
using Super::iterator;
|
||||
|
||||
// Insert node into data structure
|
||||
iterator insert(AstNode* nodep) { return emplace(m_hasher(nodep), nodep); }
|
||||
|
||||
// Check if nodes are the same (same as node1p->sameTree(node2p),
|
||||
// but first checks the hashes are equal for speed)
|
||||
bool sameNodes(AstNode* node1p, AstNode* node2p);
|
||||
|
||||
// Return duplicate, if one was inserted, with optional user check for sameness
|
||||
iterator findDuplicate(AstNode* nodep, V3DupFinderUserSame* checkp = nullptr);
|
||||
|
||||
// Dump for debug
|
||||
void dumpFile(const string& filename, bool tree);
|
||||
void dumpFilePrefixed(const string& nameComment, bool tree = false);
|
||||
};
|
||||
|
||||
#endif // Guard
|
@ -30,7 +30,7 @@
|
||||
#include "V3Graph.h"
|
||||
#include "V3Const.h"
|
||||
#include "V3Stats.h"
|
||||
#include "V3Hashed.h"
|
||||
#include "V3DupFinder.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <list>
|
||||
@ -900,7 +900,7 @@ void GateVisitor::optimizeElimVar(AstVarScope* varscp, AstNode* substp, AstNode*
|
||||
//######################################################################
|
||||
// Auxiliary hash class for GateDedupeVarVisitor
|
||||
|
||||
class GateDedupeHash final : public V3HashedUserSame {
|
||||
class GateDedupeHash final : public V3DupFinderUserSame {
|
||||
private:
|
||||
// NODE STATE
|
||||
// Ast*::user2p -> parent AstNodeAssign* for this rhsp
|
||||
@ -911,22 +911,22 @@ private:
|
||||
// AstUser1InUse m_inuser1; (Allocated for use in GateVisitor)
|
||||
// AstUser2InUse m_inuser2; (Allocated for use in GateVisitor)
|
||||
AstUser3InUse m_inuser3;
|
||||
// AstUser4InUse m_inuser4; (Allocated for use in V3Hashed)
|
||||
// AstUser4InUse m_inuser4; (Allocated for use in V3Hasher via V3DupFinder)
|
||||
AstUser5InUse m_inuser5;
|
||||
|
||||
V3Hashed m_hashed; // Hash, contains rhs of assigns
|
||||
V3DupFinder m_dupFinder; // Duplicate finder for rhs of assigns
|
||||
std::unordered_set<AstNode*> m_nodeDeleteds; // Any node in this hash was deleted
|
||||
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
void hash(AstNode* nodep) {
|
||||
// !nullptr && the object is hashable
|
||||
if (nodep && !nodep->sameHash().isIllegal()) m_hashed.hash(nodep);
|
||||
}
|
||||
bool sameHash(AstNode* node1p, AstNode* node2p) {
|
||||
return (node1p && node2p && !node1p->sameHash().isIllegal()
|
||||
&& !node2p->sameHash().isIllegal() && m_hashed.sameNodes(node1p, node2p));
|
||||
return node1p //
|
||||
&& node2p //
|
||||
&& !node1p->sameHash().isIllegal() //
|
||||
&& !node2p->sameHash().isIllegal() //
|
||||
&& m_dupFinder.sameNodes(node1p, node2p);
|
||||
}
|
||||
|
||||
bool same(AstNode* node1p, AstNode* node2p) {
|
||||
return node1p == node2p || sameHash(node1p, node2p);
|
||||
}
|
||||
@ -958,7 +958,7 @@ public:
|
||||
|| (extra2p && m_nodeDeleteds.find(extra2p) != m_nodeDeleteds.end()));
|
||||
}
|
||||
|
||||
// Callback from V3Hashed::findDuplicate
|
||||
// Callback from V3DupFinder::findDuplicate
|
||||
virtual bool isSame(AstNode* node1p, AstNode* node2p) override {
|
||||
// Assignment may have been hashReplaced, if so consider non-match (effectively removed)
|
||||
if (isReplaced(node1p) || isReplaced(node2p)) {
|
||||
@ -977,25 +977,21 @@ public:
|
||||
rhsp->user3p(extra1p);
|
||||
rhsp->user5p(extra2p);
|
||||
|
||||
hash(extra1p);
|
||||
hash(extra2p);
|
||||
|
||||
const auto inserted = m_hashed.hashAndInsert(rhsp);
|
||||
const auto dupit = m_hashed.findDuplicate(rhsp, this);
|
||||
// Even though rhsp was just inserted, V3Hashed::findDuplicate doesn't
|
||||
// return anything in the hash that has the same pointer (V3Hashed.cpp::findDuplicate)
|
||||
const auto inserted = m_dupFinder.insert(rhsp);
|
||||
const auto dupit = m_dupFinder.findDuplicate(rhsp, this);
|
||||
// Even though rhsp was just inserted, V3DupFinder::findDuplicate doesn't
|
||||
// return anything in the hash that has the same pointer (V3DupFinder::findDuplicate)
|
||||
// So dupit is either a different, duplicate rhsp, or the end of the hash.
|
||||
if (dupit != m_hashed.end()) {
|
||||
m_hashed.erase(inserted);
|
||||
return VN_CAST(m_hashed.iteratorNodep(dupit)->user2p(), NodeAssign);
|
||||
if (dupit != m_dupFinder.end()) {
|
||||
m_dupFinder.erase(inserted);
|
||||
return VN_CAST(dupit->second->user2p(), NodeAssign);
|
||||
}
|
||||
// Retain new inserted information
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void check() {
|
||||
m_hashed.check();
|
||||
for (const auto& itr : m_hashed) {
|
||||
for (const auto& itr : m_dupFinder) {
|
||||
AstNode* nodep = itr.second;
|
||||
AstNode* activep = nodep->user3p();
|
||||
AstNode* condVarp = nodep->user5p();
|
||||
@ -1003,9 +999,9 @@ public:
|
||||
// This class won't break if activep isn't an active, or
|
||||
// ifVar isn't a var, but this is checking the caller's construction.
|
||||
UASSERT_OBJ(!activep || (!VN_DELETED(activep) && VN_IS(activep, Active)), nodep,
|
||||
"V3Hashed check failed, lost active pointer");
|
||||
"V3DupFinder check failed, lost active pointer");
|
||||
UASSERT_OBJ(!condVarp || !VN_DELETED(condVarp), nodep,
|
||||
"V3Hashed check failed, lost if pointer");
|
||||
"V3DupFinder check failed, lost if pointer");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
207
src/V3Hashed.cpp
207
src/V3Hashed.cpp
@ -1,207 +0,0 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Hashed common code into functions
|
||||
//
|
||||
// Code available from: https://verilator.org
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2021 by Wilson Snyder. This program is free software; you
|
||||
// can redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
//
|
||||
//*************************************************************************
|
||||
// V3Hashed's Transformations:
|
||||
//
|
||||
// Hash each node depth first
|
||||
// Hash includes varp name and operator type, and constants
|
||||
// Form lookup table based on hash of each statement w/ nodep and next nodep
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3Global.h"
|
||||
#include "V3Hashed.h"
|
||||
#include "V3Ast.h"
|
||||
#include "V3File.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
//######################################################################
|
||||
// Hashed state, as a visitor of each AstNode
|
||||
|
||||
class HashedVisitor final : public AstNVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
// Entire netlist:
|
||||
// AstNodeStmt::user4() -> V3Hash. Hash value of this node (hash of 0 is illegal)
|
||||
// AstUser4InUse in V3Hashed.h
|
||||
|
||||
// STATE
|
||||
V3Hash m_lowerHash; // Hash of the statement we're building
|
||||
bool m_cacheInUser4; // Use user4 to cache each V3Hash?
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
void nodeHashIterate(AstNode* nodep) {
|
||||
V3Hash thisHash;
|
||||
if (!m_cacheInUser4 || !nodep->user4()) {
|
||||
UASSERT_OBJ(
|
||||
!(VN_IS(nodep->backp(), CFunc)
|
||||
&& !(VN_IS(nodep, NodeStmt) || VN_IS(nodep, CFunc))),
|
||||
nodep,
|
||||
"Node " << nodep->prettyTypeName()
|
||||
<< " in statement position but not marked stmt (node under function)");
|
||||
VL_RESTORER(m_lowerHash);
|
||||
{
|
||||
m_lowerHash = nodep->sameHash();
|
||||
UASSERT_OBJ(!m_lowerHash.isIllegal(), nodep,
|
||||
"sameHash function undefined (returns 0) for node under CFunc.");
|
||||
// For identical nodes, the type should be the same thus
|
||||
// dtypep should be the same too
|
||||
m_lowerHash
|
||||
= V3Hash(m_lowerHash, V3Hash(nodep->type() << 6, V3Hash(nodep->dtypep())));
|
||||
// Now update m_lowerHash for our children's (and next children) contributions
|
||||
iterateChildren(nodep);
|
||||
// Store the hash value
|
||||
nodep->user4(m_lowerHash.fullValue());
|
||||
// UINFO(9, " hashnode "<<m_lowerHash<<" "<<nodep<<endl);
|
||||
thisHash = m_lowerHash;
|
||||
}
|
||||
}
|
||||
// Update what will become the above node's hash
|
||||
m_lowerHash += m_cacheInUser4 ? V3Hashed::nodeHash(nodep) : thisHash;
|
||||
}
|
||||
|
||||
//--------------------
|
||||
virtual void visit(AstVar*) override {}
|
||||
virtual void visit(AstTypedef*) override {}
|
||||
virtual void visit(AstParamTypeDType*) override {}
|
||||
virtual void visit(AstNode* nodep) override {
|
||||
// Hash not just iterate
|
||||
nodeHashIterate(nodep);
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit HashedVisitor(AstNode* nodep)
|
||||
: m_cacheInUser4{true} {
|
||||
nodeHashIterate(nodep);
|
||||
// UINFO(9," stmthash "<<hex<<V3Hashed::nodeHash(nodep)<<" "<<nodep<<endl);
|
||||
}
|
||||
explicit HashedVisitor(const AstNode* nodep)
|
||||
: m_cacheInUser4{false} {
|
||||
nodeHashIterate(const_cast<AstNode*>(nodep));
|
||||
}
|
||||
V3Hash finalHash() const { return m_lowerHash; }
|
||||
virtual ~HashedVisitor() override = default;
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Hashed class functions
|
||||
|
||||
V3Hash V3Hashed::uncachedHash(const AstNode* nodep) {
|
||||
HashedVisitor visitor(nodep);
|
||||
return visitor.finalHash();
|
||||
}
|
||||
|
||||
V3Hashed::iterator V3Hashed::hashAndInsert(AstNode* nodep) {
|
||||
hash(nodep);
|
||||
return m_hashMmap.emplace(nodeHash(nodep), nodep);
|
||||
}
|
||||
|
||||
void V3Hashed::hash(AstNode* nodep) {
|
||||
UINFO(8, " hashI " << nodep << endl);
|
||||
if (!nodep->user4p()) { HashedVisitor visitor(nodep); }
|
||||
}
|
||||
|
||||
bool V3Hashed::sameNodes(AstNode* node1p, AstNode* node2p) {
|
||||
UASSERT_OBJ(node1p->user4p(), node1p, "Called isIdentical on non-hashed nodes");
|
||||
UASSERT_OBJ(node2p->user4p(), node2p, "Called isIdentical on non-hashed nodes");
|
||||
return (node1p->user4p() == node2p->user4p() // Same hash
|
||||
&& node1p->sameTree(node2p));
|
||||
}
|
||||
|
||||
void V3Hashed::erase(iterator it) {
|
||||
AstNode* nodep = iteratorNodep(it);
|
||||
UINFO(8, " erase " << nodep << endl);
|
||||
UASSERT_OBJ(nodep->user4p(), nodep, "Called removeNode on non-hashed node");
|
||||
m_hashMmap.erase(it);
|
||||
nodep->user4p(nullptr); // So we don't allow removeNode again
|
||||
}
|
||||
|
||||
void V3Hashed::check() {
|
||||
for (const auto& itr : *this) {
|
||||
AstNode* nodep = itr.second;
|
||||
UASSERT_OBJ(nodep->user4p(), nodep, "V3Hashed check failed, non-hashed node");
|
||||
}
|
||||
}
|
||||
|
||||
void V3Hashed::dumpFilePrefixed(const string& nameComment, bool tree) {
|
||||
if (v3Global.opt.dumpTree()) dumpFile(v3Global.debugFilename(nameComment) + ".hash", tree);
|
||||
}
|
||||
|
||||
void V3Hashed::dumpFile(const string& filename, bool tree) {
|
||||
const std::unique_ptr<std::ofstream> logp(V3File::new_ofstream(filename));
|
||||
if (logp->fail()) v3fatal("Can't write " << filename);
|
||||
|
||||
std::unordered_map<int, int> dist;
|
||||
|
||||
V3Hash lasthash;
|
||||
int num_in_bucket = 0;
|
||||
for (HashMmap::iterator it = begin(); true; ++it) {
|
||||
if (it == end() || lasthash != it->first) {
|
||||
if (it != end()) lasthash = it->first;
|
||||
if (num_in_bucket) {
|
||||
if (dist.find(num_in_bucket) == dist.end()) {
|
||||
dist.emplace(num_in_bucket, 1);
|
||||
} else {
|
||||
++dist[num_in_bucket];
|
||||
}
|
||||
}
|
||||
num_in_bucket = 0;
|
||||
}
|
||||
if (it == end()) break;
|
||||
num_in_bucket++;
|
||||
}
|
||||
*logp << "\n*** STATS:\n\n";
|
||||
*logp << " #InBucket Occurrences\n";
|
||||
for (const auto& i : dist) {
|
||||
*logp << " " << std::setw(9) << i.first << " " << std::setw(12) << i.second << '\n';
|
||||
}
|
||||
|
||||
*logp << "\n*** Dump:\n\n";
|
||||
for (const auto& itr : *this) {
|
||||
if (lasthash != itr.first) {
|
||||
lasthash = itr.first;
|
||||
*logp << " " << itr.first << '\n';
|
||||
}
|
||||
*logp << "\t" << itr.second << '\n';
|
||||
// Dumping the entire tree may make nearly N^2 sized dumps,
|
||||
// because the nodes under this one may also be in the hash table!
|
||||
if (tree) itr.second->dumpTree(*logp, " ");
|
||||
}
|
||||
}
|
||||
|
||||
V3Hashed::iterator V3Hashed::findDuplicate(AstNode* nodep, V3HashedUserSame* checkp) {
|
||||
UINFO(8, " findD " << nodep << endl);
|
||||
UASSERT_OBJ(nodep->user4p(), nodep, "Called findDuplicate on non-hashed node");
|
||||
std::pair<HashMmap::iterator, HashMmap::iterator> eqrange
|
||||
= mmap().equal_range(nodeHash(nodep));
|
||||
for (HashMmap::iterator eqit = eqrange.first; eqit != eqrange.second; ++eqit) {
|
||||
AstNode* node2p = eqit->second;
|
||||
if (nodep != node2p && (!checkp || checkp->isSame(nodep, node2p))
|
||||
&& sameNodes(nodep, node2p)) {
|
||||
return eqit;
|
||||
}
|
||||
}
|
||||
return end();
|
||||
}
|
@ -1,92 +0,0 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Hash AST trees to find duplicates
|
||||
//
|
||||
// Code available from: https://verilator.org
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2005-2021 by Wilson Snyder. This program is free software; you
|
||||
// can redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#ifndef VERILATOR_V3HASHED_H_
|
||||
#define VERILATOR_V3HASHED_H_
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3Error.h"
|
||||
#include "V3Ast.h"
|
||||
|
||||
//============================================================================
|
||||
|
||||
class VHashedBase VL_NOT_FINAL {
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VHashedBase() = default;
|
||||
~VHashedBase() = default;
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
};
|
||||
|
||||
//============================================================================
|
||||
|
||||
struct V3HashedUserSame {
|
||||
// Functor for V3Hashed::findDuplicate
|
||||
virtual bool isSame(AstNode*, AstNode*) = 0;
|
||||
V3HashedUserSame() = default;
|
||||
virtual ~V3HashedUserSame() = default;
|
||||
};
|
||||
|
||||
class V3Hashed final : public VHashedBase {
|
||||
// NODE STATE
|
||||
// AstNode::user4() -> V3Hash. Hash value of this node (hash of 0 is illegal)
|
||||
AstUser4InUse m_inuser4;
|
||||
|
||||
// TYPES
|
||||
public:
|
||||
using HashMmap = std::multimap<V3Hash, AstNode*>;
|
||||
using iterator = HashMmap::iterator;
|
||||
|
||||
private:
|
||||
// MEMBERS
|
||||
HashMmap m_hashMmap; // hashvalue -> nodes with that hash
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
V3Hashed() { clear(); }
|
||||
~V3Hashed() = default;
|
||||
|
||||
// ACCESSORS
|
||||
HashMmap& mmap() { return m_hashMmap; } // Return map for iteration
|
||||
iterator begin() { return m_hashMmap.begin(); }
|
||||
iterator end() { return m_hashMmap.end(); }
|
||||
|
||||
// METHODS
|
||||
void clear() {
|
||||
m_hashMmap.clear();
|
||||
AstNode::user4ClearTree();
|
||||
}
|
||||
void check(); // Check assertions on structure
|
||||
// Hash the node, and insert into map. Return iterator to inserted
|
||||
iterator hashAndInsert(AstNode* nodep);
|
||||
static void hash(AstNode* nodep); // Only hash the node
|
||||
// After hashing, and tell if identical
|
||||
static bool sameNodes(AstNode* node1p, AstNode* node2p);
|
||||
void erase(iterator it); // Remove node from structures
|
||||
// Return duplicate in hash, if any, with optional user check for sameness
|
||||
iterator findDuplicate(AstNode* nodep, V3HashedUserSame* checkp = nullptr);
|
||||
AstNode* iteratorNodep(iterator it) { return it->second; }
|
||||
void dumpFile(const string& filename, bool tree);
|
||||
void dumpFilePrefixed(const string& nameComment, bool tree = false);
|
||||
static V3Hash nodeHash(AstNode* nodep) { return V3Hash(nodep->user4p()); }
|
||||
// Hash of the nodep tree, without caching in user4.
|
||||
static V3Hash uncachedHash(const AstNode* nodep);
|
||||
};
|
||||
|
||||
#endif // Guard
|
91
src/V3Hasher.cpp
Normal file
91
src/V3Hasher.cpp
Normal file
@ -0,0 +1,91 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Hashed common code into functions
|
||||
//
|
||||
// Code available from: https://verilator.org
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2021 by Wilson Snyder. This program is free software; you
|
||||
// can redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3Hasher.h"
|
||||
|
||||
//######################################################################
|
||||
// Visitor that computes node hashes
|
||||
|
||||
class HasherVisitor final : public AstNVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
// AstNode::user4() -> V3Hash. Hash value of this node (hash of 0 is illegal)
|
||||
// AstUser4InUse in V3Hasher.h
|
||||
|
||||
// STATE
|
||||
V3Hash m_lowerHash; // Hash of the statement we're building
|
||||
const bool m_cacheInUser4; // Use user4 to cache each V3Hash?
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
//--------------------
|
||||
virtual void visit(AstVar*) override {}
|
||||
virtual void visit(AstTypedef*) override {}
|
||||
virtual void visit(AstParamTypeDType*) override {}
|
||||
|
||||
virtual void visit(AstNode* nodep) override {
|
||||
V3Hash thisHash;
|
||||
if (!m_cacheInUser4 || !nodep->user4()) {
|
||||
VL_RESTORER(m_lowerHash);
|
||||
{
|
||||
m_lowerHash = nodep->sameHash();
|
||||
UASSERT_OBJ(!m_lowerHash.isIllegal(), nodep,
|
||||
"sameHash function undefined (returns 0) for node under CFunc.");
|
||||
// For identical nodes, the type should be the same thus
|
||||
// dtypep should be the same too
|
||||
m_lowerHash = V3Hash(m_lowerHash,
|
||||
V3Hash(V3Hash(nodep->type() << 6), V3Hash(nodep->dtypep())));
|
||||
// Now update m_lowerHash for our children's (and next children) contributions
|
||||
iterateChildrenConst(nodep);
|
||||
// Store the hash value
|
||||
if (m_cacheInUser4) { nodep->user4(m_lowerHash.fullValue()); }
|
||||
thisHash = m_lowerHash;
|
||||
}
|
||||
}
|
||||
// Update what will become the above node's hash
|
||||
m_lowerHash += m_cacheInUser4 ? V3Hash(nodep->user4()) : thisHash;
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit HasherVisitor(AstNode* nodep)
|
||||
: m_cacheInUser4{true} {
|
||||
iterate(nodep);
|
||||
}
|
||||
explicit HasherVisitor(const AstNode* nodep)
|
||||
: m_cacheInUser4{false} {
|
||||
iterate(const_cast<AstNode*>(nodep));
|
||||
}
|
||||
V3Hash finalHash() const { return m_lowerHash; }
|
||||
virtual ~HasherVisitor() override = default;
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// V3Hasher methods
|
||||
|
||||
V3Hash V3Hasher::operator()(AstNode* nodep) const {
|
||||
if (!nodep->user4()) { HasherVisitor visitor(nodep); }
|
||||
return V3Hash(nodep->user4());
|
||||
}
|
||||
|
||||
V3Hash V3Hasher::uncachedHash(const AstNode* nodep) {
|
||||
HasherVisitor visitor(nodep);
|
||||
return visitor.finalHash();
|
||||
}
|
51
src/V3Hasher.h
Normal file
51
src/V3Hasher.h
Normal file
@ -0,0 +1,51 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Hash AST trees to find duplicates
|
||||
//
|
||||
// Code available from: https://verilator.org
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2005-2021 by Wilson Snyder. This program is free software; you
|
||||
// can redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// V3Hasher handles computation of AstNode hashes
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#ifndef VERILATOR_V3HASHER_H_
|
||||
#define VERILATOR_V3HASHER_H_
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3Error.h"
|
||||
#include "V3Ast.h"
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3Hasher final {
|
||||
// NODE STATE
|
||||
// AstNode::user4() -> V3Hash. Hash value of this node (hash of 0 is illegal)
|
||||
AstUser4InUse m_inuser4;
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
V3Hasher() = default;
|
||||
~V3Hasher() = default;
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
// Compute hash of node. This method caches the hash in the node's user4().
|
||||
V3Hash operator()(AstNode* nodep) const;
|
||||
|
||||
// Compute hash of node, without caching in user4.
|
||||
static V3Hash uncachedHash(const AstNode* nodep);
|
||||
};
|
||||
|
||||
#endif // Guard
|
@ -56,7 +56,7 @@
|
||||
#include "V3Parse.h"
|
||||
#include "V3Width.h"
|
||||
#include "V3Unroll.h"
|
||||
#include "V3Hashed.h"
|
||||
#include "V3Hasher.h"
|
||||
|
||||
#include <deque>
|
||||
#include <map>
|
||||
@ -314,7 +314,7 @@ class ParamProcessor final {
|
||||
key += "[" + cvtToStr(bdtp->left()) + ":" + cvtToStr(bdtp->right()) + "]";
|
||||
}
|
||||
}
|
||||
V3Hash hash = V3Hashed::uncachedHash(nodep);
|
||||
V3Hash hash = V3Hasher::uncachedHash(nodep);
|
||||
// Force hash collisions -- for testing only
|
||||
if (VL_UNLIKELY(v3Global.opt.debugCollision())) hash = V3Hash();
|
||||
int num;
|
||||
|
@ -30,7 +30,7 @@
|
||||
#include "V3Global.h"
|
||||
#include "V3Premit.h"
|
||||
#include "V3Ast.h"
|
||||
#include "V3Hashed.h"
|
||||
#include "V3DupFinder.h"
|
||||
#include "V3Stats.h"
|
||||
|
||||
#include <algorithm>
|
||||
@ -96,7 +96,7 @@ private:
|
||||
// *::user4() -> See PremitAssignVisitor
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser2InUse m_inuser2;
|
||||
// AstUser4InUse part of V3Hashed
|
||||
// AstUser4InUse part of V3Hasher via V3DupFinder
|
||||
|
||||
// STATE
|
||||
AstNodeModule* m_modp = nullptr; // Current module
|
||||
@ -106,7 +106,7 @@ private:
|
||||
AstTraceInc* m_inTracep = nullptr; // Inside while loop, special statement additions
|
||||
bool m_assignLhs = false; // Inside assignment lhs, don't breakup extracts
|
||||
|
||||
V3Hashed m_hashed; // Hash set for static constants that can be reused
|
||||
V3DupFinder m_dupFinder; // Duplicate finder for static constants that can be reused
|
||||
|
||||
VDouble0 m_staticConstantsExtracted; // Statistic tracking
|
||||
VDouble0 m_staticConstantsReused; // Statistic tracking
|
||||
@ -184,9 +184,8 @@ private:
|
||||
&& !constp->num().isFourState();
|
||||
if (useStatic) {
|
||||
// Extract as static constant
|
||||
m_hashed.hash(constp);
|
||||
const auto& it = m_hashed.findDuplicate(constp);
|
||||
if (it == m_hashed.end()) {
|
||||
const auto& it = m_dupFinder.findDuplicate(constp);
|
||||
if (it == m_dupFinder.end()) {
|
||||
const string newvarname = string("__Vconst") + cvtToStr(m_modp->varNumGetInc());
|
||||
varp = new AstVar(nodep->fileline(), AstVarType::MODULETEMP, newvarname,
|
||||
nodep->dtypep());
|
||||
@ -194,7 +193,7 @@ private:
|
||||
varp->isStatic(true);
|
||||
varp->valuep(constp);
|
||||
m_modp->addStmtp(varp);
|
||||
m_hashed.hashAndInsert(constp);
|
||||
m_dupFinder.insert(constp);
|
||||
nodep->user2p(varp);
|
||||
++m_staticConstantsExtracted;
|
||||
} else {
|
||||
@ -230,12 +229,12 @@ private:
|
||||
virtual void visit(AstNodeModule* nodep) override {
|
||||
UINFO(4, " MOD " << nodep << endl);
|
||||
UASSERT_OBJ(m_modp == nullptr, nodep, "Nested modules ?");
|
||||
UASSERT_OBJ(m_hashed.mmap().empty(), nodep, "Statements outside module ?");
|
||||
UASSERT_OBJ(m_dupFinder.empty(), nodep, "Statements outside module ?");
|
||||
m_modp = nodep;
|
||||
m_cfuncp = nullptr;
|
||||
iterateChildren(nodep);
|
||||
m_modp = nullptr;
|
||||
m_hashed.clear();
|
||||
m_dupFinder.clear();
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) override {
|
||||
VL_RESTORER(m_cfuncp);
|
||||
|
@ -20,7 +20,7 @@
|
||||
#include "V3Global.h"
|
||||
#include "V3String.h"
|
||||
#include "V3ProtectLib.h"
|
||||
#include "V3Hashed.h"
|
||||
#include "V3Hasher.h"
|
||||
#include "V3Task.h"
|
||||
|
||||
#include <list>
|
||||
@ -87,7 +87,7 @@ private:
|
||||
|
||||
iterateChildren(nodep);
|
||||
|
||||
V3Hash hash = V3Hashed::uncachedHash(m_cfilep);
|
||||
V3Hash hash = V3Hasher::uncachedHash(m_cfilep);
|
||||
m_hashValuep->addText(fl, cvtToStr(hash.fullValue()) + ";\n");
|
||||
m_cHashValuep->addText(fl, cvtToStr(hash.fullValue()) + "U;\n");
|
||||
m_foundTop = true;
|
||||
|
@ -23,7 +23,7 @@
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3Ast.h"
|
||||
#include "V3Hashed.h"
|
||||
#include "V3Hasher.h"
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
@ -37,7 +37,7 @@ private:
|
||||
// TYPES
|
||||
struct HashSenTree {
|
||||
size_t operator()(const AstSenTree* kp) const {
|
||||
return V3Hashed::uncachedHash(kp).fullValue();
|
||||
return V3Hasher::uncachedHash(kp).fullValue();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -342,7 +342,7 @@ private:
|
||||
|
||||
AstVarScope* findDuplicateTable(AstVarScope* vsc1p) {
|
||||
// See if another table we've created is identical, if so use it for both.
|
||||
// (A more 'modern' way would be to instead use V3Hashed::findDuplicate)
|
||||
// (A more 'modern' way would be to instead use V3DupFinder::findDuplicate)
|
||||
AstVar* var1p = vsc1p->varp();
|
||||
for (AstVarScope* vsc2p : m_modTableVscs) {
|
||||
AstVar* var2p = vsc2p->varp();
|
||||
|
@ -42,7 +42,7 @@
|
||||
#include "V3Trace.h"
|
||||
#include "V3EmitCBase.h"
|
||||
#include "V3Graph.h"
|
||||
#include "V3Hashed.h"
|
||||
#include "V3DupFinder.h"
|
||||
#include "V3Stats.h"
|
||||
|
||||
#include <map>
|
||||
@ -154,8 +154,8 @@ public:
|
||||
class TraceVisitor final : public EmitCBaseVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
// V3Hashed
|
||||
// Ast*::user4() // V3Hashed calculation
|
||||
// V3Hasher in V3DupFinder
|
||||
// Ast*::user4() // V3Hasher calculation
|
||||
// Cleared entire netlist
|
||||
// AstCFunc::user1() // V3GraphVertex* for this node
|
||||
// AstTraceDecl::user1() // V3GraphVertex* for this node
|
||||
@ -165,7 +165,7 @@ private:
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser2InUse m_inuser2;
|
||||
AstUser3InUse m_inuser3;
|
||||
// AstUser4InUse In V3Hashed
|
||||
// AstUser4InUse In V3Hasher via V3DupFinder
|
||||
|
||||
// STATE
|
||||
AstNodeModule* m_topModp = nullptr; // Module to add variables to
|
||||
@ -194,7 +194,7 @@ private:
|
||||
void detectDuplicates() {
|
||||
UINFO(9, "Finding duplicates\n");
|
||||
// Note uses user4
|
||||
V3Hashed hashed; // Duplicate code detection
|
||||
V3DupFinder dupFinder; // Duplicate code detection
|
||||
// Hash all of the values the traceIncs need
|
||||
for (const V3GraphVertex* itp = m_graph.verticesBeginp(); itp;
|
||||
itp = itp->verticesNextp()) {
|
||||
@ -205,13 +205,9 @@ private:
|
||||
UASSERT_OBJ(nodep->valuep()->backp() == nodep, nodep,
|
||||
"Trace duplicate back needs consistency,"
|
||||
" so we can map duplicates back to TRACEINCs");
|
||||
hashed.hash(nodep->valuep());
|
||||
UINFO(8, " Hashed " << std::hex << hashed.nodeHash(nodep->valuep()) << " "
|
||||
<< nodep << endl);
|
||||
|
||||
// Just keep one node in the map and point all duplicates to this node
|
||||
if (hashed.findDuplicate(nodep->valuep()) == hashed.end()) {
|
||||
hashed.hashAndInsert(nodep->valuep());
|
||||
if (dupFinder.findDuplicate(nodep->valuep()) == dupFinder.end()) {
|
||||
dupFinder.insert(nodep->valuep());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -221,10 +217,10 @@ private:
|
||||
if (TraceTraceVertex* const vvertexp = dynamic_cast<TraceTraceVertex*>(itp)) {
|
||||
AstTraceDecl* const nodep = vvertexp->nodep();
|
||||
if (nodep->valuep() && !vvertexp->duplicatep()) {
|
||||
const auto dupit = hashed.findDuplicate(nodep->valuep());
|
||||
if (dupit != hashed.end()) {
|
||||
const auto dupit = dupFinder.findDuplicate(nodep->valuep());
|
||||
if (dupit != dupFinder.end()) {
|
||||
const AstTraceDecl* const dupDeclp
|
||||
= VN_CAST_CONST(hashed.iteratorNodep(dupit)->backp(), TraceDecl);
|
||||
= VN_CAST_CONST(dupit->second->backp(), TraceDecl);
|
||||
UASSERT_OBJ(dupDeclp, nodep, "Trace duplicate of wrong type");
|
||||
TraceTraceVertex* const dupvertexp
|
||||
= dynamic_cast<TraceTraceVertex*>(dupDeclp->user1u().toGraphVertex());
|
||||
@ -237,7 +233,6 @@ private:
|
||||
}
|
||||
}
|
||||
}
|
||||
hashed.clear();
|
||||
}
|
||||
|
||||
void graphSimplify(bool initial) {
|
||||
|
Loading…
Reference in New Issue
Block a user