1/*******************************************************************\
3Module: Program Transformation
5Author: Daniel Kroening, kroening@kroening.com
7\*******************************************************************/
26#include <unordered_map>
56 throw "unsupported expression type for finding base symbol";
69 converter.goto_convert(code, where, mode);
74 natural_loops.
loop_map.size() == 0,
"quantifier must not contain loops");
77 // All bound variables are local.
80 // `last` is the instruction corresponding to the last expression in the
81 // statement expression.
87 // `last` is an other-instruction.
101 "expression statements must contain a terminator expression");
113 // `paths` contains all the `targett` we are iterating over.
114 std::vector<goto_programt::const_targett> paths;
118 std::vector<goto_programt::const_targett> paths,
119 std::vector<std::pair<exprt, replace_mapt>>
128 return paths.empty();
151 paths.push_back(target);
169 // Visit the quantifier body along `paths`.
170 while(!paths.empty())
174 auto &value_map = paths.back_value_map();
184 // Add all local-declared symbols into `declared_symbols`.
190 // Add the replace lhr <- value_map(rhs) to the current value_map.
193 // Check that if lhs is a declared symbol.
197 "quantifier must not contain side effects");
200 value_map[lhs] = rhs;
206 // Move the current targett to label.
208 // IF cond GOTO label
210 // Move the current targett to targett+1 with path condition
211 // path_condition && !cond;
212 // and add a new path starting from label with path condition
213 // path_condition && cond.
218 if(condition !=
true)
235 // The last instruction is an expression statement.
236 // We add the predicate path_condition ==> value_map(expr) to res.
250 // Ignored instructions.
261 // Unsupported instructions.
293 new_symbol.
value = expr;
295 // The value might depend on a variable, thus
296 // generate code for this.
299 result.add_source_location() = source_location;
301 // The lifetime of compound literals is really that of
302 // the block they are in.
307 code_assign.add_source_location() = source_location;
310 // now create a 'dead' instruction
334 // We can't flatten quantified expressions by introducing new literals for
335 // conditional expressions. This is because the body of the quantified
336 // may refer to bound variables, which are not visible outside the scope
337 // of the quantifier.
339 // For example, the following transformation would not be valid:
341 // forall (i : int) (i == 0 || i > 10)
347 // forall (i : int) (g1 || g2)
351 // Need cleaning when the quantifier body is a side-effect expression.
358 for(
const auto &op : expr.
operands())
377 "' must be Boolean, but got ",
382 // re-write "a ==> b" into a?b:1
386 std::move(implies->lhs()),
387 std::move(implies->rhs()),
393 // re-write "a && b" into nested a?b:0
394 // re-write "a || b" into nested a?1:b
403 tmp.add_source_location() = source_location;
407 // start with last one
408 for(exprt::operandst::reverse_iterator it =
ops.rbegin(); it !=
ops.rend();
415 "boolean operators must have only boolean operands",
430 .with_source_location(source_location);
446 // && || ==> ?: comma (control-dependency)
448 // object constructors like arrays, string constants, structs
449 // ++ -- (pre and post)
450 // compound assignments
466 // first clean condition
483 "condition for an 'if' must be boolean",
484 if_expr.find_source_location());
489 // We do some constant-folding here, to mimic
490 // what typical compilers do.
541 // preserve the expressions for possible later checks
542 if(
if_expr.true_case().is_not_nil())
544 // add a (void) type cast so that is_skip catches it in case the
545 // expression is just a constant
551 if(
if_expr.false_case().is_not_nil())
553 // add a (void) type cast so that is_skip catches it in case the
554 // expression is just a constant
563 // generate guard for argument side-effects
568 if_expr.true_case().source_location(),
570 if_expr.false_case().source_location(),
594 bool last = (it == --expr.
operands().end());
596 // special treatment for last one
606 // remember these for later checks
614 else // result not used
620 // remember as expression statement for later checks
634 // preserve 'result_is_used'
638 if(typecast.
op().is_nil())
645 // some of the side-effects need special treatment!
650 // need to do separately
655 // need to do separately to prevent that
656 // the operands of expr get 'cleaned'
662 // we do a special treatment for x=f(...)
665 "side-effect assignment expressions must have two operands");
711 code.operands()[0].get_named_sub()[
ID_statement].id() ==
713 "quantifier must not contain side effects");
715 // Handle the case that quantifier body is a statement expression.
718 code.operands()[0].get_named_sub()[
ID_statement].id() ==
735 // TODO: evaluation order
747 // This is simply replaced by the literal
749 expr.
operands().size() == 1,
"ID_compound_literal has a single operand");
761 // The address of object constructors can be taken,
762 // which is re-written into the address of a variable.
767 expr.
operands().size() == 1,
"ID_compound_literal has a single operand");
774 // Leave for now, but long-term these might become static symbols.
775 // LLVM appears to do precisely that.
790 // Yes, one can take the address of a comma expression.
791 // Treatment is similar to clean_expr() above.
797 bool last = (it == --expr.
operands().end());
799 // special treatment for last one
806 // get any side-effects
839 // first remove side-effects from condition
842 // now we can copy op0 safely
853 // there might still be junk in expr.op2()
@ AUTOMATIC_LOCAL
Allocate local objects with automatic lifetime.
Operator to return the address of an object.
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Boolean AND All operands must be boolean, and the result is always boolean.
A goto_instruction_codet representing an assignment in the program.
A goto_instruction_codet representing the removal of a local variable going out of scope.
A goto_instruction_codet representing the declaration of a local variable.
codet representation of an expression statement.
const exprt & expression() const
Operator to dereference a pointer.
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Base class for all expressions.
const source_locationt & find_source_location() const
Get a source_locationt from the expression or from its operands (non-recursively).
std::vector< exprt > operandst
bool is_boolean() const
Return whether the expression represents a Boolean.
typet & type()
Return the type of the expression.
const source_locationt & source_location() const
source_locationt & add_source_location()
exprt & with_source_location(source_locationt location) &
Add the source location from location, if it is non-nil.
The Boolean constant false.
clean_expr_resultt clean_expr_address_of(exprt &expr, const irep_idt &mode)
symbol_table_baset & symbol_table
void convert_assign(const code_assignt &code, goto_programt &dest, const irep_idt &mode)
clean_expr_resultt remove_gcc_conditional_expression(exprt &expr, const irep_idt &mode)
void copy(const codet &code, goto_program_instruction_typet type, goto_programt &dest)
void generate_ifthenelse(const exprt &cond, const source_locationt &, goto_programt &true_case, const source_locationt &, goto_programt &false_case, const source_locationt &, goto_programt &dest, const irep_idt &mode)
if(guard) true_case; else false_case;
std::string tmp_symbol_prefix
struct goto_convertt::targetst targets
symbolt & new_tmp_symbol(const typet &type, const std::string &suffix, goto_programt &dest, const source_locationt &, const irep_idt &mode)
symbol_exprt make_compound_literal(const exprt &expr, goto_programt &dest, const irep_idt &mode)
clean_expr_resultt remove_side_effect(side_effect_exprt &expr, const irep_idt &mode, bool result_is_used, bool address_taken)
static bool needs_cleaning(const exprt &expr)
Returns 'true' for expressions that may change the program state.
void convert(const codet &code, goto_programt &dest, const irep_idt &mode)
converts 'code' and appends the result to 'dest'
clean_expr_resultt remove_function_call(side_effect_expr_function_callt &expr, const irep_idt &mode, bool result_is_used)
clean_expr_resultt remove_statement_expression(side_effect_exprt &expr, const irep_idt &mode, bool result_is_used)
clean_expr_resultt clean_expr(exprt &expr, const irep_idt &mode, bool result_is_used=true)
void rewrite_boolean(exprt &dest)
re-write boolean operators into ?:
static bool assignment_lhs_needs_temporary(const exprt &lhs)
A generic container class for the GOTO intermediate representation of one function.
instructionst instructions
The list of instructions in the goto program.
instructionst::const_iterator const_targett
void compute_location_numbers(unsigned &nr)
Compute location numbers.
The trinary if-then-else operator.
const irep_idt & id() const
message_handlert & get_message_handler()
mstreamt & result() const
A base class for quantifier expressions.
const irep_idt & get_statement() const
Expression to hold a symbol (variable)
The symbol table base class interface.
class symbol_exprt symbol_expr() const
Produces a symbol_exprt for a symbol.
exprt value
Initial value of symbol.
The Boolean constant true.
Semantic type conversion.
static exprt conditional_cast(const exprt &expr, const typet &type)
void destruct_locals(const std::list< irep_idt > &vars, goto_programt &dest, const namespacet &ns)
#define Forall_operands(it, expr)
const exprt & skip_typecast(const exprt &expr)
find the expression nested inside typecasts, if any
bool has_subexpr(const exprt &expr, const std::function< bool(const exprt &)> &pred)
returns true if the expression has a subexpression that satisfies pred
Deprecated expression utility functions.
symbolt & get_fresh_aux_symbol(const typet &type, const std::string &name_prefix, const std::string &basename_prefix, const source_locationt &source_location, const irep_idt &symbol_mode, const namespacet &ns, symbol_table_baset &symbol_table)
Installs a fresh-named symbol with respect to the given namespace ns with the requested name pattern ...
Fresh auxiliary symbol creation.
static symbol_exprt find_base_symbol(const exprt &expr)
static exprt convert_statement_expression(const quantifier_exprt &qex, const code_expressiont &code, const irep_idt &mode, symbol_table_baset &symbol_table, message_handlert &message_handler)
API to expression classes for 'mathematical' expressions.
const quantifier_exprt & to_quantifier_expr(const exprt &expr)
Cast an exprt to a quantifier_exprt.
Compute natural loops in a goto_function.
std::list< patht > pathst
API to expression classes for Pointers.
const address_of_exprt & to_address_of_expr(const exprt &expr)
Cast an exprt to an address_of_exprt.
const dereference_exprt & to_dereference_expr(const exprt &expr)
Cast an exprt to a dereference_exprt.
bool replace_expr(const exprt &what, const exprt &by, exprt &dest)
std::unordered_map< exprt, exprt, irep_hash > replace_mapt
exprt deref_expr(const exprt &expr)
Wraps a given expression into a dereference_exprt unless it is an address_of_exprt in which case it j...
bool simplify(exprt &expr, const namespacet &ns)
#define PRECONDITION_WITH_DIAGNOSTICS(CONDITION,...)
#define UNREACHABLE
This should be used to mark dead code.
#define DATA_INVARIANT(CONDITION, REASON)
This condition should be used to document that assumptions that are made on goto_functions,...
#define PRECONDITION(CONDITION)
#define INVARIANT(CONDITION, REASON)
This macro uses the wrapper function 'invariant_violated_string'.
#define DATA_INVARIANT_WITH_DIAGNOSTICS(CONDITION, REASON,...)
side_effect_exprt & to_side_effect_expr(exprt &expr)
side_effect_expr_function_callt & to_side_effect_expr_function_call(exprt &expr)
side_effect_expr_assignt & to_side_effect_expr_assign(exprt &expr)
code_expressiont & to_code_expression(codet &code)
API to expression classes.
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
const typecast_exprt & to_typecast_expr(const exprt &expr)
Cast an exprt to a typecast_exprt.
const binary_exprt & to_binary_expr(const exprt &expr)
Cast an exprt to a binary_exprt.
const unary_exprt & to_unary_expr(const exprt &expr)
Cast an exprt to a unary_exprt.
const if_exprt & to_if_expr(const exprt &expr)
Cast an exprt to an if_exprt.
const member_exprt & to_member_expr(const exprt &expr)
Cast an exprt to a member_exprt.
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
std::list< irep_idt > temporaries
Identifiers of temporaries introduced while cleaning an expression.
void add(clean_expr_resultt &&other)
void add_temporary(const irep_idt &id)
goto_programt side_effects
Statements implementing side effects of the expression that was subject to cleaning.