Skip to content

Commit 9f97bb2

Browse files
committed
Handle mix of unsigned and signed in expression enumerators
1 parent a6276c5 commit 9f97bb2

File tree

1 file changed

+71
-45
lines changed

1 file changed

+71
-45
lines changed

src/goto-synthesizer/expr_enumerator.cpp

Lines changed: 71 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Author: Qinheping Hu
55

66
#include "expr_enumerator.h"
77

8+
#include <util/bitvector_types.h>
89
#include <util/format_expr.h>
910
#include <util/simplify_expr.h>
1011
#include <util/std_expr.h>
@@ -310,70 +311,95 @@ bool binary_functional_enumeratort::is_equivalence_class_representation(
310311
return true;
311312
}
312313

313-
exprt binary_functional_enumeratort::instantiate(const expr_listt &exprs) const
314+
// Handle mix of unsigned and signed leafs in one expression.
315+
// From the C99 standard, section 6.3.1.8:
316+
// "if the operand that has unsigned integer type has rank greater or equal to
317+
// the rank of the type of the other operand, then the operand with signed
318+
// integer type is converted to the type of the operand with unsigned integer
319+
// type."
320+
static std::pair<const exprt, const exprt>
321+
widen_bitvector(const exprt &lhs, const exprt &rhs)
314322
{
315-
INVARIANT(
316-
exprs.size() == 2,
317-
"number of arguments should be 2: " + integer2string(exprs.size()));
318-
if(op_id == ID_equal)
323+
// Widening conversion.
324+
if(
325+
lhs.type() != rhs.type() &&
326+
(lhs.type().id() == ID_unsignedbv || lhs.type().id() == ID_signedbv) &&
327+
(rhs.type().id() == ID_unsignedbv || rhs.type().id() == ID_signedbv))
319328
{
320-
auto &lhs = exprs.front();
321-
auto &rhs = exprs.back();
322-
323-
// Widening conversion.
324-
if(
325-
lhs.type() != rhs.type() &&
326-
(lhs.type().id() == ID_unsignedbv || lhs.type().id() == ID_signedbv) &&
327-
(rhs.type().id() == ID_unsignedbv || rhs.type().id() == ID_signedbv))
329+
const auto &lhs_type = type_try_dynamic_cast<bitvector_typet>(lhs.type());
330+
const auto &rhs_type = type_try_dynamic_cast<bitvector_typet>(rhs.type());
331+
332+
// Same rank, unsigned win.
333+
if(lhs_type->get_width() == rhs_type->get_width())
328334
{
329-
const auto &lhs_type = type_try_dynamic_cast<bitvector_typet>(lhs.type());
330-
const auto &rhs_type = type_try_dynamic_cast<bitvector_typet>(rhs.type());
331-
if(lhs_type->get_width() >= rhs_type->get_width())
332-
return equal_exprt(lhs, typecast_exprt(rhs, lhs.type()));
335+
if((lhs.type().id() == ID_unsignedbv || rhs.type().id() == ID_unsignedbv))
336+
{
337+
return std::pair<const exprt, const exprt>(
338+
typecast_exprt::conditional_cast(
339+
lhs, unsignedbv_typet(lhs_type->get_width())),
340+
typecast_exprt::conditional_cast(
341+
rhs, unsignedbv_typet(lhs_type->get_width())));
342+
}
333343
else
334-
return equal_exprt(typecast_exprt(lhs, rhs.type()), rhs);
344+
{
345+
return std::pair<const exprt, const exprt>(
346+
typecast_exprt::conditional_cast(
347+
lhs, signedbv_typet(lhs_type->get_width())),
348+
typecast_exprt::conditional_cast(
349+
rhs, signedbv_typet(lhs_type->get_width())));
350+
}
335351
}
336352

337-
return equal_exprt(exprs.front(), exprs.back());
338-
}
339-
if(op_id == ID_notequal)
340-
{
341-
auto &lhs = exprs.front();
342-
auto &rhs = exprs.back();
343-
344-
// Widening conversion.
345-
if(
346-
lhs.type() != rhs.type() &&
347-
(lhs.type().id() == ID_unsignedbv || lhs.type().id() == ID_signedbv) &&
348-
(rhs.type().id() == ID_unsignedbv || rhs.type().id() == ID_signedbv))
353+
// Different rank, higher rank win.
354+
if(lhs_type->get_width() > rhs_type->get_width())
349355
{
350-
const auto &lhs_type = type_try_dynamic_cast<bitvector_typet>(lhs.type());
351-
const auto &rhs_type = type_try_dynamic_cast<bitvector_typet>(rhs.type());
352-
if(lhs_type->get_width() >= rhs_type->get_width())
353-
return notequal_exprt(lhs, typecast_exprt(rhs, lhs.type()));
354-
else
355-
return notequal_exprt(typecast_exprt(lhs, rhs.type()), rhs);
356+
return std::pair<const exprt, const exprt>(
357+
lhs, typecast_exprt::conditional_cast(rhs, *lhs_type));
356358
}
357-
358-
return notequal_exprt(exprs.front(), exprs.back());
359+
else
360+
{
361+
return std::pair<const exprt, const exprt>(
362+
typecast_exprt::conditional_cast(lhs, *rhs_type), rhs);
363+
}
364+
}
365+
// no need of bitvector conversion.
366+
else
367+
{
368+
return std::pair<const exprt, const exprt>(lhs, rhs);
359369
}
370+
}
371+
372+
exprt binary_functional_enumeratort::instantiate(const expr_listt &exprs) const
373+
{
374+
INVARIANT(
375+
exprs.size() == 2,
376+
"number of arguments should be 2: " + integer2string(exprs.size()));
377+
378+
// Make two operands the same type if they are of different bitvector types.
379+
auto operands = widen_bitvector(exprs.front(), exprs.back());
380+
381+
if(op_id == ID_equal)
382+
return equal_exprt(operands.first, operands.second);
383+
if(op_id == ID_notequal)
384+
return notequal_exprt(operands.first, operands.second);
360385
if(op_id == ID_le)
361-
return less_than_or_equal_exprt(exprs.front(), exprs.back());
386+
return less_than_or_equal_exprt(operands.first, operands.second);
362387
if(op_id == ID_lt)
363-
return less_than_exprt(exprs.front(), exprs.back());
388+
return less_than_exprt(operands.first, operands.second);
364389
if(op_id == ID_gt)
365-
return greater_than_exprt(exprs.front(), exprs.back());
390+
return greater_than_exprt(operands.first, operands.second);
366391
if(op_id == ID_ge)
367-
return greater_than_or_equal_exprt(exprs.front(), exprs.back());
392+
return greater_than_or_equal_exprt(operands.first, operands.second);
368393
if(op_id == ID_and)
369394
return and_exprt(exprs.front(), exprs.back());
370395
if(op_id == ID_or)
371396
return or_exprt(exprs.front(), exprs.back());
372397
if(op_id == ID_plus)
373-
return plus_exprt(exprs.front(), exprs.back());
398+
return plus_exprt(operands.first, operands.second);
374399
if(op_id == ID_minus)
375-
return minus_exprt(exprs.front(), exprs.back());
376-
return binary_exprt(exprs.front(), op_id, exprs.back());
400+
return minus_exprt(operands.first, operands.second);
401+
402+
return binary_exprt(operands.first, op_id, operands.second);
377403
}
378404

379405
expr_sett alternatives_enumeratort::enumerate(const std::size_t size) const

0 commit comments

Comments
 (0)