2012-04-13 01:08:20 +00:00
|
|
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
2006-08-26 11:35:28 +00:00
|
|
|
//*************************************************************************
|
|
|
|
// DESCRIPTION: Verilator: Rename scope references to module-local references
|
|
|
|
//
|
2019-11-08 03:33:59 +00:00
|
|
|
// Code available from: https://verilator.org
|
2006-08-26 11:35:28 +00:00
|
|
|
//
|
|
|
|
//*************************************************************************
|
|
|
|
//
|
2020-03-21 15:24:24 +00:00
|
|
|
// Copyright 2003-2020 by Wilson Snyder. This program is free software; you
|
|
|
|
// can redistribute it and/or modify it under the terms of either the GNU
|
2009-05-04 21:07:57 +00:00
|
|
|
// Lesser General Public License Version 3 or the Perl Artistic License
|
|
|
|
// Version 2.0.
|
2020-03-21 15:24:24 +00:00
|
|
|
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
2006-08-26 11:35:28 +00:00
|
|
|
//
|
|
|
|
//*************************************************************************
|
|
|
|
// DESCOPE TRANSFORMATIONS:
|
2019-05-19 20:13:13 +00:00
|
|
|
// All modules:
|
|
|
|
// Each VARREF/FUNCCALL
|
|
|
|
// Change varref name() to be relative to current module
|
|
|
|
// Remove varScopep()
|
|
|
|
// This allows for better V3Combine'ing.
|
2008-06-10 01:25:10 +00:00
|
|
|
//
|
2006-08-26 11:35:28 +00:00
|
|
|
//*************************************************************************
|
2019-10-05 00:17:11 +00:00
|
|
|
|
2006-12-18 19:20:45 +00:00
|
|
|
#include "config_build.h"
|
|
|
|
#include "verilatedos.h"
|
2006-08-26 11:35:28 +00:00
|
|
|
|
|
|
|
#include "V3Global.h"
|
|
|
|
#include "V3Descope.h"
|
|
|
|
#include "V3Ast.h"
|
2006-08-30 21:07:55 +00:00
|
|
|
#include "V3EmitCBase.h"
|
2006-08-26 11:35:28 +00:00
|
|
|
|
2018-10-14 17:43:24 +00:00
|
|
|
#include <map>
|
|
|
|
|
2006-08-26 11:35:28 +00:00
|
|
|
//######################################################################
|
|
|
|
|
2020-11-19 02:32:16 +00:00
|
|
|
class DescopeVisitor final : public AstNVisitor {
|
2006-08-26 11:35:28 +00:00
|
|
|
private:
|
|
|
|
// NODE STATE
|
|
|
|
// Cleared entire netlist
|
2019-05-19 20:13:13 +00:00
|
|
|
// AstCFunc::user() // bool. Indicates processing completed
|
2020-01-20 16:43:41 +00:00
|
|
|
AstUser1InUse m_inuser1;
|
2006-08-26 11:35:28 +00:00
|
|
|
|
|
|
|
// TYPES
|
2020-01-20 16:43:41 +00:00
|
|
|
typedef std::multimap<string, AstCFunc*> FuncMmap;
|
2006-08-26 11:35:28 +00:00
|
|
|
|
|
|
|
// STATE
|
2020-08-15 17:11:27 +00:00
|
|
|
AstNodeModule* m_modp = nullptr; // Current module
|
|
|
|
AstScope* m_scopep = nullptr; // Current scope
|
|
|
|
bool m_modSingleton = false; // m_modp is only instanced once
|
|
|
|
bool m_allowThis = false; // Allow function non-static
|
|
|
|
bool m_needThis = false; // Make function non-static
|
2020-01-20 16:43:41 +00:00
|
|
|
FuncMmap m_modFuncs; // Name of public functions added
|
2006-08-26 11:35:28 +00:00
|
|
|
|
|
|
|
// METHODS
|
2018-05-14 10:50:47 +00:00
|
|
|
VL_DEBUG_FUNC; // Declare debug()
|
2009-01-21 21:56:50 +00:00
|
|
|
|
2017-10-05 22:18:11 +00:00
|
|
|
static bool modIsSingleton(AstNodeModule* modp) {
|
|
|
|
// True iff there's exactly one instance of this module in the design.
|
|
|
|
int instances = 0;
|
2020-01-20 16:43:41 +00:00
|
|
|
for (AstNode* stmtp = modp->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
2018-02-02 02:32:58 +00:00
|
|
|
if (VN_IS(stmtp, Scope)) {
|
2017-10-05 22:18:11 +00:00
|
|
|
if (++instances > 1) { return false; }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return (instances == 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Construct the best prefix to reference an object in 'scopep'
|
|
|
|
// from a CFunc in 'm_scopep'. Result may be relative
|
|
|
|
// ("this->[...]") or absolute ("vlTOPp->[...]").
|
|
|
|
//
|
|
|
|
// Using relative references allows V3Combine'ing
|
|
|
|
// code across multiple instances of the same module.
|
|
|
|
//
|
|
|
|
// Sets 'hierThisr' true if the object is local to this scope
|
|
|
|
// (and could be made into a function-local later in V3Localize),
|
|
|
|
// false if the object is in another scope.
|
2020-11-25 03:46:02 +00:00
|
|
|
string descopedName(bool& hierThisr, string& hierUnprot, const AstScope* scopep,
|
|
|
|
const AstVar* varp) {
|
2018-06-13 22:05:00 +00:00
|
|
|
UASSERT(scopep, "Var/Func not scoped");
|
2019-05-19 20:13:13 +00:00
|
|
|
hierThisr = (scopep == m_scopep);
|
2017-10-05 22:18:11 +00:00
|
|
|
|
|
|
|
// It's possible to disable relative references. This is a concession
|
|
|
|
// to older compilers (gcc < 4.5.x) that don't understand __restrict__
|
|
|
|
// well and emit extra ld/st to guard against pointer aliasing
|
|
|
|
// when this-> and vlTOPp-> are mixed in the same function.
|
|
|
|
//
|
|
|
|
// "vlTOPp" is declared "restrict" so better compilers understand
|
|
|
|
// that it won't alias with "this".
|
|
|
|
bool relativeRefOk = v3Global.opt.relativeCFuncs();
|
2019-01-16 05:38:42 +00:00
|
|
|
//
|
|
|
|
// Static functions can't use this
|
|
|
|
if (!m_allowThis) relativeRefOk = false;
|
|
|
|
//
|
2017-10-05 22:18:11 +00:00
|
|
|
// Use absolute refs in top-scoped routines, keep them static.
|
|
|
|
// The DPI callback registration depends on representing top-level
|
|
|
|
// static routines as plain function pointers. That breaks if those
|
|
|
|
// become true OO routines.
|
|
|
|
//
|
|
|
|
// V3Combine wouldn't likely be able to combine top-level
|
|
|
|
// routines anyway, so there's no harm in keeping these static.
|
2020-01-25 15:19:59 +00:00
|
|
|
UASSERT_OBJ(m_modp, scopep, "Scope not under module");
|
2020-01-20 16:43:41 +00:00
|
|
|
if (m_modp->isTop()) relativeRefOk = false;
|
2019-01-16 05:38:42 +00:00
|
|
|
//
|
2017-10-05 22:18:11 +00:00
|
|
|
// Use absolute refs if this scope is the only instance of the module.
|
|
|
|
// Saves a bit of overhead on passing the 'this' pointer, and there's no
|
|
|
|
// need to be nice to V3Combine when we have only a single instance.
|
|
|
|
// The risk that this prevents combining identical logic from differently-
|
|
|
|
// named but identical modules seems low.
|
2020-01-20 16:43:41 +00:00
|
|
|
if (m_modSingleton) relativeRefOk = false;
|
2020-04-05 13:30:23 +00:00
|
|
|
//
|
|
|
|
// Class methods need relative
|
|
|
|
if (m_modp && VN_IS(m_modp, Class)) relativeRefOk = true;
|
2017-10-05 22:18:11 +00:00
|
|
|
|
2019-05-19 20:13:13 +00:00
|
|
|
if (varp && varp->isFuncLocal()) {
|
2017-10-05 22:18:11 +00:00
|
|
|
hierThisr = true;
|
2019-05-19 20:13:13 +00:00
|
|
|
return ""; // Relative to function, not in this
|
2017-10-05 22:18:11 +00:00
|
|
|
} else if (relativeRefOk && scopep == m_scopep) {
|
|
|
|
m_needThis = true;
|
|
|
|
return "this->";
|
2020-11-25 03:46:02 +00:00
|
|
|
} else if (VN_IS(scopep->modp(), Class)) {
|
|
|
|
hierUnprot = v3Global.opt.modPrefix() + "_"; // Prefix before protected part
|
|
|
|
return scopep->modp()->name() + "::";
|
2020-04-14 02:51:35 +00:00
|
|
|
} else if (relativeRefOk && scopep->aboveScopep() && scopep->aboveScopep() == m_scopep) {
|
2017-10-05 22:18:11 +00:00
|
|
|
// Reference to scope of cell directly under this module, can just "cell->"
|
|
|
|
string name = scopep->name();
|
|
|
|
string::size_type pos;
|
2020-01-20 16:43:41 +00:00
|
|
|
if ((pos = name.rfind('.')) != string::npos) name.erase(0, pos + 1);
|
2017-10-05 22:18:11 +00:00
|
|
|
m_needThis = true;
|
2020-01-20 16:43:41 +00:00
|
|
|
return name + "->";
|
2017-10-05 22:18:11 +00:00
|
|
|
} else {
|
2019-09-09 11:50:21 +00:00
|
|
|
// Reference to something elsewhere, or relative references
|
2017-10-05 22:18:11 +00:00
|
|
|
// are disabled. Use global variable
|
2020-01-20 16:43:41 +00:00
|
|
|
UINFO(8, " Descope " << scopep << endl);
|
|
|
|
UINFO(8, " to " << scopep->name() << endl);
|
|
|
|
UINFO(8, " under " << m_scopep->name() << endl);
|
2019-05-19 20:13:13 +00:00
|
|
|
if (!scopep->aboveScopep()) { // Top
|
2017-10-05 22:18:11 +00:00
|
|
|
// We could also return "vlSymsp->TOPp->" here, but GCC would
|
|
|
|
// suspect aliases.
|
|
|
|
return "vlTOPp->";
|
|
|
|
} else {
|
2020-01-20 16:43:41 +00:00
|
|
|
return scopep->nameVlSym() + ".";
|
2017-10-05 22:18:11 +00:00
|
|
|
}
|
|
|
|
}
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void makePublicFuncWrappers() {
|
2019-05-19 20:13:13 +00:00
|
|
|
// We recorded all public functions in m_modFuncs.
|
|
|
|
// If for any given name only one function exists, we can use that function directly.
|
|
|
|
// If multiple functions exist, we need to select the appropriate scope.
|
2020-01-20 16:43:41 +00:00
|
|
|
for (FuncMmap::iterator it = m_modFuncs.begin(); it != m_modFuncs.end(); ++it) {
|
2019-05-19 20:13:13 +00:00
|
|
|
string name = it->first;
|
|
|
|
AstCFunc* topFuncp = it->second;
|
2020-08-16 15:43:49 +00:00
|
|
|
auto nextIt1 = it;
|
2020-01-20 16:43:41 +00:00
|
|
|
++nextIt1;
|
|
|
|
bool moreOfSame1 = (nextIt1 != m_modFuncs.end() && nextIt1->first == name);
|
2019-05-19 20:13:13 +00:00
|
|
|
if (moreOfSame1) {
|
|
|
|
// Multiple functions under this name, need a wrapper function
|
2020-01-20 16:43:41 +00:00
|
|
|
UINFO(6, " Wrapping " << name << " multifuncs\n");
|
2019-05-19 20:13:13 +00:00
|
|
|
AstCFunc* newfuncp = topFuncp->cloneTree(false);
|
2020-01-20 16:43:41 +00:00
|
|
|
if (newfuncp->initsp()) newfuncp->initsp()->unlinkFrBackWithNext()->deleteTree();
|
|
|
|
if (newfuncp->stmtsp()) newfuncp->stmtsp()->unlinkFrBackWithNext()->deleteTree();
|
2019-05-19 20:13:13 +00:00
|
|
|
if (newfuncp->finalsp()) newfuncp->finalsp()->unlinkFrBackWithNext()->deleteTree();
|
|
|
|
newfuncp->name(name);
|
|
|
|
newfuncp->isStatic(false);
|
|
|
|
newfuncp->addInitsp(
|
|
|
|
new AstCStmt(newfuncp->fileline(),
|
2020-01-20 16:43:41 +00:00
|
|
|
EmitCBaseVisitor::symClassVar() + " = this->__VlSymsp;\n"));
|
|
|
|
newfuncp->addInitsp(
|
|
|
|
new AstCStmt(newfuncp->fileline(), EmitCBaseVisitor::symTopAssign() + "\n"));
|
2019-05-19 20:13:13 +00:00
|
|
|
topFuncp->addNextHere(newfuncp);
|
|
|
|
// In the body, call each function if it matches the given scope
|
|
|
|
for (FuncMmap::iterator eachIt = it;
|
2020-01-20 16:43:41 +00:00
|
|
|
eachIt != m_modFuncs.end() && eachIt->first == name; ++eachIt) {
|
2019-05-19 20:13:13 +00:00
|
|
|
it = eachIt;
|
|
|
|
AstCFunc* funcp = eachIt->second;
|
2020-08-16 15:43:49 +00:00
|
|
|
auto nextIt2 = eachIt;
|
2020-01-20 16:43:41 +00:00
|
|
|
++nextIt2;
|
|
|
|
bool moreOfSame = (nextIt2 != m_modFuncs.end() && nextIt2->first == name);
|
2019-07-06 16:57:50 +00:00
|
|
|
UASSERT_OBJ(funcp->scopep(), funcp, "Not scoped");
|
2006-08-26 11:35:28 +00:00
|
|
|
|
2020-01-20 16:43:41 +00:00
|
|
|
UINFO(6, " Wrapping " << name << " " << funcp << endl);
|
2020-04-14 02:51:35 +00:00
|
|
|
UINFO(6,
|
|
|
|
" at " << newfuncp->argTypes() << " und " << funcp->argTypes() << endl);
|
2019-05-19 20:13:13 +00:00
|
|
|
funcp->declPrivate(true);
|
2020-08-15 14:12:55 +00:00
|
|
|
AstNode* argsp = nullptr;
|
2020-01-20 16:43:41 +00:00
|
|
|
for (AstNode* stmtp = newfuncp->argsp(); stmtp; stmtp = stmtp->nextp()) {
|
2018-02-02 02:32:58 +00:00
|
|
|
if (AstVar* portp = VN_CAST(stmtp, Var)) {
|
2018-10-27 21:29:00 +00:00
|
|
|
if (portp->isIO() && !portp->isFuncReturn()) {
|
2020-09-07 21:09:25 +00:00
|
|
|
AstNode* newp = new AstVarRef(portp->fileline(), portp,
|
|
|
|
portp->isWritable() ? VAccess::WRITE
|
|
|
|
: VAccess::READ);
|
2020-01-20 16:43:41 +00:00
|
|
|
argsp = argsp ? argsp->addNextNull(newp) : newp;
|
2018-10-27 21:29:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2006-08-26 11:35:28 +00:00
|
|
|
|
2020-01-20 16:43:41 +00:00
|
|
|
AstNode* returnp = new AstCReturn(
|
|
|
|
funcp->fileline(), new AstCCall(funcp->fileline(), funcp, argsp));
|
2006-08-26 11:35:28 +00:00
|
|
|
|
2019-05-19 20:13:13 +00:00
|
|
|
if (moreOfSame) {
|
2020-01-20 16:43:41 +00:00
|
|
|
AstIf* ifp = new AstIf(
|
|
|
|
funcp->fileline(),
|
|
|
|
new AstEq(
|
|
|
|
funcp->fileline(), new AstCMath(funcp->fileline(), "this", 64),
|
|
|
|
new AstCMath(funcp->fileline(),
|
|
|
|
string("&(") + funcp->scopep()->nameVlSym() + ")",
|
|
|
|
64)),
|
2020-08-15 14:12:55 +00:00
|
|
|
returnp, nullptr);
|
2019-05-19 20:13:13 +00:00
|
|
|
newfuncp->addStmtsp(ifp);
|
|
|
|
} else {
|
|
|
|
newfuncp->addStmtsp(returnp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Not really any way the user could do this, and we'd need
|
|
|
|
// to come up with some return value
|
2020-01-20 16:43:41 +00:00
|
|
|
// newfuncp->addStmtsp(new AstDisplay(newfuncp->fileline(),
|
2019-05-19 20:13:13 +00:00
|
|
|
// AstDisplayType::DT_WARNING,
|
2020-01-20 16:43:41 +00:00
|
|
|
// string("%%Error: ")+name+"() called with bad
|
2020-08-15 14:12:55 +00:00
|
|
|
// scope", nullptr));
|
2020-01-20 16:43:41 +00:00
|
|
|
// newfuncp->addStmtsp(new AstStop(newfuncp->fileline()));
|
|
|
|
if (debug() >= 9) newfuncp->dumpTree(cout, " newfunc: ");
|
2019-05-19 20:13:13 +00:00
|
|
|
} else {
|
|
|
|
// Only a single function under this name, we can simply rename it
|
2020-01-20 16:43:41 +00:00
|
|
|
UINFO(6, " Wrapping " << name << " just one " << topFuncp << endl);
|
2019-05-19 20:13:13 +00:00
|
|
|
topFuncp->name(name);
|
|
|
|
}
|
|
|
|
}
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// VISITORS
|
2020-08-15 14:03:34 +00:00
|
|
|
virtual void visit(AstNodeModule* nodep) override {
|
2020-08-25 01:10:43 +00:00
|
|
|
VL_RESTORER(m_modp);
|
2020-01-20 18:27:27 +00:00
|
|
|
{
|
|
|
|
m_modp = nodep;
|
|
|
|
m_modFuncs.clear();
|
|
|
|
m_modSingleton = modIsSingleton(m_modp);
|
|
|
|
iterateChildren(nodep);
|
|
|
|
makePublicFuncWrappers();
|
|
|
|
}
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
2020-08-15 14:03:34 +00:00
|
|
|
virtual void visit(AstScope* nodep) override {
|
2019-05-19 20:13:13 +00:00
|
|
|
m_scopep = nodep;
|
2018-05-11 00:55:37 +00:00
|
|
|
iterateChildren(nodep);
|
2020-08-15 14:12:55 +00:00
|
|
|
m_scopep = nullptr;
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
2020-08-15 14:03:34 +00:00
|
|
|
virtual void visit(AstVarScope* nodep) override {
|
2019-05-19 20:13:13 +00:00
|
|
|
// Delete the varscope when we're finished
|
|
|
|
nodep->unlinkFrBack();
|
|
|
|
pushDeletep(nodep);
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
2020-08-15 14:03:34 +00:00
|
|
|
virtual void visit(AstNodeVarRef* nodep) override {
|
2018-05-11 00:55:37 +00:00
|
|
|
iterateChildren(nodep);
|
2019-05-19 20:13:13 +00:00
|
|
|
// Convert the hierch name
|
2020-11-25 03:46:02 +00:00
|
|
|
UINFO(9, " ref-in " << nodep << endl);
|
2019-07-06 16:57:50 +00:00
|
|
|
UASSERT_OBJ(m_scopep, nodep, "Node not under scope");
|
2019-05-19 20:13:13 +00:00
|
|
|
bool hierThis;
|
2020-11-25 03:46:02 +00:00
|
|
|
string hierUnprot;
|
|
|
|
nodep->hiernameToProt(descopedName(hierThis /*ref*/, hierUnprot /*ref*/,
|
|
|
|
nodep->varScopep()->scopep(),
|
|
|
|
nodep->varScopep()->varp()));
|
|
|
|
nodep->hiernameToUnprot(hierUnprot);
|
2019-05-19 20:13:13 +00:00
|
|
|
nodep->hierThis(hierThis);
|
2020-08-15 14:12:55 +00:00
|
|
|
nodep->varScopep(nullptr);
|
2020-11-25 03:46:02 +00:00
|
|
|
UINFO(9, " refout " << nodep << endl);
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
2020-08-15 14:03:34 +00:00
|
|
|
virtual void visit(AstNodeCCall* nodep) override {
|
2020-04-15 11:58:34 +00:00
|
|
|
// UINFO(9, " " << nodep << endl);
|
2018-05-11 00:55:37 +00:00
|
|
|
iterateChildren(nodep);
|
2019-05-19 20:13:13 +00:00
|
|
|
// Convert the hierch name
|
2019-07-06 16:57:50 +00:00
|
|
|
UASSERT_OBJ(m_scopep, nodep, "Node not under scope");
|
|
|
|
UASSERT_OBJ(nodep->funcp()->scopep(), nodep, "CFunc not under scope");
|
2019-05-19 20:13:13 +00:00
|
|
|
bool hierThis;
|
2020-11-25 03:46:02 +00:00
|
|
|
string hierUnprot;
|
|
|
|
nodep->hiernameToProt(
|
|
|
|
descopedName(hierThis /*ref*/, hierUnprot /*ref*/, nodep->funcp()->scopep(), nullptr));
|
|
|
|
nodep->hiernameToUnprot(hierUnprot);
|
2019-05-19 20:13:13 +00:00
|
|
|
// Can't do this, as we may have more calls later
|
2020-08-15 14:12:55 +00:00
|
|
|
// nodep->funcp()->scopep(nullptr);
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
2020-08-15 14:03:34 +00:00
|
|
|
virtual void visit(AstCFunc* nodep) override {
|
2020-10-31 12:59:35 +00:00
|
|
|
VL_RESTORER(m_needThis);
|
|
|
|
VL_RESTORER(m_allowThis);
|
2019-05-19 20:13:13 +00:00
|
|
|
if (!nodep->user1()) {
|
|
|
|
m_needThis = false;
|
2020-02-01 15:57:55 +00:00
|
|
|
m_allowThis = nodep->isStatic().falseUnknown(); // Non-static or unknown if static
|
2018-05-11 00:55:37 +00:00
|
|
|
iterateChildren(nodep);
|
2019-01-16 05:38:42 +00:00
|
|
|
nodep->user1(true);
|
2020-01-20 16:43:41 +00:00
|
|
|
if (m_needThis) nodep->isStatic(false);
|
2019-05-19 20:13:13 +00:00
|
|
|
// If it's under a scope, move it up to the top
|
|
|
|
if (m_scopep) {
|
|
|
|
nodep->unlinkFrBack();
|
|
|
|
m_modp->addStmtp(nodep);
|
2006-10-06 16:08:46 +00:00
|
|
|
|
2019-05-19 20:13:13 +00:00
|
|
|
if (nodep->funcPublic()) {
|
|
|
|
// There may be multiple public functions by the same name;
|
|
|
|
// record for later correction or making of shells
|
|
|
|
m_modFuncs.insert(make_pair(nodep->name(), nodep));
|
2020-01-20 16:43:41 +00:00
|
|
|
nodep->name(m_scopep->nameDotless() + "__" + nodep->name());
|
2019-05-19 20:13:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
2020-08-15 14:03:34 +00:00
|
|
|
virtual void visit(AstVar*) override {}
|
|
|
|
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
2020-01-20 16:43:41 +00:00
|
|
|
|
2006-08-26 11:35:28 +00:00
|
|
|
public:
|
|
|
|
// CONSTRUCTORS
|
2020-08-15 17:11:27 +00:00
|
|
|
explicit DescopeVisitor(AstNetlist* nodep) { iterate(nodep); }
|
2020-11-17 00:56:16 +00:00
|
|
|
virtual ~DescopeVisitor() override = default;
|
2006-08-26 11:35:28 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
// Descope class functions
|
|
|
|
|
|
|
|
void V3Descope::descopeAll(AstNetlist* nodep) {
|
2020-04-14 02:51:35 +00:00
|
|
|
UINFO(2, __FUNCTION__ << ": " << endl);
|
2020-11-14 21:13:06 +00:00
|
|
|
v3Global.assertScoped(false);
|
2020-04-14 02:51:35 +00:00
|
|
|
{ DescopeVisitor visitor(nodep); } // Destruct before checking
|
2017-09-18 02:52:57 +00:00
|
|
|
V3Global::dumpCheckGlobalTree("descope", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|