-
Notifications
You must be signed in to change notification settings - Fork 274
Add public interface for natural_loopst and natural_loopt #5059
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
Merged
smowton
merged 1 commit into
diffblue:develop
from
smowton:smowton/cleanup/natural-loops-interface
Aug 27, 2019
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,6 +28,83 @@ Author: Georg Weissenbacher, [email protected] | |
|
||
#include "cfg_dominators.h" | ||
|
||
template <class, class> | ||
class natural_loops_templatet; | ||
|
||
/// A natural loop, specified as a set of instructions | ||
template <class P, class T> | ||
class natural_loop_templatet | ||
{ | ||
typedef natural_loops_templatet<P, T> natural_loopst; | ||
// For natural_loopst to directly manipulate loop_instructions, cf. clients | ||
// which should use the public iterface: | ||
friend natural_loopst; | ||
|
||
typedef std::set<T> loop_instructionst; | ||
loop_instructionst loop_instructions; | ||
|
||
public: | ||
explicit natural_loop_templatet(natural_loopst &natural_loops) | ||
: natural_loops(natural_loops) | ||
{ | ||
} | ||
|
||
/// Returns true if \p instruction is in this loop | ||
bool contains(const T instruction) const | ||
{ | ||
return natural_loops.loop_contains(*this, instruction); | ||
} | ||
|
||
/// Get the \ref natural_loopst analysis this loop relates to | ||
const natural_loopst &get_natural_loops() const | ||
{ | ||
return natural_loops; | ||
} | ||
/// Get the \ref natural_loopst analysis this loop relates to | ||
natural_loopst &get_natural_loops() | ||
{ | ||
return natural_loops; | ||
} | ||
|
||
// NOLINTNEXTLINE(readability/identifiers) | ||
typedef typename loop_instructionst::const_iterator const_iterator; | ||
|
||
/// Iterator over this loop's instructions | ||
const_iterator begin() const | ||
{ | ||
return loop_instructions.begin(); | ||
} | ||
|
||
/// Iterator over this loop's instructions | ||
const_iterator end() const | ||
{ | ||
return loop_instructions.end(); | ||
} | ||
|
||
/// Number of instructions in this loop | ||
std::size_t size() const | ||
{ | ||
return loop_instructions.size(); | ||
} | ||
|
||
/// Returns true if this loop contains no instructions | ||
bool empty() const | ||
{ | ||
return loop_instructions.empty(); | ||
} | ||
|
||
/// Adds \p instruction to this loop. The caller must verify that the added | ||
/// instruction does not alter loop structure; if it does they must discard | ||
/// and recompute the related \ref natural_loopst instance. | ||
void insert_instruction(const T instruction) | ||
{ | ||
loop_instructions.insert(instruction); | ||
} | ||
|
||
private: | ||
natural_loopst &natural_loops; | ||
}; | ||
|
||
/// Main driver for working out if a class (normally goto_programt) has any natural loops. | ||
/// \ref compute takes an entire goto_programt, iterates over the instructions and for | ||
/// any backwards jumps attempts to find out if it's a natural loop. | ||
|
@@ -46,8 +123,7 @@ template<class P, class T> | |
class natural_loops_templatet | ||
{ | ||
public: | ||
typedef std::set<T> natural_loopt; | ||
|
||
typedef natural_loop_templatet<P, T> natural_loopt; | ||
// map loop headers to loops | ||
typedef std::map<T, natural_loopt> loop_mapt; | ||
|
||
|
@@ -65,6 +141,18 @@ class natural_loops_templatet | |
return cfg_dominators; | ||
} | ||
|
||
/// Returns true if \p instruction is in \p loop | ||
bool loop_contains(const natural_loopt &loop, const T instruction) const | ||
{ | ||
return loop.loop_instructions.count(instruction); | ||
} | ||
|
||
/// Returns true if \p instruction is the header of any loop | ||
bool is_loop_header(const T instruction) const | ||
{ | ||
return loop_map.count(instruction); | ||
} | ||
|
||
natural_loops_templatet() | ||
{ | ||
} | ||
|
@@ -74,6 +162,15 @@ class natural_loops_templatet | |
compute(program); | ||
} | ||
|
||
// The loop structures stored in `loop_map` contain back-pointers to this | ||
// class, so we forbid copying or moving the analysis struct. If this becomes | ||
// necessary then either add a layer of indirection or update the loop_map | ||
// back-pointers on copy/move. | ||
natural_loops_templatet(const natural_loops_templatet &) = delete; | ||
natural_loops_templatet(natural_loops_templatet &&) = delete; | ||
natural_loops_templatet &operator=(const natural_loops_templatet &) = delete; | ||
natural_loops_templatet &operator=(natural_loops_templatet &&) = delete; | ||
|
||
protected: | ||
cfg_dominators_templatet<P, T, false> cfg_dominators; | ||
typedef typename cfg_dominators_templatet<P, T, false>::cfgt::nodet nodet; | ||
|
@@ -143,10 +240,12 @@ void natural_loops_templatet<P, T>::compute_natural_loop(T m, T n) | |
|
||
std::stack<T> stack; | ||
|
||
natural_loopt &loop=loop_map[n]; | ||
auto insert_result = loop_map.emplace(n, natural_loopt{*this}); | ||
INVARIANT(insert_result.second, "each loop head should only be visited once"); | ||
natural_loopt &loop = insert_result.first->second; | ||
|
||
loop.insert(n); | ||
loop.insert(m); | ||
loop.insert_instruction(n); | ||
loop.insert_instruction(m); | ||
|
||
if(n!=m) | ||
stack.push(m); | ||
|
@@ -161,8 +260,8 @@ void natural_loops_templatet<P, T>::compute_natural_loop(T m, T n) | |
for(const auto &edge : node.in) | ||
{ | ||
T q=cfg_dominators.cfg[edge.first].PC; | ||
std::pair<typename natural_loopt::const_iterator, bool> result= | ||
loop.insert(q); | ||
std::pair<typename natural_loopt::const_iterator, bool> result = | ||
loop.loop_instructions.insert(q); | ||
if(result.second) | ||
stack.push(q); | ||
} | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Why is this public?
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.
Doh, fixed it now, and made these private as you say.