@@ -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
379405expr_sett alternatives_enumeratort::enumerate (const std::size_t size) const
0 commit comments