Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SymbolTable]: initial support for implicit declarations #746

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions verilog/analysis/symbol_table.cc
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,9 @@ static absl::Status DiagnoseMemberSymbolResolutionFailure(
context_name, "."));
}

static const SymbolTableNode* LookupSymbolUpwards(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you like, you may move the below definition earlier in the file.

const SymbolTableNode& context, absl::string_view symbol);

class SymbolTable::Builder : public TreeContextVisitor {
public:
Builder(const VerilogSourceFile& source, SymbolTable* symbol_table,
Expand Down Expand Up @@ -266,6 +269,9 @@ class SymbolTable::Builder : public TreeContextVisitor {
case NodeEnum::kEnumType:
DescendEnumType(node);
break;
case NodeEnum::kLPValue:
HandlePossibleImplicitDeclaration(node);
break;
default:
Descend(node);
break;
Expand Down Expand Up @@ -521,6 +527,26 @@ class SymbolTable::Builder : public TreeContextVisitor {
}
}

void HandlePossibleImplicitDeclaration(const SyntaxTreeNode& node) {
VLOG(2) << __FUNCTION__;

// Only left-hand side of continuous assignment statements are allowed to
// implicitly declare nets (LRM 6.10: Implicit declarations).
if (Context().DirectParentsAre(
{NodeEnum::kNetVariableAssignment, NodeEnum::kAssignmentList,
NodeEnum::kContinuousAssignmentStatement})) {
CHECK(node.MatchesTag(NodeEnum::kLPValue));

DeclarationTypeInfo decl_type_info;
const ValueSaver<DeclarationTypeInfo*> save_type(&declaration_type_info_,
&decl_type_info);
declaration_type_info_->implicit = true;
Descend(node);
} else {
Descend(node);
}
}

void HandleIdentifier(const SyntaxTreeLeaf& leaf) {
const absl::string_view text = leaf.get().text();
VLOG(2) << __FUNCTION__ << ": " << text;
Expand Down Expand Up @@ -655,6 +681,29 @@ class SymbolTable::Builder : public TreeContextVisitor {
return;
}

// Handle possible implicit declarations here
if (declaration_type_info_ != nullptr && declaration_type_info_->implicit) {
const SymbolTableNode* resolved =
LookupSymbolUpwards(*ABSL_DIE_IF_NULL(current_scope_), text);
if (resolved == nullptr) {
// No explicit declaration found, declare here
SymbolTableNode& implicit_declaration =
EmplaceTypedElementInCurrentScope(
leaf, text, SymbolMetaType::kDataNetVariableInstance);

const ReferenceComponent implicit_ref{
.identifier = text,
.ref_type = InferReferenceType(),
.required_metatype = InferMetaType(),
// pre-resolve
.resolved_symbol = &implicit_declaration,
};

ref.PushReferenceComponent(implicit_ref);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this push needed? When a symbol is implicitly declared, do we ever need to build a hierarchical reference from it with the net/variable as a parent?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we do. Implicit declaration is also an reference to that symbol and we want to keep that reference.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, sounds good.

return;
}
}

// For all other cases, grow the reference chain deeper.
// For type references, which may contained named parameters,
// when encountering the first unqualified reference, establish its
Expand Down Expand Up @@ -1770,6 +1819,10 @@ std::ostream& operator<<(std::ostream& stream,
stream << "(primitive)";
}

if (decl_type_info.implicit) {
stream << ", implicit";
}

return stream << " }";
}

Expand Down
5 changes: 5 additions & 0 deletions verilog/analysis/symbol_table.h
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,11 @@ struct DeclarationTypeInfo {
// advance, and only ever moving ReferenceComponents, never copying them.
const ReferenceComponentNode* user_defined_type = nullptr;

// Indicates that this is implicit declaration.
// FIXME(ldk): Check if this could be replaced by user_defined_type pointing
// to default implicit type.
bool implicit = false;

public:
DeclarationTypeInfo() = default;

Expand Down
Loading