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

[FIRRTL] Fix sub-* op in layer block verifier #7462

Merged
merged 1 commit into from
Aug 9, 2024

Conversation

seldridge
Copy link
Member

@seldridge seldridge commented Aug 8, 2024

Fix issues with verification of subfield, subindex, and subaccess
operations which appear in a layer block. These operations are allowed to
occur in a layer block even if they capture non-passive operands.

This requires reworking layer block verification to no longer check for
operations using non-passive operands. The spec requires that no
operation in a layer block drives a value declared outside the layer
block. However, this is exceedingly difficult to verify due to the fact
that non-passive destinations in ConnectLike operations can be
source-to-destination, destination-to-source, or bi-directional. If the
verifier sees this, just allow it. The FIRRTL pass pipeline will later
canonicalize away flips (i.e., make all types passive) which will then
allow the verifier to check these. This should be revisited in the
future.

Fixes #7451.

Metadata

The commits are in logical order and can be reviewed independently.

Copy link
Contributor

@dtzSiFive dtzSiFive left a comment

Choose a reason for hiding this comment

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

LGTM!

The language about "passive captures" threw me a bit, looks like that's dropped which makes sense to me!

This sort of thing is tricky to do appropriately generically presently (if rvalues were separate from lvalues, that sort of thing) but I think this looks right to me!

include/circt/Support/Utils.h Outdated Show resolved Hide resolved
lib/Dialect/FIRRTL/FIRRTLOps.cpp Outdated Show resolved Hide resolved
lib/Dialect/FIRRTL/FIRRTLOps.cpp Outdated Show resolved Hide resolved
lib/Dialect/FIRRTL/FIRRTLOps.cpp Outdated Show resolved Hide resolved
lib/Dialect/FIRRTL/FIRRTLOps.cpp Outdated Show resolved Hide resolved
// We can drive any destination inside the current layerblock.
// Verify that connects only drive values declared in the layer block.
// If we see a non-passive connect destination, then verify that the
// source is in the same layer block so that the source is not driven.
Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for this comment explaining why the passivity of the operand is being checked!
(and great explanation in PR body, 🙇 )

I was going to file issues but I'll leave these examples here (and less sure about them, WDYT?) -- they seem like they ... could be supported? It depends on whether driving a bundle with only flip elements (similarly a bundle with zero-width but flipped element) counts as violating the rules re:layer.

Non-passive but only leaf connection is into the layer:

FIRRTL version 4.0.0

circuit LF:
  layer T, bind :
  public module LF:
    output o : { flip x : UInt<1> }

    layerblock T :
      wire w : { flip x : UInt<1> }
      connect o, w

Similarly:

FIRRTL version 4.0.0

circuit LF:
  layer L, bind :

  type T = { flip a : { flip b : UInt<5> } }

  extmodule Sink:
    input in : UInt<5>
  public module LF:
    input x : T

    layerblock L:
      inst s of Sink
      connect s.in, x.a.b

Anyway looks like the "passive capture" rule is an verifier optimization to avoid having to chase/check too many operations in the common case.

Gosh, having this reliably sorted would really make this simpler -- really don't want to have to teach this verifier how to understand "connect" in all it's glory.

Anyway it's arguable that connecting bundle isn't the same as connecting its elements (the framing here changes AFAICT in different contexts) in which case these should be rejected.

Onwards!

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 think the PR is just wrong. I had started to write his using foldFlow which I think is how it has to work if the operation is a connect. The check for matchingconnect and simpler operations is easier. Let me dig into this.

Copy link
Member Author

Choose a reason for hiding this comment

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

foldFlow isn't quite right either. In order for this to work correctly, it needs to know if something is a source, sink, or duplex. However, this isn't the usual foldFlow computation which looks up towards the declaration, but looks down towards the leaves of the type.

It's annoying because I think it would be just a passive check if type canonicalization was possible.

Copy link
Member Author

Choose a reason for hiding this comment

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

This is exceedingly annoying to verify... It requires examining the type in detail. In this PR, I opted to not verify this. I don't like this, however, non-passive types are incredibly short-lived in the compiler. These are almost immediately removed due to everything becoming matchingconnect. This saves some tedious, expensive verification for a code path that is pretty rare.

I put a massive TODO in the code explaining this and will expect to revisit this in the future.

I'd like to merge this as-is and we can tighten this up later.

Copy link
Contributor

Choose a reason for hiding this comment

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

Sounds good!

if (isAncestor(getOperation(), dest)) {
if (passive)
return WalkResult::advance();
dest = getFieldRefFromValue(connect.getSrc()).getValue();
Copy link
Contributor

Choose a reason for hiding this comment

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

These may want to look through casts to chase to the actual defining op? Maybe future work.

Copy link
Member Author

Choose a reason for hiding this comment

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

Agree. I'll put this in the future work bucket.

test/Dialect/FIRRTL/layers.mlir Show resolved Hide resolved
lib/Support/CMakeLists.txt Outdated Show resolved Hide resolved
@seldridge seldridge force-pushed the dev/seldridge/issue-7451 branch 2 times, most recently from eaaad49 to fcb92a0 Compare August 9, 2024 04:27
@seldridge seldridge requested review from dtzSiFive and darthscsi and removed request for darthscsi August 9, 2024 04:29
Fix issues with verification of subfield, subindex, and subaccess
operations which appear in a layer block.  These operations are allowed to
occur in a layer block even if they capture non-passive operands.

This requires reworking layer block verification to no longer check for
operations using non-passive operands.  The spec requires that no
operation in a layer block _drives_ a value declared outside the layer
block.  However, this is exceedingly difficult to verify due to the fact
that non-passive destinations in ConnectLike operations can be
source-to-destination, destination-to-source, or bi-directional.  If the
verifier sees this, just allow it.  The FIRRTL pass pipeline will later
canonicalize away flips (i.e., make all types passive) which will then
allow the verifier to check these.  This should be revisited in the
future.

Fixes #7451.

Signed-off-by: Schuyler Eldridge <[email protected]>

Don't check non-passive connects.
@seldridge seldridge force-pushed the dev/seldridge/issue-7451 branch from fcb92a0 to a6028ee Compare August 9, 2024 16:06
@seldridge seldridge merged commit a6028ee into main Aug 9, 2024
4 checks passed
@seldridge seldridge deleted the dev/seldridge/issue-7451 branch August 9, 2024 16:22
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.

[FIRRTL] Layer Sink can sink subfield which is "non passive"
2 participants