Skip to content

Commit 8ef9acd

Browse files
committed
Build out constants_evaluator
The constants_evaluator class wraps up what was previous contained in constant_abstract_valuet::expression_transform. While it could have been implemented with free functions, using a class allows us to restrict scope, refactor to clearer code by reducing the number of parameters flying around. The process of building the class signposted a number of additional small clean ups that I might have otherwise overlooked.
1 parent 8329afd commit 8ef9acd

File tree

2 files changed

+117
-81
lines changed

2 files changed

+117
-81
lines changed

src/analyses/variable-sensitivity/abstract_value_object.cpp

Lines changed: 106 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -172,113 +172,144 @@ abstract_object_pointert abstract_value_objectt::expression_transform(
172172
return transform(expr, operands, environment, ns);
173173
}
174174

175-
// constant_abstract_value expresion transfrom
176-
static abstract_object_pointert try_transform_expr_with_all_rounding_modes(
177-
const exprt &expr,
178-
const abstract_environmentt &environment,
179-
const namespacet &ns);
180-
181-
abstract_object_pointert constants_expression_transform(
182-
const exprt &expr,
183-
const std::vector<abstract_object_pointert> &operands,
184-
const abstract_environmentt &environment,
185-
const namespacet &ns)
175+
// constant_abstract_value expression transfrom
176+
class constants_evaluator
186177
{
187-
// try finding the rounding mode. If it's not constant, try
188-
// seeing if we can get the same result with all rounding modes
189-
auto rounding_mode_symbol =
190-
symbol_exprt(CPROVER_PREFIX "rounding_mode", signedbv_typet(32));
191-
auto rounding_mode_value = environment.eval(rounding_mode_symbol, ns);
192-
auto rounding_mode_constant = rounding_mode_value->to_constant();
193-
if(rounding_mode_constant.is_nil())
178+
public:
179+
constants_evaluator(
180+
const exprt &e,
181+
const abstract_environmentt &env,
182+
const namespacet &n)
183+
: expression(e), environment(env), ns(n)
194184
{
195-
return try_transform_expr_with_all_rounding_modes(expr, environment, ns);
196185
}
197186

198-
exprt adjusted_expr = expr;
199-
adjust_float_expressions(adjusted_expr, ns);
200-
exprt constant_replaced_expr = adjusted_expr;
201-
constant_replaced_expr.operands().clear();
187+
abstract_object_pointert operator()() const
188+
{
189+
// try finding the rounding mode. If it's not constant, try
190+
// seeing if we can get the same result with all rounding modes
191+
if(rounding_mode_is_not_set())
192+
return try_transform_expr_with_all_rounding_modes();
202193

203-
// Two passes over the expression - one for simplification,
204-
// another to check if there are any top subexpressions left
205-
for(const exprt &op : adjusted_expr.operands())
194+
return transform();
195+
}
196+
197+
private:
198+
abstract_object_pointert transform() const
206199
{
207-
abstract_object_pointert lhs_abstract_object = environment.eval(op, ns);
208-
const exprt &lhs_value = lhs_abstract_object->to_constant();
209-
if(lhs_value.is_nil())
200+
exprt expr = adjust_expression_for_rounding_mode();
201+
auto operands = expr.operands();
202+
expr.operands().clear();
203+
204+
// Two passes over the expression - one for simplification,
205+
// another to check if there are any top subexpressions left
206+
for(const exprt &op : operands)
210207
{
208+
auto lhs_value = eval_constant(op);
209+
211210
// do not give up if a sub-expression is not a constant,
212211
// because the whole expression may still be simplified in some cases
213-
constant_replaced_expr.operands().push_back(op);
212+
expr.operands().push_back(lhs_value.is_nil() ? op : lhs_value);
214213
}
215-
else
214+
215+
exprt simplified = simplify_expr(expr, ns);
216+
for(const exprt &op : simplified.operands())
216217
{
217-
// rebuild the operands list with constant versions of
218-
// any symbols
219-
constant_replaced_expr.operands().push_back(lhs_value);
218+
auto lhs_value = eval_constant(op);
219+
if(lhs_value.is_nil())
220+
return top(simplified.type());
220221
}
222+
223+
// the expression is fully simplified
224+
return environment.abstract_object_factory(
225+
simplified.type(), simplified, ns);
221226
}
222-
exprt simplified = simplify_expr(constant_replaced_expr, ns);
223227

224-
for(const exprt &op : simplified.operands())
228+
abstract_object_pointert try_transform_expr_with_all_rounding_modes() const
225229
{
226-
abstract_object_pointert lhs_abstract_object = environment.eval(op, ns);
227-
const exprt &lhs_value = lhs_abstract_object->to_constant();
228-
if(lhs_value.is_nil())
230+
std::vector<abstract_object_pointert> possible_results;
231+
for(auto rounding_mode : all_rounding_modes)
229232
{
230-
return environment.abstract_object_factory(
231-
simplified.type(), ns, true, false);
233+
auto child_env(environment_with_rounding_mode(rounding_mode));
234+
possible_results.push_back(
235+
constants_evaluator(expression, child_env, ns)());
232236
}
233-
}
234237

235-
return environment.abstract_object_factory(simplified.type(), simplified, ns);
236-
}
238+
auto first = possible_results.front()->to_constant();
239+
for(auto const &possible_result : possible_results)
240+
{
241+
auto current = possible_result->to_constant();
242+
if(current.is_nil() || current != first)
243+
return top(expression.type());
244+
}
245+
return possible_results.front();
246+
}
237247

238-
static abstract_object_pointert try_transform_expr_with_all_rounding_modes(
239-
const exprt &expr,
240-
const abstract_environmentt &environment,
241-
const namespacet &ns)
242-
{
243-
const symbol_exprt rounding_mode_symbol =
244-
symbol_exprt(CPROVER_PREFIX "rounding_mode", signedbv_typet(32));
245-
// NOLINTNEXTLINE (whitespace/braces)
246-
auto rounding_modes = std::array<ieee_floatt::rounding_modet, 4>{
247-
// NOLINTNEXTLINE (whitespace/braces)
248-
{ieee_floatt::ROUND_TO_EVEN,
249-
ieee_floatt::ROUND_TO_ZERO,
250-
ieee_floatt::ROUND_TO_MINUS_INF,
251-
// NOLINTNEXTLINE (whitespace/braces)
252-
ieee_floatt::ROUND_TO_PLUS_INF}};
253-
std::vector<abstract_object_pointert> possible_results;
254-
for(auto current_rounding_mode : rounding_modes)
248+
abstract_environmentt
249+
environment_with_rounding_mode(ieee_floatt::rounding_modet rm) const
255250
{
256251
abstract_environmentt child_env(environment);
257252
child_env.assign(
258253
rounding_mode_symbol,
259254
child_env.abstract_object_factory(
260255
signedbv_typet(32),
261256
from_integer(
262-
mp_integer(static_cast<unsigned long>(current_rounding_mode)),
263-
signedbv_typet(32)),
257+
mp_integer(static_cast<unsigned long>(rm)), signedbv_typet(32)),
264258
ns),
265259
ns);
260+
return child_env;
261+
}
266262

267-
// Dummy vector as the called expression_transform() ignores it
268-
std::vector<abstract_object_pointert> dummy;
269-
possible_results.push_back(
270-
constants_expression_transform(expr, dummy, child_env, ns));
263+
exprt adjust_expression_for_rounding_mode() const
264+
{
265+
exprt adjusted_expr = expression;
266+
adjust_float_expressions(adjusted_expr, ns);
267+
return adjusted_expr;
271268
}
272-
auto first = possible_results.front()->to_constant();
273-
for(auto const &possible_result : possible_results)
269+
270+
exprt eval_constant(const exprt &op) const
274271
{
275-
auto current = possible_result->to_constant();
276-
if(current.is_nil() || current != first)
277-
{
278-
return environment.abstract_object_factory(expr.type(), ns, true, false);
279-
}
272+
return environment.eval(op, ns)->to_constant();
280273
}
281-
return possible_results.front();
274+
275+
abstract_object_pointert top(const typet &type) const
276+
{
277+
return environment.abstract_object_factory(type, ns, true, false);
278+
}
279+
280+
bool rounding_mode_is_not_set() const
281+
{
282+
auto rounding_mode = eval_constant(rounding_mode_symbol);
283+
return rounding_mode.is_nil();
284+
}
285+
286+
const exprt &expression;
287+
const abstract_environmentt &environment;
288+
const namespacet &ns;
289+
290+
static const symbol_exprt rounding_mode_symbol;
291+
292+
using rounding_modes = std::vector<ieee_floatt::rounding_modet>;
293+
static const rounding_modes all_rounding_modes;
294+
};
295+
296+
const symbol_exprt constants_evaluator::rounding_mode_symbol =
297+
symbol_exprt(CPROVER_PREFIX "rounding_mode", signedbv_typet(32));
298+
299+
const constants_evaluator::rounding_modes
300+
constants_evaluator::all_rounding_modes{ieee_floatt::ROUND_TO_EVEN,
301+
ieee_floatt::ROUND_TO_ZERO,
302+
ieee_floatt::ROUND_TO_MINUS_INF,
303+
ieee_floatt::ROUND_TO_PLUS_INF};
304+
305+
abstract_object_pointert constants_expression_transform(
306+
const exprt &expr,
307+
const std::vector<abstract_object_pointert> &operands,
308+
const abstract_environmentt &environment,
309+
const namespacet &ns)
310+
{
311+
auto evaluator = constants_evaluator(expr, environment, ns);
312+
return evaluator();
282313
}
283314

284315
///////////////////////////////////////////////////////
@@ -660,13 +691,7 @@ resolve_values(const abstract_object_sett &new_values)
660691
auto unwrapped_values = unwrap_and_extract_values(new_values);
661692

662693
if(unwrapped_values.size() > value_set_abstract_objectt::max_value_set_size)
663-
{
664694
return unwrapped_values.to_interval();
665-
}
666-
//if(unwrapped_values.size() == 1)
667-
//{
668-
// return (*unwrapped_values.begin());
669-
//}
670695

671696
const auto &type = new_values.first()->type();
672697
auto result = std::make_shared<value_set_abstract_objectt>(type);

unit/analyses/variable-sensitivity/constant_abstract_value/expression_evaluation.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,5 +80,16 @@ SCENARIO(
8080
EXPECT(result, {val3});
8181
}
8282
}
83+
WHEN("1 + { 1, 2 }")
84+
{
85+
auto op1 = make_constant(val1, environment, ns);
86+
auto op2 = make_value_set({val1, val2}, environment, ns);
87+
auto result = add_as_value_set(op1, op2, environment, ns);
88+
89+
THEN("= { 2, 3 }")
90+
{
91+
EXPECT(result, {val2, val3});
92+
}
93+
}
8394
}
8495
}

0 commit comments

Comments
 (0)