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

formalsec / smtml / 274

05 Feb 2025 01:53PM UTC coverage: 47.698% (+0.2%) from 47.539%
274

push

github

filipeom
fix doc

1544 of 3237 relevant lines covered (47.7%)

32.65 hits per line

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

60.41
/src/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
(* TODO: This module should be concrete or a part of the reducer *)
11

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

21
exception Value of Ty.t
22

23
exception
24
  TypeError of
25
    { index : int
26
    ; value : Value.t
27
    ; ty : Ty.t
28
    ; op : op_type
29
    }
30

31
exception DivideByZero
32

33
exception ConversionToInteger
34

35
exception IntegerOverflow
36

37
exception IndexOutOfBounds
38

39
exception ParseNumError
40

41
let of_arg f n v op =
42
  try f v
324✔
43
  with Value t -> raise (TypeError { index = n; value = v; ty = t; op })
×
44
[@@inline]
45

46
module Int = struct
47
  let to_value (i : int) : Value.t = Int i [@@inline]
32✔
48

49
  let of_value (n : int) (op : op_type) (v : Value.t) : int =
50
    of_arg (function Int i -> i | _ -> raise_notrace (Value Ty_int)) n v op
×
51
  [@@inline]
52

53
  let unop (op : Ty.Unop.t) (v : Value.t) : Value.t =
54
    let f =
2✔
55
      match op with
56
      | Neg -> Int.neg
1✔
57
      | Not -> Int.lognot
×
58
      | Abs -> Int.abs
1✔
59
      | _ -> Fmt.failwith {|unop: Unsupported int operator "%a"|} Ty.Unop.pp op
×
60
    in
61
    to_value (f (of_value 1 (`Unop op) v))
2✔
62

63
  let exp_by_squaring x n =
64
    let rec exp_by_squaring2 y x n =
1✔
65
      if n < 0 then exp_by_squaring2 y (1 / x) ~-n
×
66
      else if n = 0 then y
1✔
67
      else if n mod 2 = 0 then exp_by_squaring2 y (x * x) (n / 2)
1✔
68
      else begin
1✔
69
        assert (n mod 2 = 1);
1✔
70
        exp_by_squaring2 (x * y) (x * y) ((n - 1) / 2)
71
      end
72
    in
73
    exp_by_squaring2 1 x n
74

75
  let binop (op : Ty.Binop.t) (v1 : Value.t) (v2 : Value.t) : Value.t =
76
    let f =
17✔
77
      match op with
78
      | Add -> Int.add
3✔
79
      | Sub -> Int.sub
1✔
80
      | Mul -> Int.mul
1✔
81
      | Div -> Int.div
1✔
82
      | Rem -> Int.rem
1✔
83
      | Pow -> exp_by_squaring
1✔
84
      | Min -> Int.min
1✔
85
      | Max -> Int.max
1✔
86
      | And -> Int.logand
1✔
87
      | Or -> Int.logor
1✔
88
      | Xor -> Int.logxor
1✔
89
      | Shl -> Int.shift_left
1✔
90
      | ShrL -> Int.shift_right_logical
1✔
91
      | ShrA -> Int.shift_right
2✔
92
      | _ ->
×
93
        Fmt.failwith {|binop: Unsupported int operator "%a"|} Ty.Binop.pp op
×
94
    in
95
    to_value (f (of_value 1 (`Binop op) v1) (of_value 2 (`Binop op) v2))
17✔
96

97
  let relop (op : Ty.Relop.t) (v1 : Value.t) (v2 : Value.t) : bool =
98
    let f =
4✔
99
      match op with
100
      | Lt -> ( < )
1✔
101
      | Le -> ( <= )
1✔
102
      | Gt -> ( > )
1✔
103
      | Ge -> ( >= )
1✔
104
      | Eq -> ( = )
×
105
      | Ne -> ( <> )
×
106
      | _ ->
×
107
        Fmt.failwith {|relop: Unsupported int operator "%a"|} Ty.Relop.pp op
×
108
    in
109
    f (of_value 1 (`Relop op) v1) (of_value 2 (`Relop op) v2)
4✔
110

111
  let of_bool : Value.t -> int = function
112
    | True -> 1
1✔
113
    | False -> 0
1✔
114
    | _ -> assert false
115
  [@@inline]
116

117
  let cvtop (op : Ty.Cvtop.t) (v : Value.t) : Value.t =
118
    match op with
4✔
119
    | OfBool -> to_value (of_bool v)
2✔
120
    | Reinterpret_float ->
1✔
121
      Int (Int.of_float (match v with Real v -> v | _ -> assert false))
1✔
122
    | ToString -> Str (string_of_int (of_value 1 (`Cvtop op) v))
1✔
123
    | _ -> Fmt.failwith {|cvtop: Unsupported int operator "%a"|} Ty.Cvtop.pp op
×
124
end
125

126
module Real = struct
127
  let to_value (v : float) : Value.t = Real v [@@inline]
17✔
128

129
  let of_value (n : int) (op : op_type) (v : Value.t) : float =
130
    of_arg (function Real v -> v | _ -> raise_notrace (Value Ty_int)) n v op
×
131
  [@@inline]
132

133
  let unop (op : Ty.Unop.t) (v : Value.t) : Value.t =
134
    let v = of_value 1 (`Unop op) v in
8✔
135
    match op with
8✔
136
    | Neg -> to_value @@ Float.neg v
1✔
137
    | Abs -> to_value @@ Float.abs v
1✔
138
    | Sqrt -> to_value @@ Float.sqrt v
1✔
139
    | Nearest -> to_value @@ Float.round v
1✔
140
    | Ceil -> to_value @@ Float.ceil v
1✔
141
    | Floor -> to_value @@ Float.floor v
1✔
142
    | Trunc -> to_value @@ Float.trunc v
1✔
143
    | Is_nan -> if Float.is_nan v then Value.True else Value.False
×
144
    | _ -> Fmt.failwith {|unop: Unsupported real operator "%a"|} Ty.Unop.pp op
×
145

146
  let binop (op : Ty.Binop.t) (v1 : Value.t) (v2 : Value.t) : Value.t =
147
    let f =
7✔
148
      match op with
149
      | Add -> Float.add
1✔
150
      | Sub -> Float.sub
1✔
151
      | Mul -> Float.mul
1✔
152
      | Div -> Float.div
1✔
153
      | Rem -> Float.rem
1✔
154
      | Min -> Float.min
1✔
155
      | Max -> Float.max
1✔
156
      | Pow -> Float.pow
×
157
      | _ ->
×
158
        Fmt.failwith {|binop: Unsupported real operator "%a"|} Ty.Binop.pp op
×
159
    in
160
    to_value (f (of_value 1 (`Binop op) v1) (of_value 2 (`Binop op) v2))
7✔
161

162
  let relop (op : Ty.Relop.t) (v1 : Value.t) (v2 : Value.t) : bool =
163
    let f =
5✔
164
      match op with
165
      | Lt -> Float.Infix.( < )
1✔
166
      | Le -> Float.Infix.( <= )
1✔
167
      | Gt -> Float.Infix.( > )
1✔
168
      | Ge -> Float.Infix.( >= )
1✔
169
      | Eq -> Float.Infix.( = )
1✔
170
      | Ne -> Float.Infix.( <> )
×
171
      | _ ->
×
172
        Fmt.failwith {|relop: Unsupported real operator "%a"|} Ty.Relop.pp op
×
173
    in
174
    f (of_value 1 (`Relop op) v1) (of_value 2 (`Relop op) v2)
5✔
175

176
  let cvtop (op : Ty.Cvtop.t) (v : Value.t) : Value.t =
177
    let op' = `Cvtop op in
3✔
178
    match op with
179
    | ToString -> Str (Float.to_string (of_value 1 op' v))
1✔
180
    | OfString ->
1✔
181
      let v = match v with Str v -> v | _ -> raise_notrace (Value Ty_str) in
×
182
      begin
183
        match Float.of_string_opt v with
184
        | None -> assert false
185
        | Some v -> to_value v
1✔
186
      end
187
    | Reinterpret_int ->
1✔
188
      let v = match v with Int v -> v | _ -> raise_notrace (Value Ty_int) in
×
189
      to_value (float_of_int v)
1✔
190
    | Reinterpret_float -> Int (Float.to_int (of_value 1 op' v))
×
191
    | _ -> Fmt.failwith {|cvtop: Unsupported real operator "%a"|} Ty.Cvtop.pp op
×
192
end
193

194
module Bool = struct
195
  let to_value (b : bool) : Value.t = if b then True else False [@@inline]
4✔
196

197
  let of_value (n : int) (op : op_type) (v : Value.t) : bool =
198
    of_arg
15✔
199
      (function
200
        | True -> true | False -> false | _ -> raise_notrace (Value Ty_bool) )
×
201
      n v op
202
  [@@inline]
203

204
  let unop (op : Ty.Unop.t) v =
205
    let b = of_value 1 (`Unop op) v in
1✔
206
    match op with
1✔
207
    | Not -> to_value (not b)
1✔
208
    | _ -> Fmt.failwith {|unop: Unsupported bool operator "%a"|} Ty.Unop.pp op
×
209

210
  let xor b1 b2 =
211
    match (b1, b2) with
×
212
    | true, true -> false
×
213
    | true, false -> true
×
214
    | false, true -> true
×
215
    | false, false -> false
×
216

217
  let binop (op : Ty.Binop.t) v1 v2 =
218
    let f =
×
219
      match op with
220
      | And -> ( && )
×
221
      | Or -> ( || )
×
222
      | Xor -> xor
×
223
      | _ ->
×
224
        Fmt.failwith {|binop: Unsupported bool operator "%a"|} Ty.Binop.pp op
×
225
    in
226
    to_value (f (of_value 1 (`Binop op) v1) (of_value 2 (`Binop op) v2))
×
227

228
  let triop (op : Ty.Triop.t) c v1 v2 =
229
    match op with
×
230
    | Ite -> ( match of_value 1 (`Triop op) c with true -> v1 | false -> v2 )
×
231
    | _ -> Fmt.failwith {|triop: Unsupported bool operator "%a"|} Ty.Triop.pp op
×
232

233
  let relop (op : Ty.Relop.t) v1 v2 =
234
    match op with
26✔
235
    | Eq -> Value.equal v1 v2
17✔
236
    | Ne -> not (Value.equal v1 v2)
9✔
237
    | _ -> Fmt.failwith {|relop: Unsupported bool operator "%a"|} Ty.Relop.pp op
×
238

239
  let cvtop _ _ = assert false
×
240

241
  let naryop (op : Ty.Naryop.t) vs =
242
    let b =
4✔
243
      match op with
244
      | Logand ->
2✔
245
        List.fold_left ( && ) true
2✔
246
          (List.mapi (fun i -> of_value i (`Naryop op)) vs)
2✔
247
      | Logor ->
2✔
248
        List.fold_left ( || ) false
2✔
249
          (List.mapi (fun i -> of_value i (`Naryop op)) vs)
2✔
250
      | _ ->
×
251
        Fmt.failwith {|naryop: Unsupported bool operator "%a"|} Ty.Naryop.pp op
×
252
    in
253
    to_value b
254
end
255

256
module Str = struct
257
  let to_value (str : string) : Value.t = Str str [@@inline]
12✔
258

259
  let of_value (n : int) (op : op_type) (v : Value.t) : string =
260
    of_arg
46✔
261
      (function Str str -> str | _ -> raise_notrace (Value Ty_str))
×
262
      n v op
263
  [@@inline]
264

265
  let replace s t t' =
266
    let len_s = String.length s in
1✔
267
    let len_t = String.length t in
1✔
268
    let rec loop i =
1✔
269
      if i >= len_s then s
×
270
      else if i + len_t > len_s then s
×
271
      else if String.equal (String.sub s i len_t) t then
2✔
272
        let s' = Fmt.str "%s%s" (String.sub s 0 i) t' in
1✔
273
        let s'' = String.sub s (i + len_t) (len_s - i - len_t) in
1✔
274
        Fmt.str "%s%s" s' s''
1✔
275
      else loop (i + 1)
1✔
276
    in
277
    loop 0
278

279
  let indexof s sub start =
280
    let len_s = String.length s in
2✔
281
    let len_sub = String.length sub in
2✔
282
    let max_i = len_s - 1 in
2✔
283
    let rec loop i =
284
      if i > max_i then ~-1
×
285
      else if i + len_sub > len_s then ~-1
×
286
      else if String.equal sub (String.sub s i len_sub) then i
2✔
287
      else loop (i + 1)
2✔
288
    in
289
    if start <= 0 then loop 0 else loop start
×
290

291
  let contains s sub = if indexof s sub 0 < 0 then false else true
×
292

293
  let unop (op : Ty.Unop.t) v =
294
    let str = of_value 1 (`Unop op) v in
2✔
295
    match op with
2✔
296
    | Length -> Int.to_value (String.length str)
1✔
297
    | Trim -> to_value (String.trim str)
1✔
298
    | _ -> Fmt.failwith {|unop: Unsupported str operator "%a"|} Ty.Unop.pp op
×
299

300
  let binop (op : Ty.Binop.t) v1 v2 =
301
    let op' = `Binop op in
4✔
302
    let str = of_value 1 op' v1 in
303
    match op with
4✔
304
    | At -> (
1✔
305
      let i = Int.of_value 2 op' v2 in
306
      try to_value (Fmt.str "%c" (String.get str i))
1✔
307
      with Invalid_argument _ -> raise IndexOutOfBounds )
×
308
    | String_prefix ->
1✔
309
      Bool.to_value (String.starts_with ~prefix:str (of_value 2 op' v2))
1✔
310
    | String_suffix ->
1✔
311
      Bool.to_value (String.ends_with ~suffix:str (of_value 2 op' v2))
1✔
312
    | String_contains -> Bool.to_value (contains str (of_value 2 op' v2))
1✔
313
    | _ -> Fmt.failwith {|binop: Unsupported str operator "%a"|} Ty.Binop.pp op
×
314

315
  let triop (op : Ty.Triop.t) v1 v2 v3 =
316
    let op' = `Triop op in
3✔
317
    let str = of_value 1 op' v1 in
318
    match op with
3✔
319
    | String_extract ->
1✔
320
      let i = Int.of_value 2 op' v2 in
321
      let len = Int.of_value 3 op' v3 in
1✔
322
      to_value (String.sub str i len)
1✔
323
    | String_replace ->
1✔
324
      let t = of_value 2 op' v2 in
325
      let t' = of_value 2 op' v3 in
1✔
326
      to_value (replace str t t')
1✔
327
    | String_index ->
1✔
328
      let t = of_value 2 op' v2 in
329
      let i = Int.of_value 3 op' v3 in
1✔
330
      Int.to_value (indexof str t i)
1✔
331
    | _ -> Fmt.failwith {|triop: Unsupported str operator "%a"|} Ty.Triop.pp op
×
332

333
  let relop (op : Ty.Relop.t) v1 v2 =
334
    let f =
8✔
335
      match op with
336
      | Lt -> ( < )
1✔
337
      | Le -> ( <= )
1✔
338
      | Gt -> ( > )
1✔
339
      | Ge -> ( >= )
1✔
340
      | Eq -> ( = )
2✔
341
      | Ne -> ( <> )
2✔
342
      | _ ->
×
343
        Fmt.failwith {|relop: Unsupported string operator "%a"|} Ty.Relop.pp op
×
344
    in
345
    let f x y = f (String.compare x y) 0 in
8✔
346
    f (of_value 1 (`Relop op) v1) (of_value 2 (`Relop op) v2)
8✔
347

348
  let cvtop (op : Ty.Cvtop.t) v =
349
    let op' = `Cvtop op in
14✔
350
    match op with
351
    | String_to_code ->
1✔
352
      let str = of_value 1 op' v in
353
      Int.to_value (Char.code str.[0])
1✔
354
    | String_from_code ->
1✔
355
      let code = Int.of_value 1 op' v in
356
      to_value (String.make 1 (Char.chr code))
1✔
357
    | String_to_int ->
7✔
358
      let s = of_value 1 op' v in
359
      let i =
7✔
360
        match int_of_string_opt s with
361
        | None -> raise ParseNumError
×
362
        | Some i -> i
7✔
363
      in
364
      Int.to_value i
365
    | String_from_int -> to_value (string_of_int (Int.of_value 1 op' v))
4✔
366
    | String_to_float ->
1✔
367
      let s = of_value 1 op' v in
368
      let f =
1✔
369
        match float_of_string_opt s with
370
        | None -> raise ParseNumError
×
371
        | Some f -> f
1✔
372
      in
373
      Real.to_value f
374
    | _ -> Fmt.failwith {|cvtop: Unsupported str operator "%a"|} Ty.Cvtop.pp op
×
375

376
  let naryop (op : Ty.Naryop.t) vs =
377
    let op' = `Naryop op in
3✔
378
    match op with
379
    | Concat -> to_value (String.concat "" (List.map (of_value 0 op') vs))
3✔
380
    | _ ->
×
381
      Fmt.failwith {|naryop: Unsupported str operator "%a"|} Ty.Naryop.pp op
382
end
383

384
module Lst = struct
385
  let of_value (n : int) (op : op_type) (v : Value.t) : Value.t list =
386
    of_arg
9✔
387
      (function List lst -> lst | _ -> raise_notrace (Value Ty_list))
×
388
      n v op
389
  [@@inline]
390

391
  let unop (op : Ty.Unop.t) (v : Value.t) : Value.t =
392
    let lst = of_value 1 (`Unop op) v in
4✔
393
    match op with
4✔
394
    | Head -> begin match lst with hd :: _tl -> hd | [] -> assert false end
1✔
395
    | Tail -> begin
1✔
396
      match lst with _hd :: tl -> List tl | [] -> assert false
1✔
397
    end
398
    | Length -> Int.to_value (List.length lst)
1✔
399
    | Reverse -> List (List.rev lst)
1✔
400
    | _ -> Fmt.failwith {|unop: Unsupported list operator "%a"|} Ty.Unop.pp op
×
401

402
  let binop (op : Ty.Binop.t) v1 v2 =
403
    let op' = `Binop op in
3✔
404
    match op with
405
    | At ->
1✔
406
      let lst = of_value 1 op' v1 in
407
      let i = Int.of_value 2 op' v2 in
1✔
408
      begin
1✔
409
        (* TODO: change datastructure? *)
410
        match List.nth_opt lst i with
411
        | None -> raise IndexOutOfBounds
×
412
        | Some v -> v
1✔
413
      end
414
    | List_cons -> List (v1 :: of_value 1 op' v2)
1✔
415
    | List_append -> List (of_value 1 op' v1 @ of_value 2 op' v2)
1✔
416
    | _ -> Fmt.failwith {|binop: Unsupported list operator "%a"|} Ty.Binop.pp op
×
417

418
  let triop (op : Ty.Triop.t) (v1 : Value.t) (v2 : Value.t) (v3 : Value.t) :
419
    Value.t =
420
    let op' = `Triop op in
1✔
421
    match op with
422
    | List_set ->
1✔
423
      let lst = of_value 1 op' v1 in
424
      let i = Int.of_value 2 op' v2 in
1✔
425
      let rec set i lst v acc =
1✔
426
        match (i, lst) with
2✔
427
        | 0, _ :: tl -> List.rev_append acc (v :: tl)
1✔
428
        | i, hd :: tl -> set (i - 1) tl v (hd :: acc)
1✔
429
        | _, [] -> raise IndexOutOfBounds
×
430
      in
431
      List (set i lst v3 [])
1✔
432
    | _ -> Fmt.failwith {|triop: Unsupported list operator "%a"|} Ty.Triop.pp op
×
433

434
  let naryop (op : Ty.Naryop.t) (vs : Value.t list) : Value.t =
435
    let op' = `Naryop op in
×
436
    match op with
437
    | Concat -> List (List.concat_map (of_value 0 op') vs)
×
438
    | _ ->
×
439
      Fmt.failwith {|naryop: Unsupported list operator "%a"|} Ty.Naryop.pp op
440
end
441

442
module I32 = struct
443
  let to_value (i : int32) : Value.t = Num (I32 i) [@@inline]
32✔
444

445
  let of_value (n : int) (op : op_type) (v : Value.t) : int32 =
446
    of_arg
91✔
447
      (function Num (I32 i) -> i | _ -> raise_notrace (Value (Ty_bitv 32)))
×
448
      n v op
449
  [@@inline]
450

451
  let cmp_u x op y = op Int32.(add x min_int) Int32.(add y min_int) [@@inline]
8✔
452

453
  let lt_u x y = cmp_u x Int32.Infix.( < ) y [@@inline]
2✔
454

455
  let le_u x y = cmp_u x Int32.Infix.( <= ) y [@@inline]
2✔
456

457
  let gt_u x y = cmp_u x Int32.Infix.( > ) y [@@inline]
2✔
458

459
  let ge_u x y = cmp_u x Int32.Infix.( >= ) y [@@inline]
2✔
460

461
  let shift f x y = f x Int32.(to_int (logand y 31l)) [@@inline]
6✔
462

463
  let shl x y = shift Int32.shift_left x y [@@inline]
3✔
464

465
  let shr_s x y = shift Int32.shift_right x y [@@inline]
1✔
466

467
  let shr_u x y = shift Int32.shift_right_logical x y [@@inline]
2✔
468

469
  (* Stolen rotl and rotr from: *)
470
  (* https://github.com/OCamlPro/owi/blob/main/src/int32.ml *)
471
  (* We must mask the count to implement rotates via shifts. *)
472
  let clamp_rotate_count n = Int32.(to_int (logand n 31l)) [@@inline]
2✔
473

474
  let rotl x y =
475
    let n = clamp_rotate_count y in
1✔
476
    Int32.logor (shl x (Int32.of_int n)) (shr_u x (Int32.of_int (32 - n)))
1✔
477
  [@@inline]
478

479
  let rotr x y =
480
    let n = clamp_rotate_count y in
1✔
481
    Int32.logor (shr_u x (Int32.of_int n)) (shl x (Int32.of_int (32 - n)))
1✔
482
  [@@inline]
483

484
  let clz n =
485
    let n = Ocaml_intrinsics.Int32.count_leading_zeros n in
×
486
    Int32.of_int n
×
487

488
  let ctz n =
489
    let n = Ocaml_intrinsics.Int32.count_trailing_zeros n in
×
490
    Int32.of_int n
×
491

492
  let unop (op : Ty.Unop.t) (v : Value.t) : Value.t =
493
    let f =
3✔
494
      match op with
495
      | Neg -> Int32.neg
2✔
496
      | Not -> Int32.lognot
1✔
497
      | Clz -> clz
×
498
      | Ctz -> ctz
×
499
      | _ -> Fmt.failwith {|unop: Unsupported i32 operator "%a"|} Ty.Unop.pp op
×
500
    in
501
    to_value (f (of_value 1 (`Unop op) v))
3✔
502

503
  let binop op v1 v2 =
504
    let f =
26✔
505
      match op with
506
      | Ty.Binop.Add -> Int32.add
10✔
507
      | Sub -> Int32.sub
3✔
508
      | Mul -> Int32.mul
3✔
509
      | Div -> Int32.div
1✔
510
      | DivU -> Int32.unsigned_div
×
511
      | Rem -> Int32.rem
2✔
512
      | RemU -> Int32.unsigned_rem
×
513
      | And -> Int32.logand
1✔
514
      | Or -> Int32.logor
1✔
515
      | Xor -> Int32.logxor
1✔
516
      | Shl -> shl
1✔
517
      | ShrL -> shr_u
×
518
      | ShrA -> shr_s
1✔
519
      | Rotl -> rotl
1✔
520
      | Rotr -> rotr
1✔
521
      | _ ->
×
522
        Fmt.failwith {|binop: Unsupported i32 operator "%a"|} Ty.Binop.pp op
×
523
    in
524
    to_value (f (of_value 1 (`Binop op) v1) (of_value 2 (`Binop op) v2))
26✔
525

526
  let relop (op : Ty.Relop.t) (v1 : Value.t) (v2 : Value.t) : bool =
527
    let f =
17✔
528
      match op with
529
      | Lt -> Int32.Infix.( < )
3✔
530
      | LtU -> lt_u
2✔
531
      | Le -> Int32.Infix.( <= )
2✔
532
      | LeU -> le_u
2✔
533
      | Gt -> Int32.Infix.( > )
2✔
534
      | GtU -> gt_u
2✔
535
      | Ge -> Int32.Infix.( >= )
2✔
536
      | GeU -> ge_u
2✔
537
      | Eq | Ne -> assert false
538
    in
539
    f (of_value 1 (`Relop op) v1) (of_value 2 (`Relop op) v2)
17✔
540
end
541

542
module I64 = struct
543
  let to_value (i : int64) : Value.t = Num (I64 i) [@@inline]
16✔
544

545
  let of_value (n : int) (op : op_type) (v : Value.t) : int64 =
546
    of_arg
45✔
547
      (function Num (I64 i) -> i | _ -> raise_notrace (Value (Ty_bitv 64)))
×
548
      n v op
549
  [@@inline]
550

551
  let cmp_u x op y = op Int64.(add x min_int) Int64.(add y min_int) [@@inline]
4✔
552

553
  let lt_u x y = cmp_u x Int64.Infix.( < ) y [@@inline]
1✔
554

555
  let le_u x y = cmp_u x Int64.Infix.( <= ) y [@@inline]
1✔
556

557
  let gt_u x y = cmp_u x Int64.Infix.( > ) y [@@inline]
1✔
558

559
  let ge_u x y = cmp_u x Int64.Infix.( >= ) y [@@inline]
1✔
560

561
  let shift f x y = f x Int64.(to_int (logand y 63L)) [@@inline]
6✔
562

563
  let shl x y = shift Int64.shift_left x y [@@inline]
3✔
564

565
  let shr_s x y = shift Int64.shift_right x y [@@inline]
1✔
566

567
  let shr_u x y = shift Int64.shift_right_logical x y [@@inline]
2✔
568

569
  (* Stolen rotl and rotr from: *)
570
  (* https://github.com/OCamlPro/owi/blob/main/src/int64.ml *)
571
  (* We must mask the count to implement rotates via shifts. *)
572
  let clamp_rotate_count n = Int64.(to_int (logand n (of_int 63))) [@@inline]
2✔
573

574
  let rotl x y =
575
    let n = clamp_rotate_count y in
1✔
576
    Int64.logor (shl x (Int64.of_int n)) (shr_u x (Int64.of_int (64 - n)))
1✔
577
  [@@inline]
578

579
  let rotr x y =
580
    let n = clamp_rotate_count y in
1✔
581
    Int64.logor (shr_u x (Int64.of_int n)) (shl x (Int64.of_int (64 - n)))
1✔
582
  [@@inline]
583

584
  let clz n =
585
    let n = Ocaml_intrinsics.Int64.count_leading_zeros n in
×
586
    Int64.of_int n
×
587

588
  let ctz n =
589
    let n = Ocaml_intrinsics.Int64.count_trailing_zeros n in
×
590
    Int64.of_int n
×
591

592
  let unop (op : Ty.Unop.t) (v : Value.t) : Value.t =
593
    let f =
2✔
594
      match op with
595
      | Neg -> Int64.neg
1✔
596
      | Not -> Int64.lognot
1✔
597
      | Clz -> clz
×
598
      | Ctz -> ctz
×
599
      | _ -> Fmt.failwith {|unop: Unsupported i64 operator "%a"|} Ty.Unop.pp op
×
600
    in
601
    to_value (f (of_value 1 (`Unop op) v))
2✔
602

603
  let binop (op : Ty.Binop.t) (v1 : Value.t) (v2 : Value.t) : Value.t =
604
    let f =
12✔
605
      match op with
606
      | Add -> Int64.add
1✔
607
      | Sub -> Int64.sub
1✔
608
      | Mul -> Int64.mul
1✔
609
      | Div -> Int64.div
1✔
610
      | DivU -> Int64.unsigned_div
×
611
      | Rem -> Int64.rem
1✔
612
      | RemU -> Int64.unsigned_rem
×
613
      | And -> Int64.logand
1✔
614
      | Or -> Int64.logor
1✔
615
      | Xor -> Int64.logxor
1✔
616
      | Shl -> shl
1✔
617
      | ShrL -> shr_u
×
618
      | ShrA -> shr_s
1✔
619
      | Rotl -> rotl
1✔
620
      | Rotr -> rotr
1✔
621
      | _ ->
×
622
        Fmt.failwith {|binop: Unsupported i64 operator "%a"|} Ty.Binop.pp op
×
623
    in
624
    to_value (f (of_value 1 (`Binop op) v1) (of_value 2 (`Binop op) v2))
12✔
625

626
  let relop (op : Ty.Relop.t) (v1 : Value.t) (v2 : Value.t) : bool =
627
    let f =
8✔
628
      match op with
629
      | Lt -> Int64.Infix.( < )
1✔
630
      | LtU -> lt_u
1✔
631
      | Le -> Int64.Infix.( <= )
1✔
632
      | LeU -> le_u
1✔
633
      | Gt -> Int64.Infix.( > )
1✔
634
      | GtU -> gt_u
1✔
635
      | Ge -> Int64.Infix.( >= )
1✔
636
      | GeU -> ge_u
1✔
637
      | Eq | Ne -> assert false
638
    in
639
    f (of_value 1 (`Relop op) v1) (of_value 2 (`Relop op) v2)
8✔
640
end
641

642
module F32 = struct
643
  let to_float (v : int32) : float = Int32.float_of_bits v [@@inline]
16✔
644

645
  let of_float (v : float) : int32 = Int32.bits_of_float v [@@inline]
6✔
646

647
  let to_value (f : int32) : Value.t = Num (F32 f) [@@inline]
6✔
648

649
  let to_value' (f : float) : Value.t = to_value @@ of_float f [@@inline]
4✔
650

651
  let of_value (i : int) (op : op_type) (v : Value.t) : int32 =
652
    of_arg
16✔
653
      (function Num (F32 f) -> f | _ -> raise_notrace (Value (Ty_fp 32)))
×
654
      i v op
655
  [@@inline]
656

657
  let of_value' (i : int) (op : op_type) (v : Value.t) : float =
658
    of_value i op v |> to_float
10✔
659
  [@@inline]
660

661
  let unop (op : Ty.Unop.t) (v : Value.t) : Value.t =
662
    let v = to_float @@ of_value 1 (`Unop op) v in
4✔
663
    match op with
4✔
664
    | Neg -> to_value' @@ Float.neg v
1✔
665
    | Abs -> to_value' @@ Float.abs v
×
666
    | Sqrt -> to_value' @@ Float.sqrt v
2✔
667
    | Nearest -> to_value' @@ Float.round v
×
668
    | Ceil -> to_value' @@ Float.ceil v
×
669
    | Floor -> to_value' @@ Float.floor v
×
670
    | Trunc -> to_value' @@ Float.trunc v
1✔
671
    | Is_nan -> if Float.is_nan v then Value.True else Value.False
×
672
    | _ -> Fmt.failwith {|unop: Unsupported f32 operator "%a"|} Ty.Unop.pp op
×
673

674
  let binop (op : Ty.Binop.t) (v1 : Value.t) (v2 : Value.t) : Value.t =
675
    let f =
×
676
      match op with
677
      | Add -> Float.add
×
678
      | Sub -> Float.sub
×
679
      | Mul -> Float.mul
×
680
      | Div -> Float.div
×
681
      | Rem -> Float.rem
×
682
      | Min -> Float.min
×
683
      | Max -> Float.max
×
684
      | _ ->
×
685
        Fmt.failwith {|binop: Unsupported f32 operator "%a"|} Ty.Binop.pp op
×
686
    in
687
    to_value' (f (of_value' 1 (`Binop op) v1) (of_value' 2 (`Binop op) v2))
×
688

689
  let relop (op : Ty.Relop.t) (v1 : Value.t) (v2 : Value.t) : bool =
690
    let f =
5✔
691
      match op with
692
      | Eq -> Float.Infix.( = )
1✔
693
      | Ne -> Float.Infix.( <> )
×
694
      | Lt -> Float.Infix.( < )
1✔
695
      | Le -> Float.Infix.( <= )
1✔
696
      | Gt -> Float.Infix.( > )
1✔
697
      | Ge -> Float.Infix.( >= )
1✔
698
      | _ ->
×
699
        Fmt.failwith {|relop: Unsupported f32 operator "%a"|} Ty.Relop.pp op
×
700
    in
701
    f (of_value' 1 (`Relop op) v1) (of_value' 2 (`Relop op) v2)
5✔
702
end
703

704
module F64 = struct
705
  let to_float (v : int64) : float = Int64.float_of_bits v [@@inline]
13✔
706

707
  let of_float (v : float) : int64 = Int64.bits_of_float v [@@inline]
4✔
708

709
  let to_value (f : int64) : Value.t = Num (F64 f) [@@inline]
4✔
710

711
  let to_value' (f : float) : Value.t = to_value @@ of_float f [@@inline]
2✔
712

713
  let of_value (i : int) (op : op_type) (v : Value.t) : int64 =
714
    of_arg
13✔
715
      (function Num (F64 f) -> f | _ -> raise_notrace (Value (Ty_fp 64)))
×
716
      i v op
717
  [@@inline]
718

719
  let of_value' (i : int) (op : op_type) (v : Value.t) : float =
720
    of_value i op v |> to_float
11✔
721
  [@@inline]
722

723
  let unop (op : Ty.Unop.t) (v : Value.t) : Value.t =
724
    let v = of_value' 1 (`Unop op) v in
1✔
725
    match op with
1✔
726
    | Neg -> to_value' @@ Float.neg v
×
727
    | Abs -> to_value' @@ Float.abs v
×
728
    | Sqrt -> to_value' @@ Float.sqrt v
×
729
    | Nearest -> to_value' @@ Float.round v
×
730
    | Ceil -> to_value' @@ Float.ceil v
×
731
    | Floor -> to_value' @@ Float.floor v
×
732
    | Trunc -> to_value' @@ Float.trunc v
1✔
733
    | Is_nan -> if Float.is_nan v then Value.True else Value.False
×
734
    | _ -> Fmt.failwith {|unop: Unsupported f32 operator "%a"|} Ty.Unop.pp op
×
735

736
  let binop (op : Ty.Binop.t) (v1 : Value.t) (v2 : Value.t) : Value.t =
737
    let f =
1✔
738
      match op with
739
      | Add -> Float.add
×
740
      | Sub -> Float.sub
×
741
      | Mul -> Float.mul
×
742
      | Div -> Float.div
1✔
743
      | Rem -> Float.rem
×
744
      | Min -> Float.min
×
745
      | Max -> Float.max
×
746
      | _ ->
×
747
        Fmt.failwith {|binop: Unsupported f32 operator "%a"|} Ty.Binop.pp op
×
748
    in
749
    to_value' (f (of_value' 1 (`Binop op) v1) (of_value' 2 (`Binop op) v2))
1✔
750

751
  let relop (op : Ty.Relop.t) (v1 : Value.t) (v2 : Value.t) : bool =
752
    let f =
4✔
753
      match op with
754
      | Eq -> Float.Infix.( = )
×
755
      | Ne -> Float.Infix.( <> )
×
756
      | Lt -> Float.Infix.( < )
1✔
757
      | Le -> Float.Infix.( <= )
1✔
758
      | Gt -> Float.Infix.( > )
1✔
759
      | Ge -> Float.Infix.( >= )
1✔
760
      | _ ->
×
761
        Fmt.failwith {|relop: Unsupported f32 operator "%a"|} Ty.Relop.pp op
×
762
    in
763
    f (of_value' 1 (`Relop op) v1) (of_value' 2 (`Relop op) v2)
4✔
764
end
765

766
module I32CvtOp = struct
767
  let extend_s (n : int) (x : int32) : int32 =
768
    let shift = 32 - n in
×
769
    Int32.(shift_right (shift_left x shift) shift)
×
770

771
  let trunc_f32_s (x : int32) =
772
    if Int32.Infix.(x <> x) then raise ConversionToInteger
×
773
    else
774
      let xf = F32.to_float x in
1✔
775
      if
1✔
776
        Float.Infix.(
777
          xf >= -.Int32.(to_float min_int) || xf < Int32.(to_float min_int) )
×
778
      then raise IntegerOverflow
×
779
      else Int32.of_float xf
1✔
780

781
  let trunc_f32_u (x : int32) =
782
    if Int32.Infix.(x <> x) then raise ConversionToInteger
×
783
    else
784
      let xf = F32.to_float x in
×
785
      if Float.Infix.(xf >= -.Int32.(to_float min_int) *. 2.0 || xf <= -1.0)
×
786
      then raise IntegerOverflow
×
787
      else Int32.of_float xf
×
788

789
  let trunc_f64_s (x : int64) =
790
    if Int64.Infix.(x <> x) then raise ConversionToInteger
×
791
    else
792
      let xf = F64.to_float x in
1✔
793
      if
1✔
794
        Float.Infix.(
795
          xf >= -.Int64.(to_float min_int) || xf < Int64.(to_float min_int) )
×
796
      then raise IntegerOverflow
×
797
      else Int32.of_float xf
1✔
798

799
  let trunc_f64_u (x : int64) =
800
    if Int64.Infix.(x <> x) then raise ConversionToInteger
×
801
    else
802
      let xf = F64.to_float x in
×
803
      if Float.Infix.(xf >= -.Int64.(to_float min_int) *. 2.0 || xf <= -1.0)
×
804
      then raise IntegerOverflow
×
805
      else Int32.of_float xf
×
806

807
  let cvtop op v =
808
    let op' = `Cvtop op in
3✔
809
    match op with
810
    | Ty.Cvtop.WrapI64 -> I32.to_value (Int64.to_int32 (I64.of_value 1 op' v))
1✔
811
    | TruncSF32 -> I32.to_value (trunc_f32_s (F32.of_value 1 op' v))
1✔
812
    | TruncUF32 -> I32.to_value (trunc_f32_u (F32.of_value 1 op' v))
×
813
    | TruncSF64 -> I32.to_value (trunc_f64_s (F64.of_value 1 op' v))
1✔
814
    | TruncUF64 -> I32.to_value (trunc_f64_u (F64.of_value 1 op' v))
×
815
    | Reinterpret_float -> I32.to_value (F32.of_value 1 op' v)
×
816
    | Sign_extend n -> I32.to_value (extend_s n (I32.of_value 1 op' v))
×
817
    | Zero_extend _n -> I32.to_value (I32.of_value 1 op' v)
×
818
    | OfBool -> v (* already a num here *)
×
819
    | ToBool | _ ->
×
820
      Fmt.failwith {|cvtop: Unsupported i32 operator "%a"|} Ty.Cvtop.pp op
821
end
822

823
module I64CvtOp = struct
824
  (* let extend_s n x = *)
825
  (*   let shift = 64 - n in *)
826
  (*   Int64.(shift_right (shift_left x shift) shift) *)
827

828
  let extend_i32_u (x : int32) =
829
    Int64.(logand (of_int32 x) 0x0000_0000_ffff_ffffL)
×
830

831
  let trunc_f32_s (x : int32) =
832
    if Int32.Infix.(x <> x) then raise ConversionToInteger
×
833
    else
834
      let xf = F32.to_float x in
1✔
835
      if
1✔
836
        Float.Infix.(
837
          xf >= -.Int64.(to_float min_int) || xf < Int64.(to_float min_int) )
×
838
      then raise IntegerOverflow
×
839
      else Int64.of_float xf
1✔
840

841
  let trunc_f32_u (x : int32) =
842
    if Int32.Infix.(x <> x) then raise ConversionToInteger
×
843
    else
844
      let xf = F32.to_float x in
×
845
      if Float.Infix.(xf >= -.Int64.(to_float min_int) *. 2.0 || xf <= -1.0)
×
846
      then raise IntegerOverflow
×
847
      else if Float.Infix.(xf >= -.Int64.(to_float min_int)) then
×
848
        Int64.(logxor (of_float (xf -. 0x1p63)) min_int)
×
849
      else Int64.of_float xf
×
850

851
  let trunc_f64_s (x : int64) =
852
    if Int64.Infix.(x <> x) then raise ConversionToInteger
×
853
    else
854
      let xf = F64.to_float x in
1✔
855
      if
1✔
856
        Float.Infix.(
857
          xf >= -.Int64.(to_float min_int) || xf < Int64.(to_float min_int) )
×
858
      then raise IntegerOverflow
×
859
      else Int64.of_float xf
1✔
860

861
  let trunc_f64_u (x : int64) =
862
    if Int64.Infix.(x <> x) then raise ConversionToInteger
×
863
    else
864
      let xf = F64.to_float x in
×
865
      if Float.Infix.(xf >= -.Int64.(to_float min_int) *. 2.0 || xf <= -1.0)
×
866
      then raise IntegerOverflow
×
867
      else if Float.Infix.(xf >= -.Int64.(to_float min_int)) then
×
868
        Int64.(logxor (of_float (xf -. 0x1p63)) min_int)
×
869
      else Int64.of_float xf
×
870

871
  let cvtop (op : Ty.Cvtop.t) (v : Value.t) : Value.t =
872
    let op' = `Cvtop op in
2✔
873
    match op with
874
    | Sign_extend 32 -> I64.to_value (Int64.of_int32 (I32.of_value 1 op' v))
×
875
    | Zero_extend 32 -> I64.to_value (extend_i32_u (I32.of_value 1 op' v))
×
876
    | TruncSF32 -> I64.to_value (trunc_f32_s (F32.of_value 1 op' v))
1✔
877
    | TruncUF32 -> I64.to_value (trunc_f32_u (F32.of_value 1 op' v))
×
878
    | TruncSF64 -> I64.to_value (trunc_f64_s (F64.of_value 1 op' v))
1✔
879
    | TruncUF64 -> I64.to_value (trunc_f64_u (F64.of_value 1 op' v))
×
880
    | Reinterpret_float -> I64.to_value (F64.of_value 1 op' v)
×
881
    | WrapI64 ->
×
882
      raise
883
        (TypeError
884
           { index = 1; value = v; ty = Ty_bitv 64; op = `Cvtop WrapI64 } )
885
    | ToBool | OfBool | _ ->
×
886
      Fmt.failwith {|cvtop: Unsupported i64 operator "%a"|} Ty.Cvtop.pp op
887
end
888

889
module F32CvtOp = struct
890
  let demote_f64 x =
891
    let xf = F64.to_float x in
×
892
    if Float.Infix.(xf = xf) then F32.of_float xf
×
893
    else
894
      let nan64bits = x in
×
895
      let sign_field =
896
        Int64.(shift_left (shift_right_logical nan64bits 63) 31)
×
897
      in
898
      let significand_field =
899
        Int64.(shift_right_logical (shift_left nan64bits 12) 41)
×
900
      in
901
      let fields = Int64.logor sign_field significand_field in
902
      Int32.logor 0x7fc0_0000l (Int64.to_int32 fields)
×
903

904
  let convert_i32_s x = F32.of_float (Int32.to_float x)
1✔
905

906
  let convert_i32_u x =
907
    F32.of_float
×
908
      Int32.(
909
        Int32.Infix.(
910
          if x >= 0l then to_float x
×
911
          else to_float (logor (shift_right_logical x 1) (logand x 1l)) *. 2.0 ) )
×
912

913
  let convert_i64_s x =
914
    F32.of_float
1✔
915
      Int64.(
916
        Int64.Infix.(
917
          if abs x < 0x10_0000_0000_0000L then to_float x
1✔
918
          else
919
            let r = if logand x 0xfffL = 0L then 0L else 1L in
×
920
            to_float (logor (shift_right x 12) r) *. 0x1p12 ) )
×
921

922
  let convert_i64_u x =
923
    F32.of_float
×
924
      Int64.(
925
        Int64.Infix.(
926
          if I64.lt_u x 0x10_0000_0000_0000L then to_float x
×
927
          else
928
            let r = if logand x 0xfffL = 0L then 0L else 1L in
×
929
            to_float (logor (shift_right_logical x 12) r) *. 0x1p12 ) )
×
930

931
  let cvtop (op : Ty.Cvtop.t) (v : Value.t) : Value.t =
932
    let op' = `Cvtop op in
2✔
933
    match op with
934
    | DemoteF64 -> F32.to_value (demote_f64 (F64.of_value 1 op' v))
×
935
    | ConvertSI32 -> F32.to_value (convert_i32_s (I32.of_value 1 op' v))
1✔
936
    | ConvertUI32 -> F32.to_value (convert_i32_u (I32.of_value 1 op' v))
×
937
    | ConvertSI64 -> F32.to_value (convert_i64_s (I64.of_value 1 op' v))
1✔
938
    | ConvertUI64 -> F32.to_value (convert_i64_u (I64.of_value 1 op' v))
×
939
    | Reinterpret_int -> F32.to_value (I32.of_value 1 op' v)
×
940
    | PromoteF32 ->
×
941
      raise
942
        (TypeError
943
           { index = 1; value = v; ty = Ty_fp 32; op = `Cvtop PromoteF32 } )
944
    | ToString | OfString | _ ->
×
945
      Fmt.failwith {|cvtop: Unsupported f32 operator "%a"|} Ty.Cvtop.pp op
946
end
947

948
module F64CvtOp = struct
949
  Float.is_nan
950

951
  let promote_f32 x =
952
    let xf = F32.to_float x in
×
953
    if Float.Infix.(xf = xf) then F64.of_float xf
×
954
    else
955
      let nan32bits = I64CvtOp.extend_i32_u x in
×
956
      let sign_field =
×
957
        Int64.(shift_left (shift_right_logical nan32bits 31) 63)
×
958
      in
959
      let significand_field =
960
        Int64.(shift_right_logical (shift_left nan32bits 41) 12)
×
961
      in
962
      let fields = Int64.logor sign_field significand_field in
963
      Int64.logor 0x7ff8_0000_0000_0000L fields
×
964

965
  let convert_i32_s x = F64.of_float (Int32.to_float x)
1✔
966

967
  (*
968
   * Unlike the other convert_u functions, the high half of the i32 range is
969
   * within the range where f32 can represent odd numbers, so we can't do the
970
   * shift. Instead, we can use int64 signed arithmetic.
971
   *)
972
  let convert_i32_u x =
973
    F64.of_float Int64.(to_float (logand (of_int32 x) 0x0000_0000_ffff_ffffL))
×
974

975
  let convert_i64_s x = F64.of_float (Int64.to_float x)
1✔
976

977
  (*
978
   * Values in the low half of the int64 range can be converted with a signed
979
   * conversion. The high half is beyond the range where f64 can represent odd
980
   * numbers, so we can shift the value right, adjust the least significant
981
   * bit to round correctly, do a conversion, and then scale it back up.
982
   *)
983
  let convert_i64_u (x : int64) =
984
    F64.of_float
×
985
      Int64.(
986
        Int64.Infix.(
987
          if x >= 0L then to_float x
×
988
          else to_float (logor (shift_right_logical x 1) (logand x 1L)) *. 2.0 ) )
×
989

990
  let cvtop (op : Ty.Cvtop.t) v : Value.t =
991
    let op' = `Cvtop op in
2✔
992
    match op with
993
    | PromoteF32 -> F64.to_value (promote_f32 (F32.of_value 1 op' v))
×
994
    | ConvertSI32 -> F64.to_value (convert_i32_s (I32.of_value 1 op' v))
1✔
995
    | ConvertUI32 -> F64.to_value (convert_i32_u (I32.of_value 1 op' v))
×
996
    | ConvertSI64 -> F64.to_value (convert_i64_s (I64.of_value 1 op' v))
1✔
997
    | ConvertUI64 -> F64.to_value (convert_i64_u (I64.of_value 1 op' v))
×
998
    | Reinterpret_int -> F64.to_value (I64.of_value 1 op' v)
×
999
    | DemoteF64 ->
×
1000
      raise
1001
        (TypeError
1002
           { index = 1; value = v; ty = Ty_bitv 64; op = `Cvtop DemoteF64 } )
1003
    | ToString | OfString | _ ->
×
1004
      Fmt.failwith {|cvtop: Unsupported f64 operator "%a"|} Ty.Cvtop.pp op
1005
end
1006

1007
(* Dispatch *)
1008

1009
let op int real bool str lst i32 i64 f32 f64 ty op =
1010
  match ty with
97✔
1011
  | Ty.Ty_int -> int op
19✔
1012
  | Ty_real -> real op
15✔
1013
  | Ty_bool -> bool op
1✔
1014
  | Ty_str -> str op
6✔
1015
  | Ty_list -> lst op
7✔
1016
  | Ty_bitv 32 -> i32 op
29✔
1017
  | Ty_bitv 64 -> i64 op
14✔
1018
  | Ty_fp 32 -> f32 op
4✔
1019
  | Ty_fp 64 -> f64 op
2✔
1020
  | Ty_bitv _ | Ty_fp _ | Ty_app | Ty_unit | Ty_none | Ty_regexp -> assert false
1021
[@@inline]
1022

1023
let unop =
1024
  op Int.unop Real.unop Bool.unop Str.unop Lst.unop I32.unop I64.unop F32.unop
44✔
1025
    F64.unop
1026

1027
let binop =
1028
  op Int.binop Real.binop Bool.binop Str.binop Lst.binop I32.binop I64.binop
44✔
1029
    F32.binop F64.binop
1030

1031
let triop = function
1032
  | Ty.Ty_bool -> Bool.triop
×
1033
  | Ty_str -> Str.triop
3✔
1034
  | Ty_list -> Lst.triop
1✔
1035
  | _ -> assert false
1036

1037
let relop = function
1038
  | Ty.Ty_int -> Int.relop
4✔
1039
  | Ty_real -> Real.relop
5✔
1040
  | Ty_bool -> Bool.relop
26✔
1041
  | Ty_str -> Str.relop
8✔
1042
  | Ty_bitv 32 -> I32.relop
17✔
1043
  | Ty_bitv 64 -> I64.relop
8✔
1044
  | Ty_fp 32 -> F32.relop
5✔
1045
  | Ty_fp 64 -> F64.relop
4✔
1046
  | _ -> assert false
1047

1048
let cvtop = function
1049
  | Ty.Ty_int -> Int.cvtop
4✔
1050
  | Ty_real -> Real.cvtop
3✔
1051
  | Ty_bool -> Bool.cvtop
×
1052
  | Ty_str -> Str.cvtop
14✔
1053
  | Ty_bitv 32 -> I32CvtOp.cvtop
3✔
1054
  | Ty_bitv 64 -> I64CvtOp.cvtop
2✔
1055
  | Ty_fp 32 -> F32CvtOp.cvtop
2✔
1056
  | Ty_fp 64 -> F64CvtOp.cvtop
2✔
1057
  | _ -> assert false
1058

1059
let naryop = function
1060
  | Ty.Ty_bool -> Bool.naryop
4✔
1061
  | Ty_str -> Str.naryop
3✔
1062
  | Ty_list -> Lst.naryop
×
1063
  | _ -> assert false
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