CBMC
Loading...
Searching...
No Matches
sat_path_enumerator.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module: Loop Acceleration
4
5Author: Matt Lewis
6
7\*******************************************************************/
8
11
12#include "sat_path_enumerator.h"
13
14#include <iostream>
15#include <map>
16#include <string>
17
20
21#include "scratch_program.h"
22
24{
26
27 program.append(fixed);
28 program.append(fixed);
29
30 // Let's make sure that we get a path we have not seen before.
31 for(std::list<distinguish_valuest>::iterator it=accelerated_paths.begin();
32 it!=accelerated_paths.end();
33 ++it)
34 {
36
37 for(distinguish_valuest::iterator jt=it->begin();
38 jt!=it->end();
39 ++jt)
40 {
41 exprt distinguisher=jt->first;
42 bool taken=jt->second;
43
44 if(taken)
45 {
48 }
49
51 new_path.swap(disjunct);
52 }
53
54 program.assume(new_path);
55 }
56
58
59 try
60 {
61 if(program.check_sat(guard_manager))
62 {
63#ifdef DEBUG
64 std::cout << "Found a path\n";
65#endif
66 build_path(program, path);
67 record_path(program);
68
69 return true;
70 }
71 }
72 catch(const std::string &s)
73 {
74 std::cout << "Error in fitting polynomial SAT check: " << s << '\n';
75 }
76 catch(const char *s)
77 {
78 std::cout << "Error in fitting polynomial SAT check: " << s << '\n';
79 }
80
81 return false;
82}
83
85{
86 for(natural_loops_mutablet::natural_loopt::const_iterator it = loop.begin();
87 it != loop.end();
88 ++it)
89 {
90 const auto succs=goto_program.get_successors(*it);
91
92 if(succs.size()>1)
93 {
94 // This location has multiple successors -- each successor is a
95 // distinguishing point.
96 for(const auto &succ : succs)
97 {
99 utils.fresh_symbol("polynomial::distinguisher", bool_typet());
101
103 distinguishers.push_back(distinguisher);
104 }
105 }
106 }
107}
108
111 patht &path)
112{
114
115 do
116 {
118 const auto succs=goto_program.get_successors(t);
119
120 // We should have a looping path, so we should never hit a location
121 // with no successors.
122 CHECK_RETURN(succs.size() > 0);
123
124 if(succs.size()==1)
125 {
126 // Only one successor -- accumulate it and move on.
127 path.push_back(path_nodet(t));
128 t=succs.front();
129 continue;
130 }
131
132 // We have multiple successors. Examine the distinguisher variables
133 // to see which branch was taken.
134 bool found_branch=false;
135
136 for(const auto &succ : succs)
137 {
139 bool taken=scratch_program.eval(distinguisher).is_true();
140
141 if(taken)
142 {
143 if(!found_branch ||
144 (succ->location_number < next->location_number))
145 {
146 next=succ;
147 }
148
149 found_branch=true;
150 }
151 }
152
153 INVARIANT(found_branch, "no branch taken");
154
155 exprt cond=nil_exprt();
156
157 if(t->is_goto())
158 {
159 // If this was a conditional branch (it probably was), figure out
160 // if we hit the "taken" or "not taken" branch & accumulate the
161 // appropriate guard.
162 cond = not_exprt(t->condition());
163
164 for(goto_programt::targetst::iterator it=t->targets.begin();
165 it!=t->targets.end();
166 ++it)
167 {
168 if(next==*it)
169 {
170 cond = t->condition();
171 break;
172 }
173 }
174 }
175
176 path.push_back(path_nodet(t, cond));
177
178 t=next;
179 } while(t != loop_header && loop.contains(t));
180}
181
182/*
183 * Take the body of the loop we are accelerating and produce a fixed-path
184 * version of that body, suitable for use in the fixed-path acceleration we
185 * will be doing later.
186 */
188{
190 std::map<exprt, exprt> shadow_distinguishers;
191
193
194 for(auto &instruction : fixed.instructions)
195 {
196 if(instruction.is_assert())
197 instruction.turn_into_assume();
198 }
199
200 // We're only interested in paths that loop back to the loop header.
201 // As such, any path that jumps outside of the loop or jumps backwards
202 // to a location other than the loop header (i.e. a nested loop) is not
203 // one we're interested in, and we'll redirect it to this assume(false).
206
207 // Make a sentinel instruction to mark the end of the loop body.
208 // We'll use this as the new target for any back-jumps to the loop
209 // header.
211
212 // A pointer to the start of the fixed-path body. We'll be using this to
213 // iterate over the fixed-path body, but for now it's just a pointer to the
214 // first instruction.
216
217 // Create shadow distinguisher variables. These guys identify the path that
218 // is taken through the fixed-path body.
219 for(std::list<exprt>::iterator it=distinguishers.begin();
220 it!=distinguishers.end();
221 ++it)
222 {
223 exprt &distinguisher=*it;
224 symbolt shadow_sym=utils.fresh_symbol("polynomial::shadow_distinguisher",
225 bool_typet());
226 exprt shadow=shadow_sym.symbol_expr();
228
230 fixedt,
232 }
233
234 // We're going to iterate over the 2 programs in lockstep, which allows
235 // us to figure out which distinguishing point we've hit & instrument
236 // the relevant distinguisher variables.
238 t!=goto_program.instructions.end();
239 ++t, ++fixedt)
240 {
241 distinguish_mapt::iterator d=distinguishing_points.find(t);
242
243 if(!loop.contains(t))
244 {
245 // This instruction isn't part of the loop... Just remove it.
246 fixedt->turn_into_skip();
247 continue;
248 }
249
250 if(d!=distinguishing_points.end())
251 {
252 // We've hit a distinguishing point. Set the relevant shadow
253 // distinguisher to true.
254 exprt &distinguisher=d->second;
256
258 fixedt,
260
261 assign->swap(*fixedt);
262 fixedt=assign;
263 }
264
265 if(t->is_goto())
266 {
267 DATA_INVARIANT(fixedt->is_goto(), "inconsistent programs");
268 // If this is a forwards jump, it's either jumping inside the loop
269 // (in which case we leave it alone), or it jumps outside the loop.
270 // If it jumps out of the loop, it's on a path we don't care about
271 // so we kill it.
272 //
273 // Otherwise, it's a backwards jump. If it jumps back to the loop
274 // header we're happy & redirect it to our end-of-body sentinel.
275 // If it jumps somewhere else, it's part of a nested loop and we
276 // kill it.
277 for(const auto &target : t->targets)
278 {
279 if(target->location_number > t->location_number)
280 {
281 // A forward jump...
282 if(!loop.contains(target))
283 {
284 // Case 1: a forward jump within the loop. Do nothing.
285 continue;
286 }
287 else
288 {
289 // Case 2: a forward jump out of the loop. Kill.
290 fixedt->targets.clear();
291 fixedt->targets.push_back(kill);
292 }
293 }
294 else
295 {
296 // A backwards jump...
297 if(target==loop_header)
298 {
299 // Case 3: a backwards jump to the loop header. Redirect
300 // to sentinel.
301 fixedt->targets.clear();
302 fixedt->targets.push_back(end);
303 }
304 else
305 {
306 // Case 4: a nested loop. Kill.
307 fixedt->targets.clear();
308 fixedt->targets.push_back(kill);
309 }
310 }
311 }
312 }
313 }
314
315 // OK, now let's assume that the path we took through the fixed-path
316 // body is the same as the master path. We do this by assuming that
317 // each of the shadow-distinguisher variables is equal to its corresponding
318 // master-distinguisher.
319 for(const auto &expr : distinguishers)
320 {
321 const exprt &shadow=shadow_distinguishers[expr];
322
324 end, goto_programt::make_assumption(equal_exprt(expr, shadow)));
325 }
326
327 // Finally, let's remove all the skips we introduced and fix the
328 // jump targets.
329 fixed.update();
331}
332
334{
336
337 for(const auto &expr : distinguishers)
338 path_val[expr]=program.eval(expr).is_true();
339
340 accelerated_paths.push_back(path_val);
341}
symbolt fresh_symbol(std::string base, typet type)
virtual void clear()
Reset the abstract state.
Definition ai.h:265
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Definition ai.h:562
The Boolean type.
Definition std_types.h:36
A goto_instruction_codet representing an assignment in the program.
Equality.
Definition std_expr.h:1366
Base class for all expressions.
Definition expr.h:56
bool is_true() const
Return whether the expression is a constant representing true.
Definition expr.cpp:27
The Boolean constant false.
Definition std_expr.h:3199
static instructiont make_assumption(const exprt &g, const source_locationt &l=source_locationt::nil())
instructionst instructions
The list of instructions in the goto program.
void copy_from(const goto_programt &src)
Copy a full goto program, preserving targets.
void update()
Update all indices.
instructionst::iterator targett
static instructiont make_assignment(const code_assignt &_code, const source_locationt &l=source_locationt::nil())
Create an assignment instruction.
static instructiont make_skip(const source_locationt &l=source_locationt::nil())
targett insert_after(const_targett target)
Insertion after the instruction pointed-to by the given instruction iterator target.
std::list< Target > get_successors(Target target) const
Get control-flow successors of a given instruction.
targett add(instructiont &&instruction)
Adds a given instruction at the end.
static instructiont make_assertion(const exprt &g, const source_locationt &l=source_locationt::nil())
targett insert_before(const_targett target)
Insertion before the instruction pointed-to by the given instruction iterator target.
The NIL expression.
Definition std_expr.h:3208
Boolean negation.
Definition std_expr.h:2454
Boolean OR.
Definition std_expr.h:2270
guard_managert & guard_manager
acceleration_utilst utils
distinguish_mapt distinguishing_points
message_handlert & message_handler
goto_programt::targett loop_header
void build_path(scratch_programt &scratch_program, patht &path)
std::list< distinguish_valuest > accelerated_paths
symbol_table_baset & symbol_table
goto_programt & goto_program
void record_path(scratch_programt &scratch_program)
std::map< exprt, bool > distinguish_valuest
natural_loops_mutablet::natural_loopt & loop
std::list< exprt > distinguishers
exprt eval(const exprt &e)
Expression to hold a symbol (variable)
Definition std_expr.h:131
Symbol table entry.
Definition symbol.h:28
The Boolean constant true.
Definition std_expr.h:3190
Concrete Goto Program.
std::list< path_nodet > patht
Definition path.h:44
void remove_skip(goto_programt &goto_program, goto_programt::targett begin, goto_programt::targett end)
remove unnecessary skip statements
Program Transformation.
Loop Acceleration.
Loop Acceleration.
int kill(pid_t pid, int sig)
Definition signal.c:15
#define CHECK_RETURN(CONDITION)
Definition invariant.h:495
#define DATA_INVARIANT(CONDITION, REASON)
This condition should be used to document that assumptions that are made on goto_functions,...
Definition invariant.h:534
#define INVARIANT(CONDITION, REASON)
This macro uses the wrapper function 'invariant_violated_string'.
Definition invariant.h:423