Skip to content

Commit d08257e

Browse files
committed
Add new feature to provide models for volatile reads
Implements the option --nondet-volatile-model <variable>:<model> to allow to specify models which are called whenever the given volatile variable is read. The return value of the model is used as the value read from the volatile variable.
1 parent 47bb11e commit d08257e

File tree

1 file changed

+96
-23
lines changed

1 file changed

+96
-23
lines changed

src/goto-instrument/nondet_volatile.cpp

Lines changed: 96 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Date: September 2011
1414
#include "nondet_volatile.h"
1515

1616
#include <util/cmdline.h>
17+
#include <util/fresh_symbol.h>
1718
#include <util/options.h>
1819
#include <util/std_expr.h>
1920
#include <util/string_utils.h>
@@ -46,11 +47,23 @@ class nondet_volatilet
4647
private:
4748
static bool is_volatile(const namespacet &ns, const typet &src);
4849

49-
void handle_volatile_expression(exprt &expr, const namespacet &ns);
50+
void handle_volatile_expression(
51+
exprt &expr,
52+
const namespacet &ns,
53+
goto_programt &pre,
54+
goto_programt &post);
5055

51-
void nondet_volatile_rhs(const symbol_tablet &symbol_table, exprt &expr);
56+
void nondet_volatile_rhs(
57+
const symbol_tablet &symbol_table,
58+
exprt &expr,
59+
goto_programt &pre,
60+
goto_programt &post);
5261

53-
void nondet_volatile_lhs(const symbol_tablet &symbol_table, exprt &expr);
62+
void nondet_volatile_lhs(
63+
const symbol_tablet &symbol_table,
64+
exprt &expr,
65+
goto_programt &pre,
66+
goto_programt &post);
5467

5568
void
5669
nondet_volatile(symbol_tablet &symbol_table, goto_programt &goto_program);
@@ -89,8 +102,11 @@ bool nondet_volatilet::is_volatile(const namespacet &ns, const typet &src)
89102

90103
void nondet_volatilet::handle_volatile_expression(
91104
exprt &expr,
92-
const namespacet &ns)
105+
const namespacet &ns,
106+
goto_programt &pre,
107+
goto_programt &post)
93108
{
109+
// Check if we should replace the variable by a nondet expression
94110
if(
95111
all_nondet ||
96112
(expr.id() == ID_symbol &&
@@ -99,18 +115,56 @@ void nondet_volatilet::handle_volatile_expression(
99115
typet t = expr.type();
100116
t.remove(ID_C_volatile);
101117

102-
// replace by nondet
103118
side_effect_expr_nondett nondet_expr(t, expr.source_location());
104119
expr.swap(nondet_expr);
120+
121+
return;
122+
}
123+
124+
// Now check if we should replace the variable by a model
125+
126+
if(expr.id() != ID_symbol)
127+
{
128+
return;
129+
}
130+
131+
const irep_idt &id = to_symbol_expr(expr).get_identifier();
132+
const auto &it = variable_models.find(id);
133+
134+
if(it == variable_models.end())
135+
{
136+
return;
105137
}
138+
139+
const auto &model_symbol = ns.lookup(it->second);
140+
141+
const auto &new_variable = get_fresh_aux_symbol(
142+
to_code_type(model_symbol.type).return_type(),
143+
"",
144+
"modelled_volatile",
145+
source_locationt(),
146+
ID_C,
147+
goto_model.symbol_table)
148+
.symbol_expr();
149+
150+
pre.instructions.push_back(goto_programt::make_decl(new_variable));
151+
152+
code_function_callt call(new_variable, model_symbol.symbol_expr(), {});
153+
pre.instructions.push_back(goto_programt::make_function_call(call));
154+
155+
post.instructions.push_back(goto_programt::make_dead(new_variable));
156+
157+
expr = new_variable;
106158
}
107159

108160
void nondet_volatilet::nondet_volatile_rhs(
109161
const symbol_tablet &symbol_table,
110-
exprt &expr)
162+
exprt &expr,
163+
goto_programt &pre,
164+
goto_programt &post)
111165
{
112166
Forall_operands(it, expr)
113-
nondet_volatile_rhs(symbol_table, *it);
167+
nondet_volatile_rhs(symbol_table, *it, pre, post);
114168

115169
if(expr.id()==ID_symbol ||
116170
expr.id()==ID_dereference)
@@ -119,33 +173,37 @@ void nondet_volatilet::nondet_volatile_rhs(
119173

120174
if(is_volatile(ns, expr.type()))
121175
{
122-
handle_volatile_expression(expr, ns);
176+
handle_volatile_expression(expr, ns, pre, post);
123177
}
124178
}
125179
}
126180

127181
void nondet_volatilet::nondet_volatile_lhs(
128182
const symbol_tablet &symbol_table,
129-
exprt &expr)
183+
exprt &expr,
184+
goto_programt &pre,
185+
goto_programt &post)
130186
{
131187
if(expr.id()==ID_if)
132188
{
133-
nondet_volatile_rhs(symbol_table, to_if_expr(expr).cond());
134-
nondet_volatile_lhs(symbol_table, to_if_expr(expr).true_case());
135-
nondet_volatile_lhs(symbol_table, to_if_expr(expr).false_case());
189+
nondet_volatile_rhs(symbol_table, to_if_expr(expr).cond(), pre, post);
190+
nondet_volatile_lhs(symbol_table, to_if_expr(expr).true_case(), pre, post);
191+
nondet_volatile_lhs(symbol_table, to_if_expr(expr).false_case(), pre, post);
136192
}
137193
else if(expr.id()==ID_index)
138194
{
139-
nondet_volatile_lhs(symbol_table, to_index_expr(expr).array());
140-
nondet_volatile_rhs(symbol_table, to_index_expr(expr).index());
195+
nondet_volatile_lhs(symbol_table, to_index_expr(expr).array(), pre, post);
196+
nondet_volatile_rhs(symbol_table, to_index_expr(expr).index(), pre, post);
141197
}
142198
else if(expr.id()==ID_member)
143199
{
144-
nondet_volatile_lhs(symbol_table, to_member_expr(expr).struct_op());
200+
nondet_volatile_lhs(
201+
symbol_table, to_member_expr(expr).struct_op(), pre, post);
145202
}
146203
else if(expr.id()==ID_dereference)
147204
{
148-
nondet_volatile_rhs(symbol_table, to_dereference_expr(expr).pointer());
205+
nondet_volatile_rhs(
206+
symbol_table, to_dereference_expr(expr).pointer(), pre, post);
149207
}
150208
}
151209

@@ -155,14 +213,21 @@ void nondet_volatilet::nondet_volatile(
155213
{
156214
namespacet ns(symbol_table);
157215

158-
Forall_goto_program_instructions(i_it, goto_program)
216+
for(auto i_it = goto_program.instructions.begin();
217+
i_it != goto_program.instructions.end();
218+
i_it++)
159219
{
160-
goto_programt::instructiont &instruction=*i_it;
220+
goto_programt pre;
221+
goto_programt post;
222+
223+
goto_programt::instructiont &instruction = *i_it;
161224

162225
if(instruction.is_assign())
163226
{
164-
nondet_volatile_rhs(symbol_table, to_code_assign(instruction.code).rhs());
165-
nondet_volatile_lhs(symbol_table, to_code_assign(instruction.code).lhs());
227+
nondet_volatile_rhs(
228+
symbol_table, to_code_assign(instruction.code).rhs(), pre, post);
229+
nondet_volatile_lhs(
230+
symbol_table, to_code_assign(instruction.code).lhs(), pre, post);
166231
}
167232
else if(instruction.is_function_call())
168233
{
@@ -176,18 +241,26 @@ void nondet_volatilet::nondet_volatile(
176241
it=code_function_call.arguments().begin();
177242
it!=code_function_call.arguments().end();
178243
it++)
179-
nondet_volatile_rhs(symbol_table, *it);
244+
nondet_volatile_rhs(symbol_table, *it, pre, post);
180245

181246
// do return value
182-
nondet_volatile_lhs(symbol_table, code_function_call.lhs());
247+
nondet_volatile_lhs(symbol_table, code_function_call.lhs(), pre, post);
183248
}
184249
else if(instruction.has_condition())
185250
{
186251
// do condition
187252
exprt cond = instruction.get_condition();
188-
nondet_volatile_rhs(symbol_table, cond);
253+
nondet_volatile_rhs(symbol_table, cond, pre, post);
189254
instruction.set_condition(cond);
190255
}
256+
257+
const auto pre_size = pre.instructions.size();
258+
goto_program.insert_before_swap(i_it, pre);
259+
std::advance(i_it, pre_size);
260+
261+
const auto post_size = post.instructions.size();
262+
goto_program.destructive_insert(std::next(i_it), post);
263+
std::advance(i_it, post_size);
191264
}
192265
}
193266

0 commit comments

Comments
 (0)