Fix linear searches. bug1316.

This commit is contained in:
John Coiner 2018-06-11 22:05:45 -04:00
parent c124fe6d0c
commit 3e739db7fa
7 changed files with 99 additions and 43 deletions

View File

@ -24,6 +24,7 @@ The contributors that suggested a given feature are shown in []. Thanks!
**** Fix parsing error on bad missing #, bug1308. [Dan Kirkham]
**** Fix Verilation performance issues, bug1316. [John Coiner]
* Verilator 3.922 2018-03-17

View File

@ -44,6 +44,8 @@
#include "V3Ast.h"
#include "V3EmitCBase.h"
#include "V3Const.h"
#include "V3SenTree.h" // for SenTreeSet
#include VL_INCLUDE_UNORDERED_MAP
//***** See below for main transformation engine
@ -62,7 +64,11 @@ private:
AstScope* m_scopep; // Current scope to add statement to
AstActive* m_iActivep; // For current scope, the IActive we're building
AstActive* m_cActivep; // For current scope, the SActive(combo) we're building
std::vector<AstActive*> m_activeVec; // List of sensitive actives, for folding
SenTreeSet m_activeSens; // Sen lists for each active we've made
typedef vl_unordered_map<AstSenTree*, AstActive*> ActiveMap;
ActiveMap m_activeMap; // Map sentree to active, for folding.
// METHODS
void addActive(AstActive* nodep) {
if (!m_scopep) nodep->v3fatalSrc("NULL scope");
@ -73,7 +79,8 @@ private:
m_scopep = nodep;
m_iActivep = NULL;
m_cActivep = NULL;
m_activeVec.clear();
m_activeSens.clear();
m_activeMap.clear();
iterateChildren(nodep);
// Don't clear scopep, the namer persists beyond this visit
}
@ -112,22 +119,15 @@ public:
}
AstActive* getActive(FileLine* fl, AstSenTree* sensesp) {
// Return a sentree in this scope that matches given sense list.
// Not the fastest, but scopes tend to have few clocks
AstActive* activep = NULL;
//sitemsp->dumpTree(cout," Lookingfor: ");
for (std::vector<AstActive*>::iterator it = m_activeVec.begin(); it!=m_activeVec.end(); ++it) {
activep = *it;
if (activep) { // Not deleted
// Compare the list
AstSenTree* asenp = activep->sensesp();
if (asenp->sameTree(sensesp)) {
UINFO(8," Found ACTIVE "<<activep<<endl);
goto found;
}
}
activep = NULL;
}
found:
AstSenTree* activeSenp = m_activeSens.find(sensesp);
if (activeSenp) {
ActiveMap::iterator it = m_activeMap.find(activeSenp);
UASSERT(it != m_activeMap.end(), "Corrupt active map");
activep = it->second;
}
// Not found, form a new one
if (!activep) {
AstSenTree* newsenp = sensesp->cloneTree(false);
@ -136,7 +136,8 @@ public:
UINFO(8," New ACTIVE "<<activep<<endl);
// Form the sensitivity list
addActive(activep);
m_activeVec.push_back(activep);
m_activeMap[newsenp] = activep;
m_activeSens.add(newsenp);
// Note actives may have also been added above in the Active visitor
}
return activep;

View File

@ -2120,6 +2120,7 @@ public:
ASTNODE_NODE_FUNCS(SenTree)
virtual void dump(std::ostream& str);
virtual bool maybePointedTo() const { return true; }
virtual V3Hash sameHash() const { return V3Hash(); }
bool isMulti() const { return m_multi; }
AstNodeSenItem* sensesp() const { return VN_CAST(op1p(), NodeSenItem); } // op1 = Sensitivity list
void addSensesp(AstNodeSenItem* nodep) { addOp1p(nodep); }

View File

@ -146,7 +146,8 @@ private:
AstActive* createActivePost(AstVarRef* varrefp) {
AstActive* newactp = new AstActive (varrefp->fileline(), "sequentdly",
m_activep->sensesp());
m_activep->addNext(newactp);
// Was addNext(), but addNextHere() avoids a linear search.
m_activep->addNextHere(newactp);
return newactp;
}
void checkActivePost(AstVarRef* varrefp, AstActive* oldactivep) {

View File

@ -52,17 +52,19 @@ private:
// 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) {
if (!nodep->user4()) {
V3Hash thisHash;
if (!m_cacheInUser4 || !nodep->user4()) {
if (VN_IS(nodep->backp(), CFunc)
&& !(VN_IS(nodep, NodeStmt) || VN_IS(nodep, CFunc))) {
nodep->v3fatalSrc("Node "<<nodep->prettyTypeName()<<" in statement position but not marked stmt (node under function)");
}
V3Hash oldHash = m_lowerHash;
V3Hash oldHash = m_lowerHash;
{
m_lowerHash = nodep->sameHash();
if (m_lowerHash.isIllegal()) {
@ -76,10 +78,12 @@ private:
nodep->user4(m_lowerHash.fullValue());
//UINFO(9, " hashnode "<<m_lowerHash<<" "<<nodep<<endl);
}
thisHash = m_lowerHash;
m_lowerHash = oldHash;
}
// Update what will become the above node's hash
m_lowerHash += V3Hashed::nodeHash(nodep);
m_lowerHash += m_cacheInUser4
? V3Hashed::nodeHash(nodep) : thisHash;
}
//--------------------
@ -94,15 +98,26 @@ private:
public:
// CONSTUCTORS
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() {}
};
//######################################################################
// 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.insert(make_pair(nodeHash(nodep), nodep));

View File

@ -83,6 +83,8 @@ public:
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

View File

@ -41,19 +41,69 @@
#include <map>
#include <algorithm>
#include <vector>
#include VL_INCLUDE_UNORDERED_SET
#include "V3Global.h"
#include "V3Ast.h"
#include "V3Hashed.h"
//######################################################################
// Collect SenTrees under the entire scope
// And provide functions to find/add a new one
class SenTreeSet {
// Hash table of sensitive blocks.
private:
// TYPES
class HashSenTree {
public:
HashSenTree() {}
size_t operator() (const AstSenTree* kp) const {
return V3Hashed::uncachedHash(kp).fullValue();
}
private:
VL_UNCOPYABLE(HashSenTree);
};
class EqSenTree {
public:
EqSenTree() {}
bool operator() (const AstSenTree* ap, const AstSenTree* bp) const {
return ap->sameTree(bp);
}
private:
VL_UNCOPYABLE(EqSenTree);
};
// MEMBERS
typedef vl_unordered_set<AstSenTree*, HashSenTree, EqSenTree> Set;
Set m_trees; // Set of sensitive blocks, for folding.
public:
// CONSTRUCTORS
SenTreeSet() {}
// METHODS
void add(AstSenTree* nodep) { m_trees.insert(nodep); }
AstSenTree* find(AstSenTree* likep) {
AstSenTree* resultp = NULL;
Set::iterator it = m_trees.find(likep);
if (it != m_trees.end()) {
resultp = *it;
}
return resultp;
}
void clear() { m_trees.clear(); }
private:
VL_UNCOPYABLE(SenTreeSet);
};
class SenTreeFinder : public AstNVisitor {
private:
// STATE
AstTopScope* m_topscopep; // Top scope to add statement to
std::vector<AstSenTree*> m_treesp; // List of sensitive blocks, for folding
AstTopScope* m_topscopep; // Top scope to add statement to
SenTreeSet m_trees; // Set of sensitive blocks, for folding
// VISITORS
VL_DEBUG_FUNC; // Declare debug()
@ -77,9 +127,7 @@ private:
// Don't grab SenTrees under Actives, only those that are global (under Scope directly)
iterateChildren(nodep);
}
virtual void visit(AstSenTree* nodep) {
m_treesp.push_back(nodep);
}
virtual void visit(AstSenTree* nodep) { m_trees.add(nodep); }
// Empty visitors, speed things up
virtual void visit(AstNodeStmt* nodep) { }
virtual void visit(AstNode* nodep) {
@ -89,31 +137,18 @@ private:
public:
void clear() {
m_topscopep = NULL;
m_treesp.clear();
m_trees.clear();
}
AstSenTree* getSenTree(FileLine* fl, AstSenTree* sensesp) {
// Return a global sentree that matches given sense list.
// Not the fastest, but there tend to be few clocks
AstSenTree* treep = NULL;
//sensesp->dumpTree(cout," Lookingfor: ");
for (std::vector<AstSenTree*>::iterator it = m_treesp.begin(); it!=m_treesp.end(); ++it) {
treep = *it;
if (treep) { // Not deleted
if (treep->sameTree(sensesp)) {
UINFO(8," Found SBLOCK "<<treep<<endl);
goto found;
}
}
treep = NULL;
}
found:
AstSenTree* treep = m_trees.find(sensesp);
// Not found, form a new one
if (!treep) {
UASSERT(m_topscopep,"Never called main()");
treep = sensesp->cloneTree(false);
m_topscopep->addStmtsp(treep);
UINFO(8," New SENTREE "<<treep<<endl);
m_treesp.push_back(treep);
m_trees.add(treep);
// Note blocks may have also been added above in the Active visitor
}
return treep;