mirror of
https://github.com/verilator/verilator.git
synced 2026-10-06 10:03:44 +02:00
Fix library method argument references (#8252)
Each VCMethod now carries a signature describing the access required of the references passed as arguments to the call. 'r' if the argument is read, 'w' if it is fully assigned so the old value does not matter, 'm' if it is modified (or only conditionally assigned), with a trailing '+' repeating the preceding entry for all remaining arguments. Signatures are validated at compile time, and V3Broken checks the arguments of every AstCMethodHard against them. The incorrect references this found and that are easy to fix are repaired in this patch. "TODO" marks method that are currently broken or not yet fit the scheme, these will be fixed in follow up patches. Also renames SCHED_COMMIT and SCHED_ENQUEUE to NBA_COMMIT and NBA_ENQUEUE, and remove unused methods.
This commit is contained in:
@@ -227,6 +227,52 @@ private:
|
||||
}
|
||||
return false;
|
||||
}
|
||||
static void checkArgRefs(AstNodeExpr* nodep, const char* descrp, AstNodeExpr* argsp) {
|
||||
if (!std::strcmp(descrp, "TODO")) return; // Skip if not yet checked
|
||||
|
||||
// Check each argument
|
||||
const char* dp = descrp;
|
||||
for (AstNodeExpr* argp = argsp; argp; argp = VN_AS(argp->nextp(), NodeExpr)) {
|
||||
if (argp->fileline()->erroringOn()) return; // Intentionally skip all checks
|
||||
const AstNodeExpr* const lvalp = argp->cLValueTargetp();
|
||||
const VAccess access = [&]() -> VAccess {
|
||||
if (const AstVarRef* const varrefp = VN_CAST(lvalp, VarRef)) {
|
||||
return varrefp->access();
|
||||
}
|
||||
if (const AstMemberSel* const memberselp = VN_CAST(lvalp, MemberSel)) {
|
||||
return memberselp->access();
|
||||
}
|
||||
UASSERT_OBJ(!lvalp, argp, "Unknown LValue expression");
|
||||
// Not an LValue, so it's read-only
|
||||
return VAccess::READ;
|
||||
}();
|
||||
if (dp[0] == '+') --dp; // Repeats the entry before it
|
||||
switch (dp[0]) {
|
||||
case 'r':
|
||||
UASSERT_OBJ(access.isReadOnly(), argp,
|
||||
"Input argument of library call is not a read-only expression");
|
||||
break;
|
||||
case 'w':
|
||||
UASSERT_OBJ(lvalp, argp, //
|
||||
"Output argument of library call is not a valid C++ LValue");
|
||||
UASSERT_OBJ(access.isWriteOnly(), argp,
|
||||
"Output argument of library call is not write-only");
|
||||
break;
|
||||
case 'm':
|
||||
UASSERT_OBJ(lvalp, argp, //
|
||||
"Inout argument of library call is not a valid C++ LValue");
|
||||
UASSERT_OBJ(access.isRW(), argp,
|
||||
"Inout argument of library call is not read-write");
|
||||
break;
|
||||
default:
|
||||
UASSERT_OBJ(dp[0], argp, "Unexpected trailing arguments to library call");
|
||||
break; // LCOV_EXCL_LINE
|
||||
}
|
||||
++dp;
|
||||
}
|
||||
UASSERT_OBJ(!dp[0] || dp[0] == '+', nodep, "Insufficient arguments to library call");
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
void visit(AstNodeAssign* nodep) override {
|
||||
processEnter(nodep);
|
||||
@@ -291,6 +337,7 @@ private:
|
||||
void visit(AstCMethodHard* nodep) override {
|
||||
++m_nCalls;
|
||||
processAndIterate(nodep);
|
||||
checkArgRefs(nodep, nodep->method().args(), nodep->pinsp());
|
||||
}
|
||||
void visit(AstNodeFTaskRef* nodep) override {
|
||||
++m_nCalls;
|
||||
|
||||
Reference in New Issue
Block a user