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

implementation of an AST -> SCFG transformer #114

Merged
merged 22 commits into from
Apr 29, 2024
Merged

implementation of an AST -> SCFG transformer #114

merged 22 commits into from
Apr 29, 2024

Conversation

esc
Copy link
Member

@esc esc commented Apr 19, 2024

AST: Python Abstract Synatx Tree
(S)CFG: (Structured) Control Flow Graph

Items to note for reviewers:

  • Most of changes are in the ast_transforms.py module which contains the meat of the implementation.
  • Temporary data structures are created for a pure AST based CFG (ASTCFG) with blocks that are writable. This made it much easier to implement the builder pattern. They can easily be converted to a SCFG using the ASTCFG.to_SCFG() function.
  • The AST2SCFGTranformer is stateful and is populated with housekeeping data structures post transform.
  • The tests are all in test_ast_transforms.py. They are of the usual format: Python function as input and serialized graph to compare to.
  • The tests also check the values of the unreachable and empty nodes that have been pruned from the CFG.
  • The for-loop decomposition is a bit involved, hence there is an extensive docstring to describe what it does.
  • Some minor changes had to be made to the scfg.py module to support displaying "broken" SCFGs during development. This makes it easier to visually debug the graph upon making programming mistakes.
  • The modules basic_block.py and rendering.py were modified to support construction and visualization of the PythonASTBlock, which is a new block type for the SCFG that contains a block derived from Python AST.
  • The central entrypoint is: AST2CFG(function) -> SCFG . This will turn a Python function into an SCFG.
  • A stub has been added for the invserse, SCFG -> AST transformer.

Example:

from numba_rvsdg import AST2SCFG
def fun():
    ...
scfg = AST2SCFG(fun)
scfg.render()
scfg.restructure()
scfg.render()

AST: Python Abstract Synatx Tree
(S)CFG: (Structured) Control Flow Graph

Items to note for reviewers:

* Most of changes are in the `ast_transforms.py` module which contains
  the meat of the implementation.
* Temporary data structures are created for a pure AST based CFG
  (`ASTCFG`) with blocks that are writable. This made it much easier to
  implement the builder pattern. They can easily be converted to a SCFG
  using the `ASTCFG.to_SCFG()` function.
* The `AST2SCFGTranformer` is stateful and is populated with
  housekeeping data structures post transform.
* The tests are all in `test_ast_transforms.py`. They are of the usual
  format: Python function as input and serialized graph to compare to.
* The tests also check the values of the unreachable and empty nodes
  that have been pruned from the CFG.
* The for-loop decomposition is a bit involved, hence there is an
  extensive docstring to describe what it does.
* Some minor changes had to be made to the `scfg.py` module to support
  displaying "broken" SCFGs during development. This makes it easier to
  visually debug the graph upon making programming mistakes.
* The modules `basic_block.py` and `rendering.py` were modified to
  support construction and visualization of the `PythonASTBlock`, which
  is a new block type for the SCFG that contains a block derived from
  Python AST.
* The central entrypoint is: `AST2CFG(function) -> SCFG `. This will
  turn a Python function into an SCFG.
* A stub has been added for the invserse, SCFG -> AST transformer.

Example:

```python
from numba_rvsdg import AST2SCFG
def fun():
    ...
scfg = AST2SCFG(fun)
scfg.render()
scfg.restructure()
scfg.render()
```
@esc esc requested a review from sklam April 19, 2024 17:37
@esc
Copy link
Member Author

esc commented Apr 19, 2024

@brandonwillard have a look at the above ☝️ may be of interest to you.

@esc esc added the enhancement New feature or request label Apr 19, 2024
@brandonwillard
Copy link

@brandonwillard have a look at the above ☝️ may be of interest to you.

This is fantastic!

esc added 5 commits April 19, 2024 20:28
This reduces the graph even more, since blocks with a single break or continue become empty blocks and are pruned
@esc
Copy link
Member Author

esc commented Apr 19, 2024

Coverage report for caa5ea2

coverage report
Name                                                Stmts   Miss  Cover
-----------------------------------------------------------------------
numba_rvsdg/__init__.py                                 1      0   100%
numba_rvsdg/core/datastructures/ast_transforms.py     197      8    96%
numba_rvsdg/core/datastructures/basic_block.py        106      2    98%
numba_rvsdg/core/datastructures/block_names.py         13      0   100%
numba_rvsdg/core/datastructures/byte_flow.py           17      0   100%
numba_rvsdg/core/datastructures/flow_info.py           46      0   100%
numba_rvsdg/core/datastructures/scfg.py               404     29    93%
numba_rvsdg/core/transformations.py                   309      3    99%
numba_rvsdg/core/utils.py                              24      1    96%
numba_rvsdg/networkx_vendored/scc.py                   64     27    58%
numba_rvsdg/rendering/rendering.py                    167    125    25%
numba_rvsdg/tests/mock_asm.py                         122      2    98%
numba_rvsdg/tests/simulator.py                        226     46    80%
numba_rvsdg/tests/test_ast_transforms.py              200    116    42%
numba_rvsdg/tests/test_byteflow.py                     68      3    96%
numba_rvsdg/tests/test_figures.py                      21      0   100%
numba_rvsdg/tests/test_mock_asm.py                     44      0   100%
numba_rvsdg/tests/test_scc.py                          47     38    19%
numba_rvsdg/tests/test_scfg.py                         44      5    89%
numba_rvsdg/tests/test_simulate.py                    114      2    98%
numba_rvsdg/tests/test_transforms.py                  171      1    99%
numba_rvsdg/tests/test_utils.py                        66      0   100%
-----------------------------------------------------------------------
TOTAL                                                2471    408    83%

esc added 2 commits April 20, 2024 17:42
The jump_targets for the else-branch of the for-loop must be set after
recursion, not before. Otherwise nested flow-control constructs in the
else-branch will fail to codegen correctly, leading to a broken CFG with
blocks that point to non-existing blocks. The test exposes this and
demonstrates the fix is valid.
Copy link
Member

@sklam sklam left a comment

Choose a reason for hiding this comment

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

Just some minor adjustments. The biggest thing is for loop orelse need to be sealed.

numba_rvsdg/core/datastructures/ast_transforms.py Outdated Show resolved Hide resolved
numba_rvsdg/core/datastructures/ast_transforms.py Outdated Show resolved Hide resolved
esc added 7 commits April 24, 2024 22:27
This test exposes a bug in a missing seal for using continue in the
nested for-else clause. Specifically, one needs to have an else-clause
with a series of linear statements and a continue to hit this. If you
try to break, the break index will be the same as the exit index for the
seal_inside_of_loop as the default_index is also the exit_index. So you
can only hit this with exit_index. In that case the block with the
continue does not point to the loop header but to the incorrect exit
instead.

The test has been constructed such that a potential reconstruction would
also fail execution with an incorrect return value.
As title
@esc
Copy link
Member Author

esc commented Apr 25, 2024

@sklam as discussed OOB, I have implemented while: else: and simplified the handle_while method: 3563570

@esc
Copy link
Member Author

esc commented Apr 25, 2024

@sklam I have addressed all the review comments and added most of the features we spoke about OOB.

The only thing I don't know how to decide on is how to further structure the API. In any case, the transformations are implemented and work so maybe we need to defer decisions about the API to a later stage.

@esc esc requested a review from sklam April 25, 2024 18:31
Copy link
Member

@sklam sklam left a comment

Choose a reason for hiding this comment

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

Some nitpicks regarding accept AST as input. Everything else looks good.

numba_rvsdg/core/datastructures/ast_transforms.py Outdated Show resolved Hide resolved
@esc
Copy link
Member Author

esc commented Apr 29, 2024

As per an OOB discussion with @sklam I have addressed all the requested improvements and am merging this now! Thank you for the review.

@esc esc merged commit 47503d7 into numba:main Apr 29, 2024
2 of 3 checks passed
@esc esc deleted the ast->scfg branch April 30, 2024 09:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants