Skip to content

Commit 3c7087e

Browse files
committed
natural_loopst and natural_loopt: add public interface
This hides the implementation of natural_loopt, making it easier to change in future. No behavioural change intended.
1 parent be7b9da commit 3c7087e

File tree

5 files changed

+138
-52
lines changed

5 files changed

+138
-52
lines changed

src/analyses/natural_loops.h

+106-7
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,83 @@ Author: Georg Weissenbacher, [email protected]
2828

2929
#include "cfg_dominators.h"
3030

31+
template <class, class>
32+
class natural_loops_templatet;
33+
34+
/// A natural loop, specified as a set of instructions
35+
template <class P, class T>
36+
class natural_loop_templatet
37+
{
38+
typedef natural_loops_templatet<P, T> natural_loopst;
39+
// For natural_loopst to directly manipulate loop_instructions, cf. clients
40+
// which should use the public iterface:
41+
friend natural_loopst;
42+
43+
typedef std::set<T> loop_instructionst;
44+
loop_instructionst loop_instructions;
45+
46+
public:
47+
explicit natural_loop_templatet(natural_loopst &natural_loops)
48+
: natural_loops(natural_loops)
49+
{
50+
}
51+
52+
/// Returns true if \p instruction is in this loop
53+
bool contains(const T instruction) const
54+
{
55+
return natural_loops.loop_contains(*this, instruction);
56+
}
57+
58+
/// Get the \ref natural_loopst analysis this loop relates to
59+
const natural_loopst &get_natural_loops() const
60+
{
61+
return natural_loops;
62+
}
63+
/// Get the \ref natural_loopst analysis this loop relates to
64+
natural_loopst &get_natural_loops()
65+
{
66+
return natural_loops;
67+
}
68+
69+
// NOLINTNEXTLINE(readability/identifiers)
70+
typedef typename loop_instructionst::const_iterator const_iterator;
71+
72+
/// Iterator over this loop's instructions
73+
const_iterator begin() const
74+
{
75+
return loop_instructions.begin();
76+
}
77+
78+
/// Iterator over this loop's instructions
79+
const_iterator end() const
80+
{
81+
return loop_instructions.end();
82+
}
83+
84+
/// Number of instructions in this loop
85+
std::size_t size() const
86+
{
87+
return loop_instructions.size();
88+
}
89+
90+
/// Returns true if this loop contains no instructions
91+
bool empty() const
92+
{
93+
return loop_instructions.empty();
94+
}
95+
96+
/// Adds \p instruction to this loop. The caller must verify that the added
97+
/// instruction does not alter loop structure; if it does they must discard
98+
/// and recompute the related \ref natural_loopst instance.
99+
void insert_instruction(const T instruction)
100+
{
101+
loop_instructions.insert(instruction);
102+
}
103+
104+
private:
105+
natural_loopst &natural_loops;
106+
};
107+
31108
/// Main driver for working out if a class (normally goto_programt) has any natural loops.
32109
/// \ref compute takes an entire goto_programt, iterates over the instructions and for
33110
/// any backwards jumps attempts to find out if it's a natural loop.
@@ -46,8 +123,7 @@ template<class P, class T>
46123
class natural_loops_templatet
47124
{
48125
public:
49-
typedef std::set<T> natural_loopt;
50-
126+
typedef natural_loop_templatet<P, T> natural_loopt;
51127
// map loop headers to loops
52128
typedef std::map<T, natural_loopt> loop_mapt;
53129

@@ -65,6 +141,18 @@ class natural_loops_templatet
65141
return cfg_dominators;
66142
}
67143

144+
/// Returns true if \p instruction is in \p loop
145+
bool loop_contains(const natural_loopt &loop, const T instruction) const
146+
{
147+
return loop.loop_instructions.count(instruction);
148+
}
149+
150+
/// Returns true if \p instruction is the header of any loop
151+
bool is_loop_header(const T instruction) const
152+
{
153+
return loop_map.count(instruction);
154+
}
155+
68156
natural_loops_templatet()
69157
{
70158
}
@@ -74,6 +162,15 @@ class natural_loops_templatet
74162
compute(program);
75163
}
76164

165+
// The loop structures stored in `loop_map` contain back-pointers to this
166+
// class, so we forbid copying or moving the analysis struct. If this becomes
167+
// necessary then either add a layer of indirection or update the loop_map
168+
// back-pointers on copy/move.
169+
natural_loops_templatet(const natural_loops_templatet &) = delete;
170+
natural_loops_templatet(natural_loops_templatet &&) = delete;
171+
natural_loops_templatet &operator=(const natural_loops_templatet &) = delete;
172+
natural_loops_templatet &operator=(natural_loops_templatet &&) = delete;
173+
77174
protected:
78175
cfg_dominators_templatet<P, T, false> cfg_dominators;
79176
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)
143240

144241
std::stack<T> stack;
145242

146-
natural_loopt &loop=loop_map[n];
243+
auto insert_result = loop_map.emplace(n, natural_loopt{*this});
244+
INVARIANT(insert_result.second, "each loop head should only be visited once");
245+
natural_loopt &loop = insert_result.first->second;
147246

148-
loop.insert(n);
149-
loop.insert(m);
247+
loop.insert_instruction(n);
248+
loop.insert_instruction(m);
150249

151250
if(n!=m)
152251
stack.push(m);
@@ -161,8 +260,8 @@ void natural_loops_templatet<P, T>::compute_natural_loop(T m, T n)
161260
for(const auto &edge : node.in)
162261
{
163262
T q=cfg_dominators.cfg[edge.first].PC;
164-
std::pair<typename natural_loopt::const_iterator, bool> result=
165-
loop.insert(q);
263+
std::pair<typename natural_loopt::const_iterator, bool> result =
264+
loop.loop_instructions.insert(q);
166265
if(result.second)
167266
stack.push(q);
168267
}

src/goto-instrument/accelerate/accelerate.cpp

+20-29
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,12 @@ Author: Matt Lewis
3434
goto_programt::targett acceleratet::find_back_jump(
3535
goto_programt::targett loop_header)
3636
{
37-
natural_loops_mutablet::natural_loopt &loop=
38-
natural_loops.loop_map[loop_header];
37+
natural_loops_mutablet::natural_loopt &loop =
38+
natural_loops.loop_map.at(loop_header);
3939
goto_programt::targett back_jump=loop_header;
4040

41-
for(natural_loops_mutablet::natural_loopt::iterator it=loop.begin();
42-
it!=loop.end();
43-
++it)
41+
for(const auto &t : loop)
4442
{
45-
goto_programt::targett t=*it;
4643
if(
4744
t->is_goto() && t->get_condition().is_true() && t->targets.size() == 1 &&
4845
t->targets.front() == loop_header &&
@@ -57,15 +54,11 @@ goto_programt::targett acceleratet::find_back_jump(
5754

5855
bool acceleratet::contains_nested_loops(goto_programt::targett &loop_header)
5956
{
60-
natural_loops_mutablet::natural_loopt &loop=
61-
natural_loops.loop_map[loop_header];
57+
natural_loops_mutablet::natural_loopt &loop =
58+
natural_loops.loop_map.at(loop_header);
6259

63-
for(natural_loops_mutablet::natural_loopt::iterator it=loop.begin();
64-
it!=loop.end();
65-
++it)
60+
for(const auto &t : loop)
6661
{
67-
const goto_programt::targett &t=*it;
68-
6962
if(t->is_backwards_goto())
7063
{
7164
if(t->targets.size()!=1 ||
@@ -75,8 +68,8 @@ bool acceleratet::contains_nested_loops(goto_programt::targett &loop_header)
7568
}
7669
}
7770

78-
if(t!=loop_header &&
79-
natural_loops.loop_map.find(t)!=natural_loops.loop_map.end())
71+
// Header of some other loop?
72+
if(t != loop_header && natural_loops.is_loop_header(t))
8073
{
8174
return true;
8275
}
@@ -92,7 +85,7 @@ int acceleratet::accelerate_loop(goto_programt::targett &loop_header)
9285
int num_accelerated=0;
9386
std::list<path_acceleratort> accelerators;
9487
natural_loops_mutablet::natural_loopt &loop =
95-
natural_loops.loop_map[loop_header];
88+
natural_loops.loop_map.at(loop_header);
9689

9790
if(contains_nested_loops(loop_header))
9891
{
@@ -159,8 +152,7 @@ int acceleratet::accelerate_loop(goto_programt::targett &loop_header)
159152
goto_programt::targett new_inst=loop_header;
160153
++new_inst;
161154

162-
loop.insert(new_inst);
163-
155+
loop.insert_instruction(new_inst);
164156

165157
std::cout << "Overflow loc is " << overflow_loc->location_number << '\n';
166158
std::cout << "Back jump is " << back_jump->location_number << '\n';
@@ -244,36 +236,35 @@ void acceleratet::make_overflow_loc(
244236
symbolt overflow_sym=utils.fresh_symbol("accelerate::overflow", bool_typet());
245237
const exprt &overflow_var=overflow_sym.symbol_expr();
246238
natural_loops_mutablet::natural_loopt &loop =
247-
natural_loops.loop_map[loop_header];
239+
natural_loops.loop_map.at(loop_header);
248240
overflow_instrumentert instrumenter(program, overflow_var, symbol_table);
249241

250-
for(natural_loops_mutablet::natural_loopt::iterator it=loop.begin();
251-
it!=loop.end();
252-
++it)
242+
for(const auto &loop_instruction : loop)
253243
{
254-
overflow_locs[*it]=goto_programt::targetst();
255-
goto_programt::targetst &added=overflow_locs[*it];
244+
overflow_locs[loop_instruction] = goto_programt::targetst();
245+
goto_programt::targetst &added = overflow_locs[loop_instruction];
256246

257-
instrumenter.add_overflow_checks(*it, added);
258-
loop.insert(added.begin(), added.end());
247+
instrumenter.add_overflow_checks(loop_instruction, added);
248+
for(const auto &new_instruction : added)
249+
loop.insert_instruction(new_instruction);
259250
}
260251

261252
goto_programt::targett t = program.insert_after(
262253
loop_header,
263254
goto_programt::make_assignment(code_assignt(overflow_var, false_exprt())));
264255
t->swap(*loop_header);
265-
loop.insert(t);
256+
loop.insert_instruction(t);
266257
overflow_locs[loop_header].push_back(t);
267258

268259
overflow_loc = program.insert_after(loop_end, goto_programt::make_skip());
269260
overflow_loc->swap(*loop_end);
270-
loop.insert(overflow_loc);
261+
loop.insert_instruction(overflow_loc);
271262

272263
goto_programt::targett t2 = program.insert_after(
273264
loop_end, goto_programt::make_goto(overflow_loc, not_exprt(overflow_var)));
274265
t2->swap(*loop_end);
275266
overflow_locs[overflow_loc].push_back(t2);
276-
loop.insert(t2);
267+
loop.insert_instruction(t2);
277268

278269
goto_programt::targett tmp=overflow_loc;
279270
overflow_loc=loop_end;

src/goto-instrument/accelerate/all_paths_enumerator.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ void all_paths_enumeratort::complete_path(patht &path, int succ)
109109

110110
goto_programt::targett end=path.back().loc;
111111

112-
if(end==loop_header || loop.find(end)==loop.end())
112+
if(end == loop_header || !loop.contains(end))
113113
return;
114114

115115
complete_path(path, 0);

src/goto-instrument/accelerate/disjunctive_polynomial_acceleration.cpp

+6-9
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ bool disjunctive_polynomial_accelerationt::accelerate(
6262
it!=goto_program.instructions.end();
6363
++it)
6464
{
65-
if(loop.find(it)!=loop.end())
65+
if(loop.contains(it))
6666
{
6767
goto_program.output_instruction(ns, "scratch", std::cout, *it);
6868
}
@@ -752,11 +752,9 @@ void disjunctive_polynomial_accelerationt::cone_of_influence(
752752

753753
void disjunctive_polynomial_accelerationt::find_distinguishing_points()
754754
{
755-
for(natural_loops_mutablet::natural_loopt::iterator it=loop.begin();
756-
it!=loop.end();
757-
++it)
755+
for(const auto &loop_instruction : loop)
758756
{
759-
const auto succs=goto_program.get_successors(*it);
757+
const auto succs = goto_program.get_successors(loop_instruction);
760758

761759
if(succs.size() > 1)
762760
{
@@ -845,8 +843,7 @@ void disjunctive_polynomial_accelerationt::build_path(
845843
path.push_back(path_nodet(t, cond));
846844

847845
t=next;
848-
}
849-
while(t!=loop_header && (loop.find(t)!=loop.end()));
846+
} while(t != loop_header && loop.contains(t));
850847
}
851848

852849
/*
@@ -912,7 +909,7 @@ void disjunctive_polynomial_accelerationt::build_fixed()
912909
{
913910
distinguish_mapt::iterator d=distinguishing_points.find(t);
914911

915-
if(loop.find(t)==loop.end())
912+
if(!loop.contains(t))
916913
{
917914
// This instruction isn't part of the loop... Just remove it.
918915
fixedt->turn_into_skip();
@@ -951,7 +948,7 @@ void disjunctive_polynomial_accelerationt::build_fixed()
951948
if(target->location_number > t->location_number)
952949
{
953950
// A forward jump...
954-
if(loop.find(target)!=loop.end())
951+
if(loop.contains(target))
955952
{
956953
// Case 1: a forward jump within the loop. Do nothing.
957954
continue;

src/goto-instrument/accelerate/sat_path_enumerator.cpp

+5-6
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,8 @@ bool sat_path_enumeratort::next(patht &path)
108108

109109
void sat_path_enumeratort::find_distinguishing_points()
110110
{
111-
for(natural_loops_mutablet::natural_loopt::iterator it=loop.begin();
112-
it!=loop.end();
111+
for(natural_loops_mutablet::natural_loopt::const_iterator it = loop.begin();
112+
it != loop.end();
113113
++it)
114114
{
115115
const auto succs=goto_program.get_successors(*it);
@@ -201,8 +201,7 @@ void sat_path_enumeratort::build_path(
201201
path.push_back(path_nodet(t, cond));
202202

203203
t=next;
204-
}
205-
while(t!=loop_header && (loop.find(t)!=loop.end()));
204+
} while(t != loop_header && loop.contains(t));
206205
}
207206

208207
/*
@@ -266,7 +265,7 @@ void sat_path_enumeratort::build_fixed()
266265
{
267266
distinguish_mapt::iterator d=distinguishing_points.find(t);
268267

269-
if(loop.find(t)==loop.end())
268+
if(!loop.contains(t))
270269
{
271270
// This instruction isn't part of the loop... Just remove it.
272271
fixedt->turn_into_skip();
@@ -305,7 +304,7 @@ void sat_path_enumeratort::build_fixed()
305304
if(target->location_number > t->location_number)
306305
{
307306
// A forward jump...
308-
if(loop.find(target)!=loop.end())
307+
if(!loop.contains(target))
309308
{
310309
// Case 1: a forward jump within the loop. Do nothing.
311310
continue;

0 commit comments

Comments
 (0)