Skip to content

Commit f8380e5

Browse files
Merge pull request #7631 from remi-delmas-3000/contracts-loop-nesting-graph
CONTRACTS: represent loop nesting structure as a graph
2 parents 9161eae + b4b59d9 commit f8380e5

File tree

3 files changed

+139
-0
lines changed

3 files changed

+139
-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_cprover_symbol.cpp \
2324
contracts/dynamic-frames/dfcc_is_fresh.cpp \
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
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 Loop normal form properties must hold.
27+
dfcc_loop_nesting_grapht
28+
build_loop_nesting_graph(goto_programt &goto_program, messaget &log)
29+
{
30+
natural_loops_mutablet natural_loops(goto_program);
31+
dfcc_loop_nesting_grapht loop_nesting_graph;
32+
// Add a node per natural loop
33+
for(auto &loop : natural_loops.loop_map)
34+
{
35+
auto loop_head = loop.first;
36+
auto &loop_instructions = loop.second;
37+
38+
if(loop_instructions.size() <= 1)
39+
{
40+
// ignore single instruction loops of the form
41+
// LOOP: goto LOOP;
42+
continue;
43+
}
44+
45+
// Find the instruction that jumps back to `loop_head` and has the
46+
// highest GOTO location number, define it as the latch.
47+
auto loop_latch = loop_head;
48+
for(const auto &t : loop_instructions)
49+
{
50+
if(
51+
t->is_goto() && t->get_target() == loop_head &&
52+
t->location_number > loop_latch->location_number)
53+
loop_latch = t;
54+
}
55+
56+
DATA_INVARIANT(loop_latch != loop_head, "Natural loop latch is found");
57+
58+
loop_nesting_graph.add_node(loop_head, loop_latch, loop_instructions);
59+
}
60+
61+
// Add edges to the graph, pointing from inner loop to outer loops.
62+
// An `inner` will be considered nested in `outer` iff both its head
63+
// and latch instructions are instructions of `outer`.
64+
for(size_t outer = 0; outer < loop_nesting_graph.size(); ++outer)
65+
{
66+
const auto &outer_instructions = loop_nesting_graph[outer].instructions;
67+
68+
for(size_t inner = 0; inner < loop_nesting_graph.size(); ++inner)
69+
{
70+
if(inner == outer)
71+
continue;
72+
73+
if(outer_instructions.contains(loop_nesting_graph[inner].head))
74+
{
75+
loop_nesting_graph.add_edge(inner, outer);
76+
}
77+
}
78+
}
79+
80+
auto topsorted_size = loop_nesting_graph.topsort().size();
81+
INVARIANT(
82+
topsorted_size == loop_nesting_graph.size(),
83+
"loop_nesting_graph must be acyclic");
84+
85+
return loop_nesting_graph;
86+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
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+
dfcc_loop_nesting_grapht
51+
build_loop_nesting_graph(goto_programt &goto_program, messaget &log);
52+
#endif

0 commit comments

Comments
 (0)