Internals: clang-format and refactor taskref pin handling.
This commit is contained in:
parent
ea3acc2d3a
commit
1e2d73fc80
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Reference in New Issue