@@ -11,7 +11,6 @@ Date: September 2021
11
11
#include " utils.h"
12
12
13
13
#include < util/c_types.h>
14
- #include < util/exception_utils.h>
15
14
#include < util/fresh_symbol.h>
16
15
#include < util/graph.h>
17
16
#include < util/mathematical_expr.h>
@@ -450,81 +449,107 @@ void add_quantified_variable(
450
449
}
451
450
}
452
451
453
- void replace_history_parameter (
452
+ static void replace_history_parameter_rec (
454
453
symbol_table_baset &symbol_table,
455
454
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,
458
457
const irep_idt &mode,
459
458
goto_programt &history,
460
- const irep_idt &id )
459
+ const irep_idt &history_id )
461
460
{
462
461
for (auto &op : expr.operands ())
463
462
{
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 );
466
465
}
467
466
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 ;
471
469
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 ||
475
474
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 ());
479
479
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)});
517
484
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);
527
512
}
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;
528
553
}
529
554
530
555
void generate_history_variables_initialization (
@@ -533,19 +558,12 @@ void generate_history_variables_initialization(
533
558
const irep_idt &mode,
534
559
goto_programt &program)
535
560
{
536
- std::map<exprt, exprt> parameter2history;
537
- goto_programt history;
538
561
// 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 );
547
565
// Add all the history variable initialization instructions
548
- program.destructive_append (history );
566
+ program.destructive_append (result. history_construction );
549
567
}
550
568
551
569
bool is_transformed_loop_head (const goto_programt::const_targett &target)
0 commit comments