Skip to content

[ImportVerilog] Look through labels on module-level concurrent assertions#10796

Open
AmurG wants to merge 1 commit into
llvm:mainfrom
AmurG:ripe/importverilog-robustness
Open

[ImportVerilog] Look through labels on module-level concurrent assertions#10796
AmurG wants to merge 1 commit into
llvm:mainfrom
AmurG:ripe/importverilog-robustness

Conversation

@AmurG

@AmurG AmurG commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

A statement label on a module-level concurrent assertion wraps it in a single-statement block, which defeats the module-scope conversion short-circuit. On current main the labeled assertion converts inside a moore.procedure always while its unlabeled twin converts at module scope, so a label silently changes which lowering an assertion gets:

module top(input logic clk, input logic a, input logic b);
  assert property (@(posedge clk) a |-> b);       // verif.clocked_assert at module scope
  CHK: assert property (@(posedge clk) a |-> b);  // same ops, nested in moore.procedure
endmodule

Labeled checkers are the norm in verification IP, and our own builtins.sv documents the artifact: its 19 labeled sampled-value assertions pin moore.procedure always wrappers that their unlabeled equivalents would not get.

Look through label blocks in the synthesized always wrapper so labeled and unlabeled assertions take the same path; for a body that reduces to a single concurrent assertion the two forms are equivalent (IEEE 1800-2017 16.14.6). Assertions in initial/final procedures keep their one-attempt semantics and are deliberately not rerouted.

Tested: new labeled-concurrent-assertions.sv (labeled == unlabeled at module scope; initial-block form not rerouted); builtins.sv expectations updated to the module-scope form (same per-assertion op chains, each block anchored on its ltl.clock + verif.assert).

Written with AI assistance; I've reviewed the diff and tests.

…ions

A statement label on a module-level concurrent assertion (`CHK: assert
property (p);` -- the ubiquitous verification-IP checker idiom) wraps
the assertion in a single-statement block, which defeats the
module-scope conversion short-circuit: the labeled assertion converts
inside a `moore.procedure always` while its unlabeled twin converts at
module scope, so a label silently changes which lowering an assertion
gets and module-scope consumers of the assertion ops never see labeled
checkers. Our own builtins.sv test documents the artifact: its labeled
sampled-value assertions are pinned inside procedure wrappers that
their unlabeled equivalents would not get.

Look through label blocks in the synthesized `always` wrapper so
labeled and unlabeled assertions take the same path; for a body that
reduces to a single concurrent assertion the two forms are equivalent
(IEEE 1800-2017 16.14.6). Assertions in initial/final procedures keep
one-attempt semantics and are deliberately NOT rerouted -- pinned in
the new test.

builtins.sv expectations updated: the sampled-value assertion checks
lose their `moore.procedure always` wrappers (same op chains, now at
module scope like their unlabeled forms). New test
labeled-concurrent-assertions.sv pins labeled==unlabeled and the
initial-block non-reroute.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@circt-bot

circt-bot Bot commented Jul 8, 2026

Copy link
Copy Markdown

Results of circt-tests run for 9b73522 compared to results for 01b5614: no change to test results.

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.

1 participant