Internal cleanups towards recursive functions (#3267)
This commit is contained in:
parent
4e5f30858b
commit
41a563bdc8
|
|
@ -39,6 +39,7 @@ private:
|
||||||
|
|
||||||
V3Hash hashNodeAndIterate(AstNode* nodep, bool hashDType, bool hashChildren,
|
V3Hash hashNodeAndIterate(AstNode* nodep, bool hashDType, bool hashChildren,
|
||||||
std::function<void()>&& f) {
|
std::function<void()>&& f) {
|
||||||
|
// See comments in visit(AstCFunc) about this breaking recursion
|
||||||
if (m_cacheInUser4 && nodep->user4()) {
|
if (m_cacheInUser4 && nodep->user4()) {
|
||||||
return V3Hash(nodep->user4());
|
return V3Hash(nodep->user4());
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -393,6 +394,12 @@ private:
|
||||||
}
|
}
|
||||||
virtual void visit(AstCFunc* nodep) override {
|
virtual void visit(AstCFunc* nodep) override {
|
||||||
m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { //
|
m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { //
|
||||||
|
// We might be in a recursive function, if so on *second* call
|
||||||
|
// here we need to break what would be an infinite loop.
|
||||||
|
nodep->user4(V3Hash(1).value()); // Set this "first" call
|
||||||
|
// So that a second call will then exit hashNodeAndIterate
|
||||||
|
// Having a constant in the hash just means the recursion will
|
||||||
|
// end, it shouldn't change the CFunc having a unique hash itself.
|
||||||
m_hash += nodep->isLoose();
|
m_hash += nodep->isLoose();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -488,11 +495,12 @@ private:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
explicit HasherVisitor(AstNode* nodep)
|
HasherVisitor(AstNode* nodep)
|
||||||
: m_cacheInUser4{true} {
|
: m_cacheInUser4{true} {
|
||||||
iterate(nodep);
|
iterate(nodep);
|
||||||
}
|
}
|
||||||
explicit HasherVisitor(const AstNode* nodep)
|
class Uncached {};
|
||||||
|
HasherVisitor(const AstNode* nodep, Uncached)
|
||||||
: m_cacheInUser4{false} {
|
: m_cacheInUser4{false} {
|
||||||
iterate(const_cast<AstNode*>(nodep));
|
iterate(const_cast<AstNode*>(nodep));
|
||||||
}
|
}
|
||||||
|
|
@ -504,11 +512,11 @@ public:
|
||||||
// V3Hasher methods
|
// V3Hasher methods
|
||||||
|
|
||||||
V3Hash V3Hasher::operator()(AstNode* nodep) const {
|
V3Hash V3Hasher::operator()(AstNode* nodep) const {
|
||||||
if (!nodep->user4()) { HasherVisitor{nodep}; }
|
if (!nodep->user4()) HasherVisitor{nodep};
|
||||||
return V3Hash(nodep->user4());
|
return V3Hash(nodep->user4());
|
||||||
}
|
}
|
||||||
|
|
||||||
V3Hash V3Hasher::uncachedHash(const AstNode* nodep) {
|
V3Hash V3Hasher::uncachedHash(const AstNode* nodep) {
|
||||||
const HasherVisitor visitor{nodep};
|
const HasherVisitor visitor{nodep, HasherVisitor::Uncached{}};
|
||||||
return visitor.finalHash();
|
return visitor.finalHash();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -140,7 +140,10 @@ public:
|
||||||
getFTaskVertex(nodep)->cFuncp(cfuncp);
|
getFTaskVertex(nodep)->cFuncp(cfuncp);
|
||||||
}
|
}
|
||||||
void checkPurity(AstNodeFTask* nodep) { checkPurity(nodep, getFTaskVertex(nodep)); }
|
void checkPurity(AstNodeFTask* nodep) { checkPurity(nodep, getFTaskVertex(nodep)); }
|
||||||
|
|
||||||
|
private:
|
||||||
void checkPurity(AstNodeFTask* nodep, TaskBaseVertex* vxp) {
|
void checkPurity(AstNodeFTask* nodep, TaskBaseVertex* vxp) {
|
||||||
|
if (nodep->recursive()) return; // Impure, but no warning
|
||||||
if (!vxp->pure()) {
|
if (!vxp->pure()) {
|
||||||
nodep->v3warn(
|
nodep->v3warn(
|
||||||
IMPURE, "Unsupported: External variable referenced by non-inlined function/task: "
|
IMPURE, "Unsupported: External variable referenced by non-inlined function/task: "
|
||||||
|
|
@ -156,8 +159,6 @@ public:
|
||||||
checkPurity(nodep, static_cast<TaskBaseVertex*>(edgep->top()));
|
checkPurity(nodep, static_cast<TaskBaseVertex*>(edgep->top()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
TaskFTaskVertex* getFTaskVertex(AstNodeFTask* nodep) {
|
TaskFTaskVertex* getFTaskVertex(AstNodeFTask* nodep) {
|
||||||
if (!nodep->user4p()) nodep->user4p(new TaskFTaskVertex(&m_callGraph, nodep));
|
if (!nodep->user4p()) nodep->user4p(new TaskFTaskVertex(&m_callGraph, nodep));
|
||||||
return static_cast<TaskFTaskVertex*>(nodep->user4u().toGraphVertex());
|
return static_cast<TaskFTaskVertex*>(nodep->user4u().toGraphVertex());
|
||||||
|
|
@ -209,6 +210,7 @@ private:
|
||||||
m_curVxp = getFTaskVertex(nodep);
|
m_curVxp = getFTaskVertex(nodep);
|
||||||
if (nodep->dpiImport()) m_curVxp->noInline(true);
|
if (nodep->dpiImport()) m_curVxp->noInline(true);
|
||||||
if (nodep->classMethod()) m_curVxp->noInline(true); // Until V3Task supports it
|
if (nodep->classMethod()) m_curVxp->noInline(true); // Until V3Task supports it
|
||||||
|
if (nodep->recursive()) m_curVxp->noInline(true);
|
||||||
if (nodep->isConstructor()) {
|
if (nodep->isConstructor()) {
|
||||||
m_curVxp->noInline(true);
|
m_curVxp->noInline(true);
|
||||||
m_ctorp = nodep;
|
m_ctorp = nodep;
|
||||||
|
|
@ -726,6 +728,24 @@ private:
|
||||||
return new AstCStmt(portp->fileline(), stmt);
|
return new AstCStmt(portp->fileline(), stmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void unlinkAndClone(AstNodeFTask* funcp, AstNode* nodep, bool withNext) {
|
||||||
|
UASSERT_OBJ(nodep, funcp, "null in function object clone");
|
||||||
|
VNRelinker relinkHandle;
|
||||||
|
if (withNext) {
|
||||||
|
nodep->unlinkFrBackWithNext(&relinkHandle);
|
||||||
|
} else {
|
||||||
|
nodep->unlinkFrBack(&relinkHandle);
|
||||||
|
}
|
||||||
|
if (funcp->recursive()) {
|
||||||
|
// Recursive functions require the original argument list to
|
||||||
|
// still be live for linking purposes.
|
||||||
|
// The old function gets clone, so that node pointers are mostly
|
||||||
|
// retained through the V3Task transformations
|
||||||
|
AstNode* const newp = nodep->cloneTree(withNext);
|
||||||
|
relinkHandle.relink(newp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static AstNode* createAssignInternalToDpi(AstVar* portp, bool isPtr, const string& frSuffix,
|
static AstNode* createAssignInternalToDpi(AstVar* portp, bool isPtr, const string& frSuffix,
|
||||||
const string& toSuffix) {
|
const string& toSuffix) {
|
||||||
const string stmt = V3Task::assignInternalToDpi(portp, isPtr, frSuffix, toSuffix);
|
const string stmt = V3Task::assignInternalToDpi(portp, isPtr, frSuffix, toSuffix);
|
||||||
|
|
@ -1149,7 +1169,7 @@ private:
|
||||||
if (ftaskNoInline || nodep->dpiExport()) {
|
if (ftaskNoInline || nodep->dpiExport()) {
|
||||||
portp->funcReturn(false); // Converting return to 'outputs'
|
portp->funcReturn(false); // Converting return to 'outputs'
|
||||||
}
|
}
|
||||||
portp->unlinkFrBack();
|
unlinkAndClone(nodep, portp, false);
|
||||||
rtnvarp = portp;
|
rtnvarp = portp;
|
||||||
rtnvarp->funcLocal(true);
|
rtnvarp->funcLocal(true);
|
||||||
rtnvarp->name(rtnvarp->name()
|
rtnvarp->name(rtnvarp->name()
|
||||||
|
|
@ -1260,7 +1280,7 @@ private:
|
||||||
} else {
|
} else {
|
||||||
if (portp->isIO()) {
|
if (portp->isIO()) {
|
||||||
// Move it to new function
|
// Move it to new function
|
||||||
portp->unlinkFrBack();
|
unlinkAndClone(nodep, portp, false);
|
||||||
portp->funcLocal(true);
|
portp->funcLocal(true);
|
||||||
cfuncp->addArgsp(portp);
|
cfuncp->addArgsp(portp);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1282,10 +1302,21 @@ private:
|
||||||
if (rtnvarp) cfuncp->addArgsp(rtnvarp);
|
if (rtnvarp) cfuncp->addArgsp(rtnvarp);
|
||||||
|
|
||||||
// Move body
|
// Move body
|
||||||
AstNode* const bodysp = nodep->stmtsp();
|
AstNode* bodysp = nodep->stmtsp();
|
||||||
if (bodysp) {
|
if (bodysp) {
|
||||||
bodysp->unlinkFrBackWithNext();
|
unlinkAndClone(nodep, bodysp, true);
|
||||||
cfuncp->addStmtsp(bodysp);
|
AstBegin* const tempp = new AstBegin{nodep->fileline(), "[EditWrapper]", bodysp};
|
||||||
|
VL_DANGLING(bodysp);
|
||||||
|
// If we cloned due to recursion, now need to rip out the ports
|
||||||
|
// (that remained in place) then got cloned
|
||||||
|
for (AstNode *nextp, *stmtp = tempp->stmtsp(); stmtp; stmtp = nextp) {
|
||||||
|
nextp = stmtp->nextp();
|
||||||
|
if (AstVar* const portp = VN_CAST(stmtp, Var)) {
|
||||||
|
if (portp->isIO()) portp->unlinkFrBack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tempp->stmtsp()) cfuncp->addStmtsp(tempp->stmtsp()->unlinkFrBackWithNext());
|
||||||
|
VL_DO_DANGLING(tempp->deleteTree(), tempp);
|
||||||
}
|
}
|
||||||
if (nodep->dpiImport()) bodyDpiImportFunc(nodep, rtnvscp, cfuncp, dpiFuncp);
|
if (nodep->dpiImport()) bodyDpiImportFunc(nodep, rtnvscp, cfuncp, dpiFuncp);
|
||||||
|
|
||||||
|
|
@ -1455,7 +1486,7 @@ private:
|
||||||
if (visitp) iterateAndNextNull(visitp);
|
if (visitp) iterateAndNextNull(visitp);
|
||||||
}
|
}
|
||||||
virtual void visit(AstNodeFTask* nodep) override {
|
virtual void visit(AstNodeFTask* nodep) override {
|
||||||
UINFO(4, " Inline " << nodep << endl);
|
UINFO(4, " visitFTask " << nodep << endl);
|
||||||
VL_RESTORER(m_insMode);
|
VL_RESTORER(m_insMode);
|
||||||
VL_RESTORER(m_insStmtp);
|
VL_RESTORER(m_insStmtp);
|
||||||
m_insMode = IM_BEFORE;
|
m_insMode = IM_BEFORE;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue