File: bv.mlw

package info (click to toggle)
why3 1.8.2-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 45,028 kB
  • sloc: xml: 185,443; ml: 111,224; ansic: 3,998; sh: 2,578; makefile: 2,568; java: 865; python: 720; javascript: 290; lisp: 205; pascal: 173
file content (446 lines) | stat: -rw-r--r-- 14,311 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
(** {1 Program functions on bitvectors with preconditions}

    This module provides extra functions with pre-conditions ensuring
    the absence of overflows.

    Those pre-conditions are expressed in term of interpretation into
    mathematical integers, or using bitvectors of size 128.

*)

(** {2 Generic module, for a parametric size} *)

module BVCheck_Gen
  use int.Int

  type t

  constant size : int
  constant size_bv : t

  (* Overflow checks are performed using bitvectors of size 128. Thus
     this module cannot be cloned with a [size] > 64. *)
  axiom not_greater_than_64 : size <= 64

  constant two_power_size : int
  constant two_power_size_minus_one : int
  constant zeros           : t
  constant minus_one : t

  function to_uint t   : int
  function to_int t   : int
  function of_int  int : t

  function add  t t : t
  function sub  t t : t
  function mul  t t : t
  function udiv t t : t
  function urem t t : t
  function sdiv t t : t
  function srem t t : t

  function lsl    t int : t
  function lsl_bv t t   : t
  function lsr    t int : t
  function lsr_bv t t   : t
  function asr    t int : t
  function asr_bv t t   : t

  predicate ule t t
  predicate ult t t
  predicate uge t t
  predicate ugt t t

  predicate sle t t
  predicate slt t t
  predicate sge t t
  predicate sgt t t

  use bv.BV128 as BV128

  function sto_bv128 t : BV128.t
  function uto_bv128 t : BV128.t

  constant min_sint : t
  constant max_sint : t
  constant max_uint : t
  constant min_sint_as_bv128 : BV128.t = sto_bv128 min_sint
  constant max_sint_as_bv128 : BV128.t = sto_bv128 max_sint
  constant max_uint_as_bv128 : BV128.t = uto_bv128 max_uint

  (** unsigned addition forbidding overflows *)
  val u_add (a b:t) : t
    requires { [@expl:arithmetic overflow]
                  to_uint a + to_uint b < two_power_size
               \/ BV128.ule (BV128.add (uto_bv128 a) (uto_bv128 b)) max_uint_as_bv128 }
    ensures  { to_uint result = to_uint a + to_uint b }
    ensures  { result = add a b }

  (** signed addition forbidding overflows *)
  val s_add (a b:t) : t
    requires { [@expl:arithmetic overflow]
      - two_power_size_minus_one <= to_int a + to_int b < two_power_size_minus_one
      \/ let r = BV128.add (sto_bv128 a) (sto_bv128 b) in
         (BV128.sle min_sint_as_bv128 r /\ BV128.sle r max_sint_as_bv128) }
    ensures  { to_int result = to_int a + to_int b }
    ensures  { result = add a b }

  (** unsigned subtraction with overflow check *)
  val u_sub (a b:t) : t
    requires { [@expl:arithmetic overflow] to_uint a >= to_uint b \/ uge a b }
    ensures  { result = sub a b }
    ensures  { to_uint result = to_uint a - to_uint b }

  (** signed subtraction with overflow check *)
  val s_sub (a b:t) : t
    requires { [@expl:arithmetic overflow]
      - two_power_size_minus_one <= to_int a - to_int b < two_power_size_minus_one
      \/ let r = BV128.sub (sto_bv128 a) (sto_bv128 b) in
         (BV128.sle min_sint_as_bv128 r /\ BV128.sle r max_sint_as_bv128) }
    ensures  { result = sub a b }
    ensures  { to_int result = to_int a - to_int b }

  (** unsigned multiplication with overflow check *)
  val u_mul (a b:t) : t
    requires { [@expl:arithmetic overflow]
                  to_uint a * to_uint b < two_power_size
               \/ BV128.ule (BV128.mul (uto_bv128 a) (uto_bv128 b)) max_uint_as_bv128 }
    ensures  { result = mul a b }
    ensures  { to_int result = to_uint a * to_uint b }

  (** signed multiplication with overflow check *)
  val s_mul (a b:t) : t
    requires { [@expl:arithmetic overflow]
      - two_power_size_minus_one <= to_int a * to_int b < two_power_size_minus_one
      \/ let r = BV128.mul (sto_bv128 a) (sto_bv128 b) in
         (BV128.sle min_sint_as_bv128 r /\ BV128.sle r max_sint_as_bv128) }
    ensures  { result = mul a b }
    ensures  { to_int result = to_int a * to_int b }

  use bv.Pow2int

  (** A logical shift left requiring the second argument to be smaller than bitvector size.
      For this function we do not forbid overflow: bits can be ``lost'' on the left.
      This function corresponds to the left shifting [<<] of unsigned ints in C or Java *)
  val u_lsl (a b:t) : t
    requires { [@expl:out-of-bounds shifting]
                ult b size_bv \/ to_uint b < size }
    ensures  { result = lsl_bv a b }
    ensures  { result = lsl a (to_uint b) }

  (** Alternative logical shift left, still requiring the second argument to be smaller
      than bitvector size, but also forbidding overflow.
      This function corresponds to the left shifting [<<] of signed ints in C or Java *)
  val s_lsl (a b:t) : t
    requires { [@expl:out-of-bounds shifting]
                ult b size_bv \/ to_uint b < size }
    requires { [@expl:out-of-bounds shifting]
                sle zeros a \/ to_int a >= 0 }
    requires { [@expl:arithmetic overflow]
      (to_int a) * (pow2 (to_int b)) < two_power_size_minus_one
      \/ let r = BV128.lsl_bv (sto_bv128 a) (sto_bv128 b) in
         (BV128.sle min_sint_as_bv128 r /\ BV128.sle r max_sint_as_bv128) }
    ensures  { result = lsl_bv a b }
    ensures  { result = lsl a (to_uint b) }

  (** Logical shift right, requiring the second argument to be smaller than bitvector size.
      No overflow can occur anyway.
      This function corresponds to the (logical) right shifting [>>] of unsigned ints in C
      or Java. *)
  val u_lsr (a b:t) : t
    requires { [@expl:out-of-bounds shifting]
                ult b size_bv \/ to_uint b < size }
    ensures  { result = lsr_bv a b }
    ensures  { result = lsr a (to_uint b) }

  (** The so-called "arithmetic" shift right, requirings the second
      argument to be smaller than bitvector size.  This function
      corresponds to the arithmetic right shifting [>>>] of signed
      ints in Java, that does not exist in C. *)
  val s_asr (a b:t) : t
    requires { [@expl:out-of-bounds shifting]
                ult b size_bv \/ to_uint b < size }
    ensures  { result = asr_bv a b }
    ensures  { result = asr a (to_uint b) }

  (** The shift right function for signed int, requirings the second
      argument to be smaller than bitvector size, and that the first argument in non-negative.
      This function corresponds to the right shifting [>>] of signed ints in C. *)
  val s_asr_strict (a b:t) : t
    requires { [@expl:out-of-bounds shifting]
                ult b size_bv \/ to_uint b < size }
    requires { [@expl:out-of-bounds shifting]
                sge a zeros \/ to_int a >= 0 }
    ensures  { result = asr_bv a b }
    ensures  { result = asr a (to_uint b) }

  use int.EuclideanDivision as ED

  (** unsigned division requires the second argument to be non-zero *)
  val u_div (a b:t) : t
    requires { [@expl:division by zero] b <> zeros \/ to_uint b <> 0 }
    ensures  { to_uint result = ED.div (to_uint a) (to_uint b) }
    ensures  { result = udiv a b }

  (** unsigned remainder requires the second argument to be non-zero *)
  val u_rem (a b:t) : t
    requires { [@expl:remainder by zero] b <> zeros  \/ to_uint b <> 0 }
    ensures  { to_uint result = ED.mod (to_uint a) (to_uint b) }
    ensures  { result = urem a b }

  use int.ComputerDivision as CD

  (** signed division requires the second argument to be non-zero, but also that
      either the dividend is not [min_int] or the divisor is not [-1] *)
  val s_div (a b:t) : t
    requires { [@expl:division by zero] b <> zeros  \/ to_int b <> 0 }
    requires { [@expl:signed division overflow check] (a <> min_sint \/ b <> minus_one)
                \/ (to_int a <> to_int min_sint \/ to_int b <> -1)}
    ensures  { to_int result = CD.div (to_int a) (to_int b) }
    ensures  { result = sdiv a b }

  (** signed remainder requires the second argument to be non-zero *)
  val s_rem (a b:t) : t
    requires { [@expl:remainder by zero] b <> zeros \/ to_int b <> 0 }
    ensures  { to_int result = CD.mod (to_int a) (to_int b) }
    ensures  { result = srem a b }

  (** comparison operators have no preconditions *)
  val us_eq (a b:t) : bool
    ensures { result <-> a = b }

  val us_ne (a b:t) : bool
    ensures { result <-> a <> b }

  val u_le (a b:t) : bool
    ensures { result <-> to_uint a <= to_uint b }
    ensures { result <-> ule a b }

  val u_lt (a b:t) : bool
    ensures { result <-> to_uint a < to_uint b }
    ensures { result <-> ult a b }

  val u_ge (a b:t) : bool
    ensures { result <-> to_uint a >= to_uint b }
    ensures { result <-> uge a b }

  val u_gt (a b:t) : bool
    ensures { result <-> to_uint a > to_uint b }
    ensures { result <-> ugt a b }

  val s_le (a b:t) : bool
    ensures { result <-> to_int a <= to_int b }
    ensures { result <-> sle a b }

  val s_lt (a b:t) : bool
    ensures { result <-> to_int a < to_int b }
    ensures { result <-> slt a b }

  val s_ge (a b:t) : bool
    ensures { result <-> to_int a >= to_int b }
    ensures { result <-> sge a b }

  val s_gt (a b:t) : bool
    ensures { result <-> to_int a > to_int b }
    ensures { result <-> sgt a b }

end

(** {2 Modules for specific sizes} obtained by cloning the previous generic module *)

module BVCheck8
  use export bv.BV8

  constant minus_one : t = 0xFF
  constant min_sint : t = 0x80
  constant max_sint : t = 0x7F
  constant max_uint : t = 0xFF

  use bv.BVConverter_8_128

  clone export BVCheck_Gen with
    type t = t,
    constant size = size,
    constant size_bv = size_bv,
    function two_power_size = two_power_size,
    function two_power_size_minus_one = two_power_size_minus_one,
    function zeros = zeros,
    function minus_one = minus_one,
    function min_sint = min_sint,
    function max_sint = max_sint,
    function max_uint = max_uint,
    function to_uint = t'int,
    function to_int = to_int,
    function of_int = of_int,
    function add = add,
    function sub = sub,
    function mul = mul,
    function udiv = udiv,
    function urem = urem,
    function sdiv = sdiv,
    function srem = srem,
    function lsl = lsl,
    function lsl_bv = lsl_bv,
    function lsr = lsr,
    function lsr_bv = lsr_bv,
    function asr = asr,
    function asr_bv = asr_bv,
    predicate ule = ule,
    predicate ult = ult,
    predicate uge = uge,
    predicate ugt = ugt,
    predicate sle = sle,
    predicate slt = slt,
    predicate sge = sge,
    predicate sgt = sgt,
    function sto_bv128 = stoBig,
    function uto_bv128 = toBig
end


module BVCheck16
  use export bv.BV16

  constant minus_one : t = 0xFFFF
  constant min_sint : t = 0x8000
  constant max_sint : t = 0x7FFF
  constant max_uint : t = 0xFFFF

  use bv.BVConverter_16_128

  clone export BVCheck_Gen with
    type t = t,
    constant size = size,
    constant size_bv = size_bv,
    function two_power_size = two_power_size,
    function two_power_size_minus_one = two_power_size_minus_one,
    function zeros = zeros,
    function minus_one = minus_one,
    function min_sint = min_sint,
    function max_sint = max_sint,
    function max_uint = max_uint,
    function to_uint = t'int,
    function to_int = to_int,
    function of_int = of_int,
    function add = add,
    function sub = sub,
    function mul = mul,
    function udiv = udiv,
    function urem = urem,
    function sdiv = sdiv,
    function srem = srem,
    function lsl = lsl,
    function lsl_bv = lsl_bv,
    function lsr = lsr,
    function lsr_bv = lsr_bv,
    function asr = asr,
    function asr_bv = asr_bv,
    predicate ule = ule,
    predicate ult = ult,
    predicate uge = uge,
    predicate ugt = ugt,
    predicate sle = sle,
    predicate slt = slt,
    predicate sge = sge,
    predicate sgt = sgt,
    function sto_bv128 = stoBig,
    function uto_bv128 = toBig
end

module BVCheck32
  use export bv.BV32

  constant minus_one : t = 0xFFFF_FFFF
  constant min_sint : t = 0x8000_0000
  constant max_sint : t = 0x7FFF_FFFF
  constant max_uint : t = 0xFFFF_FFFF

  use bv.BVConverter_32_128

  clone export BVCheck_Gen with
    type t = t,
    constant size = size,
    constant size_bv = size_bv,
    function two_power_size = two_power_size,
    function two_power_size_minus_one = two_power_size_minus_one,
    function zeros = zeros,
    function minus_one = minus_one,
    function min_sint = min_sint,
    function max_sint = max_sint,
    function max_uint = max_uint,
    function to_uint = t'int,
    function to_int = to_int,
    function of_int = of_int,
    function add = add,
    function sub = sub,
    function mul = mul,
    function udiv = udiv,
    function urem = urem,
    function sdiv = sdiv,
    function srem = srem,
    function lsl = lsl,
    function lsl_bv = lsl_bv,
    function lsr = lsr,
    function lsr_bv = lsr_bv,
    function asr = asr,
    function asr_bv = asr_bv,
    predicate ule = ule,
    predicate ult = ult,
    predicate uge = uge,
    predicate ugt = ugt,
    predicate sle = sle,
    predicate slt = slt,
    predicate sge = sge,
    predicate sgt = sgt,
    function sto_bv128 = stoBig,
    function uto_bv128 = toBig
end

module BVCheck64
  use export bv.BV64

  constant minus_one : t = 0xFFFF_FFFF_FFFF_FFFF
  constant min_sint : t = 0x8000_0000_0000_0000
  constant max_sint : t = 0x7FFF_FFFF_FFFF_FFFF
  constant max_uint : t = 0xFFFF_FFFF_FFFF_FFFF

  use bv.BVConverter_64_128

  clone export BVCheck_Gen with
    type t = t,
    constant size = size,
    constant size_bv = size_bv,
    function two_power_size = two_power_size,
    function two_power_size_minus_one = two_power_size_minus_one,
    function zeros = zeros,
    function minus_one = minus_one,
    function min_sint = min_sint,
    function max_sint = max_sint,
    function max_uint = max_uint,
    function to_uint = t'int,
    function to_int = to_int,
    function of_int = of_int,
    function add = add,
    function sub = sub,
    function mul = mul,
    function udiv = udiv,
    function urem = urem,
    function sdiv = sdiv,
    function srem = srem,
    function lsl = lsl,
    function lsl_bv = lsl_bv,
    function lsr = lsr,
    function lsr_bv = lsr_bv,
    function asr = asr,
    function asr_bv = asr_bv,
    predicate ule = ule,
    predicate ult = ult,
    predicate uge = uge,
    predicate ugt = ugt,
    predicate sle = sle,
    predicate slt = slt,
    predicate sge = sge,
    predicate sgt = sgt,
    function sto_bv128 = stoBig,
    function uto_bv128 = toBig
end