mirror of
https://github.com/verilator/verilator.git
synced 2026-09-07 01:52:17 +02:00
Add verilator no_inline_task
git-svn-id: file://localhost/svn/verilator/trunk/verilator@816 77ca24e4-aefa-0310-84f0-b9a241c72d87
This commit is contained in:
+310
-102
@@ -39,6 +39,54 @@
|
||||
#include "V3Inst.h"
|
||||
#include "V3Ast.h"
|
||||
#include "V3EmitCBase.h"
|
||||
#include "V3Graph.h"
|
||||
|
||||
//######################################################################
|
||||
// Graph subclasses
|
||||
|
||||
class TaskBaseVertex : public V3GraphVertex {
|
||||
AstNode* m_impurep; // Node causing impure function w/ outside references
|
||||
bool m_noInline; // Marked with pragma
|
||||
public:
|
||||
TaskBaseVertex(V3Graph* graphp)
|
||||
: V3GraphVertex(graphp), m_impurep(NULL), m_noInline(false) {}
|
||||
virtual ~TaskBaseVertex() {}
|
||||
bool pure() const { return m_impurep==NULL; }
|
||||
AstNode* impureNode() const { return m_impurep; }
|
||||
void impure(AstNode* nodep) { m_impurep = nodep; }
|
||||
bool noInline() const { return m_noInline; }
|
||||
void noInline(bool flag) { m_noInline = flag; }
|
||||
};
|
||||
|
||||
class TaskFTaskVertex : public TaskBaseVertex {
|
||||
// Every task gets a vertex, and we link tasks together based on funcrefs.
|
||||
AstNodeFTask* m_nodep;
|
||||
public:
|
||||
TaskFTaskVertex(V3Graph* graphp, AstNodeFTask* nodep)
|
||||
: TaskBaseVertex(graphp), m_nodep(nodep) {}
|
||||
virtual ~TaskFTaskVertex() {}
|
||||
AstNodeFTask* nodep() const { return m_nodep; }
|
||||
virtual string name() const { return nodep()->name(); }
|
||||
virtual string dotColor() const { return pure() ? "black" : "red"; }
|
||||
};
|
||||
|
||||
class TaskCodeVertex : public TaskBaseVertex {
|
||||
// Top vertex for all calls not under another task
|
||||
public:
|
||||
TaskCodeVertex(V3Graph* graphp)
|
||||
: TaskBaseVertex(graphp) {}
|
||||
virtual ~TaskCodeVertex() {}
|
||||
virtual string name() const { return "*CODE*"; }
|
||||
virtual string dotColor() const { return "green"; }
|
||||
};
|
||||
|
||||
class TaskEdge : public V3GraphEdge {
|
||||
public:
|
||||
TaskEdge(V3Graph* graphp, TaskBaseVertex* fromp, TaskBaseVertex* top)
|
||||
: V3GraphEdge(graphp, fromp, top, 1, false) {}
|
||||
virtual ~TaskEdge() {}
|
||||
virtual string dotLabel() const { return "w"+cvtToStr(weight()); }
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
@@ -47,12 +95,17 @@ private:
|
||||
// NODE STATE
|
||||
// Output:
|
||||
// AstNodeFTask::user3p // AstScope* this FTask is under
|
||||
// AstNodeFTask::user4p // GraphFTaskVertex* this FTask is under
|
||||
// AstVar::user4p // GraphFTaskVertex* this variable is declared in
|
||||
|
||||
// TYPES
|
||||
typedef std::map<pair<AstScope*,AstVar*>,AstVarScope*> VarToScopeMap;
|
||||
// MEMBERS
|
||||
VarToScopeMap m_varToScopeMap; // Map for Var -> VarScope mappings
|
||||
AstAssignW* m_assignwp; // Current assignment
|
||||
V3Graph m_callGraph; // Task call graph
|
||||
TaskBaseVertex* m_curVxp; // Current vertex we're adding to
|
||||
|
||||
public:
|
||||
// METHODS
|
||||
AstScope* getScope(AstNodeFTask* nodep) {
|
||||
@@ -65,7 +118,30 @@ public:
|
||||
if (iter == m_varToScopeMap.end()) nodep->v3fatalSrc("No scope for var");
|
||||
return iter->second;
|
||||
}
|
||||
bool ftaskNoInline(AstNodeFTask* nodep) {
|
||||
return (getFTaskVertex(nodep)->noInline());
|
||||
}
|
||||
void checkPurity(AstNodeFTask* nodep) {
|
||||
checkPurity(nodep, getFTaskVertex(nodep));
|
||||
}
|
||||
void checkPurity(AstNodeFTask* nodep, TaskBaseVertex* vxp) {
|
||||
if (!vxp->pure()) {
|
||||
nodep->v3warn(IMPURE,"Unsupported: External variable referenced by non-inlined function/task: "<<nodep->prettyName());
|
||||
vxp->impureNode()->v3warn(IMPURE,"... Location of the external reference: "<<vxp->impureNode()->prettyName());
|
||||
}
|
||||
// And, we need to check all tasks this task calls
|
||||
for (V3GraphEdge* edgep = vxp->outBeginp(); edgep; edgep=edgep->outNextp()) {
|
||||
checkPurity(nodep, static_cast<TaskBaseVertex*>(edgep->top()));
|
||||
}
|
||||
}
|
||||
private:
|
||||
TaskBaseVertex* getFTaskVertex(AstNodeFTask* nodep) {
|
||||
if (!nodep->user4p()) {
|
||||
nodep->user4p(new TaskFTaskVertex(&m_callGraph, nodep));
|
||||
}
|
||||
return static_cast<TaskBaseVertex*>(nodep->user4p()->castGraphVertex());
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstScope* nodep, AstNUser*) {
|
||||
// Each FTask is unique per-scope, so AstNodeFTaskRefs do not need
|
||||
@@ -90,7 +166,7 @@ private:
|
||||
}
|
||||
virtual void visit(AstAssignW* nodep, AstNUser*) {
|
||||
m_assignwp = nodep;
|
||||
nodep->iterateChildren(*this); // May delete nodep.
|
||||
nodep->iterateChildren(*this); nodep=NULL; // May delete nodep.
|
||||
m_assignwp = NULL;
|
||||
}
|
||||
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
|
||||
@@ -104,6 +180,37 @@ private:
|
||||
AstNode* alwaysp = new AstAlways (m_assignwp->fileline(), NULL, assignp);
|
||||
m_assignwp->replaceWith(alwaysp); pushDeletep(m_assignwp); m_assignwp=NULL;
|
||||
}
|
||||
// We make multiple edges if a task is called multiple times from another task.
|
||||
new TaskEdge (&m_callGraph, m_curVxp, getFTaskVertex(nodep->taskp()));
|
||||
}
|
||||
virtual void visit(AstNodeFTask* nodep, AstNUser*) {
|
||||
UINFO(9," TASK "<<nodep<<endl);
|
||||
TaskBaseVertex* lastVxp = m_curVxp;
|
||||
m_curVxp = getFTaskVertex(nodep);
|
||||
nodep->iterateChildren(*this);
|
||||
m_curVxp = lastVxp;
|
||||
}
|
||||
virtual void visit(AstPragma* nodep, AstNUser*) {
|
||||
if (nodep->pragType() == AstPragmaType::NO_INLINE_TASK) {
|
||||
// Just mark for the next steps, and we're done with it.
|
||||
m_curVxp->noInline(true);
|
||||
nodep->unlinkFrBack()->deleteTree();
|
||||
}
|
||||
else {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstVar* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
nodep->user4p(m_curVxp); // Remember what task it's under
|
||||
}
|
||||
virtual void visit(AstVarRef* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
if (nodep->varp()->user4p() != m_curVxp) {
|
||||
if (m_curVxp->pure()) {
|
||||
m_curVxp->impure(nodep);
|
||||
}
|
||||
}
|
||||
}
|
||||
//--------------------
|
||||
// Default: Just iterate
|
||||
@@ -112,10 +219,16 @@ private:
|
||||
}
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
TaskStateVisitor(AstNode* nodep) {
|
||||
TaskStateVisitor(AstNetlist* nodep) {
|
||||
m_assignwp = NULL;
|
||||
m_curVxp = new TaskCodeVertex(&m_callGraph);
|
||||
AstNode::user3ClearTree();
|
||||
AstNode::user4ClearTree();
|
||||
//
|
||||
nodep->iterateAndNext(*this, NULL);
|
||||
//
|
||||
m_callGraph.removeRedundantEdgesSum(&TaskEdge::followAlwaysTrue);
|
||||
m_callGraph.dumpDotFilePrefixed("task_call");
|
||||
}
|
||||
virtual ~TaskStateVisitor() {}
|
||||
};
|
||||
@@ -165,6 +278,7 @@ private:
|
||||
// AstNodeFTask::user // True if its been expanded
|
||||
// Each funccall
|
||||
// AstVar::user2p // AstVarScope* to replace varref with
|
||||
// AstNodeFTask::user5p // AstCFunc* created for non-inlined tasks
|
||||
|
||||
// TYPES
|
||||
enum InsertMode {
|
||||
@@ -207,79 +321,81 @@ private:
|
||||
//
|
||||
// Create input variables
|
||||
AstNode::user2ClearTree();
|
||||
AstNode* pinp = refp->pinsp();
|
||||
AstNode* nextpinp = pinp;
|
||||
AstNode* nextstmtp;
|
||||
for (AstNode* stmtp = newbodysp; stmtp; pinp=nextpinp, stmtp=nextstmtp) {
|
||||
nextstmtp = stmtp->nextp();
|
||||
if (AstVar* portp = stmtp->castVar()) {
|
||||
portp->unlinkFrBack(); // Remove it from the clone (not original)
|
||||
pushDeletep(portp);
|
||||
if (portp->isIO()) {
|
||||
if (pinp==NULL) {
|
||||
refp->v3error("Too few arguments in function call");
|
||||
pinp = new AstConst(refp->fileline(), 0);
|
||||
m_modp->addStmtp(pinp); // For below unlink
|
||||
}
|
||||
UINFO(9, " Port "<<portp<<endl);
|
||||
UINFO(9, " pin "<<pinp<<endl);
|
||||
//
|
||||
nextpinp = pinp->nextp();
|
||||
pinp->unlinkFrBack(); // Relinked to assignment below
|
||||
//
|
||||
if (portp->isInout()) {
|
||||
if (AstVarRef* varrefp = pinp->castVarRef()) {
|
||||
// Connect to this exact variable
|
||||
AstVarScope* localVscp = varrefp->varScopep(); if (!localVscp) varrefp->v3fatalSrc("Null var scope");
|
||||
portp->user2p(localVscp);
|
||||
} else {
|
||||
pinp->v3error("Unsupported: Function/task input argument is not simple variable");
|
||||
{
|
||||
AstNode* pinp = refp->pinsp();
|
||||
AstNode* nextpinp = pinp;
|
||||
AstNode* nextstmtp;
|
||||
for (AstNode* stmtp = newbodysp; stmtp; pinp=nextpinp, stmtp=nextstmtp) {
|
||||
nextstmtp = stmtp->nextp();
|
||||
if (AstVar* portp = stmtp->castVar()) {
|
||||
portp->unlinkFrBack(); // Remove it from the clone (not original)
|
||||
pushDeletep(portp);
|
||||
if (portp->isIO()) {
|
||||
if (pinp==NULL) {
|
||||
refp->v3error("Too few arguments in function call");
|
||||
pinp = new AstConst(refp->fileline(), 0);
|
||||
m_modp->addStmtp(pinp); // For below unlink
|
||||
}
|
||||
UINFO(9, " Port "<<portp<<endl);
|
||||
UINFO(9, " pin "<<pinp<<endl);
|
||||
//
|
||||
nextpinp = pinp->nextp();
|
||||
pinp->unlinkFrBack(); // Relinked to assignment below
|
||||
//
|
||||
if (portp->isInout()) {
|
||||
if (AstVarRef* varrefp = pinp->castVarRef()) {
|
||||
// Connect to this exact variable
|
||||
AstVarScope* localVscp = varrefp->varScopep(); if (!localVscp) varrefp->v3fatalSrc("Null var scope");
|
||||
portp->user2p(localVscp);
|
||||
} else {
|
||||
pinp->v3error("Unsupported: Function/task input argument is not simple variable");
|
||||
}
|
||||
}
|
||||
else if (portp->isOutput() && outvscp) {
|
||||
refp->v3error("Outputs not allowed in function declarations");
|
||||
}
|
||||
else if (portp->isOutput()) {
|
||||
// Make output variables
|
||||
// Correct lvalue; we didn't know when we linked
|
||||
if (AstVarRef* varrefp = pinp->castVarRef()) {
|
||||
varrefp->lvalue(true);
|
||||
} else {
|
||||
pinp->v3error("Unsupported: Task output pin connected to non-variable");
|
||||
}
|
||||
// Even if it's referencing a varref, we still make a temporary
|
||||
// Else task(x,x,x) might produce incorrect results
|
||||
AstVarScope* outvscp = createVarScope (portp, namePrefix+"__"+portp->shortName());
|
||||
portp->user2p(outvscp);
|
||||
AstAssign* assp = new AstAssign (pinp->fileline(),
|
||||
pinp,
|
||||
new AstVarRef(outvscp->fileline(), outvscp, false));
|
||||
// Put assignment BEHIND of all other statements
|
||||
beginp->addNext(assp);
|
||||
}
|
||||
else if (portp->isInput()) {
|
||||
// Make input variable
|
||||
AstVarScope* inVscp = createVarScope (portp, namePrefix+"__"+portp->shortName());
|
||||
portp->user2p(inVscp);
|
||||
AstAssign* assp = new AstAssign (pinp->fileline(),
|
||||
new AstVarRef(inVscp->fileline(), inVscp, true),
|
||||
pinp);
|
||||
// Put assignment in FRONT of all other statements
|
||||
if (AstNode* afterp = beginp->nextp()) {
|
||||
afterp->unlinkFrBackWithNext();
|
||||
assp->addNext(afterp);
|
||||
}
|
||||
beginp->addNext(assp);
|
||||
}
|
||||
}
|
||||
else if (portp->isOutput() && outvscp) {
|
||||
refp->v3error("Outputs not allowed in function declarations");
|
||||
else { // Var is not I/O
|
||||
// Move it to a new localized variable
|
||||
AstVarScope* localVscp = createVarScope (portp, namePrefix+"__"+portp->shortName());
|
||||
portp->user2p(localVscp);
|
||||
}
|
||||
else if (portp->isOutput()) {
|
||||
// Make output variables
|
||||
// Correct lvalue; we didn't know when we linked
|
||||
if (AstVarRef* varrefp = pinp->castVarRef()) {
|
||||
varrefp->lvalue(true);
|
||||
} else {
|
||||
pinp->v3error("Unsupported: Task output pin connected to non-variable");
|
||||
}
|
||||
// Even if it's referencing a varref, we still make a temporary
|
||||
// Else task(x,x,x) might produce incorrect results
|
||||
AstVarScope* outvscp = createVarScope (portp, namePrefix+"__"+portp->shortName());
|
||||
portp->user2p(outvscp);
|
||||
AstAssign* assp = new AstAssign (pinp->fileline(),
|
||||
pinp,
|
||||
new AstVarRef(outvscp->fileline(), outvscp, false));
|
||||
// Put assignment BEHIND of all other statements
|
||||
beginp->addNext(assp);
|
||||
}
|
||||
else if (portp->isInput()) {
|
||||
// Make input variable
|
||||
AstVarScope* inVscp = createVarScope (portp, namePrefix+"__"+portp->shortName());
|
||||
portp->user2p(inVscp);
|
||||
AstAssign* assp = new AstAssign (pinp->fileline(),
|
||||
new AstVarRef(inVscp->fileline(), inVscp, true),
|
||||
pinp);
|
||||
// Put assignment in FRONT of all other statements
|
||||
if (AstNode* afterp = beginp->nextp()) {
|
||||
afterp->unlinkFrBackWithNext();
|
||||
assp->addNext(afterp);
|
||||
}
|
||||
beginp->addNext(assp);
|
||||
}
|
||||
}
|
||||
else { // Var is not I/O
|
||||
// Move it to a new localized variable
|
||||
AstVarScope* localVscp = createVarScope (portp, namePrefix+"__"+portp->shortName());
|
||||
portp->user2p(localVscp);
|
||||
}
|
||||
}
|
||||
if (pinp!=NULL) refp->v3error("Too many arguments in function call");
|
||||
}
|
||||
if (pinp!=NULL) refp->v3error("Too many arguments in function call");
|
||||
// Create function output variables
|
||||
if (outvscp) {
|
||||
//UINFO(0, "setflag on "<<funcp->fvarp()<<" to "<<outvscp<<endl);
|
||||
@@ -292,9 +408,71 @@ private:
|
||||
return beginp;
|
||||
}
|
||||
|
||||
AstNode* createNonInlinedFTask(AstNodeFTaskRef* refp, string namePrefix, AstVarScope* outvscp) {
|
||||
// outvscp is the variable for functions only, if NULL, it's a task
|
||||
if (!refp->taskp()) refp->v3fatalSrc("Unlinked?");
|
||||
AstCFunc* cfuncp = refp->taskp()->user5p()->castNode()->castCFunc();
|
||||
|
||||
AstCFunc* makeUserFunc(AstNodeFTask* nodep) {
|
||||
// Given a already cloned node, make a public C function.
|
||||
if (!cfuncp) refp->v3fatalSrc("No non-inline task associated with this task call?");
|
||||
//
|
||||
AstNode* beginp = new AstComment(refp->fileline(), (string)("Function: ")+refp->name());
|
||||
AstCCall* ccallp = new AstCCall(refp->fileline(), cfuncp, NULL);
|
||||
beginp->addNext(ccallp);
|
||||
// Convert complicated outputs to temp signals
|
||||
{
|
||||
AstNode* pinp = refp->pinsp();
|
||||
AstNode* nextpinp = pinp;
|
||||
AstNode* nextstmtp;
|
||||
for (AstNode* stmtp = refp->taskp()->stmtsp(); stmtp; pinp=nextpinp, stmtp=nextstmtp) {
|
||||
nextstmtp = stmtp->nextp();
|
||||
if (AstVar* portp = stmtp->castVar()) {
|
||||
if (portp->isIO()) {
|
||||
UINFO(9, " Port "<<portp<<endl);
|
||||
UINFO(9, " pin "<<pinp<<endl);
|
||||
//
|
||||
nextpinp = pinp->nextp();
|
||||
//
|
||||
if (portp->isInout()) {
|
||||
if (pinp->castVarRef()) {
|
||||
// Connect to this exact variable
|
||||
} else {
|
||||
pinp->v3error("Unsupported: Function/task input argument is not simple variable");
|
||||
}
|
||||
}
|
||||
else if (portp->isOutput()) {
|
||||
// Make output variables
|
||||
// Correct lvalue; we didn't know when we linked
|
||||
if (AstVarRef* varrefp = pinp->castVarRef()) {
|
||||
varrefp->lvalue(true);
|
||||
} else {
|
||||
pinp->v3error("Unsupported: Task output pin connected to non-variable");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pinp!=NULL) refp->v3error("Too many arguments in function call");
|
||||
}
|
||||
// First argument is symbol table, then output if a function
|
||||
ccallp->argTypes("vlSymsp");
|
||||
if (outvscp) {
|
||||
ccallp->addArgsp(new AstVarRef(refp->fileline(), outvscp, true));
|
||||
}
|
||||
// Create connections
|
||||
AstNode* nextpinp;
|
||||
for (AstNode* pinp = refp->pinsp(); pinp; pinp=nextpinp) {
|
||||
nextpinp = pinp->nextp();
|
||||
// Move pin to the CCall
|
||||
pinp->unlinkFrBack();
|
||||
ccallp->addArgsp(pinp);
|
||||
}
|
||||
if (debug()>=9) { beginp->dumpTree(cout,"-nitask: "); }
|
||||
return beginp;
|
||||
}
|
||||
|
||||
|
||||
AstCFunc* makeUserFunc(AstNodeFTask* nodep, bool forUser) {
|
||||
// Given a already cloned node, make a public C function, or a non-inline C function
|
||||
// Probably some of this work should be done later, but...
|
||||
// should the type of the function be bool/uint32/64 etc (based on lookup) or IData?
|
||||
AstNode::user2ClearTree();
|
||||
@@ -305,6 +483,7 @@ private:
|
||||
if (NULL!=(portp = nodep->castFunc()->fvarp()->castVar())) {
|
||||
if (!portp->isFuncReturn()) nodep->v3error("Not marked as function return var");
|
||||
if (portp->isWide()) nodep->v3error("Unsupported: Public functions with return > 64 bits wide. (Make it a output instead.)");
|
||||
if (!forUser) portp->funcReturn(false); // Converting return to 'outputs'
|
||||
portp->unlinkFrBack();
|
||||
rtnvarp = portp;
|
||||
rtnvarp->funcLocal(true);
|
||||
@@ -315,20 +494,28 @@ private:
|
||||
nodep->v3fatalSrc("function without function output variable");
|
||||
}
|
||||
}
|
||||
AstCFunc* funcp = new AstCFunc(nodep->fileline(), nodep->name(),
|
||||
m_scopep,
|
||||
(rtnvarp?rtnvarp->cType():""));
|
||||
if (rtnvarp) funcp->addArgsp(rtnvarp);
|
||||
funcp->dontCombine(true);
|
||||
funcp->funcPublic(true);
|
||||
funcp->entryPoint(true);
|
||||
funcp->isStatic(false);
|
||||
AstCFunc* cfuncp = new AstCFunc(nodep->fileline(),
|
||||
string(forUser?"":"__VnoInFunc_") + nodep->name(),
|
||||
m_scopep,
|
||||
((forUser && rtnvarp)?rtnvarp->cType():""));
|
||||
cfuncp->dontCombine(true);
|
||||
cfuncp->entryPoint(true);
|
||||
cfuncp->funcPublic(forUser);
|
||||
cfuncp->isStatic(!forUser);
|
||||
|
||||
// We need to get a pointer to all of our variables (may have eval'ed something else earlier)
|
||||
funcp->addInitsp(
|
||||
new AstCStmt(nodep->fileline(),
|
||||
" "+EmitCBaseVisitor::symClassVar()+" = this->__VlSymsp;\n"));
|
||||
funcp->addInitsp(new AstCStmt(nodep->fileline()," "+EmitCBaseVisitor::symTopAssign()+"\n"));
|
||||
if (forUser) {
|
||||
// We need to get a pointer to all of our variables (may have eval'ed something else earlier)
|
||||
cfuncp->addInitsp(
|
||||
new AstCStmt(nodep->fileline(),
|
||||
" "+EmitCBaseVisitor::symClassVar()+" = this->__VlSymsp;\n"));
|
||||
} else {
|
||||
// Need symbol table
|
||||
cfuncp->argTypes(EmitCBaseVisitor::symClassVar());
|
||||
}
|
||||
// Fake output variable if was a function
|
||||
if (rtnvarp) cfuncp->addArgsp(rtnvarp);
|
||||
|
||||
cfuncp->addInitsp(new AstCStmt(nodep->fileline()," "+EmitCBaseVisitor::symTopAssign()+"\n"));
|
||||
|
||||
// Create list of arguments and move to function
|
||||
for (AstNode* nextp, *stmtp = nodep->stmtsp(); stmtp; stmtp=nextp) {
|
||||
@@ -338,7 +525,7 @@ private:
|
||||
// Move it to new function
|
||||
portp->unlinkFrBack();
|
||||
portp->funcLocal(true);
|
||||
funcp->addArgsp(portp);
|
||||
cfuncp->addArgsp(portp);
|
||||
} else {
|
||||
// "Normal" variable, mark inside function
|
||||
portp->funcLocal(true);
|
||||
@@ -350,18 +537,19 @@ private:
|
||||
}
|
||||
// Move body
|
||||
AstNode* bodysp = nodep->stmtsp();
|
||||
if (bodysp) { bodysp->unlinkFrBackWithNext(); funcp->addStmtsp(bodysp); }
|
||||
if (bodysp) { bodysp->unlinkFrBackWithNext(); cfuncp->addStmtsp(bodysp); }
|
||||
// Return statement
|
||||
if (rtnvscp) {
|
||||
funcp->addFinalsp(new AstCReturn(rtnvscp->fileline(),
|
||||
new AstVarRef(rtnvscp->fileline(), rtnvscp, false)));
|
||||
if (rtnvscp && forUser) {
|
||||
cfuncp->addFinalsp(new AstCReturn(rtnvscp->fileline(),
|
||||
new AstVarRef(rtnvscp->fileline(), rtnvscp, false)));
|
||||
}
|
||||
// Replace variable refs
|
||||
TaskRelinkVisitor visit (funcp);
|
||||
TaskRelinkVisitor visit (cfuncp);
|
||||
// Delete rest of cloned task and return new func
|
||||
pushDeletep(nodep); nodep=NULL;
|
||||
if (debug()>=9) { funcp->dumpTree(cout,"-userFunc: "); }
|
||||
return funcp;
|
||||
if (debug()>=9 && forUser) { cfuncp->dumpTree(cout,"-userFunc: "); }
|
||||
if (debug()>=9 && !forUser) { cfuncp->dumpTree(cout,"-noInFunc: "); }
|
||||
return cfuncp;
|
||||
}
|
||||
|
||||
void iterateIntoFTask(AstNodeFTask* nodep) {
|
||||
@@ -421,7 +609,12 @@ private:
|
||||
if (debug()>=9) { nodep->dumpTree(cout,"-inltask:"); }
|
||||
// Create cloned statements
|
||||
string namePrefix = "__Vtask_"+nodep->taskp()->shortName()+"__"+cvtToStr(m_modNCalls++);
|
||||
AstNode* beginp = createInlinedFTask(nodep, namePrefix, NULL);
|
||||
AstNode* beginp;
|
||||
if (m_statep->ftaskNoInline(nodep->taskp())) {
|
||||
beginp = createNonInlinedFTask(nodep, namePrefix, NULL);
|
||||
} else {
|
||||
beginp = createInlinedFTask(nodep, namePrefix, NULL);
|
||||
}
|
||||
// Replace the ref
|
||||
nodep->replaceWith(beginp);
|
||||
nodep->deleteTree(); nodep=NULL;
|
||||
@@ -442,7 +635,13 @@ private:
|
||||
if (debug()>=9) { nodep->taskp()->dumpTree(cout,"-oldfunc:"); }
|
||||
if (!nodep->taskp()) nodep->v3fatalSrc("Unlinked?");
|
||||
|
||||
AstNode* beginp = createInlinedFTask(nodep, namePrefix, outvscp);
|
||||
AstNode* beginp;
|
||||
if (m_statep->ftaskNoInline(nodep->taskp())) {
|
||||
// This may share VarScope's with a public task, if any. Yuk.
|
||||
beginp = createNonInlinedFTask(nodep, namePrefix, outvscp);
|
||||
} else {
|
||||
beginp = createInlinedFTask(nodep, namePrefix, outvscp);
|
||||
}
|
||||
// Replace the ref
|
||||
AstVarRef* outrefp = new AstVarRef (nodep->fileline(), outvscp, false);
|
||||
nodep->replaceWith(outrefp);
|
||||
@@ -450,27 +649,34 @@ private:
|
||||
insertBeforeStmt(nodep, beginp);
|
||||
// Cleanup
|
||||
nodep->deleteTree(); nodep=NULL;
|
||||
UINFO(4," Done.\n");
|
||||
UINFO(4," Func REF Done.\n");
|
||||
}
|
||||
virtual void visit(AstNodeFTask* nodep, AstNUser*) {
|
||||
UINFO(4," Inline "<<nodep<<endl);
|
||||
InsertMode prevInsMode = m_insMode;
|
||||
AstNode* prevInsStmtp = m_insStmtp;
|
||||
m_insMode = IM_BEFORE;
|
||||
m_insStmtp = nodep->stmtsp(); // Might be null if no statements, but we won't use it
|
||||
if (!nodep->user()) {
|
||||
// Expand functions in it & Mark for later delete
|
||||
// Expand functions in it
|
||||
nodep->user(true);
|
||||
if (!nodep->taskPublic()) {
|
||||
nodep->unlinkFrBack();
|
||||
} else {
|
||||
if (nodep->taskPublic()) {
|
||||
// Clone it first, because we may have later FTaskRef's that still need
|
||||
// the original version.
|
||||
AstNodeFTask* clonedFuncp = nodep->cloneTree(false)->castNodeFTask();
|
||||
AstCFunc* cfuncp = makeUserFunc(clonedFuncp);
|
||||
// Replace it
|
||||
nodep->replaceWith(cfuncp);
|
||||
AstCFunc* cfuncp = makeUserFunc(clonedFuncp, true);
|
||||
nodep->addNextHere(cfuncp);
|
||||
iterateIntoFTask(clonedFuncp); // Do the clone too
|
||||
}
|
||||
if (m_statep->ftaskNoInline(nodep)) {
|
||||
m_statep->checkPurity(nodep);
|
||||
AstNodeFTask* clonedFuncp = nodep->cloneTree(false)->castNodeFTask();
|
||||
AstCFunc* cfuncp = makeUserFunc(clonedFuncp, false);
|
||||
nodep->user5p(cfuncp);
|
||||
nodep->addNextHere(cfuncp);
|
||||
iterateIntoFTask(clonedFuncp); // Do the clone too
|
||||
}
|
||||
|
||||
// Any variables inside the function still have varscopes pointing to them.
|
||||
// We're going to delete the vars, so delete the varscopes.
|
||||
if (nodep->castFunc()) {
|
||||
@@ -489,6 +695,7 @@ private:
|
||||
}
|
||||
}
|
||||
// Just push, as other references to func may remain until visitor exits
|
||||
nodep->unlinkFrBack();
|
||||
pushDeletep(nodep); nodep=NULL;
|
||||
}
|
||||
m_insMode = prevInsMode;
|
||||
@@ -532,6 +739,7 @@ public:
|
||||
m_scopep = NULL;
|
||||
m_insStmtp = NULL;
|
||||
AstNode::userClearTree();
|
||||
AstNode::user5ClearTree();
|
||||
nodep->accept(*this);
|
||||
}
|
||||
virtual ~TaskVisitor() {}
|
||||
|
||||
Reference in New Issue
Block a user