Skip to content

Commit 8c152bc

Browse files
authored
Merge pull request #7686 from tautschnig/cleanup/refactor-replace_history_parameter
Refactor replace_history_parameter
2 parents ba47c86 + 74159df commit 8c152bc

File tree

5 files changed

+132
-118
lines changed

5 files changed

+132
-118
lines changed

src/goto-instrument/contracts/contracts.cpp

+8-13
Original file line numberDiff line numberDiff line change
@@ -125,21 +125,16 @@ void code_contractst::check_apply_loop_contracts(
125125
//
126126
// Assertions for assigns clause checking are inserted in the loop body.
127127

128-
// an intermediate goto_program to store generated instructions
129-
// to be inserted before the loop head
130-
goto_programt pre_loop_head_instrs;
131-
132128
// Process "loop_entry" history variables.
133129
// We find and replace all "__CPROVER_loop_entry" subexpressions in invariant.
134-
std::map<exprt, exprt> history_var_map;
135-
replace_history_parameter(
136-
symbol_table,
137-
invariant,
138-
history_var_map,
139-
loop_head_location,
140-
mode,
141-
pre_loop_head_instrs,
142-
ID_loop_entry);
130+
auto replace_history_result = replace_history_loop_entry(
131+
symbol_table, invariant, loop_head_location, mode);
132+
invariant.swap(replace_history_result.expression_after_replacement);
133+
const auto &history_var_map = replace_history_result.parameter_to_history;
134+
// an intermediate goto_program to store generated instructions
135+
// to be inserted before the loop head
136+
goto_programt &pre_loop_head_instrs =
137+
replace_history_result.history_construction;
143138

144139
// Create a temporary to track if we entered the loop,
145140
// i.e., the loop guard was satisfied.

src/goto-instrument/contracts/dynamic-frames/dfcc_instrument_loop.cpp

+11-22
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ void dfcc_instrument_loopt::operator()(
167167
goto_programt::targett loop_latch =
168168
loop.find_latch(goto_function.body).value();
169169

170-
const auto &history_var_map = add_prehead_instructions(
170+
const auto history_var_map = add_prehead_instructions(
171171
loop_id,
172172
goto_function,
173173
symbol_table,
@@ -234,7 +234,8 @@ void dfcc_instrument_loopt::operator()(
234234
goto_function.body.update();
235235
}
236236

237-
std::map<exprt, exprt> dfcc_instrument_loopt::add_prehead_instructions(
237+
std::unordered_map<exprt, symbol_exprt, irep_hash>
238+
dfcc_instrument_loopt::add_prehead_instructions(
238239
const std::size_t loop_id,
239240
goto_functionst::goto_functiont &goto_function,
240241
symbol_tablet &symbol_table,
@@ -269,22 +270,13 @@ std::map<exprt, exprt> dfcc_instrument_loopt::add_prehead_instructions(
269270
// GOTO HEAD;
270271
// ```
271272

272-
goto_programt pre_loop_head_instrs;
273-
std::map<exprt, exprt> history_var_map;
274273

275274
// initialize loop_entry history vars;
276-
{
277-
// Process "loop_entry" history variables.
278-
// We find and replace all "__CPROVER_loop_entry" in invariant.
279-
replace_history_parameter(
280-
symbol_table,
281-
invariant,
282-
history_var_map,
283-
loop_head_location,
284-
language_mode,
285-
pre_loop_head_instrs,
286-
ID_loop_entry);
287-
}
275+
auto replace_history_result = replace_history_loop_entry(
276+
symbol_table, invariant, loop_head_location, language_mode);
277+
invariant.swap(replace_history_result.expression_after_replacement);
278+
goto_programt &pre_loop_head_instrs =
279+
replace_history_result.history_construction;
288280

289281
// entered_loop = false
290282
{
@@ -354,7 +346,7 @@ std::map<exprt, exprt> dfcc_instrument_loopt::add_prehead_instructions(
354346
goto_programt::make_goto(loop_head, true_exprt{}, loop_head_location));
355347

356348
goto_function.body.destructive_insert(loop_head, pre_loop_head_instrs);
357-
return history_var_map;
349+
return replace_history_result.parameter_to_history;
358350
}
359351

360352
goto_programt::instructiont::targett
@@ -614,7 +606,7 @@ void dfcc_instrument_loopt::add_exit_instructions(
614606
goto_programt::targett loop_head,
615607
const symbol_exprt &loop_write_set,
616608
const symbol_exprt &addr_of_loop_write_set,
617-
const std::map<exprt, exprt> &history_var_map,
609+
const std::unordered_map<exprt, symbol_exprt, irep_hash> &history_var_map,
618610
const symbol_exprt &entered_loop,
619611
const symbol_exprt &initial_invariant,
620612
const symbol_exprt &in_base_case,
@@ -690,10 +682,7 @@ void dfcc_instrument_loopt::add_exit_instructions(
690682

691683
// Mark history variables as going out of scope.
692684
for(const auto &v : history_var_map)
693-
{
694-
loop_exit_program.add(
695-
goto_programt::make_dead(to_symbol_expr(v.second), exit_location));
696-
}
685+
loop_exit_program.add(goto_programt::make_dead(v.second, exit_location));
697686

698687
// Mark decreases clause snapshots as gong out of scope.
699688
for(size_t i = 0; i < old_decreases_vars.size(); i++)

src/goto-instrument/contracts/dynamic-frames/dfcc_instrument_loop.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ class dfcc_instrument_loopt
197197
/// \param[in] in_base_case temporary variable `in_base_case`.
198198
/// \param[in] symbol_mode Language mode of the function.
199199
/// \return `history_var_map` that maps variables to loop_entry variables.
200-
std::map<exprt, exprt> add_prehead_instructions(
200+
std::unordered_map<exprt, symbol_exprt, irep_hash> add_prehead_instructions(
201201
const std::size_t loop_id,
202202
goto_functionst::goto_functiont &goto_function,
203203
symbol_tablet &symbol_table,
@@ -348,7 +348,7 @@ class dfcc_instrument_loopt
348348
goto_programt::targett loop_head,
349349
const symbol_exprt &loop_write_set,
350350
const symbol_exprt &addr_of_loop_write_set,
351-
const std::map<exprt, exprt> &history_var_map,
351+
const std::unordered_map<exprt, symbol_exprt, irep_hash> &history_var_map,
352352
const symbol_exprt &entered_loop,
353353
const symbol_exprt &initial_invariant,
354354
const symbol_exprt &in_base_case,

src/goto-instrument/contracts/utils.cpp

+91-73
Original file line numberDiff line numberDiff line change
@@ -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> &parameter2history,
457-
source_locationt location,
455+
std::unordered_map<exprt, symbol_exprt, irep_hash> &parameter2history,
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 &parameter = 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 &parameter = 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

530555
void 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

551569
bool is_transformed_loop_head(const goto_programt::const_targett &target)

src/goto-instrument/contracts/utils.h

+20-8
Original file line numberDiff line numberDiff line change
@@ -242,16 +242,28 @@ void add_quantified_variable(
242242
exprt &expression,
243243
const irep_idt &mode);
244244

245-
/// This function recursively identifies the "old" expressions within expr
245+
struct replace_history_parametert
246+
{
247+
exprt expression_after_replacement;
248+
std::unordered_map<exprt, symbol_exprt, irep_hash> parameter_to_history;
249+
goto_programt history_construction;
250+
};
251+
252+
/// This function recursively identifies the "old" expressions within \p expr
246253
/// and replaces them with corresponding history variables.
247-
void replace_history_parameter(
254+
replace_history_parametert replace_history_old(
248255
symbol_table_baset &symbol_table,
249-
exprt &expr,
250-
std::map<exprt, exprt> &parameter2history,
251-
source_locationt location,
252-
const irep_idt &mode,
253-
goto_programt &history,
254-
const irep_idt &id);
256+
const exprt &expr,
257+
const source_locationt &location,
258+
const irep_idt &mode);
259+
260+
/// This function recursively identifies the "loop_entry" expressions within
261+
/// \p expr and replaces them with corresponding history variables.
262+
replace_history_parametert replace_history_loop_entry(
263+
symbol_table_baset &symbol_table,
264+
const exprt &expr,
265+
const source_locationt &location,
266+
const irep_idt &mode);
255267

256268
/// This function generates all the instructions required to initialize
257269
/// history variables.

0 commit comments

Comments
 (0)