Skip to content

Commit 9094f89

Browse files
committed
Pulled out interval_evaluator
Wrap up interval evaluation in a wrapper class. Most significant change is simplifying the process of coercing constants to intervals. Rather than trying to bail out early if we hit a top value or something which can't be converted, go over the whole list of operands, skipping any we can't convert. Check afterwards if we're missing some and then decide what to do.
1 parent 8ef9acd commit 9094f89

File tree

1 file changed

+146
-132
lines changed

1 file changed

+146
-132
lines changed

src/analyses/variable-sensitivity/abstract_value_object.cpp

Lines changed: 146 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -314,170 +314,184 @@ abstract_object_pointert constants_expression_transform(
314314

315315
///////////////////////////////////////////////////////
316316
// intervals expression transform
317-
using interval_abstract_value_pointert = sharing_ptrt<interval_abstract_valuet>;
318-
319-
static abstract_object_pointert interval_evaluate_conditional(
320-
const exprt &expr,
321-
const std::vector<interval_abstract_value_pointert> &interval_operands,
322-
const abstract_environmentt &env,
323-
const namespacet &ns);
324-
static abstract_object_pointert interval_evaluate_unary_expr(
325-
const exprt &expr,
326-
const std::vector<interval_abstract_value_pointert> &interval_operands,
327-
const abstract_environmentt &environment,
328-
const namespacet &ns);
329-
330-
abstract_object_pointert intervals_expression_transform(
331-
const exprt &expr,
332-
const std::vector<abstract_object_pointert> &operands,
333-
const abstract_environmentt &environment,
334-
const namespacet &ns)
317+
class interval_evaluator
335318
{
336-
std::size_t num_operands = expr.operands().size();
337-
PRECONDITION(operands.size() == num_operands);
319+
public:
320+
interval_evaluator(
321+
const exprt &e,
322+
const std::vector<abstract_object_pointert> &ops,
323+
const abstract_environmentt &env,
324+
const namespacet &n)
325+
: expression(e), operands(ops), environment(env), ns(n)
326+
{
327+
PRECONDITION(expression.operands().size() == operands.size());
328+
}
338329

339-
std::vector<sharing_ptrt<interval_abstract_valuet>> interval_operands;
330+
abstract_object_pointert operator()() const
331+
{
332+
return transform();
333+
}
340334

341-
for(const auto &op : operands)
335+
private:
336+
using interval_abstract_value_pointert =
337+
sharing_ptrt<const interval_abstract_valuet>;
338+
339+
abstract_object_pointert transform() const
342340
{
343-
auto iav = std::dynamic_pointer_cast<const interval_abstract_valuet>(op);
344-
if(!iav)
341+
auto interval_operands = operands_as_intervals();
342+
auto num_operands = interval_operands.size();
343+
344+
if(num_operands != operands.size())
345345
{
346-
// The operand isn't an interval - if it's an integral constant we can
347-
// convert it into an interval.
346+
// We could not convert all operands into intervals,
347+
// e.g. if its type is not something we can represent as an interval,
348+
// try dispatching the expression_transform under that type instead.
349+
return constants_expression_transform(
350+
expression, operands, environment, ns);
351+
}
352+
353+
if(num_operands == 0)
354+
return environment.abstract_object_factory(
355+
expression.type(), ns, true, false);
356+
357+
if(expression.id() == ID_if)
358+
return interval_evaluate_conditional(interval_operands);
359+
360+
if(num_operands == 1)
361+
return interval_evaluate_unary_expr(interval_operands);
362+
363+
constant_interval_exprt result = interval_operands[0]->to_interval();
348364

349-
if(constant_interval_exprt::is_int(op->type()))
365+
for(size_t opIndex = 1; opIndex != interval_operands.size(); ++opIndex)
366+
{
367+
auto &interval_next = interval_operands[opIndex]->to_interval();
368+
result = result.eval(expression.id(), interval_next);
369+
}
370+
371+
INVARIANT(
372+
result.type() == expression.type(),
373+
"Type of result interval should match expression type");
374+
return make_interval(expression.type(), result);
375+
}
376+
377+
std::vector<interval_abstract_value_pointert> operands_as_intervals() const
378+
{
379+
std::vector<interval_abstract_value_pointert> interval_operands;
380+
381+
for(const auto &op : operands)
382+
{
383+
auto iav = std::dynamic_pointer_cast<const interval_abstract_valuet>(op);
384+
if(!iav)
350385
{
351-
const auto op_as_constant = op->to_constant();
352-
if(op_as_constant.is_nil())
353-
{
354-
auto top_object =
355-
environment.abstract_object_factory(expr.type(), ns, true, false);
356-
auto top_context_object =
357-
std::dynamic_pointer_cast<const context_abstract_objectt>(
358-
top_object);
359-
CHECK_RETURN(top_context_object);
360-
return top_context_object->get_child();
361-
}
362-
const auto ivop =
363-
environment.abstract_object_factory(op->type(), op_as_constant, ns);
364-
const auto ivop_context =
365-
std::dynamic_pointer_cast<const context_abstract_objectt>(ivop);
366-
if(ivop_context)
386+
// The operand isn't an interval - if it's an integral constant we can
387+
// convert it into an interval.
388+
if(constant_interval_exprt::is_int(op->type()))
367389
{
368-
iav = std::dynamic_pointer_cast<const interval_abstract_valuet>(
369-
ivop_context->get_child());
390+
const auto op_as_constant = op->to_constant();
391+
if(op_as_constant.is_nil())
392+
return std::vector<interval_abstract_value_pointert>();
393+
394+
const auto ivop =
395+
environment.abstract_object_factory(op->type(), op_as_constant, ns);
396+
const auto ivop_context =
397+
std::dynamic_pointer_cast<const context_abstract_objectt>(ivop);
398+
if(ivop_context)
399+
{
400+
iav = std::dynamic_pointer_cast<const interval_abstract_valuet>(
401+
ivop_context->get_child());
402+
}
403+
else
404+
iav =
405+
std::dynamic_pointer_cast<const interval_abstract_valuet>(ivop);
370406
}
371-
else
372-
iav = std::dynamic_pointer_cast<const interval_abstract_valuet>(ivop);
407+
CHECK_RETURN(
408+
!std::dynamic_pointer_cast<const context_abstract_objectt>(iav));
373409
}
374-
CHECK_RETURN(
375-
!std::dynamic_pointer_cast<const context_abstract_objectt>(iav));
376410

377-
if(!iav)
378-
{
379-
// If we could not convert the operand into an interval,
380-
// e.g. if its type is not something we can represent as an interval,
381-
// try dispatching the expression_transform under that type instead.
382-
if(
383-
std::dynamic_pointer_cast<const constant_abstract_valuet>(op) !=
384-
nullptr)
385-
return constants_expression_transform(
386-
expr, operands, environment, ns);
387-
return op->expression_transform(expr, operands, environment, ns);
388-
}
411+
if(iav)
412+
interval_operands.push_back(iav);
389413
}
390414

391-
INVARIANT(iav, "Should be an interval abstract value");
392-
interval_operands.push_back(iav);
415+
return interval_operands;
393416
}
394417

395-
if(num_operands == 0)
396-
return environment.abstract_object_factory(expr.type(), ns, true, false);
418+
abstract_object_pointert interval_evaluate_conditional(
419+
const std::vector<interval_abstract_value_pointert> &interval_operands)
420+
const
421+
{
422+
auto const &condition_interval = interval_operands[0]->to_interval();
423+
auto const &true_interval = interval_operands[1]->to_interval();
424+
auto const &false_interval = interval_operands[2]->to_interval();
397425

398-
if(expr.id() == ID_if)
399-
return interval_evaluate_conditional(
400-
expr, interval_operands, environment, ns);
426+
auto condition_result = condition_interval.is_definitely_true();
401427

402-
if(num_operands == 1)
403-
return interval_evaluate_unary_expr(
404-
expr, interval_operands, environment, ns);
428+
if(condition_result.is_unknown())
429+
{
430+
// Value of the condition is both true and false, so
431+
// combine the intervals of both the true and false expressions
432+
return make_interval(
433+
expression.type(),
434+
constant_interval_exprt(
435+
constant_interval_exprt::get_min(
436+
true_interval.get_lower(), false_interval.get_lower()),
437+
constant_interval_exprt::get_max(
438+
true_interval.get_upper(), false_interval.get_upper())));
439+
}
405440

406-
constant_interval_exprt result = interval_operands[0]->to_interval();
441+
return condition_result.is_true()
442+
? make_interval(true_interval.type(), true_interval)
443+
: make_interval(false_interval.type(), false_interval);
444+
}
407445

408-
for(size_t opIndex = 1; opIndex != interval_operands.size(); ++opIndex)
446+
abstract_object_pointert interval_evaluate_unary_expr(
447+
const std::vector<interval_abstract_value_pointert> &interval_operands)
448+
const
409449
{
410-
auto &interval_next = interval_operands[opIndex]->to_interval();
411-
result = result.eval(expr.id(), interval_next);
412-
}
450+
const constant_interval_exprt &operand_expr =
451+
interval_operands[0]->to_interval();
413452

414-
INVARIANT(
415-
result.type() == expr.type(),
416-
"Type of result interval should match expression type");
417-
return environment.abstract_object_factory(expr.type(), result, ns);
418-
}
453+
if(expression.id() == ID_typecast)
454+
{
455+
const typecast_exprt &tce = to_typecast_expr(expression);
419456

420-
abstract_object_pointert interval_evaluate_conditional(
421-
const exprt &expr,
422-
const std::vector<interval_abstract_value_pointert> &interval_operands,
423-
const abstract_environmentt &env,
424-
const namespacet &ns)
425-
{
426-
auto const &condition_interval = interval_operands[0]->to_interval();
427-
auto const &true_interval = interval_operands[1]->to_interval();
428-
auto const &false_interval = interval_operands[2]->to_interval();
457+
const constant_interval_exprt &new_interval =
458+
operand_expr.typecast(tce.type());
459+
460+
INVARIANT(
461+
new_interval.type() == expression.type(),
462+
"Type of result interval should match expression type");
463+
464+
return make_interval(tce.type(), new_interval);
465+
}
429466

430-
auto condition_result = condition_interval.is_definitely_true();
467+
const constant_interval_exprt &interval_result =
468+
operand_expr.eval(expression.id());
469+
INVARIANT(
470+
interval_result.type() == expression.type(),
471+
"Type of result interval should match expression type");
472+
return make_interval(expression.type(), interval_result);
473+
}
431474

432-
if(condition_result.is_unknown())
475+
abstract_object_pointert
476+
make_interval(const typet &type, const exprt &expr) const
433477
{
434-
// Value of the condition is both true and false, so
435-
// combine the intervals of both the true and false expressions
436-
return env.abstract_object_factory(
437-
expr.type(),
438-
constant_interval_exprt(
439-
constant_interval_exprt::get_min(
440-
true_interval.get_lower(), false_interval.get_lower()),
441-
constant_interval_exprt::get_max(
442-
true_interval.get_upper(), false_interval.get_upper())),
443-
ns);
478+
return environment.abstract_object_factory(type, expr, ns);
444479
}
445480

446-
return condition_result.is_true()
447-
? env.abstract_object_factory(
448-
true_interval.type(), true_interval, ns)
449-
: env.abstract_object_factory(
450-
false_interval.type(), false_interval, ns);
451-
}
481+
const exprt &expression;
482+
const std::vector<abstract_object_pointert> &operands;
483+
const abstract_environmentt &environment;
484+
const namespacet &ns;
485+
};
452486

453-
abstract_object_pointert interval_evaluate_unary_expr(
487+
abstract_object_pointert intervals_expression_transform(
454488
const exprt &expr,
455-
const std::vector<interval_abstract_value_pointert> &interval_operands,
489+
const std::vector<abstract_object_pointert> &operands,
456490
const abstract_environmentt &environment,
457491
const namespacet &ns)
458492
{
459-
const constant_interval_exprt &operand_expr =
460-
interval_operands[0]->to_interval();
461-
462-
if(expr.id() == ID_typecast)
463-
{
464-
const typecast_exprt &tce = to_typecast_expr(expr);
465-
466-
const constant_interval_exprt &new_interval =
467-
operand_expr.typecast(tce.type());
468-
469-
INVARIANT(
470-
new_interval.type() == expr.type(),
471-
"Type of result interval should match expression type");
472-
473-
return environment.abstract_object_factory(tce.type(), new_interval, ns);
474-
}
475-
476-
const constant_interval_exprt &interval_result = operand_expr.eval(expr.id());
477-
INVARIANT(
478-
interval_result.type() == expr.type(),
479-
"Type of result interval should match expression type");
480-
return environment.abstract_object_factory(expr.type(), interval_result, ns);
493+
auto evaluator = interval_evaluator(expr, operands, environment, ns);
494+
return evaluator();
481495
}
482496

483497
/////////////////////////////////////////////////////////

0 commit comments

Comments
 (0)