Internals: Rework AstInitArray to have O(1) access. No functional change intended.

This commit is contained in:
Wilson Snyder 2019-11-09 15:34:41 -05:00
parent 704f40b1a2
commit 4767083a72
7 changed files with 102 additions and 58 deletions

View File

@ -902,6 +902,15 @@ void AstIfaceRefDType::dumpSmall(std::ostream& str) const {
this->AstNodeDType::dumpSmall(str);
str<<"iface";
}
void AstInitArray::dump(std::ostream& str) const {
this->AstNode::dump(str);
int n = 0;
const AstInitArray::KeyItemMap& mapr = map();
for (AstInitArray::KeyItemMap::const_iterator it = mapr.begin(); it != mapr.end(); ++it) {
if (n++ > 5) { str<<" ..."; break; }
str<<" ["<<it->first<<"]="<<(void*)it->second;
}
}
void AstJumpGo::dump(std::ostream& str) const {
this->AstNode::dump(str);
str<<" -> ";

View File

@ -805,7 +805,7 @@ public:
ASTNODE_NODE_FUNCS(EnumItemRef)
virtual void dump(std::ostream& str) const;
virtual string name() const { return itemp()->name(); }
virtual const char* broken() const { BROKEN_RTN(!itemp()); return NULL; }
virtual const char* broken() const { BROKEN_RTN(!VN_IS(itemp(), EnumItem)); return NULL; }
virtual int instrCount() const { return 0; }
virtual void cloneRelink() { if (m_itemp->clonep()) m_itemp = VN_CAST(m_itemp->clonep(), EnumItem); }
virtual bool same(const AstNode* samep) const {
@ -3476,14 +3476,33 @@ public:
virtual bool cleanOut() const { return false; } // NA
};
class AstInitItem : public AstNode {
// Container for a item in an init array
// This container is present so that the value underneath may get replaced with a new nodep
// and the upper AstInitArray's map will remain correct (pointing to this InitItem)
public:
// Parents: INITARRAY
AstInitItem(FileLine* fl, AstNode* valuep)
: AstNode(fl) { addOp1p(valuep); }
ASTNODE_NODE_FUNCS(InitItem)
virtual bool maybePointedTo() const { return true; }
virtual bool hasDType() const { return false; } // See valuep()'s dtype instead
virtual V3Hash sameHash() const { return V3Hash(); }
AstNode* valuep() const { return op1p(); } // op1 = Value
void valuep(AstNode* nodep) { addOp1p(nodep); }
};
class AstInitArray : public AstNode {
// Set a var to a large list of values
// The values must be in sorted order, and not exceed the size of the var's array.
// The first value on the initsp() list is for the lo() index of the array.
// Set a var to a map of values
// The list of initsp() is not relevant
// If default is specified, the vector may be sparse, and not provide each value.
// Key values are C++ array style, with lo() at index 0
// Parents: ASTVAR::init()
// Children: CONSTs...
std::deque<uint32_t> m_indices; // Which array index each entry in the list is for (if defaultp)
// Children: AstInitItem
public:
typedef std::map<uint32_t, AstInitItem*> KeyItemMap;
private:
KeyItemMap m_map; // Node value for each array index
public:
AstInitArray(FileLine* fl, AstNodeArrayDType* newDTypep, AstNode* defaultp)
: AstNode(fl) {
@ -3491,27 +3510,55 @@ public:
addNOp1p(defaultp);
}
ASTNODE_NODE_FUNCS(InitArray)
AstNode* defaultp() const { return op1p(); } // op1 = Default if sparse
void defaultp(AstNode* newp) { setOp1p(newp); }
AstNode* initsp() const { return op2p(); } // op2 = Initial value expressions
void addValuep(AstNode* newp) { addIndexValuep(m_indices.size(), newp); }
void addIndexValuep(uint32_t index, AstNode* newp) {
// Must insert in sorted order
if (!m_indices.empty()) UASSERT(index > m_indices.back(), "InitArray adding index <= previous index");
m_indices.push_back(index);
addOp2p(newp); }
void addFrontValuep(AstNode* newp) { // Add to front of list, e.g. index 0.
// e.g. 0:100, 1:101 when addFront(200), get 0:200, 1:100, 2:101
initsp()->addHereThisAsNext(newp);
m_indices.push_back(m_indices.size());
virtual void dump(std::ostream& str) const;
virtual const char* broken() const {
for (KeyItemMap::const_iterator it = m_map.begin(); it != m_map.end(); ++it) {
BROKEN_RTN(!VN_IS(it->second, InitItem));
BROKEN_RTN(!it->second->brokeExists());
}
return NULL;
}
virtual void cloneRelink() {
for (KeyItemMap::iterator it = m_map.begin(); it != m_map.end(); ++it) {
if (it->second->clonep()) it->second = it->second->clonep();
}
}
int posIndex(int listPos) {
UASSERT(listPos < (int)m_indices.size(), "InitArray past end of indices list");
return m_indices[listPos]; }
virtual bool hasDType() const { return true; }
virtual V3Hash sameHash() const { return V3Hash(); }
virtual bool same(const AstNode* samep) const {
return m_indices == static_cast<const AstInitArray*>(samep)->m_indices; }
// Only works if exact same children, instead should override comparison
// of children list, and instead use map-vs-map key/value compare
return m_map == static_cast<const AstInitArray*>(samep)->m_map;
}
AstNode* defaultp() const { return op1p(); } // op1 = Default if sparse
void defaultp(AstNode* newp) { setOp1p(newp); }
AstNode* initsp() const { return op2p(); } // op2 = Initial value expressions
void addValuep(AstNode* newp) { addIndexValuep(m_map.size(), newp); }
const KeyItemMap& map() const { return m_map; }
AstNode* addIndexValuep(uint32_t index, AstNode* newp) {
// Returns old value, caller must garbage collect
AstNode* oldp = NULL;
KeyItemMap::iterator it = m_map.find(index);
if (it != m_map.end()) {
oldp = it->second->valuep();
it->second->valuep(newp);
} else {
AstInitItem* itemp = new AstInitItem(fileline(), newp);
m_map.insert(it, make_pair(index, itemp));
addOp2p(itemp);
}
return oldp;
}
AstNode* getIndexValuep(uint32_t index) const {
KeyItemMap::const_iterator it = m_map.find(index);
if (it == m_map.end()) return NULL;
else return it->second->valuep();
}
AstNode* getIndexDefaultedValuep(uint32_t index) const {
AstNode* valuep = getIndexValuep(index);
if (!valuep) valuep = defaultp();
return valuep;
}
};
class AstPragma : public AstNode {

View File

@ -1589,19 +1589,7 @@ private:
else if (m_selp && VN_IS(valuep, InitArray)) {
AstInitArray* initarp = VN_CAST(valuep, InitArray);
uint32_t bit = m_selp->bitConst();
int pos = 0;
AstNode* itemp = initarp->initsp();
for (; itemp; ++pos, itemp=itemp->nextp()) {
uint32_t index = initarp->posIndex(pos);
if (index == bit) break;
if (index > bit) {
if (initarp->defaultp()) {
itemp = initarp->defaultp();
} else {
initarp->v3fatalSrc("Not enough values in array initialization");
}
}
}
AstNode* itemp = initarp->getIndexDefaultedValuep(bit);
if (VN_IS(itemp, Const)) {
const V3Number& num = VN_CAST(itemp, Const)->num();
//UINFO(2,"constVisit "<<cvtToHex(valuep)<<" "<<num<<endl);
@ -2122,7 +2110,9 @@ private:
}
}
virtual void visit(AstInitArray* nodep) {
// Constant if all children are constant
iterateChildren(nodep);
}
virtual void visit(AstInitItem* nodep) {
iterateChildren(nodep);
}
// These are converted by V3Param. Don't constify as we don't want the

View File

@ -1749,13 +1749,13 @@ void EmitCImp::emitVarReset(AstVar* varp) {
VN_CAST(initarp->defaultp(), Const));
puts("}}\n");
}
int pos = 0;
for (AstNode* itemp = initarp->initsp(); itemp; ++pos, itemp=itemp->nextp()) {
int index = initarp->posIndex(pos);
UASSERT_OBJ(initarp->defaultp() || index==pos, initarp,
"Not enough values in array initialization");
const AstInitArray::KeyItemMap& mapr = initarp->map();
for (AstInitArray::KeyItemMap::const_iterator it = mapr.begin();
it != mapr.end(); ++it) {
AstNode* valuep = it->second->valuep();
emitSetVarConstant(varp->nameProtect()
+"["+cvtToStr(index)+"]", VN_CAST(itemp, Const));
+"["+cvtToStr(it->first)+"]",
VN_CAST(valuep, Const));
}
} else {
varp->v3fatalSrc("InitArray under non-arrayed var");

View File

@ -467,13 +467,15 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
}
virtual void visit(AstInitArray* nodep) {
putfs(nodep, "`{");
int pos = 0;
for (AstNode* itemp = nodep->initsp(); itemp; ++pos, itemp=itemp->nextp()) {
int index = nodep->posIndex(pos);
puts(cvtToStr(index));
int comma = 0;
const AstInitArray::KeyItemMap& mapr = nodep->map();
for (AstInitArray::KeyItemMap::const_iterator it = mapr.begin();
it != mapr.end(); ++it) {
if (comma++) putbs(", ");
puts(cvtToStr(it->first));
puts(":");
iterate(itemp);
if (itemp->nextp()) putbs(",");
AstNode* valuep = it->second->valuep();
iterate(valuep);
}
puts("}");
}

View File

@ -86,12 +86,9 @@ class SliceVisitor : public AstNVisitor {
AstNode* newp;
if (AstInitArray* initp = VN_CAST(nodep, InitArray)) {
UINFO(9," cloneInitArray("<<elements<<","<<offset<<") "<<nodep<<endl);
AstNode* itemp = initp->initsp();
int leOffset = !arrayp->rangep()->littleEndian()
? arrayp->rangep()->elementsConst()-1-offset : offset;
for (int pos = 0; itemp && pos < leOffset; ++pos) {
itemp = itemp->nextp();
}
AstNode* itemp = initp->getIndexDefaultedValuep(leOffset);
if (!itemp) {
nodep->v3error("Array initialization has too few elements, need element "<<offset);
itemp = initp->initsp();

View File

@ -1438,6 +1438,9 @@ private:
}
nodep->dtypeFrom(nodep->itemp());
}
virtual void visit(AstInitItem* nodep) {
userIterateChildren(nodep, m_vup);
}
virtual void visit(AstInitArray* nodep) {
// InitArray has type of the array; children are array values
if (m_vup->prelim()) { // First stage evaluation
@ -1983,13 +1986,9 @@ private:
if (!newp) {
AstInitArray* newap
= new AstInitArray(nodep->fileline(), arrayp, NULL);
newap->addValuep(valuep);
newp = newap;
} else {
// We iterate hi()..lo() as that is what packed needs,
// but INITARRAY needs lo() first
VN_CAST(newp, InitArray)->addFrontValuep(valuep);
}
VN_CAST(newp, InitArray)->addIndexValuep(ent - range.lo(), valuep);
} else { // Packed. Convert to concat for now.
if (!newp) newp = valuep;
else {