diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 9501d7a92..fabe9ed8f 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -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<<" ["<first<<"]="<<(void*)it->second; + } +} void AstJumpGo::dump(std::ostream& str) const { this->AstNode::dump(str); str<<" -> "; diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 7e6f60563..2d548fbf2 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -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 m_indices; // Which array index each entry in the list is for (if defaultp) + // Children: AstInitItem +public: + typedef std::map 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(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(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 { diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 47fa2a326..cc8bb79ea 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -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 "<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"); diff --git a/src/V3EmitV.cpp b/src/V3EmitV.cpp index 4e7a468bc..e2d6dd909 100644 --- a/src/V3EmitV.cpp +++ b/src/V3EmitV.cpp @@ -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("}"); } diff --git a/src/V3Slice.cpp b/src/V3Slice.cpp index 2a5f26bf1..6c0b15d7d 100644 --- a/src/V3Slice.cpp +++ b/src/V3Slice.cpp @@ -86,12 +86,9 @@ class SliceVisitor : public AstNVisitor { AstNode* newp; if (AstInitArray* initp = VN_CAST(nodep, InitArray)) { UINFO(9," cloneInitArray("<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 "<initsp(); diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 49fac3610..7035d515e 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -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 {