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

formalsec / smtml / 175

12 Jul 2024 09:10AM UTC coverage: 50.585% (+1.4%) from 49.176%
175

push

github

filipeom
Test relop simplification

1125 of 2224 relevant lines covered (50.58%)

22.03 hits per line

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

45.45
/lib/expr.ml
1
(***************************************************************************)
2
(* This file is part of the third-party OCaml library `smtml`.             *)
3
(* Copyright (C) 2023-2024 formalsec                                       *)
4
(*                                                                         *)
5
(* This program is free software: you can redistribute it and/or modify    *)
6
(* it under the terms of the GNU General Public License as published by    *)
7
(* the Free Software Foundation, either version 3 of the License, or       *)
8
(* (at your option) any later version.                                     *)
9
(*                                                                         *)
10
(* This program is distributed in the hope that it will be useful,         *)
11
(* but WITHOUT ANY WARRANTY; without even the implied warranty of          *)
12
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *)
13
(* GNU General Public License for more details.                            *)
14
(*                                                                         *)
15
(* You should have received a copy of the GNU General Public License       *)
16
(* along with this program.  If not, see <https://www.gnu.org/licenses/>.  *)
17
(***************************************************************************)
18

19
open Ty
20

21
type t = expr Hc.hash_consed
22

23
and expr =
24
  | Val of Value.t
25
  | Ptr of
26
      { base : int32
27
      ; offset : t
28
      }
29
  | Symbol of Symbol.t
30
  | List of t list
31
  | App : [> `Op of string ] * t list -> expr
32
  | Unop of Ty.t * unop * t
33
  | Binop of Ty.t * binop * t * t
34
  | Triop of Ty.t * triop * t * t * t
35
  | Relop of Ty.t * relop * t * t
36
  | Cvtop of Ty.t * cvtop * t
37
  | Naryop of Ty.t * naryop * t list
38
  | Extract of t * int * int
39
  | Concat of t * t
40

41
module Expr = struct
42
  type t = expr
43

44
  let list_eq (l1 : 'a list) (l2 : 'a list) : bool =
45
    if List.compare_lengths l1 l2 = 0 then List.for_all2 ( == ) l1 l2 else false
×
46

47
  let equal (e1 : expr) (e2 : expr) : bool =
48
    match (e1, e2) with
900✔
49
    | Val v1, Val v2 -> Value.equal v1 v2
730✔
50
    | Ptr { base = b1; offset = o1 }, Ptr { base = b2; offset = o2 } ->
3✔
51
      Int32.equal b1 b2 && o1 == o2
3✔
52
    | Symbol s1, Symbol s2 -> Symbol.equal s1 s2
85✔
53
    | List l1, List l2 -> list_eq l1 l2
4✔
54
    | App (`Op x1, l1), App (`Op x2, l2) -> String.equal x1 x2 && list_eq l1 l2
×
55
    | Unop (t1, op1, e1), Unop (t2, op2, e2) ->
6✔
56
      Ty.equal t1 t2 && op1 = op2 && e1 == e2
6✔
57
    | Binop (t1, op1, e1, e3), Binop (t2, op2, e2, e4) ->
54✔
58
      Ty.equal t1 t2 && op1 = op2 && e1 == e2 && e3 == e4
54✔
59
    | Relop (t1, op1, e1, e3), Relop (t2, op2, e2, e4) ->
6✔
60
      Ty.equal t1 t2 && op1 = op2 && e1 == e2 && e3 == e4
6✔
61
    | Triop (t1, op1, e1, e3, e5), Triop (t2, op2, e2, e4, e6) ->
×
62
      Ty.equal t1 t2 && op1 = op2 && e1 == e2 && e3 == e4 && e5 == e6
×
63
    | Cvtop (t1, op1, e1), Cvtop (t2, op2, e2) ->
12✔
64
      Ty.equal t1 t2 && op1 = op2 && e1 == e2
12✔
65
    | Naryop (t1, op1, l1), Naryop (t2, op2, l2) ->
×
66
      Ty.equal t1 t2 && op1 = op2 && list_eq l1 l2
×
67
    | Extract (e1, h1, l1), Extract (e2, h2, l2) ->
×
68
      e1 == e2 && h1 = h2 && l1 = l2
×
69
    | Concat (e1, e3), Concat (e2, e4) -> e1 == e2 && e3 == e4
×
70
    | _ -> false
×
71

72
  let hash (e : expr) : int =
73
    let h x = Hashtbl.hash x in
3,649✔
74
    match e with
75
    | Val v -> h v
1,465✔
76
    | Ptr { base; offset } -> h (base, offset.tag)
13✔
77
    | Symbol s -> h s
377✔
78
    | List v -> h v
16✔
79
    | App (x, es) -> h (x, es)
×
80
    | Unop (ty, op, e) -> h (ty, op, e.tag)
44✔
81
    | Cvtop (ty, op, e) -> h (ty, op, e.tag)
34✔
82
    | Binop (ty, op, e1, e2) -> h (ty, op, e1.tag, e2.tag)
1,198✔
83
    | Relop (ty, op, e1, e2) -> h (ty, op, e1.tag, e2.tag)
472✔
84
    | Triop (ty, op, e1, e2, e3) -> h (ty, op, e1.tag, e2.tag, e3.tag)
10✔
85
    | Naryop (ty, op, es) -> h (ty, op, es)
×
86
    | Extract (e, hi, lo) -> h (e.tag, hi, lo)
14✔
87
    | Concat (e1, e2) -> h (e1.tag, e2.tag)
6✔
88
end
89

90
module Hc = Hc.Make [@inlined hint] (Expr)
91

92
let equal (hte1 : t) (hte2 : t) = hte1.tag == hte2.tag
199✔
93

94
let hash (hte : t) = hte.tag
4✔
95

96
let make (e : expr) = Hc.hashcons e
2,269✔
97

98
let ( @: ) e _ = make e
×
99

100
let view (hte : t) : expr = hte.node [@@inline]
4,257✔
101

102
let symbol s = make (Symbol s)
14✔
103

104
let mk_symbol s = make (Symbol s)
217✔
105

106
let is_num (e : t) = match view e with Val (Num _) -> true | _ -> false
×
107

108
let rec ty (hte : t) : Ty.t =
109
  match view hte with
45✔
110
  | Val x -> Value.type_of x
×
111
  | Ptr _ -> Ty_bitv 32
×
112
  | Symbol x -> Symbol.type_of x
44✔
113
  | List _ -> Ty_list
×
114
  | App _ -> assert false
115
  | Unop (ty, _, _) -> ty
×
116
  | Binop (ty, _, _, _) -> ty
1✔
117
  | Triop (ty, _, _, _, _) -> ty
×
118
  | Relop (ty, _, _, _) -> ty
×
119
  | Cvtop (ty, _, _) -> ty
×
120
  | Naryop (ty, _, _) -> ty
×
121
  | Extract (_, h, l) -> Ty_bitv ((h - l) * 8)
×
122
  | Concat (e1, e2) -> (
×
123
    match (ty e1, ty e2) with
×
124
    | Ty_bitv n1, Ty_bitv n2 -> Ty_bitv (n1 + n2)
×
125
    | t1, t2 -> Log.err "Invalid concat of (%a) with (%a)" Ty.pp t1 Ty.pp t2 )
×
126

127
let rec is_symbolic (v : t) : bool =
128
  match view v with
×
129
  | Val _ -> false
×
130
  | Symbol _ -> true
×
131
  | Ptr { offset; _ } -> is_symbolic offset
×
132
  | List vs -> List.exists is_symbolic vs
×
133
  | App (_, vs) -> List.exists is_symbolic vs
×
134
  | Unop (_, _, v) -> is_symbolic v
×
135
  | Binop (_, _, v1, v2) -> is_symbolic v1 || is_symbolic v2
×
136
  | Triop (_, _, v1, v2, v3) ->
×
137
    is_symbolic v1 || is_symbolic v2 || is_symbolic v3
×
138
  | Cvtop (_, _, v) -> is_symbolic v
×
139
  | Relop (_, _, v1, v2) -> is_symbolic v1 || is_symbolic v2
×
140
  | Naryop (_, _, vs) -> List.exists is_symbolic vs
×
141
  | Extract (e, _, _) -> is_symbolic e
×
142
  | Concat (e1, e2) -> is_symbolic e1 || is_symbolic e2
×
143

144
let get_symbols (hte : t list) =
145
  let tbl = Hashtbl.create 64 in
×
146
  let rec symbols (hte : t) =
×
147
    match view hte with
×
148
    | Val _ -> ()
×
149
    | Ptr { offset; _ } -> symbols offset
×
150
    | Symbol s -> Hashtbl.replace tbl s ()
×
151
    | List es -> List.iter symbols es
×
152
    | App (_, es) -> List.iter symbols es
×
153
    | Unop (_, _, e1) -> symbols e1
×
154
    | Binop (_, _, e1, e2) ->
×
155
      symbols e1;
156
      symbols e2
×
157
    | Triop (_, _, e1, e2, e3) ->
×
158
      symbols e1;
159
      symbols e2;
×
160
      symbols e3
×
161
    | Relop (_, _, e1, e2) ->
×
162
      symbols e1;
163
      symbols e2
×
164
    | Cvtop (_, _, e) -> symbols e
×
165
    | Naryop (_, _, es) -> List.iter symbols es
×
166
    | Extract (e, _, _) -> symbols e
×
167
    | Concat (e1, e2) ->
×
168
      symbols e1;
169
      symbols e2
×
170
  in
171
  List.iter symbols hte;
172
  Hashtbl.fold (fun k () acc -> k :: acc) tbl []
×
173

174
let negate_relop (hte : t) : (t, string) Result.t =
175
  let e =
×
176
    match view hte with
177
    | Relop (ty, Eq, e1, e2) -> Ok (Relop (ty, Ne, e1, e2))
×
178
    | Relop (ty, Ne, e1, e2) -> Ok (Relop (ty, Eq, e1, e2))
×
179
    | Relop (ty, Lt, e1, e2) -> Ok (Relop (ty, Ge, e1, e2))
×
180
    | Relop (ty, LtU, e1, e2) -> Ok (Relop (ty, GeU, e1, e2))
×
181
    | Relop (ty, Le, e1, e2) -> Ok (Relop (ty, Gt, e1, e2))
×
182
    | Relop (ty, LeU, e1, e2) -> Ok (Relop (ty, GtU, e1, e2))
×
183
    | Relop (ty, Gt, e1, e2) -> Ok (Relop (ty, Le, e1, e2))
×
184
    | Relop (ty, GtU, e1, e2) -> Ok (Relop (ty, LeU, e1, e2))
×
185
    | Relop (ty, Ge, e1, e2) -> Ok (Relop (ty, Lt, e1, e2))
×
186
    | Relop (ty, GeU, e1, e2) -> Ok (Relop (ty, LtU, e1, e2))
×
187
    | _ -> Error "negate_relop: not a relop."
×
188
  in
189
  Result.map make e
190

191
module Pp = struct
192
  open Format
193

194
  let rec pp fmt (hte : t) =
195
    match view hte with
×
196
    | Val v -> Value.pp fmt v
×
197
    | Ptr { base; offset } -> fprintf fmt "(Ptr (i32 %ld) %a)" base pp offset
×
198
    | Symbol s -> Symbol.pp fmt s
×
199
    | List v -> fprintf fmt "(%a)" (pp_print_list pp) v
×
200
    | App (`Op x, v) -> fprintf fmt "(%s %a)" x (pp_print_list pp) v
×
201
    | Unop (ty, op, e) -> fprintf fmt "(%a.%a %a)" Ty.pp ty pp_unop op pp e
×
202
    | Binop (ty, op, e1, e2) ->
×
203
      fprintf fmt "(%a.%a %a %a)" Ty.pp ty pp_binop op pp e1 pp e2
204
    | Triop (ty, op, e1, e2, e3) ->
×
205
      fprintf fmt "(%a.%a %a %a %a)" Ty.pp ty pp_triop op pp e1 pp e2 pp e3
206
    | Relop (ty, op, e1, e2) ->
×
207
      fprintf fmt "(%a.%a %a %a)" Ty.pp ty pp_relop op pp e1 pp e2
208
    | Cvtop (ty, op, e) -> fprintf fmt "(%a.%a %a)" Ty.pp ty pp_cvtop op pp e
×
209
    | Naryop (ty, op, es) ->
×
210
      fprintf fmt "(%a.%a (%a))" Ty.pp ty pp_naryop op (pp_print_list pp) es
×
211
    | Extract (e, h, l) -> fprintf fmt "(extract %a %d %d)" pp e l h
×
212
    | Concat (e1, e2) -> fprintf fmt "(++ %a %a)" pp e1 pp e2
×
213
    | App _ -> assert false
214

215
  let pp_list fmt (es : t list) = pp_print_list ~pp_sep:pp_print_space pp fmt es
×
216

217
  let pp_smt fmt (es : t list) : unit =
218
    let pp_symbols fmt syms =
×
219
      pp_print_list ~pp_sep:pp_print_newline
×
220
        (fun fmt sym ->
221
          let t = Symbol.type_of sym in
×
222
          fprintf fmt "(let-const %a %a)" Symbol.pp sym Ty.pp t )
×
223
        fmt syms
224
    in
225
    let pp_asserts fmt es =
226
      pp_print_list ~pp_sep:pp_print_newline
×
227
        (fun fmt e -> fprintf fmt "(assert @[<h 2>%a@])" pp e)
×
228
        fmt es
229
    in
230
    let syms = get_symbols es in
231
    if List.length syms > 0 then fprintf fmt "%a@\n" pp_symbols syms;
×
232
    if List.length es > 0 then fprintf fmt "%a@\n" pp_asserts es;
×
233
    pp_print_string fmt "(check-sat)"
×
234
end
235

236
let pp = Pp.pp
237

238
let pp_list = Pp.pp_list
239

240
let pp_smt = Pp.pp_smt
241

242
let to_string e = Format.asprintf "%a" pp e
×
243

244
let value (v : Value.t) : t = make (Val v) [@@inline]
1,041✔
245

246
let ptr base offset = make (Ptr { base; offset })
8✔
247

248
let unop' (ty : Ty.t) (op : unop) (hte : t) : t = make (Unop (ty, op, hte))
5✔
249
[@@inline]
250

251
let unop (ty : Ty.t) (op : unop) (hte : t) : t =
252
  match (op, view hte) with
35✔
253
  | _, Val v -> value (Eval.unop ty op v)
24✔
254
  | Not, Unop (_, Not, hte') -> hte'
1✔
255
  | Neg, Unop (_, Neg, hte') -> hte'
1✔
256
  | Head, List (hd :: _) -> hd
1✔
257
  | Tail, List (_ :: tl) -> make (List tl)
1✔
258
  | Reverse, List es -> make (List (List.rev es))
2✔
259
  | Length, List es -> value (Int (List.length es))
1✔
260
  | _ -> unop' ty op hte
4✔
261

262
let binop' (ty : Ty.t) (op : binop) (hte1 : t) (hte2 : t) : t =
263
  make (Binop (ty, op, hte1, hte2))
596✔
264
[@@inline]
265

266
let rec binop ty (op : binop) (hte1 : t) (hte2 : t) : t =
267
  match (op, view hte1, view hte2) with
661✔
268
  | op, Val v1, Val v2 -> value (Eval.binop ty op v1 v2)
60✔
269
  | Sub, Ptr { base = b1; offset = os1 }, Ptr { base = b2; offset = os2 } ->
1✔
270
    if b1 = b2 then binop ty Sub os1 os2 else binop' ty op hte1 hte2
×
271
  | Add, Ptr { base; offset }, _ ->
1✔
272
    ptr base (binop (Ty_bitv 32) Add offset hte2)
1✔
273
  | Sub, Ptr { base; offset }, _ ->
1✔
274
    ptr base (binop (Ty_bitv 32) Sub offset hte2)
1✔
275
  | Rem, Ptr { base; offset }, _ ->
1✔
276
    let rhs = value (Num (I32 base)) in
277
    let addr = binop (Ty_bitv 32) Add rhs offset in
1✔
278
    binop ty Rem addr hte2
1✔
279
  | Add, _, Ptr { base; offset } ->
1✔
280
    ptr base (binop (Ty_bitv 32) Add offset hte1)
1✔
281
  | (Add | Or), Val (Num (I32 0l)), _ -> hte2
×
282
  | (And | Div | DivU | Mul | Rem | RemU), Val (Num (I32 0l)), _ -> hte1
×
283
  | (Add | Or), _, Val (Num (I32 0l)) -> hte1
×
284
  | (And | Mul), _, Val (Num (I32 0l)) -> hte2
×
285
  | Add, Binop (ty, Add, x, { node = Val v1; _ }), Val v2 ->
1✔
286
    let v = value (Eval.binop ty Add v1 v2) in
1✔
287
    binop' ty Add x v
1✔
288
  | Sub, Binop (ty, Sub, x, { node = Val v1; _ }), Val v2 ->
1✔
289
    let v = value (Eval.binop ty Add v1 v2) in
1✔
290
    binop' ty Sub x v
1✔
291
  | Mul, Binop (ty, Mul, x, { node = Val v1; _ }), Val v2 ->
1✔
292
    let v = value (Eval.binop ty Mul v1 v2) in
1✔
293
    binop' ty Mul x v
1✔
294
  | Add, Val v1, Binop (ty, Add, x, { node = Val v2; _ }) ->
1✔
295
    let v = value (Eval.binop ty Add v1 v2) in
1✔
296
    binop' ty Add v x
1✔
297
  | Mul, Val v1, Binop (ty, Mul, x, { node = Val v2; _ }) ->
1✔
298
    let v = value (Eval.binop ty Mul v1 v2) in
1✔
299
    binop' ty Mul v x
1✔
300
  | At, List es, Val (Int n) -> List.nth es n
1✔
301
  | List_append_last, List es, _ -> make (List (es @ [ hte2 ]))
1✔
302
  | List_append, List es, _ -> make (List (hte2 :: es))
1✔
303
  | _ -> binop' ty op hte1 hte2
584✔
304

305
let triop' (ty : Ty.t) (op : triop) (e1 : t) (e2 : t) (e3 : t) : t =
306
  make (Triop (ty, op, e1, e2, e3))
1✔
307
[@@inline]
308

309
let triop ty (op : triop) (e1 : t) (e2 : t) (e3 : t) : t =
310
  match (op, view e1, view e2, view e3) with
7✔
311
  | Ite, Val True, _, _ -> e2
2✔
312
  | Ite, Val False, _, _ -> e3
1✔
313
  | op, Val v1, Val v2, Val v3 -> value (Eval.triop ty op v1 v2 v3)
4✔
314
  | _ -> triop' ty op e1 e2 e3
×
315

316
let relop' (ty : Ty.t) (op : relop) (hte1 : t) (hte2 : t) : t =
317
  make (Relop (ty, op, hte1, hte2))
206✔
318
[@@inline]
319

320
let rec relop ty (op : relop) (hte1 : t) (hte2 : t) : t =
321
  match (op, view hte1, view hte2) with
280✔
322
  | op, Val (App (`Op s1, _)), Val (App (`Op s2, _)) ->
2✔
323
    if String.equal s1 s2 then value (if op = Eq then True else False)
1✔
324
    else relop' ty op hte1 hte2
×
325
  | Eq, Val (App _), Val _ | Eq, Val _, Val (App _) -> value False
×
326
  | Ne, Val (App _), Val _ | Ne, Val _, Val (App _) -> value True
×
327
  | (Ne, Val (Real v), Symbol _ | Ne, Symbol _, Val (Real v))
×
328
    when Float.is_nan v || Float.is_infinite v ->
×
329
    value True
1✔
330
  | (_, Val (Real v), Symbol _ | _, Symbol _, Val (Real v))
×
331
    when Float.is_nan v || Float.is_infinite v ->
×
332
    value False
1✔
333
  | op, Val v1, Val v2 -> value (if Eval.relop ty op v1 v2 then True else False)
28✔
334
  | Eq, Ptr { base = b1; offset = os1 }, Ptr { base = b2; offset = os2 } ->
2✔
335
    if b1 = b2 then relop Ty_bool Eq os1 os2 else value False
1✔
336
  | Ne, Ptr { base = b1; offset = os1 }, Ptr { base = b2; offset = os2 } ->
2✔
337
    if b1 = b2 then relop Ty_bool Ne os1 os2 else value True
1✔
338
  | ( (LtU | LeU | GtU | GeU)
1✔
339
    , Ptr { base = b1; offset = os1 }
340
    , Ptr { base = b2; offset = os2 } ) ->
341
    if b1 = b2 then relop ty op os1 os2
2✔
342
    else
343
      value
2✔
344
        (if Eval.relop ty op (Num (I32 b1)) (Num (I32 b2)) then True else False)
1✔
345
  | op, Val (Num _ as n), Ptr { base; offset = { node = Val (Num _ as o); _ } }
2✔
346
    ->
347
    let base = Eval.binop (Ty_bitv 32) Add (Num (I32 base)) o in
348
    value (if Eval.relop ty op n base then True else False)
1✔
349
  | op, Ptr { base; offset = { node = Val (Num _ as o); _ } }, Val (Num _ as n)
2✔
350
    ->
351
    let base = Eval.binop (Ty_bitv 32) Add (Num (I32 base)) o in
352
    value (if Eval.relop ty op base n then True else False)
1✔
353
  | _, _, _ -> relop' ty op hte1 hte2
205✔
354

355
let cvtop' (ty : Ty.t) (op : cvtop) (hte : t) : t = make (Cvtop (ty, op, hte))
3✔
356
[@@inline]
357

358
let cvtop ty (op : cvtop) (hte : t) : t =
359
  match view hte with
23✔
360
  | Val v -> value (Eval.cvtop ty op v)
21✔
361
  | _ -> cvtop' ty op hte
2✔
362

363
let naryop' (ty : Ty.t) (op : naryop) (es : t list) : t =
364
  make (Naryop (ty, op, es))
×
365
[@@inline]
366

367
let naryop (ty : Ty.t) (op : naryop) (es : t list) : t =
368
  if List.for_all (fun e -> match view e with Val _ -> true | _ -> false) es
×
369
  then
370
    let vs =
7✔
371
      List.map (fun e -> match view e with Val v -> v | _ -> assert false) es
20✔
372
    in
373
    value (Eval.naryop ty op vs)
7✔
374
  else naryop' ty op es
×
375

376
let nland64 (x : int64) (n : int) =
377
  let rec loop x' n' acc =
×
378
    if n' = 0 then Int64.logand x' acc
×
379
    else loop x' (n' - 1) Int64.(logor (shift_left acc 8) 0xffL)
×
380
  in
381
  loop x n 0L
382

383
let nland32 (x : int32) (n : int) =
384
  let rec loop x' n' acc =
×
385
    if n' = 0 then Int32.logand x' acc
×
386
    else loop x' (n' - 1) Int32.(logor (shift_left acc 8) 0xffl)
×
387
  in
388
  loop x n 0l
389

390
let extract' (hte : t) ~(high : int) ~(low : int) : t =
391
  make (Extract (hte, high, low))
7✔
392
[@@inline]
393

394
let extract (hte : t) ~(high : int) ~(low : int) : t =
395
  match view hte with
1✔
396
  | Val (Num (I64 x)) ->
×
397
    let x' = nland64 (Int64.shift_right x (low * 8)) (high - low) in
×
398
    value (Num (I64 x'))
×
399
  | _ -> if high - low = size (ty hte) then hte else extract' hte ~high ~low
×
400

401
let concat' (msb : t) (lsb : t) : t = make (Concat (msb, lsb)) [@@inline]
3✔
402

403
let concat (msb : t) (lsb : t) : t =
404
  match (view msb, view lsb) with
3✔
405
  | ( Extract ({ node = Val (Num (I64 x2)); _ }, h2, l2)
×
406
    , Extract ({ node = Val (Num (I64 x1)); _ }, h1, l1) ) ->
407
    let d1 = h1 - l1 in
408
    let d2 = h2 - l2 in
409
    let x1' = nland64 (Int64.shift_right x1 (l1 * 8)) d1 in
×
410
    let x2' = nland64 (Int64.shift_right x2 (l2 * 8)) d2 in
×
411
    let x = Int64.(logor (shift_left x2' (d1 * 8)) x1') in
×
412
    extract' (value (Num (I64 x))) ~high:(d1 + d2) ~low:0
×
413
  | ( Extract ({ node = Val (Num (I32 x2)); _ }, h2, l2)
×
414
    , Extract ({ node = Val (Num (I32 x1)); _ }, h1, l1) ) ->
415
    let d1 = h1 - l1 in
416
    let d2 = h2 - l2 in
417
    let x1' = nland32 (Int32.shift_right x1 (l1 * 8)) d1 in
×
418
    let x2' = nland32 (Int32.shift_right x2 (l2 * 8)) d2 in
×
419
    let x = Int32.(logor (shift_left x2' (d1 * 8)) x1') in
×
420
    extract' (value (Num (I32 x))) ~high:(d1 + d2) ~low:0
×
421
  | Extract (s1, h, m1), Extract (s2, m2, l) when equal s1 s2 && m1 = m2 ->
3✔
422
    extract' s1 ~high:h ~low:l
3✔
423
  | ( Extract ({ node = Val (Num (I64 x2)); _ }, h2, l2)
×
424
    , Concat
425
        ({ node = Extract ({ node = Val (Num (I64 x1)); _ }, h1, l1); _ }, se) )
426
    when not (is_num se) ->
×
427
    let d1 = h1 - l1 in
×
428
    let d2 = h2 - l2 in
429
    let x1' = nland64 (Int64.shift_right x1 (l1 * 8)) d1 in
×
430
    let x2' = nland64 (Int64.shift_right x2 (l2 * 8)) d2 in
×
431
    let x = Int64.(logor (shift_left x2' (d1 * 8)) x1') in
×
432
    concat' (extract' (value (Num (I64 x))) ~high:(d1 + d2) ~low:0) se
×
433
  | _ -> concat' msb lsb
×
434

435
let rec simplify_expr ?(rm_extract = true) (hte : t) : t =
38✔
436
  match view hte with
44✔
437
  | Val _ | Symbol _ -> hte
5✔
438
  | Ptr { base; offset } -> ptr base (simplify_expr offset)
×
439
  | List es -> make @@ List (List.map simplify_expr es)
×
440
  | App (x, es) -> make @@ App (x, List.map simplify_expr es)
×
441
  | Unop (ty, op, e) ->
1✔
442
    let e = simplify_expr e in
443
    unop ty op e
1✔
444
  | Binop (ty, op, e1, e2) ->
7✔
445
    let e1 = simplify_expr e1 in
446
    let e2 = simplify_expr e2 in
7✔
447
    binop ty op e1 e2
7✔
448
  | Relop (ty, op, e1, e2) ->
1✔
449
    let e1 = simplify_expr e1 in
450
    let e2 = simplify_expr e2 in
1✔
451
    relop ty op e1 e2
1✔
452
  | Triop (ty, op, c, e1, e2) ->
1✔
453
    let c = simplify_expr c in
454
    let e1 = simplify_expr e1 in
1✔
455
    let e2 = simplify_expr e2 in
1✔
456
    triop ty op c e1 e2
1✔
457
  | Cvtop (ty, op, e) ->
1✔
458
    let e = simplify_expr e in
459
    cvtop ty op e
1✔
460
  | Naryop (ty, op, es) ->
×
461
    let es = List.map (simplify_expr ~rm_extract:false) es in
462
    naryop ty op es
×
463
  | Extract (s, high, low) ->
5✔
464
    if not rm_extract then hte else extract s ~high ~low
1✔
465
  | Concat (e1, e2) ->
3✔
466
    let msb = simplify_expr ~rm_extract:false e1 in
467
    let lsb = simplify_expr ~rm_extract:false e2 in
3✔
468
    concat msb lsb
3✔
469

470
let simplify (hte : t) : t =
471
  let rec loop x =
8✔
472
    let simpl_x = simplify_expr x in
17✔
473
    if equal x simpl_x then simpl_x else loop simpl_x
8✔
474
  in
475
  loop hte
476

477
module Bool = struct
478
  let of_val = function
479
    | Val True -> Some true
×
480
    | Val False -> Some false
×
481
    | _ -> None
×
482

483
  let true_ = value True
28✔
484

485
  let false_ = value False
28✔
486

487
  let to_val b = if b then true_ else false_
×
488

489
  let v b = to_val b [@@inline]
×
490

491
  let not (b : t) =
492
    let bexpr = view b in
×
493
    match of_val bexpr with
×
494
    | Some b -> to_val (not b)
×
495
    | None -> (
×
496
      match bexpr with
497
      | Unop (Ty_bool, Not, cond) -> cond
×
498
      | _ -> unop Ty_bool Not b )
×
499

500
  let equal (b1 : t) (b2 : t) =
501
    match (view b1, view b2) with
×
502
    | Val True, Val True | Val False, Val False -> true_
×
503
    | _ -> relop Ty_bool Eq b1 b2
×
504

505
  let distinct (b1 : t) (b2 : t) =
506
    match (view b1, view b2) with
×
507
    | Val True, Val False | Val False, Val True -> true_
×
508
    | _ -> relop Ty_bool Ne b1 b2
×
509

510
  let and_ (b1 : t) (b2 : t) =
511
    match (of_val (view b1), of_val (view b2)) with
×
512
    | Some true, _ -> b2
×
513
    | _, Some true -> b1
×
514
    | Some false, _ | _, Some false -> false_
×
515
    | _ -> binop Ty_bool And b1 b2
×
516

517
  let or_ (b1 : t) (b2 : t) =
518
    match (of_val (view b1), of_val (view b2)) with
×
519
    | Some false, _ -> b2
×
520
    | _, Some false -> b1
×
521
    | Some true, _ | _, Some true -> true_
×
522
    | _ -> binop Ty_bool Or b1 b2
×
523

524
  let ite (c : t) (r1 : t) (r2 : t) = triop Ty_bool Ite c r1 r2
×
525
end
526

527
module Make (T : sig
528
  type elt
529

530
  val ty : Ty.t
531

532
  val num : elt -> Num.t
533
end) =
534
struct
535
  let v i = value (Num (T.num i))
24✔
536

537
  let sym x = mk_symbol Symbol.(x @: T.ty)
12✔
538

539
  let ( ~- ) e = unop T.ty Neg e
×
540

541
  let ( = ) e1 e2 = relop Ty_bool Eq e1 e2
×
542

543
  let ( != ) e1 e2 = relop Ty_bool Ne e1 e2
×
544

545
  let ( > ) e1 e2 = relop T.ty Gt e1 e2
2✔
546

547
  let ( >= ) e1 e2 = relop T.ty Ge e1 e2
×
548

549
  let ( < ) e1 e2 = relop T.ty Lt e1 e2
5✔
550

551
  let ( <= ) e1 e2 = relop T.ty Le e1 e2
×
552
end
553

554
module Bitv = struct
555
  module I8 = Make (struct
556
    type elt = int
557

558
    let ty = Ty_bitv 8
559

560
    let num i = Num.I8 i
3✔
561
  end)
562

563
  module I32 = Make (struct
564
    type elt = int32
565

566
    let ty = Ty_bitv 32
567

568
    let num i = Num.I32 i
13✔
569
  end)
570

571
  module I64 = Make (struct
572
    type elt = int64
573

574
    let ty = Ty_bitv 64
575

576
    let num i = Num.I64 i
1✔
577
  end)
578
end
579

580
module Fpa = struct
581
  module F32 = struct
582
    include Make (struct
583
      type elt = float
584

585
      let ty = Ty_fp 32
586

587
      let num f = Num.F32 (Int32.bits_of_float f)
6✔
588
    end)
589

590
    (* Redeclare equality due to incorrect theory annotation *)
591
    let ( = ) e1 e2 = relop (Ty_fp 32) Eq e1 e2
3✔
592

593
    let ( != ) e1 e2 = relop (Ty_fp 32) Ne e1 e2
×
594
  end
595

596
  module F64 = struct
597
    include Make (struct
598
      type elt = float
599

600
      let ty = Ty_fp 64
601

602
      let num f = Num.F64 (Int64.bits_of_float f)
1✔
603
    end)
604

605
    (* Redeclare equality due to incorrect theory annotation *)
606
    let ( = ) e1 e2 = relop (Ty_fp 64) Eq e1 e2
1✔
607

608
    let ( != ) e1 e2 = relop (Ty_fp 64) Ne e1 e2
×
609
  end
610
end
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

© 2025 Coveralls, Inc