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

[slang] Introduce net aliases bits duplication checks #1045

Conversation

likeamahoney
Copy link
Contributor

Introduce 2 new net alias bit checks from SystemVerilog LRM section 10.11:

  • check that net aliased to itself
  • check that aliased bits specified more than once at module instance scope

@likeamahoney
Copy link
Contributor Author

I think with it LRM section 10.11 is done

Copy link

codecov bot commented Jul 4, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 94.77%. Comparing base (f6e3510) to head (7b7474f).
Report is 42 commits behind head on master.

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##           master    #1045   +/-   ##
=======================================
  Coverage   94.76%   94.77%           
=======================================
  Files         191      191           
  Lines       47743    47825   +82     
=======================================
+ Hits        45243    45325   +82     
  Misses       2500     2500           
Files with missing lines Coverage Δ
include/slang/ast/Compilation.h 100.00% <ø> (ø)
include/slang/ast/SemanticFacts.h 84.21% <100.00%> (ø)
include/slang/ast/symbols/ValueSymbol.h 100.00% <100.00%> (ø)
source/ast/Compilation.cpp 96.74% <100.00%> (+0.01%) ⬆️
source/ast/symbols/MemberSymbols.cpp 97.57% <100.00%> (+0.10%) ⬆️
source/ast/symbols/ValueSymbol.cpp 98.03% <100.00%> (+0.13%) ⬆️

Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update f6e3510...7b7474f. Read the comment docs.

@likeamahoney likeamahoney force-pushed the feature/net-alias-duplication-check branch from 49d4723 to 16b72d5 Compare July 12, 2024 15:05
// Store any net alias bits to check it's possible intersections.
// Since alias statements can appear anywhere module instance statements can appears
// good option is to store aliased bits info in the module instance scope.
mutable AliasMap* aliasedBits;
Copy link
Owner

Choose a reason for hiding this comment

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

It seems unnecessary to have an alias map allocated for every instance. The rules about net alias overlap are global, so it seems fine to have just one alias map stored in the Compilation object that all aliases can access. Then you don't need a custom allocator for it either.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

reimplemented all in order to last commentary

@@ -2196,7 +2196,6 @@ NetAliasSymbol& NetAliasSymbol::fromSyntax(const ASTContext& parentContext,
if (!netType.isError()) {
SmallVector<const IdentifierNameSyntax*> implicitNetNames;
Expression::findPotentiallyImplicitNets(*expr, context, implicitNetNames);

Copy link
Owner

Choose a reason for hiding this comment

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

Random newline deletion seems unrelated to the rest of the diff

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

if (const auto* sym = processExpr(expr)) {
const auto& eSelExpr = expr.template as<ElementSelectExpression>();
// If value can't be evaluated that means it is unbounded
const auto evalVal = toInt(context.tryEval(eSelExpr.selector()));
Copy link
Owner

Choose a reason for hiding this comment

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

I don't think this is correct in all cases. An example is when there is multiple selections of a multi-dimensional array. It's actually pretty tricky to figure out the statically assigned bits of an arbitrary expression -- that's essentially what the ValueDriver code in ValueSymbol.cpp is doing to be able to issue multi-driven errors. It occurs to me that it may make more sense to use that code to implement the net alias check. You could add a new flag to AssignFlags that says it's a net alias and do the check for overlap there.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Great Idea! The solution was reimplemented according to it!

@likeamahoney likeamahoney force-pushed the feature/net-alias-duplication-check branch from 16b72d5 to 4dd5370 Compare July 16, 2024 12:18
Copy link
Owner

@MikePopoloski MikePopoloski left a comment

Choose a reason for hiding this comment

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

Ok yeah, this is way better. I left some additional comments to help simplify this a bit more.

@@ -7,6 +7,8 @@
//------------------------------------------------------------------------------
#include "slang/ast/symbols/ValueSymbol.h"

#include <iostream>
Copy link
Owner

Choose a reason for hiding this comment

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

The iostream include isn't needed right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

removed

@@ -136,7 +136,8 @@ void ASTContext::setAttributes(const Expression& expr,

void ASTContext::addDriver(const ValueSymbol& symbol, const Expression& longestStaticPrefix,
bitmask<AssignFlags> assignFlags) const {
if (flags.has(ASTFlags::NotADriver) || scope->isUninstantiated())
if ((flags.has(ASTFlags::NotADriver) && !assignFlags.has(AssignFlags::NetAlias)) ||
Copy link
Owner

Choose a reason for hiding this comment

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

I think you can get rid of this change if you simply don't use the NotADriver flag when binding the net alias expressions

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

@@ -2119,16 +2124,18 @@ std::span<const Expression* const> NetAliasSymbol::getNetReferences() const {
auto syntax = getSyntax();
SLANG_ASSERT(scope && syntax);

// TODO: there should be a global check somewhere that any given bit
// of a net isn't aliased to the same target signal bit multiple times.
bitwidth_t bitWidth = 0;
bool issuedError = false;
SmallVector<const Expression*> buffer;
ASTContext context(*scope, LookupLocation::after(*this),
ASTFlags::NonProcedural | ASTFlags::NotADriver);
Copy link
Owner

Choose a reason for hiding this comment

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

Down here, you can remove the NotADriver

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The flag is needed to skip the first alias (the leftmost one) in order to prevent FP. I left it, but remove it after the first iteration of the loop.

Copy link
Owner

Choose a reason for hiding this comment

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

I'm not following why the first alias expression should be exempt from the duplicate checking. There isn't anything special about the first alias vs any others; you can reverse the order without changing the behavior.

I do think we need more info included in the addDriver call though, since it's only an error if the overlap occurs with the same target net? Like you can alias the same range of bits from one net to multiple different nets, it's only error if it's the same nets each time. This example from the LRM I think won't pass with the current code?

module overlap(inout wire [15:0] bus16, inout wire [11:0] low12, high12);
alias bus16[11:0] = low12;
alias bus16[15:4] = high12;
endmodule

module overlap(inout wire [15:0] bus16, inout wire [11:0] low12, high12);
alias bus16 = {high12, low12[3:0]};
alias high12[7:0] = low12[11:4];
endmodule

Or maybe it will, but not if you reverse the ordering in the alias statements.


for (auto exprSyntax : syntax->as<NetAliasSyntax>().nets) {
for (auto exprSyntax : nets) {
auto& netRef = Expression::bind(*exprSyntax, context);
if (!netRef.requireLValue(context))
Copy link
Owner

Choose a reason for hiding this comment

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

And then here pass your new AssignFlag and then you won't need the additional addDriver call below I think.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

@likeamahoney likeamahoney force-pushed the feature/net-alias-duplication-check branch from 54382d4 to 1ea3267 Compare July 23, 2024 19:49
@@ -2144,6 +2159,21 @@ std::span<const Expression* const> NetAliasSymbol::getNetReferences() const {

netRef.visit(visitor);
buffer.push_back(&netRef);

if (exprSyntax != *nets.begin()) {
Copy link
Owner

Choose a reason for hiding this comment

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

This logic seems confusing to me; you really just need to check whether the same symbol appears in more than one of the net alias expressions right? The aliasedSyms map in the NetAliasVisitor is already tracking that; instead of insert_or_assign up above you can just check whether the insertion fails because the symbol already exists, in which case you can issue the error right there. Then you don't need any of this special casing for it here and the separate map tracking the same thing.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

solution was reimplemented by focusing on merge net alias expressions

aliasedSyms map logic was reduced from NetAliasVisitor

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My solution no longer ignores the leftoutermost net alias expression

Copy link
Contributor Author

Choose a reason for hiding this comment

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

To relate net alias expressions to existing alias sybmols, I used a comparison of their syntaxes

it's not a best solution but in this case it is possible, since in aliases all symbols are global nets from the point of view of the module, in the future we need to come up with a better comparator

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not following why the first alias expression should be exempt from the duplicate checking. There isn't anything special about the first alias vs any others; you can reverse the order without changing the behavior.

I do think we need more info included in the addDriver call though, since it's only an error if the overlap occurs with the same target net? Like you can alias the same range of bits from one net to multiple different nets, it's only error if it's the same nets each time. This example from the LRM I think won't pass with the current code?

module overlap(inout wire [15:0] bus16, inout wire [11:0] low12, high12);
alias bus16[11:0] = low12;
alias bus16[15:4] = high12;
endmodule

module overlap(inout wire [15:0] bus16, inout wire [11:0] low12, high12);
alias bus16 = {high12, low12[3:0]};
alias high12[7:0] = low12[11:4];
endmodule
Or maybe it will, but not if you reverse the ordering in the alias statements.

Provided example works correctly regardless of the alias permutations.

@@ -2119,16 +2124,18 @@ std::span<const Expression* const> NetAliasSymbol::getNetReferences() const {
auto syntax = getSyntax();
SLANG_ASSERT(scope && syntax);

// TODO: there should be a global check somewhere that any given bit
// of a net isn't aliased to the same target signal bit multiple times.
bitwidth_t bitWidth = 0;
bool issuedError = false;
SmallVector<const Expression*> buffer;
ASTContext context(*scope, LookupLocation::after(*this),
ASTFlags::NonProcedural | ASTFlags::NotADriver);
Copy link
Owner

Choose a reason for hiding this comment

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

I'm not following why the first alias expression should be exempt from the duplicate checking. There isn't anything special about the first alias vs any others; you can reverse the order without changing the behavior.

I do think we need more info included in the addDriver call though, since it's only an error if the overlap occurs with the same target net? Like you can alias the same range of bits from one net to multiple different nets, it's only error if it's the same nets each time. This example from the LRM I think won't pass with the current code?

module overlap(inout wire [15:0] bus16, inout wire [11:0] low12, high12);
alias bus16[11:0] = low12;
alias bus16[15:4] = high12;
endmodule

module overlap(inout wire [15:0] bus16, inout wire [11:0] low12, high12);
alias bus16 = {high12, low12[3:0]};
alias high12[7:0] = low12[11:4];
endmodule

Or maybe it will, but not if you reverse the ordering in the alias statements.

@likeamahoney likeamahoney force-pushed the feature/net-alias-duplication-check branch from 848e6c6 to 3a128e4 Compare August 1, 2024 15:29
@likeamahoney
Copy link
Contributor Author

closes #947

SlicedPort = 1 << 7
SlicedPort = 1 << 7,

// The assignment declares net alias
Copy link
Owner

Choose a reason for hiding this comment

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

Should use triple comments to make it show up in documentation, like other entries above.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

@@ -298,6 +299,9 @@ class SLANG_EXPORT ASTContext {
/// Various flags that control how AST creation is performed.
bitmask<ASTFlags> flags;

/// Placeholder for storing currently processed net alias
const NetAliasSymbol* netAlias = nullptr;
Copy link
Owner

Choose a reason for hiding this comment

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

It would be good to not add another member to ASTContext if we can help it, especially since net aliases are very rare. I think you should be able to reuse instanceOrProc for this. We can rename it to something more generic like "relevantSymbol" maybe and then you can set it when you create the specialized ASTContext for checking net aliases.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

removed


// Preprocessing net alias expressions to relate them to existing net aliases.
const NetAliasSymbol* current = this;
for (auto exprSyntax : nets) {
Copy link
Owner

Choose a reason for hiding this comment

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

The logic here still seems wrong. Consider this simple example:

module m;
    wire [1:0] a, b, c;
    alias a = b[1:0];
    alias c = b[1:0];
endmodule

which results in the following error (when it should not):

source:5:15: error: it is not allowed to specify an alias from an individual signal to itself or to specify a given alias more than once
    alias c = b[1:0];
              ^~~~~~
source:4:15: note: alias declared here
    alias a = b[1:0];
              ^~~~~~

I don't think this mergeOrAddNetAlias idea works or is even necessary really. We don't need a compilation-wide map. Each net can already track which bits have been aliased using the driver mechanism. I think what you need to do is to do an addDriver() call across the cartesian product of the aliases in a given net alias statement. Instead of the "containing symbol" being the net alias, instead you make it the net it's being aliased to.

As an example:

alias a = b = c;

you want the following sequence of addDriver calls to be made, where the argument here is what gets set as the "containing symbol" inside ValueDriver:
a.addDriver(b);
a.addDriver(c);
b.addDriver(a);
b.addDriver(c);
c.addDriver(a);
c.addDriver(b);

And then I think the existing logic will just do the right thing without the need for a global map or comparing syntax nodes to each other.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

sorry for delay

solution was reimplemented according to your suggestion

Copy link
Contributor Author

Choose a reason for hiding this comment

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

but i need to add more complex tests

Copy link
Contributor Author

Choose a reason for hiding this comment

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

and fix CI

Copy link
Contributor Author

Choose a reason for hiding this comment

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

CI was fixed and new tests were added

@likeamahoney likeamahoney force-pushed the feature/net-alias-duplication-check branch 3 times, most recently from 622f998 to cd0a5d0 Compare August 23, 2024 00:25
@likeamahoney likeamahoney force-pushed the feature/net-alias-duplication-check branch from 44d93ee to 677fa45 Compare August 23, 2024 11:22
@likeamahoney likeamahoney force-pushed the feature/net-alias-duplication-check branch 2 times, most recently from 8fed29e to 6cff3b3 Compare August 23, 2024 20:03
@likeamahoney likeamahoney force-pushed the feature/net-alias-duplication-check branch from 6cff3b3 to bc6e58e Compare August 23, 2024 20:21
@MikePopoloski MikePopoloski merged commit 528e209 into MikePopoloski:master Oct 23, 2024
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants