2 (** This module describes the values manipulated by high level
6 let error_prefix = "Value"
7 let error s = Error.global_error error_prefix s
12 (** The representation of values depends on the size of integers and the size of
15 (** This is the signature of the parameter module. *)
17 module type DATA_SIZE =
23 (** This is the signature of the module that provides types and functions to
32 (** The type of values. A value may be: a bounded integer, a chunk of an
33 address (exactly an address when they have the same size as a machine
34 register), or undefined. *)
37 val compare : t -> t -> int
38 val equal : t -> t -> bool
39 val eq : t -> t -> bool
41 val to_string : t -> string
43 (* The functions of this module may raise a Failure exception when
44 trying to convert them to their various representation. *)
46 val is_int : t -> bool
50 val of_int_repr : IntValue.int_repr -> t
51 val to_int_repr : t -> IntValue.int_repr
53 val of_bool : bool -> t
54 val to_bool : t -> bool
59 val is_true : t -> bool
60 val is_false : t -> bool
63 (** The cast operations below returns the undefined value for non-integer
64 values. For integer values, it will return the integer value that
65 represents the same quantity, but using every bits (sign or zero
66 extension) of an integer value. For example, the function [cast8unsigned]
67 should be read as "cast from an 8 bits unsigned integer". *)
68 val cast8unsigned : t -> t
69 val cast8signed : t -> t
70 val cast16unsigned : t -> t
71 val cast16signed : t -> t
74 (** [zero_ext v n m] performs a zero extension on [v] where [n] bytes are
75 significant to a value where [m] bytes are significant. *)
76 val zero_ext : t -> int -> int -> t
77 (** [sign_ext v n m] performs a sign extension on [v] where [n] bytes are
78 significant to a value where [m] bytes are significant. *)
79 val sign_ext : t -> int -> int -> t
81 (** Integer opposite *)
83 (** Boolean negation *)
92 (** [add_and_of v1 v2] returns the sum of [v1] and [v2], and whether this sum
94 val add_and_of : t -> t -> (t * t)
96 (** [add_of v1 v2] returns the [1] value if the sum of [v1] and [v2]
97 overflows, and [0] otherwise. *)
98 val add_of : t -> t -> t
99 (** [sub_and_uf v1 v2] returns the substraction of [v1] and [v2], and whether
100 this substraction underflows. *)
101 val sub_and_uf : t -> t -> (t * t)
102 val sub : t -> t -> t
103 (** [sub_uf v1 v2] returns the [1] value if the substraction of [v1] and [v2]
104 underflows, and [0] otherwise. *)
105 val sub_uf : t -> t -> t
106 val mul : t -> t -> t
107 val div : t -> t -> t
108 val divu : t -> t -> t
109 val modulo : t -> t -> t
110 val modulou : t -> t -> t
111 val and_op : t -> t -> t
112 val or_op : t -> t -> t
113 val xor : t -> t -> t
114 val shl : t -> t -> t
115 val shr : t -> t -> t
116 val shru : t -> t -> t
118 (** Signed comparisions *)
119 val cmp_eq : t -> t -> t
120 val cmp_ne : t -> t -> t
121 val cmp_lt : t -> t -> t
122 val cmp_ge : t -> t -> t
123 val cmp_le : t -> t -> t
124 val cmp_gt : t -> t -> t
126 (** Unsigned comparisions *)
127 val cmp_eq_u : t -> t -> t
128 val cmp_ne_u : t -> t -> t
129 val cmp_lt_u : t -> t -> t
130 val cmp_ge_u : t -> t -> t
131 val cmp_le_u : t -> t -> t
132 val cmp_gt_u : t -> t -> t
134 (** A chunk is a part of a value that has the size of a memory cell. *)
137 val string_of_chunk : chunk -> string
138 val undef_byte : chunk
139 val is_undef_byte : chunk -> bool
141 (** [break v] cuts [v] in chunks that each fits into a memory cell. In the
142 resulting list, the first element is the low bits, and the last is the
143 high bits (little endian representation). *)
144 val break : t -> chunk list
145 (** [merge l] creates the value where the first element of [l] is its low
146 bits, etc, and the last element of [l] is its high bits (little endian
148 val merge : chunk list -> t
150 (** Addresses from the memory point of view. *)
152 (** Some architectures have pointers bigger than integers. In this case, only
153 a chunk of pointer can fit into a machine register. Thus, an address is
154 represented by several values (little endian representation). *)
156 type address = t list
157 val string_of_address : address -> string
160 (** Addresses from the memory point of view. Only use the functions below in
163 (** Addresses are represented by a block, i.e. a base address, and an offset
164 from this block. Both blocks and offsets are represented using bounded
166 module Block : IntValue.S
167 module Offset : IntValue.S
170 val string_of_mem_address : mem_address -> string
172 val is_mem_address : address -> bool
174 val of_mem_address : mem_address -> address
175 val to_mem_address : address -> mem_address
176 val make_mem_address : Block.t -> Offset.t -> mem_address
177 val decompose_mem_address : mem_address -> Block.t * Offset.t
178 val block_of_address : address -> Block.t
179 val offset_of_address : address -> Offset.t
181 val change_address_offset : address -> Offset.t -> address
182 val add_address : address -> Offset.t -> address
183 val eq_address : address -> address -> bool
188 module Make (D : DATA_SIZE) =
191 let int_size = D.int_size
192 let ptr_size = D.ptr_size
194 module BoundedInt = IntValue.Make (struct let size = D.int_size end)
196 (* Integer values. *)
197 module ValInt = BoundedInt
199 (* Addresses are represented by a block, i.e. a base address, and an offset
200 from this block. Both blocks and offsets are represented using bounded
201 integers. However, values must fit into a machine register. Some
202 architectures, like the 8051, have addresses bigger than registers. Pointer
203 values will only represent a part of a full pointer (or exactly a pointer
204 when addresses fit into a register). *)
206 (* Blocks and offsets need [D.ptr_size] bits each to be represented. Indeed,
207 one may allocate 2^[D.ptr_size] blocks of size one byte, or one block of
208 size 2^[D.ptr_size] bytes. *)
210 module ValBlock = BoundedInt
211 module ValOffset = BoundedInt
214 | Val_int of ValInt.t
215 | Val_ptr of ValBlock.t * ValOffset.t
218 let compare a b = match a, b with
219 | Val_int i1, Val_int i2 -> ValInt.compare i1 i2
220 | Val_ptr (b1, off1), Val_ptr (b2, off2) ->
221 let i1 = ValBlock.compare b1 b2 in
222 if i1 = 0 then ValOffset.compare off1 off2
224 | Val_undef, Val_undef -> 0
232 | Val_int i -> ValInt.to_int i
233 | Val_float f -> int_of_float f
237 | Val_ptrl (b,o) -> ValInt.to_int (ValInt.add b o)
240 let hash = Hashtbl.hash
242 let equal a b = compare a b = 0
243 let eq a b = compare a b = 0
245 let to_string = function
246 | Val_int i -> ValInt.to_string i
247 | Val_ptr (b, off) ->
248 "VPtr(" ^ (ValBlock.to_string b) ^ ", " ^ (ValOffset.to_string off) ^ ")"
249 | Val_undef -> "undef"
251 let is_int = function
255 let to_int = function
256 | Val_int i -> ValInt.to_int i
257 | _ -> raise (Failure "Value.to_int")
259 let of_int i = Val_int (ValInt.of_int i)
262 let of_int_repr i = Val_int i
264 let to_int_repr = function
266 | _ -> raise (Failure "Value.to_int_repr")
268 let zero = Val_int ValInt.zero
269 let val_true = Val_int ValInt.one
270 let val_false = Val_int ValInt.zero
272 let is_true = function
273 | Val_int i -> ValInt.neq i ValInt.zero
274 | Val_ptr (b, off) ->
275 (ValBlock.neq b ValBlock.zero) || (ValOffset.neq off ValOffset.zero)
278 let is_false = function
279 | Val_int i -> ValInt.eq i ValInt.zero
280 | Val_ptr (b, off) ->
281 (ValBlock.eq b ValBlock.zero) && (ValOffset.eq off ValOffset.zero)
284 let of_bool = function
289 if is_true v then true
291 if is_false v then false
292 else error "Undefined value."
294 let undef = Val_undef
296 let cast cast_fun = function
297 | Val_int i -> Val_int (cast_fun i)
300 (** Sign or 0 extensions from various bounded integers. *)
301 let cast8unsigned = cast (ValInt.zero_ext 8)
302 let cast8signed = cast (ValInt.sign_ext 8)
303 let cast16unsigned = cast (ValInt.zero_ext 16)
304 let cast16signed = cast (ValInt.sign_ext 16)
305 let cast32 = cast (ValInt.zero_ext 32)
308 let unary_int_op f = function
309 | Val_int i -> Val_int (f i)
312 let binary_int_op f v1 v2 = match v1, v2 with
313 | Val_int i1, Val_int i2 -> Val_int (f i1 i2)
316 let negint = unary_int_op ValInt.neg
319 if is_true v then val_false
321 if is_false v then val_true
324 let notint = unary_int_op ValInt.lognot
326 let cmpl = unary_int_op ValInt.lognot
328 (** [add_and_of v1 v2] returns the sum of [v1] and [v2], and whether this sum
330 let add_and_of v1 v2 = match v1, v2 with
331 | Val_int i1, Val_int i2 ->
332 (Val_int (ValInt.add i1 i2), of_bool (ValInt.add_of i1 i2))
333 | Val_int i, Val_ptr (b, off)
334 | Val_ptr (b, off), Val_int i ->
335 let i = ValOffset.cast i in
336 (Val_ptr (b, ValOffset.add off i), of_bool (ValOffset.add_of off i))
337 | _, _ -> (Val_undef, Val_undef)
339 let add v1 v2 = fst (add_and_of v1 v2)
340 let add_of v1 v2 = snd (add_and_of v1 v2)
342 let succ v = add v (Val_int ValInt.one)
344 (** [sub_and_uf v1 v2] returns the substraction of [v1] and [v2], and whether
345 this substraction underflows. *)
346 let sub_and_uf v1 v2 = match v1, v2 with
347 | Val_int i1, Val_int i2 ->
348 (Val_int (ValInt.sub i1 i2), of_bool (ValInt.sub_uf i1 i2))
349 | Val_ptr (b, off), Val_int i ->
350 let i = ValOffset.cast i in
351 (Val_ptr (b, ValOffset.sub off i), of_bool (ValOffset.sub_uf off i))
352 | Val_ptr (b1, off1), Val_ptr (b2, off2) when ValBlock.eq b1 b2 ->
353 (Val_int (ValInt.cast (ValOffset.sub off1 off2)),
354 of_bool (ValOffset.sub_uf off1 off2))
355 | _, _ -> (Val_undef, Val_undef)
357 let sub v1 v2 = fst (sub_and_uf v1 v2)
358 let sub_uf v1 v2 = snd (sub_and_uf v1 v2)
360 let pred v = sub v (Val_int ValInt.one)
362 let mul = binary_int_op ValInt.mul
364 let is_zero = function
365 | Val_int i when ValInt.eq i ValInt.zero -> true
368 let error_if_zero op v1 v2 =
369 if is_zero v2 then error "Division by zero."
370 else binary_int_op op v1 v2
372 let div = error_if_zero ValInt.div
373 let divu = error_if_zero ValInt.divu
374 let modulo = error_if_zero ValInt.modulo
375 let modulou = error_if_zero ValInt.modulou
377 let and_op = binary_int_op ValInt.logand
378 let or_op = binary_int_op ValInt.logor
379 let xor = binary_int_op ValInt.logxor
380 let shl = binary_int_op ValInt.shl
381 let shr = binary_int_op ValInt.shr
382 let shru = binary_int_op ValInt.shrl
387 let real_size = D.int_size * 8 in
388 let int_sh sh v n = sh v (of_int n) in
390 if m = real_size then v
391 else modulou v (shl one (of_int m))
393 let v = int_sh shl v (real_size - n) in
394 let v = int_sh sh v (m - n) in
395 int_sh shru v (real_size - m)
397 let zero_ext = ext shru
398 let sign_ext = ext shr
400 let cmp f_int f_off v1 v2 = match v1, v2 with
401 | Val_int i1, Val_int i2 -> of_bool (f_int i1 i2)
402 | Val_ptr (b1, off1), Val_ptr (b2, off2) when ValBlock.eq b1 b2 ->
403 of_bool (f_off off1 off2)
406 let cmp_eq = cmp ValInt.eq ValOffset.eq
407 let cmp_ne = cmp ValInt.neq ValOffset.neq
408 let cmp_lt = cmp ValInt.lt ValOffset.lt
409 let cmp_ge = cmp ValInt.ge ValOffset.ge
410 let cmp_le = cmp ValInt.le ValOffset.le
411 let cmp_gt = cmp ValInt.gt ValOffset.gt
413 let cmp_eq_u = cmp ValInt.eq ValOffset.eq
414 let cmp_ne_u = cmp ValInt.neq ValOffset.neq
415 let cmp_lt_u = cmp ValInt.ltu ValOffset.ltu
416 let cmp_ge_u = cmp ValInt.geu ValOffset.geu
417 let cmp_le_u = cmp ValInt.leu ValOffset.leu
418 let cmp_gt_u = cmp ValInt.gtu ValOffset.gtu
421 (* The memory is based on byte values. In order to be able to fit a bigger
422 integer or pointer value in memory, we need to be able to break this value
423 into several values of size a byte. An integer will be broken into multiple
424 8 bits integers. A pointer will be broken into several couples of 8 bits
425 blocks and 8 bits offsets. *)
427 module Int8 = IntValue.Int8
429 (* 8 bits integers *)
430 module IntChunk = Int8
432 module BlockChunk = Int8
434 module OffsetChunk = Int8
436 (** A chunk is a part of a value that has the size of a memory cell. *)
439 | Byte_int of IntChunk.t
440 | Byte_ptr of BlockChunk.t * OffsetChunk.t
443 let string_of_chunk = function
444 | Byte_int i -> IntChunk.to_string i
445 | Byte_ptr (b, off) ->
446 "BPtr(" ^ (BlockChunk.to_string b) ^ ", " ^
447 (OffsetChunk.to_string off) ^ ")"
448 | Byte_undef -> "Bundef"
450 let undef_byte = Byte_undef
452 let is_undef_byte = function
456 let break_and_cast break cast x n =
457 let ys = break x n in
460 (** [break v] cuts [v] in chunks that each fits into a memory cell. In the
461 resulting list, the first element is the low bits, and the last is the
462 high bits (little endian representation). *)
464 let nb_chunks = D.int_size in
466 | Val_ptr (b, off) ->
467 let bbs = break_and_cast ValBlock.break BlockChunk.cast b nb_chunks in
469 break_and_cast ValOffset.break OffsetChunk.cast off nb_chunks in
470 List.map2 (fun bb boff -> Byte_ptr (bb, boff)) bbs boffs
472 let bis = break_and_cast ValInt.break IntChunk.cast i nb_chunks in
473 List.map (fun i' -> Byte_int i') bis
474 | _ -> MiscPottier.make Byte_undef nb_chunks
476 (** [all_are_pointers l] returns [true] iff the values in the list [l] all are
478 let all_are_pointers =
479 let f b v = b && (match v with Byte_ptr _ -> true | _ -> false) in
480 List.fold_left f true
482 (** [all_are_integers l] returns [true] iff the values in the list [l] all are
484 let all_are_integers =
485 let f b v = b && (match v with Byte_int _ -> true | _ -> false) in
486 List.fold_left f true
488 let bblock_of_chunk = function
489 | Byte_ptr (b, _) -> b
490 | _ -> assert false (* do not use on this argument *)
492 let boffset_of_chunk = function
493 | Byte_ptr (_, off) -> off
494 | _ -> assert false (* do not use on this argument *)
496 let bint_of_chunk = function
498 | _ -> assert false (* do not use on this argument *)
500 let cast_and_merge cast merge transform l =
501 merge (List.map (fun x -> cast (transform x)) l)
503 (** [merge l] creates the value where the first element of [l] is its low
504 bits, etc, and the last element of [l] is its high bits (little endian
507 | l when all_are_pointers l ->
508 let b = cast_and_merge ValBlock.cast ValBlock.merge bblock_of_chunk l in
510 cast_and_merge ValOffset.cast ValOffset.merge boffset_of_chunk l in
512 | l when all_are_integers l ->
513 Val_int (cast_and_merge ValInt.cast ValInt.merge bint_of_chunk l)
517 (** Addresses from the memory point of view. *)
519 (** Some architectures have pointers bigger than integers. In this case, only
520 a chunk of pointer can fit into a machine register. Thus, an address is
521 represented by several values (little endian representation). *)
523 type address = t list
525 let string_of_address vs =
526 "[" ^ (MiscPottier.string_of_list " " to_string vs) ^ "]"
529 (** Addresses are represented by a block, i.e. a base address, and an offset
530 from this block. Both blocks and offsets are represented using bounded
533 let ptr_int_size = max (D.ptr_size / D.int_size) 1
535 module Block = IntValue.Make (struct let size = D.ptr_size end)
536 module Offset = IntValue.Make (struct let size = D.ptr_size end)
538 type mem_address = Block.t * Offset.t
540 let string_of_mem_address (b, off) =
541 Printf.sprintf "(%s, %s)" (Block.to_string b) (Offset.to_string off)
544 let f b v = b && (match v with | Val_ptr _ -> true | _ -> false) in
545 List.fold_left f true
547 let of_mem_address (b, off) =
548 let bs = Block.break b ptr_int_size in
549 let offs = Offset.break off ptr_int_size in
550 let f b off = Val_ptr (ValBlock.cast b, ValOffset.cast off) in
553 let decompose_Val_ptr = function
554 | Val_ptr (b, off) -> (b, off)
555 | _ -> error "Not an address."
557 let to_mem_address vs =
558 let (bs, offs) = List.split (List.map decompose_Val_ptr vs) in
559 let b = Block.merge (List.map Block.cast bs) in
560 let off = Offset.merge (List.map Offset.cast offs) in
563 let make_mem_address b off = (b, off)
564 let decompose_mem_address addr = addr
565 let block_of_address vs = fst (to_mem_address vs)
566 let offset_of_address vs = snd (to_mem_address vs)
568 let null = of_mem_address (Block.zero, Offset.zero)
570 let change_address_offset vs off =
571 let (b, _) = decompose_mem_address (to_mem_address vs) in
572 of_mem_address (make_mem_address b off)
574 let add_address vs off' =
575 let (b, off) = decompose_mem_address (to_mem_address vs) in
576 let off = Offset.add off off' in
577 of_mem_address (make_mem_address b off)
579 let eq_address addr1 addr2 =
580 let f b v1 v2 = b && (eq v1 v2) in
581 List.fold_left2 f true addr1 addr2