Skip to content

Commit cca3634

Browse files
committed
Merge branch 'master' into annotations
2 parents 553b47d + 4729082 commit cca3634

2 files changed

Lines changed: 61 additions & 0 deletions

File tree

‎src/SUMMARY.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
- [Domains](./domains.md)
4040
- [Declaring new types](./domains-new-types.md)
4141
- [Axiomatising custom theories](./domains-axiomatising.md)
42+
- [Interpreted domains](./domains-interpretations.md)
4243
- [Encoding an array datatype](./domains-array.md)
4344
- [ADT plugin](./domains-adt.md)
4445
- [Termination](./termination.md)

‎src/domains-interpretations.md‎

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# Interpreted domains
2+
3+
The domains presented so far introduce *uninterpreted* types and functions, whose meaning is given entirely by user-written axioms. Sometimes, however, the theory one wants to model is already built into the tools underlying Viper's verification backends: for example, SMT solvers natively support fixed-size bitvectors and IEEE floating-point numbers. For such cases, Viper allows attaching *interpretations* to a domain and its functions, mapping the domain type directly onto a sort of the backend's input language, and the domain's functions onto operations of that sort.
4+
5+
An interpreted domain is declared by following the domain name with an `interpretation` clause. This clause is a key-value map that specifies, for each backend, the name of the backend sort the domain type stands for: the value for the `SMTLIB` key is used by Viper's Symbolic Execution (SE) backend, whose proof obligations are expressed in SMT-LIB, and the value for the `Boogie` key by the Verification Condition Generation (VCG) backend, which encodes Viper programs into the Boogie language. Individual keys may be omitted (the clause cannot, however, be abbreviated to a single string), but using an interpreted domain that lacks the key for the backend the program is verified with results in an error.
6+
7+
The `interpretation` clause on an individual domain *function* has a different form: it is always a single string, namely, the SMT-LIB name of the operation the function stands for; this name is used by both backends. The following example declares a type of 32-bit bitvectors, along with several operations on them:
8+
9+
```viper,editable,playground
10+
domain BV32 interpretation (SMTLIB: "(_ BitVec 32)", Boogie: "bv32") {
11+
function toBV32(i: Int): BV32 interpretation "(_ int2bv 32)"
12+
function bv_and(a: BV32, b: BV32): BV32 interpretation "bvand"
13+
function bv_or(a: BV32, b: BV32): BV32 interpretation "bvor"
14+
function bv_add(a: BV32, b: BV32): BV32 interpretation "bvadd"
15+
function bv_shl(a: BV32, b: BV32): BV32 interpretation "bvshl"
16+
}
17+
18+
method bvTest()
19+
{
20+
var a: BV32 := toBV32(5)
21+
var b: BV32 := toBV32(3)
22+
assert bv_and(a, b) == toBV32(1)
23+
assert bv_or(a, b) == toBV32(7)
24+
assert bv_add(a, b) == toBV32(8)
25+
assert bv_shl(toBV32(1), toBV32(3)) == toBV32(8)
26+
}
27+
```
28+
29+
Values of an interpreted domain type can be used like values of any other type: they can be stored in variables, fields and collections, passed to methods and functions, and compared with `==`. The interpretation strings themselves are *not* interpreted by Viper: they are passed to the backend verbatim, and it is the user's responsibility to denote existing sorts and operations (with matching arities and types) in the backend's input language -- mistakes will surface as errors from the backend rather than as Viper type errors.
30+
31+
Interpreted domains can be freely combined with the usual domain features: functions without an `interpretation` clause remain uninterpreted, and axioms can be written to relate interpreted and uninterpreted functions. As a second example, the following domain models IEEE 32-bit floating-point numbers, constructed from their bit-level representation:
32+
33+
```viper,editable,playground
34+
domain BV32 interpretation (SMTLIB: "(_ BitVec 32)", Boogie: "bv32") {
35+
function toBV32(i: Int): BV32 interpretation "(_ int2bv 32)"
36+
}
37+
38+
domain Float32 interpretation (SMTLIB: "Float32", Boogie: "float24e8") {
39+
function toFloat(bv: BV32): Float32 interpretation "(_ to_fp 8 24)"
40+
function fadd(a: Float32, b: Float32): Float32 interpretation "fp.add RNE"
41+
function fgt(a: Float32, b: Float32): Bool interpretation "fp.gt"
42+
}
43+
44+
method floatTest()
45+
{
46+
// the arguments below are the bit patterns of the
47+
// floating-point numbers 3.75, 25.5 and 29.25
48+
var a: Float32 := toFloat(toBV32(1081081856))
49+
var b: Float32 := toFloat(toBV32(1103888384))
50+
var c: Float32 := toFloat(toBV32(1105854464))
51+
assert fadd(a, b) == c
52+
assert fgt(fadd(a, b), a)
53+
}
54+
```
55+
56+
Note that `fadd` is interpreted as `fp.add RNE`, i.e., floating-point addition with a fixed rounding mode (round-nearest-even); reasoning happens with respect to the exact IEEE semantics, including rounding.
57+
58+
> **Exercise**
59+
> * Extend the `BV32` domain of the first example with a function `bv_xor` interpreted as `"bvxor"`, and use it to prove `bv_xor(x, x) == toBV32(0)` for an arbitrary method parameter `x: BV32`.
60+
> * In the second example, replace the bit pattern of `c` with that of a different number (e.g., change the last digit) and observe that the first assertion fails.

0 commit comments

Comments
 (0)