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

[analysis] Simplify core analysis code #6034

Merged
merged 5 commits into from
Oct 25, 2023
Merged

[analysis] Simplify core analysis code #6034

merged 5 commits into from
Oct 25, 2023

Conversation

tlively
Copy link
Member

@tlively tlively commented Oct 20, 2023

Simplify the monotone analyzer by replacing all the state it used to store in
BlockState with a simple vector of lattice elements. Use simple indices to
refer to both blocks and their associated states in the vector. Remove the
ability for transfer functions to control the initial enqueued order of basic
blocks since that was a leaky abstraction. Replace the worklist with a
UniqueDeferredQueue since that has generally proven to be more efficient in
smiilarly contexts, and more importantly, it has a nicer API. Make miscellaneous
simplifications to other code as well.

Delete a few unit tests that exposed the order in which blocks were analyzed
because they printed intermediate results. These tests should be replaced with
tests of analyses' public APIs in the future.

@tlively tlively requested review from ashleynh and kripken October 20, 2023 23:08
Base automatically changed from txfn-concept to main October 21, 2023 00:22
Simplify the monotone analyzer by replacing all the state it used to store in
`BlockState` with a simple vector of lattice elements. Use simple indices to
refer to both blocks and their associated states in the vector. Remove the
ability for transfer functions to control the initial enqueued order of basic
blocks since that was a leaky abstraction. Replace the worklist with a
UniqueDeferredQueue since that has generally proven to be more efficient in
smiilarly contexts, and more importantly, it has a nicer API. Make miscellaneous
simplifications to other code as well.

Delete a few unit tests that exposed the order in which blocks were analyzed
because they printed intermediate results. These tests should be replaced with
tests of analyses' public APIs in the future.
@kripken
Copy link
Member

kripken commented Oct 23, 2023

Would it be difficult to split this up? From the description there are various changes, and reading the code it's not immediately obvious to me which is which.

@tlively
Copy link
Member Author

tlively commented Oct 23, 2023

I'll see what I can do.

FiniteIntPowersetLattice lattice(numLocals);
LivenessTransferFunction transferFunction;

MonotoneCFGAnalyzer<FiniteIntPowersetLattice, LivenessTransferFunction>
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do you need to replace this test now or will this be 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.

This will be future work. We generally should not have tests that check intermediate results like this because they break when we change internal implementation details. OTOH, the reason the test was like this was that we didn't have a very clean API for accessing the analysis results. I expect to revisit the API problem soon.

(FWIW, generators could help a lot here because we could interleave visiting the expressions and getting their analysis results with test assertions.)

for (auto cfgIter = cfgBlock->begin(); cfgIter != cfgBlock->end();
++cfgIter) {
static_cast<SubType*>(this)->visit(*cfgIter);
for (auto it = bb.begin(); it != bb.end(); ++it) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Are you using the .begin() .end() iterator pattern for symmetry with the If-true block above? Just wondering why not the range-based loop that's used on line 263 in src/tools/wasm-fuzz-lattices.cpp?

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, it's for symmetry. You're right that a range-based for loop would have worked here as well.

Copy link
Member

Choose a reason for hiding this comment

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

A range-based loop would be better imo, even if it looks more different than the other loop above. I see that as a benefit actually: the difference is more obvious, and separately this one becomes easier to read.


// The lattice element representing the program state before each block.
std::vector<Element> states;
// std::vector<BlockState<L>> stateBlocks;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Did you want to delete this commented line?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yep, thanks 👍

@@ -96,12 +68,21 @@ inline void MonotoneCFGAnalyzer<L, TxFn>::collectResults() {
template<Lattice L, TransferFunction TxFn>
inline void MonotoneCFGAnalyzer<L, TxFn>::print(std::ostream& os) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you explain why this print function instead of a << overload? Does it have to do with Concepts?

Copy link
Member Author

Choose a reason for hiding this comment

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

No particular reason. The original author probably thought print was a nicer interface than <<, and that seems like a reasonable opinion to me. A << overload would have worked just as well. Print methods generally have a slight advantage that they are easier to call from a debugger, although I'm not sure whether it's easy to get the ostream to pass into this one from the debugger. toString methods are generally the easiest for debugging.

@tlively
Copy link
Member Author

tlively commented Oct 24, 2023

I don't think it makes sense to split this up after all, since all the changes are either tightly coupled (e.g. removing BlockState and using indices to find block states) or otherwise touch the same code (e.g. replacing the work list data structure and removing the API to initialize the work list). The separable changes are generally variable renamings or changing while loops to for loops, etc, that I don't think would benefit much from being split out.

for (auto cfgIter = cfgBlock->begin(); cfgIter != cfgBlock->end();
++cfgIter) {
static_cast<SubType*>(this)->visit(*cfgIter);
for (auto it = bb.begin(); it != bb.end(); ++it) {
Copy link
Member

Choose a reason for hiding this comment

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

A range-based loop would be better imo, even if it looks more different than the other loop above. I see that as a benefit actually: the difference is more obvious, and separately this one becomes easier to read.

@tlively
Copy link
Member Author

tlively commented Oct 25, 2023

Merge activity

  • Oct 25, 1:00 PM: @tlively started a stack merge that includes this pull request via Graphite.
  • Oct 25, 1:00 PM: @tlively merged this pull request with Graphite.

@tlively tlively merged commit ef8e424 into main Oct 25, 2023
14 checks passed
@tlively tlively deleted the simplify-analyzer branch October 25, 2023 17:00
radekdoulik pushed a commit to dotnet/binaryen that referenced this pull request Jul 12, 2024
Simplify the monotone analyzer by replacing all the state it used to store in
`BlockState` with a simple vector of lattice elements. Use simple indices to
refer to both blocks and their associated states in the vector. Remove the
ability for transfer functions to control the initial enqueued order of basic
blocks since that was a leaky abstraction. Replace the worklist with a
UniqueDeferredQueue since that has generally proven to be more efficient in
smiilarly contexts, and more importantly, it has a nicer API. Make miscellaneous
simplifications to other code as well.

Delete a few unit tests that exposed the order in which blocks were analyzed
because they printed intermediate results. These tests should be replaced with
tests of analyses' public APIs in the future.
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.

3 participants