CBMC
invariant_propagation.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: Invariant Propagation
4 
5 Author: Daniel Kroening, kroening@kroening.com
6 
7 \*******************************************************************/
8 
11 
12 #include "invariant_propagation.h"
13 
14 #include <util/simplify_expr.h>
15 #include <util/std_expr.h>
16 
19  : public ai_domain_factoryt<invariant_set_domaint>
20 {
21 public:
23  {
24  }
25 
26  std::unique_ptr<statet> make(locationt l) const override
27  {
28  auto p = std::make_unique<invariant_set_domaint>(
30  CHECK_RETURN(p->is_bottom());
31 
32  return std::unique_ptr<statet>(p.release());
33  }
34 
35 private:
37 };
38 
40  const namespacet &_ns,
41  value_setst &_value_sets)
43  std::make_unique<invariant_set_domain_factoryt>(*this)),
44  ns(_ns),
45  value_sets(_value_sets),
46  object_store(_ns)
47 {
48 }
49 
51 {
52  for(auto &state :
53  static_cast<location_sensitive_storaget &>(*storage).internal())
54  static_cast<invariant_set_domaint &>(*(state.second))
56 }
57 
59 {
60  for(auto &state :
61  static_cast<location_sensitive_storaget &>(*storage).internal())
62  static_cast<invariant_set_domaint &>(*(state.second))
64 }
65 
67  const goto_programt &goto_program)
68 {
69  // get the globals
70  object_listt globals;
71  get_globals(globals);
72 
73  // get the locals
75  goto_program.get_decl_identifiers(locals);
76 
77  // cache the list for the locals to speed things up
78  typedef std::unordered_map<irep_idt, object_listt> object_cachet;
79  object_cachet object_cache;
80 
81  forall_goto_program_instructions(i_it, goto_program)
82  {
83  #if 0
84  invariant_sett &is=(*this)[i_it].invariant_set;
85 
86  is.add_objects(globals);
87  #endif
88 
89  for(const auto &local : locals)
90  {
91  // cache hit?
92  object_cachet::const_iterator e_it=object_cache.find(local);
93 
94  if(e_it==object_cache.end())
95  {
96  const symbolt &symbol=ns.lookup(local);
97 
98  object_listt &objects=object_cache[local];
99  get_objects(symbol, objects);
100  #if 0
101  is.add_objects(objects);
102  #endif
103  }
104  #if 0
105  else
106  is.add_objects(e_it->second);
107  #endif
108  }
109  }
110 }
111 
113  const symbolt &symbol,
114  object_listt &dest)
115 {
116  std::list<exprt> object_list;
117 
118  get_objects_rec(symbol.symbol_expr(), object_list);
119 
120  for(const auto &expr : object_list)
121  dest.push_back(object_store.add(expr));
122 }
123 
125  const exprt &src,
126  std::list<exprt> &dest)
127 {
128  const typet &t = src.type();
129 
130  if(
131  t.id() == ID_struct || t.id() == ID_union || t.id() == ID_struct_tag ||
132  t.id() == ID_union_tag)
133  {
134  const struct_union_typet &struct_type =
135  (t.id() == ID_struct_tag || t.id() == ID_union_tag)
138 
139  for(const auto &component : struct_type.components())
140  {
141  const member_exprt member_expr(
142  src, component.get_name(), component.type());
143  // recursive call
144  get_objects_rec(member_expr, dest);
145  }
146  }
147  else if(t.id()==ID_array)
148  {
149  // get_objects_rec(identifier, suffix+"[]", t.subtype(), dest);
150  // we don't track these
151  }
152  else if(check_type(t))
153  {
154  dest.push_back(src);
155  }
156 }
157 
159  const goto_functionst &goto_functions)
160 {
161  // get the globals
162  object_listt globals;
163  get_globals(globals);
164 
165  for(const auto &gf_entry : goto_functions.function_map)
166  {
167  // get the locals
168  std::set<irep_idt> locals;
169  get_local_identifiers(gf_entry.second, locals);
170 
171  const goto_programt &goto_program = gf_entry.second.body;
172 
173  // cache the list for the locals to speed things up
174  typedef std::unordered_map<irep_idt, object_listt> object_cachet;
175  object_cachet object_cache;
176 
177  forall_goto_program_instructions(i_it, goto_program)
178  {
179  #if 0
180  invariant_sett &is=(*this)[i_it].invariant_set;
181 
182  is.add_objects(globals);
183  #endif
184 
185  for(const auto &local : locals)
186  {
187  // cache hit?
188  object_cachet::const_iterator e_it=object_cache.find(local);
189 
190  if(e_it==object_cache.end())
191  {
192  const symbolt &symbol=ns.lookup(local);
193 
194  object_listt &objects=object_cache[local];
195  get_objects(symbol, objects);
196  #if 0
197  is.add_objects(objects);
198  #endif
199  }
200  #if 0
201  else
202  is.add_objects(e_it->second);
203  #endif
204  }
205  }
206  }
207 }
208 
210  object_listt &dest)
211 {
212  // static ones
213  for(const auto &symbol_pair : ns.get_symbol_table().symbols)
214  {
215  if(symbol_pair.second.is_lvalue && symbol_pair.second.is_static_lifetime)
216  {
217  get_objects(symbol_pair.second, dest);
218  }
219  }
220 }
221 
223 {
224  if(type.id()==ID_pointer)
225  return true;
226  else if(
227  type.id() == ID_struct || type.id() == ID_union ||
228  type.id() == ID_struct_tag || type.id() == ID_union_tag)
229  {
230  return false;
231  }
232  else if(type.id()==ID_array)
233  return false;
234  else if(type.id()==ID_unsignedbv ||
235  type.id()==ID_signedbv)
236  return true;
237  else if(type.id()==ID_bool)
238  return true;
239 
240  return false;
241 }
242 
244  const irep_idt &function,
245  const goto_programt &goto_program)
246 {
247  baset::initialize(function, goto_program);
248 
249  add_objects(goto_program);
250 }
251 
253 {
254  for(auto &gf_entry : goto_functions.function_map)
255  simplify(gf_entry.second.body);
256 }
257 
259 {
260  Forall_goto_program_instructions(i_it, goto_program)
261  {
262  if(!i_it->is_assert())
263  continue;
264 
265  // find invariant set
266  const auto &d = (*this)[i_it];
267  if(d.is_bottom())
268  continue;
269 
270  const invariant_sett &invariant_set = d.invariant_set;
271 
272  exprt simplified_guard(i_it->condition());
273 
274  invariant_set.simplify(simplified_guard);
275  ::simplify(simplified_guard, ns);
276 
277  if(invariant_set.implies(simplified_guard).is_true())
278  i_it->condition_nonconst() = true_exprt();
279  }
280 }
virtual void initialize(const irep_idt &function_id, const goto_programt &goto_program)
Initialize all the abstract states for a single function.
Definition: ai.cpp:194
ai_domain_baset::locationt locationt
Definition: ai_domain.h:174
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Definition: ai.h:562
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
typet & type()
Return the type of the expression.
Definition: expr.h:84
A collection of goto functions.
function_mapt function_map
A generic container class for the GOTO intermediate representation of one function.
Definition: goto_program.h:73
std::set< irep_idt > decl_identifierst
Definition: goto_program.h:853
void get_decl_identifiers(decl_identifierst &decl_identifiers) const
get the variables in decl statements
unsigned add(const exprt &expr)
void add_objects(const goto_programt &goto_program)
void simplify(goto_programt &goto_program)
void get_objects(const symbolt &symbol, object_listt &dest)
void initialize(const irep_idt &function, const goto_programt &goto_program) override
Initialize all the abstract states for a single function.
void get_objects_rec(const exprt &src, std::list< exprt > &dest)
std::list< unsigned > object_listt
inv_object_storet object_store
bool check_type(const typet &type) const
void get_globals(object_listt &globals)
invariant_propagationt(const namespacet &_ns, value_setst &_value_sets)
Pass the necessary arguments to the invariant_set_domaint's when constructed.
std::unique_ptr< statet > make(locationt l) const override
invariant_set_domain_factoryt(invariant_propagationt &_ip)
void simplify(exprt &expr) const
tvt implies(const exprt &expr) const
const irep_idt & id() const
Definition: irep.h:388
The most conventional storage; one domain per location.
Definition: ai_storage.h:154
state_mapt & internal(void)
Definition: ai_storage.h:169
Extract member of struct or union.
Definition: std_expr.h:2854
const union_typet & follow_tag(const union_tag_typet &) const
Follow type tag of union type.
Definition: namespace.cpp:63
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition: namespace.h:94
bool lookup(const irep_idt &name, const symbolt *&symbol) const override
See documentation for namespace_baset::lookup().
Definition: namespace.cpp:148
const symbol_table_baset & get_symbol_table() const
Return first symbol table registered with the namespace.
Definition: namespace.h:126
Base type for structs and unions.
Definition: std_types.h:62
const componentst & components() const
Definition: std_types.h:147
const symbolst & symbols
Read-only field, used to look up symbols given their names.
Symbol table entry.
Definition: symbol.h:28
class symbol_exprt symbol_expr() const
Produces a symbol_exprt for a symbol.
Definition: symbol.cpp:121
The Boolean constant true.
Definition: std_expr.h:3073
bool is_true() const
Definition: threeval.h:25
The type of an expression, extends irept.
Definition: type.h:29
void get_local_identifiers(const goto_functiont &goto_function, std::set< irep_idt > &dest)
Return in dest the identifiers of the local variables declared in the goto_function and the identifie...
#define forall_goto_program_instructions(it, program)
#define Forall_goto_program_instructions(it, program)
Invariant Propagation.
#define CHECK_RETURN(CONDITION)
Definition: invariant.h:495
auto component(T &struct_expr, const irep_idt &name, const namespacet &ns) -> decltype(struct_expr.op0())
Definition: std_expr.cpp:97
API to expression classes.
const struct_union_typet & to_struct_union_type(const typet &type)
Cast a typet to a struct_union_typet.
Definition: std_types.h:214
const struct_or_union_tag_typet & to_struct_or_union_tag_type(const typet &type)
Cast a typet to a struct_or_union_tag_typet.
Definition: std_types.h:478