Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

Scheremo
Copy link
Contributor

@Scheremo Scheremo commented Sep 21, 2025

This commit adds support for lowering $rose $stable and $fell from assertion contexts into LTL.
To this end, this PR adds a new operation for look-back semantics, ltl.PastOp.

  • New op
    • ltl.past: takes an integer and a delay, returning the sequence observed $delay cycles earlier.
  • Assertion system call lowering
    • Added Context::convertAssertionSystemCallArity1 to map single-argument system calls into LTL constructs:
      • $rose(x)x ∧ ¬past(x,1)
      • $fell(x)¬x ∧ past(x,1)
      • $stable(x)(x ∧ past(x,1)) ∨ (¬x ∧ ¬past(x,1))
    • Integrated into convertAssertionCallExpression to dispatch on $rose/$fell/$stable from the AST.
  • Conversion plumbing
    • Added entry point convertAssertionCallExpression to Context.
    • Adjusted Expressions.cpp visitor to recognize these system calls and redirect them to the new assertion conversion path.
  • Tests
    • Extended builtins.sv with assertions using $rose, $fell, $stable.
    • CHECK lines verify correct lowering into ltl.past, ltl.not, ltl.and, ltl.or sequences.

@Scheremo Scheremo force-pushed the pr-sampled-value branch 2 times, most recently from bd09846 to f80e221 Compare September 21, 2025 14:58
This commit adds support for lowering `$rose` `$stable` and `$fell` from assertion contexts into LTL.
To this end, this PR adds a new operation for look-back semantics, `ltl.PastOp`.

* **New op**
  * `ltl.past`: takes a sequence and an integer delay, returning the sequence observed `$delay` cycles earlier.
* **Assertion system call lowering**
  * Added `Context::convertAssertionSystemCallArity1` to map single-argument system calls into LTL constructs:
    * `$rose(x)` → `x ∧ ¬past(x,1)`
    * `$fell(x)` → `¬x ∧ past(x,1)`
    * `$stable(x)` → `(x ∧ past(x,1)) ∨ (¬x ∧ ¬past(x,1))`
  * Integrated into `convertAssertionCallExpression` to dispatch on `$rose/$fell/$stable` from the AST.
* **Conversion plumbing**
  * Added entry point `convertAssertionCallExpression` to `Context`.
  * Adjusted `Expressions.cpp` visitor to recognize these system calls and redirect them to the new assertion conversion path.
* **Tests**
  * Extended `builtins.sv` with assertions using `$rose`, `$fell`, `$stable`.
  * CHECK lines verify correct lowering into `ltl.past`, `ltl.not`, `ltl.and`, `ltl.or` sequences.
@Scheremo Scheremo marked this pull request as ready for review September 21, 2025 16:04
@sequencer
Copy link
Contributor

I think this PR should be implemented after the #8673 is finished. Wdyt?

Copy link
Contributor

@fabianschuiki fabianschuiki left a comment

Choose a reason for hiding this comment

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

LGTM! Only a minor comment on past on sequences.


def PastOp : LTLOp<"past", [Pure]> {
let arguments = (ins
LTLAnySequenceType:$input,
Copy link
Contributor

@fabianschuiki fabianschuiki Sep 21, 2025

Choose a reason for hiding this comment

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

What are the semantics of ltl.past when used on a sequence instead of a boolean? Does that mean the sequence must have finished matching in the previous cycle? And how would we print an ltl.past with a sequence input back as Verilog?

If I remember correctly, the $past function in Verilog only operates on booleans. In that case it might make sense to make ltl.past operate on just i1 for now. It's always easier to start with an overconstrained op and relax later, than figuring out semantics later 😃

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's a fair point, I'll limit it to i1 for this PR!

@fabianschuiki
Copy link
Contributor

fabianschuiki commented Sep 21, 2025

I think this PR should be implemented after the #8673 is finished. Wdyt?

@sequencer Good point, this also has the concerning quality of magically inferring what clock the $past refers to. Since #8673 has to do an overhaul of all implicitly clocked ops anyway, I think it would make sense to not block this PR behind #8673 and just add ltl.past to the list of ops that will need a clock there. Otherwise we create a dependency between the PRs which might not be necessary.

Do you have an idea how we could do that clock inference in ImportVerilog? Would we apply the clock inference rules of the SV standard and search for a parent construct that has a clock, and then use that when we create the LTL ops?

@Scheremo
Copy link
Contributor Author

Scheremo commented Sep 21, 2025

I think this PR should be implemented after the #8673 is finished. Wdyt?

Hi, I wasn't aware of the discussion in #8673. It's clearly important & useful work, but judging from the duration from opening until now (2.5 months) I would suppose it will take some time to land.
I tend to agree with Fabian's viewpoint that the semantic issue of past is the same as delay, and adjusting both at once seems reasonable. I would argue having more existing test surface for refactoring/restructuring the dialect by merging this PR might actually be helpful. From my personal point of view having at least intermediate support for rose, fell, and stable is very useful, as lots of SV code use these constructs.
Does that seem reasonable to you?

@MikePopoloski
Copy link

FWIW slang implements all of the clock flow and clock inference rules from the LRM in its analysis layer, e.g. https://github.com/MikePopoloski/slang/blob/6637781e9315193e6ca2cfd3128d91eb05acd41a/source/analysis/AnalyzedAssertion.cpp#L269 (and yes, the rules are arcane and messy).

This is not easily exposed via a nice API at the moment, mostly because I wasn't sure how downstream consumers would like it to be presented. I'm happy to accept a proposal for how that information could be extracted and made usable by the ImportVerilog pass.

@fabianschuiki
Copy link
Contributor

FWIW slang implements all of the clock flow and clock inference rules from the LRM in its analysis layer

@MikePopoloski Reusing this from Slang would be absolutely fantastic 🥳. Not having to go through all the pain of distilling out those rules again, and instead helping maintain a single implementation sounds much more reasonable.

ImportVerilog simply walks the AST and conjures up IR ops along the way. It would be nice if we could either run the analysis for asserts and sampled value funcs as we encounter them, and then basically ask what the implied clock is, or if we could run the analysis once on the entire AST, and then just query that analysis for the implied clocks. Would something like that make sense?

@fabianschuiki
Copy link
Contributor

I think I'm going to land this now to not hold up subsequent work. Hope that's okay with you, @sequencer!

@fabianschuiki fabianschuiki merged commit 7615252 into llvm:main Sep 22, 2025
7 checks passed
@MikePopoloski
Copy link

FWIW slang implements all of the clock flow and clock inference rules from the LRM in its analysis layer

@MikePopoloski Reusing this from Slang would be absolutely fantastic 🥳. Not having to go through all the pain of distilling out those rules again, and instead helping maintain a single implementation sounds much more reasonable.

ImportVerilog simply walks the AST and conjures up IR ops along the way. It would be nice if we could either run the analysis for asserts and sampled value funcs as we encounter them, and then basically ask what the implied clock is, or if we could run the analysis once on the entire AST, and then just query that analysis for the implied clocks. Would something like that make sense?

Yes, the AnalysisManager runs in one pass once the AST is fully constructed. The question is how to store and query the results of the assertion analysis.

@fabianschuiki
Copy link
Contributor

Could we populate a hash map with the analysis results for each relevant AST node? Something that makes it easy to later pick up one of the asserts or sampled value function calls, and ask the analysis for the stored information associated with that.

If the analysis is just visiting the AST and generating diagnostics, you could also leave the burden of storing the analysis results in a meaningful format to the user by accepting a callback function that the analysis calls whenever it has gathered some information. ImportVerilog could then supply its own callback that just stores the info in a format convenient for it.

On the other hand, I could see other users of Slang be interested in this info. Having the analysis result stored in some form on the Slang side would be useful for that.

@MikePopoloski
Copy link

I opened MikePopoloski/slang#1528 to track adding the API. I'm leaning toward a callback but we'll see how it looks when I start working on it.

@Scheremo
Copy link
Contributor Author

I opened MikePopoloski/slang#1528 to track adding the API. I'm leaning toward a callback but we'll see how it looks when I start working on it.

You're a legend, Mike! Let us know if we can help in any way.

@Scheremo Scheremo deleted the pr-sampled-value branch October 21, 2025 07:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants