CBMC
cfg.h
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: Control Flow Graph
4 
5 Author: Daniel Kroening, kroening@kroening.com
6 
7 \*******************************************************************/
8 
11 
12 #ifndef CPROVER_GOTO_PROGRAMS_CFG_H
13 #define CPROVER_GOTO_PROGRAMS_CFG_H
14 
15 #include <util/dense_integer_map.h>
16 #include <util/graph.h>
17 #include <util/std_expr.h>
18 
19 #include "goto_functions.h"
20 
22 {
23 };
24 
25 // these are the CFG nodes
26 template<class T, typename I>
27 struct cfg_base_nodet:public graph_nodet<empty_edget>, public T
28 {
31 
32  I PC;
33 };
34 
37 template <class T>
39 {
40 public:
41  std::size_t operator()(T &&t) const
42  {
43  return std::forward<T>(identity_functort{}(t));
44  }
45 };
46 
48 template <>
50 {
51 public:
52  std::size_t operator()(const goto_programt::const_targett &t) const
53  {
54  return t->location_number;
55  }
56 };
57 
83 template<class T,
84  typename P=const goto_programt,
86 class cfg_baset:public grapht< cfg_base_nodet<T, I> >
87 {
89 
90 public:
91  typedef typename base_grapht::node_indext entryt;
92  typedef typename base_grapht::nodet nodet;
93 
94  class entry_mapt final
95  {
96  typedef dense_integer_mapt<
98  entryt,
102 
103  public:
105 
106  // NOLINTNEXTLINE(readability/identifiers)
107  typedef typename data_typet::iterator iterator;
108  // NOLINTNEXTLINE(readability/identifiers)
110 
111  template <typename U>
112  const_iterator find(U &&u) const { return data.find(std::forward<U>(u)); }
113 
114  iterator begin() { return data.begin(); }
115  const_iterator begin() const { return data.begin(); }
116  const_iterator cbegin() const { return data.cbegin(); }
117 
118  iterator end() { return data.end(); }
119  const_iterator end() const { return data.end(); }
120  const_iterator cend() const { return data.cend(); }
121 
122  explicit entry_mapt(grapht< cfg_base_nodet<T, I> > &_container):
123  container(_container)
124  {
125  }
126 
128  {
129  auto e=data.insert(std::make_pair(t, 0));
130 
131  if(e.second)
132  e.first->second=container.add_node();
133 
134  return e.first->second;
135  }
136 
138  {
139  return data.at(t);
140  }
141  const entryt &at(const goto_programt::const_targett &t) const
142  {
143  return data.at(t);
144  }
145 
146  template <class Iter>
147  void setup_for_keys(Iter begin, Iter end)
148  {
150  }
151  };
153 
154 protected:
155  virtual void compute_edges_goto(
156  const goto_programt &goto_program,
157  const goto_programt::instructiont &instruction,
159  entryt &entry);
160 
161  virtual void compute_edges_catch(
162  const goto_programt &goto_program,
163  const goto_programt::instructiont &instruction,
165  entryt &entry);
166 
167  virtual void compute_edges_throw(
168  const goto_programt &goto_program,
169  const goto_programt::instructiont &instruction,
171  entryt &entry);
172 
174  const goto_programt &goto_program,
175  const goto_programt::instructiont &instruction,
177  entryt &entry);
178 
180  const goto_functionst &goto_functions,
181  const goto_programt &goto_program,
182  const goto_programt::instructiont &instruction,
184  entryt &entry);
185 
187  const goto_functionst &goto_functions,
188  const goto_programt &goto_program,
189  I PC);
190 
192  const goto_functionst &goto_functions,
193  P &goto_program);
194 
196  const goto_functionst &goto_functions);
197 
198 public:
200  {
201  }
202 
203  virtual ~cfg_baset()
204  {
205  }
206 
208  const goto_functionst &goto_functions)
209  {
210  std::vector<goto_programt::const_targett> possible_keys;
211  for(const auto &id_and_function : goto_functions.function_map)
212  {
213  const auto &instructions = id_and_function.second.body.instructions;
214  possible_keys.reserve(possible_keys.size() + instructions.size());
215  for(auto it = instructions.begin(); it != instructions.end(); ++it)
216  possible_keys.push_back(it);
217  }
218  entry_map.setup_for_keys(possible_keys.begin(), possible_keys.end());
219  compute_edges(goto_functions);
220  }
221 
222  void operator()(P &goto_program)
223  {
224  goto_functionst goto_functions;
225  std::vector<goto_programt::const_targett> possible_keys;
226  const auto &instructions = goto_program.instructions;
227  possible_keys.reserve(instructions.size());
228  for(auto it = instructions.begin(); it != instructions.end(); ++it)
229  possible_keys.push_back(it);
230  entry_map.setup_for_keys(possible_keys.begin(), possible_keys.end());
231  compute_edges(goto_functions, goto_program);
232  }
233 
240  {
241  return entry_map.at(program_point);
242  }
243 
246  {
247  return (*this)[get_node_index(program_point)];
248  }
249 
251  const nodet &get_node(const goto_programt::const_targett &program_point) const
252  {
253  return (*this)[get_node_index(program_point)];
254  }
255 
259  const entry_mapt &entries() const
260  {
261  return entry_map;
262  }
263 
264  static I get_first_node(P &program)
265  {
266  return program.instructions.begin();
267  }
268  static I get_last_node(P &program)
269  {
270  return --program.instructions.end();
271  }
272  static bool nodes_empty(P &program)
273  {
274  return program.instructions.empty();
275  }
276 };
277 
278 template<class T,
279  typename P=const goto_programt,
280  typename I=goto_programt::const_targett>
281 class concurrent_cfg_baset:public virtual cfg_baset<T, P, I>
282 {
283 protected:
285  const goto_programt &goto_program,
286  const goto_programt::instructiont &instruction,
288  typename cfg_baset<T, P, I>::entryt &entry);
289 };
290 
291 template<class T,
292  typename P=const goto_programt,
293  typename I=goto_programt::const_targett>
294 class procedure_local_cfg_baset:public virtual cfg_baset<T, P, I>
295 {
296 protected:
298  const goto_functionst &goto_functions,
299  const goto_programt &goto_program,
300  const goto_programt::instructiont &instruction,
302  typename cfg_baset<T, P, I>::entryt &entry);
303 };
304 
305 template<class T,
306  typename P=const goto_programt,
307  typename I=goto_programt::const_targett>
309  public concurrent_cfg_baset<T, P, I>,
310  public procedure_local_cfg_baset<T, P, I>
311 {
312 };
313 
314 template<class T, typename P, typename I>
316  const goto_programt &goto_program,
317  const goto_programt::instructiont &instruction,
319  entryt &entry)
320 {
321  if(
322  next_PC != goto_program.instructions.end() &&
323  !instruction.condition().is_true())
324  {
325  this->add_edge(entry, entry_map[next_PC]);
326  }
327 
328  this->add_edge(entry, entry_map[instruction.get_target()]);
329 }
330 
331 template<class T, typename P, typename I>
333  const goto_programt &goto_program,
334  const goto_programt::instructiont &instruction,
336  entryt &entry)
337 {
338  if(next_PC!=goto_program.instructions.end())
339  this->add_edge(entry, entry_map[next_PC]);
340 
341  // Not ideal, but preserves targets
342  // Ideally, the throw statements should have those as successors
343 
344  for(const auto &t : instruction.targets)
345  if(t!=goto_program.instructions.end())
346  this->add_edge(entry, entry_map[t]);
347 }
348 
349 template<class T, typename P, typename I>
351  const goto_programt &,
354  entryt &)
355 {
356  // no (trivial) successors
357 }
358 
359 template<class T, typename P, typename I>
361  const goto_programt &goto_program,
364  entryt &entry)
365 {
366  if(next_PC!=goto_program.instructions.end())
367  this->add_edge(entry, entry_map[next_PC]);
368 }
369 
370 template<class T, typename P, typename I>
372  const goto_programt &goto_program,
373  const goto_programt::instructiont &instruction,
375  typename cfg_baset<T, P, I>::entryt &entry)
376 {
378  goto_program,
379  instruction,
380  next_PC,
381  entry);
382 
383  this->add_edge(entry, this->entry_map[instruction.get_target()]);
384 }
385 
386 template<class T, typename P, typename I>
388  const goto_functionst &goto_functions,
389  const goto_programt &goto_program,
390  const goto_programt::instructiont &instruction,
392  entryt &entry)
393 {
394  const exprt &function = instruction.call_function();
395 
396  if(function.id()!=ID_symbol)
397  return;
398 
399  const irep_idt &identifier=
400  to_symbol_expr(function).get_identifier();
401 
402  goto_functionst::function_mapt::const_iterator f_it=
403  goto_functions.function_map.find(identifier);
404 
405  if(f_it!=goto_functions.function_map.end() &&
406  f_it->second.body_available())
407  {
408  // get the first instruction
410  f_it->second.body.instructions.begin();
411 
413  f_it->second.body.instructions.end();
414 
415  goto_programt::const_targett last_it=e_it; last_it--;
416 
417  if(i_it!=e_it)
418  {
419  // nonempty function
420  this->add_edge(entry, entry_map[i_it]);
421 
422  // add the last instruction as predecessor of the return location
423  if(next_PC!=goto_program.instructions.end())
424  this->add_edge(entry_map[last_it], entry_map[next_PC]);
425  }
426  else if(next_PC!=goto_program.instructions.end())
427  {
428  // empty function
429  this->add_edge(entry, entry_map[next_PC]);
430  }
431  }
432  else if(next_PC!=goto_program.instructions.end())
433  this->add_edge(entry, entry_map[next_PC]);
434 }
435 
436 template<class T, typename P, typename I>
438  const goto_functionst &,
439  const goto_programt &goto_program,
440  const goto_programt::instructiont &instruction,
442  typename cfg_baset<T, P, I>::entryt &entry)
443 {
444  const exprt &function = instruction.call_function();
445 
446  if(function.id()!=ID_symbol)
447  return;
448 
449  if(next_PC!=goto_program.instructions.end())
450  this->add_edge(entry, this->entry_map[next_PC]);
451 }
452 
453 template<class T, typename P, typename I>
455  const goto_functionst &goto_functions,
456  const goto_programt &goto_program,
457  I PC)
458 {
459  const goto_programt::instructiont &instruction=*PC;
460  entryt entry=entry_map[PC];
461  (*this)[entry].PC=PC;
462  goto_programt::const_targett next_PC(PC);
463  next_PC++;
464 
465  // compute forward edges first
466  switch(instruction.type())
467  {
468  case GOTO:
469  compute_edges_goto(goto_program, instruction, next_PC, entry);
470  break;
471 
472  case CATCH:
473  compute_edges_catch(goto_program, instruction, next_PC, entry);
474  break;
475 
476  case THROW:
477  compute_edges_throw(goto_program, instruction, next_PC, entry);
478  break;
479 
480  case START_THREAD:
481  compute_edges_start_thread(
482  goto_program,
483  instruction,
484  next_PC,
485  entry);
486  break;
487 
488  case FUNCTION_CALL:
489  compute_edges_function_call(
490  goto_functions,
491  goto_program,
492  instruction,
493  next_PC,
494  entry);
495  break;
496 
497  case END_THREAD:
498  case END_FUNCTION:
499  // no successor
500  break;
501 
502  case ASSUME:
503  // false guard -> no successor
504  if(instruction.condition().is_false())
505  break;
506 
507  case ASSIGN:
508  case ASSERT:
509  case OTHER:
510  case SET_RETURN_VALUE:
511  case SKIP:
512  case LOCATION:
513  case ATOMIC_BEGIN:
514  case ATOMIC_END:
515  case DECL:
516  case DEAD:
517  if(next_PC!=goto_program.instructions.end())
518  this->add_edge(entry, entry_map[next_PC]);
519  break;
520 
521  case NO_INSTRUCTION_TYPE:
522  case INCOMPLETE_GOTO:
523  UNREACHABLE;
524  break;
525  }
526 }
527 
528 template<class T, typename P, typename I>
530  const goto_functionst &goto_functions,
531  P &goto_program)
532 {
533  for(I it=goto_program.instructions.begin();
534  it!=goto_program.instructions.end();
535  ++it)
536  compute_edges(goto_functions, goto_program, it);
537 }
538 
539 template<class T, typename P, typename I>
541  const goto_functionst &goto_functions)
542 {
543  for(const auto &gf_entry : goto_functions.function_map)
544  {
545  if(gf_entry.second.body_available())
546  compute_edges(goto_functions, gf_entry.second.body);
547  }
548 }
549 
550 #endif // CPROVER_GOTO_PROGRAMS_CFG_H
const_iterator cend() const
Definition: cfg.h:120
const_iterator find(U &&u) const
Definition: cfg.h:112
grapht< cfg_base_nodet< T, I > > & container
Definition: cfg.h:104
entryt & operator[](const goto_programt::const_targett &t)
Definition: cfg.h:127
entry_mapt(grapht< cfg_base_nodet< T, I > > &_container)
Definition: cfg.h:122
iterator end()
Definition: cfg.h:118
dense_integer_mapt< goto_programt::const_targett, entryt, cfg_instruction_to_dense_integert< goto_programt::const_targett > > data_typet
Definition: cfg.h:100
iterator begin()
Definition: cfg.h:114
void setup_for_keys(Iter begin, Iter end)
Definition: cfg.h:147
data_typet::iterator iterator
Definition: cfg.h:107
data_typet data
Definition: cfg.h:101
const entryt & at(const goto_programt::const_targett &t) const
Definition: cfg.h:141
data_typet::const_iterator const_iterator
Definition: cfg.h:109
const_iterator begin() const
Definition: cfg.h:115
const_iterator cbegin() const
Definition: cfg.h:116
entryt & at(const goto_programt::const_targett &t)
Definition: cfg.h:137
const_iterator end() const
Definition: cfg.h:119
A multi-procedural control flow graph (CFG) whose nodes store references to instructions in a GOTO pr...
Definition: cfg.h:87
virtual ~cfg_baset()
Definition: cfg.h:203
void compute_edges(const goto_functionst &goto_functions, P &goto_program)
Definition: cfg.h:529
base_grapht::node_indext entryt
Definition: cfg.h:91
virtual void compute_edges_catch(const goto_programt &goto_program, const goto_programt::instructiont &instruction, goto_programt::const_targett next_PC, entryt &entry)
Definition: cfg.h:332
const entry_mapt & entries() const
Get a map from program points to their corresponding node indices.
Definition: cfg.h:259
static I get_first_node(P &program)
Definition: cfg.h:264
static I get_last_node(P &program)
Definition: cfg.h:268
virtual void compute_edges_function_call(const goto_functionst &goto_functions, const goto_programt &goto_program, const goto_programt::instructiont &instruction, goto_programt::const_targett next_PC, entryt &entry)
Definition: cfg.h:387
void compute_edges(const goto_functionst &goto_functions)
Definition: cfg.h:540
virtual void compute_edges_start_thread(const goto_programt &goto_program, const goto_programt::instructiont &instruction, goto_programt::const_targett next_PC, entryt &entry)
Definition: cfg.h:360
base_grapht::nodet nodet
Definition: cfg.h:92
void operator()(P &goto_program)
Definition: cfg.h:222
cfg_baset()
Definition: cfg.h:199
const nodet & get_node(const goto_programt::const_targett &program_point) const
Get the CFG graph node relating to program_point.
Definition: cfg.h:251
entryt get_node_index(const goto_programt::const_targett &program_point) const
Get the graph node index for program_point.
Definition: cfg.h:239
entry_mapt entry_map
Definition: cfg.h:152
nodet & get_node(const goto_programt::const_targett &program_point)
Get the CFG graph node relating to program_point.
Definition: cfg.h:245
void operator()(const goto_functionst &goto_functions)
Definition: cfg.h:207
grapht< cfg_base_nodet< T, I > > base_grapht
Definition: cfg.h:88
void compute_edges(const goto_functionst &goto_functions, const goto_programt &goto_program, I PC)
Definition: cfg.h:454
virtual void compute_edges_throw(const goto_programt &goto_program, const goto_programt::instructiont &instruction, goto_programt::const_targett next_PC, entryt &entry)
Definition: cfg.h:350
virtual void compute_edges_goto(const goto_programt &goto_program, const goto_programt::instructiont &instruction, goto_programt::const_targett next_PC, entryt &entry)
Definition: cfg.h:315
static bool nodes_empty(P &program)
Definition: cfg.h:272
GOTO-instruction to location number functor.
Definition: cfg.h:50
std::size_t operator()(const goto_programt::const_targett &t) const
Definition: cfg.h:52
Functor to convert cfg nodes into dense integers, used by cfg_baset.
Definition: cfg.h:39
std::size_t operator()(T &&t) const
Definition: cfg.h:41
virtual void compute_edges_start_thread(const goto_programt &goto_program, const goto_programt::instructiont &instruction, goto_programt::const_targett next_PC, typename cfg_baset< T, P, I >::entryt &entry)
Definition: cfg.h:371
A map type that is backed by a vector, which relies on the ability to (a) see the keys that might be ...
void setup_for_keys(Iter first, Iter last)
Set the keys that are allowed to be used in this container.
const_iterator cbegin() const
iterator_templatet< typename backing_storet::const_iterator, const typename backing_storet::value_type > const_iterator
const iterator.
std::pair< iterator, bool > insert(const std::pair< const K, V > &pair)
iterator_templatet< typename backing_storet::iterator, typename backing_storet::value_type > iterator
iterator.
const_iterator cend() const
const V & at(const K &key) const
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:38
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
bool is_false() const
Return whether the expression is a constant representing false.
Definition: expr.cpp:34
A collection of goto functions.
function_mapt function_map
This class represents an instruction in the GOTO intermediate representation.
Definition: goto_program.h:181
const exprt & condition() const
Get the condition of gotos, assume, assert.
Definition: goto_program.h:366
const exprt & call_function() const
Get the function that is called for FUNCTION_CALL.
Definition: goto_program.h:272
targetst targets
The list of successor instructions.
Definition: goto_program.h:414
const_targett get_target() const
Returns the first (and only) successor for the usual case of a single target.
Definition: goto_program.h:418
goto_program_instruction_typet type() const
What kind of instruction?
Definition: goto_program.h:344
A generic container class for the GOTO intermediate representation of one function.
Definition: goto_program.h:73
instructionst instructions
The list of instructions in the goto program.
Definition: goto_program.h:622
instructionst::const_iterator const_targett
Definition: goto_program.h:615
This class represents a node in a directed graph.
Definition: graph.h:35
A generic directed graph with a parametric node type.
Definition: graph.h:167
nodet::node_indext node_indext
Definition: graph.h:173
node_indext add_node(arguments &&... values)
Definition: graph.h:180
Identity functor. When we use C++20 this can be replaced with std::identity.
virtual void compute_edges_function_call(const goto_functionst &goto_functions, const goto_programt &goto_program, const goto_programt::instructiont &instruction, goto_programt::const_targett next_PC, typename cfg_baset< T, P, I >::entryt &entry)
Definition: cfg.h:437
const irep_idt & get_identifier() const
Definition: std_expr.h:160
Dense integer map.
Goto Programs with Functions.
@ FUNCTION_CALL
Definition: goto_program.h:49
@ ATOMIC_END
Definition: goto_program.h:44
@ DEAD
Definition: goto_program.h:48
@ LOCATION
Definition: goto_program.h:41
@ END_FUNCTION
Definition: goto_program.h:42
@ ASSIGN
Definition: goto_program.h:46
@ ASSERT
Definition: goto_program.h:36
@ SET_RETURN_VALUE
Definition: goto_program.h:45
@ ATOMIC_BEGIN
Definition: goto_program.h:43
@ CATCH
Definition: goto_program.h:51
@ END_THREAD
Definition: goto_program.h:40
@ SKIP
Definition: goto_program.h:38
@ NO_INSTRUCTION_TYPE
Definition: goto_program.h:33
@ START_THREAD
Definition: goto_program.h:39
@ THROW
Definition: goto_program.h:50
@ DECL
Definition: goto_program.h:47
@ OTHER
Definition: goto_program.h:37
@ GOTO
Definition: goto_program.h:34
@ INCOMPLETE_GOTO
Definition: goto_program.h:52
@ ASSUME
Definition: goto_program.h:35
A Template Class for Graphs.
#define UNREACHABLE
This should be used to mark dead code.
Definition: invariant.h:525
API to expression classes.
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition: std_expr.h:272
graph_nodet< empty_edget >::edgest edgest
Definition: cfg.h:30
graph_nodet< empty_edget >::edget edget
Definition: cfg.h:29