Skip to content

Commit

Permalink
Allow specifying top modules in libraries, configs
Browse files Browse the repository at this point in the history
  • Loading branch information
MikePopoloski committed Oct 28, 2023
1 parent a702457 commit 7493bac
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 24 deletions.
4 changes: 2 additions & 2 deletions include/slang/ast/Compilation.h
Original file line number Diff line number Diff line change
Expand Up @@ -724,7 +724,7 @@ class SLANG_EXPORT Compilation : public BumpAllocator {
// module has ever been instantiated to know whether it should be considered top-level.
flat_hash_set<std::string_view> globalInstantiations;

struct DefinitionMetadata {
struct SyntaxMetadata {
const syntax::SyntaxTree* tree = nullptr;
const SourceLibrary* library = nullptr;
const NetType* defaultNetType = nullptr;
Expand All @@ -733,7 +733,7 @@ class SLANG_EXPORT Compilation : public BumpAllocator {
};

// Map from syntax nodes to parse-time metadata about them.
flat_hash_map<const syntax::ModuleDeclarationSyntax*, DefinitionMetadata> definitionMetadata;
flat_hash_map<const syntax::SyntaxNode*, SyntaxMetadata> syntaxMetadata;

// The name map for all module, interface, and program definitions.
// The key is a combination of definition name + the scope in which it was declared.
Expand Down
62 changes: 43 additions & 19 deletions source/ast/Compilation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,7 @@ void Compilation::addSyntaxTree(std::shared_ptr<SyntaxTree> tree) {
compilationUnits.push_back(unit);

for (auto& [n, meta] : tree->getMetadata().nodeMap) {
auto decl = &n->as<ModuleDeclarationSyntax>();
DefinitionMetadata result;
SyntaxMetadata result;
result.tree = tree.get();
result.library = meta.library;
result.defaultNetType = &getNetType(meta.defaultNetType);
Expand All @@ -227,7 +226,7 @@ void Compilation::addSyntaxTree(std::shared_ptr<SyntaxTree> tree) {
break;
}

definitionMetadata[decl] = result;
syntaxMetadata[n] = result;
}

for (auto& name : tree->getMetadata().globalInstances)
Expand Down Expand Up @@ -345,13 +344,21 @@ const RootSymbol& Compilation::getRoot(bool skipDefParamsAndBinds) {
continue;

for (auto def : defList) {
// TODO: allow these to include a library name
if (def->sourceLibrary)
continue;

if (def->definitionKind == DefinitionKind::Module ||
def->definitionKind == DefinitionKind::Program) {
if (auto it = tm.find(def->name); it != tm.end()) {

// If this definition is in a library, it can only be targeted as
// a top module by the user including the library name in the string.
flat_hash_set<std::string_view>::iterator it;
if (def->sourceLibrary) {
auto target = fmt::format("{}.{}", def->sourceLibrary->name, def->name);
it = tm.find(target);
}
else {
it = tm.find(def->name);
}

if (it != tm.end()) {
// Remove from the top modules set so that we know we visited it.
tm.erase(it);

Expand All @@ -368,20 +375,36 @@ const RootSymbol& Compilation::getRoot(bool skipDefParamsAndBinds) {
}

// Otherwise this definition might be unreferenced and not automatically
// instantiated.
if (globalInstantiations.find(def->name) == globalInstantiations.end())
// instantiated (don't add library definitions to this list though).
if (globalInstantiations.find(def->name) == globalInstantiations.end() &&
!def->sourceLibrary) {
unreferencedDefs.push_back(def);
}
}
}

// Any names still in the map were not found as module definitions.
for (auto& name : tm) {
// This might be a config block instead.
if (auto confIt = configBlocks.find(name); confIt != configBlocks.end()) {
for (auto& userProvidedName : tm) {
// This might be a config block instead. If it has a dot, assume that's
// the library designator.
std::string confLib;
std::string confName(userProvidedName);
if (auto pos = confName.find_first_of('.'); pos != std::string::npos) {
confLib = confName.substr(0, pos);
confName = confName.substr(pos + 1);
}

// A trailing ':config' is stripped -- it's there to allow the user
// to disambiguate modules and config blocks.
constexpr std::string_view configSuffix = ":config";
if (confName.ends_with(configSuffix))
confName = confName.substr(0, confName.length() - configSuffix.length());

if (auto confIt = configBlocks.find(confName); confIt != configBlocks.end()) {
const ConfigBlockSymbol* foundConf = nullptr;
for (auto conf : confIt->second) {
// TODO: handle configs in libraries
if (!conf->sourceLibrary) {
if ((!conf->sourceLibrary && confLib.empty()) ||
(conf->sourceLibrary && conf->sourceLibrary->name == confLib)) {
foundConf = conf;
break;
}
Expand Down Expand Up @@ -414,7 +437,7 @@ const RootSymbol& Compilation::getRoot(bool skipDefParamsAndBinds) {
}
}

root->addDiag(diag::InvalidTopModule, SourceLocation::NoLocation) << name;
root->addDiag(diag::InvalidTopModule, SourceLocation::NoLocation) << userProvidedName;
}
}

Expand Down Expand Up @@ -582,7 +605,7 @@ void Compilation::createDefinition(const Scope& scope, LookupLocation location,
// We can only be missing metadata if the definition is created programmatically
// (i.e. not via the parser) so we just fill in the parent's default net type
// so that it's not a null pointer.
auto& metadata = definitionMetadata[&syntax];
auto& metadata = syntaxMetadata[&syntax];
if (!metadata.defaultNetType)
metadata.defaultNetType = &scope.getDefaultNetType();

Expand Down Expand Up @@ -665,7 +688,7 @@ const PackageSymbol* Compilation::getPackage(std::string_view lookupName) const

const PackageSymbol& Compilation::createPackage(const Scope& scope,
const ModuleDeclarationSyntax& syntax) {
auto& metadata = definitionMetadata[&syntax];
auto& metadata = syntaxMetadata[&syntax];
if (!metadata.defaultNetType)
metadata.defaultNetType = &scope.getDefaultNetType();

Expand All @@ -687,8 +710,9 @@ const PackageSymbol& Compilation::createPackage(const Scope& scope,

const ConfigBlockSymbol& Compilation::createConfigBlock(const Scope& scope,
const ConfigDeclarationSyntax& syntax) {
// TODO: set sourcelibrary pointer
auto& metadata = syntaxMetadata[&syntax];
auto& config = ConfigBlockSymbol::fromSyntax(scope, syntax);
config.sourceLibrary = metadata.library;

auto it = configBlocks.find(config.name);
if (it == configBlocks.end()) {
Expand Down
5 changes: 5 additions & 0 deletions source/parsing/ParserMetadata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,11 @@ class MetadataVisitor : public SyntaxVisitor<MetadataVisitor> {
meta.nodeMap[&syntax] = {library, defaultNetType, unconnectedDrive, timeScale};
}

void handle(const ConfigDeclarationSyntax& syntax) {
visitDefault(syntax);
meta.nodeMap[&syntax] = {library, defaultNetType, unconnectedDrive, timeScale};
}

void visitToken(Token token) {
// Look through the token's trivia for any preprocessor directives
// that might need to be captured in the metadata for module decls.
Expand Down
12 changes: 9 additions & 3 deletions source/parsing/Parser_members.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3398,6 +3398,10 @@ ConfigDeclarationSyntax& Parser::parseConfigDeclaration(AttrList attributes) {
auto name = expect(TokenKind::Identifier);
auto semi1 = expect(TokenKind::Semicolon);

auto& pp = getPP();
ParserMetadata::Node node{pp.getCurrentLibrary(), pp.getDefaultNetType(),
pp.getUnconnectedDrive(), pp.getTimeScale()};

SmallVector<ParameterDeclarationStatementSyntax*> localparams;
while (peek(TokenKind::LocalParamKeyword)) {
Token paramSemi;
Expand Down Expand Up @@ -3465,9 +3469,11 @@ ConfigDeclarationSyntax& Parser::parseConfigDeclaration(AttrList attributes) {
auto blockName = parseNamedBlockClause();
checkBlockNames(name, blockName);

return factory.configDeclaration(attributes, config, name, semi1, localparams.copy(alloc),
design, topCells.copy(alloc), semi2, rules.copy(alloc),
endconfig, blockName);
auto& result = factory.configDeclaration(attributes, config, name, semi1,
localparams.copy(alloc), design, topCells.copy(alloc),
semi2, rules.copy(alloc), endconfig, blockName);
meta.nodeMap[&result] = node;
return result;
}

MemberSyntax* Parser::parseLibraryMember() {
Expand Down
77 changes: 77 additions & 0 deletions tests/unittests/ast/ConfigTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,33 @@ TEST_CASE("Driver library explicit ordering") {
CHECK(m.getDefinition().sourceLibrary->name == "lib2");
}

TEST_CASE("Top module in a library") {
auto lib1 = std::make_unique<SourceLibrary>("lib1", 1);

auto tree1 = SyntaxTree::fromText(R"(
module mod;
endmodule
)",
SyntaxTree::getDefaultSourceManager(), "source", "", {},
lib1.get());
auto tree2 = SyntaxTree::fromText(R"(
module top;
endmodule
)");

CompilationOptions options;
options.topModules.emplace("lib1.mod");

Compilation compilation(options);
compilation.addSyntaxTree(tree1);
compilation.addSyntaxTree(tree2);
NO_COMPILATION_ERRORS;

auto topInstances = compilation.getRoot().topInstances;
CHECK(topInstances.size() == 1);
CHECK(topInstances[0]->name == "mod");
}

TEST_CASE("Config block top modules") {
auto tree = SyntaxTree::fromText(R"(
config cfg1;
Expand All @@ -107,3 +134,53 @@ endmodule
CHECK(topInstances.size() == 1);
CHECK(topInstances[0]->name == "frob");
}

TEST_CASE("Config in library, disambiguate with module name") {
auto lib1 = std::make_unique<SourceLibrary>("lib1", 1);
auto lib2 = std::make_unique<SourceLibrary>("lib2", 2);

auto tree1 = SyntaxTree::fromText(R"(
module mod;
endmodule
config cfg;
design mod;
endconfig
)",
SyntaxTree::getDefaultSourceManager(), "source", "", {},
lib1.get());
auto tree2 = SyntaxTree::fromText(R"(
module mod;
endmodule
module cfg;
endmodule
config cfg;
design mod;
endconfig
)",
SyntaxTree::getDefaultSourceManager(), "source", "", {},
lib2.get());
auto tree3 = SyntaxTree::fromText(R"(
module mod;
endmodule
config cfg;
design mod;
endconfig
)");

CompilationOptions options;
options.topModules.emplace("lib2.cfg:config");

Compilation compilation(options);
compilation.addSyntaxTree(tree1);
compilation.addSyntaxTree(tree2);
compilation.addSyntaxTree(tree3);
NO_COMPILATION_ERRORS;

auto top = compilation.getRoot().topInstances[0];
CHECK(top->name == "mod");
CHECK(top->getDefinition().sourceLibrary->name == "lib2");
}

0 comments on commit 7493bac

Please sign in to comment.