-
Notifications
You must be signed in to change notification settings - Fork 747
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
Conversation
Current dependencies on/for this PR:
This stack of pull requests is managed by Graphite. |
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.
734f4cc
to
dd4546f
Compare
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. |
I'll see what I can do. |
FiniteIntPowersetLattice lattice(numLocals); | ||
LivenessTransferFunction transferFunction; | ||
|
||
MonotoneCFGAnalyzer<FiniteIntPowersetLattice, LivenessTransferFunction> |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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
?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
src/analysis/monotone-analyzer.h
Outdated
|
||
// The lattice element representing the program state before each block. | ||
std::vector<Element> states; | ||
// std::vector<BlockState<L>> stateBlocks; |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
I don't think it makes sense to split this up after all, since all the changes are either tightly coupled (e.g. removing |
for (auto cfgIter = cfgBlock->begin(); cfgIter != cfgBlock->end(); | ||
++cfgIter) { | ||
static_cast<SubType*>(this)->visit(*cfgIter); | ||
for (auto it = bb.begin(); it != bb.end(); ++it) { |
There was a problem hiding this comment.
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.
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.
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 torefer 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.