1/*******************************************************************\
3Module: Simplify State Expressions
5Author: Daniel Kroening, dkr@amazon.com
7\*******************************************************************/
33 const std::unordered_set<symbol_exprt, irep_hash> &
address_taken,
48 const std::unordered_set<symbol_exprt, irep_hash> &
address_taken,
59 std::cout <<
"E: " <<
format(evaluate_expr.
address()) <<
"\n";
60 std::cout <<
"T: " <<
format(evaluate_expr.
address().type()) <<
"\n";
70 std::cout <<
"M: ?\n";
78 // The object is known to be the same.
88 // The object is known to be different.
89 // (ς[❝x❞:=V])(❝y❞) --> ς(❝y❞)
90 // It might be possible to further simplify ς(❝y❞).
96 // The object may or may not be the same.
97 // (ς[A:=V])(B) --> if cond then V else ς(B) endif
119 // Types are compatible?
123 // Disregard case where the two memory regions overlap.
126 // IF same_object(w, r) ∧ offset(w) = offset(r) THEN
160 // Complex case. Types don't match.
181 // A store does not affect the result.
182 // allocate(ς[A:=V]), size) --> allocate(ς, size)
202 return std::move(src);
211 // const auto &allocate_expr = to_allocate_expr(evaluate_expr.state());
221 auto symbol_expr =
symbol_exprt(identifier, object_type);
224 return std::move(evaluate_expr);
233 return std::move(evaluate_expr);
242 // deallocate isn't visible to 'evaluate'
290 return src;
// no change
298 return src;
// no change
311 const std::unordered_set<symbol_exprt, irep_hash> &
address_taken,
314 const auto &pointer = src.
address();
322 if(identifier.starts_with(
"allocate-"))
325 else if(identifier ==
"return_value")
329 else if(identifier.starts_with(
"va_args::"))
335 const auto &symbol = ns.
lookup(identifier);
336 if(symbol.is_static_lifetime)
343 // A store does not affect the result.
344 // live_object(ς[A:=V]), p) --> live_object(ς, p)
355 // live_object(deallocate_state(ς, p), q) -->
356 // IF same_object(p, q) THEN false ELSE live_object(ς, q) ENDIF
367 // This begins the life of a local-scoped variable.
373 // live_object(enter_scope_state(ς, p), q) -->
374 // IF same_object(p, q) THEN true ELSE live_object(ς, q) ENDIF
396 // This ends the life of a local-scoped variable.
401 // live_object(exit_scope_state(ς, p), q) -->
402 // IF same_object(p, q) THEN false ELSE live_object(ς, q) ENDIF
422 return std::move(src);
429 const auto &pointer = src.
address();
437 if(identifier.starts_with(
"allocate-"))
440 else if(identifier.starts_with(
"va_args::"))
446 const auto &symbol = ns.
lookup(identifier);
451 // A store does not affect the result.
452 // writeable_object(ς[A:=V]), p) --> writeable_object(ς, p)
456 return std::move(src);
459 return std::move(src);
464 const auto &pointer = src.
address();
470 // these are not dynamic
474 // A store does not affect the result.
475 // is_dynamic_object(ς[A:=V]), p) --> is_dynamic_object(ς, p)
493 return std::move(src);
500 const auto &pointer = src.
address();
511 return std::move(src);
// no change
514 // A store does not affect the result.
515 // object_size(ς[A:=V]), p) --> object_size(ς, p)
525 return std::move(src);
530 const std::unordered_set<symbol_exprt, irep_hash> &
address_taken,
533 auto &state = src.
state();
535 auto &size = src.
size();
539 // A store does not affect the result.
540 // X_ok(ς[A:=V]), A, S) --> X_ok(ς, A, S)
555 // replace array by array[0]
576 // Known to be live, only need to check upper bound.
577 // Extend one bit, to cover overflow case.
585 return std::move(src);
613 // Known to be dead if it's the same object.
626 return std::move(src);
630static bool is_one(
const exprt &src)
637 return value_opt.has_value() && *value_opt == 1;
664 const std::unordered_set<symbol_exprt, irep_hash> &
address_taken,
668 const auto &state = src.
state();
669 const auto &pointer = src.
address();
686 // cstring(s[x:=v], p) --> cstring(s, p)
692 // Are we writing zero?
695 // cstring(s[p:=0], q) --> if p alias q then true else cstring(s, q)
728 // is_cstring(ς, p + 1)) --> is_cstring(ς, p) ∨ ς(p)=0
743 // is_cstring(ς, &"...")) --> true
752 // TODO: compare offset to length
753 // is_cstring(ς, element_address(&"...", 0))) --> true
757 return std::move(src);
762 const std::unordered_set<symbol_exprt, irep_hash> &
address_taken,
765 const auto &state = src.
state();
766 const auto &pointer = src.
address();
782 // cstrlen(s[x:=v], p) --> cstrlen(s, p)
788 // Are we writing zero?
791 // cstrlen(s[p:=0], p) --> 0
803 // is_cstring(ς, p + 1)) --> is_cstring(ς, p) ∨ ς(p)=0
819 // is_cstring(ς, &"...")) --> true
830 // TODO: compare offset to length
831 // is_cstring(ς, element_address(&"...", 0))) --> true
836 return std::move(src);
841 const std::unordered_set<symbol_exprt, irep_hash> &
address_taken,
845 const auto &state = src.
state();
846 const auto &head = src.
head();
847 const auto &tail = src.
tail();
850 // ς(h.❝n❞) = t ∧ ς(t.❝p❞) = h --> is_sentinel_dll(ς, h, t)
870 // are we writing to something that might be a node pointer?
872 if(update_type != src.
head().type())
874 // update is irrelevant, drop update
894 return std::move(src);
899 const std::unordered_set<symbol_exprt, irep_hash> &
address_taken,
904 // pointer_offset(❝x❞) -> 0
910 // pointer_offset(element_address(Z, y)) -->
911 // pointer_offset(Z) + y*sizeof(x)
924 return std::move(
sum);
937 // remove the typecast
945 return std::move(src);
950 const std::unordered_set<symbol_exprt, irep_hash> &
address_taken,
958 return std::move(src);
963 const std::unordered_set<symbol_exprt, irep_hash> &
address_taken,
1037 // element_address(X, Y) + Z --> element_address(X, Y + Z)
1089 const std::unordered_set<symbol_exprt, irep_hash> &
address_taken,
1092 // operands first, recursively
1096 // now the node itself
std::unordered_set< symbol_exprt, irep_hash > address_taken(const std::vector< exprt > &src)
const bitvector_typet & to_bitvector_type(const typet &type)
Cast a typet to a bitvector_typet.
byte_extract_exprt make_byte_extract(const exprt &_op, const exprt &_offset, const typet &_type)
Construct a byte_extract_exprt with endianness and byte width matching the current configuration.
bitvector_typet char_type()
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
allocate_exprt with_state(exprt state) const
const exprt & state() const
Boolean AND All operands must be boolean, and the result is always boolean.
A base class for relations, i.e., binary predicates whose two operands have the same type.
std::size_t get_width() const
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Operator to return the address of an array element relative to a base address.
const exprt & address() const
const exprt & state() const
evaluate_exprt with_state(exprt state) const
Base class for all expressions.
bool is_constant() const
Return whether the expression is a constant.
typet & type()
Return the type of the expression.
The Boolean constant false.
The trinary if-then-else operator.
const irep_idt & id() const
Binary multiplication Associativity is not specified.
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
bool lookup(const irep_idt &name, const symbolt *&symbol) const override
See documentation for namespace_baset::lookup().
Operator to return the address of an object.
Boolean OR All operands must be boolean, and the result is always boolean.
The plus expression Associativity is not specified.
A numerical identifier for the object a pointer points to.
The offset (in bytes) of a pointer relative to the object.
const exprt & state() const
state_cstrlen_exprt with_state(exprt state) const
const exprt & address() const
const exprt & address() const
const exprt & state() const
state_is_cstring_exprt with_state(exprt state) const
const exprt & state() const
const exprt & address() const
state_is_dynamic_object_exprt with_state(exprt state) const
const exprt & head() const
const exprt & state() const
state_is_sentinel_dll_exprt with_state(exprt state) const
const exprt & tail() const
const exprt & address() const
const exprt & state() const
state_live_object_exprt with_state(exprt state) const
const exprt & state() const
state_object_size_exprt with_state(exprt state) const
const exprt & address() const
state_ok_exprt with_state(exprt state) const
const exprt & size() const
const exprt & address() const
const exprt & state() const
const exprt & address() const
const exprt & state() const
Expression to hold a symbol (variable)
The Boolean constant true.
Semantic type conversion.
static exprt conditional_cast(const exprt &expr, const typet &type)
The type of an expression, extends irept.
Fixed-width bit-vector with unsigned binary interpretation.
constant_exprt make_boolean_expr(bool value)
returns true_exprt if given true and false_exprt otherwise
Deprecated expression utility functions.
static exprt implication(exprt lhs, exprt rhs)
std::optional< exprt > may_alias(const exprt &a, const exprt &b, const std::unordered_set< symbol_exprt, irep_hash > &address_taken, const namespacet &ns)
exprt may_be_same_object(const exprt &a, const exprt &b, const std::unordered_set< symbol_exprt, irep_hash > &address_taken, const namespacet &ns)
const element_address_exprt & to_element_address_expr(const exprt &expr)
Cast an exprt to an element_address_exprt.
const object_address_exprt & to_object_address_expr(const exprt &expr)
Cast an exprt to an object_address_exprt.
const address_of_exprt & to_address_of_expr(const exprt &expr)
Cast an exprt to an address_of_exprt.
const pointer_typet & to_pointer_type(const typet &type)
Cast a typet to a pointer_typet.
const pointer_offset_exprt & to_pointer_offset_expr(const exprt &expr)
Cast an exprt to a pointer_offset_exprt.
const pointer_object_exprt & to_pointer_object_expr(const exprt &expr)
Cast an exprt to a pointer_object_exprt.
const field_address_exprt & to_field_address_expr(const exprt &expr)
Cast an exprt to an field_address_exprt.
std::optional< exprt > size_of_expr(const typet &type, const namespacet &ns)
exprt pointer_offset(const exprt &pointer)
exprt object_size(const exprt &pointer)
exprt same_object(const exprt &p1, const exprt &p2)
Various predicates over pointers in programs.
std::optional< exprt > sentinel_dll_prev(const exprt &state, const exprt &node, const namespacet &ns)
std::optional< exprt > sentinel_dll_next(const exprt &state, const exprt &node, const namespacet &ns)
const state_is_sentinel_dll_exprt & to_state_is_sentinel_dll_expr(const exprt &expr)
Cast an exprt to a state_is_sentinel_dll_exprt.
exprt simplify_expr(exprt src, const namespacet &ns)
exprt simplify_evaluate_enter_scope_state(evaluate_exprt evaluate_expr, const namespacet &ns)
exprt simplify_allocate(allocate_exprt src)
exprt simplify_is_dynamic_object_expr(state_is_dynamic_object_exprt src)
exprt simplify_object_expression_rec(exprt src)
static bool is_zero_char(const exprt &src, const namespacet &ns)
exprt simplify_live_object_expr(state_live_object_exprt src, const std::unordered_set< symbol_exprt, irep_hash > &address_taken, const namespacet &ns)
exprt simplify_is_sentinel_dll_expr(state_is_sentinel_dll_exprt src, const std::unordered_set< symbol_exprt, irep_hash > &address_taken, const namespacet &ns)
exprt simplify_evaluate_exit_scope_state(evaluate_exprt evaluate_expr, const namespacet &ns)
exprt simplify_ok_expr(state_ok_exprt src, const std::unordered_set< symbol_exprt, irep_hash > &address_taken, const namespacet &ns)
exprt simplify_state_expr_node(exprt, const std::unordered_set< symbol_exprt, irep_hash > &address_taken, const namespacet &)
exprt simplify_is_cstring_expr(state_is_cstring_exprt src, const std::unordered_set< symbol_exprt, irep_hash > &address_taken, const namespacet &ns)
exprt simplify_evaluate_update(evaluate_exprt evaluate_expr, const std::unordered_set< symbol_exprt, irep_hash > &address_taken, const namespacet &ns)
exprt simplify_cstrlen_expr(state_cstrlen_exprt src, const std::unordered_set< symbol_exprt, irep_hash > &address_taken, const namespacet &ns)
std::size_t allocate_counter
exprt simplify_pointer_offset_expr(pointer_offset_exprt src, const std::unordered_set< symbol_exprt, irep_hash > &address_taken, const namespacet &ns)
static bool is_a_char_type(const typet &type)
exprt simplify_evaluate_deallocate_state(evaluate_exprt evaluate_expr, const namespacet &ns)
exprt simplify_object_expression(exprt src)
exprt simplify_object_size_expr(state_object_size_exprt src, const namespacet &ns)
exprt simplify_state_expr(exprt src, const std::unordered_set< symbol_exprt, irep_hash > &address_taken, const namespacet &ns)
exprt simplify_writeable_object_expr(state_writeable_object_exprt src, const namespacet &ns)
exprt simplify_pointer_object_expr(pointer_object_exprt src, const std::unordered_set< symbol_exprt, irep_hash > &address_taken, const namespacet &ns)
exprt simplify_evaluate_allocate_state(evaluate_exprt evaluate_expr, const namespacet &ns)
static bool types_are_compatible(const typet &a, const typet &b)
Simplify State Expression.
#define PRECONDITION(CONDITION)
const state_ok_exprt & to_state_ok_expr(const exprt &expr)
Cast an exprt to a state_ok_exprt.
const state_is_cstring_exprt & to_state_is_cstring_expr(const exprt &expr)
Cast an exprt to a state_is_cstring_exprt.
const state_cstrlen_exprt & to_state_cstrlen_expr(const exprt &expr)
Cast an exprt to a state_cstrlen_exprt.
const exit_scope_state_exprt & to_exit_scope_state_expr(const exprt &expr)
Cast an exprt to a exit_scope_state_exprt.
const enter_scope_state_exprt & to_enter_scope_state_expr(const exprt &expr)
Cast an exprt to a enter_scope_state_exprt.
const state_writeable_object_exprt & to_state_writeable_object_expr(const exprt &expr)
Cast an exprt to a state_writeable_object_exprt.
const state_is_dynamic_object_exprt & to_state_is_dynamic_object_expr(const exprt &expr)
Cast an exprt to a state_is_dynamic_object_exprt.
const state_object_size_exprt & to_state_object_size_expr(const exprt &expr)
Cast an exprt to a state_object_size_exprt.
const update_state_exprt & to_update_state_expr(const exprt &expr)
Cast an exprt to a update_state_exprt.
const deallocate_state_exprt & to_deallocate_state_expr(const exprt &expr)
Cast an exprt to a deallocate_state_exprt.
const allocate_exprt & to_allocate_expr(const exprt &expr)
Cast an exprt to a allocate_exprt.
const evaluate_exprt & to_evaluate_expr(const exprt &expr)
Cast an exprt to a evaluate_exprt.
const state_live_object_exprt & to_state_live_object_expr(const exprt &expr)
Cast an exprt to a state_live_object_exprt.
API to expression classes.
const typecast_exprt & to_typecast_expr(const exprt &expr)
Cast an exprt to a typecast_exprt.
const plus_exprt & to_plus_expr(const exprt &expr)
Cast an exprt to a plus_exprt.
const equal_exprt & to_equal_expr(const exprt &expr)
Cast an exprt to an equal_exprt.
const array_typet & to_array_type(const typet &type)
Cast a typet to an array_typet.