Skip to content

CONTRACTS: Move some functions from synthesizer_utils to contracts/utils #7782

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 128 additions & 0 deletions src/goto-instrument/contracts/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Date: September 2021

#include <goto-programs/cfg.h>

#include <analyses/natural_loops.h>
#include <ansi-c/c_expr.h>
#include <langapi/language_util.h>

Expand Down Expand Up @@ -610,3 +611,130 @@ unsigned get_suffix_unsigned(const std::string &str, const std::string &prefix)
std::string result = str.substr(first_index, last_index - first_index);
return std::stol(result);
}

goto_programt::const_targett get_loop_end_from_loop_head_and_content(
const goto_programt::const_targett &loop_head,
const loop_templatet<
goto_programt::const_targett,
goto_programt::target_less_than> &loop)
{
goto_programt::const_targett loop_end = loop_head;
for(const auto &t : loop)
{
// an instruction is the loop end if it is a goto instruction
// and it jumps backward to the loop head
if(
t->is_goto() && t->get_target() == loop_head &&
t->location_number > loop_end->location_number)
loop_end = t;
}
INVARIANT(
loop_head != loop_end,
"Could not find end of the loop starting at: " +
loop_head->source_location().as_string());

return loop_end;
}

goto_programt::targett get_loop_end_from_loop_head_and_content_mutable(
const goto_programt::targett &loop_head,
const loop_templatet<goto_programt::targett, goto_programt::target_less_than>
&loop)
{
goto_programt::targett loop_end = loop_head;
for(const auto &t : loop)
{
// an instruction is the loop end if it is a goto instruction
// and it jumps backward to the loop head
if(
t->is_goto() && t->get_target() == loop_head &&
t->location_number > loop_end->location_number)
loop_end = t;
}
INVARIANT(
loop_head != loop_end,
"Could not find end of the loop starting at: " +
loop_head->source_location().as_string());

return loop_end;
}

goto_programt::targett get_loop_head_or_end(
const unsigned int target_loop_number,
goto_functiont &function,
bool finding_head)
{
natural_loops_mutablet natural_loops(function.body);

// iterate over all natural loops to find the loop with `target_loop_number`
for(const auto &loop_p : natural_loops.loop_map)
{
const goto_programt::targett loop_head = loop_p.first;
goto_programt::targett loop_end =
get_loop_end_from_loop_head_and_content_mutable(loop_head, loop_p.second);
// check if the current loop is the target loop by comparing loop number
if(loop_end->loop_number == target_loop_number)
{
if(finding_head)
return loop_head;
else
return loop_end;
}
}

UNREACHABLE;
}

goto_programt::targett
get_loop_end(const unsigned int target_loop_number, goto_functiont &function)
{
return get_loop_head_or_end(target_loop_number, function, false);
}

goto_programt::targett
get_loop_head(const unsigned int target_loop_number, goto_functiont &function)
{
return get_loop_head_or_end(target_loop_number, function, true);
}

void annotate_invariants(
const invariant_mapt &invariant_map,
goto_modelt &goto_model)
{
for(const auto &invariant_map_entry : invariant_map)
{
loop_idt loop_id = invariant_map_entry.first;
irep_idt function_id = loop_id.function_id;
unsigned int loop_number = loop_id.loop_number;

// get the last instruction of the target loop
auto &function = goto_model.goto_functions.function_map[function_id];
goto_programt::targett loop_end = get_loop_end(loop_number, function);

// annotate the invariant to the condition of `loop_end`
loop_end->condition_nonconst().add(ID_C_spec_loop_invariant) =
invariant_map_entry.second;
}
}

void annotate_assigns(
const std::map<loop_idt, std::set<exprt>> &assigns_map,
goto_modelt &goto_model)
{
for(const auto &assigns_map_entry : assigns_map)
{
loop_idt loop_id = assigns_map_entry.first;
irep_idt function_id = loop_id.function_id;
unsigned int loop_number = loop_id.loop_number;

// get the last instruction of the target loop
auto &function = goto_model.goto_functions.function_map[function_id];
goto_programt::targett loop_end = get_loop_end(loop_number, function);

exprt &condition = loop_end->condition_nonconst();
auto assigns = exprt(ID_target_list);
for(const auto &e : assigns_map_entry.second)
assigns.add_to_operands(e);
condition.add(ID_C_spec_assigns) = assigns;
}
}
46 changes: 46 additions & 0 deletions src/goto-instrument/contracts/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Date: September 2021
#include <goto-programs/goto_convert_class.h>

#include <goto-programs/goto_model.h>
#include <goto-programs/loop_ids.h>

#include <goto-instrument/havoc_utils.h>

Expand All @@ -24,6 +25,10 @@ Date: September 2021
#define IN_LOOP_HAVOC_BLOCK "__in_loop_havoc_block"
#define INIT_INVARIANT "__init_invariant"

template <class T, typename C>
class loop_templatet;
typedef std::map<loop_idt, exprt> invariant_mapt;

/// Class that allows to clean expressions of side effects and to generate
/// havoc_slice expressions.
class cleanert : public goto_convertt
Expand Down Expand Up @@ -271,4 +276,45 @@ bool is_assignment_to_instrumented_variable(
/// Convert the suffix digits right after `prefix` of `str` into unsigned.
unsigned get_suffix_unsigned(const std::string &str, const std::string &prefix);

/// Find the goto instruction of `loop` that jumps to `loop_head`
goto_programt::targett get_loop_end_from_loop_head_and_content_mutable(
const goto_programt::targett &loop_head,
const loop_templatet<goto_programt::targett, goto_programt::target_less_than>
&loop);

goto_programt::const_targett get_loop_end_from_loop_head_and_content(
const goto_programt::const_targett &loop_head,
const loop_templatet<
goto_programt::const_targett,
goto_programt::target_less_than> &loop);

/// Return loop head if `finding_head` is true,
/// Otherwise return loop end.
goto_programt::targett get_loop_head_or_end(
const unsigned int loop_number,
goto_functiont &function,
bool finding_head);

/// Find and return the last instruction of the natural loop with
/// `loop_number` in `function`. loop_end -> loop_head
goto_programt::targett
get_loop_end(const unsigned int loop_number, goto_functiont &function);

/// Find and return the first instruction of the natural loop with
/// `loop_number` in `function`. loop_end -> loop_head
goto_programt::targett
get_loop_head(const unsigned int loop_number, goto_functiont &function);

/// Annotate the invariants in `invariant_map` to their corresponding
/// loops. Corresponding loops are specified by keys of `invariant_map`
void annotate_invariants(
const invariant_mapt &invariant_map,
goto_modelt &goto_model);

/// Annotate the assigns in `assigns_map` to their corresponding
/// loops. Corresponding loops are specified by keys of `assigns_map`
void annotate_assigns(
const std::map<loop_idt, std::set<exprt>> &assigns_map,
goto_modelt &goto_model);

#endif // CPROVER_GOTO_INSTRUMENT_CONTRACTS_UTILS_H
133 changes: 0 additions & 133 deletions src/goto-synthesizer/synthesizer_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,139 +8,6 @@ Author: Qinheping Hu

#include "synthesizer_utils.h"

#include <util/optional.h>

#include <analyses/natural_loops.h>
#include <goto-instrument/contracts/utils.h>
#include <goto-instrument/havoc_utils.h>

goto_programt::const_targett get_loop_end_from_loop_head_and_content(
const goto_programt::const_targett &loop_head,
const loop_templatet<
goto_programt::const_targett,
goto_programt::target_less_than> &loop)
{
goto_programt::const_targett loop_end = loop_head;
for(const auto &t : loop)
{
// an instruction is the loop end if it is a goto instruction
// and it jumps backward to the loop head
if(
t->is_goto() && t->get_target() == loop_head &&
t->location_number > loop_end->location_number)
loop_end = t;
}
INVARIANT(
loop_head != loop_end,
"Could not find end of the loop starting at: " +
loop_head->source_location().as_string());

return loop_end;
}

goto_programt::targett get_loop_end_from_loop_head_and_content_mutable(
const goto_programt::targett &loop_head,
const loop_templatet<goto_programt::targett, goto_programt::target_less_than>
&loop)
{
goto_programt::targett loop_end = loop_head;
for(const auto &t : loop)
{
// an instruction is the loop end if it is a goto instruction
// and it jumps backward to the loop head
if(
t->is_goto() && t->get_target() == loop_head &&
t->location_number > loop_end->location_number)
loop_end = t;
}
INVARIANT(
loop_head != loop_end,
"Could not find end of the loop starting at: " +
loop_head->source_location().as_string());

return loop_end;
}

goto_programt::targett get_loop_head_or_end(
const unsigned int target_loop_number,
goto_functiont &function,
bool finding_head)
{
natural_loops_mutablet natural_loops(function.body);

// iterate over all natural loops to find the loop with `target_loop_number`
for(const auto &loop_p : natural_loops.loop_map)
{
const goto_programt::targett loop_head = loop_p.first;
goto_programt::targett loop_end =
get_loop_end_from_loop_head_and_content_mutable(loop_head, loop_p.second);
// check if the current loop is the target loop by comparing loop number
if(loop_end->loop_number == target_loop_number)
{
if(finding_head)
return loop_head;
else
return loop_end;
}
}

UNREACHABLE;
}

goto_programt::targett
get_loop_end(const unsigned int target_loop_number, goto_functiont &function)
{
return get_loop_head_or_end(target_loop_number, function, false);
}

goto_programt::targett
get_loop_head(const unsigned int target_loop_number, goto_functiont &function)
{
return get_loop_head_or_end(target_loop_number, function, true);
}

void annotate_invariants(
const invariant_mapt &invariant_map,
goto_modelt &goto_model)
{
for(const auto &invariant_map_entry : invariant_map)
{
loop_idt loop_id = invariant_map_entry.first;
irep_idt function_id = loop_id.function_id;
unsigned int loop_number = loop_id.loop_number;

// get the last instruction of the target loop
auto &function = goto_model.goto_functions.function_map[function_id];
goto_programt::targett loop_end = get_loop_end(loop_number, function);

// annotate the invariant to the condition of `loop_end`
loop_end->condition_nonconst().add(ID_C_spec_loop_invariant) =
invariant_map_entry.second;
}
}

void annotate_assigns(
const std::map<loop_idt, std::set<exprt>> &assigns_map,
goto_modelt &goto_model)
{
for(const auto &assigns_map_entry : assigns_map)
{
loop_idt loop_id = assigns_map_entry.first;
irep_idt function_id = loop_id.function_id;
unsigned int loop_number = loop_id.loop_number;

// get the last instruction of the target loop
auto &function = goto_model.goto_functions.function_map[function_id];
goto_programt::targett loop_end = get_loop_end(loop_number, function);

exprt &condition = loop_end->condition_nonconst();
auto assigns = exprt(ID_target_list);
for(const auto &e : assigns_map_entry.second)
assigns.add_to_operands(e);
condition.add(ID_C_spec_assigns) = assigns;
}
}

invariant_mapt combine_in_and_post_invariant_clauses(
const invariant_mapt &in_clauses,
const invariant_mapt &post_clauses,
Expand Down
Loading