Skip to content

Commit f28331b

Browse files
committed
Add support for signed/unsigned conversions
1 parent 3977209 commit f28331b

File tree

8 files changed

+58
-4
lines changed

8 files changed

+58
-4
lines changed

src/main/scala/inox/ast/Deconstructors.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,16 @@ trait TreeDeconstructor {
287287
(NoIdentifiers, NoVariables, Seq(e), Seq(bvt), NoFlags,
288288
(_, _, es, tps, _) => t.BVWideningCast(es(0), tps(0).asInstanceOf[t.BVType]))
289289
},
290+
classOf[s.BVUnsignedToSigned] -> { expr =>
291+
val s.BVUnsignedToSigned(e) = expr
292+
(NoIdentifiers, NoVariables, Seq(e), NoTypes, NoFlags,
293+
(_, _, es, _, _) => t.BVUnsignedToSigned(es(0)))
294+
},
295+
classOf[s.BVSignedToUnsigned] -> { expr =>
296+
val s.BVSignedToUnsigned(e) = expr
297+
(NoIdentifiers, NoVariables, Seq(e), NoTypes, NoFlags,
298+
(_, _, es, _, _) => t.BVSignedToUnsigned(es(0)))
299+
},
290300
classOf[s.Tuple] -> { expr =>
291301
val s.Tuple(args) = expr
292302
(NoIdentifiers, NoVariables, args, NoTypes, NoFlags,

src/main/scala/inox/ast/Expressions.scala

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -532,7 +532,7 @@ trait Expressions { self: Trees =>
532532

533533
/** $encodingof `... .toByte` and other narrowing casts */
534534
sealed case class BVNarrowingCast(expr: Expr, newType: BVType) extends Expr with CachingTyped {
535-
// The expression is well types iff `expr` is well typed and the BVTypes' size match a narrowing cast.
535+
// The expression is well typed iff `expr` is well typed and the BVTypes' size match a narrowing cast.
536536
override protected def computeType(implicit s: Symbols): Type = cast match {
537537
case Some((from, to)) => newType
538538
case _ => Untyped
@@ -547,7 +547,7 @@ trait Expressions { self: Trees =>
547547

548548
/** $encodingof `... .toInt` and other widening casts */
549549
sealed case class BVWideningCast(expr: Expr, newType: BVType) extends Expr with CachingTyped {
550-
// The expression is well types iff `expr` is well typed and the BVTypes' size match a widening cast.
550+
// The expression is well typed iff `expr` is well typed and the BVTypes' size match a widening cast.
551551
override protected def computeType(implicit s: Symbols): Type = cast match {
552552
case Some((from, to)) => newType
553553
case _ => Untyped
@@ -560,6 +560,22 @@ trait Expressions { self: Trees =>
560560
}
561561
}
562562

563+
/** Bitvector conversion from unsigned to signed */
564+
sealed case class BVUnsignedToSigned(expr: Expr) extends Expr with CachingTyped {
565+
override protected def computeType(implicit s: Symbols): Type = getBVType(expr) match {
566+
case BVType(false, size) => BVType(true, size)
567+
case _ => Untyped
568+
}
569+
}
570+
571+
/** Bitvector conversion from signed to unsigned */
572+
sealed case class BVSignedToUnsigned(expr: Expr) extends Expr with CachingTyped {
573+
override protected def computeType(implicit s: Symbols): Type = getBVType(expr) match {
574+
case BVType(true, size) => BVType(false, size)
575+
case _ => Untyped
576+
}
577+
}
578+
563579

564580
/* Tuple operations */
565581

src/main/scala/inox/ast/Printers.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,8 @@ trait Printer {
260260
case BVWideningCast(e, Int32Type()) => p"$e.toInt"
261261
case BVWideningCast(e, Int64Type()) => p"$e.toLong"
262262
case BVWideningCast(e, BVType(_, size)) => p"$e.toBV($size)"
263+
case BVUnsignedToSigned(e) => p"$e.toSigned"
264+
case BVSignedToUnsigned(e) => p"$e.toUnsigned"
263265

264266
case fs @ FiniteSet(rs, _) => p"{${rs}}"
265267
case fs @ FiniteBag(rs, _) => p"{${rs.toSeq}}"

src/main/scala/inox/evaluators/RecursiveEvaluator.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,18 @@ trait RecursiveEvaluator
325325
case x => throw EvalError(typeErrorMsg(x, BVType(bvt.signed, bvt.size - 1))) // or any smaller BVType
326326
}
327327

328+
case BVUnsignedToSigned(expr) =>
329+
e(expr) match {
330+
case BVLiteral(false, bits, size) => BVLiteral(true, bits, size)
331+
case x => throw EvalError("Expected unsigned bitvector type")
332+
}
333+
334+
case BVSignedToUnsigned(expr) =>
335+
e(expr) match {
336+
case BVLiteral(true, bits, size) => BVLiteral(false, bits, size)
337+
case x => throw EvalError("Expected signed bitvector type")
338+
}
339+
328340
case LessThan(l,r) =>
329341
(e(l), e(r)) match {
330342
case (b1 @ BVLiteral(sig1, _, s1), b2 @ BVLiteral(sig2, _, s2)) if sig1 == sig2 && s1 == s2 =>

src/main/scala/inox/solvers/princess/AbstractPrincessSolver.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,12 @@ trait AbstractPrincessSolver extends AbstractSolver with ADTManagers {
364364
val Some((from, to)) = c.cast
365365
Mod.extract(to - 1, 0, parseTerm(e))
366366

367+
case BVUnsignedToSigned(e) =>
368+
parseTerm(e)
369+
370+
case BVSignedToUnsigned(e) =>
371+
parseTerm(e)
372+
367373
case _ => unsupported(expr, "Unexpected formula " + expr)
368374
}
369375

src/main/scala/inox/solvers/smtlib/SMTLIBTarget.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,9 @@ trait SMTLIBTarget extends SMTLIBParser with Interruptible with ADTManagers {
446446
val Some((from, to)) = c.cast
447447
FixedSizeBitVectors.Extract(to - 1, 0, toSMT(e))
448448

449+
case BVUnsignedToSigned(e) => toSMT(e)
450+
case BVSignedToUnsigned(e) => toSMT(e)
451+
449452
case And(sub) => SmtLibConstructors.and(sub.map(toSMT))
450453
case Or(sub) => SmtLibConstructors.or(sub.map(toSMT))
451454
case IfExpr(cond, thenn, elze) => Core.ITE(toSMT(cond), toSMT(thenn), toSMT(elze))

src/main/scala/inox/solvers/z3/Z3Native.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,9 @@ trait Z3Native extends ADTManagers with Interruptible { self: AbstractSolver =>
327327
val Some((from, to)) = c.cast
328328
z3.mkExtract(to - 1, 0, rec(e))
329329

330+
case BVUnsignedToSigned(e) => rec(e)
331+
case BVSignedToUnsigned(e) => rec(e)
332+
330333
case LessThan(l, r) => l.getType match {
331334
case IntegerType() => z3.mkLT(rec(l), rec(r))
332335
case RealType() => z3.mkLT(rec(l), rec(r))

src/main/scala/inox/utils/Serialization.scala

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -523,10 +523,10 @@ class InoxSerializer(val trees: ast.Trees, serializeProducts: Boolean = false) e
523523
/** A mapping from `Class[_]` to `Serializer[_]` for classes that commonly
524524
* occur within Stainless programs.
525525
*
526-
* The `Serializer[_]` identifiers in this mapping range from 10 to 102
526+
* The `Serializer[_]` identifiers in this mapping range from 10 to 105
527527
* (ignoring special identifiers that are smaller than 10).
528528
*
529-
* NEXT ID: 104
529+
* NEXT ID: 106
530530
*/
531531
protected def classSerializers: Map[Class[_], Serializer[_]] = Map(
532532
// Inox Expressions
@@ -598,6 +598,8 @@ class InoxSerializer(val trees: ast.Trees, serializeProducts: Boolean = false) e
598598
classSerializer[FiniteMap] (72),
599599
classSerializer[MapApply] (73),
600600
classSerializer[MapUpdated] (74),
601+
classSerializer[BVUnsignedToSigned](104),
602+
classSerializer[BVSignedToUnsigned](105),
601603

602604
// Inox Types
603605
classSerializer[Untyped.type] (75),

0 commit comments

Comments
 (0)