void ParamVisitor::visitCell(AstCell* nodep) { // Cell: Check for parameters in the instantiation. nodep->iterateChildren(*this); if (!nodep->modp()) nodep->v3fatalSrc("Not linked?"); if (nodep->paramsp() || 1 // Need to look for interfaces; could track when one exists, but should be harmless to always do this ) { UINFO(4,"De-parameterize: "<<nodep<<endl); // Create new module name with _'s between the constants if (debug()>=10) nodep->dumpTree(cout,"-cell:\t"); // Evaluate all module constants V3Const::constifyParamsEdit(nodep); // Make sure constification worked // Must be a separate loop, as constant conversion may have changed some pointers. //if (debug()) nodep->dumpTree(cout,"-cel2:\t"); string longname = nodep->modp()->name(); bool any_overrides = false; longname += "_"; if (debug()>8) nodep->paramsp()->dumpTreeAndNext(cout,"-cellparams:\t"); for (AstPin* pinp = nodep->paramsp(); pinp; pinp=pinp->nextp()->castPin()) { if (!pinp->exprp()) continue; // No-connect AstVar* modvarp = pinp->modVarp(); if (!modvarp) { pinp->v3error("Parameter not found in sub-module: Param "<<pinp->name()<<" of "<<nodep->prettyName()); } else if (!modvarp->isGParam()) { pinp->v3error("Attempted parameter setting of non-parameter: Param "<<pinp->name()<<" of "<<nodep->prettyName()); } else { AstConst* constp = pinp->exprp()->castConst(); AstConst* origconstp = modvarp->valuep()->castConst(); if (!constp) { //if (debug()) pinp->dumpTree(cout,"error:"); pinp->v3error("Can't convert defparam value to constant: Param "<<pinp->name()<<" of "<<nodep->prettyName()); pinp->exprp()->replaceWith(new AstConst(pinp->fileline(), V3Number(pinp->fileline(), modvarp->width(), 0))); } else if (origconstp && constp->sameTree(origconstp)) { // Setting parameter to its default value. Just ignore it. // This prevents making additional modules, and makes coverage more // obvious as it won't show up under a unique module page name. } else { longname += "_" + paramSmallName(nodep->modp(),pinp->modVarp())+constp->num().ascii(false); any_overrides = true; } } } IfaceRefRefs ifaceRefRefs; for (AstPin* pinp = nodep->pinsp(); pinp; pinp=pinp->nextp()->castPin()) { AstVar* modvarp = pinp->modVarp(); if (modvarp->isIfaceRef()) { AstIfaceRefDType* portIrefp = modvarp->subDTypep()->castIfaceRefDType(); //UINFO(9," portIfaceRef "<<portIrefp<<endl); if (!pinp->exprp() || !pinp->exprp()->castVarRef() || !pinp->exprp()->castVarRef()->varp() || !pinp->exprp()->castVarRef()->varp()->subDTypep() || !pinp->exprp()->castVarRef()->varp()->subDTypep()->castIfaceRefDType()) { pinp->v3error("Interface port '"<<modvarp->prettyName()<<"' is not connected to interface/modport pin expression"); } else { AstIfaceRefDType* pinIrefp = pinp->exprp()->castVarRef()->varp()->subDTypep()->castIfaceRefDType(); //UINFO(9," pinIfaceRef "<<pinIrefp<<endl); if (portIrefp->ifaceViaCellp() != pinIrefp->ifaceViaCellp()) { UINFO(9," IfaceRefDType needs reconnect "<<pinIrefp<<endl); longname += "_" + paramSmallName(nodep->modp(),pinp->modVarp())+paramValueNumber(pinIrefp); any_overrides = true; ifaceRefRefs.push_back(make_pair(portIrefp,pinIrefp)); } } } } if (!any_overrides) { UINFO(8,"Cell parameters all match original values, skipping expansion.\n"); } else { // If the name is very long, we don't want to overwhelm the filename limit // We don't do this always, as it aids debugability to have intuitive naming. // TODO can use new V3Name hash replacement instead of this string newname = longname; if (longname.length()>30) { LongMap::iterator iter = m_longMap.find(longname); if (iter != m_longMap.end()) { newname = iter->second; } else { newname = nodep->modp()->name(); newname += "__pi"+cvtToStr(++m_longId); // We use all upper case above, so lower here can't conflict m_longMap.insert(make_pair(longname, newname)); } } UINFO(4,"Name: "<<nodep->modp()->name()<<"->"<<longname<<"->"<<newname<<endl); // // Already made this flavor? AstNodeModule* modp = NULL; ModNameMap::iterator iter = m_modNameMap.find(newname); if (iter != m_modNameMap.end()) modp = iter->second.m_modp; if (!modp) { // Deep clone of new module // Note all module internal variables will be re-linked to the new modules by clone // However links outside the module (like on the upper cells) will not. modp = nodep->modp()->cloneTree(false); modp->name(newname); modp->user5(false); // We need to re-recurse this module once changed nodep->modp()->addNextHere(modp); // Keep tree sorted by cell occurrences m_modNameMap.insert(make_pair(modp->name(), ModInfo(modp))); iter = m_modNameMap.find(newname); VarCloneMap* clonemapp = &(iter->second.m_cloneMap); UINFO(4," De-parameterize to new: "<<modp<<endl); // Grab all I/O so we can remap our pins later // Note we allow multiple users of a parameterized model, thus we need to stash this info. for (AstNode* stmtp=modp->stmtsp(); stmtp; stmtp = stmtp->nextp()) { if (AstVar* varp = stmtp->castVar()) { if (varp->isIO() || varp->isGParam() || varp->isIfaceRef()) { // Cloning saved a pointer to the new node for us, so just follow that link. AstVar* oldvarp = varp->clonep()->castVar(); //UINFO(8,"Clone list 0x"<<hex<<(uint32_t)oldvarp<<" -> 0x"<<(uint32_t)varp<<endl); clonemapp->insert(make_pair(oldvarp, varp)); } } } // Relink parameter vars to the new module relinkPins(clonemapp, nodep->paramsp()); // Fix any interface references for (IfaceRefRefs::iterator it=ifaceRefRefs.begin(); it!=ifaceRefRefs.end(); ++it) { AstIfaceRefDType* portIrefp = it->first; AstIfaceRefDType* pinIrefp = it->second; AstIfaceRefDType* cloneIrefp = portIrefp->clonep()->castIfaceRefDType(); UINFO(8," IfaceOld "<<portIrefp<<endl); UINFO(8," IfaceTo "<<pinIrefp<<endl); if (!cloneIrefp) portIrefp->v3fatalSrc("parameter clone didn't hit AstIfaceRefDType"); UINFO(8," IfaceClo "<<cloneIrefp<<endl); cloneIrefp->ifacep(pinIrefp->ifaceViaCellp()); UINFO(8," IfaceNew "<<cloneIrefp<<endl); } // Assign parameters to the constants specified // DOES clone() so must be finished with module clonep() before here for (AstPin* pinp = nodep->paramsp(); pinp; pinp=pinp->nextp()->castPin()) { AstVar* modvarp = pinp->modVarp(); if (modvarp && pinp->exprp()) { AstConst* constp = pinp->exprp()->castConst(); // Remove any existing parameter if (modvarp->valuep()) modvarp->valuep()->unlinkFrBack()->deleteTree(); // Set this parameter to value requested by cell modvarp->valuep(constp->cloneTree(false)); } } } else { UINFO(4," De-parameterize to old: "<<modp<<endl); } // Have child use this module instead. nodep->modp(modp); nodep->modName(newname); // We need to relink the pins to the new module VarCloneMap* clonemapp = &(iter->second.m_cloneMap); relinkPins(clonemapp, nodep->pinsp()); UINFO(8," Done with "<<modp<<endl); } // if any_overrides // Delete the parameters from the cell; they're not relevant any longer. if (nodep->paramsp()) nodep->paramsp()->unlinkFrBackWithNext()->deleteTree(); UINFO(8," Done with "<<nodep<<endl); //if (debug()>=10) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("param-out.tree")); } // Now remember to process the child module at the end of the module m_todoModps.insert(make_pair(nodep->modp()->level(),nodep->modp())); }
int main(int argc, char **argv) { #ifdef _MEMMGR HeapManager heap; #endif clock_t from, to; double diff; LongHash lhash; LongMap lmap; StringHash shash; StringMap smap; srand(clock()); int nelems = 10; int naccess = 100; if (argc >= 2) { sscanf(argv[1], "%d", &nelems); } if (argc >= 3) { sscanf(argv[2], "%d", &naccess); } const char *strpool[] = { "hello", "_", "world", "012", "before", "after", "if", "then", "else", "for", "while", "do", "@", "~", "+", "-", "function", "class" }; size_t nstrings = sizeof(strpool) / sizeof(const char*); // fill elements std::vector<std::string> skeys(nelems); std::vector<long> lkeys(nelems); std::cout << "Buid hash and map with " << nelems << " elements" << std::endl; for (int i=0; i<nelems; ++i) { long k = rand(); lkeys[i] = k; int p = rand() % nstrings; int s = rand() % nstrings; skeys[i] = strpool[p]; skeys[i] += strpool[s]; } from = clock(); for (int i=0; i<nelems; ++i) { lhash.insert(lkeys[i], rand()); } to = clock(); diff = double(to - from) / CLOCKS_PER_SEC; std::cout << "LongHash fill " << nelems << " values: " << diff << " (s)" << std::endl; from = clock(); for (int i=0; i<nelems; ++i) { lmap[lkeys[i]] = rand(); } to = clock(); diff = double(to - from) / CLOCKS_PER_SEC; std::cout << "LongMap fill " << nelems << " values: " << diff << " (s)" << std::endl; from = clock(); for (int i=0; i<nelems; ++i) { shash.insert(skeys[i], rand()); } to = clock(); diff = double(to - from) / CLOCKS_PER_SEC; std::cout << "StringHash fill " << nelems << " values: " << diff << " (s)" << std::endl; from = clock(); for (int i=0; i<nelems; ++i) { smap[skeys[i]] = rand(); } to = clock(); diff = double(to - from) / CLOCKS_PER_SEC; std::cout << "StringMap fill " << nelems << " values: " << diff << " (s)" << std::endl; // check datas /* std::cout << "Check data" << std::endl; for (int k=0; k<nelems; ++k) { long v0 = lhash.getValue(lkeys[k]); long v1 = lmap[lkeys[k]]; if (v0 != v1) { std::cout << "Data mismatch at long key \"" << lkeys[k] << "\"" << std::endl; } v0 = shash.getValue(skeys[k]); v1 = smap[skeys[k]]; if (v0 != v1) { std::cout << "Data mismatch at std::string key \"" << skeys[k] << "\"" << std::endl; } } */ // test long map from = clock(); for (int i=0; i<naccess; ++i) { long k = rand() % nelems; long v = lhash.getValue(lkeys[k]); } to = clock(); diff = double(to - from) / CLOCKS_PER_SEC; std::cout << "LongHash " << naccess << " random access: " << diff << " (s)" << std::endl; from = clock(); for (int i=0; i<naccess; ++i) { long k = rand() % nelems; long v = lmap[lkeys[k]]; } to = clock(); diff = double(to - from) / CLOCKS_PER_SEC; std::cout << "LongMap " << naccess << " random access: " << diff << " (s)" << std::endl; // test string map from = clock(); for (int i=0; i<naccess; ++i) { long k = rand() % nelems; long v = shash.getValue(skeys[k]); } to = clock(); diff = double(to - from) / CLOCKS_PER_SEC; std::cout << "StringHash " << naccess << " random access: " << diff << " (s)" << std::endl; from = clock(); for (int i=0; i<naccess; ++i) { long k = rand() % nelems; long v = smap[skeys[k]]; } to = clock(); diff = double(to - from) / CLOCKS_PER_SEC; std::cout << "StringMap " << naccess << " random access: " << diff << " (s)" << std::endl; // test random keys // should make it so we have around 50% chances to find the element // build a new key array size_t numhits = 0; double hitperc = 0.0; std::vector<long> rkeys(2*nelems); for (size_t i=0; i<lkeys.size(); ++i) { rkeys[i] = lkeys[i]; } for (size_t i=nelems; i<size_t(2 * nelems); ++i) { rkeys[i] = rand(); } from = clock(); for (int i=0; i<naccess; ++i) { long k = rkeys[rand() % (2 * nelems)]; long v; if (lhash.getValue(k, v)) { //if (lhash.hasKey(k)) { ++numhits; //long v = lhash.getValue(k); } } to = clock(); diff = double(to - from) / CLOCKS_PER_SEC; hitperc = double(numhits) / double(naccess); std::cout << "LongHash " << naccess << " random keys: " << diff << " (s) [" << (hitperc*100) << " % hit]" << std::endl; /* HashMap<long, long>::iterator hit; numhits = 0; from = clock(); for (int i=0; i<naccess; ++i) { long k = rkeys[rand() % (2 * nelems)]; hit = lhash.find(k); if (hit != lhash.end()) { ++numhits; long v = hit->second; } } to = clock(); diff = double(to - from) / CLOCKS_PER_SEC; hitperc = double(numhits) / double(naccess); std::cout << "LongHash " << naccess << " random keys: " << diff << " (s) [" << (hitperc*100) << " % hit, using iterators]" << std::endl; */ std::map<long,long>::iterator mit; numhits = 0; from = clock(); for (int i=0; i<naccess; ++i) { long k = rkeys[rand() % (2 * nelems)]; mit = lmap.find(k); if (mit != lmap.end()) { ++numhits; long v = mit->second; } } to = clock(); diff = double(to - from) / CLOCKS_PER_SEC; hitperc = double(numhits) / double(naccess); std::cout << "LongMap " << naccess << " random keys: " << diff << " (s) [" << (hitperc*100) << " % hit]" << std::endl; return 0; }