• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

formalsec / smtml / 442

13 Dec 2025 07:41PM UTC coverage: 45.333% (-0.3%) from 45.639%
442

push

github

filipeom
add some shortcuts on relop based on physical equality

6 of 19 new or added lines in 1 file covered. (31.58%)

3 existing lines in 3 files now uncovered.

879 of 1939 relevant lines covered (45.33%)

7.46 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

78.57
/src/smtml/eval.ml
1
(* SPDX-License-Identifier: MIT *)
2
(* Copyright (C) 2023-2024 formalsec *)
3
(* Written by the Smtml programmers *)
4

5
(* Adapted from: *)
6
(* - https://github.com/WebAssembly/spec/blob/main/interpreter/exec/ixx.ml, *)
7
(* - https://github.com/WebAssembly/spec/blob/main/interpreter/exec/fxx.ml, and *)
8
(* - https://github.com/WebAssembly/spec/blob/main/interpreter/exec *)
9

10
type op_type =
11
  [ `Unop of Ty.Unop.t
12
  | `Binop of Ty.Binop.t
13
  | `Relop of Ty.Relop.t
14
  | `Triop of Ty.Triop.t
15
  | `Cvtop of Ty.Cvtop.t
16
  | `Naryop of Ty.Naryop.t
17
  ]
18

19
let pp_op_type fmt = function
20
  | `Unop op -> Fmt.pf fmt "unop '%a'" Ty.Unop.pp op
6✔
21
  | `Binop op -> Fmt.pf fmt "binop '%a'" Ty.Binop.pp op
×
22
  | `Relop op -> Fmt.pf fmt "relop '%a'" Ty.Relop.pp op
×
23
  | `Triop op -> Fmt.pf fmt "triop '%a'" Ty.Triop.pp op
×
24
  | `Cvtop op -> Fmt.pf fmt "cvtop '%a'" Ty.Cvtop.pp op
×
25
  | `Naryop op -> Fmt.pf fmt "naryop '%a'" Ty.Naryop.pp op
×
26

27
type type_error_info =
28
  { index : int
29
  ; value : Value.t
30
  ; ty : Ty.t
31
  ; op : op_type
32
  ; msg : string
33
  }
34

35
type error_kind =
36
  [ `Divide_by_zero
37
  | `Conversion_to_integer
38
  | `Integer_overflow
39
  | `Index_out_of_bounds
40
  | `Invalid_format_conversion
41
  | `Unsupported_operator of op_type * Ty.t
42
  | `Unsupported_theory of Ty.t
43
  | `Type_error of type_error_info
44
  ]
45

46
exception Eval_error of error_kind
47

48
exception Value of Ty.t
49

50
(* Exception helpers *)
51

52
let eval_error kind = raise (Eval_error kind)
13✔
53

54
let type_error n v ty op msg =
55
  eval_error (`Type_error { index = n; value = v; ty; op; msg })
9✔
56

57
let err_str n op ty_expected ty_actual =
58
  Fmt.str "Argument %d of %a expected type %a but got %a instead." n pp_op_type
6✔
59
    op Ty.pp ty_expected Ty.pp ty_actual
60

61
let[@inline] of_arg f n v op =
62
  try f v
649✔
63
  with Value expected_ty ->
6✔
64
    let actual_ty = Value.type_of v in
65
    let msg = err_str n op expected_ty actual_ty in
6✔
66
    type_error n v expected_ty op msg
6✔
67

68
(* Coercion helpers *)
69

70
let of_int n op v =
71
  of_arg (function Int x -> x | _ -> raise_notrace (Value Ty_int)) n v op
1✔
72

73
let[@inline] to_int x = Value.Int x
48✔
74

75
let of_real n op v =
76
  of_arg (function Real x -> x | _ -> raise_notrace (Value Ty_real)) n v op
1✔
77

78
let[@inline] to_real x = Value.Real x
37✔
79

80
let of_bool n op v =
81
  of_arg
51✔
82
    (function
83
      | True -> true | False -> false | _ -> raise_notrace (Value Ty_bool) )
1✔
84
    n v op
85

86
let[@inline] to_bool x = if x then Value.True else False
12✔
87

88
let of_str n op v =
89
  of_arg (function Str x -> x | _ -> raise_notrace (Value Ty_str)) n v op
1✔
90

91
let[@inline] to_str x = Value.Str x
16✔
92

93
let of_list n op v =
94
  of_arg (function List x -> x | _ -> raise_notrace (Value Ty_list)) n v op
×
95

96
let of_bitv n op v =
97
  of_arg
154✔
98
    (function Bitv x -> x | _ -> raise_notrace (Value (Ty_bitv 0)))
×
99
    n v op
100

101
let int32_of_bitv n op v = of_bitv n op v |> Bitvector.to_int32
8✔
102

103
let int64_of_bitv n op v = of_bitv n op v |> Bitvector.to_int64
12✔
104

105
let[@inline] to_bitv x = Value.Bitv x
75✔
106

107
let[@inline] bitv_of_int32 x = to_bitv (Bitvector.of_int32 x)
14✔
108

109
let[@inline] bitv_of_int64 x = to_bitv (Bitvector.of_int64 x)
11✔
110

111
let of_fp32 i op v : int32 =
112
  of_arg
92✔
113
    (function Num (F32 f) -> f | _ -> raise_notrace (Value (Ty_fp 32)))
1✔
114
    i v op
115

116
let[@inline] to_fp32 (x : int32) = Value.Num (F32 x)
35✔
117

118
let[@inline] fp32_of_float (x : float) = to_fp32 (Int32.bits_of_float x)
15✔
119

120
let of_fp64 i op v : int64 =
121
  of_arg
87✔
122
    (function Num (F64 f) -> f | _ -> raise_notrace (Value (Ty_fp 32)))
1✔
123
    i v op
124

125
let[@inline] to_fp64 (x : int64) = Value.Num (F64 x)
32✔
126

127
let[@inline] fp64_of_float (x : float) = to_fp64 (Int64.bits_of_float x)
15✔
128

129
(* Operator evaluation *)
130

131
module Int = struct
132
  let unop (op : Ty.Unop.t) (v : Value.t) : Value.t =
133
    let f =
6✔
134
      match op with
135
      | Neg -> Int.neg
3✔
136
      | Not -> Int.lognot
1✔
137
      | Abs -> Int.abs
2✔
138
      | _ -> eval_error (`Unsupported_operator (`Unop op, Ty_int))
×
139
    in
140
    to_int (f (of_int 1 (`Unop op) v))
5✔
141

142
  let exp_by_squaring x n =
143
    let rec exp_by_squaring2 y x n =
2✔
144
      if n < 0 then exp_by_squaring2 y (1 / x) ~-n
×
145
      else if n = 0 then y
2✔
146
      else if n mod 2 = 0 then exp_by_squaring2 y (x * x) (n / 2)
1✔
147
      else begin
3✔
148
        assert (n mod 2 = 1);
3✔
149
        exp_by_squaring2 (x * y) (x * x) ((n - 1) / 2)
150
      end
151
    in
152
    exp_by_squaring2 1 x n
153

154
  let binop (op : Ty.Binop.t) (v1 : Value.t) (v2 : Value.t) : Value.t =
155
    let f =
31✔
156
      match op with
157
      | Add -> Int.add
4✔
158
      | Sub -> Int.sub
2✔
159
      | Mul -> Int.mul
2✔
160
      | Div -> Int.div
3✔
161
      | Rem -> Int.rem
2✔
162
      | Pow -> exp_by_squaring
2✔
163
      | Min -> Int.min
2✔
164
      | Max -> Int.max
2✔
165
      | And -> Int.logand
2✔
166
      | Or -> Int.logor
2✔
167
      | Xor -> Int.logxor
2✔
168
      | Shl -> Int.shift_left
2✔
169
      | ShrL -> Int.shift_right_logical
1✔
170
      | ShrA -> Int.shift_right
3✔
171
      | _ -> eval_error (`Unsupported_operator (`Binop op, Ty_int))
×
172
    in
173
    to_int (f (of_int 1 (`Binop op) v1) (of_int 2 (`Binop op) v2))
30✔
174

175
  let relop (op : Ty.Relop.t) (v1 : Value.t) (v2 : Value.t) : bool =
176
    let f =
8✔
177
      match op with
178
      | Lt -> ( < )
2✔
179
      | Le -> ( <= )
2✔
180
      | Gt -> ( > )
2✔
181
      | Ge -> ( >= )
2✔
UNCOV
182
      | Eq -> Int.equal
×
183
      | Ne -> fun a b -> not (Int.equal a b)
×
184
      | _ -> eval_error (`Unsupported_operator (`Relop op, Ty_int))
×
185
    in
186
    f (of_int 1 (`Relop op) v1) (of_int 2 (`Relop op) v2)
8✔
187

188
  let of_bool : Value.t -> int = function
189
    | True -> 1
2✔
190
    | False -> 0
1✔
191
    | _ -> assert false
192
  [@@inline]
193

194
  let cvtop (op : Ty.Cvtop.t) (v : Value.t) : Value.t =
195
    match op with
5✔
196
    | OfBool -> to_int (of_bool v)
3✔
197
    | Reinterpret_float -> Int (Int.of_float (of_real 1 (`Cvtop op) v))
2✔
198
    | _ -> eval_error (`Unsupported_operator (`Cvtop op, Ty_int))
×
199
end
200

201
module Real = struct
202
  let unop (op : Ty.Unop.t) (v : Value.t) : Value.t =
203
    let v = of_real 1 (`Unop op) v in
19✔
204
    match op with
18✔
205
    | Neg -> to_real @@ Float.neg v
2✔
206
    | Abs -> to_real @@ Float.abs v
2✔
207
    | Sqrt -> to_real @@ Float.sqrt v
2✔
208
    | Nearest -> to_real @@ Float.round v
3✔
209
    | Ceil -> to_real @@ Float.ceil v
2✔
210
    | Floor -> to_real @@ Float.floor v
2✔
211
    | Trunc -> to_real @@ Float.trunc v
2✔
212
    | Is_nan -> if Float.is_nan v then Value.True else Value.False
1✔
213
    | _ -> eval_error (`Unsupported_operator (`Unop op, Ty_real))
×
214

215
  let binop (op : Ty.Binop.t) (v1 : Value.t) (v2 : Value.t) : Value.t =
216
    let f =
16✔
217
      match op with
218
      | Add -> Float.add
2✔
219
      | Sub -> Float.sub
2✔
220
      | Mul -> Float.mul
2✔
221
      | Div -> Float.div
3✔
222
      | Rem -> Float.rem
2✔
223
      | Min -> Float.min
2✔
224
      | Max -> Float.max
2✔
225
      | Pow -> Float.pow
1✔
226
      | _ -> eval_error (`Unsupported_operator (`Binop op, Ty_real))
×
227
    in
228
    to_real (f (of_real 1 (`Binop op) v1) (of_real 2 (`Binop op) v2))
16✔
229

230
  let relop (op : Ty.Relop.t) (v1 : Value.t) (v2 : Value.t) : bool =
231
    let f =
12✔
232
      match op with
233
      | Lt -> Float.Infix.( < )
2✔
234
      | Le -> Float.Infix.( <= )
2✔
235
      | Gt -> Float.Infix.( > )
2✔
236
      | Ge -> Float.Infix.( >= )
2✔
237
      | Eq -> Float.Infix.( = )
2✔
238
      | Ne -> Float.Infix.( <> )
2✔
239
      | _ -> eval_error (`Unsupported_operator (`Relop op, Ty_real))
×
240
    in
241
    f (of_real 1 (`Relop op) v1) (of_real 2 (`Relop op) v2)
12✔
242

243
  let cvtop (op : Ty.Cvtop.t) (v : Value.t) : Value.t =
244
    let op' = `Cvtop op in
8✔
245
    match op with
246
    | ToString -> Str (Float.to_string (of_real 1 op' v))
2✔
247
    | OfString -> begin
3✔
248
      match float_of_string_opt (of_str 1 op' v) with
3✔
249
      | None -> eval_error `Invalid_format_conversion
1✔
250
      | Some v -> to_real v
2✔
251
    end
252
    | Reinterpret_int -> to_real (float_of_int (of_int 1 op' v))
2✔
253
    | Reinterpret_float -> to_int (Float.to_int (of_real 1 op' v))
1✔
254
    | _ -> eval_error (`Unsupported_operator (op', Ty_real))
×
255
end
256

257
module Bool = struct
258
  let unop (op : Ty.Unop.t) v =
259
    let b = of_bool 1 (`Unop op) v in
3✔
260
    match op with
2✔
261
    | Not -> to_bool (not b)
2✔
262
    | _ -> eval_error (`Unsupported_operator (`Unop op, Ty_bool))
×
263

264
  let xor b1 b2 =
265
    match (b1, b2) with
4✔
266
    | true, true -> false
1✔
267
    | true, false -> true
1✔
268
    | false, true -> true
1✔
269
    | false, false -> false
1✔
270

271
  let binop (op : Ty.Binop.t) v1 v2 =
272
    let f =
13✔
273
      match op with
274
      | And -> ( && )
5✔
275
      | Or -> ( || )
4✔
276
      | Xor -> xor
4✔
277
      | _ -> eval_error (`Unsupported_operator (`Binop op, Ty_bool))
×
278
    in
279
    to_bool (f (of_bool 1 (`Binop op) v1) (of_bool 2 (`Binop op) v2))
13✔
280

281
  let triop (op : Ty.Triop.t) c v1 v2 =
282
    match op with
2✔
283
    | Ite -> ( match of_bool 1 (`Triop op) c with true -> v1 | false -> v2 )
1✔
284
    | _ -> eval_error (`Unsupported_operator (`Triop op, Ty_bool))
×
285

286
  let relop (op : Ty.Relop.t) v1 v2 =
287
    match op with
9✔
288
    | Eq -> Value.equal v1 v2
4✔
289
    | Ne -> not (Value.equal v1 v2)
5✔
290
    | _ -> eval_error (`Unsupported_operator (`Relop op, Ty_bool))
×
291

292
  let naryop (op : Ty.Naryop.t) vs =
293
    let b =
6✔
294
      match op with
295
      | Logand ->
3✔
296
        List.fold_left ( && ) true
3✔
297
          (List.mapi (fun i -> of_bool i (`Naryop op)) vs)
3✔
298
      | Logor ->
3✔
299
        List.fold_left ( || ) false
3✔
300
          (List.mapi (fun i -> of_bool i (`Naryop op)) vs)
3✔
301
      | _ -> eval_error (`Unsupported_operator (`Naryop op, Ty_bool))
×
302
    in
303
    to_bool b
304
end
305

306
module Str = struct
307
  let replace s t t' =
308
    let len_s = String.length s in
2✔
309
    let len_t = String.length t in
2✔
310
    let rec loop i =
2✔
311
      if i >= len_s then s
×
312
      else if i + len_t > len_s then s
×
313
      else if String.equal (String.sub s i len_t) t then
4✔
314
        let s' = Fmt.str "%s%s" (String.sub s 0 i) t' in
2✔
315
        let s'' = String.sub s (i + len_t) (len_s - i - len_t) in
2✔
316
        Fmt.str "%s%s" s' s''
2✔
317
      else loop (i + 1)
2✔
318
    in
319
    loop 0
320

321
  let indexof s sub start =
322
    let len_s = String.length s in
4✔
323
    let len_sub = String.length sub in
4✔
324
    let max_i = len_s - 1 in
4✔
325
    let rec loop i =
326
      if i > max_i then ~-1
×
327
      else if i + len_sub > len_s then ~-1
×
328
      else if String.equal sub (String.sub s i len_sub) then i
4✔
329
      else loop (i + 1)
4✔
330
    in
331
    if start <= 0 then loop 0 else loop start
×
332

333
  let contains s sub = if indexof s sub 0 < 0 then false else true
×
334

335
  let unop (op : Ty.Unop.t) v =
336
    let str = of_str 1 (`Unop op) v in
5✔
337
    match op with
4✔
338
    | Length -> to_int (String.length str)
2✔
339
    | Trim -> to_str (String.trim str)
2✔
340
    | _ -> eval_error (`Unsupported_operator (`Unop op, Ty_str))
×
341

342
  let binop (op : Ty.Binop.t) v1 v2 =
343
    let op' = `Binop op in
9✔
344
    let str = of_str 1 op' v1 in
345
    match op with
9✔
346
    | At -> begin
3✔
347
      let i = of_int 2 op' v2 in
348
      try to_str (Fmt.str "%c" (String.get str i))
2✔
349
      with Invalid_argument _ -> eval_error `Index_out_of_bounds
1✔
350
    end
351
    | String_prefix ->
2✔
352
      to_bool (String.starts_with ~prefix:str (of_str 2 op' v2))
2✔
353
    | String_suffix -> to_bool (String.ends_with ~suffix:str (of_str 2 op' v2))
2✔
354
    | String_contains -> to_bool (contains str (of_str 2 op' v2))
2✔
355
    | _ -> eval_error (`Unsupported_operator (op', Ty_str))
×
356

357
  let triop (op : Ty.Triop.t) v1 v2 v3 =
358
    let op' = `Triop op in
6✔
359
    let str = of_str 1 op' v1 in
360
    match op with
6✔
361
    | String_extract -> begin
2✔
362
      let i = of_int 2 op' v2 in
363
      let len = of_int 3 op' v3 in
2✔
364
      try to_str (String.sub str i len)
2✔
365
      with Invalid_argument _ -> eval_error `Index_out_of_bounds
×
366
    end
367
    | String_replace ->
2✔
368
      let t = of_str 2 op' v2 in
369
      let t' = of_str 2 op' v3 in
2✔
370
      to_str (replace str t t')
2✔
371
    | String_index ->
2✔
372
      let t = of_str 2 op' v2 in
373
      let i = of_int 3 op' v3 in
2✔
374
      to_int (indexof str t i)
2✔
375
    | _ -> eval_error (`Unsupported_operator (`Triop op, Ty_str))
×
376

377
  let relop (op : Ty.Relop.t) v1 v2 =
378
    let f =
14✔
379
      match op with
380
      | Lt -> ( < )
2✔
381
      | Le -> ( <= )
2✔
382
      | Gt -> ( > )
2✔
383
      | Ge -> ( >= )
2✔
384
      | Eq -> ( = )
3✔
385
      | Ne -> ( <> )
3✔
386
      | _ -> eval_error (`Unsupported_operator (`Relop op, Ty_str))
×
387
    in
388
    let f x y = f (String.compare x y) 0 in
14✔
389
    f (of_str 1 (`Relop op) v1) (of_str 2 (`Relop op) v2)
14✔
390

391
  let cvtop (op : Ty.Cvtop.t) v =
392
    let op' = `Cvtop op in
12✔
393
    match op with
394
    | String_to_code ->
2✔
395
      let str = of_str 1 op' v in
396
      to_int (Char.code str.[0])
2✔
397
    | String_from_code ->
2✔
398
      let code = of_int 1 op' v in
399
      to_str (String.make 1 (Char.chr code))
2✔
400
    | String_to_int -> begin
3✔
401
      let s = of_str 1 op' v in
402
      match int_of_string_opt s with
3✔
403
      | None -> eval_error `Invalid_format_conversion
1✔
404
      | Some x -> to_int x
2✔
405
    end
406
    | String_from_int -> to_str (string_of_int (of_int 1 op' v))
2✔
407
    | String_to_float -> begin
3✔
408
      let s = of_str 1 op' v in
409
      match float_of_string_opt s with
3✔
410
      | None -> eval_error `Invalid_format_conversion
1✔
411
      | Some f -> to_real f
2✔
412
    end
413
    | _ -> eval_error (`Unsupported_operator (`Cvtop op, Ty_str))
×
414

415
  let naryop (op : Ty.Naryop.t) vs =
416
    let op' = `Naryop op in
4✔
417
    match op with
418
    | Concat -> to_str (String.concat "" (List.map (of_str 0 op') vs))
4✔
419
    | _ -> eval_error (`Unsupported_operator (`Naryop op, Ty_str))
×
420
end
421

422
module Lst = struct
423
  let unop (op : Ty.Unop.t) (v : Value.t) : Value.t =
424
    let lst = of_list 1 (`Unop op) v in
4✔
425
    match op with
4✔
426
    | Head -> begin
1✔
427
      (* FIXME: Exception handling *)
428
      match lst with
429
      | hd :: _tl -> hd
1✔
430
      | [] -> assert false
431
    end
432
    | Tail -> begin
1✔
433
      (* FIXME: Exception handling *)
434
      match lst with
435
      | _hd :: tl -> List tl
1✔
436
      | [] -> assert false
437
    end
438
    | Length -> to_int (List.length lst)
1✔
439
    | Reverse -> List (List.rev lst)
1✔
440
    | _ -> eval_error (`Unsupported_operator (`Unop op, Ty_list))
×
441

442
  let binop (op : Ty.Binop.t) v1 v2 =
443
    let op' = `Binop op in
3✔
444
    match op with
445
    | At ->
1✔
446
      let lst = of_list 1 op' v1 in
447
      let i = of_int 2 op' v2 in
1✔
448
      (* TODO: change datastructure? *)
449
      begin match List.nth_opt lst i with
1✔
450
      | None -> eval_error `Index_out_of_bounds
×
451
      | Some v -> v
1✔
452
      end
453
    | List_cons -> List (v1 :: of_list 1 op' v2)
1✔
454
    | List_append -> List (of_list 1 op' v1 @ of_list 2 op' v2)
1✔
455
    | _ -> eval_error (`Unsupported_operator (`Binop op, Ty_list))
×
456

457
  let triop (op : Ty.Triop.t) (v1 : Value.t) (v2 : Value.t) (v3 : Value.t) :
458
    Value.t =
459
    let op' = `Triop op in
1✔
460
    match op with
461
    | List_set ->
1✔
462
      let lst = of_list 1 op' v1 in
463
      let i = of_int 2 op' v2 in
1✔
464
      let rec set i lst v acc =
1✔
465
        match (i, lst) with
2✔
466
        | 0, _ :: tl -> List.rev_append acc (v :: tl)
1✔
467
        | i, hd :: tl -> set (i - 1) tl v (hd :: acc)
1✔
468
        | _, [] -> eval_error `Index_out_of_bounds
×
469
      in
470
      List (set i lst v3 [])
1✔
471
    | _ -> eval_error (`Unsupported_operator (`Triop op, Ty_list))
×
472

473
  let naryop (op : Ty.Naryop.t) (vs : Value.t list) : Value.t =
474
    let op' = `Naryop op in
×
475
    match op with
476
    | Concat -> List (List.concat_map (of_list 0 op') vs)
×
477
    | _ -> eval_error (`Unsupported_operator (`Naryop op, Ty_list))
×
478
end
479

480
module I64 = struct
481
  let cmp_u x op y = op Int64.(add x min_int) Int64.(add y min_int) [@@inline]
2✔
482

483
  let lt_u x y = cmp_u x Int64.Infix.( < ) y [@@inline]
2✔
484
end
485

486
module Bitv = struct
487
  let unop op bv =
488
    let bv = of_bitv 1 (`Unop op) bv in
4✔
489
    to_bitv
4✔
490
    @@
491
    match op with
492
    | Ty.Unop.Neg -> Bitvector.neg bv
2✔
493
    | Not -> Bitvector.lognot bv
2✔
494
    | Clz -> Bitvector.clz bv
×
495
    | Ctz -> Bitvector.ctz bv
×
496
    | Popcnt -> Bitvector.popcnt bv
×
497
    | _ ->
×
498
      eval_error
×
499
        (`Unsupported_operator (`Unop op, Ty_bitv (Bitvector.numbits bv)))
×
500

501
  let binop op bv1 bv2 =
502
    let bv1 = of_bitv 1 (`Binop op) bv1 in
38✔
503
    let bv2 = of_bitv 2 (`Binop op) bv2 in
38✔
504
    to_bitv
38✔
505
    @@
506
    match op with
507
    | Ty.Binop.Add -> Bitvector.add bv1 bv2
11✔
508
    | Sub -> Bitvector.sub bv1 bv2
4✔
509
    | Mul -> Bitvector.mul bv1 bv2
4✔
510
    | Div -> Bitvector.div bv1 bv2
2✔
511
    | DivU -> Bitvector.div_u bv1 bv2
×
512
    | Rem -> Bitvector.rem bv1 bv2
3✔
513
    | RemU -> Bitvector.rem_u bv1 bv2
×
514
    | And -> Bitvector.logand bv1 bv2
2✔
515
    | Or -> Bitvector.logor bv1 bv2
2✔
516
    | Xor -> Bitvector.logxor bv1 bv2
2✔
517
    | Shl -> Bitvector.shl bv1 bv2
2✔
518
    | ShrL -> Bitvector.lshr bv1 bv2
×
519
    | ShrA -> Bitvector.ashr bv1 bv2
2✔
520
    | Rotl -> Bitvector.rotate_left bv1 bv2
2✔
521
    | Rotr -> Bitvector.rotate_right bv1 bv2
2✔
522
    | _ -> eval_error (`Unsupported_operator (`Binop op, Ty_bitv 0))
×
523

524
  let relop op bv1 bv2 =
525
    let bv1 = of_bitv 1 (`Relop op) bv1 in
23✔
526
    let bv2 = of_bitv 2 (`Relop op) bv2 in
23✔
527
    match op with
23✔
528
    | Ty.Relop.Lt -> Bitvector.lt bv1 bv2
3✔
529
    | LtU -> Bitvector.lt_u bv1 bv2
3✔
530
    | Le -> Bitvector.le bv1 bv2
3✔
531
    | LeU -> Bitvector.le_u bv1 bv2
3✔
532
    | Gt -> Bitvector.gt bv1 bv2
3✔
533
    | GtU -> Bitvector.gt_u bv1 bv2
2✔
534
    | Ge -> Bitvector.ge bv1 bv2
3✔
535
    | GeU -> Bitvector.ge_u bv1 bv2
2✔
536
    | Eq -> Bitvector.equal bv1 bv2
1✔
537
    | Ne -> not @@ Bitvector.equal bv1 bv2
×
538
end
539

540
module F32 = struct
541
  (* Stolen from Owi *)
542
  let abs x = Int32.logand x Int32.max_int
6✔
543

544
  let neg x = Int32.logxor x Int32.min_int
2✔
545

546
  let unop (op : Ty.Unop.t) (v : Value.t) : Value.t =
547
    let f = Int32.float_of_bits (of_fp32 1 (`Unop op) v) in
12✔
548
    match op with
12✔
549
    | Neg -> to_fp32 @@ neg @@ of_fp32 1 (`Unop op) v
2✔
550
    | Abs -> to_fp32 @@ abs @@ of_fp32 1 (`Unop op) v
1✔
551
    | Sqrt -> fp32_of_float @@ Float.sqrt f
1✔
552
    | Nearest -> fp32_of_float @@ Float.round f
2✔
553
    | Ceil -> fp32_of_float @@ Float.ceil f
1✔
554
    | Floor -> fp32_of_float @@ Float.floor f
1✔
555
    | Trunc -> fp32_of_float @@ Float.trunc f
2✔
556
    | Is_nan -> if Float.is_nan f then Value.True else Value.False
1✔
557
    | _ -> eval_error (`Unsupported_operator (`Unop op, Ty_fp 32))
×
558

559
  (* Stolen from Owi *)
560
  let copy_sign x y = Int32.logor (abs x) (Int32.logand y Int32.min_int)
5✔
561

562
  let binop (op : Ty.Binop.t) (v1 : Value.t) (v2 : Value.t) : Value.t =
563
    let a = Int32.float_of_bits @@ of_fp32 1 (`Binop op) v1 in
13✔
564
    let b = Int32.float_of_bits @@ of_fp32 1 (`Binop op) v2 in
13✔
565
    match op with
13✔
566
    | Add -> fp32_of_float @@ Float.add a b
1✔
567
    | Sub -> fp32_of_float @@ Float.sub a b
1✔
568
    | Mul -> fp32_of_float @@ Float.mul a b
1✔
569
    | Div -> fp32_of_float @@ Float.div a b
2✔
570
    | Rem -> fp32_of_float @@ Float.rem a b
1✔
571
    | Min -> fp32_of_float @@ Float.min a b
1✔
572
    | Max -> fp32_of_float @@ Float.max a b
1✔
573
    | Copysign ->
5✔
574
      let a = of_fp32 1 (`Binop op) v1 in
575
      let b = of_fp32 1 (`Binop op) v2 in
5✔
576
      to_fp32 (copy_sign a b)
5✔
577
    | _ -> eval_error (`Unsupported_operator (`Binop op, Ty_fp 32))
×
578

579
  let relop (op : Ty.Relop.t) (v1 : Value.t) (v2 : Value.t) : bool =
580
    let f =
13✔
581
      match op with
582
      | Eq -> Float.Infix.( = )
3✔
583
      | Ne -> Float.Infix.( <> )
2✔
584
      | Lt -> Float.Infix.( < )
2✔
585
      | Le -> Float.Infix.( <= )
2✔
586
      | Gt -> Float.Infix.( > )
2✔
587
      | Ge -> Float.Infix.( >= )
2✔
588
      | _ -> eval_error (`Unsupported_operator (`Relop op, Ty_fp 32))
×
589
    in
590
    let a = Int32.float_of_bits @@ of_fp32 1 (`Relop op) v1 in
13✔
591
    let b = Int32.float_of_bits @@ of_fp32 2 (`Relop op) v2 in
13✔
592
    f a b
13✔
593
end
594

595
module F64 = struct
596
  (* Stolen from owi *)
597
  let abs x = Int64.logand x Int64.max_int
6✔
598

599
  let neg x = Int64.logxor x Int64.min_int
1✔
600

601
  let unop (op : Ty.Unop.t) (v : Value.t) : Value.t =
602
    let f = Int64.float_of_bits @@ of_fp64 1 (`Unop op) v in
11✔
603
    match op with
11✔
604
    | Neg -> to_fp64 @@ neg @@ of_fp64 1 (`Unop op) v
1✔
605
    | Abs -> to_fp64 @@ abs @@ of_fp64 1 (`Unop op) v
1✔
606
    | Sqrt -> fp64_of_float @@ Float.sqrt f
1✔
607
    | Nearest -> fp64_of_float @@ Float.round f
2✔
608
    | Ceil -> fp64_of_float @@ Float.ceil f
1✔
609
    | Floor -> fp64_of_float @@ Float.floor f
1✔
610
    | Trunc -> fp64_of_float @@ Float.trunc f
2✔
611
    | Is_nan -> if Float.is_nan f then Value.True else Value.False
1✔
612
    | _ -> Fmt.failwith {|unop: Unsupported f32 operator "%a"|} Ty.Unop.pp op
×
613

614
  let copy_sign x y = Int64.logor (abs x) (Int64.logand y Int64.min_int)
5✔
615

616
  let binop (op : Ty.Binop.t) (v1 : Value.t) (v2 : Value.t) : Value.t =
617
    let a = Int64.float_of_bits @@ of_fp64 1 (`Binop op) v1 in
13✔
618
    let b = Int64.float_of_bits @@ of_fp64 2 (`Binop op) v2 in
13✔
619
    match op with
13✔
620
    | Add -> fp64_of_float @@ Float.add a b
1✔
621
    | Sub -> fp64_of_float @@ Float.sub a b
1✔
622
    | Mul -> fp64_of_float @@ Float.mul a b
1✔
623
    | Div -> fp64_of_float @@ Float.div a b
2✔
624
    | Rem -> fp64_of_float @@ Float.rem a b
1✔
625
    | Min -> fp64_of_float @@ Float.min a b
1✔
626
    | Max -> fp64_of_float @@ Float.max a b
1✔
627
    | Copysign ->
5✔
628
      let a = of_fp64 1 (`Binop op) v1 in
629
      let b = of_fp64 2 (`Binop op) v2 in
5✔
630
      to_fp64 @@ copy_sign a b
5✔
631
    | _ -> eval_error (`Unsupported_operator (`Binop op, Ty_fp 64))
×
632

633
  let relop (op : Ty.Relop.t) (v1 : Value.t) (v2 : Value.t) : bool =
634
    let f =
12✔
635
      match op with
636
      | Eq -> Float.Infix.( = )
2✔
637
      | Ne -> Float.Infix.( <> )
2✔
638
      | Lt -> Float.Infix.( < )
2✔
639
      | Le -> Float.Infix.( <= )
2✔
640
      | Gt -> Float.Infix.( > )
2✔
641
      | Ge -> Float.Infix.( >= )
2✔
642
      | _ -> eval_error (`Unsupported_operator (`Relop op, Ty_fp 64))
×
643
    in
644
    let a = Int64.float_of_bits @@ of_fp64 1 (`Relop op) v1 in
12✔
645
    let b = Int64.float_of_bits @@ of_fp64 2 (`Relop op) v2 in
12✔
646
    f a b
12✔
647
end
648

649
module I32CvtOp = struct
650
  let trunc_f32_s (x : int32) =
651
    if Int32.Infix.(x <> x) then eval_error `Conversion_to_integer
×
652
    else
653
      let xf = Int32.float_of_bits x in
2✔
654
      if
2✔
655
        Float.Infix.(
656
          xf >= -.Int32.(to_float min_int) || xf < Int32.(to_float min_int) )
×
657
      then eval_error `Integer_overflow
×
658
      else Int32.of_float xf
2✔
659

660
  let trunc_f32_u (x : int32) =
661
    if Int32.Infix.(x <> x) then eval_error `Conversion_to_integer
×
662
    else
663
      let xf = Int32.float_of_bits x in
1✔
664
      if Float.Infix.(xf >= -.Int32.(to_float min_int) *. 2.0 || xf <= -1.0)
×
665
      then eval_error `Integer_overflow
×
666
      else Int32.of_float xf
1✔
667

668
  let trunc_f64_s (x : int64) =
669
    if Int64.Infix.(x <> x) then eval_error `Conversion_to_integer
×
670
    else
671
      let xf = Int64.float_of_bits x in
2✔
672
      if
2✔
673
        Float.Infix.(
674
          xf >= -.Int64.(to_float min_int) || xf < Int64.(to_float min_int) )
×
675
      then eval_error `Integer_overflow
×
676
      else Int32.of_float xf
2✔
677

678
  let trunc_f64_u (x : int64) =
679
    if Int64.Infix.(x <> x) then eval_error `Conversion_to_integer
×
680
    else
681
      let xf = Int64.float_of_bits x in
1✔
682
      if Float.Infix.(xf >= -.Int64.(to_float min_int) *. 2.0 || xf <= -1.0)
×
683
      then eval_error `Integer_overflow
×
684
      else Int32.of_float xf
1✔
685

686
  let trunc_sat_f32_s x =
687
    if Int32.Infix.(x <> x) then 0l
×
688
    else
689
      let xf = Int32.float_of_bits x in
1✔
690
      if Float.Infix.(xf < Int32.(to_float min_int)) then Int32.min_int
×
691
      else if Float.Infix.(xf >= -.Int32.(to_float min_int)) then Int32.max_int
×
692
      else Int32.of_float xf
1✔
693

694
  let trunc_sat_f32_u x =
695
    if Int32.Infix.(x <> x) then 0l
×
696
    else
697
      let xf = Int32.float_of_bits x in
1✔
698
      if Float.Infix.(xf <= -1.0) then 0l
×
699
      else if Float.Infix.(xf >= -.Int32.(to_float min_int) *. 2.0) then -1l
×
700
      else Int32.of_float xf
1✔
701

702
  let trunc_sat_f64_s x =
703
    if Int64.Infix.(x <> x) then 0l
×
704
    else
705
      let xf = Int64.float_of_bits x in
1✔
706
      if Float.Infix.(xf < Int64.(to_float min_int)) then Int32.min_int
×
707
      else if Float.Infix.(xf >= -.Int64.(to_float min_int)) then Int32.max_int
×
708
      else Int32.of_float xf
1✔
709

710
  let trunc_sat_f64_u x =
711
    if Int64.Infix.(x <> x) then 0l
×
712
    else
713
      let xf = Int64.float_of_bits x in
1✔
714
      if Float.Infix.(xf <= -1.0) then 0l
×
715
      else if Float.Infix.(xf >= -.Int64.(to_float min_int) *. 2.0) then -1l
×
716
      else Int32.of_float xf
1✔
717

718
  let cvtop op v =
719
    let op' = `Cvtop op in
17✔
720
    match op with
721
    | Ty.Cvtop.WrapI64 -> bitv_of_int32 (Int64.to_int32 (int64_of_bitv 1 op' v))
2✔
722
    | TruncSF32 -> bitv_of_int32 (trunc_f32_s (of_fp32 1 op' v))
2✔
723
    | TruncUF32 -> bitv_of_int32 (trunc_f32_u (of_fp32 1 op' v))
1✔
724
    | TruncSF64 -> bitv_of_int32 (trunc_f64_s (of_fp64 1 op' v))
2✔
725
    | TruncUF64 -> bitv_of_int32 (trunc_f64_u (of_fp64 1 op' v))
1✔
726
    | Trunc_sat_f32_s -> bitv_of_int32 (trunc_sat_f32_s (of_fp32 1 op' v))
1✔
727
    | Trunc_sat_f32_u -> bitv_of_int32 (trunc_sat_f32_u (of_fp32 1 op' v))
1✔
728
    | Trunc_sat_f64_s -> bitv_of_int32 (trunc_sat_f64_s (of_fp64 1 op' v))
1✔
729
    | Trunc_sat_f64_u -> bitv_of_int32 (trunc_sat_f64_u (of_fp64 1 op' v))
1✔
730
    | Reinterpret_float -> bitv_of_int32 (of_fp32 1 op' v)
2✔
731
    | Sign_extend n -> to_bitv (Bitvector.sign_extend n (of_bitv 1 op' v))
2✔
732
    | Zero_extend n -> to_bitv (Bitvector.zero_extend n (of_bitv 1 op' v))
1✔
733
    | OfBool -> v (* v is already a number here *)
×
734
    | ToBool | _ -> eval_error (`Unsupported_operator (op', Ty_bitv 32))
×
735
end
736

737
module I64CvtOp = struct
738
  let extend_i32_u (x : int32) =
739
    Int64.(logand (of_int32 x) 0x0000_0000_ffff_ffffL)
1✔
740

741
  let trunc_f32_s (x : int32) =
742
    if Int32.Infix.(x <> x) then eval_error `Conversion_to_integer
×
743
    else
744
      let xf = Int32.float_of_bits x in
2✔
745
      if
2✔
746
        Float.Infix.(
747
          xf >= -.Int64.(to_float min_int) || xf < Int64.(to_float min_int) )
×
748
      then eval_error `Integer_overflow
×
749
      else Int64.of_float xf
2✔
750

751
  let trunc_f32_u (x : int32) =
752
    if Int32.Infix.(x <> x) then eval_error `Conversion_to_integer
×
753
    else
754
      let xf = Int32.float_of_bits x in
1✔
755
      if Float.Infix.(xf >= -.Int64.(to_float min_int) *. 2.0 || xf <= -1.0)
×
756
      then eval_error `Integer_overflow
×
757
      else if Float.Infix.(xf >= -.Int64.(to_float min_int)) then
1✔
758
        Int64.(logxor (of_float (xf -. 0x1p63)) min_int)
×
759
      else Int64.of_float xf
1✔
760

761
  let trunc_f64_s (x : int64) =
762
    if Int64.Infix.(x <> x) then eval_error `Conversion_to_integer
×
763
    else
764
      let xf = Int64.float_of_bits x in
2✔
765
      if
2✔
766
        Float.Infix.(
767
          xf >= -.Int64.(to_float min_int) || xf < Int64.(to_float min_int) )
×
768
      then eval_error `Integer_overflow
×
769
      else Int64.of_float xf
2✔
770

771
  let trunc_f64_u (x : int64) =
772
    if Int64.Infix.(x <> x) then eval_error `Conversion_to_integer
×
773
    else
774
      let xf = Int64.float_of_bits x in
1✔
775
      if Float.Infix.(xf >= -.Int64.(to_float min_int) *. 2.0 || xf <= -1.0)
×
776
      then eval_error `Integer_overflow
×
777
      else if Float.Infix.(xf >= -.Int64.(to_float min_int)) then
1✔
778
        Int64.(logxor (of_float (xf -. 0x1p63)) min_int)
×
779
      else Int64.of_float xf
1✔
780

781
  let trunc_sat_f32_s (x : int32) =
782
    if Int32.Infix.(x <> x) then 0L
×
783
    else
784
      let xf = Int32.float_of_bits x in
1✔
785
      if Float.Infix.(xf < Int64.(to_float min_int)) then Int64.min_int
×
786
      else if Float.Infix.(xf >= -.Int64.(to_float min_int)) then Int64.max_int
×
787
      else Int64.of_float xf
1✔
788

789
  let trunc_sat_f32_u (x : int32) =
790
    if Int32.Infix.(x <> x) then 0L
×
791
    else
792
      let xf = Int32.float_of_bits x in
1✔
793
      if Float.Infix.(xf <= -1.0) then 0L
×
794
      else if Float.Infix.(xf >= -.Int64.(to_float min_int) *. 2.0) then -1L
×
795
      else if Float.Infix.(xf >= -.Int64.(to_float min_int)) then
1✔
796
        Int64.(logxor (of_float (xf -. 0x1p63)) min_int)
×
797
      else Int64.of_float xf
1✔
798

799
  let trunc_sat_f64_s (x : int64) =
800
    if Int64.Infix.(x <> x) then 0L
×
801
    else
802
      let xf = Int64.float_of_bits x in
1✔
803
      if Float.Infix.(xf < Int64.(to_float min_int)) then Int64.min_int
×
804
      else if Float.Infix.(xf >= -.Int64.(to_float min_int)) then Int64.max_int
×
805
      else Int64.of_float xf
1✔
806

807
  let trunc_sat_f64_u (x : int64) =
808
    if Int64.Infix.(x <> x) then 0L
×
809
    else
810
      let xf = Int64.float_of_bits x in
1✔
811
      if Float.Infix.(xf <= -1.0) then 0L
×
812
      else if Float.Infix.(xf >= -.Int64.(to_float min_int) *. 2.0) then -1L
×
813
      else if Float.Infix.(xf >= -.Int64.(to_float min_int)) then
1✔
814
        Int64.(logxor (of_float (xf -. 0x1p63)) min_int)
×
815
      else Int64.of_float xf
1✔
816

817
  let cvtop (op : Ty.Cvtop.t) (v : Value.t) : Value.t =
818
    let op' = `Cvtop op in
17✔
819
    match op with
820
    | Sign_extend n -> to_bitv (Bitvector.sign_extend n (of_bitv 1 op' v))
3✔
821
    | Zero_extend n -> to_bitv (Bitvector.zero_extend n (of_bitv 1 op' v))
2✔
822
    | TruncSF32 -> bitv_of_int64 (trunc_f32_s (of_fp32 1 op' v))
2✔
823
    | TruncUF32 -> bitv_of_int64 (trunc_f32_u (of_fp32 1 op' v))
1✔
824
    | TruncSF64 -> bitv_of_int64 (trunc_f64_s (of_fp64 1 op' v))
2✔
825
    | TruncUF64 -> bitv_of_int64 (trunc_f64_u (of_fp64 1 op' v))
1✔
826
    | Trunc_sat_f32_s -> bitv_of_int64 (trunc_sat_f32_s (of_fp32 1 op' v))
1✔
827
    | Trunc_sat_f32_u -> bitv_of_int64 (trunc_sat_f32_u (of_fp32 1 op' v))
1✔
828
    | Trunc_sat_f64_s -> bitv_of_int64 (trunc_sat_f64_s (of_fp64 1 op' v))
1✔
829
    | Trunc_sat_f64_u -> bitv_of_int64 (trunc_sat_f64_u (of_fp64 1 op' v))
1✔
830
    | Reinterpret_float -> bitv_of_int64 (of_fp64 1 op' v)
1✔
831
    | WrapI64 -> type_error 1 v (Ty_bitv 64) op' "Cannot wrapI64 on an I64"
1✔
832
    | ToBool | OfBool | _ -> eval_error (`Unsupported_operator (op', Ty_bitv 64))
×
833
end
834

835
module F32CvtOp = struct
836
  let demote_f64 x =
837
    let xf = Int64.float_of_bits x in
2✔
838
    if Float.Infix.(xf = xf) then Int32.bits_of_float xf
1✔
839
    else
840
      let nan64bits = x in
1✔
841
      let sign_field =
842
        Int64.(shift_left (shift_right_logical nan64bits 63) 31)
1✔
843
      in
844
      let significand_field =
845
        Int64.(shift_right_logical (shift_left nan64bits 12) 41)
1✔
846
      in
847
      let fields = Int64.logor sign_field significand_field in
848
      Int32.logor 0x7fc0_0000l (Int64.to_int32 fields)
1✔
849

850
  let convert_i32_s x = Int32.bits_of_float (Int32.to_float x)
2✔
851

852
  let convert_i32_u x =
853
    Int32.bits_of_float
2✔
854
      Int32.(
855
        Int32.Infix.(
856
          if x >= 0l then to_float x
1✔
857
          else to_float (logor (shift_right_logical x 1) (logand x 1l)) *. 2.0 ) )
1✔
858

859
  let convert_i64_s x =
860
    Int32.bits_of_float
3✔
861
      Int64.(
862
        Int64.Infix.(
863
          if abs x < 0x10_0000_0000_0000L then to_float x
2✔
864
          else
865
            let r = if logand x 0xfffL = 0L then 0L else 1L in
×
866
            to_float (logor (shift_right x 12) r) *. 0x1p12 ) )
1✔
867

868
  let convert_i64_u x =
869
    Int32.bits_of_float
2✔
870
      Int64.(
871
        Int64.Infix.(
872
          if I64.lt_u x 0x10_0000_0000_0000L then to_float x
1✔
873
          else
874
            let r = if logand x 0xfffL = 0L then 0L else 1L in
×
875
            to_float (logor (shift_right_logical x 12) r) *. 0x1p12 ) )
1✔
876

877
  let cvtop (op : Ty.Cvtop.t) (v : Value.t) : Value.t =
878
    let op' = `Cvtop op in
13✔
879
    match op with
880
    | DemoteF64 -> to_fp32 (demote_f64 (of_fp64 1 op' v))
2✔
881
    | ConvertSI32 -> to_fp32 (convert_i32_s (int32_of_bitv 1 op' v))
2✔
882
    | ConvertUI32 -> to_fp32 (convert_i32_u (int32_of_bitv 1 op' v))
2✔
883
    | ConvertSI64 -> to_fp32 (convert_i64_s (int64_of_bitv 1 op' v))
3✔
884
    | ConvertUI64 -> to_fp32 (convert_i64_u (int64_of_bitv 1 op' v))
2✔
885
    | Reinterpret_int -> to_fp32 (int32_of_bitv 1 op' v)
1✔
886
    | PromoteF32 -> type_error 1 v (Ty_fp 32) op' "F64 must promote F32"
1✔
887
    | ToString | OfString | _ ->
×
888
      eval_error (`Unsupported_operator (op', Ty_fp 32))
889
end
890

891
module F64CvtOp = struct
892
  let promote_f32 x =
893
    let xf = Int32.float_of_bits x in
2✔
894
    if Float.Infix.(xf = xf) then Int64.bits_of_float xf
1✔
895
    else
896
      let nan32bits = I64CvtOp.extend_i32_u x in
1✔
897
      let sign_field =
1✔
898
        Int64.(shift_left (shift_right_logical nan32bits 31) 63)
1✔
899
      in
900
      let significand_field =
901
        Int64.(shift_right_logical (shift_left nan32bits 41) 12)
1✔
902
      in
903
      let fields = Int64.logor sign_field significand_field in
904
      Int64.logor 0x7ff8_0000_0000_0000L fields
1✔
905

906
  let convert_i32_s x = Int64.bits_of_float (Int32.to_float x)
2✔
907

908
  (*
909
   * Unlike the other convert_u functions, the high half of the i32 range is
910
   * within the range where f32 can represent odd numbers, so we can't do the
911
   * shift. Instead, we can use int64 signed arithmetic.
912
   *)
913
  let convert_i32_u x =
914
    Int64.bits_of_float
1✔
915
      Int64.(to_float (logand (of_int32 x) 0x0000_0000_ffff_ffffL))
1✔
916

917
  let convert_i64_s x = Int64.bits_of_float (Int64.to_float x)
2✔
918

919
  (*
920
   * Values in the low half of the int64 range can be converted with a signed
921
   * conversion. The high half is beyond the range where f64 can represent odd
922
   * numbers, so we can shift the value right, adjust the least significant
923
   * bit to round correctly, do a conversion, and then scale it back up.
924
   *)
925
  let convert_i64_u (x : int64) =
926
    Int64.bits_of_float
2✔
927
      Int64.(
928
        Int64.Infix.(
929
          if x >= 0L then to_float x
1✔
930
          else to_float (logor (shift_right_logical x 1) (logand x 1L)) *. 2.0 ) )
1✔
931

932
  let cvtop (op : Ty.Cvtop.t) v : Value.t =
933
    let op' = `Cvtop op in
11✔
934
    match op with
935
    | PromoteF32 -> to_fp64 (promote_f32 (of_fp32 1 op' v))
2✔
936
    | ConvertSI32 -> to_fp64 (convert_i32_s (int32_of_bitv 1 op' v))
2✔
937
    | ConvertUI32 -> to_fp64 (convert_i32_u (int32_of_bitv 1 op' v))
1✔
938
    | ConvertSI64 -> to_fp64 (convert_i64_s (int64_of_bitv 1 op' v))
2✔
939
    | ConvertUI64 -> to_fp64 (convert_i64_u (int64_of_bitv 1 op' v))
2✔
940
    | Reinterpret_int -> to_fp64 (int64_of_bitv 1 op' v)
1✔
941
    | DemoteF64 -> type_error 1 v (Ty_fp 64) op' "F32 must demote a F64"
1✔
942
    | ToString | OfString | _ ->
×
943
      eval_error (`Unsupported_operator (op', Ty_fp 64))
944
end
945

946
(* Dispatch *)
947

948
let op int real bool str lst bv f32 f64 ty op =
949
  match ty with
202✔
950
  | Ty.Ty_int -> int op
37✔
951
  | Ty_real -> real op
35✔
952
  | Ty_bool -> bool op
16✔
953
  | Ty_str -> str op
14✔
954
  | Ty_list -> lst op
7✔
955
  | Ty_bitv _ -> bv op
42✔
956
  | Ty_fp 32 -> f32 op
26✔
957
  | Ty_fp 64 -> f64 op
25✔
958
  | Ty_fp _ | Ty_app | Ty_unit | Ty_none | Ty_regexp | Ty_roundingMode ->
×
959
    eval_error (`Unsupported_theory ty)
960
[@@inline]
961

962
let unop =
963
  op Int.unop Real.unop Bool.unop Str.unop Lst.unop Bitv.unop F32.unop F64.unop
7✔
964

965
let binop =
966
  op Int.binop Real.binop Bool.binop Str.binop Lst.binop Bitv.binop F32.binop
7✔
967
    F64.binop
968

969
let triop = function
970
  | Ty.Ty_bool -> Bool.triop
2✔
971
  | Ty_str -> Str.triop
6✔
972
  | Ty_list -> Lst.triop
1✔
973
  | ty -> eval_error (`Unsupported_theory ty)
×
974

975
let relop = function
976
  | Ty.Ty_int -> Int.relop
8✔
977
  | Ty_real -> Real.relop
12✔
978
  | Ty_bool -> Bool.relop
9✔
979
  | Ty_str -> Str.relop
14✔
980
  | Ty_bitv _ -> Bitv.relop
23✔
981
  | Ty_fp 32 -> F32.relop
13✔
982
  | Ty_fp 64 -> F64.relop
12✔
983
  | ty -> eval_error (`Unsupported_theory ty)
×
984

985
let cvtop = function
986
  | Ty.Ty_int -> Int.cvtop
5✔
987
  | Ty_real -> Real.cvtop
8✔
988
  | Ty_str -> Str.cvtop
12✔
989
  | Ty_bitv 32 -> I32CvtOp.cvtop
17✔
990
  | Ty_bitv 64 -> I64CvtOp.cvtop
17✔
991
  | Ty_fp 32 -> F32CvtOp.cvtop
13✔
992
  | Ty_fp 64 -> F64CvtOp.cvtop
11✔
993
  | ty -> eval_error (`Unsupported_theory ty)
×
994

995
let naryop = function
996
  | Ty.Ty_bool -> Bool.naryop
6✔
997
  | Ty_str -> Str.naryop
4✔
998
  | Ty_list -> Lst.naryop
×
999
  | ty -> eval_error (`Unsupported_theory ty)
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc