Internals: clang-format and refactor taskref pin handling.

This commit is contained in:
Wilson Snyder 2020-04-12 08:26:14 -04:00
parent ea3acc2d3a
commit 1e2d73fc80
2 changed files with 75 additions and 56 deletions

View File

@ -1327,7 +1327,7 @@ V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp)
// Missing pin/expr? We return (pinvar, NULL)
// Extra pin/expr? We clean it up
typedef std::map<string,int> NameToIndex;
typedef std::map<string, int> NameToIndex;
NameToIndex nameToIndex;
V3TaskConnects tconnects;
UASSERT_OBJ(nodep->taskp(), nodep, "unlinked");
@ -1335,16 +1335,18 @@ V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp)
// Find ports
int tpinnum = 0;
AstVar* sformatp = NULL;
for (AstNode* stmtp = taskStmtsp; stmtp; stmtp=stmtp->nextp()) {
for (AstNode* stmtp = taskStmtsp; stmtp; stmtp = stmtp->nextp()) {
if (AstVar* portp = VN_CAST(stmtp, Var)) {
if (portp->isIO()) {
tconnects.push_back(make_pair(portp, static_cast<AstArg*>(NULL)));
nameToIndex.insert(make_pair(portp->name(), tpinnum)); // For name based connections
nameToIndex.insert(
make_pair(portp->name(), tpinnum)); // For name based connections
tpinnum++;
if (portp->attrSFormat()) {
sformatp = portp;
} else if (sformatp) {
nodep->v3error("/*verilator sformat*/ can only be applied to last argument of a function");
portp->v3error("/*verilator sformat*/ can only be applied to last argument of "
"a function");
}
}
}
@ -1353,7 +1355,7 @@ V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp)
// Find pins
int ppinnum = 0;
bool reorganize = false;
for (AstNode* nextp, *pinp = nodep->pinsp(); pinp; pinp=nextp) {
for (AstNode *nextp, *pinp = nodep->pinsp(); pinp; pinp = nextp) {
nextp = pinp->nextp();
AstArg* argp = VN_CAST(pinp, Arg);
UASSERT_OBJ(argp, pinp, "Non-arg under ftask reference");
@ -1361,14 +1363,15 @@ V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp)
// By name
NameToIndex::iterator it = nameToIndex.find(argp->name());
if (it == nameToIndex.end()) {
pinp->v3error("No such argument "<<argp->prettyNameQ()
<<" in function call to "<<nodep->taskp()->prettyTypeName());
pinp->v3error("No such argument " << argp->prettyNameQ() << " in function call to "
<< nodep->taskp()->prettyTypeName());
// We'll just delete it; seems less error prone than making a false argument
VL_DO_DANGLING(pinp->unlinkFrBack()->deleteTree(), pinp);
} else {
if (tconnects[it->second].second) {
pinp->v3error("Duplicate argument "<<argp->prettyNameQ()
<<" in function call to "<<nodep->taskp()->prettyTypeName());
pinp->v3error("Duplicate argument " << argp->prettyNameQ()
<< " in function call to "
<< nodep->taskp()->prettyTypeName());
}
argp->name(""); // Can forget name as will add back in pin order
tconnects[it->second].second = argp;
@ -1382,7 +1385,7 @@ V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp)
tpinnum++;
} else {
pinp->v3error("Too many arguments in function call to "
<<nodep->taskp()->prettyTypeName());
<< nodep->taskp()->prettyTypeName());
// We'll just delete it; seems less error prone than making a false argument
VL_DO_DANGLING(pinp->unlinkFrBack()->deleteTree(), pinp);
}
@ -1394,13 +1397,14 @@ V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp)
}
// Connect missing ones
for (int i=0; i<tpinnum; ++i) {
for (int i = 0; i < tpinnum; ++i) {
AstVar* portp = tconnects[i].first;
if (!tconnects[i].second || !tconnects[i].second->exprp()) {
AstNode* newvaluep = NULL;
if (!portp->valuep()) {
nodep->v3error("Missing argument on non-defaulted argument "<<portp->prettyNameQ()
<<" in function call to "<<nodep->taskp()->prettyTypeName());
nodep->v3error("Missing argument on non-defaulted argument "
<< portp->prettyNameQ() << " in function call to "
<< nodep->taskp()->prettyTypeName());
newvaluep = new AstConst(nodep->fileline(), AstConst::Unsized32(), 0);
} else if (!VN_IS(portp->valuep(), Const)) {
// The default value for this port might be a constant
@ -1412,11 +1416,10 @@ V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp)
// call, or something else that only makes sense in the
// domain of the function, not the callee.
nodep->v3error("Unsupported: Non-constant default value in missing argument "
<<portp->prettyNameQ()
<<" in function call to "<<nodep->taskp()->prettyTypeName());
<< portp->prettyNameQ() << " in function call to "
<< nodep->taskp()->prettyTypeName());
newvaluep = new AstConst(nodep->fileline(), AstConst::Unsized32(), 0);
}
else {
} else {
newvaluep = newvaluep->cloneTree(true);
}
} else {
@ -1424,7 +1427,7 @@ V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp)
}
// To avoid problems with callee needing to know to deleteTree
// or not, we make this into a pin
UINFO(9,"Default pin for "<<portp<<endl);
UINFO(9, "Default pin for " << portp << endl);
AstArg* newp = new AstArg(nodep->fileline(), portp->name(), newvaluep);
if (tconnects[i].second) { // Have a "NULL" pin already defined for it
VL_DO_CLEAR(tconnects[i].second->unlinkFrBack()->deleteTree(),
@ -1433,25 +1436,30 @@ V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp)
tconnects[i].second = newp;
reorganize = true;
}
if (tconnects[i].second) { UINFO(9,"Connect "<<portp
<<" -> "<<tconnects[i].second<<endl); }
else { UINFO(9,"Connect "<<portp<<" -> NONE"<<endl); }
if (tconnects[i].second) {
UINFO(9, "Connect " << portp << " -> " << tconnects[i].second << endl);
} else {
UINFO(9, "Connect " << portp << " -> NONE" << endl);
}
}
if (reorganize) {
// To simplify downstream, put argument list back into pure pinnumber ordering
while (nodep->pinsp()) nodep->pinsp()->unlinkFrBack(); // Must unlink each pin, not all pins linked together as one list
for (int i=0; i<tpinnum; ++i) {
while (nodep->pinsp()) {
// Must unlink each pin, not all pins linked together as one list
nodep->pinsp()->unlinkFrBack();
}
for (int i = 0; i < tpinnum; ++i) {
AstArg* argp = tconnects[i].second;
UASSERT_OBJ(argp, nodep, "Lost argument in func conversion");
nodep->addPinsp(argp);
}
}
if (debug()>=9) {
if (debug() >= 9) {
nodep->dumpTree(cout, "-ftref-out: ");
for (int i=0; i<tpinnum; ++i) {
UINFO(0," pin "<<i<<" conn="<<cvtToHex(tconnects[i].second)<<endl);
for (int i = 0; i < tpinnum; ++i) {
UINFO(0, " pin " << i << " conn=" << cvtToHex(tconnects[i].second) << endl);
}
}
return tconnects;

View File

@ -3446,19 +3446,19 @@ private:
nodep->dtypeFrom(nodep->taskp());
//if (debug()) nodep->dumpTree(cout, " FuncOut: ");
}
virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE {
void processFTaskRefArgs(AstNodeFTaskRef* nodep) {
// For arguments, is assignment-like context; see IEEE rules in AstNodeAssign
// Function hasn't been widthed, so make it so.
UINFO(5, " FTASKREF "<<nodep<<endl);
UINFO(5, " FTASKREF " << nodep << endl);
UASSERT_OBJ(nodep->taskp(), nodep, "Unlinked");
if (nodep->didWidth()) return;
userIterate(nodep->taskp(), NULL);
//
// And do the arguments to the task/function too
do {
reloop:
reloop:
V3TaskConnects tconnects = V3Task::taskConnects(nodep, nodep->taskp()->stmtsp());
for (V3TaskConnects::iterator it=tconnects.begin(); it!=tconnects.end(); ++it) {
for (V3TaskConnects::iterator it = tconnects.begin(); it != tconnects.end(); ++it) {
AstVar* portp = it->first;
AstArg* argp = it->second;
AstNode* pinp = argp->exprp();
@ -3467,18 +3467,23 @@ private:
// pointer, so need to iterate separately later
if (portp->attrSFormat()
&& (!VN_IS(pinp, SFormatF) || pinp->nextp())) { // Not already done
UINFO(4," sformat via metacomment: "<<nodep<<endl);
UINFO(4, " sformat via metacomment: " << nodep << endl);
AstNRelinker handle;
argp->unlinkFrBackWithNext(&handle); // Format + additional args, if any
AstNode* argsp = NULL;
while (AstArg* nextargp = VN_CAST(argp->nextp(), Arg)) {
argsp = AstNode::addNext(
argsp, nextargp->exprp()->unlinkFrBackWithNext()); // Expression goes to SFormatF
argsp, nextargp->exprp()
->unlinkFrBackWithNext()); // Expression goes to SFormatF
nextargp->unlinkFrBack()->deleteTree(); // Remove the call's Arg wrapper
}
string format;
if (VN_IS(pinp, Const)) format = VN_CAST(pinp, Const)->num().toString();
else pinp->v3error("Format to $display-like function must have constant format string");
if (VN_IS(pinp, Const)) {
format = VN_CAST(pinp, Const)->num().toString();
} else {
pinp->v3error(
"Format to $display-like function must have constant format string");
}
VL_DO_DANGLING(pushDeletep(argp), argp);
AstSFormatF* newp = new AstSFormatF(nodep->fileline(), format, false, argsp);
if (!newp->scopeNamep() && newp->formatScopeTracking()) {
@ -3487,13 +3492,15 @@ private:
handle.relink(new AstArg(newp->fileline(), "", newp));
// Connection list is now incorrect (has extra args in it).
goto reloop; // so exit early; next loop will correct it
}
else if (portp->basicp() && portp->basicp()->keyword()==AstBasicDTypeKwd::STRING
} //
else if (portp->basicp()
&& portp->basicp()->keyword() == AstBasicDTypeKwd::STRING
&& !VN_IS(pinp, CvtPackString)
&& !VN_IS(pinp, SFormatF) // Already generates a string
&& !(VN_IS(pinp, VarRef)
&& VN_CAST(pinp, VarRef)->varp()->basicp()->keyword()==AstBasicDTypeKwd::STRING)) {
UINFO(4," Add CvtPackString: "<<pinp<<endl);
&& VN_CAST(pinp, VarRef)->varp()->basicp()->keyword()
== AstBasicDTypeKwd::STRING)) {
UINFO(4, " Add CvtPackString: " << pinp << endl);
AstNRelinker handle;
pinp->unlinkFrBack(&handle); // No next, that's the next pin
AstNode* newp = new AstCvtPackString(pinp->fileline(), pinp);
@ -3507,21 +3514,19 @@ private:
// Stage 2
{
V3TaskConnects tconnects = V3Task::taskConnects(nodep, nodep->taskp()->stmtsp());
for (V3TaskConnects::iterator it=tconnects.begin(); it!=tconnects.end(); ++it) {
for (V3TaskConnects::iterator it = tconnects.begin(); it != tconnects.end(); ++it) {
AstVar* portp = it->first;
AstArg* argp = it->second;
AstNode* pinp = argp->exprp();
if (!pinp) continue; // Argument error we'll find later
// Change data types based on above accept completion
if (portp->isDouble()) {
VL_DO_DANGLING(spliceCvtD(pinp), pinp);
}
if (portp->isDouble()) VL_DO_DANGLING(spliceCvtD(pinp), pinp);
}
}
// Stage 3
{
V3TaskConnects tconnects = V3Task::taskConnects(nodep, nodep->taskp()->stmtsp());
for (V3TaskConnects::iterator it=tconnects.begin(); it!=tconnects.end(); ++it) {
for (V3TaskConnects::iterator it = tconnects.begin(); it != tconnects.end(); ++it) {
AstVar* portp = it->first;
AstArg* argp = it->second;
AstNode* pinp = argp->exprp();
@ -3532,13 +3537,11 @@ private:
}
}
// Cleanup any open arrays
if (markHasOpenArray(nodep->taskp())) {
makeOpenArrayShell(nodep);
}
if (markHasOpenArray(nodep->taskp())) makeOpenArrayShell(nodep);
// Stage 4
{
V3TaskConnects tconnects = V3Task::taskConnects(nodep, nodep->taskp()->stmtsp());
for (V3TaskConnects::iterator it=tconnects.begin(); it!=tconnects.end(); ++it) {
for (V3TaskConnects::iterator it = tconnects.begin(); it != tconnects.end(); ++it) {
AstVar* portp = it->first;
AstArg* argp = it->second;
AstNode* pinp = argp->exprp();
@ -3546,16 +3549,14 @@ private:
if (portp->direction() == VDirection::REF
&& !similarDTypeRecurse(portp->dtypep(), pinp->dtypep())) {
pinp->v3error("Ref argument requires matching types;"
<<" port "<<portp->prettyNameQ()
<<" requires "<<portp->prettyTypeName()
<<" but connection is "<<pinp->prettyTypeName()<<".");
} else if (portp->isWritable()
&& pinp->width() != portp->width()) {
<< " port " << portp->prettyNameQ() << " requires "
<< portp->prettyTypeName() << " but connection is "
<< pinp->prettyTypeName() << ".");
} else if (portp->isWritable() && pinp->width() != portp->width()) {
pinp->v3error("Unsupported: Function output argument "
<<portp->prettyNameQ()
<<" requires "<<portp->width()
<<" bits, but connection's "<<pinp->prettyTypeName()
<<" generates "<<pinp->width()<<" bits.");
<< portp->prettyNameQ() << " requires " << portp->width()
<< " bits, but connection's " << pinp->prettyTypeName()
<< " generates " << pinp->width() << " bits.");
// otherwise would need some mess to force both sides to proper size
// (get an ASSIGN with EXTEND on the lhs instead of rhs)
}
@ -3566,6 +3567,16 @@ private:
}
}
}
}
virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE {
// For arguments, is assignment-like context; see IEEE rules in AstNodeAssign
// Function hasn't been widthed, so make it so.
UINFO(5, " FTASKREF " << nodep << endl);
UASSERT_OBJ(nodep->taskp(), nodep, "Unlinked");
if (nodep->didWidth()) return;
userIterate(nodep->taskp(), NULL);
// And do the arguments to the task/function too
processFTaskRefArgs(nodep);
nodep->didWidth(true);
}
virtual void visit(AstInitial* nodep) VL_OVERRIDE {