Internals: V3Task: refactor common code to connectPort. No functional change intended (#4488)
Signed-off-by: Kamil Rakoczy <krakoczy@antmicro.com>
This commit is contained in:
parent
3dde57d539
commit
0d67caff77
207
src/V3Task.cpp
207
src/V3Task.cpp
|
|
@ -412,6 +412,84 @@ private:
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void connectPort(AstVar* portp, AstArg* argp, const string& namePrefix, AstNode* beginp,
|
||||||
|
bool inlineTask) {
|
||||||
|
AstNodeExpr* const pinp = argp->exprp();
|
||||||
|
if (inlineTask) {
|
||||||
|
portp->unlinkFrBack();
|
||||||
|
pushDeletep(portp); // Remove it from the clone (not original)
|
||||||
|
}
|
||||||
|
if (!pinp) {
|
||||||
|
// Too few arguments in function call
|
||||||
|
} else {
|
||||||
|
UINFO(9, " Port " << portp << endl);
|
||||||
|
UINFO(9, " pin " << pinp << endl);
|
||||||
|
if (inlineTask) {
|
||||||
|
pinp->unlinkFrBack(); // Relinked to assignment below
|
||||||
|
VL_DO_DANGLING(argp->unlinkFrBack()->deleteTree(), argp); // Args no longer needed
|
||||||
|
}
|
||||||
|
if (portp->isWritable() && VN_IS(pinp, Const)) {
|
||||||
|
pinp->v3error("Function/task " + portp->direction().prettyName() // e.g. "output"
|
||||||
|
+ " connected to constant instead of variable: "
|
||||||
|
+ portp->prettyNameQ());
|
||||||
|
} else if (portp->isInoutish()) {
|
||||||
|
// Correct lvalue; see comments below
|
||||||
|
V3LinkLValue::linkLValueSet(pinp);
|
||||||
|
|
||||||
|
if (AstVarRef* const varrefp = VN_CAST(pinp, VarRef)) {
|
||||||
|
// Connect to this exact variable
|
||||||
|
if (inlineTask) {
|
||||||
|
AstVarScope* const localVscp = varrefp->varScopep();
|
||||||
|
UASSERT_OBJ(localVscp, varrefp, "Null var scope");
|
||||||
|
portp->user2p(localVscp);
|
||||||
|
pushDeletep(pinp);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pinp->v3warn(
|
||||||
|
E_TASKNSVAR,
|
||||||
|
"Unsupported: Function/task input argument is not simple variable");
|
||||||
|
}
|
||||||
|
} else if (portp->isWritable()) {
|
||||||
|
// Make output variables
|
||||||
|
// Correct lvalue; we didn't know when we linked
|
||||||
|
// This is slightly scary; are we sure no decisions were made
|
||||||
|
// before here based on this not being a lvalue?
|
||||||
|
// Doesn't seem so; V3Unknown uses it earlier, but works ok.
|
||||||
|
V3LinkLValue::linkLValueSet(pinp);
|
||||||
|
// Even if it's referencing a varref, we still make a temporary
|
||||||
|
// Else task(x,x,x) might produce incorrect results
|
||||||
|
AstVarScope* const newvscp
|
||||||
|
= createVarScope(portp, namePrefix + "__" + portp->shortName());
|
||||||
|
portp->user2p(newvscp);
|
||||||
|
if (!inlineTask)
|
||||||
|
pinp->replaceWith(new AstVarRef{newvscp->fileline(), newvscp, VAccess::WRITE});
|
||||||
|
AstAssign* const assp
|
||||||
|
= new AstAssign{pinp->fileline(), pinp,
|
||||||
|
new AstVarRef{newvscp->fileline(), newvscp, VAccess::READ}};
|
||||||
|
assp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ,
|
||||||
|
true); // Ok if in <= block
|
||||||
|
// Put assignment BEHIND of all other statements
|
||||||
|
beginp->addNext(assp);
|
||||||
|
} else if (inlineTask && portp->isNonOutput()) {
|
||||||
|
// Make input variable
|
||||||
|
AstVarScope* const inVscp
|
||||||
|
= createVarScope(portp, namePrefix + "__" + portp->shortName());
|
||||||
|
portp->user2p(inVscp);
|
||||||
|
AstAssign* const assp = new AstAssign{
|
||||||
|
pinp->fileline(), new AstVarRef{inVscp->fileline(), inVscp, VAccess::WRITE},
|
||||||
|
pinp};
|
||||||
|
assp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ,
|
||||||
|
true); // Ok if in <= block
|
||||||
|
// Put assignment in FRONT of all other statements
|
||||||
|
if (AstNode* const afterp = beginp->nextp()) {
|
||||||
|
afterp->unlinkFrBackWithNext();
|
||||||
|
AstNode::addNext<AstNode, AstNode>(assp, afterp);
|
||||||
|
}
|
||||||
|
beginp->addNext(assp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
AstNode* createInlinedFTask(AstNodeFTaskRef* refp, const string& namePrefix,
|
AstNode* createInlinedFTask(AstNodeFTaskRef* refp, const string& namePrefix,
|
||||||
AstVarScope* outvscp) {
|
AstVarScope* outvscp) {
|
||||||
// outvscp is the variable for functions only, if nullptr, it's a task
|
// outvscp is the variable for functions only, if nullptr, it's a task
|
||||||
|
|
@ -425,77 +503,12 @@ private:
|
||||||
//
|
//
|
||||||
// Create input variables
|
// Create input variables
|
||||||
AstNode::user2ClearTree();
|
AstNode::user2ClearTree();
|
||||||
const V3TaskConnects tconnects = V3Task::taskConnects(refp, beginp);
|
{
|
||||||
for (const auto& itr : tconnects) {
|
const V3TaskConnects tconnects = V3Task::taskConnects(refp, beginp);
|
||||||
AstVar* const portp = itr.first;
|
for (const auto& itr : tconnects) {
|
||||||
AstArg* const argp = itr.second;
|
AstVar* const portp = itr.first;
|
||||||
AstNodeExpr* const pinp = argp->exprp();
|
AstArg* const argp = itr.second;
|
||||||
portp->unlinkFrBack();
|
connectPort(portp, argp, namePrefix, beginp, true);
|
||||||
pushDeletep(portp); // Remove it from the clone (not original)
|
|
||||||
if (!pinp) {
|
|
||||||
// Too few arguments in function call
|
|
||||||
} else {
|
|
||||||
UINFO(9, " Port " << portp << endl);
|
|
||||||
UINFO(9, " pin " << pinp << endl);
|
|
||||||
pinp->unlinkFrBack(); // Relinked to assignment below
|
|
||||||
VL_DO_DANGLING(argp->unlinkFrBack()->deleteTree(), argp); // Args no longer needed
|
|
||||||
//
|
|
||||||
if (portp->isWritable() && VN_IS(pinp, Const)) {
|
|
||||||
pinp->v3error(
|
|
||||||
"Function/task " + portp->direction().prettyName() // e.g. "output"
|
|
||||||
+ " connected to constant instead of variable: " + portp->prettyNameQ());
|
|
||||||
} else if (portp->isInoutish()) {
|
|
||||||
// Correct lvalue; see comments below
|
|
||||||
V3LinkLValue::linkLValueSet(pinp);
|
|
||||||
|
|
||||||
if (AstVarRef* const varrefp = VN_CAST(pinp, VarRef)) {
|
|
||||||
// Connect to this exact variable
|
|
||||||
AstVarScope* const localVscp = varrefp->varScopep();
|
|
||||||
UASSERT_OBJ(localVscp, varrefp, "Null var scope");
|
|
||||||
portp->user2p(localVscp);
|
|
||||||
pushDeletep(pinp);
|
|
||||||
} else {
|
|
||||||
pinp->v3warn(
|
|
||||||
E_TASKNSVAR,
|
|
||||||
"Unsupported: Function/task input argument is not simple variable");
|
|
||||||
}
|
|
||||||
} else if (portp->isWritable()) {
|
|
||||||
// Make output variables
|
|
||||||
// Correct lvalue; we didn't know when we linked
|
|
||||||
// This is slightly scary; are we sure no decisions were made
|
|
||||||
// before here based on this not being a lvalue?
|
|
||||||
// Doesn't seem so; V3Unknown uses it earlier, but works ok.
|
|
||||||
V3LinkLValue::linkLValueSet(pinp);
|
|
||||||
|
|
||||||
// Even if it's referencing a varref, we still make a temporary
|
|
||||||
// Else task(x,x,x) might produce incorrect results
|
|
||||||
AstVarScope* const tempvscp
|
|
||||||
= createVarScope(portp, namePrefix + "__" + portp->shortName());
|
|
||||||
portp->user2p(tempvscp);
|
|
||||||
AstAssign* const assp = new AstAssign{
|
|
||||||
pinp->fileline(), pinp,
|
|
||||||
new AstVarRef{tempvscp->fileline(), tempvscp, VAccess::READ}};
|
|
||||||
assp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ,
|
|
||||||
true); // Ok if in <= block
|
|
||||||
// Put assignment BEHIND of all other statements
|
|
||||||
beginp->addNext(assp);
|
|
||||||
} else if (portp->isNonOutput()) {
|
|
||||||
// Make input variable
|
|
||||||
AstVarScope* const inVscp
|
|
||||||
= createVarScope(portp, namePrefix + "__" + portp->shortName());
|
|
||||||
portp->user2p(inVscp);
|
|
||||||
AstAssign* const assp = new AstAssign{
|
|
||||||
pinp->fileline(),
|
|
||||||
new AstVarRef{inVscp->fileline(), inVscp, VAccess::WRITE}, pinp};
|
|
||||||
assp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ,
|
|
||||||
true); // Ok if in <= block
|
|
||||||
// Put assignment in FRONT of all other statements
|
|
||||||
if (AstNode* const afterp = beginp->nextp()) {
|
|
||||||
afterp->unlinkFrBackWithNext();
|
|
||||||
AstNode::addNext<AstNode, AstNode>(assp, afterp);
|
|
||||||
}
|
|
||||||
beginp->addNext(assp);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
UASSERT_OBJ(!refp->pinsp(), refp, "Pin wasn't removed by above loop");
|
UASSERT_OBJ(!refp->pinsp(), refp, "Pin wasn't removed by above loop");
|
||||||
|
|
@ -555,52 +568,12 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert complicated outputs to temp signals
|
// Convert complicated outputs to temp signals
|
||||||
const V3TaskConnects tconnects = V3Task::taskConnects(refp, refp->taskp()->stmtsp());
|
{
|
||||||
for (const auto& itr : tconnects) {
|
const V3TaskConnects tconnects = V3Task::taskConnects(refp, refp->taskp()->stmtsp());
|
||||||
AstVar* const portp = itr.first;
|
for (const auto& itr : tconnects) {
|
||||||
AstNodeExpr* const pinp = itr.second->exprp();
|
AstVar* const portp = itr.first;
|
||||||
if (!pinp) {
|
AstArg* const argp = itr.second;
|
||||||
// Too few arguments in function call
|
connectPort(portp, argp, namePrefix, beginp, false);
|
||||||
} else {
|
|
||||||
UINFO(9, " Port " << portp << endl);
|
|
||||||
UINFO(9, " pin " << pinp << endl);
|
|
||||||
if (portp->isWritable() && VN_IS(pinp, Const)) {
|
|
||||||
pinp->v3error(
|
|
||||||
"Function/task " + portp->direction().prettyName() // e.g. "output"
|
|
||||||
+ " connected to constant instead of variable: " + portp->prettyNameQ());
|
|
||||||
} else if (portp->isInoutish()) {
|
|
||||||
// Correct lvalue; see comments below
|
|
||||||
V3LinkLValue::linkLValueSet(pinp);
|
|
||||||
|
|
||||||
if (VN_IS(pinp, VarRef)) {
|
|
||||||
// Connect to this exact variable
|
|
||||||
} else {
|
|
||||||
pinp->v3warn(
|
|
||||||
E_TASKNSVAR,
|
|
||||||
"Unsupported: Function/task input argument is not simple variable");
|
|
||||||
}
|
|
||||||
} else if (portp->isWritable()) {
|
|
||||||
// Make output variables
|
|
||||||
// Correct lvalue; we didn't know when we linked
|
|
||||||
// This is slightly scary; are we sure no decisions were made
|
|
||||||
// before here based on this not being a lvalue?
|
|
||||||
// Seems correct assumption; V3Unknown uses it earlier, but works ok.
|
|
||||||
V3LinkLValue::linkLValueSet(pinp);
|
|
||||||
|
|
||||||
// Even if it's referencing a varref, we still make a temporary
|
|
||||||
// Else task(x,x,x) might produce incorrect results
|
|
||||||
AstVarScope* const newvscp
|
|
||||||
= createVarScope(portp, namePrefix + "__" + portp->shortName());
|
|
||||||
portp->user2p(newvscp);
|
|
||||||
pinp->replaceWith(new AstVarRef{newvscp->fileline(), newvscp, VAccess::WRITE});
|
|
||||||
AstAssign* const assp = new AstAssign{
|
|
||||||
pinp->fileline(), pinp,
|
|
||||||
new AstVarRef{newvscp->fileline(), newvscp, VAccess::READ}};
|
|
||||||
assp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ,
|
|
||||||
true); // Ok if in <= block
|
|
||||||
// Put assignment BEHIND of all other statements
|
|
||||||
beginp->addNext(assp);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// First argument is symbol table, then output if a function
|
// First argument is symbol table, then output if a function
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue