Skip to content

Commit

Permalink
Support cell override rules applying param assignments
Browse files Browse the repository at this point in the history
  • Loading branch information
MikePopoloski committed Mar 2, 2024
1 parent 4c4155f commit 696c74d
Show file tree
Hide file tree
Showing 12 changed files with 147 additions and 104 deletions.
39 changes: 26 additions & 13 deletions include/slang/ast/Compilation.h
Original file line number Diff line number Diff line change
Expand Up @@ -313,24 +313,38 @@ class SLANG_EXPORT Compilation : public BumpAllocator {
/// Gets the default library object.
const SourceLibrary& getDefaultLibrary() const { return *defaultLibPtr; }

/// A struct containing the result of a definition lookup.
struct DefinitionLookupResult {
/// The definition that was found, or nullptr if none was found.
const Symbol* definition = nullptr;

/// A new config root that applies to this definition and
/// any hierarchy underneath it, or nullptr if none.
const ConfigBlockSymbol* configRoot = nullptr;

/// A config rule that applies to instances using this
/// definition, or nullptr if none.
const ConfigRule* configRule = nullptr;
};

/// Gets the definition with the given name, or nullptr if there is no such definition.
/// This takes into account the given scope so that nested definitions are found
/// before more global ones.
const Symbol* tryGetDefinition(std::string_view name, const Scope& scope) const;
DefinitionLookupResult tryGetDefinition(std::string_view name, const Scope& scope) const;

/// Gets the definition with the given name, or nullptr if there is no such definition.
/// If no definition is found an appropriate diagnostic will be issued.
const Symbol* getDefinition(std::string_view name, const Scope& scope, SourceRange sourceRange,
DiagCode code) const;

/// Gets the definition for the given syntax node, or nullptr if it does not exist.
const DefinitionSymbol* getDefinition(const syntax::ModuleDeclarationSyntax& syntax) const;
DefinitionLookupResult getDefinition(std::string_view name, const Scope& scope,
SourceRange sourceRange, DiagCode code) const;

/// Gets the definition indicated by the given config rule, or nullptr if it does not exist.
/// If no definition is found an appropriate diagnostic will be issued.
const Symbol* getDefinition(std::string_view name, const Scope& scope,
const ConfigRule& configRule, SourceRange sourceRange,
DiagCode code) const;
DefinitionLookupResult getDefinition(std::string_view name, const Scope& scope,
const ConfigRule& configRule, SourceRange sourceRange,
DiagCode code) const;

/// Gets the definition for the given syntax node, or nullptr if it does not exist.
const DefinitionSymbol* getDefinition(const syntax::ModuleDeclarationSyntax& syntax) const;

/// Gets the definition indicated by the given config and cell ID, or nullptr
/// if it does not exist. If no definition is found an appropriate diagnostic will be issued.
Expand Down Expand Up @@ -684,10 +698,9 @@ class SLANG_EXPORT Compilation : public BumpAllocator {
void checkBindTargetParams(const syntax::BindDirectiveSyntax& syntax, const Scope& scope,
std::span<const Symbol* const> instTargets,
const DefinitionSymbol* defTarget);
std::pair<const Symbol*, bool> resolveConfigRules(std::string_view name, const Scope& scope,
const ResolvedConfig* parentConfig,
const ConfigRule* configRule,
const std::vector<Symbol*>& defList) const;
std::pair<DefinitionLookupResult, bool> resolveConfigRules(
std::string_view name, const Scope& scope, const ResolvedConfig* parentConfig,
const ConfigRule* configRule, const std::vector<Symbol*>& defList) const;
Diagnostic* errorMissingDef(std::string_view name, const Scope& scope, SourceRange sourceRange,
DiagCode code) const;

Expand Down
11 changes: 5 additions & 6 deletions include/slang/ast/symbols/InstanceSymbols.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,11 @@ class SLANG_EXPORT InstanceSymbol : public InstanceSymbolBase {

/// Creates a default-instantiated instance of the given definition. All parameters must
/// have defaults specified.
static InstanceSymbol& createDefault(Compilation& compilation,
const DefinitionSymbol& definition,
const HierarchyOverrideNode* hierarchyOverrideNode,
const ConfigBlockSymbol* configBlock,
const ConfigRule* configRule,
SourceLocation locationOverride = {});
static InstanceSymbol& createDefault(
Compilation& compilation, const DefinitionSymbol& definition,
const HierarchyOverrideNode* hierarchyOverrideNode = nullptr,
const ConfigBlockSymbol* configBlock = nullptr, const ConfigRule* configRule = nullptr,
SourceLocation locationOverride = {});

/// Creates a placeholder instance for a virtual interface type declaration.
static InstanceSymbol& createVirtual(
Expand Down
94 changes: 54 additions & 40 deletions source/ast/Compilation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -551,7 +551,8 @@ const CompilationUnitSymbol* Compilation::getCompilationUnit(
return nullptr;
}

const Symbol* Compilation::tryGetDefinition(std::string_view lookupName, const Scope& scope) const {
Compilation::DefinitionLookupResult Compilation::tryGetDefinition(std::string_view lookupName,
const Scope& scope) const {
// Try to find a config block for this scope to help choose the right definition.
const ResolvedConfig* resolvedConfig = nullptr;
if (auto inst = scope.getContainingInstance(); inst && inst->parentInstance)
Expand All @@ -564,7 +565,7 @@ const Symbol* Compilation::tryGetDefinition(std::string_view lookupName, const S
// override for this cell name.
if (resolvedConfig)
return resolveConfigRules(lookupName, scope, resolvedConfig, nullptr, {}).first;
return nullptr;
return {};
}

// If the second flag is set it means there are nested modules
Expand All @@ -590,27 +591,51 @@ const Symbol* Compilation::tryGetDefinition(std::string_view lookupName, const S
for (auto lib : defaultLiblist) {
for (auto def : defList) {
if (def->getSourceLibrary() == lib)
return def;
return {def, nullptr, nullptr};
}
}

// Otherwise return the first definition in the list -- it's already
// sorted in priority order.
return defList.empty() ? nullptr : defList.front();
return defList.empty() ? DefinitionLookupResult{}
: DefinitionLookupResult{defList.front(), nullptr, nullptr};
}

static Token getExternNameToken(const SyntaxNode& sn) {
return sn.kind == SyntaxKind::ExternModuleDecl ? sn.as<ExternModuleDeclSyntax>().header->name
: sn.as<ExternUdpDeclSyntax>().name;
}

const Symbol* Compilation::getDefinition(std::string_view name, const Scope& scope,
SourceRange sourceRange, DiagCode code) const {
if (auto def = tryGetDefinition(name, scope))
return def;
Compilation::DefinitionLookupResult Compilation::getDefinition(std::string_view name,
const Scope& scope,
SourceRange sourceRange,
DiagCode code) const {
if (auto result = tryGetDefinition(name, scope); result.definition)
return result;

errorMissingDef(name, scope, sourceRange, code);
return nullptr;
return {};
}

Compilation::DefinitionLookupResult Compilation::getDefinition(std::string_view lookupName,
const Scope& scope,
const ConfigRule& configRule,
SourceRange sourceRange,
DiagCode code) const {
std::pair<DefinitionLookupResult, bool> result;
if (auto it = definitionMap.find({lookupName, root.get()}); it != definitionMap.end())
result = resolveConfigRules(lookupName, scope, nullptr, &configRule, it->second.first);
else
result = resolveConfigRules(lookupName, scope, nullptr, &configRule, {});

if (!result.first.definition && !result.second) {
// No definition found and no error issued, so issue one ourselves.
auto diag = errorMissingDef(lookupName, scope, sourceRange, code);
if (diag)
diag->addNote(diag::NoteConfigRule, configRule.sourceRange);
}

return result.first;
}

const DefinitionSymbol* Compilation::getDefinition(const ModuleDeclarationSyntax& syntax) const {
Expand All @@ -632,25 +657,6 @@ const DefinitionSymbol* Compilation::getDefinition(const ModuleDeclarationSyntax
return nullptr;
}

const Symbol* Compilation::getDefinition(std::string_view lookupName, const Scope& scope,
const ConfigRule& configRule, SourceRange sourceRange,
DiagCode code) const {
std::pair<const Symbol*, bool> result;
if (auto it = definitionMap.find({lookupName, root.get()}); it != definitionMap.end())
result = resolveConfigRules(lookupName, scope, nullptr, &configRule, it->second.first);
else
result = resolveConfigRules(lookupName, scope, nullptr, &configRule, {});

if (!result.first && !result.second) {
// No definition found and no error issued, so issue one ourselves.
auto diag = errorMissingDef(lookupName, scope, sourceRange, code);
if (diag)
diag->addNote(diag::NoteConfigRule, configRule.sourceRange);
}

return result.first;
}

const DefinitionSymbol* Compilation::getDefinition(const ConfigBlockSymbol& config,
std::string_view cellName,
std::string_view libName,
Expand Down Expand Up @@ -1950,7 +1956,8 @@ void Compilation::resolveBindTargets(const BindDirectiveSyntax& syntax, const Sc
return;

Token name = syntax.target->as<IdentifierNameSyntax>().identifier;
auto targetDef = getDefinition(name.valueText(), scope, name.range(), diag::UnknownModule);
auto targetDef =
getDefinition(name.valueText(), scope, name.range(), diag::UnknownModule).definition;
if (!targetDef)
return;

Expand Down Expand Up @@ -1984,8 +1991,8 @@ void Compilation::resolveBindTargets(const BindDirectiveSyntax& syntax, const Sc
// If we didn't find the name as an instance, try as a definition.
if (syntax.target->kind == SyntaxKind::IdentifierName) {
Token name = syntax.target->as<IdentifierNameSyntax>().identifier;
auto def = getDefinition(name.valueText(), scope, name.range(),
diag::UnknownModule);
auto def = getDefinition(name.valueText(), scope, name.range(), diag::UnknownModule)
.definition;
if (!def)
return;

Expand Down Expand Up @@ -2271,7 +2278,7 @@ void Compilation::resolveDefParamsAndBinds() {
copyStateInto(*this, true);
}

std::pair<const Symbol*, bool> Compilation::resolveConfigRules(
std::pair<Compilation::DefinitionLookupResult, bool> Compilation::resolveConfigRules(
std::string_view lookupName, const Scope& scope, const ResolvedConfig* parentConfig,
const ConfigRule* rule, const std::vector<Symbol*>& defList) const {

Expand Down Expand Up @@ -2321,7 +2328,7 @@ std::pair<const Symbol*, bool> Compilation::resolveConfigRules(
overrideLib = getSourceLibrary(id.lib);
if (!overrideLib) {
root->addDiag(diag::UnknownLibrary, id.sourceRange) << id.lib;
return {nullptr, true};
return {{}, true};
}
}

Expand All @@ -2332,20 +2339,27 @@ std::pair<const Symbol*, bool> Compilation::resolveConfigRules(
// matches our target library.
auto result = findDefByLib(overrideDefIt->second.first, *overrideLib);
if (result)
return {result, true};
return {{result, nullptr, rule}, true};
}
}

// If we didn't find a target definition, try to look for a config.
if (auto configIt = configBlocks.find(id.name); configIt != configBlocks.end()) {
auto result = findDefByLib(configIt->second, *overrideLib);
if (result)
return {result, true};
if (result) {
auto topCells = result->getTopCells();
if (topCells.size() != 1) {
// TODO: error
return {{}, true};
}

return {{&topCells[0].definition, result, nullptr}, true};
}
}

// Otherwise we have an error.
errorMissingDef(id.name, *root, id.sourceRange, diag::UnknownModule);
return {nullptr, true};
return {{}, true};
}
}

Expand All @@ -2354,16 +2368,16 @@ std::pair<const Symbol*, bool> Compilation::resolveConfigRules(
// (or even just one element each) in basically all cases.
for (auto lib : liblist) {
if (auto def = findDefByLib(defList, *lib))
return {def, false};
return {{def, nullptr, rule}, false};
}
}
else if (auto parentDef = scope.asSymbol().getDeclaringDefinition()) {
// Fall back to picking based on the parent instance's library.
if (auto def = findDefByLib(defList, parentDef->sourceLibrary))
return {def, false};
return {{def, nullptr, rule}, false};
}

return {nullptr, false};
return {{}, false};
}

Diagnostic* Compilation::errorMissingDef(std::string_view name, const Scope& scope,
Expand Down
2 changes: 1 addition & 1 deletion source/ast/Lookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2182,7 +2182,7 @@ void Lookup::reportUndeclared(const Scope& initialScope, std::string_view name,
}

// Otherwise, check if this names a definition, in which case we can give a nicer error.
if (auto def = comp.tryGetDefinition(name, initialScope);
if (auto def = comp.tryGetDefinition(name, initialScope).definition;
def && def->kind == SymbolKind::Definition) {
if (isHierarchical) {
result.addDiag(initialScope, diag::CouldNotResolveHierarchicalPath, range) << name;
Expand Down
6 changes: 3 additions & 3 deletions source/ast/Scope.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1261,7 +1261,7 @@ bool Scope::handleDataDeclaration(const DataDeclarationSyntax& syntax) {
if (symbol || namedType.name->kind != SyntaxKind::IdentifierName)
return false;

auto def = compilation.tryGetDefinition(name, *this);
auto def = compilation.tryGetDefinition(name, *this).definition;
if (!def || def->kind != SymbolKind::Definition)
return false;

Expand Down Expand Up @@ -1293,7 +1293,7 @@ void Scope::tryFixupInstances(const DataDeclarationSyntax& syntax, const ASTCont
SmallVectorBase<const Symbol*>& results) const {
auto& namedType = syntax.type->as<NamedTypeSyntax>();
std::string_view name = getIdentifierName(namedType);
auto def = compilation.tryGetDefinition(name, *this);
auto def = compilation.tryGetDefinition(name, *this).definition;
if (!def || def->kind != SymbolKind::Definition)
return;

Expand Down Expand Up @@ -1352,7 +1352,7 @@ void Scope::handleNestedDefinition(const ModuleDeclarationSyntax& syntax) const
if (!def || def->isInstantiated())
return;

auto& inst = InstanceSymbol::createDefault(compilation, *def, nullptr, nullptr, nullptr);
auto& inst = InstanceSymbol::createDefault(compilation, *def);
insertMember(&inst, lastMember, /* isElaborating */ true, /* incrementIndex */ true);
}

Expand Down
2 changes: 1 addition & 1 deletion source/ast/SemanticModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ const Symbol* SemanticModel::getDeclaredSymbol(const SyntaxNode& syntax) {
return nullptr;

// There is no symbol to use here so create a placeholder instance.
auto result = &InstanceSymbol::createDefault(compilation, *def, nullptr, nullptr, nullptr);
auto result = &InstanceSymbol::createDefault(compilation, *def);
symbolCache[&syntax] = result;
return result;
}
Expand Down
Loading

0 comments on commit 696c74d

Please sign in to comment.