Source file bitwise.ml
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
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
module In_bits = Units.In_bits
let pretty_detailed = true
module Quadrivalent = Lattices.Quadrivalent
module Make (Sub : Sig.BASE) = struct
let name() = "Bitwise(" ^ (Sub.name()) ^ ")";;
let unique_id() = Sig.Fresh_id.fresh @@ name();;
(** To represent values, we could use an array where each bit would
be a bit in another variable, but this would be slow for most
operation. So, we use a list of "parts" that group these bits,
and the information is complemented with the known 0 bits and
known 1 bits informat that we query from Sub. *)
type binary_part = { size:In_bits.t; index:In_bits.t; oldsize:In_bits.t; value:Sub.binary }
module Part = struct
let pretty ctx fmt {size;index;oldsize;value} =
if index == In_bits.zero && size == oldsize
then Format.fprintf fmt "(%a)<%d>" (Sub.binary_pretty ~size ctx) value (size:>int)
else Format.fprintf fmt "(%a)[%d..+%d]" (Sub.binary_pretty ~size ctx) value (index:>int) (size:>int)
let zero ctx ~size = { size; index=In_bits.zero; oldsize=size;
value=Sub.Binary_Forward.biconst ~size Z.zero ctx}
let ones ctx ~size =
{ size; index=In_bits.zero; oldsize=size;
value = Sub.Binary_Forward.biconst ~size (Z.extract Z.minus_one 0 (size:>int)) ctx }
let ctx {size;index;oldsize;value} =
if size = oldsize then value
else Sub.Binary_Forward.bextract ~size ~index ~oldsize ctx value
let to_singleton ctx {size;index;oldsize;value} =
let bin = Sub.Binary_Forward.bextract ~size ~index ~oldsize ctx value in
Sub.Query.binary ~size ctx bin |> Sub.Query.Binary_Lattice.is_singleton ~size
let from_value ~size value = {size;index=In_bits.zero;oldsize=size;value}
end
module Parts = struct
type t = binary_part list;;
let cut_start ~index p =
let rec loop i = function
| [] -> assert false
| { size; _ }::rest when In_bits.(i + size <= index) -> loop In_bits.(i + size) rest
| { size=sizee; index=indexe; oldsize; value }::rest as l ->
if i == index then l
else
let removed_size = In_bits.(index - i) in
{ size=In_bits.(sizee-removed_size); index=In_bits.(indexe+removed_size); oldsize; value }::rest
in loop In_bits.zero p
;;
let cut_end ~size p =
let rec loop i = function
| [] -> assert false
| hd::tl when In_bits.(i + hd.size < size) -> hd::(loop In_bits.(i + hd.size) tl)
| hd::_ when In_bits.(i + hd.size) = size -> [hd]
| { size=sizee; index; oldsize; value }::_ ->
let removed_size = In_bits.(i + sizee - size) in
[{ size=In_bits.(sizee-removed_size); index; oldsize; value }]
in loop In_bits.zero p
;;
let ~index ~size ~oldsize p =
let p =
if index == In_bits.zero then p
else cut_start ~index p
in
let p =
if In_bits.(index + size) == oldsize then p
else cut_end ~size p
in
p
;;
let append a b = List.append a b;;
let append ctx a b =
match b with
| [] -> assert false
| hdb::tlb -> begin
let rec loop = function
| [] -> b
| [lasta] -> begin
match lasta,hdb with
| { size=sizea; index=indexa; oldsize=oldsizea; value=valuea },
{ size=sizeb; index=indexb; oldsize=oldsizeb; value=valueb }
when In_bits.(indexa + sizea == indexb) && Sub.Binary.equal valuea valueb ->
assert(oldsizea == oldsizeb);
{ size=In_bits.(sizea+sizeb); index=indexa; oldsize=oldsizea; value=valuea }::tlb
| { size=sizea; _ },{size=sizeb; _ } -> begin
match Part.to_singleton ctx lasta,Part.to_singleton ctx hdb with
| Some csta, Some cstb ->
let size = In_bits.(sizea + sizeb) in
let zvalue = Operator.Concrete.Bitvector_Interp.bconcat ~size1:sizeb ~size2:sizea cstb csta in
let value = Sub.Binary_Forward.biconst ~size zvalue ctx in
(Part.from_value ~size value)::tlb
| _ -> lasta::hdb::tlb
end
end
| hd::tl -> hd::(loop tl)
in loop a
end
;;
let prepend_zero ~size ctx p = append ctx [(Part.zero ~size ctx)] p;;
let append_zero ~size ctx p = append ctx p [(Part.zero ~size ctx)];;
let chop_last l =
let rec loop acc = function
| [] -> assert false
| [x] -> List.rev acc, x
| hd :: tl -> loop (hd :: acc) tl
in loop [] l
let signed_extend ~size ~oldsize ctx p =
let beginning, { size=s_last; value; _ } = chop_last p in
let zeroes, ones = Sub.Query.(binary ~size:s_last ctx value |> Binary_Lattice.to_known_bits ~size:s_last) in
if not (Z.testbit zeroes ((s_last:>int)-1)) then
append_zero ~size:In_bits.(size - oldsize) ctx p
else if Z.testbit ones ((s_last:>int)-1) then
append ctx p [Part.ones ~size:In_bits.(size - oldsize) ctx]
else
let s = In_bits.(size - oldsize + s_last) in
append ctx beginning [Part.from_value ~size:s (Sub.Binary_Forward.bsext ~size:s ~oldsize:s_last ctx value)]
let fold2 ctx f acc pa pb =
let rec loop acc pa pb = match pa,pb with
| [],[] -> acc
| [], _ | _, [] -> acc
| ({size=sizea;index=indexa;oldsize=oldsizea;value=valuea} as pa)::tla,
({size=sizeb;index=indexb;oldsize=oldsizeb;value=valueb} as pb)::tlb ->
if(sizea == sizeb) then
let acc = f ~size:sizea acc pa pb in
loop acc tla tlb
else if(sizea < sizeb) then
let bb = {size=sizea; index=indexb; oldsize=oldsizeb; value=valueb} in
let acc = f ~size:sizea acc pa bb in
loop acc tla ({size=In_bits.(sizeb-sizea);index=In_bits.(indexb+sizea);oldsize=oldsizeb;value=valueb}::tlb)
else
let ba = {size=sizeb; index=indexa; oldsize=oldsizea; value=valuea} in
let acc = f ~size:sizeb acc ba pb in
loop acc ({size=In_bits.(sizea-sizeb);index=In_bits.(indexa+sizeb);oldsize=oldsizea;value=valuea}::tla) tlb
in loop acc pa pb
type bits =
| Zeroes of In_bits.t (** size. *)
| Ones of In_bits.t (** size. *)
| Unknown of binary_part
let pretty_bits ctx fmt =
let open Format in function
| Zeroes s -> fprintf fmt "00..0<%d>" (s:>int)
| Ones s -> fprintf fmt "11..1<%d>" (s:>int)
| Unknown p -> Part.pretty ctx fmt p
let decompose_using_known_bits ~size ctx part =
let {size;index;oldsize;value} = part in
let sub = Part.do_extract ctx part in
let zeroes, ones = Sub.Query.Binary_Lattice.to_known_bits ~size @@ Sub.Query.binary ~size ctx sub in
let rec loop acc cur (i:int) =
if i >= (size:>int) then List.rev (cur :: acc)
else match Z.testbit zeroes i, Z.testbit ones i, cur with
| false, true, _ -> raise Sig.Bottom
| false, _, Zeroes s -> loop acc (Zeroes In_bits.(s+one)) (i+1)
| false, _, _ -> loop (cur :: acc) (Zeroes In_bits.one) (i+1)
| _, true, Ones s -> loop acc (Ones In_bits.(s+one)) (i+1)
| _, true, _ -> loop (cur :: acc) (Ones In_bits.one) (i+1)
| true, false, Unknown e -> loop acc (Unknown{e with size=In_bits.(e.size+one)}) (i+1)
| true, false, _ -> loop (cur :: acc) (Unknown{size=In_bits.one;index=In_bits.(index+ of_int i);oldsize;value}) (i+1)
in
loop []
(if not (Z.testbit zeroes 0)
then Zeroes In_bits.one
else if Z.testbit ones 0
then Ones In_bits.one
else Unknown {size=In_bits.one;index;oldsize;value})
1
let fold2_bits ctx f acc pa pb =
let split size_fst = function
| Zeroes size -> Zeroes size_fst, Zeroes In_bits.(size - size_fst)
| Ones size -> Ones size_fst, Ones In_bits.(size - size_fst)
| Unknown {size;index;oldsize;value} ->
Unknown {size=size_fst; index; oldsize; value},
Unknown {size=In_bits.(size-size_fst); index=In_bits.(index+size_fst); oldsize; value}
in
let rec loop acc pa pb = match pa,pb with
| [],[] -> acc
| [],_ | _,[] -> assert false
| (( Unknown{size=sizea;_}
| Zeroes sizea
| Ones sizea) as pa) :: tla,
(( Unknown{size=sizeb;_}
| Zeroes sizeb
| Ones sizeb) as pb) :: tlb ->
if sizea = sizeb then
let acc = f ctx ~size:sizea acc pa pb in
loop acc tla tlb
else if sizea < sizeb then
let fst_pb, rest_pb = split sizea pb in
let acc = f ctx ~size:sizea acc pa fst_pb in
loop acc tla (rest_pb :: tlb)
else
let fst_pa, rest_pa = split sizeb pa in
let acc = f ctx ~size:sizeb acc fst_pa pb in
loop acc (rest_pa :: tla) tlb
in
loop acc pa pb
let fold2_known_bits ctx f acc pa pb =
fold2 ctx (fun ~size acc pa pb ->
let bitsa = decompose_using_known_bits ~size ctx pa in
let bitsb = decompose_using_known_bits ~size ctx pb in
fold2_bits ctx f acc bitsa bitsb
) acc pa pb
end
type binary_ = { complete: Sub.binary;
parts: Parts.t
}
module Binary = struct
type t = binary_;;
let equal x y = Sub.Binary.equal x.complete y.complete
let compare x y = Sub.Binary.compare x.complete y.complete
let hash _ = assert false
let pretty pp x =
Sub.Binary.pretty pp x.complete
let lift0 ~size x = { complete = x; parts = [{size;oldsize=size;index=In_bits.zero;value=x}]}
let lift1 ~size f x =
{ complete = f ~size x.complete;
parts = List.map (function
| x -> { x with value=f ~size:x.oldsize x.value }
) x.parts }
let lift2 ~size ctx f x y =
let x = match x.parts with
| [p] -> Part.do_extract ctx p
| _ -> x.complete
in
let y = match y.parts with
| [p] -> Part.do_extract ctx p
| _ -> y.complete
in
f ~size ctx x y
let lift2_pred ~size ctx f x y =
let with_parts = lift2 ~size ctx f x y in
match Sub.query_boolean ctx with_parts with
| Quadrivalent.True | Quadrivalent.False | Quadrivalent.Bottom -> with_parts
| _ -> f ~size ctx x.complete y.complete
;;
end
module Types = struct
type binary = Binary.t
type enum = Sub.enum
type boolean = Sub.boolean
end
include Types
module Boolean = Sub.Boolean
module Enum = Sub.Enum
module Context = Sub.Context
open Context
let root_context = Sub.root_context
let context_pretty = Sub.context_pretty
let mu_context_open = Sub.mu_context_open
let assume = Sub.assume
let binary_empty ~size ctx = { parts = []; complete = Sub.binary_empty ~size ctx }
let boolean_empty = Sub.boolean_empty
let enum_empty = Sub.enum_empty
module Boolean_Forward = Sub.Boolean_Forward
module Enum_Forward = Sub.Enum_Forward
let binary_pretty ~size ctx fmt (x : binary) =
Sub.binary_pretty ~size ctx fmt x.complete
module Binary_Forward = struct
module SBF = Sub.Binary_Forward;;
let bofbool ~size ctx b =
SBF.bofbool ~size ctx b |> Binary.lift0 ~size
let bchoose ~size choice ctx x = SBF.bchoose ~size choice ctx x.complete |> Binary.lift0 ~size
let valid ~size _ = assert false
let bindex ~size _ = assert false
let valid_ptr_arith ~size arith ctx a b =
Sub.Binary_Forward.valid_ptr_arith ~size arith ctx a.complete b.complete
let biconst ~size ctx k = Binary.lift0 ~size @@ SBF.biconst ~size ctx k;;
let buninit ~size ctx = Binary.lift0 ~size @@ SBF.buninit ~size ctx;;
let bisle ~size ctx a b = Binary.lift2_pred ~size ctx SBF.bisle a b
let biule ~size ctx a b = Binary.lift2_pred ~size ctx SBF.biule a b
let bisub ~size ~flags ctx a b = Binary.lift0 ~size @@ SBF.bisub ~size ~flags ctx a.complete b.complete
let bimul ~size ~flags ctx a b = Binary.lift0 ~size @@ SBF.bimul ~size ~flags ctx a.complete b.complete
let bisdiv ~size ctx a b = Binary.lift0 ~size @@ SBF.bisdiv ~size ctx a.complete b.complete
let biudiv ~size ctx a b = Binary.lift0 ~size @@ SBF.biudiv ~size ctx a.complete b.complete
let bismod ~size ctx a b = Binary.lift0 ~size @@ SBF.bismod ~size ctx a.complete b.complete
let biumod ~size ctx a b = Binary.lift0 ~size @@ SBF.biumod ~size ctx a.complete b.complete
let bconcat ~size1 ~size2 ctx b1 b2 =
let complete = SBF.bconcat ~size1 ~size2 ctx b1.complete b2.complete in
let parts = Parts.append ctx b2.parts b1.parts in
let res = { complete; parts; } in
res
let buext ~size ~oldsize ctx x =
{ complete = SBF.buext ~size ~oldsize ctx x.complete;
parts = Parts.append_zero ~size:In_bits.(size-oldsize) ctx x.parts;
}
;;
let bsext ~size ~oldsize ctx x =
{ complete = SBF.bsext ~size ~oldsize ctx x.complete;
parts = Parts.signed_extend ~size ~oldsize ctx x.parts }
let ~size ~index ~oldsize ctx x =
let res =
{ parts = Parts.extract ~index ~size ~oldsize x.parts;
complete = SBF.bextract ~size ~index ~oldsize ctx x.complete
}
in
res
let bshl ~size ~flags ctx x y =
let complete = SBF.bshl ~size ~flags ctx x.complete y.complete in
match Sub.Query.Binary_Lattice.is_singleton ~size @@ Sub.Query.binary ~size ctx y.complete with
| None -> Binary.lift0 ~size complete
| Some y ->
let parts = Parts.prepend_zero ~size:In_bits.(of_int @@ Z.to_int y) ctx x.parts in
let parts = Parts.cut_end ~size parts in
{ complete; parts }
;;
let blshr ~size ctx x y =
let complete = SBF.blshr ~size ctx x.complete y.complete in
match Sub.Query.Binary_Lattice.is_singleton ~size @@ Sub.Query.binary ~size ctx y.complete with
| None -> Binary.lift0 ~size complete
| Some y ->
let yi = Z.to_int y |> In_bits.of_int in
assert In_bits.(zero <= yi);
if yi == In_bits.zero then x else
let parts = Parts.append_zero ~size:yi ctx x.parts in
let parts = Parts.cut_start ~index:yi parts in
{ complete; parts }
let bashr ~size ctx x y =
let complete = SBF.bashr ~size ctx x.complete y.complete in
match Sub.Query.(Binary_Lattice.is_singleton ~size @@ binary ~size ctx y.complete) with
| None -> Binary.lift0 ~size complete
| Some y ->
let yi = Z.to_int y |> In_bits.of_int in
let beginning, {size=s_last;value;_} = Parts.chop_last x.parts in
let zeroes,ones = Sub.Query.(Binary_Lattice.to_known_bits ~size:s_last @@
binary ~size:s_last ctx value) in
let parts =
if not (Z.testbit zeroes ((s_last:>int)-1)) then
let parts = Parts.append_zero ~size:yi ctx x.parts in
Parts.cut_start ~index:yi parts
else if Z.testbit ones ((s_last:>int)-1) then
let parts = Parts.append ctx x.parts [Part.ones ctx ~size:yi] in
Parts.cut_start ~index:yi parts
else
let new_sz_last = In_bits.(s_last+yi) in
let to_append = SBF.bsext ~size:new_sz_last ~oldsize:s_last ctx value in
let parts = Parts.append ctx beginning [Part.from_value ~size:new_sz_last to_append] in
Parts.cut_start ~index:yi parts
in
{ complete; parts }
let beq ~size ctx a b =
Parts.fold2 ctx (fun ~size acc a b ->
Sub.Boolean_Forward.(&&) ctx acc @@
Sub.Binary_Forward.beq ~size ctx (Part.do_extract ctx a) (Part.do_extract ctx b)
) (Sub.Boolean_Forward.true_ ctx) a.parts b.parts
;;
let beq ~size ctx a b =
let with_parts = beq ~size ctx a b in
match Sub.query_boolean ctx with_parts with
| Quadrivalent.True | Quadrivalent.False | Quadrivalent.Bottom -> with_parts
| _ -> Sub.Binary_Forward.beq ~size ctx a.complete b.complete;;
let of_bits ctx = function
| Parts.Zeroes size -> Part.from_value ~size @@ SBF.biconst ~size Z.zero ctx
| Parts.Ones size -> Part.from_value ~size @@ SBF.biconst ~size (Z.extract Z.minus_one 0 (size:>int)) ctx
| Parts.Unknown part -> part
let or_bits ~size ctx a b = match a,b with
| Parts.Zeroes _, _ -> of_bits ctx b
| _, Parts.Zeroes _ -> of_bits ctx a
| Parts.Ones _, _ -> of_bits ctx a
| _, Parts.Ones _ -> of_bits ctx b
| Parts.(Unknown pa, Unknown pb) ->
Part.from_value ~size @@
SBF.bor ~size ctx (Part.do_extract ctx pa) (Part.do_extract ctx pb)
let bor' complete ~size ctx a b =
let res = try
let parts = Parts.fold2_known_bits ctx (fun ctx ~size acc ba bb ->
let slice = or_bits ~size ctx ba bb in
Parts.append ctx acc [slice]
) [] a.parts b.parts in
{ parts; complete }
with Sig.Bottom -> binary_empty ~size ctx in
res
let bor ~size ctx a b =
let complete = SBF.bor ~size ctx a.complete b.complete in
bor' complete ~size ctx a b
;;
let and_bits ~size ctx a b = match a,b with
| Parts.Zeroes _, _ -> of_bits ctx a
| _, Parts.Zeroes _ -> of_bits ctx b
| Parts.Ones _, _ -> of_bits ctx b
| _, Parts.Ones _ -> of_bits ctx a
| Parts.(Unknown pa, Unknown pb) ->
Part.from_value ~size @@
SBF.band ~size ctx (Part.do_extract ctx pa) (Part.do_extract ctx pb)
let band ~size ctx a b =
try let parts = Parts.fold2_known_bits ctx (fun ctx ~size acc ba bb ->
let slice = and_bits ~size ctx ba bb in
Parts.append ctx acc [slice]
) [] a.parts b.parts in
{ parts; complete = SBF.band ~size ctx a.complete b.complete }
with Sig.Bottom -> binary_empty ~size ctx
let xor_bits ~size ctx a b = match a,b with
| Parts.Zeroes _, _ -> of_bits ctx b
| _, Parts.Zeroes _ -> of_bits ctx a
| Parts.Ones _, Parts.Ones _ ->
Part.zero ctx ~size
| Parts.(Unknown p, Ones _) | Parts.(Ones _, Unknown p) ->
let pb = Part.ones ctx ~size in
Part.from_value ~size @@
SBF.bxor ~size ctx (Part.do_extract ctx p) (Part.do_extract ctx pb)
| Parts.(Unknown pa, Unknown pb) ->
Part.from_value ~size @@
SBF.bxor ~size ctx (Part.do_extract ctx pa) (Part.do_extract ctx pb)
let bxor ~size ctx a b =
try let parts = Parts.fold2_known_bits ctx (fun ctx ~size acc ba bb ->
let slice = xor_bits ~size ctx ba bb in
Parts.append ctx acc [slice]
) [] a.parts b.parts in
{ parts; complete = SBF.bxor ~size ctx a.complete b.complete }
with Sig.Bottom -> binary_empty ~size ctx
let biadd ~size ~flags ctx a b =
let exception Exit in
let orable = try Parts.fold2 ctx (fun ~size acc pa pb ->
let za,oa = Sub.Query.(binary ~size ctx (Part.do_extract ctx pa) |> Binary_Lattice.to_known_bits ~size) in
let zb,ob = Sub.Query.(binary ~size ctx (Part.do_extract ctx pb) |> Binary_Lattice.to_known_bits ~size) in
if (Z.equal Z.zero @@ Z.(land) za zb)
then true
else raise Exit) true a.parts b.parts
with Exit -> false
in
if orable then
let complete = SBF.biadd ~size ~flags ctx a.complete b.complete in
bor' complete ~size ctx a b
else
Binary.lift0 ~size @@ SBF.biadd ~size ~flags ctx a.complete b.complete
let bshift ~size ~offset ~max ctx x =
let offset = biconst ~size (Z.of_int offset) ctx in
biadd ~size ~flags:(Operator.Flags.Biadd.pack ~nsw:false ~nuw:false ~nusw:false) ctx x offset
end
let binary_unknown ~size ctx = Binary.lift0 ~size @@ Sub.binary_unknown ~size ctx;;
let binary_unknown_typed ~size ctx typ = Binary.lift0 ~size @@ Sub.binary_unknown_typed ~size ctx typ;;
let boolean_unknown = Sub.boolean_unknown
let enum_unknown = Sub.enum_unknown
let union = Sub.union
type 'elt higher = {subf: 'tl. Sub.Context.t -> 'elt -> Sub.Context.t -> 'elt -> 'tl
Sub.Context.in_acc -> ('elt,'tl) Sub.Context.result } [@@unboxed]
let serialize (type elt) (type c)
{subf} ctxa a ctxb b (included, (acc : c in_tuple)) : (elt,c) result =
let Result (included, in_tup, deserialize) = subf ctxa a ctxb b (included, acc) in
Result (included, in_tup, deserialize)
let serialize_boolean ctxa a ctxb b acc = serialize {subf=Sub.serialize_boolean} ctxa a ctxb b acc
let serialize_enum ctxa a ctxb b acc = serialize {subf=Sub.serialize_enum} ctxa a ctxb b acc
let serialize_binary ~widens ~size ctxa a ctxb b (included, acc) =
let Result (included, in_tup, deserialize) = Sub.serialize_binary ~widens ~size ctxa a.complete ctxb b.complete (included, acc) in
Result (included, in_tup, (fun ctx out_tup ->
let res, out_tup = deserialize ctx out_tup in
Binary.lift0 ~size res,out_tup))
;;
let typed_nondet2 (type c) ctxa ctxb (acc : c in_tuple) =
Sub.typed_nondet2 ctxa ctxb acc
let nondet_same_context = Sub.nondet_same_context
let typed_fixpoint_step (type c) ~iteration ~init ~arg ~body (included, (acc : c in_tuple)) : bool * (close:bool -> (c out_tuple * Context.t)) =
let bool,continuef = Sub.typed_fixpoint_step ~iteration ~init ~arg ~body (included, acc) in
bool,fun ~close -> continuef ~close
let widened_fixpoint_step = Sub.widened_fixpoint_step
module Query = struct
include Sub.Query
let binary ~size ctx x =
binary ~size ctx x.complete
end
let query_boolean = Sub.query_boolean
let boolean_pretty = Sub.boolean_pretty
let enum_pretty = Sub.enum_pretty
let binary_is_empty ~size ctx x = x.parts = []
let integer_is_empty _ = assert false
let boolean_is_empty _ = assert false
let satisfiable = Sub.satisfiable
end