Fix linear searches. bug1316.
This commit is contained in:
parent
c124fe6d0c
commit
3e739db7fa
1
Changes
1
Changes
|
|
@ -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 parsing error on bad missing #, bug1308. [Dan Kirkham]
|
||||||
|
|
||||||
|
**** Fix Verilation performance issues, bug1316. [John Coiner]
|
||||||
|
|
||||||
* Verilator 3.922 2018-03-17
|
* Verilator 3.922 2018-03-17
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,8 @@
|
||||||
#include "V3Ast.h"
|
#include "V3Ast.h"
|
||||||
#include "V3EmitCBase.h"
|
#include "V3EmitCBase.h"
|
||||||
#include "V3Const.h"
|
#include "V3Const.h"
|
||||||
|
#include "V3SenTree.h" // for SenTreeSet
|
||||||
|
#include VL_INCLUDE_UNORDERED_MAP
|
||||||
|
|
||||||
//***** See below for main transformation engine
|
//***** See below for main transformation engine
|
||||||
|
|
||||||
|
|
@ -62,7 +64,11 @@ private:
|
||||||
AstScope* m_scopep; // Current scope to add statement to
|
AstScope* m_scopep; // Current scope to add statement to
|
||||||
AstActive* m_iActivep; // For current scope, the IActive we're building
|
AstActive* m_iActivep; // For current scope, the IActive we're building
|
||||||
AstActive* m_cActivep; // For current scope, the SActive(combo) 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
|
// METHODS
|
||||||
void addActive(AstActive* nodep) {
|
void addActive(AstActive* nodep) {
|
||||||
if (!m_scopep) nodep->v3fatalSrc("NULL scope");
|
if (!m_scopep) nodep->v3fatalSrc("NULL scope");
|
||||||
|
|
@ -73,7 +79,8 @@ private:
|
||||||
m_scopep = nodep;
|
m_scopep = nodep;
|
||||||
m_iActivep = NULL;
|
m_iActivep = NULL;
|
||||||
m_cActivep = NULL;
|
m_cActivep = NULL;
|
||||||
m_activeVec.clear();
|
m_activeSens.clear();
|
||||||
|
m_activeMap.clear();
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
// Don't clear scopep, the namer persists beyond this visit
|
// Don't clear scopep, the namer persists beyond this visit
|
||||||
}
|
}
|
||||||
|
|
@ -112,22 +119,15 @@ public:
|
||||||
}
|
}
|
||||||
AstActive* getActive(FileLine* fl, AstSenTree* sensesp) {
|
AstActive* getActive(FileLine* fl, AstSenTree* sensesp) {
|
||||||
// Return a sentree in this scope that matches given sense list.
|
// Return a sentree in this scope that matches given sense list.
|
||||||
// Not the fastest, but scopes tend to have few clocks
|
|
||||||
AstActive* activep = NULL;
|
AstActive* activep = NULL;
|
||||||
//sitemsp->dumpTree(cout," Lookingfor: ");
|
AstSenTree* activeSenp = m_activeSens.find(sensesp);
|
||||||
for (std::vector<AstActive*>::iterator it = m_activeVec.begin(); it!=m_activeVec.end(); ++it) {
|
if (activeSenp) {
|
||||||
activep = *it;
|
ActiveMap::iterator it = m_activeMap.find(activeSenp);
|
||||||
if (activep) { // Not deleted
|
UASSERT(it != m_activeMap.end(), "Corrupt active map");
|
||||||
// Compare the list
|
activep = it->second;
|
||||||
AstSenTree* asenp = activep->sensesp();
|
}
|
||||||
if (asenp->sameTree(sensesp)) {
|
|
||||||
UINFO(8," Found ACTIVE "<<activep<<endl);
|
|
||||||
goto found;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
activep = NULL;
|
|
||||||
}
|
|
||||||
found:
|
|
||||||
// Not found, form a new one
|
// Not found, form a new one
|
||||||
if (!activep) {
|
if (!activep) {
|
||||||
AstSenTree* newsenp = sensesp->cloneTree(false);
|
AstSenTree* newsenp = sensesp->cloneTree(false);
|
||||||
|
|
@ -136,7 +136,8 @@ public:
|
||||||
UINFO(8," New ACTIVE "<<activep<<endl);
|
UINFO(8," New ACTIVE "<<activep<<endl);
|
||||||
// Form the sensitivity list
|
// Form the sensitivity list
|
||||||
addActive(activep);
|
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
|
// Note actives may have also been added above in the Active visitor
|
||||||
}
|
}
|
||||||
return activep;
|
return activep;
|
||||||
|
|
|
||||||
|
|
@ -2120,6 +2120,7 @@ public:
|
||||||
ASTNODE_NODE_FUNCS(SenTree)
|
ASTNODE_NODE_FUNCS(SenTree)
|
||||||
virtual void dump(std::ostream& str);
|
virtual void dump(std::ostream& str);
|
||||||
virtual bool maybePointedTo() const { return true; }
|
virtual bool maybePointedTo() const { return true; }
|
||||||
|
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||||
bool isMulti() const { return m_multi; }
|
bool isMulti() const { return m_multi; }
|
||||||
AstNodeSenItem* sensesp() const { return VN_CAST(op1p(), NodeSenItem); } // op1 = Sensitivity list
|
AstNodeSenItem* sensesp() const { return VN_CAST(op1p(), NodeSenItem); } // op1 = Sensitivity list
|
||||||
void addSensesp(AstNodeSenItem* nodep) { addOp1p(nodep); }
|
void addSensesp(AstNodeSenItem* nodep) { addOp1p(nodep); }
|
||||||
|
|
|
||||||
|
|
@ -146,7 +146,8 @@ private:
|
||||||
AstActive* createActivePost(AstVarRef* varrefp) {
|
AstActive* createActivePost(AstVarRef* varrefp) {
|
||||||
AstActive* newactp = new AstActive (varrefp->fileline(), "sequentdly",
|
AstActive* newactp = new AstActive (varrefp->fileline(), "sequentdly",
|
||||||
m_activep->sensesp());
|
m_activep->sensesp());
|
||||||
m_activep->addNext(newactp);
|
// Was addNext(), but addNextHere() avoids a linear search.
|
||||||
|
m_activep->addNextHere(newactp);
|
||||||
return newactp;
|
return newactp;
|
||||||
}
|
}
|
||||||
void checkActivePost(AstVarRef* varrefp, AstActive* oldactivep) {
|
void checkActivePost(AstVarRef* varrefp, AstActive* oldactivep) {
|
||||||
|
|
|
||||||
|
|
@ -52,17 +52,19 @@ private:
|
||||||
|
|
||||||
// STATE
|
// STATE
|
||||||
V3Hash m_lowerHash; // Hash of the statement we're building
|
V3Hash m_lowerHash; // Hash of the statement we're building
|
||||||
|
bool m_cacheInUser4; // Use user4 to cache each V3Hash?
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
VL_DEBUG_FUNC; // Declare debug()
|
VL_DEBUG_FUNC; // Declare debug()
|
||||||
|
|
||||||
void nodeHashIterate(AstNode* nodep) {
|
void nodeHashIterate(AstNode* nodep) {
|
||||||
if (!nodep->user4()) {
|
V3Hash thisHash;
|
||||||
|
if (!m_cacheInUser4 || !nodep->user4()) {
|
||||||
if (VN_IS(nodep->backp(), CFunc)
|
if (VN_IS(nodep->backp(), CFunc)
|
||||||
&& !(VN_IS(nodep, NodeStmt) || VN_IS(nodep, CFunc))) {
|
&& !(VN_IS(nodep, NodeStmt) || VN_IS(nodep, CFunc))) {
|
||||||
nodep->v3fatalSrc("Node "<<nodep->prettyTypeName()<<" in statement position but not marked stmt (node under function)");
|
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();
|
m_lowerHash = nodep->sameHash();
|
||||||
if (m_lowerHash.isIllegal()) {
|
if (m_lowerHash.isIllegal()) {
|
||||||
|
|
@ -76,10 +78,12 @@ private:
|
||||||
nodep->user4(m_lowerHash.fullValue());
|
nodep->user4(m_lowerHash.fullValue());
|
||||||
//UINFO(9, " hashnode "<<m_lowerHash<<" "<<nodep<<endl);
|
//UINFO(9, " hashnode "<<m_lowerHash<<" "<<nodep<<endl);
|
||||||
}
|
}
|
||||||
|
thisHash = m_lowerHash;
|
||||||
m_lowerHash = oldHash;
|
m_lowerHash = oldHash;
|
||||||
}
|
}
|
||||||
// Update what will become the above node's hash
|
// 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:
|
public:
|
||||||
// CONSTUCTORS
|
// CONSTUCTORS
|
||||||
explicit HashedVisitor(AstNode* nodep) {
|
explicit HashedVisitor(AstNode* nodep) {
|
||||||
|
m_cacheInUser4 = true;
|
||||||
nodeHashIterate(nodep);
|
nodeHashIterate(nodep);
|
||||||
//UINFO(9," stmthash "<<hex<<V3Hashed::nodeHash(nodep)<<" "<<nodep<<endl);
|
//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() {}
|
virtual ~HashedVisitor() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
// Hashed class functions
|
// Hashed class functions
|
||||||
|
|
||||||
|
V3Hash V3Hashed::uncachedHash(const AstNode* nodep) {
|
||||||
|
HashedVisitor visitor(nodep);
|
||||||
|
return visitor.finalHash();
|
||||||
|
}
|
||||||
|
|
||||||
V3Hashed::iterator V3Hashed::hashAndInsert(AstNode* nodep) {
|
V3Hashed::iterator V3Hashed::hashAndInsert(AstNode* nodep) {
|
||||||
hash(nodep);
|
hash(nodep);
|
||||||
return m_hashMmap.insert(make_pair(nodeHash(nodep), nodep));
|
return m_hashMmap.insert(make_pair(nodeHash(nodep), nodep));
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,8 @@ public:
|
||||||
void dumpFile(const string& filename, bool tree);
|
void dumpFile(const string& filename, bool tree);
|
||||||
void dumpFilePrefixed(const string& nameComment, bool tree=false);
|
void dumpFilePrefixed(const string& nameComment, bool tree=false);
|
||||||
static V3Hash nodeHash(AstNode* nodep) { return V3Hash(nodep->user4p()); }
|
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
|
#endif // Guard
|
||||||
|
|
|
||||||
|
|
@ -41,19 +41,69 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include VL_INCLUDE_UNORDERED_SET
|
||||||
|
|
||||||
#include "V3Global.h"
|
#include "V3Global.h"
|
||||||
#include "V3Ast.h"
|
#include "V3Ast.h"
|
||||||
|
#include "V3Hashed.h"
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
// Collect SenTrees under the entire scope
|
// Collect SenTrees under the entire scope
|
||||||
// And provide functions to find/add a new one
|
// 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 {
|
class SenTreeFinder : public AstNVisitor {
|
||||||
private:
|
private:
|
||||||
// STATE
|
// STATE
|
||||||
AstTopScope* m_topscopep; // Top scope to add statement to
|
AstTopScope* m_topscopep; // Top scope to add statement to
|
||||||
std::vector<AstSenTree*> m_treesp; // List of sensitive blocks, for folding
|
SenTreeSet m_trees; // Set of sensitive blocks, for folding
|
||||||
|
|
||||||
// VISITORS
|
// VISITORS
|
||||||
VL_DEBUG_FUNC; // Declare debug()
|
VL_DEBUG_FUNC; // Declare debug()
|
||||||
|
|
@ -77,9 +127,7 @@ private:
|
||||||
// Don't grab SenTrees under Actives, only those that are global (under Scope directly)
|
// Don't grab SenTrees under Actives, only those that are global (under Scope directly)
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
}
|
}
|
||||||
virtual void visit(AstSenTree* nodep) {
|
virtual void visit(AstSenTree* nodep) { m_trees.add(nodep); }
|
||||||
m_treesp.push_back(nodep);
|
|
||||||
}
|
|
||||||
// Empty visitors, speed things up
|
// Empty visitors, speed things up
|
||||||
virtual void visit(AstNodeStmt* nodep) { }
|
virtual void visit(AstNodeStmt* nodep) { }
|
||||||
virtual void visit(AstNode* nodep) {
|
virtual void visit(AstNode* nodep) {
|
||||||
|
|
@ -89,31 +137,18 @@ private:
|
||||||
public:
|
public:
|
||||||
void clear() {
|
void clear() {
|
||||||
m_topscopep = NULL;
|
m_topscopep = NULL;
|
||||||
m_treesp.clear();
|
m_trees.clear();
|
||||||
}
|
}
|
||||||
AstSenTree* getSenTree(FileLine* fl, AstSenTree* sensesp) {
|
AstSenTree* getSenTree(FileLine* fl, AstSenTree* sensesp) {
|
||||||
// Return a global sentree that matches given sense list.
|
// Return a global sentree that matches given sense list.
|
||||||
// Not the fastest, but there tend to be few clocks
|
AstSenTree* treep = m_trees.find(sensesp);
|
||||||
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:
|
|
||||||
// Not found, form a new one
|
// Not found, form a new one
|
||||||
if (!treep) {
|
if (!treep) {
|
||||||
UASSERT(m_topscopep,"Never called main()");
|
UASSERT(m_topscopep,"Never called main()");
|
||||||
treep = sensesp->cloneTree(false);
|
treep = sensesp->cloneTree(false);
|
||||||
m_topscopep->addStmtsp(treep);
|
m_topscopep->addStmtsp(treep);
|
||||||
UINFO(8," New SENTREE "<<treep<<endl);
|
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
|
// Note blocks may have also been added above in the Active visitor
|
||||||
}
|
}
|
||||||
return treep;
|
return treep;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue