diff --git a/Makefile b/Makefile
index bc1699b5bd89bed03d5b51c0c53d5372c69b24f1..57d5264ffe28ef9639bb5d1b5c0a3d74b6c9f7c2 100644
--- a/Makefile
+++ b/Makefile
@@ -586,7 +586,7 @@ KERNEL_CMO=\
 	src/kernel_services/ast_printing/description.cmo                \
 	src/kernel_services/abstract_interp/lattice_messages.cmo        \
 	src/kernel_services/abstract_interp/abstract_interp.cmo         \
-	src/kernel_services/abstract_interp/bottom.cmo                  \
+	src/kernel_services/abstract_interp/lattice_bounds.cmo          \
 	src/kernel_services/abstract_interp/int_Base.cmo                \
 	src/kernel_services/analysis/bit_utils.cmo                      \
 	src/kernel_services/abstract_interp/fc_float.cmo                \
diff --git a/headers/header_spec.txt b/headers/header_spec.txt
index 45b246e8a48c7dbc258e0e48b73df33a5c0b1046..46728f67158b574cdc4d57a131dabe62f6f58a01 100644
--- a/headers/header_spec.txt
+++ b/headers/header_spec.txt
@@ -480,8 +480,6 @@ src/kernel_services/abstract_interp/abstract_offset.ml: CEA_LGPL
 src/kernel_services/abstract_interp/abstract_offset.mli: CEA_LGPL
 src/kernel_services/abstract_interp/base.ml: CEA_LGPL
 src/kernel_services/abstract_interp/base.mli: CEA_LGPL
-src/kernel_services/abstract_interp/bottom.ml: CEA_LGPL
-src/kernel_services/abstract_interp/bottom.mli: CEA_LGPL
 src/kernel_services/abstract_interp/eva_lattice_type.mli: CEA_LGPL
 src/kernel_services/abstract_interp/fc_float.ml: CEA_LGPL
 src/kernel_services/abstract_interp/fc_float.mli: CEA_LGPL
@@ -504,6 +502,8 @@ src/kernel_services/abstract_interp/int_val.ml: CEA_LGPL
 src/kernel_services/abstract_interp/int_val.mli: CEA_LGPL
 src/kernel_services/abstract_interp/ival.ml: CEA_LGPL
 src/kernel_services/abstract_interp/ival.mli: CEA_LGPL
+src/kernel_services/abstract_interp/lattice_bounds.ml: CEA_LGPL
+src/kernel_services/abstract_interp/lattice_bounds.mli: CEA_LGPL
 src/kernel_services/abstract_interp/lattice_messages.ml: CEA_LGPL
 src/kernel_services/abstract_interp/lattice_messages.mli: CEA_LGPL
 src/kernel_services/abstract_interp/lattice_type.mli: CEA_LGPL
diff --git a/src/kernel_services/abstract_interp/bottom.ml b/src/kernel_services/abstract_interp/bottom.ml
deleted file mode 100644
index b420661b852603263dd60a303203bd1f345ceab3..0000000000000000000000000000000000000000
--- a/src/kernel_services/abstract_interp/bottom.ml
+++ /dev/null
@@ -1,186 +0,0 @@
-(**************************************************************************)
-(*                                                                        *)
-(*  This file is part of Frama-C.                                         *)
-(*                                                                        *)
-(*  Copyright (C) 2007-2022                                               *)
-(*    CEA (Commissariat à l'énergie atomique et aux énergies              *)
-(*         alternatives)                                                  *)
-(*                                                                        *)
-(*  you can redistribute it and/or modify it under the terms of the GNU   *)
-(*  Lesser General Public License as published by the Free Software       *)
-(*  Foundation, version 2.1.                                              *)
-(*                                                                        *)
-(*  It is distributed in the hope that it will be useful,                 *)
-(*  but WITHOUT ANY WARRANTY; without even the implied warranty of        *)
-(*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *)
-(*  GNU Lesser General Public License for more details.                   *)
-(*                                                                        *)
-(*  See the GNU Lesser General Public License version 2.1                 *)
-(*  for more details (enclosed in the file licenses/LGPLv2.1).            *)
-(*                                                                        *)
-(**************************************************************************)
-
-
-module Type = struct
-
-  type 'a or_bottom = [ `Value of 'a | `Bottom ]
-
-  (* This monad propagates the `Bottom value if needed. *)
-  let (>>-) t f = match t with
-    | `Bottom  -> `Bottom
-    | `Value t -> f t
-
-  (* Use this monad if the following function returns a simple value. *)
-  let (>>-:) t f = match t with
-    | `Bottom  -> `Bottom
-    | `Value t -> `Value (f t)
-
-end
-
-include Type
-
-let is_bottom = function
-  | `Bottom -> true
-  | `Value _ -> false
-
-let non_bottom = function
-  | `Value v -> v
-  | `Bottom  -> assert false
-
-let value ~bottom = function
-  | `Value v -> v
-  | `Bottom -> bottom
-
-let equal equal x y = match x, y with
-  | `Bottom, `Bottom     -> true
-  | `Value vx, `Value vy -> equal vx vy
-  | _                    -> false
-
-let compare compare a b = match a, b with
-  | `Bottom, `Bottom   -> 0
-  | `Bottom, _         -> -1
-  | _, `Bottom         -> 1
-  | `Value v, `Value w -> compare v w
-
-let is_included is_included x y = match x, y with
-  | `Bottom, _           -> true
-  | _, `Bottom           -> false
-  | `Value vx, `Value vy -> is_included vx vy
-
-let join join x y = match x, y with
-  | `Value vx, `Value vy    -> `Value (join vx vy)
-  | `Bottom, (`Value _ as v)
-  | (`Value _ as v), `Bottom
-  | (`Bottom as v), `Bottom -> v
-
-let join_list j l = List.fold_left (join j) `Bottom l
-
-let narrow narrow x y = match x, y with
-  | `Value vx, `Value vy    -> narrow vx vy
-  | `Bottom, `Value _
-  | `Value _, `Bottom
-  | `Bottom, `Bottom -> `Bottom
-
-let pretty pretty fmt = function
-  | `Bottom  -> Format.fprintf fmt "Bottom"
-  | `Value v -> pretty fmt v
-
-let iter f = function
-  | `Bottom -> ()
-  | `Value v -> f v
-
-let fold ~bottom f = function
-  | `Bottom -> bottom
-  | `Value v -> f v
-
-let counter = ref 0
-
-module Make_Datatype
-    (Domain: Datatype.S)
-  =
-  Datatype.Make (
-  struct
-    include Datatype.Serializable_undefined
-    type t = Domain.t or_bottom
-    let () = incr counter
-    let name = Domain.name ^ "+bottom(" ^ string_of_int !counter ^ ")"
-    let reprs = [`Bottom; `Value (List.hd Domain.reprs)]
-    let structural_descr = Structural_descr.t_unknown
-    (* Structural_descr.t_sum [| [| Domain.packed_descr |] |] *)
-
-    let equal a b = match a, b with
-      | `Bottom, `Bottom   -> true
-      | `Value v, `Value w -> Domain.equal v w
-      | _, _               -> false
-
-    let compare a b = match a, b with
-      | `Bottom, `Bottom   -> 0
-      | `Bottom, _         -> -1
-      | _, `Bottom         -> 1
-      | `Value v, `Value w -> Domain.compare v w
-
-    let hash = function
-      | `Bottom  -> 0
-      | `Value v -> Domain.hash v
-
-    let rehash = Datatype.identity
-
-    let copy = function
-      | `Bottom  -> `Bottom
-      | `Value v -> `Value (Domain.copy v)
-
-    let pretty fmt = function
-      | `Bottom  -> Format.fprintf fmt "Bottom"
-      | `Value v -> Domain.pretty fmt v
-
-    let mem_project = Datatype.never_any_project
-  end)
-
-
-module Bound_Lattice
-    (Lattice: Lattice_type.Join_Semi_Lattice)
-= struct
-  include Make_Datatype (Lattice)
-
-  let bottom = `Bottom
-  let join = join Lattice.join
-  let is_included = is_included Lattice.is_included
-end
-
-let to_option = function
-  | `Bottom -> None
-  | `Value v -> Some v
-
-let to_list = function
-  | `Bottom  -> []
-  | `Value v -> [v]
-
-let bot_of_list = function
-  | [] -> `Bottom
-  | l  -> `Value l
-
-let list_of_bot = function
-  | `Bottom  -> []
-  | `Value l -> l
-
-let add_to_list elt list = match elt with
-  | `Bottom    -> list
-  | `Value elt -> elt :: list
-
-let all l =
-  List.fold_left (fun l elt -> add_to_list elt l) [] l
-
-module Top = struct
-
-  type 'a or_top_bottom = [ 'a or_bottom | `Top ]
-
-  let join vjoin x y = match x, y with
-    | `Top, _ | _, `Top -> `Top
-    | (#or_bottom as x), (#or_bottom as y) -> join vjoin x y
-
-  let narrow vnarrow x y = match x, y with
-    | `Top, v | v, `Top -> v
-    | (#or_bottom as x), (#or_bottom as y) ->
-      (narrow vnarrow x y :> _ or_top_bottom)
-
-end
diff --git a/src/kernel_services/abstract_interp/bottom.mli b/src/kernel_services/abstract_interp/bottom.mli
deleted file mode 100644
index fad87be41a342bee62ce8fe041c9ba0e4aa7c0ca..0000000000000000000000000000000000000000
--- a/src/kernel_services/abstract_interp/bottom.mli
+++ /dev/null
@@ -1,98 +0,0 @@
-(**************************************************************************)
-(*                                                                        *)
-(*  This file is part of Frama-C.                                         *)
-(*                                                                        *)
-(*  Copyright (C) 2007-2022                                               *)
-(*    CEA (Commissariat à l'énergie atomique et aux énergies              *)
-(*         alternatives)                                                  *)
-(*                                                                        *)
-(*  you can redistribute it and/or modify it under the terms of the GNU   *)
-(*  Lesser General Public License as published by the Free Software       *)
-(*  Foundation, version 2.1.                                              *)
-(*                                                                        *)
-(*  It is distributed in the hope that it will be useful,                 *)
-(*  but WITHOUT ANY WARRANTY; without even the implied warranty of        *)
-(*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *)
-(*  GNU Lesser General Public License for more details.                   *)
-(*                                                                        *)
-(*  See the GNU Lesser General Public License version 2.1                 *)
-(*  for more details (enclosed in the file licenses/LGPLv2.1).            *)
-(*                                                                        *)
-(**************************************************************************)
-
-(** Types, monads and utilitary functions for lattices in which the bottom is
-    managed separately from other values. *)
-
-module Type : sig
-
-  type 'a or_bottom = [ `Value of 'a | `Bottom ]
-
-  (** This monad propagates the `Bottom value if needed. *)
-  val (>>-) : 'a or_bottom -> ('a -> 'b or_bottom) -> 'b or_bottom
-
-  (** Use this monad if the following function returns a simple value. *)
-  val (>>-:) : 'a or_bottom -> ('a -> 'b) -> 'b or_bottom
-
-end
-
-include module type of Type
-
-val is_bottom: 'a or_bottom -> bool
-val non_bottom: 'a or_bottom -> 'a
-val value: bottom: 'a -> 'a or_bottom -> 'a
-
-val equal:       ('a -> 'a -> bool) -> 'a or_bottom -> 'a or_bottom -> bool
-val compare:     ('a -> 'a -> int)  -> 'a or_bottom -> 'a or_bottom -> int
-val is_included: ('a -> 'b -> bool) -> 'a or_bottom -> 'b or_bottom -> bool
-val join:        ('a -> 'a -> 'a) -> 'a or_bottom -> 'a or_bottom -> 'a or_bottom
-val join_list:   ('a -> 'a -> 'a) -> 'a or_bottom list -> 'a or_bottom
-val narrow:      ('a -> 'a -> 'a or_bottom) -> 'a or_bottom -> 'a or_bottom -> 'a or_bottom
-
-val pretty :
-  (Format.formatter -> 'a -> unit) ->
-  Format.formatter -> 'a or_bottom -> unit
-
-val iter: ('a -> unit) -> 'a or_bottom -> unit
-val fold: bottom: 'b -> ('a -> 'b) -> 'a or_bottom -> 'b
-
-(** Datatype constructor. *)
-module Make_Datatype
-    (Domain: Datatype.S)
-  : Datatype.S with type t = Domain.t or_bottom
-
-
-(** Bounds a semi-lattice. *)
-module Bound_Lattice
-    (Lattice: Lattice_type.Join_Semi_Lattice)
-  : Lattice_type.Bounded_Join_Semi_Lattice with type t = Lattice.t or_bottom
-
-
-
-(** In a lattice where the elements are lists of non-bottom values,
-    the empty list is the bottom case. *)
-
-(** Conversion functions. *)
-val to_option : 'a or_bottom -> 'a option
-val to_list: 'a or_bottom -> 'a list
-val bot_of_list: 'a list -> 'a list or_bottom
-val list_of_bot: 'a list or_bottom -> 'a list
-val all: 'a or_bottom list -> 'a list
-
-(** [elt >:: list] adds [elt] to the [list] if it is not bottom. *)
-val add_to_list : 'a or_bottom -> 'a list -> 'a list
-
-
-(** Lattices in which both top and bottom are managed separately *)
-module Top: sig
-
-  type 'a or_top_bottom = [ 'a or_bottom | `Top ]
-
-  val join:
-    ('a -> 'a -> 'a) ->
-    'a or_top_bottom -> 'a or_top_bottom -> 'a or_top_bottom
-
-  val narrow:
-    ('a -> 'a -> 'a or_bottom) ->
-    'a or_top_bottom -> 'a or_top_bottom -> 'a or_top_bottom
-
-end
diff --git a/src/kernel_services/abstract_interp/eva_lattice_type.mli b/src/kernel_services/abstract_interp/eva_lattice_type.mli
index 8c5e10c62fded3e273207b4d847b732420cc76eb..e05c1ee9c49e5d9c7de08120923ecea494ddbe53 100644
--- a/src/kernel_services/abstract_interp/eva_lattice_type.mli
+++ b/src/kernel_services/abstract_interp/eva_lattice_type.mli
@@ -25,7 +25,7 @@
     when needed. Except that, they are identical to the module signatures in
     {!Lattice_type}. *)
 
-open Bottom.Type
+open Lattice_bounds
 
 module type Join_Semi_Lattice = Lattice_type.Join_Semi_Lattice
 module type With_Top = Lattice_type.With_Top
diff --git a/src/kernel_services/abstract_interp/float_interval.ml b/src/kernel_services/abstract_interp/float_interval.ml
index aa8216f716a3171f1d8bcc34d6a8d022487179d0..1f5d34a2f4a01a74a6e140559324e5f234011673 100644
--- a/src/kernel_services/abstract_interp/float_interval.ml
+++ b/src/kernel_services/abstract_interp/float_interval.ml
@@ -21,7 +21,8 @@
 (**************************************************************************)
 
 module Comp = Abstract_interp.Comp
-open Bottom.Type
+open Lattice_bounds
+open Bottom.Operators
 
 type round = Float_sig.round = Up | Down | Near | Zero
 type prec = Float_sig.prec = Single | Double | Long_Double | Real
diff --git a/src/kernel_services/abstract_interp/float_interval_sig.mli b/src/kernel_services/abstract_interp/float_interval_sig.mli
index 560d6f692d142bc05a396c2256a84eac6920c4ec..b1b3561dcee85cc4f0c706bf3d67bd6c25607dee 100644
--- a/src/kernel_services/abstract_interp/float_interval_sig.mli
+++ b/src/kernel_services/abstract_interp/float_interval_sig.mli
@@ -22,7 +22,7 @@
 
 (** Signature for the floating-point interval semantics. *)
 
-open Bottom.Type
+open Lattice_bounds
 
 (** Precision of the intervals. *)
 type prec = Float_sig.prec
@@ -116,7 +116,7 @@ module type S = sig
       [f1] into [f1'] so that the relation [f1' op f2] holds.
       [prec] is the precision of [f1] and [f1'], but not necessarily of [f2]. *)
   val backward_comp_left_true:
-    Abstract_interp.Comp.t -> prec -> t -> t -> t Bottom.or_bottom
+    Abstract_interp.Comp.t -> prec -> t -> t -> t or_bottom
 
   (** [backward_comp_left_false op prec f1 f2] attempts to reduce
       [f1] into [f1'] so that the relation [f1' op f2] doesn't holds.
diff --git a/src/kernel_services/abstract_interp/fval.mli b/src/kernel_services/abstract_interp/fval.mli
index 93aa5e24a914d858537e5e50fe84b9615fbac907..30e3e709536d52435094415029b9b94166a53bab 100644
--- a/src/kernel_services/abstract_interp/fval.mli
+++ b/src/kernel_services/abstract_interp/fval.mli
@@ -89,7 +89,7 @@ val e: t  (** Real representation of \e. *)
 
 val contains_plus_zero : t -> bool
 
-val meet: t -> t -> t Bottom.or_bottom
+val meet: t -> t -> t Lattice_bounds.or_bottom
 
 val is_singleton : t -> bool
 (** Returns [true] on NaN. We expect this function to be e.g. to perform
@@ -134,7 +134,7 @@ val ceil: kind -> t -> t
 val trunc: kind -> t -> t
 val fround: kind -> t -> t
 
-val backward_cast_float_to_double: t -> t Bottom.or_bottom
+val backward_cast_float_to_double: t -> t Lattice_bounds.or_bottom
 (** [backward_cast_float_to_double d] return all possible float32 [f] such that
     [(double)f = d]. The double of [d] that have no float32 equivalent are
     discarded. *)
diff --git a/src/kernel_services/abstract_interp/int_interval.ml b/src/kernel_services/abstract_interp/int_interval.ml
index 9d72418a04c039447427c931d35c7881e5f5ff35..f1eb54dada1209a83225a2b0b5017fb34e7be71b 100644
--- a/src/kernel_services/abstract_interp/int_interval.ml
+++ b/src/kernel_services/abstract_interp/int_interval.ml
@@ -699,7 +699,7 @@ let div x y =
         `Value (div_range x min gneg)
       else `Bottom
     in
-    Bottom.join join result_neg result_pos
+    Lattice_bounds.Bottom.join join result_neg result_pos
 
 (* ----------------------------------- Misc --------------------------------- *)
 
diff --git a/src/kernel_services/abstract_interp/int_interval.mli b/src/kernel_services/abstract_interp/int_interval.mli
index dbdbcba5db2233ff1e0d29f7e973a8ce13689c09..1e52aa926a144e2311b8f68fc4ed9e86ab4e8da1 100644
--- a/src/kernel_services/abstract_interp/int_interval.mli
+++ b/src/kernel_services/abstract_interp/int_interval.mli
@@ -26,7 +26,7 @@
     A value of [None] for [min] (resp. [max]) represents -infinity
     (resp. +infinity). [modu] is > 0, and [0 <= rem < modu]. *)
 
-open Bottom.Type
+open Lattice_bounds
 
 include Datatype.S_with_collections
 
diff --git a/src/kernel_services/abstract_interp/int_set.ml b/src/kernel_services/abstract_interp/int_set.ml
index 72ad214057be997c0278b060c33c9a04dda5588e..1d5a7fad690e76287ed21e296371fcd9b25df308 100644
--- a/src/kernel_services/abstract_interp/int_set.ml
+++ b/src/kernel_services/abstract_interp/int_set.ml
@@ -21,7 +21,7 @@
 (**************************************************************************)
 
 open Abstract_interp
-open Bottom.Type
+open Lattice_bounds
 
 (* Make sure all this is synchronized with the default value of -ilevel *)
 let small_cardinal = ref 8
diff --git a/src/kernel_services/abstract_interp/int_set.mli b/src/kernel_services/abstract_interp/int_set.mli
index 0eab36f019c0ff870f1a29e5f7618144a8c61383..d3aac28587ccc2bf78c127d5710a0a4cc4501fba 100644
--- a/src/kernel_services/abstract_interp/int_set.mli
+++ b/src/kernel_services/abstract_interp/int_set.mli
@@ -30,7 +30,7 @@
     Sets are always non-empty. The functions reducing the sets returns a
     [set or_bottom] type: either the result is non-empty, or it is `Bottom. *)
 
-open Bottom.Type
+open Lattice_bounds
 
 (** Returns the limit above which integer sets are converted into intervals. *)
 val get_small_cardinal: unit -> int
diff --git a/src/kernel_services/abstract_interp/int_val.ml b/src/kernel_services/abstract_interp/int_val.ml
index 5cade9d5c4948b35ff016ea83e86dfbed557a055..6e661036c0cc91facfb7fc2c1d62a1e384b8146e 100644
--- a/src/kernel_services/abstract_interp/int_val.ml
+++ b/src/kernel_services/abstract_interp/int_val.ml
@@ -21,7 +21,8 @@
 (**************************************************************************)
 
 open Abstract_interp
-open Bottom.Type
+open Lattice_bounds
+open Bottom.Operators
 
 let small_cardinal = Int_set.get_small_cardinal
 let small_cardinal_Int () = Int.of_int (small_cardinal ())
diff --git a/src/kernel_services/abstract_interp/int_val.mli b/src/kernel_services/abstract_interp/int_val.mli
index 47b23b1d145c9f366da0773fbd2d2071dca790e1..86b7f208542a3b944d820a41f48a214d18ddba55 100644
--- a/src/kernel_services/abstract_interp/int_val.mli
+++ b/src/kernel_services/abstract_interp/int_val.mli
@@ -26,7 +26,7 @@
 
 (** Abstractions do not represent the empty set. Instead, operations creating
     empty sets return `Bottom. *)
-open Bottom.Type
+open Lattice_bounds
 
 include Datatype.S_with_collections
 
diff --git a/src/kernel_services/abstract_interp/ival.ml b/src/kernel_services/abstract_interp/ival.ml
index c6495c9d001045a770e8dc1b0e7d4d880b6712c1..5022d6fd6adde061e50d9b15851be9c0391ad98c 100644
--- a/src/kernel_services/abstract_interp/ival.ml
+++ b/src/kernel_services/abstract_interp/ival.ml
@@ -21,7 +21,8 @@
 (**************************************************************************)
 
 open Abstract_interp
-open Bottom.Type
+open Lattice_bounds
+open Bottom.Operators
 
 let emitter = Lattice_messages.register "Ival"
 let log_imprecision s = Lattice_messages.emit_imprecision emitter s
@@ -1031,7 +1032,6 @@ let reinterpret_as_float kind i =
         then [`Value Fval.nan]
         else []
       in
-      let open Bottom in
       let range mn mx = Fval.inject kind (conv mn) (conv mx) in
       (* convert positive floats; increasing on positive range *)
       let pos = bounds_narrow f_pos >>-: (fun (b, e) -> range b e) in
diff --git a/src/kernel_services/abstract_interp/ival.mli b/src/kernel_services/abstract_interp/ival.mli
index 5e072bc1ecb175e16a86eaeb73675f3a214517e4..82740fff771c53814b332b5658c12f92214bba01 100644
--- a/src/kernel_services/abstract_interp/ival.mli
+++ b/src/kernel_services/abstract_interp/ival.mli
@@ -272,7 +272,7 @@ val create_all_values: signed:bool -> size:int -> t
     representable in [size] bits. *)
 val all_values: size:Integer.t -> t -> bool
 
-val backward_mult_int_left: right:t -> result:t -> t option Bottom.or_bottom
+val backward_mult_int_left: right:t -> result:t -> t option Lattice_bounds.or_bottom
 
 val backward_comp_int_left : Comp.t -> t -> t -> t
 (** [backward_comp_int op l r] reduces [l] into [l'] so that
@@ -319,7 +319,7 @@ val reinterpret_as_int: size:Integer.t -> signed:bool -> t -> t
 (** Bitwise reinterpretation of the given value, of size [size], as an integer
     of the given signedness (and size). *)
 
-val complement_int_under: size:int -> signed:bool -> t -> t Bottom.or_bottom
+val complement_int_under: size:int -> signed:bool -> t -> t Lattice_bounds.or_bottom
 (** Returns an under-approximation of the integers of the given size and
     signedness that are *not* represented by the given ival. *)
 
diff --git a/src/kernel_services/abstract_interp/lattice_bounds.ml b/src/kernel_services/abstract_interp/lattice_bounds.ml
new file mode 100644
index 0000000000000000000000000000000000000000..3b7fb552f534d8b9ec6c53b4d6fbc7ef19be2367
--- /dev/null
+++ b/src/kernel_services/abstract_interp/lattice_bounds.ml
@@ -0,0 +1,328 @@
+(**************************************************************************)
+(*                                                                        *)
+(*  This file is part of Frama-C.                                         *)
+(*                                                                        *)
+(*  Copyright (C) 2007-2022                                               *)
+(*    CEA (Commissariat à l'énergie atomique et aux énergies              *)
+(*         alternatives)                                                  *)
+(*                                                                        *)
+(*  you can redistribute it and/or modify it under the terms of the GNU   *)
+(*  Lesser General Public License as published by the Free Software       *)
+(*  Foundation, version 2.1.                                              *)
+(*                                                                        *)
+(*  It is distributed in the hope that it will be useful,                 *)
+(*  but WITHOUT ANY WARRANTY; without even the implied warranty of        *)
+(*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *)
+(*  GNU Lesser General Public License for more details.                   *)
+(*                                                                        *)
+(*  See the GNU Lesser General Public License version 2.1                 *)
+(*  for more details (enclosed in the file licenses/LGPLv2.1).            *)
+(*                                                                        *)
+(**************************************************************************)
+
+type 'a or_bottom = [ `Value of 'a | `Bottom ]
+type 'a or_top = [ `Value of 'a | `Top ]
+type 'a or_top_bottom = [ `Value of 'a | `Bottom | `Top ]
+
+(** Common functions *)
+
+module Common =
+struct
+
+  (* Pretty-printing *)
+
+  let pretty_top fmt =
+    Format.pp_print_string fmt (Unicode.top_string ())
+
+  let pretty_bottom fmt =
+    Format.pp_print_string fmt (Unicode.bottom_string ())
+
+  let pretty pretty_value fmt = function
+    | `Bottom -> pretty_bottom fmt
+    | `Top -> pretty_top fmt
+    | `Value v -> pretty_value fmt v
+
+  (* Datatype *)
+
+  let hash hash_value = function
+    | `Bottom  -> 7
+    | `Top -> 13
+    | `Value v -> hash_value v
+
+  let equal equal_value x y =
+    match x, y with
+    | `Bottom, `Bottom -> true
+    | `Top, `Top -> true
+    | `Value vx, `Value vy -> equal_value vx vy
+    | (`Value _ | `Bottom | `Top), (`Value _ | `Bottom | `Top) -> false
+
+  let compare compare_value a b = match a, b with
+    | `Bottom, `Bottom -> 0
+    | `Bottom, (`Top | `Value _) -> -1
+    | (`Top | `Value _), `Bottom -> 1
+    | `Top, `Top -> 0
+    | `Top, `Value _ -> -1
+    | `Value _, `Top -> 1
+    | `Value vx, `Value vy -> compare_value vx vy
+
+  (* Tests *)
+
+  let is_bottom = function
+    | `Bottom -> true
+    | `Value _ | `Top -> false
+
+  let is_top = function
+    | `Top -> true
+    | `Value _ | `Bottom -> false
+
+  let is_included is_included x y =
+    match x, y with
+    | `Bottom, _ | _, `Top -> true
+    | _, `Bottom | `Top, _ -> false
+    | `Value vx, `Value vy -> is_included vx vy
+
+  (* Iterator *)
+  let iter f = function
+    | `Bottom | `Top -> ()
+    | `Value v -> f v
+
+  (* Conversion *)
+  let to_option = function
+    | `Bottom | `Top -> None
+    | `Value x -> Some x
+
+end
+
+module Bottom = struct
+  type 'a t = 'a or_bottom
+
+  include Common
+
+  (** Access *)
+
+  let non_bottom = function
+    | `Value v -> v
+    | `Bottom  -> assert false
+
+  let value ~bottom = function
+    | `Value v -> v
+    | `Bottom -> bottom
+
+  (* Lattice operators *)
+
+  let join join x y = match x, y with
+    | `Value vx, `Value vy    -> `Value (join vx vy)
+    | `Bottom, (`Value _ as v)
+    | (`Value _ as v), `Bottom
+    | (`Bottom as v), `Bottom -> v
+
+  let join_list j l = List.fold_left (join j) `Bottom l
+
+  let narrow narrow x y = match x, y with
+    | `Value vx, `Value vy    -> narrow vx vy
+    | `Bottom, `Value _
+    | `Value _, `Bottom
+    | `Bottom, `Bottom -> `Bottom
+
+  (* Iterators *)
+
+  let fold ~bottom f = function
+    | `Bottom -> bottom
+    | `Value v -> f v
+
+  let map f = function
+    | `Bottom -> `Bottom
+    | `Value v -> `Value (f v)
+
+  (* Combination *)
+
+  let zip x y =
+    match x, y with
+    | `Bottom, _ | _, `Bottom -> `Bottom
+    | `Value x, `Value y -> `Value (x,y)
+
+  (** Conversion *)
+
+  let of_option = function
+    | None -> `Bottom
+    | Some v -> `Value v
+
+  let to_list = function
+    | `Bottom  -> []
+    | `Value v -> [v]
+
+  let bot_of_list = function
+    | [] -> `Bottom
+    | l  -> `Value l
+
+  let list_of_bot = function
+    | `Bottom  -> []
+    | `Value l -> l
+
+  let add_to_list elt list = match elt with
+    | `Bottom    -> list
+    | `Value elt -> elt :: list
+
+  let list_values l =
+    List.fold_left (fun l elt -> add_to_list elt l) [] l
+
+  (** Operators *)
+
+  module Operators =
+  struct
+    let (>>-) t f = match t with
+      | `Bottom  -> `Bottom
+      | `Value t -> f t
+
+    let (>>-:) t f = match t with
+      | `Bottom  -> `Bottom
+      | `Value t -> `Value (f t)
+
+    let (let+) = (>>-:)
+    let (and+) = zip
+    let (let*) = (>>-)
+    let (and*) = zip
+  end
+
+  (** Datatype construction *)
+  let counter = ref 0
+
+  module Make_Datatype
+      (Domain: Datatype.S)
+    =
+    Datatype.Make (
+    struct
+      include Datatype.Serializable_undefined
+      type t = Domain.t or_bottom
+      let () = incr counter
+      let name = Domain.name ^ "+bottom(" ^ string_of_int !counter ^ ")"
+      let reprs = `Bottom :: (List.map (fun v -> `Value v) Domain.reprs)
+      let structural_descr = Structural_descr.t_unknown
+      let hash = Common.hash Domain.hash
+      let equal = (Common.equal Domain.equal :> t -> t -> bool)
+      let compare = Common.compare Domain.compare
+      let rehash = Datatype.identity
+      let copy = map Domain.copy
+      let pretty = Common.pretty Domain.pretty
+      let mem_project = Datatype.never_any_project
+    end)
+
+  (* Bound lattice *)
+
+  module Bound_Lattice
+      (Lattice: Lattice_type.Join_Semi_Lattice)
+  = struct
+    include Make_Datatype (Lattice)
+
+    let bottom = `Bottom
+    let join = join Lattice.join
+    let is_included = is_included Lattice.is_included
+  end
+end
+
+
+module Top =
+struct
+  type 'a t = 'a or_top
+
+  include Common
+
+  (** Access *)
+
+  let non_top = function
+    | `Value v -> v
+    | `Top  -> assert false
+
+  let value ~top = function
+    | `Value v -> v
+    | `Top -> top
+
+  (** Lattice *)
+
+  let join join_value x y =
+    match x, y with
+    | `Top, _ | _, `Top -> `Top
+    | `Value vx, `Value vy -> join_value vx vy
+
+  let narrow narrow_value x y =
+    match x, y with
+    | `Top, v | v, `Top -> v
+    | `Value vx, `Value vy -> `Value (narrow_value vx vy)
+
+  (** Combination *)
+
+  let zip x y =
+    match x, y with
+    | `Top, _ | _, `Top -> `Top
+    | `Value x, `Value y -> `Value (x,y)
+
+  (** Conversion. *)
+
+  let of_option = function
+    | None -> `Top
+    | Some x -> `Value x
+
+  (** Operators *)
+
+  module Operators = struct
+    let (>>-) t f = match t with
+      | `Top -> `Top
+      | `Value t -> f t
+
+    let (>>-:) t f = match t with
+      | `Top -> `Top
+      | `Value t -> `Value (f t)
+
+    let (let+) = (>>-:)
+    let (and+) = zip
+    let (let*) = (>>-)
+    let (and*) = zip
+  end
+end
+
+
+module TopBottom =
+struct
+  type 'a t = 'a or_top_bottom
+
+  include Common
+
+  (* Lattice operators *)
+
+  let join join_value x y = match x, y with
+    | `Top, _ | _, `Top -> `Top
+    | `Bottom, x | x, `Bottom -> x
+    | `Value vx, `Value vy -> (join_value vx vy :> 'a t)
+
+  let narrow narrow_value x y = match x, y with
+    | `Top, v | v, `Top -> v
+    | `Bottom, _ | _, `Bottom -> `Bottom
+    | `Value vx, `Value vy -> (narrow_value vx vy :> 'a t)
+
+  (** Combination *)
+
+  let zip x y =
+    match x, y with
+    | `Bottom, _ | _, `Bottom -> `Bottom
+    | `Top, _ | _, `Top -> `Top
+    | `Value x, `Value y -> `Value (x,y)
+
+  (** Operators *)
+
+  module Operators = struct
+    let (>>-) t f = match t with
+      | `Top -> `Top
+      | `Bottom -> `Bottom
+      | `Value t -> f t
+
+    let (>>-:) t f = match t with
+      | `Top -> `Top
+      | `Bottom -> `Bottom
+      | `Value t -> `Value (f t)
+
+    let (let+) = (>>-:)
+    let (and+) = zip
+    let (let*) = (>>-)
+    let (and*) = zip
+  end
+end
diff --git a/src/kernel_services/abstract_interp/lattice_bounds.mli b/src/kernel_services/abstract_interp/lattice_bounds.mli
new file mode 100644
index 0000000000000000000000000000000000000000..1d4ff6f981953528b5ca07ac081628344cf9e855
--- /dev/null
+++ b/src/kernel_services/abstract_interp/lattice_bounds.mli
@@ -0,0 +1,191 @@
+(**************************************************************************)
+(*                                                                        *)
+(*  This file is part of Frama-C.                                         *)
+(*                                                                        *)
+(*  Copyright (C) 2007-2022                                               *)
+(*    CEA (Commissariat à l'énergie atomique et aux énergies              *)
+(*         alternatives)                                                  *)
+(*                                                                        *)
+(*  you can redistribute it and/or modify it under the terms of the GNU   *)
+(*  Lesser General Public License as published by the Free Software       *)
+(*  Foundation, version 2.1.                                              *)
+(*                                                                        *)
+(*  It is distributed in the hope that it will be useful,                 *)
+(*  but WITHOUT ANY WARRANTY; without even the implied warranty of        *)
+(*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *)
+(*  GNU Lesser General Public License for more details.                   *)
+(*                                                                        *)
+(*  See the GNU Lesser General Public License version 2.1                 *)
+(*  for more details (enclosed in the file licenses/LGPLv2.1).            *)
+(*                                                                        *)
+(**************************************************************************)
+
+(** Types, monads and utilitary functions for lattices in which the bottom
+    and/or the top are managed separately from other values. *)
+
+type 'a or_bottom = [ `Value of 'a | `Bottom ]
+type 'a or_top = [ `Value of 'a | `Top ]
+type 'a or_top_bottom = [ `Value of 'a | `Bottom | `Top ]
+
+
+module Bottom : sig
+  type 'a t = 'a or_bottom
+
+  (** Operators *)
+  module Operators : sig
+    (** This monad propagates `Bottom and or `Top if needed. *)
+    val (>>-) : [< 'a t] -> ('a -> ([> 'b t] as 'c)) -> 'c
+
+    (** Use this monad if the following function returns a simple value. *)
+    val (>>-:) : [< 'a t] -> ('a -> 'b) -> [> 'b t]
+
+    (* Binding operators, applicative syntax *)
+    val (let+) : [< 'a t] -> ('a -> 'b) -> [> 'b t]
+    val (and+) : [< 'a t] -> [< 'b t] -> [> ('a * 'b) t]
+
+    (* Binding operators, monad syntax *)
+    val (let*) : [< 'a t] -> ('a -> ([> 'b t] as 'c)) -> 'c
+    val (and*) : [< 'a t] -> [< 'b t] -> [> ('a * 'b) t]
+  end
+
+  (** Datatype constructor *)
+  module Make_Datatype
+      (Domain: Datatype.S)
+    : Datatype.S with type t = Domain.t or_bottom
+
+  (** Bounds a semi-lattice *)
+  module Bound_Lattice
+      (Lattice: Lattice_type.Join_Semi_Lattice)
+    : Lattice_type.Bounded_Join_Semi_Lattice with type t = Lattice.t or_bottom
+
+  (** Access *)
+  val is_bottom: 'a t -> bool
+  val non_bottom: 'a t -> 'a
+  val value: bottom: 'a -> 'a t -> 'a
+
+  (** Datatype *)
+  val hash: ('a -> int) -> 'a t -> int
+  val equal: ('a -> 'a -> bool) -> 'a t -> 'a t -> bool
+  val compare: ('a -> 'a -> int)  -> 'a t -> 'a t -> int
+
+  (** Pretty-printing *)
+  val pretty_bottom :Format.formatter -> unit (* for %t specifier *)
+  val pretty :
+    (Format.formatter -> 'a -> unit) ->
+    Format.formatter -> 'a t -> unit
+
+  (* Lattice operators *)
+  val is_included: ('a -> 'b -> bool) -> 'a t -> 'b t -> bool
+  val join: ('a -> 'a -> 'a) -> 'a t -> 'a t -> 'a t
+  val join_list: ('a -> 'a -> 'a) -> 'a t list -> 'a t
+  val narrow: ('a -> 'a -> 'a t) -> 'a t -> 'a t -> 'a t
+
+  (* Iterators *)
+  val iter: ('a -> unit) -> 'a t -> unit
+  val fold: bottom: 'b -> ('a -> 'b) -> 'a t -> 'b
+  val map: ('a -> 'b) -> 'a t -> 'b t
+
+  (* Combination *)
+  val zip: 'a t -> 'b t -> ('a * 'b) t (* `Bottom if any is `Bottom *)
+
+  (** In a lattice where the elements are lists of non-bottom values,
+      the empty list is the bottom case. *)
+
+  (** Conversion *)
+  val to_option: 'a t -> 'a option
+  val of_option: 'a option -> 'a t
+  val to_list: 'a t -> 'a list
+  val bot_of_list: 'a list -> 'a list t
+  val list_of_bot: 'a list t -> 'a list
+  val list_values: 'a t list -> 'a list
+
+  (** [elt >:: list] adds [elt] to the [list] if it is not bottom. *)
+  val add_to_list: 'a t -> 'a list -> 'a list
+end
+
+
+module Top : sig
+  type 'a t = 'a or_top
+
+  (** Operators *)
+  module Operators : sig
+    (** This monad propagates `Bottom and or `Top if needed. *)
+    val (>>-) : [< 'a t] -> ('a -> ([> 'b t] as 'c)) -> 'c
+
+    (** Use this monad if the following function returns a simple value. *)
+    val (>>-:) : [< 'a t] -> ('a -> 'b) -> [> 'b t]
+
+    (* Binding operators, applicative syntax *)
+    val (let+) : [< 'a t] -> ('a -> 'b) -> [> 'b t]
+    val (and+) : [< 'a t] -> [< 'b t] -> [> ('a * 'b) t]
+
+    (* Binding operators, monad syntax *)
+    val (let*) : [< 'a t] -> ('a -> ([> 'b t] as 'c)) -> 'c
+    val (and*) : [< 'a t] -> [< 'b t] -> [> ('a * 'b) t]
+  end
+
+  (** Access *)
+  val is_top: 'a t -> bool
+  val non_top: 'a t -> 'a
+  val value: top: 'a -> 'a t -> 'a
+
+  (** Datatype *)
+  val hash: ('a -> int) -> 'a t -> int
+  val equal: ('a -> 'a -> bool) -> 'a t -> 'a t -> bool
+  val compare: ('a -> 'a -> int)  -> 'a t -> 'a t -> int
+
+  (** Pretty-printing *)
+  val pretty_top :Format.formatter -> unit (* for %t specifier *)
+  val pretty :
+    (Format.formatter -> 'a -> unit) ->
+    Format.formatter -> 'a t -> unit
+
+  (** Lattice operators *)
+  val join: ('a -> 'a -> 'a t) -> 'a t -> 'a t -> 'a t
+  val narrow: ('a -> 'a -> 'a) -> 'a t -> 'a t -> 'a t
+
+  (** Combination *)
+  val zip: 'a t -> 'b t -> ('a * 'b) t (* `Top if any is `Top *)
+
+  (** Conversion *)
+  val to_option : 'a t -> 'a option
+  val of_option : 'a option -> 'a t
+end
+
+
+module TopBottom: sig
+  type 'a t = 'a or_top_bottom
+
+  (** Operators *)
+  (* In presence of simultaneous `Bottom and `Top in and+ / and*, everything
+     narrows down to `Bottom *)
+  module Operators : sig
+    (** This monad propagates `Bottom and or `Top if needed. *)
+    val (>>-) : [< 'a t] -> ('a -> ([> 'b t] as 'c)) -> 'c
+
+    (** Use this monad if the following function returns a simple value. *)
+    val (>>-:) : [< 'a t] -> ('a -> 'b) -> [> 'b t]
+
+    (* Binding operators, applicative syntax *)
+    val (let+) : [< 'a t] -> ('a -> 'b) -> [> 'b t]
+    val (and+) : [< 'a t] -> [< 'b t] -> [> ('a * 'b) t]
+
+    (* Binding operators, monad syntax *)
+    val (let*) : [< 'a t] -> ('a -> ([> 'b t] as 'c)) -> 'c
+    val (and*) : [< 'a t] -> [< 'b t] -> [> ('a * 'b) t]
+  end
+
+  (** Datatype *)
+  val hash: ('a -> int) -> 'a t -> int
+  val equal: ('a -> 'a -> bool) -> 'a t -> 'a t -> bool
+  val compare: ('a -> 'a -> int)  -> 'a t -> 'a t -> int
+
+  (** Pretty-printing *)
+  val pretty :
+    (Format.formatter -> 'a -> unit) ->
+    Format.formatter -> 'a t -> unit
+
+  (* Lattice operators *)
+  val join: ('a -> 'a -> [< 'a t]) -> 'a t -> 'a t -> 'a t
+  val narrow: ('a -> 'a -> [< 'a t]) -> 'a t -> 'a t -> 'a t
+end
diff --git a/src/kernel_services/abstract_interp/lmap.ml b/src/kernel_services/abstract_interp/lmap.ml
index c4d22d71789d1efdfa1a53cf9e892ff226eb35ad..afe85f50c5b901176bd733b5884258627c85ea3e 100644
--- a/src/kernel_services/abstract_interp/lmap.ml
+++ b/src/kernel_services/abstract_interp/lmap.ml
@@ -22,6 +22,7 @@
 
 open Abstract_interp
 open Locations
+open Lattice_bounds
 
 let msg_emitter = Lattice_messages.register "Lmap";;
 
@@ -41,7 +42,7 @@ module Make_LOffset
       and type widen_hint = V.numerical_widen_hint)
     (Default_offsetmap: sig
        val name: string
-       val default_offsetmap : Base.t -> Offsetmap.t Bottom.or_bottom
+       val default_offsetmap : Base.t -> Offsetmap.t or_bottom
        val default_contents: V.t default_contents
      end)
 =
@@ -631,7 +632,7 @@ struct
   let find_base_or_default b = function
     | Bottom -> `Bottom
     | Top -> `Top
-    | Map m -> (M.find_or_default b m :> _ Bottom.Top.or_top_bottom)
+    | Map m -> (M.find_or_default b m :> _ or_top_bottom)
 
   let remove_base b = function
     | Bottom -> Bottom
diff --git a/src/kernel_services/abstract_interp/lmap.mli b/src/kernel_services/abstract_interp/lmap.mli
index 0d2068a665479c7c61e385117913e26859100e7d..5eb0e0b0e2aa6283397122fe4bda0581ef19657a 100644
--- a/src/kernel_services/abstract_interp/lmap.mli
+++ b/src/kernel_services/abstract_interp/lmap.mli
@@ -44,7 +44,7 @@ module Make_LOffset
        val name: string
        (** Used to create different datatypes each time the functor is applied *)
 
-       val default_offsetmap : Base.t -> Offsetmap.t Bottom.or_bottom
+       val default_offsetmap : Base.t -> Offsetmap.t Lattice_bounds.or_bottom
        (** Value returned when a map is queried, and the base is not present.
            [`Bottom] indicates that the base is never bound in such a map. *)
 
diff --git a/src/kernel_services/abstract_interp/lmap_bitwise.ml b/src/kernel_services/abstract_interp/lmap_bitwise.ml
index 850a0189bba8890801e0300f1edb7607fa1bdbee..ee6e25cad0d1d230c328933d10ed64192b07ae5e 100644
--- a/src/kernel_services/abstract_interp/lmap_bitwise.ml
+++ b/src/kernel_services/abstract_interp/lmap_bitwise.ml
@@ -21,6 +21,7 @@
 (**************************************************************************)
 
 open Locations
+open Lattice_bounds
 
 exception Bitwise_cannot_copy
 
diff --git a/src/kernel_services/abstract_interp/lmap_sig.mli b/src/kernel_services/abstract_interp/lmap_sig.mli
index 00164382ae2f4fce610c6188eecb566fdd125a7e..2636e657c17e6994dbbc9ad21a0bad5d07643beb 100644
--- a/src/kernel_services/abstract_interp/lmap_sig.mli
+++ b/src/kernel_services/abstract_interp/lmap_sig.mli
@@ -94,7 +94,7 @@ val find: ?conflate_bottom:bool -> t -> location -> v
     is no Top value in the type {!v}. *)
 
 val copy_offsetmap :
-  Location_Bits.t -> Integer.t -> t -> offsetmap Bottom.or_bottom
+  Location_Bits.t -> Integer.t -> t -> offsetmap Lattice_bounds.or_bottom
 (** [copy_offsetmap alarms loc size m] returns the superposition of the
     ranges of [size] bits starting at [loc] within [m]. [size] must be
     strictly greater than zero. Return [None] if all pointed addresses are
@@ -103,10 +103,10 @@ val copy_offsetmap :
     @raise Error_Top when the location or the state are Top, and there
     is no Top value in the type {!v}. *)
 
-val find_base : Base.t -> t -> offsetmap Bottom.Top.or_top_bottom
+val find_base : Base.t -> t -> offsetmap Lattice_bounds.or_top_bottom
 (** @raise Not_found if the varid is not present in the map. *)
 
-val find_base_or_default : Base.t -> t -> offsetmap Bottom.Top.or_top_bottom
+val find_base_or_default : Base.t -> t -> offsetmap Lattice_bounds.or_top_bottom
 (** Same as [find_base], but return the default values for bases
     that are not currently present in the map. Prefer the use of this function
     to [find_base], unless you explicitly want to see if the base is bound. *)
diff --git a/src/kernel_services/abstract_interp/offsetmap_bitwise_sig.mli b/src/kernel_services/abstract_interp/offsetmap_bitwise_sig.mli
index de3bb300395095518239e2e3f1bd4e4fefa68f3d..d70edcda7c0a9e9e7f69f9c51989d30f633c98e0 100644
--- a/src/kernel_services/abstract_interp/offsetmap_bitwise_sig.mli
+++ b/src/kernel_services/abstract_interp/offsetmap_bitwise_sig.mli
@@ -67,11 +67,11 @@ val find_iset : validity:Base.validity -> intervals -> t -> v
 
 val add_binding_intervals :
   validity:Base.validity ->
-  exact:bool -> intervals -> v -> t -> t Bottom.or_bottom
+  exact:bool -> intervals -> v -> t -> t Lattice_bounds.or_bottom
 
 val add_binding_ival :
   validity:Base.validity ->
-  exact:bool -> Ival.t -> size:Int_Base.t -> v -> t -> t Bottom.or_bottom
+  exact:bool -> Ival.t -> size:Int_Base.t -> v -> t -> t Lattice_bounds.or_bottom
 
 
 (** {2 Creating an offsetmap} *)
@@ -83,7 +83,7 @@ val empty: t
 (** offsetmap containing no interval. *)
 
 val size_from_validity:
-  Base.validity -> Integer.t Bottom.or_bottom
+  Base.validity -> Integer.t Lattice_bounds.or_bottom
 (** [size_from_validity v] returns the size to be used when creating a
     new offsetmap for a base with validity [v]. This is a convention that
     should be shared by all modules that create offsetmaps.
diff --git a/src/kernel_services/abstract_interp/offsetmap_sig.mli b/src/kernel_services/abstract_interp/offsetmap_sig.mli
index 172a935d91313ae582f3be2daea2c1f30b9246bc..c653a13f9a4b79ff887e126d661f2b13bf0595fc 100644
--- a/src/kernel_services/abstract_interp/offsetmap_sig.mli
+++ b/src/kernel_services/abstract_interp/offsetmap_sig.mli
@@ -63,7 +63,7 @@ val of_list: ((t -> v -> t) -> t -> 'l -> t) -> 'l -> Int.t -> t
 val empty: t
 (** offsetmap containing no interval. *)
 
-val size_from_validity: Base.validity -> Integer.t Bottom.or_bottom
+val size_from_validity: Base.validity -> Integer.t Lattice_bounds.or_bottom
 (** [size_from_validity v] returns the size to be used when creating a
     new offsetmap for a base with validity [v]. This is a convention that
     must be shared by all modules that create offsetmaps, because operations
@@ -196,7 +196,7 @@ val find_imprecise_everywhere: t -> v
 val copy_slice:
   validity:Base.validity ->
   offsets:Ival.t -> size:Integer.t ->
-  t -> t Bottom.or_bottom
+  t -> t Lattice_bounds.or_bottom
 (** [copy_slice ~validity ~offsets ~size m] copies and merges the slices of
     [m] starting at offsets [offsets] and of size [size]. Offsets invalid
     according to [validity] are removed. [size] must be strictly greater
@@ -220,7 +220,7 @@ val update :
   offsets:Ival.t ->
   size:Int.t ->
   v ->
-  t -> t Bottom.or_bottom
+  t -> t Lattice_bounds.or_bottom
 (** [update ?origin ~validity ~exact ~offsets ~size v m] writes [v],
     of size [size], each [offsets] in [m]; [m] must be of the size implied by
     [validity]. [~exact=true] results in a strong update, while
@@ -235,7 +235,7 @@ val update_under :
   offsets:Ival.t ->
   size:Int.t ->
   v ->
-  t -> t Bottom.or_bottom
+  t -> t Lattice_bounds.or_bottom
 (** Same as {!update}, except that no over-approximation on the set
     of offsets or on the value written occurs. In case of imprecision,
     [m] is not updated. *)
@@ -244,7 +244,7 @@ val update_under :
 val update_imprecise_everywhere:
   validity:Base.validity ->
   Origin.t -> v ->
-  t -> t Bottom.or_bottom
+  t -> t Lattice_bounds.or_bottom
 (** [update_everywhere ~validity o v m] computes the offsetmap resulting
     from imprecisely writing [v] potentially anywhere where [m] is valid
     according to [validity]. If a value becomes too imprecise, [o] is used
@@ -256,7 +256,7 @@ val paste_slice:
   from:t ->
   size:Int.t ->
   offsets:Ival.t ->
-  t -> t Bottom.or_bottom
+  t -> t Lattice_bounds.or_bottom
 
 
 (** {2 Shape} *)
diff --git a/src/plugins/value/api/values_request.ml b/src/plugins/value/api/values_request.ml
index 784b1a0fa9ad832637b2d1a9d7f761b8f95e8b2f..8714daa8f222455631017568fc60ce4afdd39618 100644
--- a/src/plugins/value/api/values_request.ml
+++ b/src/plugins/value/api/values_request.ml
@@ -337,7 +337,7 @@ end
 module Proxy(A : Analysis.S) : EvaProxy = struct
 
   open Eval
-  type dstate = A.Dom.state or_top_or_bottom
+  type dstate = A.Dom.state or_top_bottom
 
   let get_precise_loc =
     let default = fun _ -> Precise_locs.loc_top in
diff --git a/src/plugins/value/domains/cvalue/builtins_malloc.ml b/src/plugins/value/domains/cvalue/builtins_malloc.ml
index a6145775c9145c21dbb1136ee66ab61136a8e44d..c29b62c4e48ea5ddbec3b8c669f8021cee8b0e97 100644
--- a/src/plugins/value/domains/cvalue/builtins_malloc.ml
+++ b/src/plugins/value/domains/cvalue/builtins_malloc.ml
@@ -24,6 +24,7 @@ open Cil_types
 open Abstract_interp
 open Locations
 open Cvalue
+open Lattice_bounds
 
 let dkey = Self.register_category "malloc"
 
diff --git a/src/plugins/value/domains/domain_builder.ml b/src/plugins/value/domains/domain_builder.ml
index 3c434d03e0633706083da76f9238596280e8f101..141c643cc703d84b082afa5a7af9e5b6355a0b92 100644
--- a/src/plugins/value/domains/domain_builder.ml
+++ b/src/plugins/value/domains/domain_builder.ml
@@ -52,7 +52,7 @@ module type LeafDomain = sig
     current_input:t -> previous_output:t -> t
 
   val show_expr: 'a -> t -> Format.formatter -> exp -> unit
-  val post_analysis: t Bottom.or_bottom -> unit
+  val post_analysis: t Lattice_bounds.or_bottom -> unit
 
   module Store: Domain_store.S with type t := t
 
diff --git a/src/plugins/value/domains/domain_builder.mli b/src/plugins/value/domains/domain_builder.mli
index 9be07c5c74e3d39836cbcf98dc05317445ebe381..bf3c05b8f0cc79efed1e2e4ec30131f737bd49df 100644
--- a/src/plugins/value/domains/domain_builder.mli
+++ b/src/plugins/value/domains/domain_builder.mli
@@ -58,7 +58,7 @@ module type LeafDomain = sig
     current_input:t -> previous_output:t -> t
 
   val show_expr: 'a -> t -> Format.formatter -> exp -> unit
-  val post_analysis: t Bottom.or_bottom -> unit
+  val post_analysis: t Lattice_bounds.or_bottom -> unit
 
   module Store: Domain_store.S with type t := t
 
diff --git a/src/plugins/value/domains/domain_store.ml b/src/plugins/value/domains/domain_store.ml
index 426f36a687d6e3b13010d9ca067d8b2f7b1e7c58..5692678cb22ce05a3e3932e157d225b667c02ed4 100644
--- a/src/plugins/value/domains/domain_store.ml
+++ b/src/plugins/value/domains/domain_store.ml
@@ -42,12 +42,12 @@ module type S = sig
   val get_initial_state: kernel_function -> t or_bottom
   val get_initial_state_by_callstack:
     ?selection:callstack list ->
-    kernel_function -> t Value_types.Callstack.Hashtbl.t or_top_or_bottom
+    kernel_function -> t Value_types.Callstack.Hashtbl.t or_top_bottom
 
   val get_stmt_state: after:bool -> stmt -> t or_bottom
   val get_stmt_state_by_callstack:
     ?selection:callstack list ->
-    after:bool -> stmt -> t Value_types.Callstack.Hashtbl.t or_top_or_bottom
+    after:bool -> stmt -> t Value_types.Callstack.Hashtbl.t or_top_bottom
 
   val mark_as_computed: unit -> unit
   val is_computed: unit -> bool
diff --git a/src/plugins/value/domains/domain_store.mli b/src/plugins/value/domains/domain_store.mli
index 97260867803e6f922f12c44d2bf2853dff4d67f4..e4d70dce5e61b1fbaf5cbb3e98f006153d557bc2 100644
--- a/src/plugins/value/domains/domain_store.mli
+++ b/src/plugins/value/domains/domain_store.mli
@@ -49,12 +49,12 @@ module type S = sig
   val get_initial_state: kernel_function -> t or_bottom
   val get_initial_state_by_callstack:
     ?selection:callstack list ->
-    kernel_function -> t Value_types.Callstack.Hashtbl.t or_top_or_bottom
+    kernel_function -> t Value_types.Callstack.Hashtbl.t or_top_bottom
 
   val get_stmt_state: after:bool -> stmt -> t or_bottom
   val get_stmt_state_by_callstack:
     ?selection:callstack list ->
-    after:bool -> stmt -> t Value_types.Callstack.Hashtbl.t or_top_or_bottom
+    after:bool -> stmt -> t Value_types.Callstack.Hashtbl.t or_top_bottom
 
   val mark_as_computed: unit -> unit
   val is_computed: unit -> bool
diff --git a/src/plugins/value/domains/gauges/gauges_domain.ml b/src/plugins/value/domains/gauges/gauges_domain.ml
index 27188a34302751add35377747f6ad6027edb0f48..7a91a6af3f8e2dc22c04e88287d12316f2853dd0 100644
--- a/src/plugins/value/domains/gauges/gauges_domain.ml
+++ b/src/plugins/value/domains/gauges/gauges_domain.ml
@@ -108,7 +108,7 @@ module G = struct
     let join = lift Integer.min Integer.max
     let add = lift Integer.add Integer.add
 
-    let narrow (min1, max1: t) (min2, max2: t) : t Bottom.or_bottom =
+    let narrow (min1, max1: t) (min2, max2: t) : t or_bottom =
       let minb = match min1, min2 with
         | Some i1, Some i2 -> Some (Integer.max i1 i2)
         | None, i | i, None -> i
diff --git a/src/plugins/value/domains/traces_domain.ml b/src/plugins/value/domains/traces_domain.ml
index 6341124d00598a7fec90ff64b3811920abe18d20..52e14219be6b7f3d87404deb6e778f55890cc0a2 100644
--- a/src/plugins/value/domains/traces_domain.ml
+++ b/src/plugins/value/domains/traces_domain.ml
@@ -30,6 +30,7 @@ module OCamlGraph = Graph
 module Frama_c_File = File
 open Cil_types
 open Cil_datatype
+open Lattice_bounds
 
 module Node : sig
   include Datatype.S_with_collections
diff --git a/src/plugins/value/engine/analysis.ml b/src/plugins/value/engine/analysis.ml
index 25fabab93298489eec675318ab166eaca0afa0dd..ca4771584258e22ee4118a368c3cbd5e4366acf8 100644
--- a/src/plugins/value/engine/analysis.ml
+++ b/src/plugins/value/engine/analysis.ml
@@ -38,12 +38,12 @@ module type Results = sig
   val get_stmt_state : after:bool -> stmt -> state or_bottom
   val get_stmt_state_by_callstack:
     ?selection:callstack list ->
-    after:bool -> stmt -> state Value_types.Callstack.Hashtbl.t or_top_or_bottom
+    after:bool -> stmt -> state Value_types.Callstack.Hashtbl.t or_top_bottom
   val get_initial_state:
     kernel_function -> state or_bottom
   val get_initial_state_by_callstack:
     ?selection:callstack list ->
-    kernel_function -> state Value_types.Callstack.Hashtbl.t or_top_or_bottom
+    kernel_function -> state Value_types.Callstack.Hashtbl.t or_top_bottom
 
   val eval_expr : state -> exp -> value evaluated
   val copy_lvalue: state -> lval -> value flagged_value evaluated
diff --git a/src/plugins/value/engine/analysis.mli b/src/plugins/value/engine/analysis.mli
index 92dfdb74955a4ac80169393ca2738ec52269ad2e..510972db9184b41e85601f6ef1c11cb2f390482c 100644
--- a/src/plugins/value/engine/analysis.mli
+++ b/src/plugins/value/engine/analysis.mli
@@ -32,12 +32,12 @@ module type Results = sig
   val get_stmt_state : after:bool -> stmt -> state or_bottom
   val get_stmt_state_by_callstack:
     ?selection:callstack list ->
-    after:bool -> stmt -> state Value_types.Callstack.Hashtbl.t or_top_or_bottom
+    after:bool -> stmt -> state Value_types.Callstack.Hashtbl.t or_top_bottom
   val get_initial_state:
     kernel_function -> state or_bottom
   val get_initial_state_by_callstack:
     ?selection:callstack list ->
-    kernel_function -> state Value_types.Callstack.Hashtbl.t or_top_or_bottom
+    kernel_function -> state Value_types.Callstack.Hashtbl.t or_top_bottom
 
   val eval_expr : state -> exp -> value evaluated
   val copy_lvalue: state -> lval -> value flagged_value evaluated
diff --git a/src/plugins/value/engine/initialization.mli b/src/plugins/value/engine/initialization.mli
index 3aa3687606e2a9d575bbd24bc00832f97dbdb3ce..cef8e46011c16f8e0bc83ebe4f0f6ccda44a999f 100644
--- a/src/plugins/value/engine/initialization.mli
+++ b/src/plugins/value/engine/initialization.mli
@@ -23,7 +23,7 @@
 (** Creation of the initial state of abstract domain. *)
 
 open Cil_types
-open Bottom.Type
+open Lattice_bounds
 
 module type S = sig
   type state
diff --git a/src/plugins/value/engine/iterator.ml b/src/plugins/value/engine/iterator.ml
index e728a44c4444f1673af2e72bda889435fdf25643..d9d50612ebb06d92a81cf5218fdffdb626428c9e 100644
--- a/src/plugins/value/engine/iterator.ml
+++ b/src/plugins/value/engine/iterator.ml
@@ -22,7 +22,8 @@
 
 open Cil_types
 open Interpreted_automata
-open Bottom.Type
+open Lattice_bounds
+open Bottom.Operators
 
 let check_signals, signal_abort =
   let signal_emitted = ref false in
diff --git a/src/plugins/value/engine/transfer_stmt.ml b/src/plugins/value/engine/transfer_stmt.ml
index dcc295fcd5bb4ef154823a35e86800bd23a7eb0d..8e3c04f6d31f20deb9bbaf4aa09966db3482974d 100644
--- a/src/plugins/value/engine/transfer_stmt.ml
+++ b/src/plugins/value/engine/transfer_stmt.ml
@@ -272,7 +272,7 @@ module Make (Abstract: Abstractions.Eva) = struct
       in
       if is_ret then assert (Alarmset.is_empty alarms);
       Alarmset.emit kinstr alarms;
-      eval >>- fun (assigned, valuation) ->
+      let* assigned, valuation = eval in
       let domain_valuation = Eval.to_domain_valuation valuation in
       let lvalue = { lval; ltyp; lloc } in
       Domain.assign kinstr lvalue expr assigned domain_valuation state
@@ -289,7 +289,7 @@ module Make (Abstract: Abstractions.Eva) = struct
     let eval, alarms = Eval.reduce state expr positive in
     (* TODO: check not comparable. *)
     Alarmset.emit (Kstmt stmt) alarms;
-    eval >>- fun valuation ->
+    let* valuation = eval in
     Domain.assume stmt expr positive (Eval.to_domain_valuation valuation) state
 
 
@@ -394,7 +394,7 @@ module Make (Abstract: Abstractions.Eva) = struct
     let safe_arguments = filter_safe_arguments valuation call in
     let empty = Eval.Valuation.empty in
     let reduce_one_argument acc argument =
-      acc >>- fun acc ->
+      let* acc = acc in
       let pre_value = match argument.avalue with
         | Assign pre_value -> `Value pre_value
         | Copy (_lv, pre_value) -> pre_value.v
@@ -407,8 +407,8 @@ module Make (Abstract: Abstractions.Eva) = struct
          If the call has copied the argument, it may be uninitialized. Thus,
          we also avoid the backward propagation if the formal is uninitialized
          here. This should not happen in the Assign case above. *)
-      fst (Eval.copy_lvalue ~valuation:empty ~subdivnb:0 state lval)
-      >>- fun (_valuation, post_value) ->
+      let* _valuation, post_value =
+        fst (Eval.copy_lvalue ~valuation:empty ~subdivnb:0 state lval) in
       if
         Bottom.is_included Value.is_included pre_value post_value.v
         || post_value.escaping || not post_value.initialized
@@ -423,10 +423,10 @@ module Make (Abstract: Abstractions.Eva) = struct
   let reduce_arguments reductions state =
     let valuation = `Value Eval.Valuation.empty in
     let reduce_one_argument valuation (argument, post_value) =
-      valuation >>- fun valuation ->
+      let* valuation = valuation in
       Eval.assume ~valuation state argument.concrete post_value
     in
-    List.fold_left reduce_one_argument valuation reductions >>- fun valuation ->
+    let* valuation = List.fold_left reduce_one_argument valuation reductions in
     Domain.update (Eval.to_domain_valuation valuation) state
 
   (* -------------------- Treat the results of a call ----------------------- *)
@@ -441,8 +441,8 @@ module Make (Abstract: Abstractions.Eva) = struct
     | Some _, None -> assert false
     | Some lval, Some vi_ret ->
       let exp_ret_caller = Eva_utils.lval_to_exp  (Var vi_ret, NoOffset) in
-      assign_ret state (Kstmt stmt) lval exp_ret_caller
-      >>-: fun state -> Domain.leave_scope kf_callee [vi_ret] state
+      let+ state = assign_ret state (Kstmt stmt) lval exp_ret_caller in
+      Domain.leave_scope kf_callee [vi_ret] state
 
   (* ---------------------- Make a one function call ------------------------ *)
 
@@ -475,16 +475,15 @@ module Make (Abstract: Abstractions.Eva) = struct
       (* Gathers the possible reductions on the value of the concrete arguments
          at the call site, according to the value of the formals at the post
          state of the called function. *)
-      gather_reduced_arguments call valuation state
-      >>- fun reductions ->
+      let* reductions = gather_reduced_arguments call valuation state in
       (* The formals (and the locals) of the called function leave scope. *)
       let post = Domain.leave_scope kf_callee leaving_vars state in
       let recursion = Option.map Recursion.revert recursion in
       (* Computes the state after the call, from the post state at the end of
          the called function, and the pre state at the call site. *)
-      Domain.finalize_call stmt call recursion ~pre ~post >>- fun state ->
+      let* state = Domain.finalize_call stmt call recursion ~pre ~post in
       (* Backward propagates the [reductions] on the concrete arguments. *)
-      reduce_arguments reductions state >>- fun state ->
+      let* state = reduce_arguments reductions state in
       treat_return ~kf_callee lv call.return stmt state
     in
     let states =
@@ -640,8 +639,8 @@ module Make (Abstract: Abstractions.Eva) = struct
       fun fmt subdivnb lval state ->
         try
           let offsm =
-            fst (Eval.lvaluate ~for_writing:false ~subdivnb state lval)
-            >>- fun (_, loc, _) ->
+            let* (_, loc, _) =
+              fst (Eval.lvaluate ~for_writing:false ~subdivnb state lval) in
             Eval_op.offsetmap_of_loc (get_ploc loc) (get_cvalue state)
           in
           let typ = Cil.typeOfLval lval in
@@ -748,7 +747,7 @@ module Make (Abstract: Abstractions.Eva) = struct
     Alarmset.emit ki_call alarms;
     let cacheable = ref Cacheable in
     let eval =
-      functions >>-: fun functions ->
+      let+ functions = functions in
       let current_kf = Eva_utils.current_kf () in
       let process_one_function kf valuation =
         (* The special Frama_C_ functions to print states are handled here. *)
@@ -761,7 +760,7 @@ module Make (Abstract: Abstractions.Eva) = struct
           let eval, alarms = make_call ~subdivnb kf args valuation state in
           Alarmset.emit ki_call alarms;
           let states =
-            eval >>-: fun (call, recursion, valuation) ->
+            let+ call, recursion, valuation = eval in
             (* Register the call. *)
             Eva_results.add_kf_caller call.kf ~caller:(current_kf, stmt);
             (* Do the call. *)
diff --git a/src/plugins/value/eval.ml b/src/plugins/value/eval.ml
index 24ec7fe01dffd408fcba0df899feca82fe44891b..c59224b89441c60ae40a58ebccd11d2990879a3d 100644
--- a/src/plugins/value/eval.ml
+++ b/src/plugins/value/eval.ml
@@ -28,10 +28,9 @@ open Cil_types
 (**                       {2 Lattice structure }                              *)
 (* -------------------------------------------------------------------------- *)
 
-include Bottom.Type
+include Lattice_bounds
+include Bottom.Operators
 
-type 'a or_top    = [ `Value of 'a | `Top ]
-type 'a or_top_or_bottom = [ `Value of 'a | `Top | `Bottom ]
 
 (* -------------------------------------------------------------------------- *)
 (**                     {2 Types for the evaluations }                        *)
diff --git a/src/plugins/value/eval.mli b/src/plugins/value/eval.mli
index f1220412daae8394c2042f5b4dbc1353220f8a89..76f96cf20bc10c0f141cb2ac03e1448bd620c1b8 100644
--- a/src/plugins/value/eval.mli
+++ b/src/plugins/value/eval.mli
@@ -31,13 +31,8 @@ open Cil_types
 (**                      {2 Lattice structure }                               *)
 (* -------------------------------------------------------------------------- *)
 
-include module type of Bottom.Type
-
-(** For some functions, the special value top (denoting no information)
-    is managed separately. *)
-type 'a or_top    = [ `Value of 'a | `Top ]
-
-type 'a or_top_or_bottom = [ `Value of 'a | `Top | `Bottom ]
+include module type of Lattice_bounds
+include module type of Bottom.Operators
 
 
 (* -------------------------------------------------------------------------- *)
diff --git a/src/plugins/value/gui_files/gui_eval.ml b/src/plugins/value/gui_files/gui_eval.ml
index c97449d1778ea9b41e420a52dff7b64f476b9649..05ca7822f598f6266d533fc24a0ec3495b52da7a 100644
--- a/src/plugins/value/gui_files/gui_eval.ml
+++ b/src/plugins/value/gui_files/gui_eval.ml
@@ -22,6 +22,7 @@
 
 open Cil_types
 open Gui_types
+open Lattice_bounds
 
 let results_kf_computed kf =
   Analysis.is_computed () &&
@@ -107,7 +108,7 @@ module type S = sig
   val lval_as_offsm_ev: (Analysis.Dom.t, lval, gui_offsetmap_res) evaluation_functions
   val lval_zone_ev: (Analysis.Dom.t, lval, Locations.Zone.t) evaluation_functions
   val null_ev: (Analysis.Dom.t, unit, gui_offsetmap_res) evaluation_functions
-  val exp_ev: (Analysis.Dom.t, exp, Analysis.Val.t Bottom.or_bottom) evaluation_functions
+  val exp_ev: (Analysis.Dom.t, exp, Analysis.Val.t or_bottom) evaluation_functions
   val lval_ev: (Analysis.Dom.t, lval, Analysis.Val.t Eval.flagged_value) evaluation_functions
 
   val tlval_ev:
@@ -116,20 +117,20 @@ module type S = sig
     gui_loc -> (Eval_terms.eval_env, term, Locations.Zone.t) evaluation_functions
   val term_ev:
     gui_loc ->
-    (Eval_terms.eval_env, term, Analysis.Val.t Bottom.or_bottom) evaluation_functions
+    (Eval_terms.eval_env, term, Analysis.Val.t or_bottom) evaluation_functions
 
   val predicate_ev:
     gui_loc ->
     (Eval_terms.eval_env,
      predicate,
-     Eval_terms.predicate_status Bottom.or_bottom
+     Eval_terms.predicate_status or_bottom
     ) evaluation_functions
 
   val predicate_with_red:
     gui_loc ->
     (Eval_terms.eval_env * (kinstr * Value_types.callstack),
      Red_statuses.alarm_or_property * predicate,
-     Eval_terms.predicate_status Bottom.or_bottom
+     Eval_terms.predicate_status or_bottom
     ) evaluation_functions
 
 
@@ -357,8 +358,8 @@ module Make (X: Analysis.S) = struct
   (* Maps from callstacks to Value states before and after a GUI location.
      The 'after' map is not always available. *)
   type states_by_callstack = {
-    states_before: X.Dom.t Value_types.Callstack.Hashtbl.t Eval.or_top_or_bottom;
-    states_after: X.Dom.t Value_types.Callstack.Hashtbl.t Eval.or_top_or_bottom;
+    states_before: X.Dom.t Value_types.Callstack.Hashtbl.t or_top_bottom;
+    states_after: X.Dom.t Value_types.Callstack.Hashtbl.t or_top_bottom;
   }
 
   let top_states_by_callstacks = { states_before = `Top; states_after = `Top }
diff --git a/src/plugins/value/gui_files/gui_eval.mli b/src/plugins/value/gui_files/gui_eval.mli
index 9b2686313a76f88cc70636ac761f18c253b299fd..8ee4a20c0c50d5a36d3a2f032aa980a39e5d8cf7 100644
--- a/src/plugins/value/gui_files/gui_eval.mli
+++ b/src/plugins/value/gui_files/gui_eval.mli
@@ -79,7 +79,7 @@ module type S = sig
     (Analysis.Dom.t, unit, gui_offsetmap_res) evaluation_functions
 
   val exp_ev:
-    (Analysis.Dom.t, exp, Analysis.Val.t Bottom.or_bottom) evaluation_functions
+    (Analysis.Dom.t, exp, Analysis.Val.t Lattice_bounds.or_bottom) evaluation_functions
 
   val lval_ev:
     (Analysis.Dom.t, lval, Analysis.Val.t Eval.flagged_value) evaluation_functions
@@ -97,20 +97,20 @@ module type S = sig
 
   val term_ev:
     gui_loc ->
-    (Eval_terms.eval_env, term, Analysis.Val.t Bottom.or_bottom) evaluation_functions
+    (Eval_terms.eval_env, term, Analysis.Val.t Lattice_bounds.or_bottom) evaluation_functions
 
   val predicate_ev:
     gui_loc ->
     (Eval_terms.eval_env,
      predicate,
-     Eval_terms.predicate_status Bottom.or_bottom
+     Eval_terms.predicate_status Lattice_bounds.or_bottom
     ) evaluation_functions
 
   val predicate_with_red:
     gui_loc ->
     (Eval_terms.eval_env * (kinstr * Value_types.callstack),
      Red_statuses.alarm_or_property * predicate,
-     Eval_terms.predicate_status Bottom.or_bottom
+     Eval_terms.predicate_status Lattice_bounds.or_bottom
     ) evaluation_functions
 
   val make_data_all_callstacks:
diff --git a/src/plugins/value/legacy/eval_annots.ml b/src/plugins/value/legacy/eval_annots.ml
index dc71060c5f2182ada0acb15ebdbb0cbd789654c0..8c83557fd2a766d1dde996152ae20a256e009ece 100644
--- a/src/plugins/value/legacy/eval_annots.ml
+++ b/src/plugins/value/legacy/eval_annots.ml
@@ -22,6 +22,7 @@
 
 open Cil_types
 open Eval_terms
+open Lattice_bounds
 
 let has_requires spec =
   let behav_has_requires b = b.b_requires <> [] in
diff --git a/src/plugins/value/legacy/eval_op.ml b/src/plugins/value/legacy/eval_op.ml
index 439c086ede5ca6e4061fc8e24cd76528efb0d559..8168a495b7df1f845cbfc59216cdd068bb68ea99 100644
--- a/src/plugins/value/legacy/eval_op.ml
+++ b/src/plugins/value/legacy/eval_op.ml
@@ -24,6 +24,7 @@ open Cvalue
 
 open Cil_types
 open Abstract_interp
+open Lattice_bounds
 
 let offsetmap_of_v ~typ v =
   let size = Int.of_int (Cil.bitsSizeOf typ) in
diff --git a/src/plugins/value/legacy/function_args.ml b/src/plugins/value/legacy/function_args.ml
index 30b612bb2d4de720e67d7f65ae1c750aa65b239b..876450c09b1f91f7154d6289cde1a2bc51ca0988 100644
--- a/src/plugins/value/legacy/function_args.ml
+++ b/src/plugins/value/legacy/function_args.ml
@@ -21,6 +21,7 @@
 (**************************************************************************)
 
 open Cil_types
+open Lattice_bounds
 
 exception Actual_is_bottom
 exception WrongFunctionType (* at a call through a pointer *)
diff --git a/src/plugins/value/partitioning/partition.ml b/src/plugins/value/partitioning/partition.ml
index f06b5022fa1ba45f47947b5aa225f2424fb8441b..b1c1c6f7e2444d0c53b2ea3cd6f2f3b7e1c0d8b3 100644
--- a/src/plugins/value/partitioning/partition.ml
+++ b/src/plugins/value/partitioning/partition.ml
@@ -20,7 +20,8 @@
 (*                                                                        *)
 (**************************************************************************)
 
-open Bottom.Type
+open Lattice_bounds
+open Bottom.Operators
 
 (* --- Split monitors --- *)
 
@@ -411,7 +412,7 @@ struct
     let build i acc =
       let value = Abstract.Val.inject_int (Cil.typeOf exp) i in
       let state =
-        Abstract.Eval.assume ~valuation state exp value >>- fun valuation ->
+        let* valuation = Abstract.Eval.assume ~valuation state exp value in
         (* Check the reduction *)
         Abstract.Dom.update (Abstract.Eval.to_domain_valuation valuation) state
       in
@@ -471,8 +472,8 @@ struct
     in
     let source = fst (predicate.Cil_types.pred_loc) in
     let aux positive =
-      Abstract.Dom.reduce_by_predicate env state predicate positive
-      >>-: fun state' ->
+      let+ state' =
+        Abstract.Dom.reduce_by_predicate env state predicate positive in
       let x = Abstract.Dom.evaluate_predicate env state' predicate in
       if x == Unknown
       then
@@ -482,7 +483,7 @@ struct
       let value = if positive then Integer.one else Integer.zero in
       value, state'
     in
-    Bottom.all [ aux true; aux false ]
+    Bottom.list_values [ aux true; aux false ]
 
   (* --- Applying partitioning actions onto flows --------------------------- *)
 
diff --git a/src/plugins/value/partitioning/trace_partitioning.ml b/src/plugins/value/partitioning/trace_partitioning.ml
index e1cc4261b38c25a272a04e2733484fc60dc67d2d..14df177983377e98e48733c679bbab5c6ea77a07 100644
--- a/src/plugins/value/partitioning/trace_partitioning.ml
+++ b/src/plugins/value/partitioning/trace_partitioning.ml
@@ -21,7 +21,6 @@
 (**************************************************************************)
 
 open Cil_types
-open Bottom.Type
 open Partition
 
 module Make
@@ -115,7 +114,7 @@ struct
   let expanded (s : store) : (key * state) list =
     Partition.to_list s.store_partition
 
-  let smashed (s : store) : state or_bottom =
+  let smashed (s : store) : state Lattice_bounds.or_bottom =
     match expanded s with
     | [] -> `Bottom
     | (_k, v1) :: l -> `Value (List.fold_left Domain.join v1 (List.map snd l))
diff --git a/src/plugins/value/partitioning/trace_partitioning.mli b/src/plugins/value/partitioning/trace_partitioning.mli
index c4d4d76cd11713c881842c50b387094a43874314..a21dc1af6723be80131a88ac289a7c8dbf00c3c9 100644
--- a/src/plugins/value/partitioning/trace_partitioning.mli
+++ b/src/plugins/value/partitioning/trace_partitioning.mli
@@ -20,8 +20,6 @@
 (*                                                                        *)
 (**************************************************************************)
 
-open Bottom.Type
-
 module Make
     (Abstract : Abstractions.Eva)
     (Kf : sig val kf: Cil_types.kernel_function end) :
@@ -59,7 +57,7 @@ sig
   (* --- Accessors --- *)
 
   val expanded : store -> (Partition.key * state) list
-  val smashed : store -> state or_bottom
+  val smashed : store -> state Lattice_bounds.or_bottom
   val contents : flow -> state list
   val is_empty_store : store -> bool
   val is_empty_flow : flow -> bool
diff --git a/src/plugins/value/utils/abstract.ml b/src/plugins/value/utils/abstract.ml
index 4fe15353218c9fdb8c59b69eb3dd9c2474c61dad..1b5be7c02b3367f62d1077fdaf654a2e5ce0cff3 100644
--- a/src/plugins/value/utils/abstract.ml
+++ b/src/plugins/value/utils/abstract.ml
@@ -89,6 +89,6 @@ module Domain = struct
 
     val get_cvalue: (t -> Cvalue.Model.t) option
     val get_cvalue_or_top: t -> Cvalue.Model.t
-    val get_cvalue_or_bottom: t Bottom.or_bottom -> Cvalue.Model.t
+    val get_cvalue_or_bottom: t Lattice_bounds.or_bottom -> Cvalue.Model.t
   end
 end
diff --git a/src/plugins/value/utils/abstract.mli b/src/plugins/value/utils/abstract.mli
index 6ef4a4e9132c93783c5756dffb51acef1b6b8b46..087cae69ffcb7aed9c473009cd4b25e244b5a41c 100644
--- a/src/plugins/value/utils/abstract.mli
+++ b/src/plugins/value/utils/abstract.mli
@@ -113,6 +113,6 @@ module Domain : sig
     (** Special accessors for the main cvalue domain. *)
     val get_cvalue: (t -> Cvalue.Model.t) option
     val get_cvalue_or_top: t -> Cvalue.Model.t
-    val get_cvalue_or_bottom: t Bottom.or_bottom -> Cvalue.Model.t
+    val get_cvalue_or_bottom: t Lattice_bounds.or_bottom -> Cvalue.Model.t
   end
 end
diff --git a/src/plugins/value/utils/results.ml b/src/plugins/value/utils/results.ml
index 25e8a8c1001b93eacfccdd75029beba110a02e30..34883ace8adb8f69fb01045657630c21715090d6 100644
--- a/src/plugins/value/utils/results.ml
+++ b/src/plugins/value/utils/results.ml
@@ -20,14 +20,7 @@
 (*                                                                        *)
 (**************************************************************************)
 
-open Bottom.Type
-
-type 'a or_top_bottom = 'a Bottom.Top.or_top_bottom
-
-let (>>>-:) t f = match t with
-  | `Top -> `Top
-  | `Bottom  -> `Bottom
-  | `Value t -> `Value (f t)
+open Lattice_bounds
 
 module Callstack = Value_types.Callstack
 
@@ -174,13 +167,15 @@ struct
   let map_join : type c.
     ('a -> 'b) -> ('b -> 'b -> 'b) -> ('a, c) t -> 'b or_top_bottom =
     fun map join ->
-    let map' x = `Value (map x) in
-    map_reduce default map' (Bottom.Top.join join)
+    let map' x = `Value (map x)
+    and join' = TopBottom.join (fun x y -> `Value (join x y)) in
+    map_reduce default map' join'
 
-  let map_join' : type c. ('a -> 'b or_top_bottom) -> ('b -> 'b -> 'b) ->
+  let map_join' : type c. ('a -> [< 'b or_top_bottom]) -> ('b -> 'b -> 'b) ->
     ('a, c) t -> 'b or_top_bottom =
     fun map join ->
-    map_reduce default map (Bottom.Top.join join)
+    let join' = TopBottom.join (fun x y -> `Value (join x y)) in
+    map_reduce default map join'
 end
 
 
@@ -191,6 +186,8 @@ type address
 
 module Make () =
 struct
+  open TopBottom.Operators
+
   module A = (val Analysis.current_analyzer ())
 
   module EvalTypes =
@@ -307,7 +304,7 @@ struct
     let join = (@)
     and extract state =
       let r,_alarms = A.Eval.eval_function_exp exp state in
-      r >>>-: List.map fst
+      r >>-: List.map fst
     in
     get req |> Response.map_join' extract join |> convert |>
     Result.map (List.sort_uniq Kernel_function.compare)
@@ -320,11 +317,11 @@ struct
     | None -> `Top
     | Some get ->
       let make_expr (x, _alarms) =
-        x >>>-: fun (_valuation, v) ->
+        x >>-: fun (_valuation, v) ->
         Cvalue.V_Or_Uninitialized.make ~initialized:true ~escaping:false (get v)
       in
       let make_lval (x, _alarms) =
-        x >>>-: fun (_valuation, v) ->
+        let+ _valuation, v = x in
         let Eval.{ v; initialized; escaping } = v in
         let v =
           match v with
@@ -340,6 +337,7 @@ struct
 
   let extract_value :
     type c. (value, c) evaluation -> (A.Val.t or_bottom, c) Response.t =
+    let open Bottom.Operators in
     function
     | LValue r ->
       let extract (x, _alarms) = x >>- (fun (_valuation,fv) -> fv.Eval.v) in
@@ -355,7 +353,7 @@ struct
     | Some get ->
       let join = Main_values.CVal.join in
       let extract value =
-        value >>>-: get
+        value >>-: get
       in
       extract_value res |> Response.map_join' extract join |> convert
 
@@ -364,7 +362,10 @@ struct
     (A.Loc.location or_bottom, c) Response.t * Locations.access =
     function
     | Address (r, access) ->
-      let extract (x, _alarms) = x >>-: (fun (_valuation,loc,_typ) -> loc) in
+      let extract (x, _alarms) =
+        let open Bottom.Operators in
+        let+ _valuation,loc,_typ = x in loc
+      in
       Response.map extract r, access
 
   let as_location res =
@@ -379,7 +380,7 @@ struct
         assert (Int_Base.equal loc2.size size);
         make_loc loc size
       and extract loc =
-        loc >>>-: get >>>-: Precise_locs.imprecise_location
+        loc >>-: get >>-: Precise_locs.imprecise_location
       in
       extract_loc res |> fst |> Response.map_join' extract join |> convert
 
@@ -391,7 +392,8 @@ struct
       let response_loc, access = extract_loc res in
       let join = Locations.Zone.join
       and extract loc =
-        loc >>>-: get >>>-: Precise_locs.enumerate_valid_bits access
+        loc >>-: get >>-:
+        Precise_locs.enumerate_valid_bits access
       in
       response_loc |> Response.map_join' extract join |> convert
 
@@ -400,7 +402,7 @@ struct
     | LValue r ->
       let join = (&&)
       and extract (x, _alarms) =
-        x >>>-: (fun (_valuation,fv) -> fv.Eval.initialized)
+        x >>-: (fun (_valuation,fv) -> fv.Eval.initialized)
       in
       begin match Response.map_join' extract join r with
         | `Bottom | `Top -> false
diff --git a/src/plugins/value/utils/unit_tests.ml b/src/plugins/value/utils/unit_tests.ml
index 78f38064bd355e254d02e8a9b39fe6a24173fdac..bfa09e7c518d259f23e17d5da0c5b3a5a057356c 100644
--- a/src/plugins/value/utils/unit_tests.ml
+++ b/src/plugins/value/utils/unit_tests.ml
@@ -21,6 +21,7 @@
 (**************************************************************************)
 
 open Cil_types
+open Lattice_bounds
 
 (* If true, prints each operation performed for the tests. Otherwise, only
    prints wrong operations. *)
diff --git a/src/plugins/value/values/cvalue_forward.ml b/src/plugins/value/values/cvalue_forward.ml
index b1a91b8758b3ce1425776f7ae3cec963bcca1c49..550be0376e2a9b0f0a7ad39175b9e3de699d1ad9 100644
--- a/src/plugins/value/values/cvalue_forward.ml
+++ b/src/plugins/value/values/cvalue_forward.ml
@@ -23,6 +23,7 @@
 open Cvalue
 open Cil_types
 open Abstract_value
+open Lattice_bounds
 
 (* --------------------------------------------------------------------------
                                Comparison
diff --git a/src/plugins/value/values/numerors/numerors_interval.ml b/src/plugins/value/values/numerors/numerors_interval.ml
index ded1e62a5ae622753371d86bda765221ad9f8ca4..9858daa14af736aab130686424b9fd01bd78bf9e 100644
--- a/src/plugins/value/values/numerors/numerors_interval.ml
+++ b/src/plugins/value/values/numerors/numerors_interval.ml
@@ -462,7 +462,7 @@ let backward_op (op : operator) fnan ?(prec = Precisions.Real) value result () =
           let x = op ~rnd:Rounding.Near  ~prec xres yval in
           let y = op ~rnd:Rounding.Near  ~prec yres xval in
           `Value (make ~nan:false x y)
-    in Bottom.join join reduced_for_nan reduced_for_finite
+    in Lattice_bounds.Bottom.join join reduced_for_nan reduced_for_finite
 [@@inline]
 
 let synthetize left right =
diff --git a/src/plugins/value/values/numerors/numerors_interval.mli b/src/plugins/value/values/numerors/numerors_interval.mli
index 8ec3edb9281a04cb0b8df6dbb2ae70e42841fb75..395d5c54fe829e2e1a59cd8b32a2690ac61113fe 100644
--- a/src/plugins/value/values/numerors/numerors_interval.mli
+++ b/src/plugins/value/values/numerors/numerors_interval.mli
@@ -175,17 +175,17 @@ val exp    : ?prec:Precisions.t -> t -> t
 
 (** These functions perform backward propagation on intervals using the
     precision <prec> *)
-val backward_le : ?prec:Precisions.t -> t -> t -> t Bottom.or_bottom
-val backward_lt : ?prec:Precisions.t -> t -> t -> t Bottom.or_bottom
-val backward_ge : ?prec:Precisions.t -> t -> t -> t Bottom.or_bottom
-val backward_gt : ?prec:Precisions.t -> t -> t -> t Bottom.or_bottom
+val backward_le : ?prec:Precisions.t -> t -> t -> t Lattice_bounds.or_bottom
+val backward_lt : ?prec:Precisions.t -> t -> t -> t Lattice_bounds.or_bottom
+val backward_ge : ?prec:Precisions.t -> t -> t -> t Lattice_bounds.or_bottom
+val backward_gt : ?prec:Precisions.t -> t -> t -> t Lattice_bounds.or_bottom
 
 (** These functions perform backward propagation for arithmetic *)
 val backward_add : ?prec:Precisions.t -> left:t -> right:t ->
-  result:t -> unit -> (t * t) Bottom.or_bottom
+  result:t -> unit -> (t * t) Lattice_bounds.or_bottom
 val backward_sub : ?prec:Precisions.t -> left:t -> right:t ->
-  result:t -> unit -> (t * t) Bottom.or_bottom
+  result:t -> unit -> (t * t) Lattice_bounds.or_bottom
 val backward_mul : ?prec:Precisions.t -> left:t -> right:t ->
-  result:t -> unit -> (t * t) Bottom.or_bottom
+  result:t -> unit -> (t * t) Lattice_bounds.or_bottom
 val backward_div : ?prec:Precisions.t -> left:t -> right:t ->
-  result:t -> unit -> (t * t) Bottom.or_bottom
+  result:t -> unit -> (t * t) Lattice_bounds.or_bottom
diff --git a/src/plugins/value_types/cvalue.ml b/src/plugins/value_types/cvalue.ml
index 6a236513097a604c4fe7822cde08b948cc6370c5..61fc238db742832bc5ad2a2a42e13f2acd0cfbb8 100644
--- a/src/plugins/value_types/cvalue.ml
+++ b/src/plugins/value_types/cvalue.ml
@@ -259,7 +259,7 @@ module V = struct
 
   (** Comparisons *)
 
-  open Bottom.Type
+  open Lattice_bounds.Bottom.Operators
 
   let backward_mult_int_left ~right ~result =
     try
diff --git a/src/plugins/value_types/cvalue.mli b/src/plugins/value_types/cvalue.mli
index 4573934e9929fa74a5a135571d8077c983a0f15e..06768eed07afa94a17c98874bd19959a3aeb5cec 100644
--- a/src/plugins/value_types/cvalue.mli
+++ b/src/plugins/value_types/cvalue.mli
@@ -81,7 +81,7 @@ module V : sig
   val of_char : char -> t
   val of_int64: int64 -> t
 
-  val backward_mult_int_left: right:t -> result:t -> t option Bottom.or_bottom
+  val backward_mult_int_left: right:t -> result:t -> t option Lattice_bounds.or_bottom
 
   val backward_comp_int_left: Comp.t -> t -> t -> t
   val backward_comp_float_left_true: Comp.t -> Fval.kind -> t -> t -> t
@@ -241,15 +241,15 @@ module V_Offsetmap: sig
     with type v = V_Or_Uninitialized.t
      and type widen_hint = V_Or_Uninitialized.numerical_widen_hint
 
-  val narrow: t -> t -> t Bottom.Type.or_bottom
-  val narrow_reinterpret: t -> t -> t Bottom.Type.or_bottom
+  val narrow: t -> t -> t Lattice_bounds.or_bottom
+  val narrow_reinterpret: t -> t -> t Lattice_bounds.or_bottom
   (** See the corresponding functions in {!Offsetmap_sig}. *)
 end
 
 
 (** Values bound by default to a variable. *)
 module Default_offsetmap: sig
-  val default_offsetmap : Base.t -> V_Offsetmap.t Bottom.or_bottom
+  val default_offsetmap : Base.t -> V_Offsetmap.t Lattice_bounds.or_bottom
 end
 
 (** Memories. They are maps from bases to memory slices *)
diff --git a/tests/builtins/oracle/allocated.0.res.oracle b/tests/builtins/oracle/allocated.0.res.oracle
index 78bb3d8a95aaf2d0c061cd1d62396def409a63f0..25fe2055044456adf9034cd035c16e7f9f692ce9 100644
--- a/tests/builtins/oracle/allocated.0.res.oracle
+++ b/tests/builtins/oracle/allocated.0.res.oracle
@@ -16,7 +16,7 @@
 [eva] allocated.c:31: Call to builtin free
 [eva] allocated.c:31: function free: precondition 'freeable' got status valid.
 [eva:malloc] allocated.c:31: strong free on bases: {__malloc_main_l25}
-[eva] allocated.c:32: Frama_C_show_each_p_after_free: Bottom
+[eva] allocated.c:32: Frama_C_show_each_p_after_free: ⊥
 [eva] allocated.c:36: Call to builtin malloc
 [eva] allocated.c:36: allocating variable __malloc_main_l36
 [eva] allocated.c:36: assertion got status valid.
@@ -149,7 +149,7 @@
 [eva] allocated.c:120: Call to builtin malloc
 [eva] allocated.c:120: allocating variable __malloc_main_l120
 [eva] allocated.c:120: Frama_C_show_each: {{ &__malloc_main_l120 }}
-[eva] allocated.c:123: Frama_C_show_each: Bottom
+[eva] allocated.c:123: Frama_C_show_each: ⊥
 [eva] allocated.c:125: Call to builtin free
 [eva] allocated.c:125: function free: precondition 'freeable' got status valid.
 [eva:malloc] allocated.c:125: strong free on bases: {__malloc_main_l120}
diff --git a/tests/builtins/oracle/allocated.1.res.oracle b/tests/builtins/oracle/allocated.1.res.oracle
index ebfce7b0022a825db7b9d5c25a7faa4881e77c96..a944c57c4e6c64a80c7f9f266b7ee9c6ba157289 100644
--- a/tests/builtins/oracle/allocated.1.res.oracle
+++ b/tests/builtins/oracle/allocated.1.res.oracle
@@ -16,7 +16,7 @@
 [eva] allocated.c:31: Call to builtin free
 [eva] allocated.c:31: function free: precondition 'freeable' got status valid.
 [eva:malloc] allocated.c:31: strong free on bases: {__malloc_main_l25}
-[eva] allocated.c:32: Frama_C_show_each_p_after_free: Bottom
+[eva] allocated.c:32: Frama_C_show_each_p_after_free: ⊥
 [eva] allocated.c:36: Call to builtin malloc
 [eva] allocated.c:36: allocating variable __malloc_main_l36
 [eva] allocated.c:36: assertion got status valid.
@@ -636,7 +636,7 @@
 [eva] allocated.c:120: Call to builtin malloc
 [eva] allocated.c:120: allocating variable __malloc_main_l120
 [eva] allocated.c:120: Frama_C_show_each: {{ &__malloc_main_l120 }}
-[eva] allocated.c:123: Frama_C_show_each: Bottom
+[eva] allocated.c:123: Frama_C_show_each: ⊥
 [eva] allocated.c:125: Call to builtin free
 [eva] allocated.c:125: function free: precondition 'freeable' got status valid.
 [eva:malloc] allocated.c:125: strong free on bases: {__malloc_main_l120}
diff --git a/tests/float/oracle/conv.res.oracle b/tests/float/oracle/conv.res.oracle
index daa38ec7a842f43d823967175d5234eb55af4312..dea66da8e28d30a16b7a97441834f0ffc96b50ff 100644
--- a/tests/float/oracle/conv.res.oracle
+++ b/tests/float/oracle/conv.res.oracle
@@ -38,16 +38,16 @@
 [eva] conv.i:69: Frama_C_show_each: [4.94065645841e-322 .. 9.22442153475e+159]
 [eva] conv.i:73: Frama_C_show_each: {1.79769313486e+308}
 [eva] conv.i:74: assertion got status valid.
-[eva] conv.i:77: Frama_C_show_each: Bottom
-[eva] conv.i:80: Frama_C_show_each: Bottom
+[eva] conv.i:77: Frama_C_show_each: ⊥
+[eva] conv.i:80: Frama_C_show_each: ⊥
 [eva] conv.i:84: Frama_C_show_each: {-1.79769313486e+308}
 [eva] conv.i:85: assertion got status valid.
-[eva] conv.i:88: Frama_C_show_each: Bottom
+[eva] conv.i:88: Frama_C_show_each: ⊥
 [eva] conv.i:91: Frama_C_show_each: [0. .. 4.94065645841e-324]
 [eva:alarm] conv.i:94: Warning: assertion got status unknown.
-[eva] conv.i:95: Frama_C_show_each: Bottom
+[eva] conv.i:95: Frama_C_show_each: ⊥
 [eva] conv.i:98: Frama_C_show_each: {0}
-[eva] conv.i:101: Frama_C_show_each: Bottom
+[eva] conv.i:101: Frama_C_show_each: ⊥
 [eva] Recording results for main2
 [eva] Done for function main2
 [eva] Recording results for main
diff --git a/tests/value/oracle/partitioning-annots.0.res.oracle b/tests/value/oracle/partitioning-annots.0.res.oracle
index 55c450297df40885a409f0f701b45ffd30284441..a9944c463d097f25c3d87b231526dd26e7f0ce46 100644
--- a/tests/value/oracle/partitioning-annots.0.res.oracle
+++ b/tests/value/oracle/partitioning-annots.0.res.oracle
@@ -76,8 +76,7 @@
 [eva] partitioning-annots.c:100: Frama_C_show_each_split_with_uninit: {2}, {2}
 [eva] partitioning-annots.c:100: Frama_C_show_each_split_with_uninit: {1}, {1}
 [eva] partitioning-annots.c:100: Frama_C_show_each_split_with_uninit: {0}, {0}
-[eva] partitioning-annots.c:100: 
-  Frama_C_show_each_split_with_uninit: Bottom, Bottom
+[eva] partitioning-annots.c:100: Frama_C_show_each_split_with_uninit: ⊥, ⊥
 [eva] partitioning-annots.c:102: Frama_C_show_each_no_split: {0}, {0; 1; 2}
 [eva] computing for function Frama_C_interval <- test_dynamic_split <- main.
   Called from partitioning-annots.c:103.