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
447
448
449
450
451
452
453
454
455
456
(* SPDX-License-Identifier: AGPL-3.0-or-later *)
(* Copyright © 2021-2024 OCamlPro *)
(* Written by the Owi programmers *)

open Smtml
open Ty
open Expr

type vbool = Expr.t

type int32 = Expr.t

let pp_int32 = Expr.pp

type int64 = Expr.t

let pp_int64 = Expr.pp

type float32 = Expr.t

let pp_float32 = Expr.pp

type float64 = Expr.t

let pp_float64 = Expr.pp

type externref = Concrete_value.externref

type ref_value =
  | Funcref of Func_intf.t option
  | Externref of externref option

let pp_ref_value _fmt _v = assert false

type t =
  | I32 of int32
  | I64 of int64
  | F32 of float32
  | F64 of float64
  | Ref of ref_value

let const_i32 (i : Int32.t) : int32 = value (Num (I32 i))

let const_i64 (i : Int64.t) : int64 = value (Num (I64 i))

let const_f32 (f : Float32.t) : float32 = value (Num (F32 (Float32.to_bits f)))

let const_f64 (f : Float64.t) : float64 = value (Num (F64 (Float64.to_bits f)))

let ref_null _ty = Ref (Funcref None)

let ref_func f : t = Ref (Funcref (Some f))

let ref_externref t v : t = Ref (Externref (Some (E (t, v))))

let ref_is_null = function
  | Funcref (Some _) | Externref (Some _) -> value False
  | Funcref None | Externref None -> value True

let pp ppf v =
  let e =
    match v with
    | I32 e -> e
    | I64 e -> e
    | F32 e -> e
    | F64 e -> e
    | Ref _ -> assert false
  in
  Expr.pp ppf e

module Ref = struct
  let get_func (r : ref_value) : Func_intf.t Value_intf.get_ref =
    match r with
    | Funcref (Some f) -> Ref_value f
    | Funcref None -> Null
    | Externref _ -> Type_mismatch

  let get_externref (type t) (r : ref_value) (t : t Type.Id.t) :
    t Value_intf.get_ref =
    match r with
    | Externref (Some (E (ety, v))) -> (
      match Type.Id.provably_equal t ety with
      | None -> assert false
      | Some Equal -> Ref_value v )
    | _ -> assert false
end

module Bool = struct
  let const b = Bool.v b

  let not e = Bool.not e

  let or_ e1 e2 = Bool.or_ e1 e2

  let and_ e1 e2 = Bool.and_ e1 e2

  let int32 e =
    match view e with
    | Val True -> const_i32 1l
    | Val False -> const_i32 0l
    | Cvtop (Ty_bitv 32, ToBool, e') -> e'
    | _ -> make (Cvtop (Ty_bitv 32, OfBool, e))

  let select_expr c ~if_true ~if_false = Bool.ite c if_true if_false

  let pp ppf (e : vbool) = Expr.pp ppf e
end

module I32 = struct
  let ty = Ty_bitv 32

  let zero = const_i32 0l

  let clz e = unop ty Clz e

  let ctz e = unop ty Ctz e

  let popcnt _ =
    (* TODO *)
    assert false

  let add e1 e2 = binop ty Add e1 e2

  let sub e1 e2 = binop ty Sub e1 e2

  let mul e1 e2 = binop ty Mul e1 e2

  let div e1 e2 = binop ty Div e1 e2

  let unsigned_div e1 e2 = binop ty DivU e1 e2

  let rem e1 e2 = binop ty Rem e1 e2

  let unsigned_rem e1 e2 = binop ty RemU e1 e2

  let boolify e =
    match view e with
    | Val (Num (I32 0l)) -> Some (Bool.const false)
    | Val (Num (I32 1l)) -> Some (Bool.const true)
    | Cvtop (_, OfBool, cond) -> Some cond
    | _ -> None

  let logand e1 e2 =
    match (boolify e1, boolify e2) with
    | Some b1, Some b2 -> Bool.int32 (Bool.and_ b1 b2)
    | _ -> binop ty And e1 e2

  let logor e1 e2 =
    match (boolify e1, boolify e2) with
    | Some b1, Some b2 -> Bool.int32 (Bool.or_ b1 b2)
    | _ -> binop ty Or e1 e2

  let logxor e1 e2 = binop ty Xor e1 e2

  let shl e1 e2 = binop ty Shl e1 e2

  let shr_s e1 e2 = binop ty ShrA e1 e2

  let shr_u e1 e2 = binop ty ShrL e1 e2

  let rotl e1 e2 = binop ty Rotl e1 e2

  let rotr e1 e2 = binop ty Rotr e1 e2

  let eq_const e c =
    match view e with
    | Cvtop (_, OfBool, cond) -> begin
      match c with 0l -> Bool.not cond | 1l -> cond | _ -> Bool.const false
    end
    | _ -> relop Ty_bool Eq e (const_i32 c)

  let eq e1 e2 =
    if phys_equal e1 e2 then Bool.const true else relop Ty_bool Eq e1 e2

  let ne e1 e2 =
    if phys_equal e1 e2 then Bool.const false else relop Ty_bool Ne e1 e2

  let lt e1 e2 =
    if phys_equal e1 e2 then Bool.const false else relop ty Lt e1 e2

  let gt e1 e2 =
    if phys_equal e1 e2 then Bool.const false else relop ty Gt e1 e2

  let lt_u e1 e2 =
    if phys_equal e1 e2 then Bool.const false else relop ty LtU e1 e2

  let gt_u e1 e2 =
    if phys_equal e1 e2 then Bool.const false else relop ty GtU e1 e2

  let le e1 e2 = if phys_equal e1 e2 then Bool.const true else relop ty Le e1 e2

  let ge e1 e2 = if phys_equal e1 e2 then Bool.const true else relop ty Ge e1 e2

  let le_u e1 e2 =
    if phys_equal e1 e2 then Bool.const true else relop ty LeU e1 e2

  let ge_u e1 e2 =
    if phys_equal e1 e2 then Bool.const true else relop ty GeU e1 e2

  let to_bool (e : vbool) =
    match view e with
    | Val (Num (I32 i)) -> Bool.const @@ Int32.ne i 0l
    | Ptr _ -> Bool.const true
    | Cvtop (_, OfBool, cond) -> cond
    | _ -> make (Cvtop (ty, ToBool, e))

  let trunc_f32_s x = cvtop ty TruncSF32 x

  let trunc_f32_u x = cvtop ty TruncUF32 x

  let trunc_f64_s x = cvtop ty TruncSF64 x

  let trunc_f64_u x = cvtop ty TruncUF64 x

  let trunc_sat_f32_s _ = assert false

  let trunc_sat_f32_u _ = assert false

  let trunc_sat_f64_s _ = assert false

  let trunc_sat_f64_u _ = assert false

  let reinterpret_f32 x = cvtop ty Reinterpret_float x

  let wrap_i64 x = cvtop ty WrapI64 x

  (* FIXME: This is probably wrong? *)
  let extend_s n x =
    cvtop ty (Sign_extend (32 - n)) (make (Extract (x, n / 8, 0)))
end

module I64 = struct
  let ty = Ty_bitv 64

  let zero = const_i64 0L

  let clz e = unop ty Clz e

  let ctz e = unop ty Ctz e

  let popcnt _ =
    (* TODO *)
    assert false

  let add e1 e2 = binop ty Add e1 e2

  let sub e1 e2 = binop ty Sub e1 e2

  let mul e1 e2 = binop ty Mul e1 e2

  let div e1 e2 = binop ty Div e1 e2

  let unsigned_div e1 e2 = binop ty DivU e1 e2

  let rem e1 e2 = binop ty Rem e1 e2

  let unsigned_rem e1 e2 = binop ty RemU e1 e2

  let logand e1 e2 = binop ty And e1 e2

  let logor e1 e2 = binop ty Or e1 e2

  let logxor e1 e2 = binop ty Xor e1 e2

  let shl e1 e2 = binop ty Shl e1 e2

  let shr_s e1 e2 = binop ty ShrA e1 e2

  let shr_u e1 e2 = binop ty ShrL e1 e2

  let rotl e1 e2 = binop ty Rotl e1 e2

  let rotr e1 e2 = binop ty Rotr e1 e2

  let eq_const e c = relop Ty_bool Eq e (const_i64 c)

  let eq e1 e2 = relop Ty_bool Eq e1 e2

  let ne e1 e2 = relop Ty_bool Ne e1 e2

  let lt e1 e2 = relop ty Lt e1 e2

  let gt e1 e2 = relop ty Gt e1 e2

  let lt_u e1 e2 = relop ty LtU e1 e2

  let gt_u e1 e2 = relop ty GtU e1 e2

  let le e1 e2 = relop ty Le e1 e2

  let ge e1 e2 = relop ty Ge e1 e2

  let le_u e1 e2 = relop ty LeU e1 e2

  let ge_u e1 e2 = relop ty GeU e1 e2

  let of_int32 e = cvtop ty (Sign_extend 32) e

  let to_int32 e = cvtop (Ty_bitv 32) WrapI64 e

  let trunc_f32_s x = cvtop ty TruncSF32 x

  let trunc_f32_u x = cvtop ty TruncUF32 x

  let trunc_f64_s x = cvtop ty TruncSF64 x

  let trunc_f64_u x = cvtop ty TruncUF64 x

  let trunc_sat_f32_s _ = assert false

  let trunc_sat_f32_u _ = assert false

  let trunc_sat_f64_s _ = assert false

  let trunc_sat_f64_u _ = assert false

  let reinterpret_f64 x = cvtop ty Reinterpret_float x

  (* FIXME: This is probably wrong? *)
  let extend_s n x =
    cvtop ty (Sign_extend (64 - n)) (make (Extract (x, n / 8, 0)))

  let extend_i32_s x = cvtop ty (Sign_extend 32) x

  let extend_i32_u x = cvtop ty (Zero_extend 32) x
end

module F32 = struct
  let ty = Ty_fp 32

  let zero = const_f32 Float32.zero

  let abs x = unop ty Abs x

  let neg x = unop ty Neg x

  let sqrt x = unop ty Sqrt x

  let ceil x = unop ty Ceil x

  let floor x = unop ty Floor x

  let trunc x = unop ty Trunc x

  let nearest x = unop ty Nearest x

  let add x y = binop ty Add x y

  let sub x y = binop ty Sub x y

  let mul x y = binop ty Mul x y

  let div x y = binop ty Div x y

  let min x y = binop ty Min x y

  let max x y = binop ty Max x y

  let eq x y = relop ty Eq x y

  let ne x y = relop ty Ne x y

  let lt x y = relop ty Lt x y

  let gt x y = relop ty Gt x y

  let le x y = relop ty Le x y

  let ge x y = relop ty Ge x y

  let convert_i32_s x = cvtop ty ConvertSI32 x

  let convert_i32_u x = cvtop ty ConvertUI32 x

  let convert_i64_s x = cvtop ty ConvertSI64 x

  let convert_i64_u x = cvtop ty ConvertUI64 x

  let demote_f64 x = cvtop ty DemoteF64 x

  let reinterpret_i32 x = cvtop ty Reinterpret_int x

  let of_bits x = cvtop ty Reinterpret_int x

  let to_bits x = cvtop (Ty_bitv 32) Reinterpret_float x

  let copy_sign x y =
    let xi = to_bits (abs x) in
    let yi = to_bits y in
    of_bits @@ I32.logor xi (I32.logand yi (const_i32 Int32.min_int))
end

module F64 = struct
  let ty = Ty_fp 64

  let zero = const_f64 Float64.zero

  let abs x = unop ty Abs x

  let neg x = unop ty Neg x

  let sqrt x = unop ty Sqrt x

  let ceil x = unop ty Ceil x

  let floor x = unop ty Floor x

  let trunc x = unop ty Trunc x

  let nearest x = unop ty Nearest x

  let add x y = binop ty Add x y

  let sub x y = binop ty Sub x y

  let mul x y = binop ty Mul x y

  let div x y = binop ty Div x y

  let min x y = binop ty Min x y

  let max x y = binop ty Max x y

  let eq x y = relop ty Eq x y

  let ne x y = relop ty Ne x y

  let lt x y = relop ty Lt x y

  let gt x y = relop ty Gt x y

  let le x y = relop ty Le x y

  let ge x y = relop ty Ge x y

  let convert_i32_s x = cvtop ty ConvertSI32 x

  let convert_i32_u x = cvtop ty ConvertUI32 x

  let convert_i64_s x = cvtop ty ConvertSI64 x

  let convert_i64_u x = cvtop ty ConvertUI64 x

  let promote_f32 x = cvtop ty PromoteF32 x

  let reinterpret_i64 x = cvtop ty Reinterpret_int x

  let of_bits x = cvtop ty Reinterpret_int x

  let to_bits x = cvtop (Ty_bitv 64) Reinterpret_float x

  let copy_sign x y =
    let xi = to_bits (abs x) in
    let yi = to_bits y in
    of_bits @@ I64.logor xi (I64.logand yi (const_i64 Int64.min_int))
end