Cleanup mis-merge ; move initial Ast manipulation out of Grammar

Signed-off-by: Matthew Ballance <matt.ballance@gmail.com>
This commit is contained in:
Matthew Ballance 2026-03-19 04:04:30 +00:00
parent 94a65f8e64
commit 8eb03568fd
6 changed files with 44 additions and 74 deletions

View File

@ -2737,7 +2737,7 @@ public:
};
class AstCoverpoint final : public AstNodeFuncCovItem {
// @astgen op1 := exprp : AstNodeExpr
// @astgen op2 := binsp : List[AstCoverBin]
// @astgen op2 := binsp : List[AstNode] // Parse: mixed AstCoverBin/AstCgOptionAssign; post-LinkParse: AstCoverBin only
// @astgen op3 := iffp : Optional[AstNodeExpr]
// @astgen op4 := optionsp : List[AstCoverOption]
public:

View File

@ -227,12 +227,6 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst {
iterateAndNextConstNull(nodep->rhsp());
if (!m_suppressSemi) puts(";\n");
}
void visit(AstAssignDly* nodep) override {
iterateAndNextConstNull(nodep->lhsp());
putfs(nodep, " <= ");
iterateAndNextConstNull(nodep->rhsp());
puts(";\n");
}
void visit(AstAlias* nodep) override {
putbs("alias ");
iterateConst(nodep->itemsp());

View File

@ -1327,6 +1327,40 @@ class LinkParseVisitor final : public VNVisitor {
iterate(cgClassp);
}
void visit(AstCoverpoint* nodep) override {
cleanFileline(nodep);
// Re-sort the parse-time mixed bins list (AstCoverBin + AstCgOptionAssign)
// into the typed binsp and optionsp slots. The grammar attaches both node types
// to binsp (op2) as a raw List[AstNode]; now that they are properly parented we
// can iterate and split them without any temporary-parent tricks.
for (AstNode *itemp = nodep->binsp(), *nextp; itemp; itemp = nextp) {
nextp = itemp->nextp();
if (AstCgOptionAssign* const optp = VN_CAST(itemp, CgOptionAssign)) {
optp->unlinkFrBack();
VCoverOptionType optType = VCoverOptionType::COMMENT;
if (optp->name() == "at_least") {
optType = VCoverOptionType::AT_LEAST;
} else if (optp->name() == "weight") {
optType = VCoverOptionType::WEIGHT;
} else if (optp->name() == "goal") {
optType = VCoverOptionType::GOAL;
} else if (optp->name() == "auto_bin_max") {
optType = VCoverOptionType::AUTO_BIN_MAX;
} else if (optp->name() == "per_instance") {
optType = VCoverOptionType::PER_INSTANCE;
} else if (optp->name() == "comment") {
optType = VCoverOptionType::COMMENT;
} else {
optp->v3warn(COVERIGN, "Ignoring unsupported coverage option: " + optp->name());
}
nodep->addOptionsp(
new AstCoverOption{optp->fileline(), optType, optp->valuep()->cloneTree(false)});
VL_DO_DANGLING(optp->deleteTree(), optp);
}
}
iterateChildren(nodep);
}
void visit(AstNode* nodep) override {
// Default: Just iterate
cleanFileline(nodep);

View File

@ -295,6 +295,8 @@ class CodeMotionAnalysisVisitor final : public VNVisitorConst {
iterateChildrenConst(nodep);
}
// VISITORS
void visit(AstNode* nodep) override {
// Push a new stack entry at the start of a list, but only if the list is not a
// single element (this saves a lot of allocations in expressions)

View File

@ -96,66 +96,6 @@ public:
nodep->trace(singletonp()->allTracingOn(fileline));
return nodep;
}
// Helper to move bins from parser list to coverpoint
void addCoverpointBins(AstCoverpoint* cp, AstNode* binsList) {
if (!binsList) return;
// CRITICAL FIX: The parser creates a linked list of bins. When we try to move them
// to the coverpoint one by one while they're still linked, the addNext() logic
// that updates headtailp pointers creates circular references. We must fully
// unlink ALL bins before adding ANY to the coverpoint.
std::vector<AstCoverBin*> bins;
std::vector<AstCoverOption*> options;
// To unlink the head node (which has no backp), create a temporary parent
AstBegin* tempParent = new AstBegin{binsList->fileline(), "[TEMP]", nullptr, true};
tempParent->addStmtsp(binsList); // Now binsList has a backp
// Now unlink all bins - they all have backp now
for (AstNode *binp = binsList, *nextp; binp; binp = nextp) {
nextp = binp->nextp();
if (AstCoverBin* cbinp = VN_CAST(binp, CoverBin)) {
cbinp->unlinkFrBack(); // Now this works for all bins including head
bins.push_back(cbinp);
} else if (AstCgOptionAssign* optp = VN_CAST(binp, CgOptionAssign)) {
optp->unlinkFrBack();
// Convert AstCgOptionAssign to AstCoverOption
VCoverOptionType optType = VCoverOptionType::COMMENT; // default
if (optp->name() == "at_least") {
optType = VCoverOptionType::AT_LEAST;
} else if (optp->name() == "weight") {
optType = VCoverOptionType::WEIGHT;
} else if (optp->name() == "goal") {
optType = VCoverOptionType::GOAL;
} else if (optp->name() == "auto_bin_max") {
optType = VCoverOptionType::AUTO_BIN_MAX;
} else if (optp->name() == "per_instance") {
optType = VCoverOptionType::PER_INSTANCE;
} else if (optp->name() == "comment") {
optType = VCoverOptionType::COMMENT;
} else {
optp->v3warn(COVERIGN,
"Ignoring unsupported coverage option: " + optp->name());
}
AstCoverOption* coverOptp = new AstCoverOption{optp->fileline(), optType,
optp->valuep()->cloneTree(false)};
options.push_back(coverOptp);
VL_DO_DANGLING(optp->deleteTree(), optp);
} else {
binp->v3warn(COVERIGN,
"Unexpected node in bins list, ignoring"); // LCOV_EXCL_LINE
VL_DO_DANGLING(binp->deleteTree(), binp);
}
}
// Delete the temporary parent
VL_DO_DANGLING(tempParent->deleteTree(), tempParent);
// Now add standalone bins and options to coverpoint
for (AstCoverBin* cbinp : bins) { cp->addBinsp(cbinp); }
for (AstCoverOption* optp : options) { cp->addOptionsp(optp); }
}
AstDisplay* createDisplayError(FileLine* fileline) {
AstDisplay* nodep = new AstDisplay{fileline, VDisplayType::DT_ERROR, "", nullptr, nullptr};
AstNode::addNext<AstNode, AstNode>(nodep, new AstStop{fileline, false});

View File

@ -7001,43 +7001,43 @@ cover_point<nodep>: // ==IEEE: cover_point
yCOVERPOINT expr iffE bins_or_empty
{ AstCoverpoint* const cp = new AstCoverpoint{$<fl>1, "", $2};
if ($3) cp->iffp(VN_AS($3, NodeExpr));
GRAMMARP->addCoverpointBins(cp, $4);
if ($4) cp->addBinsp($4);
$$ = cp; }
// // IEEE-2012: class_scope before an ID
| id/*cover_point_id*/ ':' yCOVERPOINT expr iffE bins_or_empty
{ AstCoverpoint* const cp = new AstCoverpoint{$<fl>3, *$1, $4};
if ($5) cp->iffp(VN_AS($5, NodeExpr));
GRAMMARP->addCoverpointBins(cp, $6);
if ($6) cp->addBinsp($6);
$$ = cp; }
// // data_type_or_implicit expansion
| data_type id/*cover_point_id*/ ':' yCOVERPOINT expr iffE bins_or_empty
{ AstCoverpoint* const cp = new AstCoverpoint{$<fl>4, *$2, $5};
if ($6) cp->iffp(VN_AS($6, NodeExpr));
GRAMMARP->addCoverpointBins(cp, $7);
if ($7) cp->addBinsp($7);
$$ = cp;
DEL($1); }
| yVAR data_type id/*cover_point_id*/ ':' yCOVERPOINT expr iffE bins_or_empty
{ AstCoverpoint* const cp = new AstCoverpoint{$<fl>5, *$3, $6};
if ($7) cp->iffp(VN_AS($7, NodeExpr));
GRAMMARP->addCoverpointBins(cp, $8);
if ($8) cp->addBinsp($8);
$$ = cp;
DEL($2); }
| yVAR implicit_typeE id/*cover_point_id*/ ':' yCOVERPOINT expr iffE bins_or_empty
{ AstCoverpoint* const cp = new AstCoverpoint{$<fl>5, *$3, $6};
if ($7) cp->iffp(VN_AS($7, NodeExpr));
GRAMMARP->addCoverpointBins(cp, $8);
if ($8) cp->addBinsp($8);
$$ = cp;
DEL($2); }
| signingE rangeList id/*cover_point_id*/ ':' yCOVERPOINT expr iffE bins_or_empty
{ AstCoverpoint* const cp = new AstCoverpoint{$<fl>5, *$3, $6};
if ($7) cp->iffp(VN_AS($7, NodeExpr));
GRAMMARP->addCoverpointBins(cp, $8);
if ($8) cp->addBinsp($8);
$$ = cp;
DEL($2); }
| signing id/*cover_point_id*/ ':' yCOVERPOINT expr iffE bins_or_empty
{ AstCoverpoint* const cp = new AstCoverpoint{$<fl>4, *$2, $5};
if ($6) cp->iffp(VN_AS($6, NodeExpr));
GRAMMARP->addCoverpointBins(cp, $7);
if ($7) cp->addBinsp($7);
$$ = cp; }
// // IEEE-2012:
| bins_or_empty { $$ = $1; }