@@ -11,7 +11,6 @@ Date: September 2021
1111#include " utils.h"
1212
1313#include < util/c_types.h>
14- #include < util/exception_utils.h>
1514#include < util/fresh_symbol.h>
1615#include < util/graph.h>
1716#include < util/mathematical_expr.h>
@@ -450,81 +449,107 @@ void add_quantified_variable(
450449 }
451450}
452451
453- void replace_history_parameter (
452+ static void replace_history_parameter_rec (
454453 symbol_table_baset &symbol_table,
455454 exprt &expr,
456- std::map <exprt, exprt > ¶meter2history,
457- source_locationt location,
455+ std::unordered_map <exprt, symbol_exprt, irep_hash > ¶meter2history,
456+ const source_locationt & location,
458457 const irep_idt &mode,
459458 goto_programt &history,
460- const irep_idt &id )
459+ const irep_idt &history_id )
461460{
462461 for (auto &op : expr.operands ())
463462 {
464- replace_history_parameter (
465- symbol_table, op, parameter2history, location, mode, history, id );
463+ replace_history_parameter_rec (
464+ symbol_table, op, parameter2history, location, mode, history, history_id );
466465 }
467466
468- if (expr.id () == ID_old || expr.id () == ID_loop_entry)
469- {
470- const auto ¶meter = to_history_expr (expr, id).expression ();
467+ if (expr.id () != ID_old && expr.id () != ID_loop_entry)
468+ return ;
471469
472- const auto &id = parameter.id ();
473- if (
474- id == ID_dereference || id == ID_member || id == ID_symbol ||
470+ const auto ¶meter = to_history_expr (expr, history_id).expression ();
471+ const auto &id = parameter.id ();
472+ DATA_INVARIANT_WITH_DIAGNOSTICS (
473+ id == ID_dereference || id == ID_member || id == ID_symbol ||
475474 id == ID_ptrmember || id == ID_constant || id == ID_typecast ||
476- id == ID_index)
477- {
478- auto it = parameter2history.find (parameter);
475+ id == ID_index,
476+ " Tracking history of " + id2string (id) +
477+ " expressions is not supported yet." ,
478+ parameter.pretty ());
479479
480- if (it == parameter2history.end ())
481- {
482- // 0. Create a skip target to jump to, if the parameter is invalid
483- goto_programt skip_program;
484- const auto skip_target =
485- skip_program.add (goto_programt::make_skip (location));
486-
487- // 1. Create a temporary symbol expression that represents the
488- // history variable
489- symbol_exprt tmp_symbol =
490- new_tmp_symbol (parameter.type (), location, mode, symbol_table)
491- .symbol_expr ();
492-
493- // 2. Associate the above temporary variable to it's corresponding
494- // expression
495- parameter2history[parameter] = tmp_symbol;
496-
497- // 3. Add the required instructions to the instructions list
498- // 3.1. Declare the newly created temporary variable
499- history.add (goto_programt::make_decl (tmp_symbol, location));
500-
501- // 3.2. Skip storing the history if the expression is invalid
502- history.add (goto_programt::make_goto (
503- skip_target,
504- not_exprt{
505- all_dereferences_are_valid (parameter, namespacet (symbol_table))},
506- location));
507-
508- // 3.3. Add an assignment such that the value pointed to by the new
509- // temporary variable is equal to the value of the corresponding
510- // parameter
511- history.add (
512- goto_programt::make_assignment (tmp_symbol, parameter, location));
513-
514- // 3.4. Add a skip target
515- history.destructive_append (skip_program);
516- }
480+ // speculatively insert a dummy, which will be replaced below if the insert
481+ // actually happened
482+ auto entry =
483+ parameter2history.insert ({parameter, symbol_exprt::typeless (ID_nil)});
517484
518- expr = parameter2history[parameter];
519- }
520- else
521- {
522- throw invalid_source_file_exceptiont (
523- " Tracking history of " + id2string (parameter.id ()) +
524- " expressions is not supported yet." ,
525- expr.source_location ());
526- }
485+ if (entry.second )
486+ {
487+ // 1. Create a temporary symbol expression that represents the
488+ // history variable
489+ entry.first ->second =
490+ new_tmp_symbol (parameter.type (), location, mode, symbol_table)
491+ .symbol_expr ();
492+
493+ // 2. Add the required instructions to the instructions list
494+ // 2.1. Declare the newly created temporary variable
495+ history.add (goto_programt::make_decl (entry.first ->second , location));
496+
497+ // 2.2. Skip storing the history if the expression is invalid
498+ auto goto_instruction = history.add (goto_programt::make_incomplete_goto (
499+ not_exprt{
500+ all_dereferences_are_valid (parameter, namespacet (symbol_table))},
501+ location));
502+
503+ // 2.3. Add an assignment such that the value pointed to by the new
504+ // temporary variable is equal to the value of the corresponding
505+ // parameter
506+ history.add (
507+ goto_programt::make_assignment (entry.first ->second , parameter, location));
508+
509+ // 2.4. Complete conditional jump for invalid-parameter case
510+ auto label_instruction = history.add (goto_programt::make_skip (location));
511+ goto_instruction->complete_goto (label_instruction);
527512 }
513+
514+ expr = entry.first ->second ;
515+ }
516+
517+ replace_history_parametert replace_history_old (
518+ symbol_table_baset &symbol_table,
519+ const exprt &expr,
520+ const source_locationt &location,
521+ const irep_idt &mode)
522+ {
523+ replace_history_parametert result;
524+ result.expression_after_replacement = expr;
525+ replace_history_parameter_rec (
526+ symbol_table,
527+ result.expression_after_replacement ,
528+ result.parameter_to_history ,
529+ location,
530+ mode,
531+ result.history_construction ,
532+ ID_old);
533+ return result;
534+ }
535+
536+ replace_history_parametert replace_history_loop_entry (
537+ symbol_table_baset &symbol_table,
538+ const exprt &expr,
539+ const source_locationt &location,
540+ const irep_idt &mode)
541+ {
542+ replace_history_parametert result;
543+ result.expression_after_replacement = expr;
544+ replace_history_parameter_rec (
545+ symbol_table,
546+ result.expression_after_replacement ,
547+ result.parameter_to_history ,
548+ location,
549+ mode,
550+ result.history_construction ,
551+ ID_loop_entry);
552+ return result;
528553}
529554
530555void generate_history_variables_initialization (
@@ -533,19 +558,12 @@ void generate_history_variables_initialization(
533558 const irep_idt &mode,
534559 goto_programt &program)
535560{
536- std::map<exprt, exprt> parameter2history;
537- goto_programt history;
538561 // Find and replace "old" expression in the "expression" variable
539- replace_history_parameter (
540- symbol_table,
541- clause,
542- parameter2history,
543- clause.source_location (),
544- mode,
545- history,
546- ID_old);
562+ auto result =
563+ replace_history_old (symbol_table, clause, clause.source_location (), mode);
564+ clause.swap (result.expression_after_replacement );
547565 // Add all the history variable initialization instructions
548- program.destructive_append (history );
566+ program.destructive_append (result. history_construction );
549567}
550568
551569bool is_transformed_loop_head (const goto_programt::const_targett &target)
0 commit comments