Skip to content

Commit

Permalink
v1800-2023: covergroup inheritance
Browse files Browse the repository at this point in the history
  • Loading branch information
MikePopoloski committed May 17, 2024
1 parent 69165e2 commit 4922ab0
Show file tree
Hide file tree
Showing 13 changed files with 223 additions and 47 deletions.
6 changes: 3 additions & 3 deletions bindings/python/TypeBindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -303,8 +303,8 @@ void registerTypes(py::module_& m) {
.def_property_readonly("constraints", &ConstraintBlockSymbol::getConstraints);

py::class_<CovergroupType, Type, Scope>(m, "CovergroupType")
.def_readonly("arguments", &CovergroupType::arguments)
.def_readonly("sampleArguments", &CovergroupType::sampleArguments)
.def_property_readonly("body", [](const CovergroupType& self) { return &self.body; })
.def_property_readonly("arguments", &CovergroupType::getArguments)
.def_property_readonly("body", [](const CovergroupType& self) { return &self.getBody(); })
.def_property_readonly("baseGroup", &CovergroupType::getBaseGroup)
.def_property_readonly("coverageEvent", &CovergroupType::getCoverageEvent);
}
38 changes: 32 additions & 6 deletions include/slang/ast/symbols/CoverSymbols.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "slang/ast/types/DeclaredType.h"
#include "slang/ast/types/Type.h"
#include "slang/syntax/SyntaxFwd.h"
#include "slang/util/Function.h"

namespace slang::ast {

Expand Down Expand Up @@ -50,31 +51,56 @@ class SLANG_EXPORT CovergroupBodySymbol : public Symbol, public Scope {
void serializeTo(ASTSerializer& serializer) const;

static bool isKind(SymbolKind kind) { return kind == SymbolKind::CovergroupBody; }

private:
friend class CovergroupType;

const Symbol* lastBuiltinMember = nullptr;
};

/// Represents a covergroup definition type.
class SLANG_EXPORT CovergroupType : public Type, public Scope {
public:
std::span<const FormalArgumentSymbol* const> arguments;
std::span<const FormalArgumentSymbol* const> sampleArguments;
const CovergroupBodySymbol& body;
using ArgList = std::span<const FormalArgumentSymbol* const>;

CovergroupType(Compilation& compilation, std::string_view name, SourceLocation loc,
const CovergroupBodySymbol& body);

static const CovergroupType& fromSyntax(const Scope& scope,
const syntax::CovergroupDeclarationSyntax& syntax,
const Symbol*& classProperty);
ArgList getArguments() const {
ensureElaborated();
return arguments;
}

const CovergroupBodySymbol& getBody() const {
ensureElaborated();
return body;
}

const Type* getBaseGroup() const {
ensureElaborated();
return baseGroup;
}

const TimingControl* getCoverageEvent() const;
ConstantValue getDefaultValueImpl() const;

void serializeTo(ASTSerializer& serializer) const;

static const CovergroupType& fromSyntax(const Scope& scope,
const syntax::CovergroupDeclarationSyntax& syntax,
const Symbol*& classProperty);

static bool isKind(SymbolKind kind) { return kind == SymbolKind::CovergroupType; }

private:
friend class Scope;

void inheritMembers(function_ref<void(const Symbol&)> insertCB) const;

const CovergroupBodySymbol& body;
mutable ArgList arguments;
mutable std::optional<const TimingControl*> event;
mutable const Type* baseGroup = nullptr;
};

class BinsSelectExpr;
Expand Down
2 changes: 1 addition & 1 deletion include/slang/parsing/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ class SLANG_EXPORT Parser : ParserBase, syntax::SyntaxFacts {
syntax::MemberSyntax* parseCoverageMember();
syntax::BlockEventExpressionSyntax& parseBlockEventExpression();
syntax::WithClauseSyntax* parseWithClause();
syntax::CovergroupDeclarationSyntax& parseCovergroupDeclaration(AttrList attributes);
syntax::CovergroupDeclarationSyntax& parseCovergroupDeclaration(AttrList attributes, bool inClass);
syntax::CoverpointSyntax* parseCoverpoint(AttrList attributes, syntax::DataTypeSyntax* type, syntax::NamedLabelSyntax* label);
syntax::CoverCrossSyntax* parseCoverCross(AttrList attributes, syntax::NamedLabelSyntax* label);
syntax::CoverageOptionSyntax* parseCoverageOption(AttrList attributes);
Expand Down
1 change: 1 addition & 0 deletions scripts/diagnostics.txt
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ error FinalSpecifierLast "'final' specifier must come last in a list of class ov
error FinalWithPure "'final' specifier cannot be used with a pure virtual member"
error StaticFuncSpecifier "static members cannot have override specifiers"
error OverridingExtends "'{}' is marked 'extends' but doesn't override a base class virtual member"
error DerivedCovergroupNotInClass "covergroup inheritance can only be used inside a class"
warning dpi-pure-task DPIPureTask "DPI tasks cannot be marked 'pure'"
warning nonstandard-generate NonStandardGenBlock "standalone generate block without loop or condition is not allowed in SystemVerilog"
warning empty-pattern EmptyAssignmentPattern "empty assignment patterns are disallowed by SystemVerilog"
Expand Down
1 change: 1 addition & 0 deletions scripts/syntax.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1842,6 +1842,7 @@ token closeParen

CovergroupDeclaration base=Member
token covergroup
token extends
token name
FunctionPortList? portList
SyntaxNode? event
Expand Down
4 changes: 2 additions & 2 deletions source/ast/ElabVisitors.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ struct DiagnosticVisitor : public ASTVisitor<DiagnosticVisitor, false, false> {
attr->getValue();
}

if constexpr (requires { symbol.getBody(); }) {
if constexpr (requires { symbol.getBody().bad(); }) {
auto& body = symbol.getBody();
if (body.bad())
return true;
Expand Down Expand Up @@ -184,7 +184,7 @@ struct DiagnosticVisitor : public ASTVisitor<DiagnosticVisitor, false, false> {
return;

symbol.getCoverageEvent();
for (auto& option : symbol.body.options)
for (auto& option : symbol.getBody().options)
option.getExpression();
}

Expand Down
2 changes: 1 addition & 1 deletion source/ast/Lookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -794,7 +794,7 @@ bool resolveColonNames(SmallVectorBase<NamePlusLoc>& nameParts, int colonParts,
result.flags |= LookupResultFlags::WasImported;
}
else if (symbol->kind == SymbolKind::CovergroupType) {
symbol = symbol->as<CovergroupType>().body.find(name.text);
symbol = symbol->as<CovergroupType>().getBody().find(name.text);
}
else {
symbol = symbol->as<Scope>().find(name.text);
Expand Down
6 changes: 6 additions & 0 deletions source/ast/Scope.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -859,6 +859,12 @@ void Scope::elaborate() const {
thisSym->as<ClassType>().inheritMembers(
[this](const Symbol& member) { insertMember(&member, nullptr, true, true); });
}
else if (thisSym->kind == SymbolKind::CovergroupType) {
// If this is a covergroup type being elaborated, let it inherit members from parent
// classes.
thisSym->as<CovergroupType>().inheritMembers(
[this](const Symbol& member) { insertMember(&member, nullptr, true, true); });
}
else if (thisSym->kind == SymbolKind::InstanceBody &&
thisSym->as<InstanceBodySymbol>().getDefinition().definitionKind ==
DefinitionKind::Interface) {
Expand Down
2 changes: 1 addition & 1 deletion source/ast/expressions/AssignmentExpressions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1280,7 +1280,7 @@ Expression& NewCovergroupExpression::fromSyntax(Compilation& compilation,
auto& coverType = assignmentTarget.getCanonicalType().as<CovergroupType>();

SmallVector<const Expression*> args;
if (!CallExpression::bindArgs(syntax.argList, coverType.arguments, "new"sv, range, context,
if (!CallExpression::bindArgs(syntax.argList, coverType.getArguments(), "new"sv, range, context,
args, /* isBuiltInMethod */ false)) {
return badExpr(compilation, nullptr);
}
Expand Down
2 changes: 1 addition & 1 deletion source/ast/expressions/SelectExpressions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -941,7 +941,7 @@ Expression& MemberAccessExpression::fromSelector(
break;
}
case SymbolKind::CovergroupType:
scope = &type.as<CovergroupType>().body;
scope = &type.as<CovergroupType>().getBody();
break;
case SymbolKind::EnumType:
case SymbolKind::StringType:
Expand Down
131 changes: 104 additions & 27 deletions source/ast/symbols/CoverSymbols.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "slang/ast/TimingControl.h"
#include "slang/ast/expressions/AssignmentExpressions.h"
#include "slang/ast/symbols/ClassSymbols.h"
#include "slang/ast/symbols/MemberSymbols.h"
#include "slang/ast/symbols/SubroutineSymbols.h"
#include "slang/ast/symbols/SymbolBuilders.h"
#include "slang/ast/symbols/VariableSymbols.h"
Expand Down Expand Up @@ -182,6 +183,8 @@ CovergroupBodySymbol::CovergroupBodySymbol(Compilation& comp, SourceLocation loc
addProperty(*this, "type_option"sv, VariableLifetime::Static, type_option);

addBuiltInMethods(*this, true);

lastBuiltinMember = getLastMember();
}

void CovergroupBodySymbol::serializeTo(ASTSerializer& serializer) const {
Expand Down Expand Up @@ -212,41 +215,41 @@ const CovergroupType& CovergroupType::fromSyntax(const Scope& scope,
result->setSyntax(syntax);
result->setAttributes(scope, syntax.attributes);

if (syntax.portList) {
SmallVector<const FormalArgumentSymbol*> args;
SubroutineSymbol::buildArguments(*result, scope, *syntax.portList,
VariableLifetime::Automatic, args);
result->arguments = args.copy(comp);

for (auto arg : result->arguments) {
if (arg->direction == ArgumentDirection::Out ||
arg->direction == ArgumentDirection::InOut) {
scope.addDiag(diag::CovergroupOutArg, arg->location);
}
}
}

MethodBuilder sample(comp, "sample"sv, comp.getVoidType(), SubroutineKind::Function);
body->addMember(sample.symbol);

if (syntax.event && syntax.event->kind == SyntaxKind::WithFunctionSample) {
auto& wfs = syntax.event->as<WithFunctionSampleSyntax>();
if (wfs.portList) {
if (!syntax.extends) {
if (syntax.portList) {
SmallVector<const FormalArgumentSymbol*> args;
SubroutineSymbol::buildArguments(*result, scope, *wfs.portList,
SubroutineSymbol::buildArguments(*result, scope, *syntax.portList,
VariableLifetime::Automatic, args);
result->arguments = args.copy(comp);

result->sampleArguments = args.copy(comp);

for (auto arg : result->sampleArguments) {
for (auto arg : result->arguments) {
if (arg->direction == ArgumentDirection::Out ||
arg->direction == ArgumentDirection::InOut) {
scope.addDiag(diag::CovergroupOutArg, arg->location);
}
}
}

const_cast<FormalArgumentSymbol*>(arg)->flags |=
VariableFlags::CoverageSampleFormal;
sample.copyArg(*arg);
MethodBuilder sample(comp, "sample"sv, comp.getVoidType(), SubroutineKind::Function);
body->addMember(sample.symbol);

if (syntax.event && syntax.event->kind == SyntaxKind::WithFunctionSample) {
auto& wfs = syntax.event->as<WithFunctionSampleSyntax>();
if (wfs.portList) {
SmallVector<const FormalArgumentSymbol*> args;
SubroutineSymbol::buildArguments(*result, scope, *wfs.portList,
VariableLifetime::Automatic, args);

for (auto arg : args) {
if (arg->direction == ArgumentDirection::Out ||
arg->direction == ArgumentDirection::InOut) {
scope.addDiag(diag::CovergroupOutArg, arg->location);
}

const_cast<FormalArgumentSymbol*>(arg)->flags |=
VariableFlags::CoverageSampleFormal;
sample.copyArg(*arg);
}
}
}
}
Expand All @@ -271,11 +274,85 @@ const CovergroupType& CovergroupType::fromSyntax(const Scope& scope,
var->setType(*result);
var->flags |= VariableFlags::Const;
classProperty = var;

if (syntax.extends)
result->setNeedElaboration();
}

return *result;
}

void CovergroupType::inheritMembers(function_ref<void(const Symbol&)> insertCB) const {
auto syntax = getSyntax();
auto scope = getParentScope();
SLANG_ASSERT(syntax && scope);

// If this covergroup doesn't inherit from anything then there's nothing to do.
auto& cds = syntax->as<CovergroupDeclarationSyntax>();
if (!cds.extends)
return;

auto& comp = scope->getCompilation();
baseGroup = &comp.getErrorType();

// Find the base class's group from which we are inheriting.
auto baseClass = scope->asSymbol().as<ClassType>().getBaseClass();
if (!baseClass || baseClass->kind != SymbolKind::ClassType)
return;

auto candidateBase = baseClass->as<ClassType>().find(cds.name.valueText());
if (candidateBase && candidateBase->kind == SymbolKind::ClassProperty) {
auto& ct = candidateBase->as<ClassPropertySymbol>().getType();
if (ct.kind == SymbolKind::CovergroupType)
baseGroup = &ct;
}

if (baseGroup->isError()) {
// TODO: error
return;
}

auto& baseCG = baseGroup->as<CovergroupType>();
arguments = baseCG.getArguments();
event = baseCG.event;

// We have the base group -- inherit all of the members from it.
auto& scopeNameMap = body.getUnelaboratedNameMap();
for (auto& member : baseCG.getBody().members()) {
if (member.name.empty())
continue;

// Don't inherit if the member is already overridden.
if (auto it = scopeNameMap.find(member.name); it != scopeNameMap.end())
continue;

// If the symbol itself was already inherited, create a new wrapper around
// it for our own scope.
const Symbol* toWrap = &member;
if (member.kind == SymbolKind::TransparentMember)
toWrap = &member.as<TransparentMemberSymbol>().wrapped;

// All symbols get inserted into the beginning of the scope using the
// provided insertion callback. We insert them as TransparentMemberSymbols
// so that we can trace a path back to the actual location they are declared.
auto wrapper = comp.emplace<TransparentMemberSymbol>(*toWrap);
body.insertMember(wrapper, body.lastBuiltinMember, true, false);
}

// Also inherit any argument symbols are in the base covergroup type itself,
// as opposed to the body which we already looked at above.
for (auto& member : baseCG.members()) {
const Symbol* toWrap = &member;
if (member.kind == SymbolKind::TransparentMember)
toWrap = &member.as<TransparentMemberSymbol>().wrapped;

if (toWrap->kind == SymbolKind::FormalArgument) {
auto wrapper = comp.emplace<TransparentMemberSymbol>(*toWrap);
insertCB(*wrapper);
}
}
}

const TimingControl* CovergroupType::getCoverageEvent() const {
if (event)
return *event;
Expand Down
Loading

0 comments on commit 4922ab0

Please sign in to comment.