Skip to content

Commit 16c0299

Browse files
committed
Backend support for SMTLib types (particularly bitvectors and floats)
1 parent eaaaab2 commit 16c0299

8 files changed

Lines changed: 97 additions & 1 deletion

File tree

src/main/scala/viper/silver/ast/Expression.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,18 @@ object DomainFuncApp {
387387
DomainFuncApp(func.name,args,typVarMap)(pos, info, func.typ.substitute(typVarMap), func.domainName, errT)
388388
}
389389

390+
// --- References to built-in SMT Lib functions
391+
392+
case class SMTFuncApp(smtfunc: SMTFunc, args: Seq[Exp])
393+
(val pos: Position, val info: Info, override val typ : Type, val errT: ErrorTrafo)
394+
extends AbstractDomainFuncApp with PossibleTrigger {
395+
override lazy val check : Seq[ConsistencyError] = args.flatMap(Consistency.checkPure)
396+
def getArgs = args
397+
def withArgs(newArgs: Seq[Exp]) = SMTFuncApp(smtfunc, newArgs)(pos,info,typ, errT)
398+
override def func = (p: Program) => smtfunc
399+
def funcname = smtfunc.name
400+
}
401+
390402
// --- Field and predicate accesses
391403

392404
/** A common trait for expressions accessing a location. */

src/main/scala/viper/silver/ast/Program.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -705,3 +705,7 @@ case object NotOp extends UnOp with BoolDomainFunc {
705705
lazy val priority = 10
706706
lazy val fixity = Prefix
707707
}
708+
709+
710+
case class SMTFunc(name: String, smtName: String, override val typ: Type, override val formalArgs: Seq[LocalVarDecl]) extends Node with AbstractDomainFunc with BuiltinDomainFunc
711+

src/main/scala/viper/silver/ast/Type.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,3 +183,5 @@ case class TypeVar(name: String) extends Type {
183183

184184
//def !=(other: TypeVar) = name != other
185185
}
186+
187+
case class SMTType(boogieName: String, smtName: String) extends AtomicType

src/main/scala/viper/silver/ast/pretty/PrettyPrinter.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -618,6 +618,7 @@ object FastPrettyPrinter extends FastPrettyPrinterBase with BracketPrettyPrinter
618618
case dt@DomainType(domainName, typVarsMap) =>
619619
val typArgs = dt.typeParameters map (t => show(typVarsMap.getOrElse(t, t)))
620620
text(domainName) <> (if (typArgs.isEmpty) nil else brackets(ssep(typArgs, char (',') <> space)))
621+
case SMTType(boogieName, _) => boogieName
621622
}
622623
}
623624

@@ -766,6 +767,8 @@ object FastPrettyPrinter extends FastPrettyPrinterBase with BracketPrettyPrinter
766767
text(funcname) <> parens(ssep(args map show, char (',') <> space))
767768
case DomainFuncApp(funcname, args, _) =>
768769
text(funcname) <> parens(ssep(args map show, char (',') <> space))
770+
case SMTFuncApp(func, args) =>
771+
text(func.name) <> parens(ssep(args map show, char(',') <> space))
769772

770773
case EmptySeq(elemTyp) =>
771774
text("Seq[") <> showType(elemTyp) <> "]()"

src/main/scala/viper/silver/ast/utility/Expressions.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ object Expressions {
3232
| _: PermExp
3333
| _: FuncApp
3434
| _: DomainFuncApp
35+
| _: SMTFuncApp
3536
| _: LocationAccess
3637
| _: AbstractLocalVar
3738
| _: SeqExp

src/main/scala/viper/silver/ast/utility/Nodes.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ object Nodes {
106106
case FuncApp(_, args) => args
107107
case DomainFuncApp(_, args, m) =>
108108
args ++ m.keys ++ m.values
109+
case SMTFuncApp(_, args) => args
109110

110111
case EmptySeq(elemTyp) => Seq(elemTyp)
111112
case ExplicitSeq(elems) => elems
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package viper.silver.ast.utility
2+
3+
import viper.silver.ast.{Bool, Int, LocalVarDecl, SMTFunc, SMTType}
4+
5+
/**
6+
* A factory for fixed-size bitvectors that offers convenient access to bitvector types, as well as
7+
* function definitions for unary and binary functions on bitvectors, as well as conversions from and
8+
* to integers.
9+
*/
10+
case class BVFactory(size: Int) {
11+
lazy val typ = SMTType(s"bv${size}", s"(_ BitVec ${size})")
12+
13+
def xor(name: String) = SMTFunc(name, "bvxor", typ, Seq(LocalVarDecl("x", typ)(), LocalVarDecl("y", typ)()))
14+
def and(name: String) = SMTFunc(name, "bvand", typ, Seq(LocalVarDecl("x", typ)(), LocalVarDecl("y", typ)()))
15+
def or(name: String) = SMTFunc(name, "bvor", typ, Seq(LocalVarDecl("x", typ)(), LocalVarDecl("y", typ)()))
16+
def add(name: String) = SMTFunc(name, "bvadd", typ, Seq(LocalVarDecl("x", typ)(), LocalVarDecl("y", typ)()))
17+
def mul(name: String) = SMTFunc(name, "bvmul", typ, Seq(LocalVarDecl("x", typ)(), LocalVarDecl("y", typ)()))
18+
def shl(name: String) = SMTFunc(name, "bvshl", typ, Seq(LocalVarDecl("x", typ)(), LocalVarDecl("y", typ)()))
19+
def shr(name: String) = SMTFunc(name, "bvshr", typ, Seq(LocalVarDecl("x", typ)(), LocalVarDecl("y", typ)()))
20+
21+
def not(name: String) = SMTFunc(name, "bvnot", typ, Seq(LocalVarDecl("x", typ)()))
22+
def neg(name: String) = SMTFunc(name, "bvneg", typ, Seq(LocalVarDecl("x", typ)()))
23+
24+
def from_int(name: String) = SMTFunc(name, s"(_ int2bv ${size})", typ, Seq(LocalVarDecl("x", Int)()))
25+
def to_int(name: String) = SMTFunc(name, s"(_ bv2int ${size})", Int, Seq(LocalVarDecl("x", typ)()))
26+
def from_nat(name: String) = SMTFunc(name, s"(_ nat2bv ${size})", typ, Seq(LocalVarDecl("x", Int)()))
27+
def to_nat(name: String) = SMTFunc(name, s"(_ bv2nat ${size})", Int, Seq(LocalVarDecl("x", typ)()))
28+
}
29+
30+
/**
31+
* Rounding modes for floating point operations.
32+
*/
33+
object RoundingMode extends Enumeration {
34+
type RoundingMode = Value
35+
val RNE, RNA, RTP, RTN, RTZ = Value
36+
}
37+
import RoundingMode._
38+
39+
/**
40+
* A factory for IEEE floating point numbers with "exp" bits for the exponent, "mant" bits for the significant,
41+
* including the hidden bit, and a given rounding mode for all operations that use one.
42+
* Offers access to types, unary and binary operations, comparisons, and conversions from and to
43+
* bitvectors of size exp + mant.
44+
*/
45+
case class FloatFactory(mant: Int, exp: Int, roundingMode: RoundingMode) {
46+
47+
lazy val typ = SMTType(s"float${mant}e${exp}", s"(_ FloatingPoint ${exp} ${mant})")
48+
49+
def neg(name: String) = SMTFunc(name, "fp.neg", typ, Seq(LocalVarDecl("x", typ)()))
50+
def abs(name: String) = SMTFunc(name, "fp.abs", typ, Seq(LocalVarDecl("x", typ)()))
51+
52+
def add(name: String) = SMTFunc(name, s"fp.add ${roundingMode}", typ, Seq(LocalVarDecl("x", typ)(), LocalVarDecl("y", typ)()))
53+
def sub(name: String) = SMTFunc(name, s"fp.sub ${roundingMode}", typ, Seq(LocalVarDecl("x", typ)(), LocalVarDecl("y", typ)()))
54+
def mul(name: String) = SMTFunc(name, s"fp.mul ${roundingMode}", typ, Seq(LocalVarDecl("x", typ)(), LocalVarDecl("y", typ)()))
55+
def div(name: String) = SMTFunc(name, s"fp.div ${roundingMode}", typ, Seq(LocalVarDecl("x", typ)(), LocalVarDecl("y", typ)()))
56+
def min(name: String) = SMTFunc(name, s"fp.min ${roundingMode}", typ, Seq(LocalVarDecl("x", typ)(), LocalVarDecl("y", typ)()))
57+
def max(name: String) = SMTFunc(name, s"fp.max ${roundingMode}", typ, Seq(LocalVarDecl("x", typ)(), LocalVarDecl("y", typ)()))
58+
59+
def eq(name: String) = SMTFunc(name, s"fp.eq", Bool, Seq(LocalVarDecl("x", typ)(), LocalVarDecl("y", typ)()))
60+
def leq(name: String) = SMTFunc(name, s"fp.leq", Bool, Seq(LocalVarDecl("x", typ)(), LocalVarDecl("y", typ)()))
61+
def geq(name: String) = SMTFunc(name, s"fp.geq", Bool, Seq(LocalVarDecl("x", typ)(), LocalVarDecl("y", typ)()))
62+
def lt(name: String) = SMTFunc(name, s"fp.lt", Bool, Seq(LocalVarDecl("x", typ)(), LocalVarDecl("y", typ)()))
63+
def gt(name: String) = SMTFunc(name, s"fp.gt", Bool, Seq(LocalVarDecl("x", typ)(), LocalVarDecl("y", typ)()))
64+
65+
def isZero(name: String) = SMTFunc(name, s"fp.isZero", Bool, Seq(LocalVarDecl("x", typ)()))
66+
def isInfinite(name: String) = SMTFunc(name, s"fp.isInfinite", Bool, Seq(LocalVarDecl("x", typ)()))
67+
def isNaN(name: String) = SMTFunc(name, s"fp.isNaN", Bool, Seq(LocalVarDecl("x", typ)()))
68+
def isNegative(name: String) = SMTFunc(name, s"fp.isNegative", Bool, Seq(LocalVarDecl("x", typ)()))
69+
def isPositive(name: String) = SMTFunc(name, s"fp.isPositive", Bool, Seq(LocalVarDecl("x", typ)()))
70+
71+
def from_bv(name: String) = SMTFunc(name, s"(_ to_fp ${exp} ${mant}) ", typ, Seq(LocalVarDecl("x", BVFactory(mant+exp).typ)()))
72+
def to_bv(name: String) = SMTFunc(name, s"(_ fp.to_sbv ${exp+mant}) ${roundingMode} ", BVFactory(mant+exp).typ, Seq(LocalVarDecl("x", typ)()))
73+
}

src/main/scala/viper/silver/ast/utility/Types.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ object Types {
6969
* @return The list of transitive type constituents of `typ`.
7070
*/
7171
def typeConstituents(typ: Type): List[Type] = typ match {
72-
case Int | Bool | Perm | Ref | InternalType | _: TypeVar | Wand => Nil
72+
case Int | Bool | Perm | Ref | InternalType | _: TypeVar | Wand | _: SMTType => Nil
7373
case dt: DomainType => dt.typeParameters.map(_.substitute(dt.typVarsMap)).toList
7474
case SeqType(elementType) => elementType :: typeConstituents(elementType)
7575
case SetType(elementType) => elementType :: typeConstituents(elementType)

0 commit comments

Comments
 (0)