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] Add CheckRecursiveInstantiation diagnostic pass #7433

Merged
merged 3 commits into from
Aug 15, 2024

Conversation

youngar
Copy link
Member

@youngar youngar commented Aug 4, 2024

This adds a pass to FIRRTL to check for recursive module instantiation,
which is illegal because it corresponds to infinitely sized hardware.
This uses the path based strongly connected component (SCC) algorithm
with some extra book keeping to track if there was a loop in the current
SCC or not. This is especially helpful to detect if a single-element
SCC actually contains a loop or not.

This does not use the upstream SCCIterator because we hope that this
version of the algorithm is faster by a constant factor, we don't need
to visit the SCCs in post-order, and hopefully faster handling of cycles
in single-element SCCs (which requires re-scanning all edges from a node
using the upstream version).

@youngar youngar added the FIRRTL Involving the `firrtl` dialect label Aug 4, 2024
@youngar youngar force-pushed the firrtl-recursive-modules branch 2 times, most recently from ce41394 to 621e009 Compare August 4, 2024 20:28
@youngar
Copy link
Member Author

youngar commented Aug 4, 2024

This does not support InstanceChoice, as the InstanceGraph itself does not support it yet.

firrtl.instance b @B()
}
// expected-error @below {{recursive instantiation}}
firrtl.module @B() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Modules are public unless explicitly marked private, so I'm not sure what tests are intended but if these are meant to test re:private they should be updated, and if not a test or two for those cases seems warranted.

Copy link
Member Author

@youngar youngar Aug 5, 2024

Choose a reason for hiding this comment

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

hmm interesting. I am guessing my code is wrong, because I am specifically checking if the visibility is public.

    // Check if the current node is public.
    if (SymbolTable::getSymbolVisibility(node->getModule<Operation *>()) ==
        SymbolTable::Visibility::Public) {
      it->getSecond() = 0;
      return 0;
    }

edit to say: code looks fine, getSymbolVisibility will return public if the attr is not there. Just need to update the test case.

Copy link
Member Author

@youngar youngar Aug 5, 2024

Choose a reason for hiding this comment

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

I think this test is not working because of my depth heuristic, which is what this is meant to test, but due to the path based SCC returning nodes in pre-order. I probably need to move my top level module down to the bottom of the test case.

Copy link
Member Author

@youngar youngar Aug 5, 2024

Choose a reason for hiding this comment

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

Updated the test case as mentioned, and discovered that the depth calculation was not working 😭 Hooray for tests. Anyways, pushed a fix for that, and also renamed my test files to match the name of the pass (went through a couple different names).

@youngar
Copy link
Member Author

youngar commented Aug 5, 2024

I keep thinking about it, I think my depth heuristic (specifically my implementation of it) can return the wrong results if there is an SCC instantiating another SCC. I might rework this later when I have time.

@seldridge
Copy link
Member

seldridge commented Aug 5, 2024

This does not use the upstream SCCIterator because we hope that this
version of the algorithm is faster by a constant factor, we don't need
to visit the SCCs in post-order, and hopefully faster handling of cycles
in single-element SCCs (which requires re-scanning all edges from a node
using the upstream version).

This is worth weighing against the overhead of having another SCC implementation. If the single-element SCC is a concern, then that can be handled with a non-SCC-based pass over the modules to check for trivial self-instantiation. This could then fallback to the upstream algorithm for deeper analysis which can then assume no single-element SCCs. Alternatively, self-instantiation can be an InstanceOp verifier that checks the parent module op.

More of a thought than anything.

I weighed similar concerns with using a new SCC for layer sink and settled on the opposite finding: it was better to struggle with upstream graph traits for reasons of maintainability.

@youngar
Copy link
Member Author

youngar commented Aug 7, 2024

Ran some benchmarking, my version of the SCC was only about 25% faster, so I swapped this to use the upstream SCCIterator. As a side effect of this, this code does not find any cycles that are not reachable from the top level module.

I also removed the depth heuristic to keep the pass simple.

@youngar youngar force-pushed the firrtl-recursive-modules branch 2 times, most recently from 4062f89 to f150925 Compare August 8, 2024 00:47
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

This removes a verifier that checks that modules do not instantiate
themsselves.  This will be covered by a new diagnostic pass which can
handle indirect recursion as well.  This instance verifier goes a bit
beyond what we normally check in verifiers, as it must reach upward to
find the owning module to compare against its target module, and we
normally try to check only local operation properties in verifiers.
This adds a pass to FIRRTL to check for recursive module instantiation,
which is illegal because it corresponds to infinitely sized hardware.
@youngar youngar merged commit 669d7e7 into llvm:main Aug 15, 2024
4 checks passed
@youngar youngar deleted the firrtl-recursive-modules branch August 15, 2024 18:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
FIRRTL Involving the `firrtl` dialect
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants