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] Fix static subroutine local variables multiple assigns and reduce MultipleAlwaysAssigns diag severity #903

Closed
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
4 changes: 2 additions & 2 deletions scripts/diagnostics.txt
Original file line number Diff line number Diff line change
Expand Up @@ -665,7 +665,6 @@ error InOutVarPortConn "'{}' cannot be connected to 'inout' port (only nets are
error InOutUWireConn "'uwire' net '{}' cannot be connected to 'inout' port"
error MixedVarAssigns "cannot mix continuous and procedural assignments to variable '{}'"
error MultipleContAssigns "cannot have multiple continuous assignments to variable '{}'"
error MultipleAlwaysAssigns "variable '{}' driven by {} procedure cannot be written to by any other process"
error MultipleUWireDrivers "'uwire' net '{}' cannot have multiple drivers"
error MultipleUDNTDrivers "net '{}' with user-defined nettype '{}' cannot have multiple drivers because it does not specify a resolution function"
error InputPortAssign "cannot assign to input port '{}'"
Expand Down Expand Up @@ -705,6 +704,7 @@ warning sign-conversion SignConversion "implicit conversion changes signedness f
warning float-bool-conv FloatBoolConv "implicit conversion from floating point type {} to boolean value"
warning int-bool-conv IntBoolConv "implicit conversion from {} to boolean value"
warning useless-cast UselessCast "useless cast from {} to the same type"
warning multiple-always-assigns MultipleAlwaysAssigns "variable '{}' driven by {} procedure cannot be written to by any other process"

subsystem Statements
error ReturnNotInSubroutine "return statement is only valid inside task and function blocks"
Expand Down Expand Up @@ -1060,7 +1060,7 @@ group default = { real-underflow real-overflow vector-overflow int-overflow unco
raw-protect-eof protected-envelope specify-param dup-timing-path invalid-pulsestyle
negative-timing-limit bad-procedural-force duplicate-defparam implicit-port-type-mismatch
split-distweight-op dpi-pure-task multibit-edge unknown-sys-name unknown-library
dup-config-rule }
dup-config-rule multiple-always-assigns }

group extra = { empty-member empty-stmt dup-import pointless-void-cast case-gen-none case-gen-dup
unused-result format-real ignored-slice task-ignored width-trunc dup-attr event-const
Expand Down
15 changes: 15 additions & 0 deletions scripts/warning_docs.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1162,3 +1162,18 @@ config cfg;
instance d.foo use baz;
endconfig
```

-Wmultiple-always-assigns
Detects that variables on the left-hand side of assignments within an procedure blocks,
including variables from the contents of a called functions, shall not be written to by any other process.
```
module m(input clk, input rst);
logic i;
always_ff @(posedge clk) begin
i <= 1;
end
always_ff @(posedge rst) begin
i <= 2;
end
endmodule
```
3 changes: 1 addition & 2 deletions source/ast/expressions/CallExpression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -372,8 +372,7 @@ Expression& CallExpression::fromArgs(Compilation& compilation, const Subroutine&
// If this subroutine is invoked from a procedure, register drivers for this
// particular procedure to detect multiple driver violations.
if (!thisClass) {
if (auto proc = context.getProceduralBlock();
proc && proc->isSingleDriverBlock() && !context.scope->isUninstantiated()) {
if (auto proc = context.getProceduralBlock(); proc && !context.scope->isUninstantiated()) {
addSubroutineDrivers(*proc, symbol, *result);
}
}
Expand Down
2 changes: 1 addition & 1 deletion tests/unittests/ast/MemberTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1915,7 +1915,7 @@ endmodule
auto& diags = compilation.getAllDiagnostics();
std::string result = "\n" + report(diags);
CHECK(result == R"(
source:14:17: error: variable 'foo' driven by always_comb procedure cannot be written to by any other process
source:14:17: warning: variable 'foo' driven by always_comb procedure cannot be written to by any other process [-Wmultiple-always-assigns]
always_comb i.foo = 1;
^~~~~
note: from 'm.n2' and 'm.n1'
Expand Down
80 changes: 80 additions & 0 deletions tests/unittests/ast/SubroutineTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -708,3 +708,83 @@ endmodule
CHECK(diags[0].code == diag::MultipleAlwaysAssigns);
CHECK(diags[1].code == diag::MultipleAlwaysAssigns);
}

TEST_CASE("driver checking applied to static function args (always_ff and always_ff)") {
auto tree = SyntaxTree::fromText(R"(
module m(input clk, input rst);
function logic f(logic a);
logic b;
b = a;
return b;
endfunction

logic i, j;
always_ff @(posedge clk) begin
i <= f(i);
end
always_ff @(posedge rst) begin
j <= f(j);
end
endmodule
)");

Compilation compilation;
compilation.addSyntaxTree(tree);

auto& diags = compilation.getAllDiagnostics();
REQUIRE(diags.size() == 1);
CHECK(diags[0].code == diag::MultipleAlwaysAssigns);
}

TEST_CASE("driver checking applied to static function local variables (always_ff and always)") {
auto tree = SyntaxTree::fromText(R"(
module m(input clk, input rst);
function logic f(logic a);
logic b;
b = a;
return b;
endfunction

logic i, j;
always @(posedge clk) begin
i <= f(i);
end
always_ff @(posedge rst) begin
j <= f(j);
end
endmodule
)");

Compilation compilation;
compilation.addSyntaxTree(tree);

auto& diags = compilation.getAllDiagnostics();
REQUIRE(diags.size() == 1);
CHECK(diags[0].code == diag::MultipleAlwaysAssigns);
}

TEST_CASE("driver checking applied to static function local variables (always and always)") {
auto tree = SyntaxTree::fromText(R"(
module m(input clk, input rst);
function logic f(logic a);
logic b;
b = a;
return b;
endfunction

logic i, j;
always @(posedge clk) begin
i <= f(i);
end
always @(posedge rst) begin
j <= f(j);
end
endmodule
)");

Compilation compilation;
compilation.addSyntaxTree(tree);

auto& diags = compilation.getAllDiagnostics();
REQUIRE(diags.size() == 0);
}
Loading