Skip to content

Commit 8487f2d

Browse files
authored
Merge pull request diffblue#259 from diffblue/smowton/feature/virtual_callsite_specialiser
Add CSVSA and its specializer
2 parents 53d6a6f + d202510 commit 8487f2d

File tree

65 files changed

+2914
-238
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+2914
-238
lines changed

.travis.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,8 @@ jobs:
9292
before_install:
9393
#we create symlink to non-ccache gcc, to be used in tests
9494
- mkdir bin ; ln -s /usr/bin/gcc bin/gcc
95-
- HOMEBREW_NO_AUTO_UPDATE=1 brew install ccache ant python3
95+
- HOMEBREW_NO_AUTO_UPDATE=1 brew tap discoteq/discoteq # for flock
96+
- HOMEBREW_NO_AUTO_UPDATE=1 brew install ccache ant python3 flock
9697
- pip3 install -q pytest --user
9798
- export PATH=$HOME/.local/bin:/usr/local/opt/ccache/libexec:$PATH
9899
env:
@@ -108,7 +109,8 @@ jobs:
108109
compiler: clang
109110
cache: ccache
110111
before_install:
111-
- HOMEBREW_NO_AUTO_UPDATE=1 brew install ccache ant python3
112+
- HOMEBREW_NO_AUTO_UPDATE=1 brew tap discoteq/discoteq # for flock
113+
- HOMEBREW_NO_AUTO_UPDATE=1 brew install ccache ant python3 flock
112114
- pip3 install -q pytest --user
113115
- export PATH=$HOME/.local/bin:/usr/local/opt/ccache/libexec:$PATH
114116
env:

cbmc/src/analyses/call_graph.cpp

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,10 @@ call_grapht::call_grapht(
4242
{
4343
forall_goto_functions(f_it, goto_functions)
4444
{
45-
const goto_programt &body=f_it->second.body;
46-
add(f_it->first, body);
45+
const irep_idt &function_name = f_it->first;
46+
const goto_programt &body = f_it->second.body;
47+
nodes.insert(function_name);
48+
add(function_name, body);
4749
}
4850
}
4951

@@ -85,12 +87,14 @@ call_grapht::call_grapht(
8587
const goto_programt &goto_program=
8688
goto_functions.function_map.at(function).body;
8789

90+
nodes.insert(function);
91+
8892
forall_callsites(
8993
goto_program,
9094
[&](goto_programt::const_targett i_it, const irep_idt &callee)
9195
{
9296
add(function, callee, i_it);
93-
if(graph.find(callee)==graph.end())
97+
if(edges.find(callee)==edges.end())
9498
pending_stack.push(callee);
9599
}
96100
); // NOLINT
@@ -130,7 +134,9 @@ void call_grapht::add(
130134
const irep_idt &caller,
131135
const irep_idt &callee)
132136
{
133-
graph.insert(std::pair<irep_idt, irep_idt>(caller, callee));
137+
edges.insert({caller, callee});
138+
nodes.insert(caller);
139+
nodes.insert(callee);
134140
}
135141

136142
/// Add edge with optional callsite information
@@ -153,7 +159,8 @@ void call_grapht::add(
153159
call_grapht call_grapht::get_inverted() const
154160
{
155161
call_grapht result;
156-
for(const auto &caller_callee : graph)
162+
result.nodes = nodes;
163+
for(const auto &caller_callee : edges)
157164
result.add(caller_callee.second, caller_callee.first);
158165
return result;
159166
}
@@ -198,7 +205,12 @@ call_grapht::directed_grapht call_grapht::get_directed_graph() const
198205
call_grapht::directed_grapht ret;
199206
function_indicest function_indices(ret);
200207

201-
for(const auto &edge : graph)
208+
// To make sure we include unreachable functions we first create indices
209+
// for all nodes in the graph
210+
for(const irep_idt &function_name : nodes)
211+
function_indices[function_name];
212+
213+
for(const auto &edge : edges)
202214
{
203215
auto a_index=function_indices[edge.first];
204216
auto b_index=function_indices[edge.second];
@@ -238,7 +250,7 @@ void call_grapht::output_dot(std::ostream &out) const
238250
{
239251
out << "digraph call_graph {\n";
240252

241-
for(const auto &edge : graph)
253+
for(const auto &edge : edges)
242254
{
243255
out << " \"" << edge.first << "\" -> "
244256
<< "\"" << edge.second << "\" "
@@ -253,7 +265,7 @@ void call_grapht::output_dot(std::ostream &out) const
253265

254266
void call_grapht::output(std::ostream &out) const
255267
{
256-
for(const auto &edge : graph)
268+
for(const auto &edge : edges)
257269
{
258270
out << edge.first << " -> " << edge.second << "\n";
259271
if(collect_callsites)
@@ -268,7 +280,7 @@ void call_grapht::output_xml(std::ostream &out) const
268280
if(collect_callsites)
269281
out << "<!-- XML call-graph representation does not document callsites yet."
270282
" If you need this, edit call_grapht::output_xml -->\n";
271-
for(const auto &edge : graph)
283+
for(const auto &edge : edges)
272284
{
273285
out << "<call_graph_edge caller=\"";
274286
xmlt::escape_attribute(id2string(edge.first), out);
@@ -297,7 +309,7 @@ void find_leaves_below_function(
297309
if(to_avoid.count(function)!=0UL)
298310
return;
299311
to_avoid.insert(function);
300-
const auto range = call_graph.graph.equal_range(function);
312+
const auto range = call_graph.edges.equal_range(function);
301313
if(range.first==range.second)
302314
output.insert(function);
303315
else
@@ -344,7 +356,7 @@ void find_nearest_common_callees(
344356
}
345357

346358
std::map<irep_idt, std::size_t> counting;
347-
for(const auto &elem : call_graph.graph)
359+
for(const auto &elem : call_graph.edges)
348360
{
349361
counting[elem.first]=0U;
350362
counting[elem.second]=0U;
@@ -362,7 +374,7 @@ void find_nearest_common_callees(
362374
for(const auto &elem : counting)
363375
if(elem.second!=0U)
364376
{
365-
const auto range = call_graph.graph.equal_range(elem.first);
377+
const auto range = call_graph.edges.equal_range(elem.first);
366378
if(range.first==range.second)
367379
leaves.insert(elem.first);
368380
}
@@ -372,7 +384,7 @@ void find_nearest_common_callees(
372384
output.insert(elem.first);
373385
else if(elem.second!=0U && elem.second<functions.size())
374386
{
375-
const auto range = call_graph.graph.equal_range(elem.first);
387+
const auto range = call_graph.edges.equal_range(elem.first);
376388
for(auto it=range.first; it!=range.second; ++it)
377389
{
378390
auto cit=counting.find(it->second);
@@ -393,7 +405,7 @@ bool exists_direct_call(
393405
const irep_idt &callee)
394406
{
395407
const auto range =
396-
call_graph.graph.equal_range(caller);
408+
call_graph.edges.equal_range(caller);
397409
for(auto it=range.first; it!=range.second; ++it)
398410
if(callee==it->second)
399411
return true;
@@ -420,7 +432,7 @@ bool exists_direct_or_indirect_call(
420432
if(exists_direct_call(call_graph, caller, callee))
421433
return ignored_functions.count(callee)==0UL;
422434
const auto range =
423-
call_graph.graph.equal_range(caller);
435+
call_graph.edges.equal_range(caller);
424436
for(auto it=range.first; it!=range.second; ++it)
425437
if(exists_direct_or_indirect_call(
426438
call_graph,

cbmc/src/analyses/call_graph.h

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,17 @@ class call_grapht
6363
void output(std::ostream &out) const;
6464
void output_xml(std::ostream &out) const;
6565

66-
/// Type of the call graph. Note parallel edges (e.g. A having two callsites
67-
/// both targeting B) result in multiple graph edges.
68-
typedef std::multimap<irep_idt, irep_idt> grapht;
66+
/// Type of the nodes in the call graph.
67+
typedef std::unordered_set<irep_idt, irep_id_hash> nodest;
6968

70-
/// Type of a call graph edge in `grapht`
69+
/// Type of the edges in the call graph. Note parallel edges (e.g. A having
70+
/// two callsites both targeting B) result in multiple graph edges.
71+
typedef std::multimap<irep_idt, irep_idt> edgest;
72+
73+
/// Type of a call graph edge in `edgest`
7174
typedef std::pair<irep_idt, irep_idt> edget;
7275

76+
7377
/// Type of a callsite stored in member `callsites`
7478
typedef goto_programt::const_targett locationt;
7579

@@ -85,7 +89,8 @@ class call_grapht
8589
/// backward compatibility; use `get_directed_graph()` to get a generic
8690
/// directed graph representation that provides more graph algorithms
8791
/// (shortest path, SCCs and so on).
88-
grapht graph;
92+
edgest edges;
93+
nodest nodes;
8994

9095
/// Map from call-graph edges to a set of callsites that make the given call.
9196
callsitest callsites;

cbmc/src/analyses/static_analysis.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ class domain_baset
9292
// this computes the join between "this" and "b"
9393
// return true if "this" has changed
9494

95+
bool has_been_seen() const { return seen; }
96+
void set_seen() { seen=true; }
97+
9598
protected:
9699
bool seen;
97100

@@ -282,7 +285,7 @@ class static_analysis_baset
282285
virtual void generate_state(locationt l)=0;
283286
virtual statet &get_state(locationt l)=0;
284287
virtual const statet &get_state(locationt l) const=0;
285-
virtual std::unique_ptr<statet> make_temporary_state(statet &s)=0;
288+
virtual std::unique_ptr<statet> make_temporary_state(const statet &s)=0;
286289

287290
typedef domain_baset::expr_sett expr_sett;
288291

@@ -364,9 +367,9 @@ class static_analysist:public static_analysis_baset
364367
return static_cast<T &>(a).merge(static_cast<const T &>(b), to);
365368
}
366369

367-
virtual std::unique_ptr<statet> make_temporary_state(statet &s)
370+
virtual std::unique_ptr<statet> make_temporary_state(const statet &s)
368371
{
369-
return util_make_unique<T>(static_cast<T &>(s));
372+
return util_make_unique<T>(static_cast<const T &>(s));
370373
}
371374

372375
virtual void generate_state(locationt l)
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*******************************************************************\
2+
3+
Module: Dead code elimination
4+
5+
Author: Chris Smowton, [email protected]
6+
7+
Date: March 2018
8+
9+
\*******************************************************************/
10+
11+
/// \file
12+
/// Dead code elimination
13+
14+
#include "dead_code_elimination.h"
15+
16+
/// Replace all unreachable instructions in a program with SKIPs
17+
/// \param goto_program: program to process
18+
static void remove_dead_code(goto_programt &goto_program)
19+
{
20+
std::unordered_set<unsigned> live_location_numbers;
21+
22+
if(goto_program.empty())
23+
return;
24+
25+
// Mark live locations:
26+
std::vector<goto_programt::const_targett> worklist;
27+
worklist.push_back(goto_program.instructions.begin());
28+
29+
while(!worklist.empty())
30+
{
31+
goto_programt::const_targett next_instruction = worklist.back();
32+
worklist.pop_back();
33+
34+
auto insert_result =
35+
live_location_numbers.insert(next_instruction->location_number);
36+
// Already marked live?
37+
if(!insert_result.second)
38+
continue;
39+
40+
for(auto &target : next_instruction->targets)
41+
{
42+
if(!live_location_numbers.count(target->location_number))
43+
worklist.push_back(target);
44+
}
45+
46+
bool may_fall_through =
47+
next_instruction->type != END_FUNCTION &&
48+
(next_instruction->targets.empty() ||
49+
(next_instruction->type == GOTO && !next_instruction->guard.is_true()));
50+
51+
if(may_fall_through)
52+
{
53+
auto successor = std::next(next_instruction);
54+
if(!live_location_numbers.count(successor->location_number))
55+
worklist.push_back(successor);
56+
}
57+
}
58+
59+
// Kill locations not marked:
60+
for(auto &instruction : goto_program.instructions)
61+
{
62+
if(instruction.type != END_FUNCTION &&
63+
!live_location_numbers.count(instruction.location_number))
64+
{
65+
instruction.make_skip();
66+
}
67+
}
68+
}
69+
70+
/// Replace all unreachable instructions in a model's function map with SKIPs
71+
/// \param goto_model: model to process
72+
void remove_dead_code(goto_modelt &goto_model)
73+
{
74+
for(auto &id_and_function : goto_model.goto_functions.function_map)
75+
remove_dead_code(id_and_function.second.body);
76+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*******************************************************************\
2+
3+
Module: Remove dead code (function-local)
4+
5+
Author: Diffblue Ltd.
6+
7+
\*******************************************************************/
8+
9+
/// \file
10+
/// Remove dead code (function-local)
11+
12+
#ifndef CPROVER_GOTO_PROGRAMS_DEAD_CODE_ELIMINATION_H
13+
#define CPROVER_GOTO_PROGRAMS_DEAD_CODE_ELIMINATION_H
14+
15+
#include <goto-programs/goto_model.h>
16+
17+
void remove_dead_code(goto_modelt &goto_model);
18+
19+
#endif

0 commit comments

Comments
 (0)