Skip to content

Commit 168bcd0

Browse files
author
Remi Delmas
committed
CONTRACTS: represent loop nesting structure as a graph
Utility class for loop contracts instrumentation.
1 parent b34e991 commit 168bcd0

File tree

3 files changed

+146
-0
lines changed

3 files changed

+146
-0
lines changed

src/goto-instrument/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ SRC = accelerate/accelerate.cpp \
1818
call_sequences.cpp \
1919
contracts/contracts.cpp \
2020
contracts/dynamic-frames/dfcc_utils.cpp \
21+
contracts/dynamic-frames/dfcc_loop_nesting_graph.cpp \
2122
contracts/dynamic-frames/dfcc_library.cpp \
2223
contracts/dynamic-frames/dfcc_is_fresh.cpp \
2324
contracts/dynamic-frames/dfcc_pointer_in_range.cpp \
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/*******************************************************************\
2+
3+
Module: Dynamic frame condition checking
4+
5+
Author: Qinheping Hu, [email protected]
6+
7+
Author: Remi Delmas, [email protected]
8+
9+
Date: March 2023
10+
11+
\*******************************************************************/
12+
13+
#include "dfcc_loop_nesting_graph.h"
14+
15+
#include <util/invariant.h>
16+
#include <util/message.h>
17+
18+
dfcc_loop_nesting_graph_nodet::dfcc_loop_nesting_graph_nodet(
19+
const goto_programt::targett head,
20+
const goto_programt::targett latch,
21+
const loopt instructions)
22+
: head(head), latch(latch), instructions(instructions)
23+
{
24+
}
25+
26+
/// \pre The function \ref dfcc_check_loop_normal_form must have successfully
27+
/// been applied to the model.
28+
dfcc_loop_nesting_grapht
29+
build_loop_nesting_graph(goto_programt &goto_program, messaget &log)
30+
{
31+
natural_loops_mutablet natural_loops(goto_program);
32+
dfcc_loop_nesting_grapht loop_nesting_graph;
33+
// Add a node per natural loop
34+
for(auto &loop : natural_loops.loop_map)
35+
{
36+
auto loop_head = loop.first;
37+
auto &loop_instructions = loop.second;
38+
39+
if(loop_instructions.size() <= 1)
40+
{
41+
// ignore single instruction loops of the form
42+
// LOOP: goto LOOP;
43+
continue;
44+
}
45+
46+
// Find the instruction that jumps back to `loop_head` and has the
47+
// highest GOTO location number, define it as the latch.
48+
auto loop_latch = loop_head;
49+
for(const auto &t : loop_instructions)
50+
{
51+
if(
52+
t->is_goto() && t->get_target() == loop_head &&
53+
t->location_number > loop_latch->location_number)
54+
loop_latch = t;
55+
}
56+
57+
if(loop_latch == loop_head)
58+
{
59+
log.error() << "Could not find latch instruction of loop starting at: "
60+
<< loop_head->source_location() << messaget::eom;
61+
throw analysis_exceptiont("Could not find loop latch instruction");
62+
}
63+
64+
loop_nesting_graph.add_node(loop_head, loop_latch, loop_instructions);
65+
}
66+
67+
// Add edges to the graph, pointing from inner loop to outer loops.
68+
// An `inner` will be considered nested in `outer` iff both its head
69+
// and latch instructions are instructions of `outer`.
70+
for(size_t outer = 0; outer < loop_nesting_graph.size(); ++outer)
71+
{
72+
const auto &outer_instructions = loop_nesting_graph[outer].instructions;
73+
74+
for(size_t inner = 0; inner < loop_nesting_graph.size(); ++inner)
75+
{
76+
if(inner == outer)
77+
continue;
78+
79+
if(outer_instructions.contains(loop_nesting_graph[inner].head))
80+
{
81+
loop_nesting_graph.add_edge(inner, outer);
82+
}
83+
}
84+
}
85+
86+
auto topsorted_size = loop_nesting_graph.topsort().size();
87+
INVARIANT(
88+
topsorted_size == loop_nesting_graph.size(),
89+
"loop_nesting_graph must be acyclic");
90+
91+
return loop_nesting_graph;
92+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*******************************************************************\
2+
3+
Module: Dynamic frame condition checking
4+
5+
Author: Qinheping Hu, [email protected]
6+
7+
Author: Remi Delmas, [email protected]
8+
9+
Date: March 2023
10+
11+
\*******************************************************************/
12+
13+
/// \file
14+
/// Builds a graph describing how loops are nested in a GOTO program.
15+
16+
#ifndef CPROVER_GOTO_INSTRUMENT_CONTRACTS_DYNAMIC_FRAMES_DFCC_LOOP_NESTING_GRAPH_H
17+
#define CPROVER_GOTO_INSTRUMENT_CONTRACTS_DYNAMIC_FRAMES_DFCC_LOOP_NESTING_GRAPH_H
18+
19+
#include <util/graph.h>
20+
21+
#include <goto-instrument/loop_utils.h>
22+
23+
class messaget;
24+
25+
/// A graph node that stores information about a natural loop.
26+
struct dfcc_loop_nesting_graph_nodet : public graph_nodet<empty_edget>
27+
{
28+
public:
29+
dfcc_loop_nesting_graph_nodet(
30+
const goto_programt::targett head,
31+
const goto_programt::targett latch,
32+
const loopt instructions);
33+
34+
/// Loop head instruction
35+
goto_programt::targett head;
36+
37+
/// Loop latch instruction
38+
goto_programt::targett latch;
39+
40+
/// Set of loop instructions
41+
loopt instructions;
42+
};
43+
44+
typedef grapht<dfcc_loop_nesting_graph_nodet> dfcc_loop_nesting_grapht;
45+
46+
/// \brief Builds a graph instance describing the nesting structure of natural
47+
/// loops in the given \p goto_program.
48+
/// A loop is considered nested in an outer loop if its head and its latch are
49+
/// both found in the instructions of the outer loop.
50+
/// \pre The properties checked by \ref dfcc_check_loop_normal_form must hold
51+
dfcc_loop_nesting_grapht
52+
build_loop_nesting_graph(goto_programt &goto_program, messaget &log);
53+
#endif

0 commit comments

Comments
 (0)