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

[Verif] Add formal test intent ops #7145

Merged
merged 17 commits into from
Jul 17, 2024
Merged

[Verif] Add formal test intent ops #7145

merged 17 commits into from
Jul 17, 2024

Conversation

dobios
Copy link
Member

@dobios dobios commented Jun 8, 2024

The goal of this PR is to introduce a first round of new test intent operations, for formal tests this time, to the verif dialect following this proposal document.

This first PR will start by simply adding the ops with some verifier tests. Future PRs on this will have to then add a PrepareForFormal pass, and make sure that only verif.formal ops are used for formal verification and ignored elsewhere.

The ops that have been added in this PR are:

  • verif.formal
  • verif.symbolic_val
  • verif.concrete_val

Feel free to let me know what you think!

Copy link
Member

@maerhart maerhart left a comment

Choose a reason for hiding this comment

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

Nice to see all this progress!
Just added some (nit-picky) comments about things I saw while quickly reading through it, maybe they are useful.

include/circt/Dialect/Verif/VerifOps.td Outdated Show resolved Hide resolved
include/circt/Dialect/Verif/VerifOps.td Outdated Show resolved Hide resolved
include/circt/Dialect/Verif/VerifOps.td Outdated Show resolved Hide resolved
include/circt/Dialect/Verif/VerifOps.td Outdated Show resolved Hide resolved
include/circt/Dialect/Verif/VerifOps.td Outdated Show resolved Hide resolved
include/circt/Dialect/Verif/VerifOps.td Outdated Show resolved Hide resolved
include/circt/Dialect/Verif/VerifOps.td Outdated Show resolved Hide resolved
include/circt/Dialect/Verif/VerifOps.td Outdated Show resolved Hide resolved
include/circt/Dialect/Verif/VerifOps.td Show resolved Hide resolved
include/circt/Dialect/Verif/VerifOps.td Show resolved Hide resolved
Copy link
Contributor

@TaoBi22 TaoBi22 left a comment

Choose a reason for hiding this comment

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

Excited to see where this leads!

include/circt/Dialect/Verif/VerifOps.td Outdated Show resolved Hide resolved
@dobios dobios changed the title [WIP][Verif]Add formal test intent ops [Verif]Add formal test intent ops Jul 16, 2024
@dobios dobios marked this pull request as ready for review July 16, 2024 00:43
@dobios dobios added the verif label Jul 16, 2024
@dobios dobios requested review from TaoBi22 and maerhart July 16, 2024 01:44
include/circt/Dialect/Verif/VerifOps.td Outdated Show resolved Hide resolved
include/circt/Dialect/Verif/VerifOps.td Outdated Show resolved Hide resolved
include/circt/Dialect/Verif/VerifOps.td Outdated Show resolved Hide resolved
include/circt/Dialect/Verif/VerifOps.td Outdated Show resolved Hide resolved
include/circt/Dialect/Verif/VerifOps.td Outdated Show resolved Hide resolved
let description = [{
This operation declares a symbolic input that can then be used to reason
about `hw.instance` inputs in a symbolic manner in future assertions and
assumptions. The result type must be explicitly marked.
Copy link
Member

Choose a reason for hiding this comment

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

Is this really specific to hw.instance or could it be any instance or a fully inlined design without and instance operation in the verif.formal?
It's probably a good idea to describe a bit more precisely how this symbolic value behaves over time. Is it fixed over all clock cycles, can it change at a clock edge, can it change at any time?

Copy link
Contributor

Choose a reason for hiding this comment

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

It's probably a good idea to describe a bit more precisely how this symbolic value behaves over time. Is it fixed over all clock cycles, can it change at a clock edge, can it change at any time?

Agreed. Guessing from when we spoke about it before that it can only change on a clock-edge - we might want to add another op for a value that's fixed over all cycles (e.g. for defining BMC inputs while making sure we're adhering to the right semantics but not having to create a new BV every cycle when it's not necessary), but that's probably a matter for later.

Copy link
Member Author

Choose a reason for hiding this comment

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

So would it be a good idea to split this into e.g. symbolic_input and symbolic_const or rather simply have symbolic_input take a boolean attribute const that can be defined using a special const keyword (similar to sync /async for registers?

Copy link
Member

Choose a reason for hiding this comment

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

Both approaches are fine, but we don't necessarily have to do that right now. I just wanted to make sure that the semantics of the op is well described in the documentation to avoid any confusions in the future.

Copy link
Contributor

Choose a reason for hiding this comment

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

Good point - personally I lean in favour of separate ops as a) I wouldn't say symbolic_input isn't a super clear name for a constant value (and it would nice to keep the clear mapping to SMT vs BTOR) and b) having two separate ops may just leave less room for confusion, but I'm very happy to be overruled!

Copy link
Member Author

Choose a reason for hiding this comment

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

Wouldn't we also be able to define a value that is only set once by using a symbolic input as the init value of a concrete input and then have the update value being simply constant?

Copy link
Member

Choose a reason for hiding this comment

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

Good point. By doing the following, right?

%0 = verif.symbolic_input : i32
%1 = verif.concrete_input %0, %1 : i32

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes exactly

Copy link
Contributor

Choose a reason for hiding this comment

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

This would work functionally - the disadvantage to me is that we'd have an unnecessary symbolic_input floating around, which I guess semantically in the case of model checking would require a new SMT var to be created for that input each cycle, though it wouldn't actually be used. We could pattern match for this case and optimize it away in VerifToSMT I guess, but it would mean we couldn't immediately reject symbolic_input ops which would be nice to do (since the meaning of that might get a little messy with the init/loop regions). Happy to just worry about this in the future though!

include/circt/Dialect/Verif/VerifOps.td Outdated Show resolved Hide resolved
This operation declares a concrete input that can then be used in the
reasoning surrounding symbolic inputs, allowing for a form of concolic
reasoning to take place in a `verif.formal` block. Concrete inputs are
defined by an initial value and an update function.
Copy link
Member

Choose a reason for hiding this comment

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

Can we specify when this update function is executed? Does this op effectively behave like a register with an implicit clock?

Copy link
Member Author

Choose a reason for hiding this comment

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

I see this as the op is executed on every "time-step" so it would be converted into a register with an implicit clock yes. I'm open to other ideas if you have any

Copy link
Member

Choose a reason for hiding this comment

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

In its current state one could argue that it's not really necessary because you could just use the regular register operation, but I think it's still useful to have it so we still know that it is an input and not just part of the design. Also, providing the clock for the regular register would probably require a block argument from verif.formal. So, I'd leave it as is. I just think, it'd just be nice to describe this implicit clock and how the value updating works a bit more in the description. Basically, verif.formal provides an implicit base clock and the symbolic and concrete operations provide values for all inputs (including the actual clocks) based on this implicit clock.

include/circt/Dialect/Verif/VerifOps.td Outdated Show resolved Hide resolved
test/Dialect/Verif/basic.mlir Outdated Show resolved Hide resolved
Copy link
Contributor

@TaoBi22 TaoBi22 left a comment

Choose a reason for hiding this comment

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

Looking good! @maerhart covered most of my thoughts but a couple of other small points!

include/circt/Dialect/Verif/VerifOps.td Outdated Show resolved Hide resolved
include/circt/Dialect/Verif/VerifOps.td Show resolved Hide resolved
Additional information about how the test should be conducted can be passed
using the two supported attributes. These attributes are `k`, which defines
the bounds of the test, and `type` which defines the type of formal test
being done, i.e. Bounded Model Checking (BMC) or k-Induction.
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: happy to be overruled on grounds of repetition but it might be nice to say the syntax here, just makes the docs slightly easier to digest

let description = [{
This operation declares a symbolic input that can then be used to reason
about `hw.instance` inputs in a symbolic manner in future assertions and
assumptions. The result type must be explicitly marked.
Copy link
Contributor

Choose a reason for hiding this comment

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

It's probably a good idea to describe a bit more precisely how this symbolic value behaves over time. Is it fixed over all clock cycles, can it change at a clock edge, can it change at any time?

Agreed. Guessing from when we spoke about it before that it can only change on a clock-edge - we might want to add another op for a value that's fixed over all cycles (e.g. for defining BMC inputs while making sure we're adhering to the right semantics but not having to create a new BV every cycle when it's not necessary), but that's probably a matter for later.

@dobios dobios changed the title [Verif]Add formal test intent ops [Verif] Add formal test intent ops Jul 17, 2024
include/circt/Dialect/Verif/VerifOps.td Outdated Show resolved Hide resolved
include/circt/Dialect/Verif/VerifOps.td Outdated Show resolved Hide resolved
include/circt/Dialect/Verif/VerifOps.td Outdated Show resolved Hide resolved
include/circt/Dialect/Verif/VerifOps.td Outdated Show resolved Hide resolved
include/circt/Dialect/Verif/VerifOps.td Outdated Show resolved Hide resolved
include/circt/Dialect/Verif/VerifOps.td Outdated Show resolved Hide resolved
include/circt/Dialect/Verif/VerifOps.td Outdated Show resolved Hide resolved
include/circt/Dialect/Verif/VerifOps.td Outdated Show resolved Hide resolved
include/circt/Dialect/Verif/VerifOps.td Outdated Show resolved Hide resolved
@dobios dobios merged commit 815da47 into main Jul 17, 2024
4 checks passed
@dobios dobios deleted the dev/dobios/new-verif-ops branch July 17, 2024 22:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants