From 2689d15e0f1975f7fba4dae7e99a2c30d491212b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?C=C3=A9cile=20RUET-CROS?= <cecile.ruet-cros@cea.fr>
Date: Fri, 30 Aug 2024 09:31:33 +0200
Subject: [PATCH] [wp] MemBornat

# squashed from previous dev
---
 src/plugins/wp/Dispatcher.ml                  |  279 --
 src/plugins/wp/Factory.ml                     |   17 +-
 src/plugins/wp/Factory.mli                    |    2 +-
 src/plugins/wp/MemBornat.ml                   | 2449 +++++++++++++++++
 .../wp/{Dispatcher.mli => MemBornat.mli}      |   53 +-
 src/plugins/wp/MemBytes.ml                    |   14 +
 src/plugins/wp/MemDispatch.ml                 |  715 -----
 src/plugins/wp/MemLoader.mli                  |    2 +
 src/plugins/wp/MemTyped.ml                    |   16 +
 src/plugins/wp/MemTyped.mli                   |   32 +
 src/plugins/wp/RegionAnalysis.ml              |  224 ++
 .../{MemDispatch.mli => RegionAnalysis.mli}   |   42 +-
 src/plugins/wp/ctypes.ml                      |   27 +
 src/plugins/wp/ctypes.mli                     |    1 +
 src/plugins/wp/gui/GuiPanel.ml                |    4 +-
 15 files changed, 2849 insertions(+), 1028 deletions(-)
 delete mode 100644 src/plugins/wp/Dispatcher.ml
 create mode 100644 src/plugins/wp/MemBornat.ml
 rename src/plugins/wp/{Dispatcher.mli => MemBornat.mli} (53%)
 delete mode 100644 src/plugins/wp/MemDispatch.ml
 create mode 100644 src/plugins/wp/RegionAnalysis.ml
 rename src/plugins/wp/{MemDispatch.mli => RegionAnalysis.mli} (61%)

diff --git a/src/plugins/wp/Dispatcher.ml b/src/plugins/wp/Dispatcher.ml
deleted file mode 100644
index c52f5d3a46a..00000000000
--- a/src/plugins/wp/Dispatcher.ml
+++ /dev/null
@@ -1,279 +0,0 @@
-(**************************************************************************)
-(*                                                                        *)
-(*  This file is part of WP plug-in of Frama-C.                           *)
-(*                                                                        *)
-(*  Copyright (C) 2007-2024                                               *)
-(*    CEA (Commissariat a l'energie atomique et aux energies              *)
-(*         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).            *)
-(*                                                                        *)
-(**************************************************************************)
-
-open Either
-open Lang.F
-open Ctypes
-open Cil_types
-open Interpreted_automata
-open Sigs
-
-
-let rec partition_terminal_recursive f accl accr = function
-  | [] -> (accl, accr)
-  | c :: rest -> match f c with
-    | Left  _ -> partition_terminal_recursive f (c::accl) accr rest
-    | Right _ -> partition_terminal_recursive f accl (c::accr) rest
-
-let partition (f: 'c -> ('a,'b) Either.t) (l:'c list) : 'c list * 'c list =
-  partition_terminal_recursive f [] [] l
-
-let rec split_terminal_recursive (accl : 'a list) (accr : 'b list) = function
-  | [] -> (accl, accr)
-  | (Left  l) :: rest -> split_terminal_recursive (l::accl) accr rest
-  | (Right r) :: rest -> split_terminal_recursive accl (r::accr) rest
-
-let split l = split_terminal_recursive [] [] l
-
-
-module type Dispatcher =
-sig
-
-  type loc_left
-  type loc_right
-
-  module ML : Sigs.Model with type loc = loc_left
-  module MR : Sigs.Model with type loc = loc_right
-
-  type loc = (loc_left, loc_right) Either.t
-
-  val null : loc
-  val is_null : loc -> pred
-  val cvar : varinfo -> loc
-  val pointer_loc : QED.term -> loc
-  val loc_of_int : c_object -> QED.term -> loc
-
-  val deref_left  : loc_left  -> loc_left  -> loc
-  val deref_right : loc_right -> loc_right -> loc
-  val literal : eid:int -> Cstring.cst -> loc
-
-
-  (* utilities *)
-  val hypotheses : MemoryContext.partition -> MemoryContext.partition
-  val configure_ia: automaton -> vertex binder
-
-end
-
-
-module CollectionCObject = Qed.Collection.Make(struct
-    type t      = Ctypes.c_object
-    let compare = Ctypes.compare
-    let hash    = Ctypes.hash
-    let equal   = Ctypes.equal
-  end)
-
-
-module TySet = CollectionCObject.Set
-
-module RegionAssociator = struct
-  (* Data : WpContext.Data with type key = Key.t *)
-  type model = Typed | Bytes
-  type key = Region.node
-  type data = model
-  let name = "WP.Dispatcher.RegionDispatch"
-  let rec compile (region:Region.node) : model =
-    let kf =
-      match snd @@ WpContext.get_context () with
-      | Global -> raise Not_found
-      | Kf f -> f
-    in
-    let map = Region.get_map kf in
-    (* a. if access types are different (c_object), then memBytes *)
-    let add_type set ty = TySet.add (Ctypes.object_of ty) set in
-    let types = TySet.empty in
-    let types = List.fold_left add_type types @@ Region.reads map region in
-    let types = List.fold_left add_type types @@ Region.writes map region in
-    let types = List.fold_left add_type types @@ Region.shifts map region in
-    if List.length @@ TySet.elements types > 1 then Bytes else
-      (* b. if access type is aggregate with a union inside, then memBytes *)
-      let rec is_aggregate_with_union (ty:c_object) : bool =
-        match ty with
-        | C_int _ | C_float _ | C_pointer _ -> false
-        | C_comp compinfo ->
-          if compinfo.cstruct then true
-          else begin match compinfo.cfields with
-            | None -> false
-            | Some l -> List.exists (fun field -> is_aggregate_with_union @@ C_comp field.fcomp) l
-          end
-        | C_array arrayinfo -> is_aggregate_with_union (object_of arrayinfo.arr_element)
-      in
-      if TySet.exists is_aggregate_with_union types then Bytes else
-        (* c. if at least one of the pointed_by regions is memBytes, then memBytes *)
-        let pointed_by = Region.pointed_by map region in
-        let model_is_memBytes r = Bytes == compile r in
-        if List.exists model_is_memBytes pointed_by then Bytes else
-          (* d. otherwise if none of the above, then memTyped *)
-          Typed
-end
-
-
-module Make (ML: Sigs.Model) (MR: Sigs.Model) : Dispatcher =
-struct
-  type loc_left  = ML.loc
-  type loc_right = MR.loc
-
-  module ML = ML (* intended to be MemTyped *)
-  module MR = MR (* intended to be MemBytes *)
-
-  type loc = (loc_left, loc_right) Either.t
-
-  (** Internal handling of regions *)
-  (* Keeping track of the decision to apply which memory model to each region *)
-  module RegionDispatch = WpContext.Generator
-      (struct
-        (* Key : WPContext.Key *)
-        type t = Region.node
-        let compare a b = Int.compare (Region.get_id a) (Region.get_id b)
-        let pretty fmt r = Format.fprintf fmt "R%03d" (Region.get_id r)
-      end)
-      (RegionAssociator)
-
-
-  (** Public API of Dispatch *)
-
-  let null = Left ML.null
-  let is_null = function
-    | Left  ll -> ML.is_null ll
-    | Right lr -> MR.is_null lr
-
-  let cvar (var:varinfo) : loc = (* TODO *)
-    let f : kernel_function =
-      match snd @@ WpContext.get_context () with
-      | Global -> raise Not_found
-      | Kf f -> f
-    in
-    let map_regions = Region.get_map f in
-    let region = Region.cvar map_regions var in
-    match RegionDispatch.get region with
-    | RegionAssociator.Typed -> Left  (ML.cvar var)
-    | RegionAssociator.Bytes -> Right (MR.cvar var)
-
-
-  let pointer_loc term =
-    let region = assert false in
-    match RegionDispatch.get region with
-    | RegionAssociator.Typed -> Left  (ML.pointer_loc term)
-    | RegionAssociator.Bytes -> Right (MR.pointer_loc term)
-
-  let loc_of_int _ty _term = (* TODO *) null
-
-  let literal ~eid:_eid _const = (* TODO *) null
-
-  let deref_left  _ll1 ll2 = (* TODO *) Left  ll2
-  let deref_right _lr1 lr2 = (* TODO *) Right lr2
-
-
-  let hypotheses partition = partition
-  let configure_ia automata = (* TODO *)
-    ML.configure_ia automata
-
-end
-
-
-(*
-module MultiModuleDispatcher = struct
-
-  module Models = struct
-    (** Encoding indexes as types (not as integers) *)
-    type    z = Z       (** Zero *)
-    type 'a s = S of 'a (** Successor function *)
-
-    (** Elements from the list,
-        a  [n multiloc] corresponds to the type [loc] of the module at index [n] *)
-    type _ multiloc = ..
-
-
-    (** Index aware module type *)
-    module type IndexAware_SigsModel = sig
-      include Sigs.Model
-      type pos
-      val to_multiloc : loc -> pos multiloc
-      val of_multiloc : pos multiloc -> loc
-    end
-
-    (** Index aware list type *)
-    type 'pos indexAware_list =
-      | Nil: z indexAware_list
-      | Cons:
-          'pos indexAware_list * (module IndexAware_SigsModel with type pos = 'pos) ->
-          'pos s indexAware_list
-
-    (** Wrapper for the list with its size *)
-    module type SizeAware_List = sig
-      type size
-      val model_list : size indexAware_list
-      val get : int -> (module Sigs.Model)
-    end
-
-    (** The list is stored as a mutable reference *)
-    let model_list = ref (module struct
-      type size = z
-      let model_list = Nil
-      let get _ = raise Not_found
-    end:SizeAware_List)
-
-    (** Add a module to the list *)
-    let add_model (module Model : Sigs.Model) =
-      let module L = (val !model_list) in
-      model_list := (module struct
-        (* Create a new constructor for model at position size *)
-        type _ multiloc += Loc : Model.loc -> L.size multiloc
-        type size = L.size s (* New size of list *)
-
-        let model_list = Cons(L.model_list,
-          (module struct
-            include Model
-            type pos = L.size
-            let to_multiloc x = Loc x
-            let of_multiloc = function
-              | Loc x -> x
-              | _ -> raise (Invalid_argument "Dispatcher.MultiDispatcher.Models: Dynamic typing error")
-          end))
-        let get = function
-        | 0 -> (module Model:Sigs.Model)
-        | n when n < 0 -> raise Not_found
-        | n -> L.get (n-1)
-      end)
-
-      type 'a index =
-      | Zero of z
-      | Succ of 'a index s
-
-      (* (* the following is not typing... even though it would be more efficient *)
-      let rec get (index: _ index) (models: 'c indexAware_list) : (module Sigs.Model) =
-        begin match (index, models) with
-         | (Zero Z, Cons ((_rest : _ indexAware_list), model)) -> model
-         | (Succ (S index'), Cons ((rest : _ indexAware_list), (module _model : IndexAware_SigsModel))) ->
-          get index' rest
-        end
-        *)
-
-    (*
-      (* make type elt private here *)
-
-      let () = add_model (module Int)
-      let () = add_model (module Bool)
-      let () = add_model (module Char)
-    *)
-  end
-end
-*)
diff --git a/src/plugins/wp/Factory.ml b/src/plugins/wp/Factory.ml
index f173e8b2e0b..6b824e14825 100644
--- a/src/plugins/wp/Factory.ml
+++ b/src/plugins/wp/Factory.ml
@@ -24,7 +24,7 @@
 (* --- Model Factory                                                      --- *)
 (* -------------------------------------------------------------------------- *)
 
-type mheap = Hoare | ZeroAlias | Typed of MemTyped.pointer | Eva | Bytes
+type mheap = Hoare | ZeroAlias | Typed of MemTyped.pointer | Eva | Bytes | Bornat
 type mvar = Raw | Var | Ref | Caveat
 
 type setup = {
@@ -69,6 +69,7 @@ let descr_mheap d = function
   | Typed p -> main d "typed" ; descr_mtyped d p
   | Eva -> main d "eva"
   | Bytes -> main d "bytes"
+  | Bornat -> main d "bornat"
 
 let descr_mvar d = function
   | Var -> ()
@@ -202,9 +203,11 @@ end
 module Register(V : MemVar.VarUsage)(M : Sigs.Model)
   = MemVar.Make(MakeVarUsage(V))(M)
 
+
 module Model_Hoare_Raw = Register(MemVar.Raw)(MemEmpty)
 module Model_Hoare_Ref = Register(Ref)(MemEmpty)
-module Model_Typed_Var = Register(Var)(MemTyped)
+
+module Model_Typed_Var = Register(Var)(MemTyped) (* modèle de base, mettre MemBornat *)
 module Model_Typed_Ref = Register(Ref)(MemTyped)
 module Model_Bytes_Var = Register(Var)(MemBytes)
 module Model_Bytes_Ref = Register(Ref)(MemBytes)
@@ -220,6 +223,7 @@ struct
   module A = LogicAssigns.Make(M)(L)
 end
 
+
 module Comp_MemZeroAlias = MakeCompiler(MemZeroAlias)
 
 module Comp_Hoare_Raw = MakeCompiler(Model_Hoare_Raw)
@@ -236,6 +240,11 @@ module Comp_Bytes_Var = MakeCompiler(Model_Bytes_Var)
 module Comp_Bytes_Ref = MakeCompiler(Model_Bytes_Ref)
 
 module Comp_MemVal = MakeCompiler(MemVal)
+module Comp_Bornat =
+  MakeCompiler
+    (MemVar.Make
+       (MemVar.Static)
+       (MemBornat.MemMake(RegionAnalysis.R)(MemBytes)))
 
 
 let compiler mheap mvar : (module Sigs.Compiler) =
@@ -251,7 +260,7 @@ let compiler mheap mvar : (module Sigs.Compiler) =
   | Bytes, Raw        -> (module Comp_MemBytes)
   | Bytes, Var        -> (module Comp_Bytes_Var)
   | Bytes, Ref        -> (module Comp_Bytes_Ref)
-
+  | Bornat, _         -> (module Comp_Bornat)
 
 (* -------------------------------------------------------------------------- *)
 (* --- Tuning                                                             --- *)
@@ -270,6 +279,7 @@ let configure_mheap = function
       Context.pop MemTyped.pointer orig_memtyped_pointer
     in
     rollback
+  | Bornat -> MemBytes.configure ()
 
 let configure_driver setup driver () =
   let rollback_mheap = configure_mheap setup.mheap in
@@ -345,6 +355,7 @@ let update_config ~warning m s = function
   | "TYPED" -> { s with mheap = Typed MemTyped.Fits }
   | "CAST" -> { s with mheap = Typed MemTyped.Unsafe }
   | "NOCAST" -> { s with mheap = Typed MemTyped.NoCast }
+  | "BORNAT" -> { s with mheap = Bornat }
   | "EVA" -> { s with mheap = Eva }
   | "BYTES" -> { s with mheap = Bytes }
   | "CAVEAT" -> { s with mvar = Caveat }
diff --git a/src/plugins/wp/Factory.mli b/src/plugins/wp/Factory.mli
index 1b9ac3843c2..9dfc8620575 100644
--- a/src/plugins/wp/Factory.mli
+++ b/src/plugins/wp/Factory.mli
@@ -24,7 +24,7 @@
 (* --- Model Factory                                                      --- *)
 (* -------------------------------------------------------------------------- *)
 
-type mheap = Hoare | ZeroAlias | Typed of MemTyped.pointer | Eva | Bytes
+type mheap = Hoare | ZeroAlias | Typed of MemTyped.pointer | Eva | Bytes | Bornat
 type mvar = Raw | Var | Ref | Caveat
 
 type setup = {
diff --git a/src/plugins/wp/MemBornat.ml b/src/plugins/wp/MemBornat.ml
new file mode 100644
index 00000000000..641c6d54bb2
--- /dev/null
+++ b/src/plugins/wp/MemBornat.ml
@@ -0,0 +1,2449 @@
+(**************************************************************************)
+(*                                                                        *)
+(*  This file is part of WP plug-in of Frama-C.                           *)
+(*                                                                        *)
+(*  Copyright (C) 2007-2024                                               *)
+(*    CEA (Commissariat a l'energie atomique et aux energies              *)
+(*         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).            *)
+(*                                                                        *)
+(**************************************************************************)
+
+(* -------------------------------------------------------------------------- *)
+(* --- Bornat Memory Model                                                --- *)
+(* -------------------------------------------------------------------------- *)
+
+open Cil_types
+open Ctypes
+open Lang
+open Lang.F
+open Sigs
+open MemMemory
+
+module L = Qed.Logic
+
+
+module type ModelLoader = sig
+  include Sigs.Model
+
+  val sizeof : c_object -> term
+  val last : sigma -> c_object -> loc -> term
+
+  val frames : c_object -> loc -> chunk -> frame list
+
+  val havoc : c_object -> loc -> length:term -> chunk -> fresh:term -> current:term -> term
+
+  val eqmem_forall : c_object -> loc -> chunk -> term -> term -> var list * pred * pred
+
+  val load_int : sigma -> c_int -> loc -> term
+  val load_float : sigma -> c_float -> loc -> term
+  val load_pointer : sigma -> typ -> loc -> loc
+
+  val store_int : sigma -> c_int -> loc -> term -> Chunk.t * term
+  val store_float : sigma -> c_float -> loc -> term -> Chunk.t * term
+  val store_pointer : sigma -> typ -> loc -> term -> Chunk.t * term
+
+  val set_init_atom : sigma -> c_object -> loc -> term -> chunk * term
+  val set_init : c_object -> loc -> length:term -> chunk -> current:term -> term
+  val is_init_atom : sigma -> c_object -> loc -> term
+  val is_init_range : sigma -> c_object -> loc -> term -> pred
+
+  val value_footprint : c_object -> loc -> Sigma.domain
+  val init_footprint : c_object -> loc -> Sigma.domain
+end
+
+
+
+(*
+module Make (R:RegionAnalysis.API) (M:ModelLoader) (* : Sigs.Model *) =
+struct
+
+  type region = R.region
+
+  (****************************************************************************)
+  (*                                                                          *)
+  (*                               Extern API                                 *)
+  (*                                                                          *)
+  (****************************************************************************)
+  let datatype = "MemBornat.Make"
+  (** For projectification. Must be unique among models. *)
+
+  let configure () =
+    begin
+      let rollback () =
+        M.configure () () ;
+      in
+      rollback
+    end
+  (** Initializers to be run before using the model.
+      Typically push {i Context} values and returns a function to rollback.
+  *)
+
+  let configure_ia ia = (* TODO *) M.configure_ia ia
+  (** Given an automaton, return a vertex's binder.
+      Currently used by the automata compiler to bind current vertex.
+
+  *)
+
+  let hypotheses p = M.hypotheses p
+  (** Computes the memory model partitionning of the memory locations.
+      This function typically adds new elements to the partition received
+      in input (that can be empty).
+      ============================> TODO <======================================
+  *)
+
+  module Chunk =
+  struct
+    type t =
+      | CModel of M.chunk
+      | CVal   of R.region
+      | CInit  of R.region
+
+    let self = "MemBornat.Make.Chunk"
+    (** Chunk names, for pretty-printing. *)
+
+    let hash = function
+      | CModel c -> M.Chunk.hash c
+      | CVal   r -> 0x1000 * (R.hash r)
+      | CInit  r -> 0x1000000 * (R.hash r)
+
+    let equal ca cb = match ca, cb with
+      | CModel c1, CModel c2 -> M.Chunk.equal   c1 c2
+      | CVal   r1, CVal   r2 -> R.equal r1 r2
+      | CInit  r1, CInit  r2 -> R.equal r1 r2
+      | _, _ -> false
+
+    let compare c1 c2 = (hash c1) - (hash c2)
+
+    let pretty fmt = function
+      | CModel c -> Format.fprintf fmt "BornatModel.%a" M.Chunk.pretty c
+      | CVal   r -> Format.fprintf fmt "BornatVal.%a" R.pretty r
+      | CInit  r -> Format.fprintf fmt "BornatInit.%a" R.pretty r
+
+
+    let tau_of_primitive = function
+      | R.Int _ -> L.Int
+      | R.Float c_float -> Cfloat.tau_of_float c_float
+      | R.Ptr -> MemAddr.t_addr
+
+    let tau_of_chunk = function
+      | CModel c -> M.Chunk.tau_of_chunk c
+      | CVal   r ->
+        begin match R.kind r with
+          | R.Single p -> tau_of_primitive p
+          | R.Many   p -> L.Array(MemAddr.t_addr, tau_of_primitive p)
+          | R.Garbled  -> assert false
+        end
+      (* | CAlloc r -> t_malloc *)
+      | CInit  r ->
+        begin match R.kind r with
+          | R.Single _ -> t_bool
+          | R.Many   _ -> t_init
+          | R.Garbled  -> assert false
+        end
+
+    let basename_of_chunk = function
+      | CModel _ -> "ModelChunk"
+      | CVal   _ -> "ValueChunk"
+      | CInit  _ -> "InitChunk"
+    (** Used when generating fresh variables for a chunk. *)
+
+    let is_framed = function
+      | CModel c -> M.Chunk.is_framed c
+      | CVal _ | CInit _ -> false
+      (** Whether the chunk is local to a function call.
+
+          Means the chunk is separated from anyother call side-effects.
+          If [true], entails that a function assigning everything can not modify
+          the chunk. Only used for optimisation, it would be safe to always
+          return [false]. *)
+  end
+  (** Memory Chunks.
+
+      The concrete memory is partionned into a vector of abstract data.
+      Each component of the partition is called a {i memory chunk} and
+      holds an abstract representation of some part of the memory.
+
+      Remark: memory chunks are not required to be independant from each other,
+      provided the memory model implementation is consistent with the chosen
+      representation. Conversely, a given object might be represented by
+      several memory chunks.
+
+  *)
+
+  (* Chunks Sets and Maps. *)
+
+  module ValChunk = struct
+    include R
+    type t = region
+    let self = "chunk_val"
+    let tau_of_chunk = tau_of_region
+    let basename_of_chunk _ = "ChunkVal"
+    let is_framed _ = false
+  end
+  module InitChunk = struct
+    include R
+    type t = region
+    let self = "chunk_init"
+    let tau_of_chunk _ = t_init
+    let basename_of_chunk _ = "ChunkInit"
+    let is_framed _ = false
+  end
+
+  module ValHeap = Qed.Collection.Make(ValChunk)
+  module ValSigma = Sigma.Make(ValChunk)(ValHeap)
+
+  module InitHeap = Qed.Collection.Make(InitChunk)
+  module InitSigma = Sigma.Make(InitChunk)(InitHeap)
+
+  module Heap = Qed.Collection.Make(Chunk)
+
+  module Tuple = struct
+    type ('a, 'b, 'c) tuple = {
+      model : 'a ;
+      value : 'b ;
+      init  : 'c ;
+    }
+
+    let create f1 f2 f3 input = {
+      model = f1 input ;
+      value = f2 input ;
+      init  = f3 input ;
+    }
+
+    let iter f1 f2 f3 tuple =
+      f1 tuple.model ;
+      f2 tuple.value ;
+      f3 tuple.init  ;
+      ()
+
+    let iter2 f1 f2 f3 t1 t2 =
+      f1 t1.model t2.model ;
+      f2 t1.value t2.value ;
+      f3 t1.init  t2.init  ;
+      ()
+
+    let choose_apply f1 f2 f3 tuple = function
+      | Chunk.CModel c -> f1 tuple.model c
+      | Chunk.CVal   r -> f2 tuple.value r
+      | Chunk.CInit  r -> f3 tuple.init  r
+
+    let choose_map f1 f2 f3 tuple = function
+      | Chunk.CModel c -> { tuple with model = f1 tuple.model c }
+      | Chunk.CVal   r -> { tuple with value = f2 tuple.value r }
+      | Chunk.CInit  r -> { tuple with init  = f3 tuple.init  r }
+
+    let map f1 f2 f3 tuple = {
+      model = f1 tuple.model ;
+      value = f2 tuple.value ;
+      init  = f3 tuple.init  ;
+    }
+
+    let map2 f1 f2 f3 t1 t2 = {
+      model = f1 t1.model t2.model ;
+      value = f2 t1.value t2.value ;
+      init  = f3 t1.init  t2.init  ;
+    }
+
+    let sequence_map f1 f2 f3 seq = {
+      model = f1 { pre = seq.pre.model ; post = seq.post.model } ;
+      value = f2 { pre = seq.pre.value ; post = seq.post.value } ;
+      init  = f3 { pre = seq.pre.init  ; post = seq.post.init  } ;
+    }
+  end
+
+  type sigma = (M.sigma, ValSigma.t, InitSigma.t) Tuple.tuple
+
+  module Sigma (*: Sigma *) =
+  struct
+
+    open Tuple
+    type t = sigma
+    type chunk = Chunk.t
+
+    open Chunk
+
+    type domain = Heap.set
+
+    type dom = (M.Sigma.domain, ValSigma.domain, InitSigma.domain) Tuple.tuple
+
+    (* local *)
+    let chunk_split_list l =
+      let rec aux acc1 acc2 acc3 = function
+        | [] -> { model = List.rev acc1 ; value = List.rev acc2 ; init  = List.rev acc3 }
+        | CModel c :: rest -> aux (c::acc1) acc2 acc3 rest
+        | CVal r :: rest -> aux acc1 (r::acc2) acc3 rest
+        | CInit r :: rest -> aux acc1 acc2 (r::acc3) rest
+      in aux [] [] [] l
+
+    let of_domain (domain:domain) : dom =
+      Tuple.map
+        M.Sigma.Chunk.Set.of_list
+        ValSigma.Chunk.Set.of_list
+        InitSigma.Chunk.Set.of_list
+      @@ chunk_split_list
+      @@ Heap.Set.elements domain
+
+    let to_domain (dom:dom) : domain =
+      let cmodel = M.Heap.Set.elements dom.model in
+      let cvalue = ValSigma.Chunk.Set.elements dom.value in
+      let cinit = InitSigma.Chunk.Set.elements dom.init  in
+      let model = Heap.Set.of_list (List.map (fun c -> CModel c) cmodel) in
+      let value = Heap.Set.of_list (List.map (fun r -> CVal   r) cvalue) in
+      let init  = Heap.Set.of_list (List.map (fun r -> CInit  r) cinit)  in
+      Heap.Set.union model @@ Heap.Set.union value init
+
+    module Chunk = Heap
+
+
+    let create = Tuple.create M.Sigma.create ValSigma.create InitSigma.create
+
+    let pretty fmt sigma =
+      Format.fprintf fmt "@[{@[%a@];@[%a@];@[%a@]}@]"
+        M.Sigma.pretty sigma.model
+        ValSigma.pretty sigma.value
+        InitSigma.pretty sigma.init
+
+    let empty : domain = Heap.Set.empty
+
+    let mem = Tuple.choose_apply M.Sigma.mem ValSigma.mem InitSigma.mem
+
+    let get = Tuple.choose_apply M.Sigma.get ValSigma.get InitSigma.get
+
+    let writes sigma = to_domain @@ Tuple.sequence_map M.Sigma.writes ValSigma.writes InitSigma.writes sigma
+
+    let value = Tuple.choose_apply M.Sigma.value ValSigma.value InitSigma.value
+
+    let copy = Tuple.map M.Sigma.copy ValSigma.copy InitSigma.copy
+
+    let join sigma1 sigma2 =
+      let r = Tuple.map2 M.Sigma.join ValSigma.join InitSigma.join sigma1 sigma2 in
+      Passive.union r.model @@ Passive.union r.value r.init
+
+    let assigned ~pre:sigma1 ~post:sigma2 domain =
+      let dom = of_domain domain in
+      Bag.concat (M.Sigma.assigned ~pre:sigma1.model ~post:sigma2.model dom.model)
+      @@ Bag.concat (ValSigma.assigned ~pre:sigma1.value ~post:sigma2.value dom.value)
+      @@ InitSigma.assigned ~pre:sigma1.init ~post:sigma2.init dom.init
+
+    let choose = Tuple.map2 M.Sigma.choose ValSigma.choose InitSigma.choose
+
+    let merge s1 s2 =
+      let (sm, pm1, pm2) = M.Sigma.merge  s1.model s2.model in
+      let (sv, pv1, pv2) = ValSigma.merge s1.value s2.value in
+      let (si, pi1, pi2) = InitSigma.merge s1.init s2.init  in
+      let s = { model = sm ; value = sv ; init = si } in
+      let p1 = Passive.union pm1 @@ Passive.union pv1 pi1 in
+      let p2 = Passive.union pm2 @@ Passive.union pv2 pi2 in
+      (s,p1,p2)
+
+    let merge_list ls = (* TOCHECK *)
+      let f (s1,lp) s2 =
+        let (s,p1,p2) = merge s1 s2 in
+        (s, p1::p2::lp)
+      in
+      match ls with
+      | [] -> (create (), [])
+      | [ s ] -> (s, [ Passive.empty ])
+      | _ -> List.fold_left f (create (), []) ls
+
+    let iter f =
+      Tuple.iter
+        (M.Sigma.iter   (fun c -> f (CModel c)))
+        (ValSigma.iter  (fun r -> f (CVal   r)))
+        (InitSigma.iter (fun r -> f (CInit  r)))
+
+    let iter2 f =
+      Tuple.iter2
+        (M.Sigma.iter2   (fun c -> f (CModel c)))
+        (ValSigma.iter2  (fun r -> f (CVal   r)))
+        (InitSigma.iter2 (fun r -> f (CInit  r)))
+
+    let havoc_chunk = Tuple.choose_map M.Sigma.havoc_chunk ValSigma.havoc_chunk InitSigma.havoc_chunk
+
+    let havoc sigma domain =
+      let dom = of_domain domain in
+      Tuple.map2 M.Sigma.havoc ValSigma.havoc InitSigma.havoc sigma dom
+
+    let havoc_any ~call:call =
+      Tuple.map (M.Sigma.havoc_any ~call) (ValSigma.havoc_any ~call) (InitSigma.havoc_any ~call)
+
+    let remove_chunks sigma domain =
+      let dom = of_domain domain in
+      Tuple.map2 M.Sigma.remove_chunks ValSigma.remove_chunks InitSigma.remove_chunks sigma dom
+
+    let dom = Tuple.map M.Sigma.domain ValSigma.domain InitSigma.domain
+
+    let domain sigma =
+      let dom = dom sigma in
+      Chunk.Set.of_list
+      @@ List.append
+        (List.map (fun l -> CModel l) (M.Heap.Set.elements  dom.model ))
+      @@ List.append
+        (List.map (fun r -> CVal   r) (ValHeap.Set.elements dom.value))
+        (List.map (fun r -> CInit  r) (InitHeap.Set.elements dom.init))
+
+    let union = Chunk.Set.union
+
+  end
+
+  (* ************************************************************************ *)
+  (* ***   MemLoader instanciation from the implementation of MemTyped    *** *)
+  (* ************************************************************************ *)
+
+
+  (****************************************************************************)
+  (** module Bornat : MemLoader.Module                                       **)
+  (****************************************************************************)
+
+  module Bornat = struct
+    module Chunk = Chunk
+    module Sigma = Sigma
+    let name = "BornatModel"
+
+    type loc =
+      | Null of { repr : M.loc }
+      | Loc of { repr : M.loc ; region : region }
+
+
+    (* ---------------------------------------------------------------------- *)
+    (* --- Utilities on locations                                         --- *)
+    (* ---------------------------------------------------------------------- *)
+
+    let last sigma ty = function
+      | Null { repr } ->
+        Warning.emit ~severe:false ~source:"MemBornat.Bornat.last"
+          ~effect:"Loc is NULL" "loc=%a" M.pretty repr ;
+        M.pointer_val M.null
+      | Loc { repr } -> M.last sigma.Tuple.model ty repr
+
+    (** Conversion among loc, t_pointer terms and t_addr terms *)
+    let to_addr = function
+      | Null { repr } -> M.pointer_val repr
+      | Loc { repr } -> M.pointer_val repr
+
+    let to_region_pointer = function
+      | Null { repr } ->
+        Warning.emit ~severe:false ~source:"MemBornat.Bornat.to_region_pointer"
+          ~effect:"Pointer NULL shall not be parsed in this function" "%a" M.pretty repr ;
+        (0, M.pointer_val M.null)
+      | Loc { repr ; region } -> (R.id_of_region region, M.pointer_val repr)
+
+    let of_region_pointer id _ty term =
+      if id == 0 then
+        let _ =
+          Warning.emit ~severe:false ~source:"MemBornat.Bornat.of_region_pointer"
+            ~effect:"No region has been found" "Region_id is zero"
+        in Null { repr = M.pointer_loc term }
+      else match R.region_of_id id with
+        | None ->
+          Warning.emit ~severe:false ~source:"MemBornat.Bornat.of_region_pointer"
+            ~effect:"No region has been found" "Region_id=%d" id ;
+          Null { repr = M.pointer_loc term }
+        | Some region -> Loc { repr = M.pointer_loc term ; region }
+
+    (** Basic operations *)
+    let sizeof ty = M.sizeof ty
+
+    let field loc field : loc = (* TODO: reconstruction *) match loc with
+      | Null { repr } ->
+        Warning.emit ~severe:false ~source:"MemBornat.Bornat.field"
+          ~effect:"Loc is NULL" "(%a).(%a)" M.pretty repr Printer.pp_field field ;
+        assert false
+      | Loc { repr ; region } ->
+        match R.field region field with
+        | None ->
+          Warning.emit ~severe:false ~source:"MemBornat.Bornat.field"
+            ~effect:"No region for field" "field:%a" Printer.pp_field field ;
+          Null { repr = M.field repr field }
+        | Some region -> Loc { repr = M.field repr field ; region }
+
+    let shift loc ty offset = match loc with
+      | Null { repr } ->
+        Warning.emit ~severe:false ~source:"MemBornat.Bornat.shift"
+          ~effect:"Loc is NULL" "pointer=%a and ty=%a and offset=%a"
+          M.pretty repr Ctypes.pp_object ty QED.pretty offset ;
+        assert false
+      | Loc { repr ; region } ->
+        match R.shift region ty offset with
+        | None ->
+          Warning.emit ~severe:false ~source:"MemBornat.Bornat.field"
+            ~effect:"No region for field" "offset:%a" QED.pretty offset ;
+          Null { repr = M.shift repr ty offset }
+        | Some region ->
+          Loc { repr = M.shift repr ty offset ; region }
+
+    let frames ty loc chunk =
+      match loc with
+      | Null { repr } ->
+        Warning.emit ~severe:false ~source:"MemBornat.Bornat.frames"
+          ~effect:"Loc is NULL" "NULL=%a" M.pretty repr ;
+        assert false
+      | Loc loc ->
+        match chunk with
+        | Chunk.CModel c -> M.frames ty loc.repr c
+        | CVal r | CInit r ->
+          match R.kind r with
+          | R.Single R.Ptr | R.Many R.Ptr ->
+            let offset = M.sizeof ty in
+            let sizeof = F.e_one in
+            let tau = Chunk.tau_of_chunk chunk in
+            let basename = Chunk.basename_of_chunk chunk in
+            MemMemory.frames ~addr:(M.pointer_val loc.repr) ~offset ~sizeof ~basename tau
+          | _ -> []
+          (*
+        begin match R.kind r with
+        | R.Single R.Ptr | R.Many R.Ptr -> [MemMemory.framed (Sigma.value chunk)]
+        | _ -> []
+        end *)
+      (*
+      si chunk = CVal r et R.tau_of_region == ptr then the predicate MemMemory.framed (Sigma.value chunk)
+      si chunk = CInit r then MemMemory.cinits (Sigma.value chunk)
+      *)
+
+    let havoc ty loc ~length chunk ~fresh ~current = match loc with
+      | Null _ ->
+        Warning.emit ~severe:false ~source:"MemBornat.Bornat.havoc"
+          ~effect:"Loc is NULL" "NULL loc" ;
+        assert false
+      | Loc loc ->
+        (* TO CHECK *) assert (QED.equal length F.e_one) ;
+        match chunk with
+        | Chunk.CModel c -> M.havoc ty loc.repr ~length c ~fresh ~current
+        | Chunk.CVal _ | Chunk.CInit _ ->
+          let n = M.sizeof_havoc ty loc.repr in
+          F.e_fun f_havoc [fresh;current;M.pointer_val loc.repr;n]
+
+    let eqmem ty loc chunk m1 m2 = match loc with
+      | Null _ ->
+        Warning.emit ~severe:false ~source:"MemBornat.Bornat.eqmem"
+          ~effect:"Loc is NULL" "NULL loc" ;
+        p_true
+      | Loc loc ->
+        match chunk with
+        | Chunk.CModel c -> M.eqmem ty loc.repr c m1 m2
+        | Chunk.CVal _ | Chunk.CInit _ ->
+          F.p_call p_eqmem [m1;m2;M.pointer_val loc.repr;M.sizeof_havoc ty loc.repr]
+
+    let eqmem_forall ty loc chunk m1 m2 =match loc with
+      | Null _ ->
+        Warning.emit ~severe:false ~source:"MemBornat.Bornat.eqmem_forall"
+          ~effect:"Loc is NULL" "NULL loc" ;
+        [], p_true, p_true
+      | Loc loc ->
+        match chunk with
+        | Chunk.CModel c -> M.eqmem_forall ty loc.repr c m1 m2
+        | Chunk.CVal _ | Chunk.CInit _ ->
+          let xp = Lang.freshvar ~basename:"p" MemAddr.t_addr in
+          let p = F.e_var xp in
+          let n = M.sizeof ty in
+          let separated = F.p_call MemAddr.p_separated [p;e_one;M.pointer_val loc.repr;n] in
+          let equal = p_equal (e_get m1 p) (e_get m2 p) in
+          [xp],separated,equal
+
+    (* ---------------------------------------------------------------------- *)
+    (* --- Load                                                           --- *)
+    (* ---------------------------------------------------------------------- *)
+
+    let load_int sigma (c_int:c_int) loc : term =match loc with
+      | Null { repr } ->
+        Warning.emit ~severe:false ~source:"MemBornat.Bornat.load_int"
+          ~effect:"Loc is NULL" "NULL=%a" M.pretty repr ;
+        assert false
+      | Loc loc ->
+        match R.kind loc.region with
+        | R.Many (R.Int c_int') ->
+          if compare_c_int c_int c_int' = 0
+          then F.e_get (Sigma.value sigma (CVal loc.region)) (M.pointer_val loc.repr)
+          else
+            let _ = Warning.emit ~severe:false ~source:"MemBornat.Bornat.load_int"
+                ~effect:"Type is not the same in chunk and in argument" "%a!=%a"
+                Ctypes.pp_int c_int Ctypes.pp_int c_int'
+            in
+            F.e_get (Sigma.value sigma (CVal loc.region)) (M.pointer_val loc.repr)
+        | R.Single (R.Int c_int') ->
+          if compare_c_int c_int c_int' = 0
+          then Sigma.value sigma (CVal loc.region)
+          else assert false
+        | R.Garbled -> M.load_int sigma.model c_int loc.repr
+        | _ -> assert false
+
+    let load_float sigma (c_float:c_float) loc : term = match loc with
+      | Null { repr } ->
+        Warning.emit ~severe:false ~source:"MemBornat.Bornat.load_float"
+          ~effect:"Loc is NULL" "NULL=%a" M.pretty repr ;
+        assert false
+      | Loc loc ->
+        match R.kind loc.region with
+        | R.Many (R.Float c_float') ->
+          if compare_c_float c_float c_float' = 0
+          then F.e_get (Sigma.value sigma (CVal loc.region)) (M.pointer_val loc.repr)
+          else
+            let _ = Warning.emit ~severe:false ~source:"MemBornat.Bornat.load_float"
+                ~effect:"Type is not the same in chunk and in argument" "%a!=%a"
+                Ctypes.pp_float c_float Ctypes.pp_float c_float'
+            in
+            F.e_get (Sigma.value sigma (CVal loc.region)) (M.pointer_val loc.repr)
+        | R.Single (R.Float c_float') ->
+          if compare_c_float c_float c_float' = 0
+          then Sigma.value sigma (CVal loc.region)
+          else assert false
+        | R.Garbled -> M.load_float sigma.model c_float loc.repr
+        | _ ->
+          let _ = Warning.emit ~severe:false ~source:"MemBornat.Bornat.load_float"
+              ~effect:"Type is not the same in chunk and in argument" "%a"
+              Ctypes.pp_float c_float
+          in
+          F.e_get (Sigma.value sigma (CVal loc.region)) (M.pointer_val loc.repr)
+
+    let load_pointer sigma ty loc : loc = match loc with
+      | Null { repr } ->
+        Warning.emit ~severe:false ~source:"MemBornat.Bornat.load_pointer"
+          ~effect:"Loc is NULL" "NULL=%a" M.pretty repr ;
+        assert false
+      | Loc loc ->
+        match R.points_to loc.region with
+        | None ->
+          Warning.emit ~severe:false ~source:"MemBornat.Bornat.load_pointer"
+            ~effect:"No pointed loc" "Region=%a" R.pretty loc.region ;
+          assert false
+        | Some region ->
+          let repr = match R.kind loc.region with
+            | R.Many (R.Ptr) ->
+              M.pointer_loc @@ F.e_get (Sigma.value sigma (CVal loc.region)) (M.pointer_val loc.repr)
+            | R.Single (R.Ptr) ->
+              M.pointer_loc @@ Sigma.value sigma (CVal loc.region)
+            | R.Garbled -> M.load_pointer sigma.Tuple.model ty loc.repr
+            | _ ->
+              Warning.emit ~severe:false ~source:"MemBornat.Bornat.load_pointer"
+                ~effect:"Kind of region is not a pointer" "Region=%a" R.pretty loc.region ;
+              assert false
+          in Loc { repr ; region }
+
+    (* ---------------------------------------------------------------------- *)
+    (* --- Store                                                          --- *)
+    (* ---------------------------------------------------------------------- *)
+
+    let store_int sigma c_int loc v : Chunk.t * term = match loc with
+      | Null { repr } ->
+        Warning.emit ~severe:false ~source:"MemBornat.Bornat.store_int"
+          ~effect:"Loc is NULL" "NULL=%a" M.pretty repr ;
+        assert false
+      | Loc loc ->
+        let c = Chunk.CVal loc.region in
+        match R.kind loc.region with
+        | R.Many (R.Int c_int') ->
+          if compare_c_int c_int c_int' = 0
+          then (c, F.e_set (Sigma.value sigma c) (M.pointer_val loc.repr) v)
+          else assert false
+        | R.Single (R.Int c_int') ->
+          if compare_c_int c_int c_int' = 0
+          then (c, v)
+          else assert false
+        | R.Garbled -> let (c', v) = M.store_int sigma.model c_int loc.repr v in
+          (Chunk.CModel c', v)
+        | _ -> assert false
+
+    let store_float sigma c_float loc v : Chunk.t * term = match loc with
+      | Null { repr } ->
+        Warning.emit ~severe:false ~source:"MemBornat.Bornat.store_float"
+          ~effect:"Loc is NULL" "NULL=%a" M.pretty repr ;
+        assert false
+      | Loc loc ->
+        let c = Chunk.CVal loc.region in
+        match R.kind loc.region with
+        | R.Many (R.Float c_float') ->
+          if compare_c_float c_float c_float' = 0
+          then (c, F.e_set (Sigma.value sigma c) (M.pointer_val loc.repr) v)
+          else assert false
+        | R.Single (R.Float c_float') ->
+          if compare_c_float c_float c_float' = 0
+          then (c, v)
+          else assert false
+        | R.Garbled ->
+          let (c, t) = M.store_float sigma.Tuple.model c_float loc.repr v in
+          (Chunk.CModel c, t)
+        | _ -> assert false
+
+    let store_pointer sigma ty loc v : Chunk.t * term = match loc with
+      | Null { repr } ->
+        Warning.emit ~severe:false ~source:"MemBornat.Bornat.store_pointer"
+          ~effect:"Loc is NULL" "NULL=%a" M.pretty repr ;
+        assert false
+      | Loc loc ->
+        let c = Chunk.CVal loc.region in
+        match R.kind loc.region with
+        | R.Many (R.Ptr) ->
+          (c, F.e_set (Sigma.value sigma (CVal loc.region)) (M.pointer_val loc.repr) v)
+        | R.Single (R.Ptr) ->
+          (c, v)
+        | R.Garbled ->
+          let (c, repr) = M.store_pointer sigma.Tuple.model ty loc.repr v in
+          (Chunk.CModel c, repr)
+        | _ -> assert false
+
+    (* ---------------------------------------------------------------------- *)
+    (* --- Init                                                           --- *)
+    (* ---------------------------------------------------------------------- *)
+
+    let set_init_atom sigma loc v = match loc with
+      | Null { repr } ->
+        Warning.emit ~severe:false ~source:"MemBornat.Bornat.set_init_atom"
+          ~effect:"Loc is NULL" "NULL=%a" M.pretty repr ;
+        assert false
+      | Loc loc ->
+        match R.kind loc.region with
+        | R.Garbled ->
+          let (c, t) = M.set_init_atom sigma.Tuple.model loc.repr v in
+          (Chunk.CModel c, t)
+        | R.Single _-> (Chunk.CInit loc.region, v)
+        | R.Many _ ->
+          let c = Chunk.CInit loc.region in
+          (c, F.e_set (Sigma.value sigma c) (M.pointer_val loc.repr) v)
+
+    let is_init_atom sigma loc : term = match loc with
+      | Null { repr } ->
+        Warning.emit ~severe:false ~source:"MemBornat.Bornat.is_init_atom"
+          ~effect:"Loc is NULL" "NULL=%a" M.pretty repr ;
+        assert false
+      | Loc loc ->
+        match R.kind loc.region with
+        | R.Garbled ->
+          M.is_init_atom sigma.Tuple.model loc.repr
+        | R.Many _ ->
+          F.e_get (Sigma.value sigma (Chunk.CInit loc.region)) @@ M.pointer_val loc.repr
+        | R.Single _ ->
+          Sigma.value sigma (Chunk.CInit loc.region)
+
+    let is_init_range sigma ty loc length : pred = match loc with
+      | Null { repr } ->
+        Warning.emit ~severe:false ~source:"MemBornat.Bornat.is_init_range"
+          ~effect:"Loc is NULL" "NULL=%a" M.pretty repr ;
+        assert false
+      | Loc loc ->
+        match R.kind loc.region with
+        | R.Garbled -> M.is_init_range sigma.Tuple.model ty loc.repr length
+        | R.Many _ ->
+          let n = F.e_mul (M.sizeof ty) length in
+          F.p_call p_is_init_r [ Sigma.value sigma (Chunk.CInit loc.region) ; M.pointer_val loc.repr ; n ]
+        | R.Single _ -> (* TODO *) assert false
+
+
+    let set_init ty loc ~length chunk ~current : term = match loc with
+      | Null { repr } ->
+        Warning.emit ~severe:false ~source:"MemBornat.Bornat.set_init"
+          ~effect:"Loc is NULL" "NULL=%a" M.pretty repr ;
+        assert false
+      | Loc loc ->
+        match R.kind loc.region, chunk with
+        | R.Garbled, Chunk.CModel c ->
+          M.set_init ty loc.repr ~length c ~current
+        | R.Garbled, ( Chunk.CVal _ | Chunk.CInit _) -> assert false
+        | R.Many _, _ ->
+          let n = F.e_mul (M.sizeof ty) length in
+          F.e_fun f_set_init [current ; M.pointer_val loc.repr ; n]
+        | R.Single _, _ -> (* TODO *) assert false
+
+
+    (* ---------------------------------------------------------------------- *)
+    (* --- Footprints                                                     --- *)
+    (* ---------------------------------------------------------------------- *)
+
+    let rec value_footprint ty loc = match loc with
+      | Null { repr } ->
+        Warning.emit ~severe:false ~source:"MemBornat.Bornat.value_footprint"
+          ~effect:"Loc is NULL" "NULL=%a" M.pretty repr ;
+        Sigma.empty
+      | Loc loc ->
+        match R.kind loc.region, ty with
+        | R.Garbled, (C_int _ | C_float _ | C_pointer _) ->
+          Heap.Set.of_list @@ List.map (fun c -> Chunk.CModel c) @@ M.Heap.Set.elements
+          @@ M.value_footprint ty loc.repr
+        | (R.Many (R.Int   _) | R.Single (R.Int   _)), C_int _
+        | (R.Many (R.Float _) | R.Single (R.Float _)), C_float _
+        | (R.Many (R.Ptr    ) | R.Single (R.Ptr    )), C_pointer _->
+          Heap.Set.singleton (Chunk.CVal loc.region)
+        | (R.Many _ | R.Single _), (C_int _ | C_float _ | C_pointer _) ->
+          Warning.emit ~severe:false ~source:"MemBornat.Bornat.value_footprint"
+            ~effect:"Type is not the same in chunk and in argument" "%a" Ctypes.pretty ty ;
+          Heap.Set.singleton (Chunk.CVal loc.region)
+        | _, C_comp { cfields } ->
+          let none = Heap.Set.empty in
+          let some l_fields =
+            List.fold_left (fun acc f -> Heap.Set.union acc (value_footprint (Ctypes.object_of f.ftype) @@ field (Loc loc) f)) Heap.Set.empty l_fields
+          in Option.fold ~none ~some cfields
+        | _, C_array { arr_element } ->
+          let ty = object_of arr_element in
+          value_footprint ty (shift (Loc loc) ty e_zero)
+
+    let rec init_footprint ty loc = match loc with
+      | Null { repr } ->
+        Warning.emit ~severe:false ~source:"MemBornat.Bornat.init_footprint"
+          ~effect:"Loc is NULL" "NULL=%a" M.pretty repr ;
+        Sigma.empty
+      | Loc loc ->
+        match R.kind loc.region, ty with
+        | R.Garbled, (C_int _ | C_float _ | C_pointer _) ->
+          Heap.Set.of_list @@ List.map (fun c -> Chunk.CModel c) @@ M.Heap.Set.elements
+          @@ M.init_footprint ty loc.repr
+        | (R.Many (R.Int   _) | R.Single (R.Int   _)), C_int _
+        | (R.Many (R.Float _) | R.Single (R.Float _)), C_float _
+        | (R.Many (R.Ptr    ) | R.Single (R.Ptr    )), C_pointer _->
+          Heap.Set.singleton (Chunk.CInit loc.region)
+        | (R.Many _ | R.Single _) as k, (C_int _ | C_float _ | C_pointer _) ->
+          Warning.emit ~severe:false ~source:"MemBornat.Bornat.init_footprint"
+            ~effect:"Type is not the same in chunk and in argument" "%a != %a"
+            R.pp_kind k Ctypes.pretty ty ;
+          Heap.Set.singleton (Chunk.CInit loc.region)
+        | _, C_comp { cfields } ->
+          let none = Heap.Set.empty in
+          let some l_fields =
+            List.fold_left (fun acc f -> Heap.Set.union acc (init_footprint (Ctypes.object_of f.ftype) @@ field (Loc loc) f)) Heap.Set.empty l_fields
+          in Option.fold ~none ~some cfields
+        | _, C_array { arr_element } ->
+          let ty = object_of arr_element in
+          init_footprint ty (shift (Loc loc) ty e_zero)
+
+  end
+
+  type loc = Bornat.loc
+  type domain = Sigma.domain
+  type chunk = Chunk.t
+  type segment = loc rloc
+
+
+
+  (****************************************************************************)
+  module LOADER = MemLoader.Make(Bornat)
+  (******************************************************************************)
+
+  let load = LOADER.load
+  let load_init = LOADER.load_init
+  let stored = LOADER.stored
+  let stored_init = LOADER.stored_init
+  let copied = LOADER.copied
+  let copied_init = LOADER.copied_init
+  let initialized = LOADER.initialized
+  let domain = LOADER.domain
+
+(*
+  let sloc_oget = function
+  | Sloc None -> Sloc M.null, None
+  | Sloc (Some { Bornat.repr = repr }) -> Sloc repr
+  | Sarray (None,a,b) ->
+  | Srange (None,_,_,_)
+  | Sdescr (_,None,_) ->
+  |
+*)
+
+  let assigned seq ty sloc = match sloc with
+    | Sloc (Bornat.Null _) | Sarray (Bornat.Null _,_,_)
+    | Srange (Bornat.Null _,_,_,_) | Sdescr (_,Bornat.Null _,_) ->
+      LOADER.assigned seq ty sloc
+    | _ ->
+      (* Maintain always initialized values initialized *)
+      let region = match sloc with
+        | Sloc (Bornat.Loc loc) | Sarray (Bornat.Loc loc, _, _)
+        | Srange (Bornat.Loc loc, _, _, _)
+        | Sdescr (_, Bornat.Loc loc, _) -> loc.region
+        | Sloc (Bornat.Null _) | Sarray (Bornat.Null _,_,_) | Srange (Bornat.Null _,_,_,_)
+        | Sdescr (_,Bornat.Null _,_) -> assert false
+      in
+      Assert (MemMemory.cinits (Sigma.value seq.post (Chunk.CInit region))) ::
+      LOADER.assigned seq ty sloc
+
+  (** {2 Reversing the Model} *)
+
+  type state = M.state
+
+  let state sigma = M.state sigma.Tuple.model
+
+  let lookup s e = M.lookup s e
+
+  let updates = M.updates
+
+  let apply = M.apply
+
+  let iter = M.iter
+
+  let pretty fmt = function
+    | Bornat.Null { repr } -> Format.fprintf fmt "{ NULL=%a }" M.pretty repr
+    | Bornat.Loc loc -> Format.fprintf fmt "{ repr=%a ; region=%a }" M.pretty loc.repr R.pretty loc.region
+
+
+  (** {2 Memory Model API} *)
+
+  let vars = function
+    | Bornat.Null _ -> Vars.empty
+    | Bornat.Loc { repr } -> M.vars repr
+  (** Return the logic variables from which the given location depend on. *)
+
+  let occurs var = function
+    | Bornat.Null _ -> false
+    | Bornat.Loc { repr } -> M.occurs var repr
+  (** Test if a location depend on a given logic variable *)
+
+  let null = Bornat.Null { repr = M.null }
+  (** Return the location of the null pointer *)
+
+  let literal ~eid:eid name =
+    let repr = M.literal ~eid name in
+    match R.literal ~eid name with
+    | None -> Bornat.Null { repr }
+    | Some region -> Bornat.Loc { repr ; region }
+  (** Return the memory location of a constant string,
+      the id is a unique identifier. *)
+
+  let cvar var =
+    match R.cvar var with
+    | None ->
+      Warning.emit ~severe:false ~source:"MemBornat.cvar"
+        ~effect:"No region for this var" "%a" Printer.pp_varinfo var ;
+      Bornat.Null { repr = M.cvar var }
+    | Some region -> Bornat.Loc { repr = M.cvar var ; region }
+  (** Return the location of a C variable. *)
+
+  let pointer_loc term =
+    let repr = M.pointer_loc term in
+    if QED.equal term @@ M.pointer_val M.null
+    then Bornat.Null { repr }
+    else match R.pointer_loc () with
+      | None -> Bornat.Null { repr }
+      | Some region -> Bornat.Loc { repr ; region }
+  (** Interpret an address value (a pointer) as an abstract location.
+      Might fail on memory models not supporting pointers. *)
+
+  let pointer_val = function
+    | Bornat.Null { repr } ->
+      Warning.emit ~severe:false ~source:"MemBornat.pointer_val"
+        ~effect:"No region for this loc" "%a" M.pretty repr ;
+      M.pointer_val repr
+    | Bornat.Loc { repr } -> M.pointer_val repr
+  (** Return the adress value (a pointer) of an abstract location.
+      Might fail on memory models not capable of representing pointers. *)
+
+  let field loc fieldinfo = match loc with
+    | Bornat.Null { repr } ->
+      Warning.emit ~severe:false ~source:"MemBornat.field"
+        ~effect:"Loc is NULL" "NULL=%a" M.pretty repr ;
+      Bornat.Null { repr = M.field repr fieldinfo }
+    | Bornat.Loc loc ->
+      match R.field loc.region fieldinfo with
+      | None ->
+        Warning.emit ~severe:false ~source:"MemBornat.field"
+          ~effect:"No region for this field" "%a.%a" M.pretty loc.repr Printer.pp_field fieldinfo ;
+        Bornat.Null { repr = M.field loc.repr fieldinfo }
+      | Some region -> Bornat.Loc { repr = M.field loc.repr fieldinfo ; region }
+  (** Return the memory location obtained by field access from a given
+      memory location. *)
+
+  let shift loc ty term = match loc with
+    | Bornat.Null { repr } ->
+      Warning.emit ~severe:false ~source:"MemBornat.shift"
+        ~effect:"Loc is NULL" "NULL=%a" M.pretty repr ;
+      Bornat.Null { repr = M.shift repr ty term }
+    | Bornat.Loc loc ->
+      match R.shift loc.region ty term with
+      | None ->
+        Warning.emit ~severe:false ~source:"MemBornat.shift"
+          ~effect:"No region for this shift" "pointer=%a and ty=%a and offset=%a"
+          M.pretty loc.repr Ctypes.pp_object ty QED.pretty term;
+        Bornat.Null { repr = M.shift loc.repr ty term }
+      | Some region -> Bornat.Loc { repr = M.shift loc.repr ty term ; region }
+  (** Return the memory location obtained by array access at an index
+      represented by the given {!term}. The element of the array are of
+      the given {!c_object} type. *)
+
+  let base_addr  = function
+    | Bornat.Null { repr } ->
+      Warning.emit ~severe:false ~source:"MemBornat.base_addr"
+        ~effect:"Loc is NULL" "NULL=%a" M.pretty repr ;
+      Bornat.Null { repr = M.base_addr repr }
+    | Bornat.Loc loc -> Bornat.Loc {
+        repr   = M.base_addr loc.repr   ;
+        region = R.base_addr loc.region ;
+      }
+  (** Return the memory location of the base address of a given memory
+      location. *)
+
+  let base_offset = function
+    | Bornat.Null { repr } ->
+      Warning.emit ~severe:false ~source:"MemBornat.base_offset"
+        ~effect:"Loc is NULL" "NULL=%a" M.pretty repr ;
+      M.base_offset repr
+    | Bornat.Loc { repr } -> M.base_offset repr
+  (** Return the offset of the location, in bytes, from its base_addr. *)
+
+  let block_length sigma ty  = function
+    | Bornat.Null { repr } ->
+      Warning.emit ~severe:false ~source:"MemBornat.block_length"
+        ~effect:"Loc is NULL" "NULL=%a" M.pretty repr ;
+      M.block_length sigma.Tuple.model ty repr
+    | Bornat.Loc { repr } -> M.block_length sigma.Tuple.model ty repr
+  (**  Returns the length (in bytes) of the allocated block containing
+       the given location. *)
+
+  let cast objs = function
+    | Bornat.Null { repr } ->
+      Warning.emit ~severe:false ~source:"MemBornat.cast"
+        ~effect:"Loc is NULL" "NULL=%a" M.pretty repr ;
+      Bornat.Null { repr = M.cast objs repr }
+    | Bornat.Loc loc -> Bornat.Loc { loc with repr = M.cast objs loc.repr }
+  (** Cast a memory location into another memory location.
+      For [cast ty loc] the cast is done from [ty.pre] to [ty.post].
+      Might fail on memory models not supporting pointer casts. *)
+
+  let loc_of_int ty term =
+    let repr = M.loc_of_int ty term in
+    if QED.equal term @@ M.pointer_val M.null
+    then Bornat.Null { repr }
+    else match  R.loc_of_int ()  with
+      | None -> Bornat.Null { repr }
+      | Some region -> Bornat.Loc { repr ; region }
+
+  let int_of_loc c_int = function
+    | Bornat.Null { repr } ->
+      Warning.emit ~severe:false ~source:"MemBornat.int_of_loc"
+        ~effect:"Loc is NULL" "NULL=%a" M.pretty repr ;
+      M.pointer_val repr
+    | Bornat.Loc { repr } -> M.int_of_loc c_int repr
+  (** Cast a memory location into its absolute memory address,
+      given as an integer with the given C-type. *)
+
+  let is_null = function
+    | Bornat.Null { repr } -> M.is_null repr
+    | Bornat.Loc { repr } -> M.is_null repr
+  (** Return the formula that check if a given location is null *)
+
+  let get_repr = function
+    | Bornat.Null { repr } -> repr
+    | Bornat.Loc { repr } -> repr
+
+  let loc_eq loc_a loc_b = M.loc_eq (get_repr loc_a) (get_repr loc_b)
+  let loc_lt loc_a loc_b = M.loc_lt (get_repr loc_a) (get_repr loc_b)
+  let loc_neq loc_a loc_b =  M.loc_neq (get_repr loc_a) (get_repr loc_b)
+  let loc_leq loc_a loc_b =  M.loc_leq (get_repr loc_a) (get_repr loc_b)
+  (** Memory location comparisons *)
+
+  let loc_diff ty loc_a loc_b =  M.loc_diff ty (get_repr loc_a) (get_repr loc_b)
+  (** Compute the length in bytes between two memory locations *)
+
+  let get_rloc = function
+    | Rloc (ty, Bornat.Null { repr }) -> Rloc (ty, repr)
+    | Rloc (ty, Bornat.Loc loc) ->
+      Rloc (ty, loc.repr)
+    | Rrange (Bornat.Null { repr }, ty, inf, sup) ->
+      Rrange (repr, ty, inf, sup)
+    | Rrange (Bornat.Loc loc, ty, inf, sup) ->
+      Rrange (loc.repr, ty, inf, sup)
+
+
+  let get_rloc_region = function
+    | Rloc (ty, loc) ->
+      Rloc (ty, (match loc with Bornat.Null { repr } -> repr | Bornat.Loc { repr } -> repr)),
+      (match loc with Bornat.Null _ -> None | Bornat.Loc { region } -> Some region)
+    | Rrange (loc, ty, inf, sup) ->
+      Rrange ((match loc with Bornat.Null { repr } -> repr | Bornat.Loc { repr } -> repr), ty, inf, sup),
+      (match loc with Bornat.Null _ -> None | Bornat.Loc { region } -> Some region)
+
+
+  let valid sigma acs (rloc : loc rloc) = M.valid sigma.Tuple.model acs @@ get_rloc rloc
+  (** Return the formula that tests if a memory state is valid
+      (according to {!acs}) in the given memory state at the given
+      segment.
+  *)
+
+  let frame_value sigma region = match R.kind region with
+    | R.Many R.Ptr | R.Single R.Ptr -> MemMemory.framed @@ Sigma.value sigma @@ Chunk.CVal region
+    | R.Garbled | R.Many (R.Int _ | R.Float _) | R.Single (R.Int _ | R.Float _) -> p_true
+
+  let frame_init sigma region = match R.kind region with
+    | R.Many R.Ptr | R.Single R.Ptr -> MemMemory.cinits @@ Sigma.value sigma @@ Chunk.CInit region
+    | R.Garbled | R.Many (R.Int _ | R.Float _) | R.Single (R.Int _ | R.Float _) -> p_true
+
+  let frame sigma =
+    ValSigma.Chunk.Set.fold (fun r l -> frame_value sigma r :: l) (ValSigma.domain sigma.Tuple.value)
+    @@ InitSigma.Chunk.Set.fold (fun r l -> frame_init sigma r :: l) (InitSigma.domain sigma.Tuple.init)
+    @@ M.frame sigma.Tuple.model
+  (** Assert the memory is a proper heap state preceeding the function
+      entry point. *)
+
+  let alloc sigma vars =
+    if vars = [] then sigma else { sigma with Tuple.model = M.alloc sigma.Tuple.model vars }
+  (** Allocates new chunk for the validity of variables. *)
+
+  let invalid sigma rloc = M.invalid sigma.Tuple.model (get_rloc rloc)
+  (** Returns the formula that tests if the entire memory is invalid
+      for write access. *)
+
+  let scope sigma scope vars =
+    let m_sigma = { pre = sigma.pre.Tuple.model ; post = sigma.post.Tuple.model } in
+    M.scope m_sigma scope vars
+  (** Manage the scope of variables.  Returns the updated memory model
+      and hypotheses modeling the new validity-scope of the variables. *)
+
+  let global sigma p = M.global sigma.Tuple.model p
+  (** Given a pointer value [p], assumes this pointer [p] (when valid)
+      is allocated outside the function frame under analysis. This means
+      separated from the formals and locals of the function. *)
+
+  let included (rloc1 : segment) (rloc2 : segment) =
+    let (rl1, region1) = get_rloc_region rloc1 in
+    let (rl2, region2) = get_rloc_region rloc2 in
+    match region1, region2 with
+    | None, _ -> M.included rl1 rl2
+    | _, None -> p_false
+    | Some region1, Some region2 ->
+      if R.separated region1 region2 then p_false
+      else M.included rl1 rl2
+
+  let separated (rloc1 : segment) (rloc2 : segment) =
+    let (rl1, region1) = get_rloc_region rloc1 in
+    let (rl2, region2) = get_rloc_region rloc2 in
+    match region1, region2 with
+    | None, _ | _, None -> M.separated rl1 rl2
+    | Some region1, Some region2 ->
+      if R.separated region1 region2 then p_true
+      else M.separated rl1 rl2
+
+  let chunk_is_well_formed sigma chunk = match chunk with
+    | Chunk.CModel _ | Chunk.CInit _ -> p_true
+    | Chunk.CVal region -> match R.kind region with
+      | R.Garbled -> p_true
+      | R.Many (R.Float _ | R.Ptr ) | R.Single (R.Float _ | R.Ptr ) -> p_true
+      | R.Many (R.Int cint) ->
+        let l = Lang.freshvar ~basename:"l" (Lang.t_addr()) in
+        let m = Sigma.value sigma chunk in
+        p_forall [l] (Cint.range cint (F.e_get m (e_var l)))
+      | R.Single (R.Int cint) ->
+        Cint.range cint @@ Sigma.value sigma chunk
+
+
+  let is_well_formed sigma =
+    p_and (M.is_well_formed sigma.Tuple.model)
+    @@ p_conj @@ Sigma.Chunk.Set.fold (fun c l -> chunk_is_well_formed sigma c :: l) (Sigma.domain sigma) []
+
+
+end
+
+*)
+
+
+module MemMake (R:RegionAnalysis.API) (M:ModelLoader) (* : Sigs.Model *) =
+struct
+
+  type region = R.region
+
+  (****************************************************************************)
+  (*                                                                          *)
+  (*                               Extern API                                 *)
+  (*                                                                          *)
+  (****************************************************************************)
+  let datatype = "MemBornat.Make"
+  (** For projectification. Must be unique among models. *)
+
+  let configure () =
+    begin
+      let rollback () =
+        M.configure () () ;
+      in
+      rollback
+    end
+  (** Initializers to be run before using the model.
+      Typically push {i Context} values and returns a function to rollback.
+  *)
+
+  let configure_ia ia = (* TODO *) M.configure_ia ia
+  (** Given an automaton, return a vertex's binder.
+      Currently used by the automata compiler to bind current vertex.
+
+  *)
+
+  let hypotheses p = M.hypotheses p
+  (** Computes the memory model partitionning of the memory locations.
+      This function typically adds new elements to the partition received
+      in input (that can be empty).
+      ============================> TODO <======================================
+  *)
+
+  module BChunk = struct
+
+    (* Do not warn on unused constructors, even if they are not used yet. *)
+    [@@@ warning "-37" ]
+
+    type t =
+      | CVal of R.region
+      | CInit of R.region
+      | CGhost of R.region
+
+    let self = "MemBornat.Make.BornatChunk"
+
+
+    let hash = function
+      | CVal r -> 0x02 * R.hash r
+      | CInit r -> 0x100 * R.hash r
+      | CGhost r -> 0x10000 * R.hash r
+
+    let equal c1 c2 = match c1, c2 with
+      | CVal r1, CVal r2 | CInit r1, CInit r2 | CGhost r1, CGhost r2 -> R.equal r1 r2
+      | _ -> false
+
+    let compare c1 c2 = hash c1 - hash c2
+
+    let pretty fmt = function
+      | CVal   _ -> Format.fprintf fmt "Value"
+      | CInit  _ -> Format.fprintf fmt "Init"
+      | CGhost _ -> Format.fprintf fmt "Ghost"
+
+    let tau_of_primitive = function
+      | R.Int _ -> L.Int
+      | R.Float c_float -> Cfloat.tau_of_float c_float
+      | R.Ptr -> MemAddr.t_addr
+
+    let tau_of_chunk = function
+      | CVal   r | CGhost r ->
+        begin match R.kind r with
+          | R.Single p -> tau_of_primitive p
+          | R.Many   p -> L.Array (MemAddr.t_addr, tau_of_primitive p)
+          | R.Garbled  -> assert false
+        end
+      (* | CAlloc r -> t_malloc *)
+      | CInit  r ->
+        begin match R.kind r with
+          | R.Single _ -> t_bool
+          | R.Many   _ -> t_init
+          | R.Garbled  -> assert false
+        end
+
+    let basename_of_chunk = function
+      | CGhost _ -> "GhostChunk"
+      | CVal   _ -> "ValueChunk"
+      | CInit  _ -> "InitChunk"
+    (** Used when generating fresh variables for a chunk. *)
+
+    let is_framed _ = false
+
+  end
+
+  module B = BChunk
+
+  module BHeap = Qed.Collection.Make(B)
+
+  module BSigma = Sigma.Make(BChunk)(BHeap)
+
+  module Chunk =
+  struct
+    type t =
+      | CModel of M.chunk
+      | CBornat of BChunk.t
+
+    let self = "MemBornat.Make.Chunk"
+    (** Chunk names, for pretty-printing. *)
+
+    let hash = function
+      | CModel c -> M.Chunk.hash c
+      | CBornat c -> 0x1000 * (B.hash c)
+
+    let equal ca cb = match ca, cb with
+      | CModel  c1, CModel  c2 -> M.Chunk.equal c1 c2
+      | CBornat c1, CBornat c2 -> B.equal       c1 c2
+      | CModel _, CBornat _ | CBornat _, CModel _ -> false
+
+    let compare c1 c2 = (hash c1) - (hash c2)
+
+    let pretty fmt = function
+      | CModel  c -> Format.fprintf fmt "CModel.%a" M.Chunk.pretty c
+      | CBornat c -> Format.fprintf fmt "CBornat.%a" B.pretty c
+
+    let tau_of_chunk = function
+      | CModel c -> M.Chunk.tau_of_chunk c
+      | CBornat c -> B.tau_of_chunk c
+
+    let basename_of_chunk = function
+      | CModel  _ -> "Model"
+      | CBornat _ -> "Bornat"
+    (** Used when generating fresh variables for a chunk. *)
+
+    let is_framed = function
+      | CModel c -> M.Chunk.is_framed c
+      | CBornat _ -> false
+      (** Whether the chunk is local to a function call.
+
+          Means the chunk is separated from anyother call side-effects.
+          If [true], entails that a function assigning everything can not modify
+          the chunk. Only used for optimisation, it would be safe to always
+          return [false]. *)
+  end
+  (** Memory Chunks.
+
+      The concrete memory is partionned into a vector of abstract data.
+      Each component of the partition is called a {i memory chunk} and
+      holds an abstract representation of some part of the memory.
+
+      Remark: memory chunks are not required to be independant from each other,
+      provided the memory model implementation is consistent with the chosen
+      representation. Conversely, a given object might be represented by
+      several memory chunks.
+
+  *)
+
+  module Heap = Qed.Collection.Make(Chunk)
+
+  module Tuple = struct
+    type ('a, 'b) tuple = {
+      model  : 'a ;
+      bornat : 'b ;
+    }
+
+    let create f1 f2 input = {
+      model  = f1 input ;
+      bornat = f2 input ;
+    }
+
+    let iter f1 f2 tuple =
+      f1 tuple.model  ;
+      f2 tuple.bornat ;
+      ()
+
+    let iter2 f1 f2 t1 t2 =
+      f1 t1.model  t2.model  ;
+      f2 t1.bornat t2.bornat ;
+      ()
+
+    let choose_apply f1 f2 tuple = function
+      | Chunk.CModel  c -> f1 tuple.model  c
+      | Chunk.CBornat c -> f2 tuple.bornat c
+
+    let choose_map f1 f2 tuple = function
+      | Chunk.CModel  c -> { tuple with model  = f1 tuple.model  c }
+      | Chunk.CBornat c -> { tuple with bornat = f2 tuple.bornat c }
+
+    let map f1 f2 tuple = {
+      model  = f1 tuple.model  ;
+      bornat = f2 tuple.bornat ;
+    }
+
+    let map2 f1 f2 t1 t2 = {
+      model = f1 t1.model t2.model ;
+      bornat = f2 t1.bornat t2.bornat ;
+    }
+
+    let sequence_map f1 f2 seq = {
+      model  = f1 { pre = seq.pre.model  ; post = seq.post.model  } ;
+      bornat = f2 { pre = seq.pre.bornat ; post = seq.post.bornat } ;
+    }
+  end
+
+  type sigma = (M.sigma, BSigma.t) Tuple.tuple
+
+  module Sigma = (* Sigma.Make(Chunk)(Heap) *) struct
+
+    open Tuple
+    type t = sigma
+    type chunk = Chunk.t
+
+    open Chunk
+
+    type domain = Heap.set
+
+    type dom = (M.Sigma.domain, BSigma.domain) Tuple.tuple
+
+    (* local *)
+    let chunk_split_list l =
+      let rec aux acc1 acc2 = function
+        | [] -> { model = List.rev acc1 ; bornat = List.rev acc2 }
+        | CModel  c :: rest -> aux (c::acc1) acc2 rest
+        | CBornat c :: rest -> aux acc1 (c::acc2) rest
+      in aux [] [] l
+
+    let of_domain (domain:domain) : dom =
+      Tuple.map
+        M.Sigma.Chunk.Set.of_list
+        BSigma.Chunk.Set.of_list
+      @@ chunk_split_list
+      @@ Heap.Set.elements domain
+
+    let to_domain (dom:dom) : domain =
+      let cmodel = M.Heap.Set.elements dom.model in
+      let cbornat = BSigma.Chunk.Set.elements dom.bornat in
+      let model = Heap.Set.of_list (List.map (fun c -> CModel  c) cmodel) in
+      let bornat = Heap.Set.of_list (List.map (fun c -> CBornat c) cbornat) in
+      Heap.Set.union model bornat
+
+    module Chunk = Heap
+
+
+    let create = Tuple.create M.Sigma.create BSigma.create
+
+    let pretty fmt sigma =
+      Format.fprintf fmt "@[{@[%a@];@[%a@]}@]"
+        M.Sigma.pretty sigma.model
+        BSigma.pretty sigma.bornat
+
+    let empty : domain = Heap.Set.empty
+
+    let mem = Tuple.choose_apply M.Sigma.mem BSigma.mem
+
+    let get = Tuple.choose_apply M.Sigma.get BSigma.get
+
+    let writes sigma = to_domain @@ Tuple.sequence_map M.Sigma.writes BSigma.writes sigma
+
+    let value = Tuple.choose_apply M.Sigma.value BSigma.value
+
+    let copy = Tuple.map M.Sigma.copy BSigma.copy
+
+    let join sigma1 sigma2 =
+      let r = Tuple.map2 M.Sigma.join BSigma.join sigma1 sigma2 in
+      Passive.union r.model r.bornat
+
+    let assigned ~pre:sigma1 ~post:sigma2 domain =
+      let dom = of_domain domain in
+      Bag.concat (M.Sigma.assigned ~pre:sigma1.model ~post:sigma2.model dom.model)
+      @@ BSigma.assigned ~pre:sigma1.bornat ~post:sigma2.bornat dom.bornat
+
+    let choose = Tuple.map2 M.Sigma.choose BSigma.choose
+
+    let merge s1 s2 =
+      let (sm, pm1, pm2) = M.Sigma.merge s1.model s2.model in
+      let (sb, pb1, pb2) = BSigma.merge s1.bornat s2.bornat in
+      let s = { model = sm ; bornat = sb } in
+      let p1 = Passive.union pm1 pb1 in
+      let p2 = Passive.union pm2 pb2 in
+      (s,p1,p2)
+
+    let merge_list ls = (* TOCHECK *)
+      let f (s1,lp) s2 =
+        let (s,p1,p2) = merge s1 s2 in
+        (s, p1::p2::lp)
+      in
+      match ls with
+      | [] -> (create (), [])
+      | [ s ] -> (s, [ Passive.empty ])
+      | _ -> List.fold_left f (create (), []) ls
+
+    let iter f =
+      Tuple.iter
+        (M.Sigma.iter (fun c -> f (CModel c)))
+        (BSigma.iter (fun c -> f (CBornat c)))
+
+    let iter2 f =
+      Tuple.iter2
+        (M.Sigma.iter2 (fun c -> f (CModel c)))
+        (BSigma.iter2 (fun c -> f (CBornat c)))
+
+    let havoc_chunk = Tuple.choose_map M.Sigma.havoc_chunk BSigma.havoc_chunk
+
+    let havoc sigma domain =
+      let dom = of_domain domain in
+      Tuple.map2 M.Sigma.havoc BSigma.havoc sigma dom
+
+    let havoc_any ~call:call =
+      Tuple.map (M.Sigma.havoc_any ~call) (BSigma.havoc_any ~call)
+
+    let remove_chunks sigma domain =
+      let dom = of_domain domain in
+      Tuple.map2 M.Sigma.remove_chunks BSigma.remove_chunks sigma dom
+
+    let dom = Tuple.map M.Sigma.domain BSigma.domain
+
+    let domain sigma =
+      let dom = dom sigma in
+      Chunk.Set.of_list
+      @@ List.append
+        (List.map (fun l -> CModel l) (M.Heap.Set.elements dom.model))
+        (List.map (fun c -> CBornat c) (BHeap.Set.elements dom.bornat))
+
+    let union = Chunk.Set.union
+
+  end
+
+  (* ************************************************************************ *)
+  (* ***   MemLoader instanciation from the implementation of MemTyped    *** *)
+  (* ************************************************************************ *)
+
+
+  (****************************************************************************)
+  (** module Bornat : MemLoader.Module                                       **)
+  (****************************************************************************)
+
+  module Bornat = struct
+    module Chunk = Chunk
+    module Sigma = Sigma
+    let name = "BornatModel"
+
+    type loc =
+      | Null
+      | Raw of { repr : M.loc }
+      | Loc   of { repr : M.loc ; region : region }
+
+
+    (* ---------------------------------------------------------------------- *)
+    (* --- Utilities on locations                                         --- *)
+    (* ---------------------------------------------------------------------- *)
+
+    let last sigma ty = function
+      | Null ->
+        Warning.emit ~severe:false ~source:"MemBornat.Bornat.last"
+          ~effect:"Loc is NULL" "loc=NULL" ;
+        M.pointer_val M.null
+      | Raw { repr } ->
+        Warning.emit ~severe:false ~source:"MemBornat.Bornat.last"
+          ~effect:"Loc is Raw" "loc=%a" M.pretty repr ;
+        M.last sigma.Tuple.model ty repr
+      | Loc { repr } -> M.last sigma.Tuple.model ty repr
+
+    (** Conversion among loc, t_pointer terms and t_addr terms *)
+    let to_addr = function
+      | Null -> M.pointer_val M.null
+      | Raw { repr } -> M.pointer_val repr
+      | Loc { repr } -> M.pointer_val repr
+
+    let to_region_pointer = function
+      | Null -> (0, M.pointer_val M.null)
+      | Raw { repr } -> (0, M.pointer_val repr)
+      | Loc { repr ; region } -> (R.id_of_region region, M.pointer_val repr)
+
+    let of_region_pointer id _ty term =
+      if id == 0 then
+        if QED.equal term (M.pointer_val M.null) then Null else
+          let _ =
+            Warning.emit ~severe:false ~source:"MemBornat.Bornat.of_region_pointer"
+              ~effect:"No region has been found" "Region_id is zero for loc=%a"
+              QED.pretty term
+          in Raw { repr = M.pointer_loc term }
+      else match R.region_of_id id with
+        | None ->
+          let _ = Warning.emit ~severe:false ~source:"MemBornat.Bornat.of_region_pointer"
+              ~effect:"No region has been found" "Region_id=%d for term=%a" id
+              QED.pretty term
+          in Raw { repr = M.pointer_loc term }
+        | Some region -> Loc { repr = M.pointer_loc term ; region }
+
+    (** Basic operations *)
+    let sizeof ty = M.sizeof ty
+
+    let field loc field : loc = (* TODO: reconstruction *) match loc with
+      | Null -> Null
+      | Raw { repr } ->
+        let _ = Warning.emit ~severe:false ~source:"MemBornat.Bornat.field"
+            ~effect:"Loc is Raw" "(%a).(%a)"
+            M.pretty repr Printer.pp_field field
+        in Raw { repr = M.field repr field }
+      | Loc { repr ; region } ->
+        match R.field region field with
+        | None ->
+          let _ = Warning.emit ~severe:false ~source:"MemBornat.Bornat.field"
+              ~effect:"No region for field" "(%a in %a).(%a)"
+              M.pretty repr R.pretty region Printer.pp_field field
+          in Raw { repr = M.field repr field }
+        | Some region -> Loc { repr = M.field repr field ; region }
+
+    let shift loc ty offset = match loc with
+      | Null -> Null
+      | Raw { repr } ->
+        let _ = Warning.emit ~severe:false ~source:"MemBornat.Bornat.shift"
+            ~effect:"Loc is Raw" "No region for (%a).[%a : %a]"
+            M.pretty repr QED.pretty offset Ctypes.pp_object ty
+        in Raw { repr = M.shift repr ty offset }
+      | Loc { repr ; region } ->
+        match R.shift region ty offset with
+        | None ->
+          let _ = Warning.emit ~severe:false ~source:"MemBornat.Bornat.field"
+              ~effect:"No region for shift" "No region for (%a in %a).[%a : %a]"
+              M.pretty repr R.pretty region QED.pretty offset Ctypes.pp_object ty
+          in Raw { repr = M.shift repr ty offset }
+        | Some region ->
+          Loc { repr = M.shift repr ty offset ; region }
+
+    let frames_repr_region ty mloc r c =
+      match R.kind r with
+      | R.Single R.Ptr | R.Many R.Ptr ->
+        let offset = M.sizeof ty in
+        let sizeof = F.e_one in
+        let tau = Chunk.tau_of_chunk c in
+        let basename = Chunk.basename_of_chunk c in
+        MemMemory.frames ~addr:(M.pointer_val mloc) ~offset ~sizeof ~basename tau
+      | _ -> []
+
+    let frames ty loc chunk =
+      match loc with
+      | Null -> []
+      | Raw { repr } -> begin match chunk with
+          | Chunk.CModel c ->
+            let _ = Warning.emit ~severe:false ~source:"MemBornat.Bornat.frames"
+                ~effect:"Loc is Raw" "Frames %a" M.pretty repr
+            in M.frames ty repr c
+          | Chunk.CBornat (B.CVal r | B.CInit r | B.CGhost r) ->
+            frames_repr_region ty repr r chunk
+        end
+      | Loc { repr ; region } -> frames_repr_region ty repr region chunk
+          (*
+        begin match R.kind r with
+        | R.Single R.Ptr | R.Many R.Ptr -> [MemMemory.framed (Sigma.value chunk)]
+        | _ -> []
+        end *)
+      (*
+      si chunk = CVal r et R.tau_of_region == ptr then the predicate MemMemory.framed (Sigma.value chunk)
+      si chunk = CInit r then MemMemory.cinits (Sigma.value chunk)
+      *)
+
+    let havoc ty loc ~length chunk ~fresh ~current = match loc with
+      | Null ->
+        F.e_fun f_havoc [fresh;current;M.pointer_val M.null;length]
+      | Raw { repr } ->
+        let _ = Warning.emit ~severe:false ~source:"MemBornat.Bornat.havoc"
+            ~effect:"Loc is Raw" "havoc of Raw=%a"
+            M.pretty repr
+        in F.e_fun f_havoc [fresh;current;M.pointer_val repr;length]
+      | Loc { repr } ->
+        (* TO CHECK *) assert (QED.equal length F.e_one) ;
+        match chunk with
+        | Chunk.CModel c -> M.havoc ty repr ~length c ~fresh ~current
+        | Chunk.CBornat _ ->
+          F.e_fun f_havoc [fresh;current;M.pointer_val repr;length]
+
+
+    let eqmem_forall ty loc chunk m1 m2 = match loc, chunk with
+      | Null, Chunk.CModel  c -> M.eqmem_forall ty M.null c m1 m2
+      | Null, Chunk.CBornat _ ->
+        let _ = Warning.emit ~severe:false ~source:"MemBornat.Bornat.eqmem_forall"
+            ~effect:"Loc is NULL" "Los is Null in eqmem_forall"
+        in [], p_true, p_true
+      | (Raw { repr } | Loc { repr }), Chunk.CModel  c ->
+        M.eqmem_forall ty repr c m1 m2
+      | (Raw { repr } | Loc { repr }), Chunk.CBornat _ ->
+        let xp = Lang.freshvar ~basename:"b" MemAddr.t_addr in
+        let p = F.e_var xp in
+        let n = M.sizeof ty in
+        let separated = F.p_call MemAddr.p_separated [p;e_one;M.pointer_val repr;n] in
+        let equal = p_equal (e_get m1 p) (e_get m2 p) in
+        [xp],separated,equal
+
+    (* ---------------------------------------------------------------------- *)
+    (* --- Load                                                           --- *)
+    (* ---------------------------------------------------------------------- *)
+
+    let load_int sigma (c_int:c_int) loc : term = match loc with
+      | Null ->
+        let _ = Warning.emit ~severe:false ~source:"MemBornat.Bornat.load_int"
+            ~effect:"Loc is Null" "Attempt to load_int inside Null"
+        in M.load_int sigma.Tuple.model c_int M.null
+      | Raw { repr } ->
+        let _ = Warning.emit ~severe:false ~source:"MemBornat.Bornat.load_int"
+            ~effect:"Loc is Raw" "load_int(Raw %a)" M.pretty repr
+        in M.load_int sigma.Tuple.model c_int repr
+      | Loc { repr ; region } ->
+        let c = Chunk.CBornat (B.CVal region) in
+        match R.kind region with
+        | R.Many (R.Int c_int') ->
+          if compare_c_int c_int c_int' = 0
+          then F.e_get (Sigma.value sigma c) @@ M.pointer_val repr
+          else
+            let _ =
+              Warning.emit ~severe:false ~source:"MemBornat.Bornat.load_int"
+                ~effect:"C_int type is not the same in chunk and in argument"
+                "%a!=%a" Ctypes.pp_int c_int Ctypes.pp_int c_int'
+            in F.e_get (Sigma.value sigma c)
+            @@ M.pointer_val repr
+        | R.Single (R.Int c_int') ->
+          if compare_c_int c_int c_int' = 0
+          then Sigma.value sigma c
+          else
+            let _ =
+              Warning.emit ~severe:false ~source:"MemBornat.Bornat.load_int"
+                ~effect:"C_int type is not the same in chunk and in argument"
+                "%a!=%a" Ctypes.pp_int c_int Ctypes.pp_int c_int'
+            in Sigma.value sigma c
+        | R.Garbled -> M.load_int sigma.model c_int repr
+        | k ->
+          let _ =
+            Warning.emit ~severe:false ~source:"MemBornat.Bornat.load_int"
+              ~effect:"Region's kind is not Int" "%a : %a != %a"
+              R.pretty region R.pp_kind k Ctypes.pp_int c_int
+          in assert false
+
+    let load_float sigma (c_float:c_float) loc : term = match loc with
+      | Null ->
+        let _ = Warning.emit ~severe:false
+            ~source:"MemBornat.Bornat.load_float"
+            ~effect:"Loc is Null" "Attempt to load_float inside Null"
+        in M.load_float sigma.Tuple.model c_float M.null
+      | Raw { repr } ->
+        let _ = Warning.emit ~severe:false
+            ~source:"MemBornat.Bornat.load_float"
+            ~effect:"Loc is Raw" "load_float(Raw %a)" M.pretty repr
+        in M.load_float sigma.Tuple.model c_float repr
+      | Loc { repr ; region } ->
+        let c = Chunk.CBornat (B.CVal region) in
+        match R.kind region with
+        | R.Many (R.Float c_float') ->
+          if compare_c_float c_float c_float' = 0
+          then F.e_get (Sigma.value sigma c) @@ M.pointer_val repr
+          else
+            let _ = Warning.emit ~severe:false
+                ~source:"MemBornat.Bornat.load_float"
+                ~effect:"Type is not the same in chunk and in argument" "%a!=%a"
+                Ctypes.pp_float c_float Ctypes.pp_float c_float'
+            in F.e_get (Sigma.value sigma c) @@ M.pointer_val repr
+        | R.Single (R.Float c_float') ->
+          if compare_c_float c_float c_float' = 0
+          then Sigma.value sigma c
+          else
+            let _ = Warning.emit ~severe:false
+                ~source:"MemBornat.Bornat.load_float"
+                ~effect:"Type is not the same in chunk and in argument" "%a!=%a"
+                Ctypes.pp_float c_float Ctypes.pp_float c_float'
+            in Sigma.value sigma c
+        | R.Garbled -> M.load_float sigma.model c_float repr
+        | k ->
+          let _ =
+            Warning.emit ~severe:false ~source:"MemBornat.Bornat.load_float"
+              ~effect:"Region's kind is not Float" "%a : %a != %a"
+              R.pretty region R.pp_kind k Ctypes.pp_float c_float
+          in assert false
+
+    let load_pointer sigma ty loc : loc = match loc with
+      | Null ->
+        let _ = Warning.emit ~severe:false
+            ~source:"MemBornat.Bornat.load_float"
+            ~effect:"Loc is Null" "Attempt to load_float inside Null"
+        in let mloc = M.load_pointer sigma.Tuple.model ty M.null in
+        if QED.equal (M.pointer_val mloc) (M.pointer_val M.null)
+        then Null else Raw { repr = mloc }
+      | Raw { repr } ->
+        let _ = Warning.emit ~severe:false
+            ~source:"MemBornat.Bornat.load_pointer"
+            ~effect:"Loc is Raw" "load_pointer(Raw %a : *%a)"
+            M.pretty repr Printer.pp_typ ty
+        in Raw { repr = M.load_pointer sigma.Tuple.model ty repr }
+      | Loc { repr ; region } ->
+        let c = Chunk.CBornat (B.CVal region) in
+        match R.points_to region with
+        | None ->
+          let _ = Warning.emit ~severe:false
+              ~source:"MemBornat.Bornat.load_pointer"
+              ~effect:"No region pointed" "No region for *(%a in %a)"
+              M.pretty repr R.pretty region
+          in Raw { repr = M.load_pointer sigma.Tuple.model ty repr }
+        | Some r ->
+          let repr = match R.kind region with
+            | R.Many (R.Ptr) ->
+              M.pointer_loc
+              @@ F.e_get (Sigma.value sigma c) @@ M.pointer_val repr
+            | R.Single (R.Ptr) -> M.pointer_loc @@ Sigma.value sigma c
+            | R.Garbled -> M.load_pointer sigma.Tuple.model ty repr
+            | k ->
+              let _ = Warning.emit ~severe:false
+                  ~source:"MemBornat.Bornat.load_pointer"
+                  ~effect:"Kind of region is not a pointer"
+                  "Region %a : %a != %a"
+                  R.pretty region R.pp_kind k Printer.pp_typ ty
+              in assert false
+          in Loc { repr ; region = r }
+
+
+
+    (* ---------------------------------------------------------------------- *)
+    (* --- Store                                                          --- *)
+    (* ---------------------------------------------------------------------- *)
+
+    let store_int sigma c_int loc v : Chunk.t * term = match loc with
+      | Null ->
+        let _ = Warning.emit ~severe:false ~source:"MemBornat.Bornat.store_int"
+            ~effect:"Loc is Null" "Attempt to store_int inside Null"
+        in let c, t = M.store_int sigma.Tuple.model c_int M.null v in
+        Chunk.CModel c, t
+      | Raw { repr } ->
+        let _ = Warning.emit ~severe:false ~source:"MemBornat.Bornat.store_int"
+            ~effect:"Loc is Raw" "store_int(Raw %a)" M.pretty repr
+        in let c, t = M.store_int sigma.Tuple.model c_int repr v in
+        Chunk.CModel c, t
+      | Loc { repr ; region } ->
+        let c = Chunk.CBornat (B.CVal region) in
+        match R.kind region with
+        | R.Many (R.Int c_int') as k ->
+          if compare_c_int c_int c_int' = 0
+          then (c, F.e_set (Sigma.value sigma c) (M.pointer_val repr) v)
+          else
+            let _ = Warning.emit ~severe:false
+                ~source:"MemBornat.Bornat.store_int"
+                ~effect:"Int types are not the same"
+                "(%a in %a : %a != %a)"
+                M.pretty repr R.pretty region R.pp_kind k Ctypes.pp_int c_int
+            in (c, F.e_set (Sigma.value sigma c) (M.pointer_val repr) v)
+        | R.Single (R.Int c_int') as k ->
+          if compare_c_int c_int c_int' = 0
+          then (c, v)
+          else
+            let _ = Warning.emit ~severe:false
+                ~source:"MemBornat.Bornat.store_int"
+                ~effect:"Int types are not the same"
+                "(%a in %a : %a != %a)"
+                M.pretty repr R.pretty region R.pp_kind k Ctypes.pp_int c_int
+            in (c, v)
+        | R.Garbled ->
+          let (c', v) = M.store_int sigma.model c_int repr v in
+          (Chunk.CModel c', v)
+        | k ->
+          let _ = Warning.emit ~severe:false
+              ~source:"MemBornat.Bornat.store_int"
+              ~effect:"Int types are not the same"
+              "(%a in %a : %a != %a)"
+              M.pretty repr R.pretty region R.pp_kind k Ctypes.pp_int c_int
+          in assert false
+
+    let store_float sigma c_float loc v : Chunk.t * term = match loc with
+      | Null ->
+        let _ = Warning.emit ~severe:false
+            ~source:"MemBornat.Bornat.store_float"
+            ~effect:"Loc is Null" "Attempt to store_float inside Null"
+        in let c, t = M.store_float sigma.Tuple.model c_float M.null v in
+        Chunk.CModel c, t
+      | Raw { repr } ->
+        let _ = Warning.emit ~severe:false
+            ~source:"MemBornat.Bornat.store_float"
+            ~effect:"Loc is Raw" "store_float(Raw %a)" M.pretty repr
+        in let c, t = M.store_float sigma.Tuple.model c_float repr v in
+        Chunk.CModel c, t
+      | Loc { repr ; region } ->
+        let c = Chunk.CBornat (B.CVal region) in
+        match R.kind region with
+        | R.Many (R.Float c_float') as k ->
+          if compare_c_float c_float c_float' = 0
+          then (c, F.e_set (Sigma.value sigma c) (M.pointer_val repr) v)
+          else
+            let _ = Warning.emit ~severe:false
+                ~source:"MemBornat.Bornat.store_float"
+                ~effect:"Float types are not the same"
+                "(%a in %a : %a != %a)"
+                M.pretty repr R.pretty region R.pp_kind k Ctypes.pp_float c_float
+            in (c, F.e_set (Sigma.value sigma c) (M.pointer_val repr) v)
+        | R.Single (R.Float c_float') as k ->
+          if compare_c_float c_float c_float' = 0
+          then (c, v)
+          else
+            let _ = Warning.emit ~severe:false
+                ~source:"MemBornat.Bornat.store_float"
+                ~effect:"Float types are not the same"
+                "(%a in %a : %a != %a)"
+                M.pretty repr R.pretty region R.pp_kind k Ctypes.pp_float c_float
+            in (c, v)
+        | R.Garbled ->
+          let (c, t) = M.store_float sigma.Tuple.model c_float repr v in
+          (Chunk.CModel c, t)
+        | k ->
+          let _ = Warning.emit ~severe:false
+              ~source:"MemBornat.Bornat.store_float"
+              ~effect:"Float types are not the same"
+              "(%a in %a : %a != %a)"
+              M.pretty repr R.pretty region R.pp_kind k Ctypes.pp_float c_float
+          in assert false
+
+    let store_pointer sigma ty loc v : Chunk.t * term = match loc with
+      | Null ->
+        let _ = Warning.emit ~severe:false
+            ~source:"MemBornat.Bornat.store_pointer"
+            ~effect:"Loc is Null" "Attempt to store_pointer inside Null"
+        in let c, t = M.store_pointer sigma.Tuple.model ty M.null v in
+        Chunk.CModel c, t
+      | Raw { repr } ->
+        let _ = Warning.emit ~severe:false
+            ~source:"MemBornat.Bornat.store_pointer"
+            ~effect:"Loc is Raw" "store_pointer(Raw %a : *%a)"
+            M.pretty repr Printer.pp_typ ty
+        in let c, t = M.store_pointer sigma.Tuple.model ty repr v in
+        Chunk.CModel c, t
+      | Loc { repr ; region } ->
+        let c = Chunk.CBornat (B.CVal region) in
+        match R.kind region with
+        | R.Many (R.Ptr) ->
+          c, F.e_set (Sigma.value sigma c) (M.pointer_val repr) v
+        | R.Single (R.Ptr) -> c,v
+        | R.Garbled ->
+          let (c, repr) = M.store_pointer sigma.Tuple.model ty repr v in
+          (Chunk.CModel c, repr)
+        | k ->
+          let _ = Warning.emit ~severe:false
+              ~source:"MemBornat.Bornat.store_pointer"
+              ~effect:"This is not a region with pointer type"
+              "(%a in %a : %a != *%a)"
+              M.pretty repr R.pretty region R.pp_kind k Printer.pp_typ ty
+          in assert false
+
+    (* ---------------------------------------------------------------------- *)
+    (* --- Init                                                           --- *)
+    (* ---------------------------------------------------------------------- *)
+
+    let set_init_atom sigma ty loc v = match loc with
+      | Null ->
+        let _ = Warning.emit ~severe:false
+            ~source:"MemBornat.Bornat.set_init_atom"
+            ~effect:"Loc is Null" "Attempt to set_init_atom with Null"
+        in let (c, t) = M.set_init_atom sigma.Tuple.model ty M.null v in
+        (Chunk.CModel c, t)
+      | Raw { repr } ->
+        let _ = Warning.emit ~severe:false
+            ~source:"MemBornat.Bornat.set_init_atom"
+            ~effect:"Loc is Raw" "set_init_atom(Raw %a <- %a)"
+            M.pretty repr QED.pretty v
+        in let (c, t) = M.set_init_atom sigma.Tuple.model ty repr v in
+        (Chunk.CModel c, t)
+      | Loc { repr ; region }->
+        match R.kind region with
+        | R.Garbled ->
+          let (c, t) = M.set_init_atom sigma.Tuple.model ty repr v in
+          (Chunk.CModel c, t)
+        | R.Single _-> Chunk.CBornat (B.CInit region), v
+        | R.Many _ ->
+          let c = Chunk.CBornat (B.CInit region) in
+          c, F.e_set (Sigma.value sigma c) (M.pointer_val repr) v
+
+    let is_init_atom sigma ty loc : term = match loc with
+      | Null ->
+        let _ = Warning.emit ~severe:false
+            ~source:"MemBornat.Bornat.is_init_atom"
+            ~effect:"Loc is Null" "is_init_atom(Null)"
+        in M.is_init_atom sigma.Tuple.model ty M.null
+      | Raw { repr } ->
+        let _ = Warning.emit ~severe:false
+            ~source:"MemBornat.Bornat.is_init_atom"
+            ~effect:"Loc is Raw" "is_init_atom(Raw %a)"
+            M.pretty repr
+        in M.is_init_atom sigma.Tuple.model ty repr
+      | Loc { repr ; region } ->
+        let c = Chunk.CBornat (B.CInit region) in
+        match R.kind region with
+        | R.Garbled -> M.is_init_atom sigma.Tuple.model ty repr
+        | R.Many _ -> F.e_get (Sigma.value sigma c) @@ M.pointer_val repr
+        | R.Single _ -> Sigma.value sigma c
+
+    let is_init_range sigma ty loc length : pred = match loc with
+      | Null ->
+        let _ = Warning.emit ~severe:false
+            ~source:"MemBornat.Bornat.is_init_range"
+            ~effect:"Loc is Null" "is_init_range(Null)"
+        in M.is_init_range sigma.Tuple.model ty M.null length
+      | Raw { repr } ->
+        let _ = Warning.emit ~severe:false
+            ~source:"MemBornat.Bornat.is_init_range"
+            ~effect:"Loc is Raw" "is_init_range(%a, ty=%a, length=%a)"
+            M.pretty repr Ctypes.pp_object ty QED.pretty length
+        in M.is_init_range sigma.Tuple.model ty repr length
+      | Loc { repr ; region } ->
+        match R.kind region with
+        | R.Garbled -> M.is_init_range sigma.Tuple.model ty repr length
+        | R.Many _ ->
+          let c = Chunk.CBornat (B.CInit region) in
+          let n = F.e_mul (M.sizeof ty) length in
+          F.p_call p_is_init_r [Sigma.value sigma c;M.pointer_val repr;n]
+        | R.Single _ as k ->
+          let _ = Warning.emit ~severe:false
+              ~source:"MemBornat.Bornat.is_init_range"
+              ~effect:"Region is Single kind" "is_init_range(%a in %a : %a, ty=%a, length=%a)"
+              M.pretty repr R.pretty region R.pp_kind k
+              Ctypes.pp_object ty QED.pretty length
+          in (* TODO *) assert false
+
+
+    let set_init ty loc ~length chunk ~current : term = match loc, chunk with
+      | Null, Chunk.CModel c ->
+        let _ = Warning.emit ~severe:false
+            ~source:"MemBornat.Bornat.set_init"
+            ~effect:"Loc is Null" "set_init(Null)"
+        in M.set_init ty M.null ~length c ~current
+      | Null, Chunk.CBornat _ ->
+        let _ = Warning.emit ~severe:false
+            ~source:"MemBornat.Bornat.set_init"
+            ~effect:"Loc is Null" "set_init(Null) and Chunk is Bornat"
+        in assert false
+      | Raw { repr }, Chunk.CModel c ->
+        let _ = Warning.emit ~severe:false
+            ~source:"MemBornat.Bornat.set_init"
+            ~effect:"Loc is Null" "set_init(Raw %a)"
+            M.pretty repr
+        in M.set_init ty repr ~length c ~current
+      | Raw { repr }, Chunk.CBornat _ ->
+        let _ = Warning.emit ~severe:false
+            ~source:"MemBornat.Bornat.set_init"
+            ~effect:"Loc is Null" "set_init(Raw %a) and Chunk is Bornat"
+            M.pretty repr
+        in assert false
+      | Loc { repr }, Chunk.CModel c -> M.set_init ty repr ~length c ~current
+      | Loc { repr ; region }, Chunk.CBornat c ->
+        match R.kind region, c with
+        | R.Garbled, ( B.CVal _ | B.CInit _| B.CGhost _) ->
+          let _ = Warning.emit ~severe:false
+              ~source:"MemBornat.Bornat.set_init"
+              ~effect:"Garbled is not associated to low memory model"
+              "set_init(%a in %a : Garbled)"
+              M.pretty repr R.pretty region
+          in assert false
+        | R.Many _, _ ->
+          let n = F.e_mul (M.sizeof ty) length in
+          F.e_fun f_set_init [current;M.pointer_val repr;n]
+        | R.Single _, _ ->
+          let _ = Warning.emit ~severe:false
+              ~source:"MemBornat.Bornat.set_init"
+              ~effect:"Single is not supported"
+              "set_init(%a in %a : Single)"
+              M.pretty repr R.pretty region
+          in (* TODO *) assert false
+
+
+    (* ---------------------------------------------------------------------- *)
+    (* --- Footprints                                                     --- *)
+    (* ---------------------------------------------------------------------- *)
+
+    let rec value_footprint ty loc = match loc with
+      | Null -> Sigma.empty
+      | Raw { repr } ->
+        let _ = Warning.emit ~severe:false
+            ~source:"MemBornat.Bornat.value_footprint"
+            ~effect:"Loc is Raw"
+            "value_footprint(Raw %a : %a)"
+            M.pretty repr Ctypes.pp_object ty
+        in let mdom = M.value_footprint ty repr in
+        let bdom = BSigma.empty in
+        Sigma.to_domain { Tuple.model = mdom ; Tuple.bornat = bdom }
+      | Loc { repr ; region } ->
+        match R.kind region, ty with
+        | R.Garbled, (C_int _ | C_float _ | C_pointer _) ->
+          let mdom = M.value_footprint ty repr in
+          Sigma.to_domain { Tuple.model = mdom ; Tuple.bornat = BSigma.empty }
+        | (R.Many (R.Int   _) | R.Single (R.Int   _)), C_int _
+        | (R.Many (R.Float _) | R.Single (R.Float _)), C_float _
+        | (R.Many (R.Ptr    ) | R.Single (R.Ptr    )), C_pointer _->
+          Heap.Set.singleton (Chunk.CBornat (B.CVal region))
+        | (R.Many _ | R.Single _) as k, (C_int _ | C_float _ | C_pointer _) ->
+          let _ = Warning.emit ~severe:false
+              ~source:"MemBornat.Bornat.value_footprint"
+              ~effect:"Type is not the same in chunk and in argument"
+              "value_footprint(%a : %a in %a : %a)"
+              M.pretty repr Ctypes.pp_object ty R.pretty region R.pp_kind k
+          in Heap.Set.singleton @@ Chunk.CBornat (B.CVal region)
+        | _, C_comp { cfields } ->
+          let none = Heap.Set.empty in
+          let f_fold acc fd =
+            Heap.Set.union acc
+            @@ value_footprint (Ctypes.object_of fd.ftype)
+            @@ field loc fd
+          in let some l_fields =
+               List.fold_left f_fold Heap.Set.empty l_fields
+          in Option.fold ~none ~some cfields
+        | _, C_array { arr_element } ->
+          let ty = object_of arr_element in
+          value_footprint ty (shift loc ty e_zero)
+
+    let rec init_footprint ty loc = match loc with
+      | Null -> Sigma.empty
+      | Raw { repr } ->
+        let _ = Warning.emit ~severe:false
+            ~source:"MemBornat.Bornat.init_footprint"
+            ~effect:"Loc is Raw"
+            "init_footprint(Raw %a : %a)"
+            M.pretty repr Ctypes.pp_object ty
+        in let mdom = M.init_footprint ty repr in
+        let bdom = BSigma.empty in
+        Sigma.to_domain { Tuple.model = mdom ; Tuple.bornat = bdom }
+      | Loc { repr ; region } ->
+        match R.kind region, ty with
+        | R.Garbled, (C_int _ | C_float _ | C_pointer _) ->
+          let mdom =  M.init_footprint ty repr in
+          Sigma.to_domain { Tuple.model = mdom ; Tuple.bornat = BSigma.empty }
+        | (R.Many (R.Int   _) | R.Single (R.Int   _)), C_int _
+        | (R.Many (R.Float _) | R.Single (R.Float _)), C_float _
+        | (R.Many (R.Ptr    ) | R.Single (R.Ptr    )), C_pointer _->
+          Heap.Set.singleton @@ Chunk.CBornat (B.CInit region)
+        | (R.Many _ | R.Single _) as k, (C_int _ | C_float _ | C_pointer _) ->
+          let _ = Warning.emit ~severe:false
+              ~source:"MemBornat.Bornat.init_footprint"
+              ~effect:"Type is not the same in chunk and in argument"
+              "init_footprint(%a : %a in %a : %a)"
+              M.pretty repr Ctypes.pp_object ty R.pretty region R.pp_kind k
+          in Heap.Set.singleton @@ Chunk.CBornat (B.CInit region)
+        | _, C_comp { cfields } ->
+          let none = Heap.Set.empty in
+          let f_fold acc fd =
+            Heap.Set.union acc
+            @@ init_footprint (Ctypes.object_of fd.ftype)
+            @@ field loc fd
+          in let some l_fields = List.fold_left f_fold Heap.Set.empty l_fields
+          in Option.fold ~none ~some cfields
+        | _, C_array { arr_element } ->
+          let ty = object_of arr_element in
+          init_footprint ty (shift loc ty e_zero)
+
+  end
+
+  type loc = Bornat.loc
+  type domain = Sigma.domain
+  type chunk = Chunk.t
+  type segment = loc rloc
+
+
+
+  (****************************************************************************)
+  module LOADER = MemLoader.Make(Bornat)
+  (******************************************************************************)
+
+  let load = LOADER.load
+  let load_init = LOADER.load_init
+  let stored = LOADER.stored
+  let stored_init = LOADER.stored_init
+  let copied = LOADER.copied
+  let copied_init = LOADER.copied_init
+  let initialized = LOADER.initialized
+  let domain = LOADER.domain
+
+(*
+  let sloc_oget = function
+  | Sloc None -> Sloc M.null, None
+  | Sloc (Some { Bornat.repr = repr }) -> Sloc repr
+  | Sarray (None,a,b) ->
+  | Srange (None,_,_,_)
+  | Sdescr (_,None,_) ->
+  |
+*)
+
+  let assigned seq ty sloc = match sloc with
+    | Sloc (Bornat.Null) | Sarray (Bornat.Null,_,_)
+    | Srange (Bornat.Null,_,_,_) | Sdescr (_,Bornat.Null,_) ->
+      LOADER.assigned seq ty sloc
+    | Sloc (Bornat.Raw _) | Sarray (Bornat.Raw _,_,_)
+    | Srange (Bornat.Raw _,_,_,_) | Sdescr (_,Bornat.Raw _,_) ->
+      LOADER.assigned seq ty sloc
+    | _ ->
+      (* Maintain always initialized values initialized *)
+      let region = match sloc with
+        | Sloc (Bornat.Loc loc) | Sarray (Bornat.Loc loc, _, _)
+        | Srange (Bornat.Loc loc, _, _, _)
+        | Sdescr (_, Bornat.Loc loc, _) -> loc.region
+        | Sloc (Bornat.Null|Bornat.Raw _)
+        | Sarray ((Bornat.Null|Bornat.Raw _),_,_)
+        | Srange ((Bornat.Null|Bornat.Raw _),_,_,_)
+        | Sdescr (_,(Bornat.Null|Bornat.Raw _),_) -> assert false
+      in
+      Assert (MemMemory.cinits
+              @@ Sigma.value seq.post @@ Chunk.CBornat (B.CInit region)) ::
+      LOADER.assigned seq ty sloc
+
+  (** {2 Reversing the Model} *)
+
+  type state = M.state
+
+  let state sigma = M.state sigma.Tuple.model
+
+  let lookup s e = M.lookup s e
+
+  let updates = M.updates
+
+  let apply = M.apply
+
+  let iter = M.iter
+
+  let pretty fmt = function
+    | Bornat.Null -> Format.fprintf fmt "NULL"
+    | Bornat.Raw { repr } -> Format.fprintf fmt "{ Raw %a }" M.pretty repr
+    | Bornat.Loc { repr ; region } ->
+      Format.fprintf fmt "{ %a in %a }"
+        M.pretty repr R.pretty region
+
+
+  (** {2 Memory Model API} *)
+
+  let vars = function
+    | Bornat.Null -> Vars.empty
+    | Bornat.Raw { repr } | Bornat.Loc { repr } -> M.vars repr
+  (** Return the logic variables from which the given location depend on. *)
+
+  let occurs var = function
+    | Bornat.Null -> false
+    | Bornat.Raw {repr } | Bornat.Loc { repr } -> M.occurs var repr
+  (** Test if a location depend on a given logic variable *)
+
+  let null = Bornat.Null
+  (** Return the location of the null pointer *)
+
+  let literal ~eid:eid name =
+    let repr = M.literal ~eid name in
+    match R.literal ~eid name with
+    | None -> Bornat.Raw { repr }
+    | Some region -> Bornat.Loc { repr ; region }
+  (** Return the memory location of a constant string,
+      the id is a unique identifier. *)
+
+  let cvar var =
+    match R.cvar var with
+    | None ->
+      let _ = Warning.emit ~severe:false ~source:"MemBornat.cvar"
+          ~effect:"No region for this var" "%a"
+          Printer.pp_varinfo var
+      in Bornat.Raw { repr = M.cvar var }
+    | Some region -> Bornat.Loc { repr = M.cvar var ; region }
+  (** Return the location of a C variable. *)
+
+  let pointer_loc term =
+    if QED.equal term @@ M.pointer_val M.null
+    then Bornat.Null
+    else let repr = M.pointer_loc term in
+      match R.pointer_loc () with
+      | None -> Bornat.Raw { repr }
+      | Some region -> Bornat.Loc { repr ; region }
+  (** Interpret an address value (a pointer) as an abstract location.
+      Might fail on memory models not supporting pointers. *)
+
+  let pointer_val = function
+    | Bornat.Null -> M.pointer_val M.null
+    | Bornat.Raw { repr } ->
+      let _ = Warning.emit ~severe:false ~source:"MemBornat.pointer_val"
+          ~effect:"No region for this loc" "%a" M.pretty repr
+      in M.pointer_val repr
+    | Bornat.Loc { repr } -> M.pointer_val repr
+  (** Return the adress value (a pointer) of an abstract location.
+      Might fail on memory models not capable of representing pointers. *)
+
+  let field loc fieldinfo = match loc with
+    | Bornat.Null ->
+      let _ = Warning.emit ~severe:false ~source:"MemBornat.field"
+          ~effect:"Loc is NULL"
+          "NULL.(%a)" Printer.pp_field fieldinfo
+      in Bornat.Null
+    | Bornat.Raw { repr } ->
+      let _ = Warning.emit ~severe:false ~source:"MemBornat.field"
+          ~effect:"Loc is Raw"
+          "(%a).(%a)" M.pretty repr Printer.pp_field fieldinfo
+      in Bornat.Raw { repr = M.field repr fieldinfo }
+    | Bornat.Loc { repr ; region } ->
+      match R.field region fieldinfo with
+      | None ->
+        let _ = Warning.emit ~severe:false ~source:"MemBornat.field"
+            ~effect:"No region for this field"
+            "(%a in %a).(%a in no region)"
+            M.pretty repr R.pretty region Printer.pp_field fieldinfo
+        in Bornat.Raw { repr = M.field repr fieldinfo }
+      | Some region -> Bornat.Loc { repr = M.field repr fieldinfo ; region }
+  (** Return the memory location obtained by field access from a given
+      memory location. *)
+
+  let shift loc ty term = match loc with
+    | Bornat.Null ->
+      let _ = Warning.emit ~severe:false ~source:"MemBornat.shift"
+          ~effect:"Loc is NULL"
+          "NULL.[%a : %a]" QED.pretty term Ctypes.pp_object ty
+      in Bornat.Null
+    | Bornat.Raw { repr } ->
+      let _ = Warning.emit ~severe:false ~source:"MemBornat.shift"
+          ~effect:"Loc is Raw"
+          "(%a).[%a : %a]"
+          M.pretty repr QED.pretty term Ctypes.pp_object ty
+      in Bornat.Raw { repr = M.shift repr ty term }
+    | Bornat.Loc { repr ; region } ->
+      match R.shift region ty term with
+      | None ->
+        let _ = Warning.emit ~severe:false ~source:"MemBornat.shift"
+            ~effect:"Loc is Raw"
+            "(%a in %a).[%a : %a] in no region"
+            M.pretty repr R.pretty region QED.pretty term Ctypes.pp_object ty
+        in Bornat.Raw { repr = M.shift repr ty term }
+      | Some region -> Bornat.Loc { repr = M.shift repr ty term ; region }
+  (** Return the memory location obtained by array access at an index
+      represented by the given {!term}. The element of the array are of
+      the given {!c_object} type. *)
+
+  let base_addr  = function
+    | Bornat.Null -> Bornat.Null
+    | Bornat.Raw { repr } ->
+      let _ = Warning.emit ~severe:false ~source:"MemBornat.base_addr"
+          ~effect:"Loc is Raw" "base_addr(%a)" M.pretty repr
+      in Bornat.Raw { repr = M.base_addr repr }
+    | Bornat.Loc { repr ; region } ->
+      Bornat.Loc { repr = M.base_addr repr ; region = R.base_addr region }
+  (** Return the memory location of the base address of a given memory
+      location. *)
+
+  let base_offset = function
+    | Bornat.Null -> M.base_offset M.null
+    | Bornat.Raw { repr } ->
+      let _ = Warning.emit ~severe:false ~source:"MemBornat.base_offset"
+          ~effect:"Loc is Raw" "base_offset(%a)" M.pretty repr
+      in M.base_offset repr
+    | Bornat.Loc { repr } -> M.base_offset repr
+  (** Return the offset of the location, in bytes, from its base_addr. *)
+
+  let block_length sigma ty  = function
+    | Bornat.Null -> M.block_length sigma.Tuple.model ty M.null
+    | Bornat.Raw { repr } ->
+      let _ = Warning.emit ~severe:false ~source:"MemBornat.block_length"
+          ~effect:"Loc is Raw" "block_length(%a)" M.pretty repr
+      in M.block_length sigma.Tuple.model ty repr
+    | Bornat.Loc { repr } -> M.block_length sigma.Tuple.model ty repr
+  (**  Returns the length (in bytes) of the allocated block containing
+       the given location. *)
+
+  let cast objs = function
+    | Bornat.Null -> Bornat.Null
+    | Bornat.Raw { repr } ->
+      let _ = Warning.emit ~severe:false ~source:"MemBornat.cast"
+          ~effect:"Loc is NULL" "NULL=%a" M.pretty repr
+      in Bornat.Raw { repr = M.cast objs repr }
+    | Bornat.Loc loc -> Bornat.Loc { loc with repr = M.cast objs loc.repr }
+  (** Cast a memory location into another memory location.
+      For [cast ty loc] the cast is done from [ty.pre] to [ty.post].
+      Might fail on memory models not supporting pointer casts. *)
+
+  let loc_of_int ty term =
+    if QED.equal term @@ M.pointer_val M.null
+    then Bornat.Null
+    else match R.loc_of_int () with
+      | None -> Bornat.Raw { repr = M.loc_of_int ty term }
+      | Some region -> Bornat.Loc { repr = M.loc_of_int ty term ; region }
+
+  let int_of_loc c_int = function
+    | Bornat.Null -> M.int_of_loc c_int M.null
+    | Bornat.Raw { repr } ->
+      let _ = Warning.emit ~severe:false ~source:"MemBornat.int_of_loc"
+          ~effect:"Loc is Raw" "NULL=%a" M.pretty repr
+      in M.int_of_loc c_int repr
+    | Bornat.Loc { repr } -> M.int_of_loc c_int repr
+  (** Cast a memory location into its absolute memory address,
+      given as an integer with the given C-type. *)
+
+  let is_null = function
+    | Bornat.Null -> p_true
+    | Bornat.Raw { repr } | Bornat.Loc { repr } -> M.is_null repr
+  (** Return the formula that check if a given location is null *)
+
+  let get_repr = function
+    | Bornat.Null -> M.null
+    | Bornat.Raw { repr } -> repr
+    | Bornat.Loc { repr } -> repr
+
+  let loc_eq loc_a loc_b = M.loc_eq (get_repr loc_a) (get_repr loc_b)
+  let loc_lt loc_a loc_b = M.loc_lt (get_repr loc_a) (get_repr loc_b)
+  let loc_neq loc_a loc_b =  M.loc_neq (get_repr loc_a) (get_repr loc_b)
+  let loc_leq loc_a loc_b =  M.loc_leq (get_repr loc_a) (get_repr loc_b)
+  (** Memory location comparisons *)
+
+  let loc_diff ty loc_a loc_b =  M.loc_diff ty (get_repr loc_a) (get_repr loc_b)
+  (** Compute the length in bytes between two memory locations *)
+
+  let get_rloc = function
+    | Rloc (ty, Bornat.Null) -> Rloc (ty, M.null)
+    | Rloc (ty, Bornat.Raw { repr }) -> Rloc (ty, repr)
+    | Rloc (ty, Bornat.Loc loc) ->
+      Rloc (ty, loc.repr)
+    | Rrange (Bornat.Null, ty, inf, sup) ->
+      Rrange (M.null, ty, inf, sup)
+    | Rrange (Bornat.Raw { repr }, ty, inf, sup) ->
+      Rrange (repr, ty, inf, sup)
+    | Rrange (Bornat.Loc loc, ty, inf, sup) ->
+      Rrange (loc.repr, ty, inf, sup)
+
+
+  let get_rloc_region = function
+    | Rloc (ty, loc) ->
+      Rloc (ty, (match loc with Bornat.Null -> M.null
+                              | Bornat.Raw { repr } | Bornat.Loc { repr } -> repr)),
+      (match loc with Bornat.Null | Bornat.Raw _ -> None
+                    | Bornat.Loc { region } -> Some region)
+    | Rrange (loc, ty, inf, sup) ->
+      Rrange ((match loc with Bornat.Null -> M.null
+                            | Bornat.Raw { repr } | Bornat.Loc { repr } -> repr), ty, inf, sup),
+      (match loc with Bornat.Null | Bornat.Raw _ -> None
+                    | Bornat.Loc { region } -> Some region)
+
+
+  let valid sigma acs (rloc : loc rloc) =
+    M.valid sigma.Tuple.model acs @@ get_rloc rloc
+  (** Return the formula that tests if a memory state is valid
+      (according to {!acs}) in the given memory state at the given
+      segment.
+  *)
+
+  let frame sigma =
+    let bornat_frame sigma = function
+      | B.CInit region ->
+        MemMemory.cinits @@ Sigma.value sigma @@ Chunk.CBornat (B.CInit region)
+      | B.CVal region | B.CGhost region ->  match R.kind region with
+        | R.Many R.Ptr | R.Single R.Ptr ->
+          MemMemory.framed @@ Sigma.value sigma @@ Chunk.CBornat (B.CVal region)
+        | R.Garbled | R.Many (R.Int _ | R.Float _)
+        | R.Single (R.Int _ | R.Float _) -> p_true
+    in
+    BSigma.Chunk.Set.fold (fun c l -> bornat_frame sigma c :: l)
+      (BSigma.domain sigma.Tuple.bornat)
+    @@ M.frame sigma.Tuple.model
+  (** Assert the memory is a proper heap state preceeding the function
+      entry point. *)
+
+  let alloc sigma vars =
+    if vars = [] then sigma
+    else { sigma with Tuple.model = M.alloc sigma.Tuple.model vars }
+  (** Allocates new chunk for the validity of variables. *)
+
+  let invalid sigma rloc = M.invalid sigma.Tuple.model (get_rloc rloc)
+  (** Returns the formula that tests if the entire memory is invalid
+      for write access. *)
+
+  let scope sigma scope vars =
+    let m_sigma = { pre = sigma.pre.Tuple.model ; post = sigma.post.Tuple.model } in
+    M.scope m_sigma scope vars
+  (** Manage the scope of variables.  Returns the updated memory model
+      and hypotheses modeling the new validity-scope of the variables. *)
+
+  let global sigma p = M.global sigma.Tuple.model p
+  (** Given a pointer value [p], assumes this pointer [p] (when valid)
+      is allocated outside the function frame under analysis. This means
+      separated from the formals and locals of the function. *)
+
+  let included (rloc1 : segment) (rloc2 : segment) =
+    let (rl1, region1) = get_rloc_region rloc1 in
+    let (rl2, region2) = get_rloc_region rloc2 in
+    match region1, region2 with
+    | None, _ -> M.included rl1 rl2
+    | _, None -> p_false
+    | Some region1, Some region2 ->
+      if R.separated region1 region2 then p_false
+      else M.included rl1 rl2
+
+  let separated (rloc1 : segment) (rloc2 : segment) =
+    let (rl1, region1) = get_rloc_region rloc1 in
+    let (rl2, region2) = get_rloc_region rloc2 in
+    match region1, region2 with
+    | None, _ | _, None -> M.separated rl1 rl2
+    | Some region1, Some region2 ->
+      if R.separated region1 region2 then p_true
+      else M.separated rl1 rl2
+
+  let chunk_is_well_formed sigma chunk = match chunk with
+    | Chunk.CModel _ | Chunk.CBornat (B.CInit _)
+    | Chunk.CBornat (B.CGhost _) -> p_true
+    | Chunk.CBornat (B.CVal region) -> match R.kind region with
+      | R.Garbled -> p_true
+      | R.Many (R.Float _ | R.Ptr )
+      | R.Single (R.Float _ | R.Ptr ) -> p_true
+      | R.Many (R.Int cint) ->
+        let l = Lang.freshvar ~basename:"l" (Lang.t_addr()) in
+        let m = Sigma.value sigma chunk in
+        p_forall [l] (Cint.range cint (F.e_get m (e_var l)))
+      | R.Single (R.Int cint) ->
+        Cint.range cint @@ Sigma.value sigma chunk
+
+
+  let is_well_formed sigma =
+    p_and (M.is_well_formed sigma.Tuple.model)
+    @@ p_conj @@ Sigma.Chunk.Set.fold (fun c l -> chunk_is_well_formed sigma c :: l) (Sigma.domain sigma) []
+
+
+end
diff --git a/src/plugins/wp/Dispatcher.mli b/src/plugins/wp/MemBornat.mli
similarity index 53%
rename from src/plugins/wp/Dispatcher.mli
rename to src/plugins/wp/MemBornat.mli
index b06af86458c..828341de2e6 100644
--- a/src/plugins/wp/Dispatcher.mli
+++ b/src/plugins/wp/MemBornat.mli
@@ -20,43 +20,44 @@
 (*                                                                        *)
 (**************************************************************************)
 
-open Either
-open Lang.F
-open Ctypes
 open Cil_types
-open Interpreted_automata
+open Ctypes
+open Lang.F
 open Sigs
 
+(* -------------------------------------------------------------------------- *)
+(* --- Bornat Memory Model                                                --- *)
+(* -------------------------------------------------------------------------- *)
 
-val partition: ('a -> ('b, 'c) Either.t) -> 'a list -> 'a list * 'a list
-val split    : ('a, 'b) Either.t list -> 'a list * 'b list
-
-module type Dispatcher =
-sig
+module type ModelLoader = sig
+  include Sigs.Model
 
-  type loc_left
-  type loc_right
+  val sizeof : c_object -> term
+  val last : sigma -> c_object -> loc -> term
 
-  module ML : Sigs.Model with type loc = loc_left
-  module MR : Sigs.Model with type loc = loc_right
+  val frames : c_object -> loc -> chunk -> frame list
 
-  type loc = (loc_left, loc_right) t
+  val havoc : c_object -> loc -> length:term -> chunk -> fresh:term -> current:term -> term
 
-  val null : loc
-  val is_null : loc -> pred
-  val cvar : varinfo -> loc
-  val pointer_loc : QED.term -> loc
-  val loc_of_int : c_object -> QED.term -> loc
+  val eqmem_forall : c_object -> loc -> chunk -> term -> term -> var list * pred * pred
 
-  val deref_left  : loc_left  -> loc_left  -> loc
-  val deref_right : loc_right -> loc_right -> loc
-  val literal : eid:int -> Cstring.cst -> loc
+  val load_int : sigma -> c_int -> loc -> term
+  val load_float : sigma -> c_float -> loc -> term
+  val load_pointer : sigma -> typ -> loc -> loc
 
+  val store_int : sigma -> c_int -> loc -> term -> Chunk.t * term
+  val store_float : sigma -> c_float -> loc -> term -> Chunk.t * term
+  val store_pointer : sigma -> typ -> loc -> term -> Chunk.t * term
 
-  (* utilities *)
-  val hypotheses : MemoryContext.partition -> MemoryContext.partition
-  val configure_ia: automaton -> vertex binder
+  val set_init_atom : sigma -> c_object -> loc -> term -> chunk * term
+  val set_init : c_object -> loc -> length:term -> chunk -> current:term -> term
+  val is_init_atom : sigma -> c_object -> loc -> term
+  val is_init_range : sigma -> c_object -> loc -> term -> pred
 
+  val value_footprint : c_object -> loc -> Sigma.domain
+  val init_footprint : c_object -> loc -> Sigma.domain
 end
 
-(* module Make (_: Sigs.Model) (_: Sigs.Model) : Dispatcher *)
+
+(* module Make (_:RegionAnalysis.API) (_:ModelLoader) : Sigs.Model *)
+module MemMake (_:RegionAnalysis.API) (_:ModelLoader) : Sigs.Model
diff --git a/src/plugins/wp/MemBytes.ml b/src/plugins/wp/MemBytes.ml
index b3d3dad054f..dc0f62a17c8 100644
--- a/src/plugins/wp/MemBytes.ml
+++ b/src/plugins/wp/MemBytes.ml
@@ -1130,3 +1130,17 @@ let scope seq scope xs =
            in e_set m (BASE.get x) size)
         (Sigma.value seq.pre Alloc) xs in
     [ p_equal (Sigma.value seq.post Alloc) alloc ]
+
+(* ********************************************************************** *)
+(* API with BORNAT                                                        *)
+(* ********************************************************************** *)
+
+let sizeof = protected_sizeof_object
+let last = Model.last
+let frames = Model.frames
+let eqmem_forall = Model.eqmem_forall
+let set_init = Model.set_init
+let is_init_range = Model.is_init_range
+let value_footprint = Model.value_footprint
+let init_footprint = Model.init_footprint
+let havoc = Model.havoc
diff --git a/src/plugins/wp/MemDispatch.ml b/src/plugins/wp/MemDispatch.ml
deleted file mode 100644
index 0784fd8ab6e..00000000000
--- a/src/plugins/wp/MemDispatch.ml
+++ /dev/null
@@ -1,715 +0,0 @@
-(**************************************************************************)
-(*                                                                        *)
-(*  This file is part of WP plug-in of Frama-C.                           *)
-(*                                                                        *)
-(*  Copyright (C) 2007-2024                                               *)
-(*    CEA (Commissariat a l'energie atomique et aux energies              *)
-(*         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).            *)
-(*                                                                        *)
-(**************************************************************************)
-
-(* -------------------------------------------------------------------------- *)
-(* --- Empty Memory Model                                                 --- *)
-(* -------------------------------------------------------------------------- *)
-
-open Either
-open Product
-open Lang.F
-open Sigs
-open Vset
-open Dispatcher
-
-
-module Make(D: Dispatcher) : Sigs.Model =
-struct
-  module ML = D.ML
-  module MR = D.MR
-
-  type loc = D.loc
-
-  let datatype = "MemDispatch.Make"
-  (** For projectification. Must be unique among models. *)
-
-  let configure () =
-    begin
-      let rollback () =
-        ML.configure () () ;
-        MR.configure () () ;
-      in
-      rollback
-    end
-  (** Initializers to be run before using the model.
-      Typically push {i Context} values and returns a function to rollback.
-  *)
-
-  let configure_ia ia =
-    D.configure_ia ia
-  (** Given an automaton, return a vertex's binder.
-      Currently used by the automata compiler to bind current vertex.
-
-  *)
-
-  let hypotheses p =
-    D.hypotheses p
-  (** Computes the memory model partitionning of the memory locations.
-      This function typically adds new elements to the partition received
-      in input (that can be empty).
-      ============================> TODO <======================================
-  *)
-
-  module Chunk : Chunk
-    with type t = (ML.chunk, MR.chunk) Either.t =
-  struct
-    type t = (ML.chunk, MR.chunk) Either.t
-
-    let self = "MemDispatcher.Chunk"
-    (** Chunk names, for pretty-printing. *)
-
-    let hash = function
-      | Left  cl -> ML.Chunk.hash cl
-      | Right cr -> 0x1000 + MR.Chunk.hash cr
-
-    let equal ca cb =
-      match ca, cb with
-      | Left  c1, Left  c2 -> ML.Chunk.equal c1 c2
-      | Right c1, Right c2 -> MR.Chunk.equal c1 c2
-      | _, _ -> false
-
-    let compare c1 c2 = (hash c1) - (hash c2)
-
-    let pretty fmt = function
-      | Left  cl -> Format.fprintf fmt "ML.%a" ML.Chunk.pretty cl
-      | Right cr -> Format.fprintf fmt "MR.%a" MR.Chunk.pretty cr
-
-
-    let tau_of_chunk = function
-      | Left  c1 -> ML.Chunk.tau_of_chunk c1
-      | Right c2 -> MR.Chunk.tau_of_chunk c2
-
-    let basename_of_chunk = function
-      | Left  c1 -> String.concat "." [ "ML" ; ML.Chunk.basename_of_chunk c1 ]
-      | Right c2 -> String.concat "." [ "MR" ; MR.Chunk.basename_of_chunk c2 ]
-    (** Used when generating fresh variables for a chunk. *)
-
-    let is_framed = function
-      | Left  c1 -> ML.Chunk.is_framed c1
-      | Right c2 -> MR.Chunk.is_framed c2
-      (** Whether the chunk is local to a function call.
-
-          Means the chunk is separated from anyother call side-effects.
-          If [true], entails that a function assigning everything can not modify
-          the chunk. Only used for optimisation, it would be safe to always
-          return [false]. *)
-  end
-  (** Memory Chunks.
-
-      The concrete memory is partionned into a vector of abstract data.
-      Each component of the partition is called a {i memory chunk} and
-      holds an abstract representation of some part of the memory.
-
-      Remark: memory chunks are not required to be independant from each other,
-      provided the memory model implementation is consistent with the chosen
-      representation. Conversely, a given object might be represented by
-      several memory chunks.
-
-  *)
-
-  (* Chunks Sets and Maps. *)
-
-  module Heap : Qed.Collection.S
-    with type t = (ML.chunk, MR.chunk) t
-    = Qed.Collection.Make(Chunk)
-
-  type sigma = (ML.Sigma.t, MR.Sigma.t) product
-
-  module Sigma =
-  struct
-
-    type chunk = (ML.chunk, MR.chunk) Either.t
-
-    module Chunk = Heap
-
-    type domain = Chunk.set
-    type dom = (ML.Sigma.domain, MR.Sigma.domain) product
-
-    let of_domain (domain:domain) : dom =
-      let ldomain = Heap.Set.elements domain in
-      let (left,right) = split ldomain in
-      let left = ML.Sigma.Chunk.Set.of_list left in
-      let right = MR.Sigma.Chunk.Set.of_list right in
-      { left ; right }
-
-    let to_domain (dom:dom) : domain =
-      let left  = ML.Heap.Set.elements dom.left  in
-      let right = MR.Heap.Set.elements dom.right in
-      let left  = Heap.Set.of_list (List.map (fun l -> Left l)  left)  in
-      let right = Heap.Set.of_list (List.map (fun r -> Right r) right) in
-      Heap.Set.union left right
-
-    type t = sigma
-
-    let create () = {
-      left  = ML.Sigma.create () ;
-      right = MR.Sigma.create () ;
-    }
-
-    let pretty fmt sigma =
-      Format.fprintf fmt "@[{@[%a@];@[%a@]}@]" ML.Sigma.pretty sigma.left MR.Sigma.pretty sigma.right
-
-    let empty : domain = Heap.Set.empty
-
-    let mem sigma = function
-      | Left  cl -> ML.Sigma.mem sigma.left  cl
-      | Right cr -> MR.Sigma.mem sigma.right cr
-
-    let get sigma = function
-      | Left  cl -> ML.Sigma.get sigma.left  cl
-      | Right cr -> MR.Sigma.get sigma.right cr
-
-    let writes (seq:sigma sequence) =
-      to_domain {
-        left  = ML.Sigma.writes (Product.sequence_left  seq) ;
-        right = MR.Sigma.writes (Product.sequence_right seq) ;
-      }
-
-    let value sigma = function
-      | Left  cl -> ML.Sigma.value sigma.left  cl
-      | Right cr -> MR.Sigma.value sigma.right cr
-
-    let copy = Product.map2 ML.Sigma.copy MR.Sigma.copy
-
-    let join sigma1 sigma2 =
-      Passive.union
-        (ML.Sigma.join sigma1.left  sigma2.left )
-        (MR.Sigma.join sigma1.right sigma2.right)
-
-    let assigned ~pre:s1 ~post:s2 domain =
-      let dom = of_domain domain in
-      let bag_left  = ML.Sigma.assigned ~pre:s1.left  ~post:s2.left  dom.left  in
-      let bag_right = MR.Sigma.assigned ~pre:s1.right ~post:s2.right dom.right in
-      Bag.concat bag_left bag_right
-
-
-    let choose = Product.map22 ML.Sigma.choose MR.Sigma.choose
-
-    let merge s1 s2 =
-      let (sl, pl1, pl2) = ML.Sigma.merge s1.left  s2.left  in
-      let (sr, pr1, pr2) = MR.Sigma.merge s1.right s2.right in
-      let s = { left = sl ; right = sr } in
-      (s, Passive.union pl1 pr1, Passive.union pl2 pr2)
-
-    let merge_list ls = (* TOCHECK *)
-      let f (s1,lp) s2 =
-        let (s,p1,p2) = merge s1 s2 in
-        (s, p1::p2::lp)
-      in
-      match ls with
-      | [] -> (create (), [])
-      | [ s ] -> (s, [ Passive.empty ])
-      | _ -> List.fold_left f (create (), []) ls
-
-    let iter f sigma =
-      ML.Sigma.iter (fun l -> f (Left  l)) sigma.left  ;
-      MR.Sigma.iter (fun r -> f (Right r)) sigma.right ;
-      ()
-
-    let iter2 f =
-      let f_left c v1 v2 = f (Left c) v1 v2 in
-      let f_right c v1 v2 = f (Right c) v1 v2 in
-      Product.iter2 (ML.Sigma.iter2 f_left) (MR.Sigma.iter2 f_right)
-
-    let havoc_chunk = Product.map_either ML.Sigma.havoc_chunk MR.Sigma.havoc_chunk
-
-    let havoc sigma domain =
-      let dom = of_domain domain in
-      Product.map22 ML.Sigma.havoc MR.Sigma.havoc sigma dom
-
-    let havoc_any ~call:call = Product.map2 (ML.Sigma.havoc_any ~call) (MR.Sigma.havoc_any ~call)
-
-    let remove_chunks sigma domain =
-      let dom = of_domain domain in
-      Product.map22 ML.Sigma.remove_chunks MR.Sigma.remove_chunks sigma dom
-
-    let dom = Product.map2 ML.Sigma.domain MR.Sigma.domain
-
-    let domain sigma =
-      let dom = dom sigma in
-      let domain = List.append
-          (List.map (fun l -> Left  l) (ML.Heap.Set.elements dom.left ))
-          (List.map (fun r -> Right r) (MR.Heap.Set.elements dom.right))
-      in
-      Chunk.Set.of_list domain
-
-    let union = Chunk.Set.union
-
-  end
-
-  type chunk = Chunk.t
-  type domain = Sigma.domain
-  type segment = loc rloc
-
-  type state = (ML.state, MR.state) product
-  (** Internal (private) memory state description for later reversing the model. *)
-
-  (** Returns a memory state description from a memory environement. *)
-  let state = Product.map2 ML.state MR.state
-
-  (** Try to interpret a term as an in-memory operation
-      located at this program point. Only best-effort
-      shall be performed, otherwise return [Mvalue].
-
-      Recognized [Cil] patterns:
-      - [Mvar x,[Mindex 0]] is rendered as [*x] when [x] has a pointer type
-      - [Mmem p,[Mfield f;...]] is rendered as [p->f...] like in Cil
-      - [Mmem p,[Mindex k;...]] is rendered as [p[k]...] to catch Cil [Mem(AddPI(p,k)),...] *)
-  let lookup state term =
-    try ML.lookup state.left term with
-    | Not_found -> MR.lookup state.right term
-
-  (** Try to interpret a sequence of states into updates.
-
-      The result shall be exhaustive with respect to values that are printed as [Sigs.mval]
-      values at [post] label {i via} the [lookup] function.
-      Otherwise, those values would not be pretty-printed to the user. *)
-  let updates states var =
-    let bag_left  = ML.updates (Product.sequence_left  states) var in
-    let bag_right = MR.updates (Product.sequence_right states) var in
-    Bag.concat bag_left bag_right
-
-
-  (** Propagate a sequent substitution inside the memory state. *)
-  let apply f = Product.map2  (ML.apply f) (MR.apply f)
-
-
-  (** Debug *)
-  let iter f state = Product.iter (ML.iter f) (MR.iter f) state
-
-  let pretty fmt loc = match loc with
-    | Left  ll -> Format.fprintf fmt "ML.%a" ML.pretty ll
-    | Right lr -> Format.fprintf fmt "MR.%a" MR.pretty lr
-  (** pretty printing of memory location *)
-
-
-  (** {2 Memory Model API} *)
-
-  let vars = function
-    | Left  ll -> ML.vars ll
-    | Right lr -> MR.vars lr
-
-  (** Return the logic variables from which the given location depend on. *)
-
-  let occurs var = function
-    | Left  ll -> ML.occurs var ll
-    | Right lr -> MR.occurs var lr
-  (** Test if a location depend on a given logic variable *)
-
-  let null = D.null
-  (** Return the location of the null pointer *)
-
-  let literal ~eid:eid name = D.literal ~eid name
-  (** Return the memory location of a constant string,
-      the id is a unique identifier. *)
-
-  let cvar var = D.cvar var
-  (** Return the location of a C variable. *)
-
-  let pointer_loc term = D.pointer_loc term
-  (** Interpret an address value (a pointer) as an abstract location.
-      Might fail on memory models not supporting pointers. *)
-
-  let pointer_val = function
-    | Left  ll -> ML.pointer_val ll
-    | Right lr -> MR.pointer_val lr
-  (** Return the adress value (a pointer) of an abstract location.
-      Might fail on memory models not capable of representing pointers. *)
-
-  let field loc fieldinfo =
-    let left  = fun l -> ML.field l fieldinfo in
-    let right = fun r -> MR.field r fieldinfo in
-    Either.map ~left ~right loc
-  (** Return the memory location obtained by field access from a given
-      memory location. *)
-
-  let shift loc ty term = match loc with
-    | Left  l -> D.deref_left  l (ML.shift l ty term)
-    | Right r -> D.deref_right r (MR.shift r ty term)
-  (** Return the memory location obtained by array access at an index
-      represented by the given {!term}. The element of the array are of
-      the given {!c_object} type. *)
-
-  let base_addr = Either.map ~left:ML.base_addr ~right:MR.base_addr
-  (** Return the memory location of the base address of a given memory
-      location. *)
-
-  let base_offset = function
-    | Left  ll -> ML.base_offset ll
-    | Right lr -> MR.base_offset lr
-  (** Return the offset of the location, in bytes, from its base_addr. *)
-
-  let block_length (sigma:sigma) ty = function
-    | Left  ll -> ML.block_length sigma.left  ty ll
-    | Right lr -> MR.block_length sigma.right ty lr
-  (**  Returns the length (in bytes) of the allocated block containing
-       the given location. *)
-
-  let cast objs = Either.map ~left:(ML.cast objs) ~right:(MR.cast objs)
-
-  (** Cast a memory location into another memory location.
-      For [cast ty loc] the cast is done from [ty.pre] to [ty.post].
-      Might fail on memory models not supporting pointer casts. *)
-
-  let loc_of_int ty term = D.loc_of_int ty term
-  (** Cast a term representing an absolute memory address (to some c_object)
-      given as an integer, into an abstract memory location. The sigma parameter
-      is meant to assure that the cast returns a pointer only if in this given
-      sigma, the physical address makes sense.
-
-      @before Frama-C+dev there was no sigma parameter
-  *)
-
-  let int_of_loc c_int = function
-    | Left  ll -> ML.int_of_loc c_int ll
-    | Right lr -> MR.int_of_loc c_int lr
-  (** Cast a memory location into its absolute memory address,
-      given as an integer with the given C-type. *)
-
-  let domain ty = function
-    | Left  ll -> Heap.Set.of_list (List.map (fun l -> Left l)  (ML.Heap.Set.elements (ML.domain ty ll)))
-    | Right lr -> Heap.Set.of_list (List.map (fun r -> Right r) (MR.Heap.Set.elements (MR.domain ty lr)))
-  (** Compute the set of chunks that hold the value of an object with
-      the given C-type. It is safe to retun an over-approximation of the
-      chunks involved. *)
-
-  let is_well_formed sigma =
-    p_and (ML.is_well_formed sigma.left) (MR.is_well_formed sigma.right)
-  (** Provides the constraint corresponding to the kind of data stored by all
-      chunks in sigma. *)
-
-  let load sigma ty = function
-    | Left  ll1 -> begin match ML.load sigma.left  ty ll1 with
-        | Val t   -> Val t
-        | Loc ll2 -> Loc (D.deref_left  ll1 ll2)
-      end
-    | Right lr1 -> begin match MR.load sigma.right ty lr1 with
-        | Val t   -> Val t
-        | Loc lr2 -> Loc (D.deref_right lr1 lr2)
-      end
-  (** Return the value of the object of the given type at the given location in
-      the given memory state. *)
-
-  let load_init sigma ty = function
-    | Left  ll -> ML.load_init sigma.left  ty ll
-    | Right lr -> MR.load_init sigma.right ty lr
-  (** Return the initialization status at the given location in the given
-      memory state. *)
-
-  let stored sigmas ty loc term = match loc with
-    | Left  ll -> ML.stored (Product.sequence_left  sigmas) ty ll term
-    | Right lr -> MR.stored (Product.sequence_right sigmas) ty lr term
-  (**
-     Return a set of formula that express a modification between two memory
-     state.
-
-     [stored sigma ty loc t] returns a set of formula expressing that
-     [sigma.pre] and [sigma.post] are identical except for an object [ty] at
-     location [loc] which is represented by [t] in [sigma.post].
-  *)
-
-  let stored_init sigmas ty loc term = match loc with
-    | Left  ll -> ML.stored_init (Product.sequence_left  sigmas) ty ll term
-    | Right lr -> MR.stored_init (Product.sequence_right sigmas) ty lr term
-  (**
-     Return a set of formula that express a modification of the initialization
-     status between two memory state.
-
-     [stored_init sigma ty loc t] returns a set of formula expressing that
-     [sigma.pre] and [sigma.post] are identical except for an object [ty] at
-     location [loc] which has a new init represented by [t] in [sigma.post].
-  *)
-
-  let copied sigmas ty loc1 loc2 = (* TOCHECK *) match loc1, loc2 with
-    | Left  ll1, Left  ll2 ->
-      ML.copied (Product.sequence_left  sigmas) ty ll1 ll2
-    | Right lr1, Right lr2 ->
-      MR.copied (Product.sequence_right sigmas) ty lr1 lr2
-    | _,_ -> begin match load sigmas.pre ty loc1 with
-        | Val t   -> stored sigmas ty loc2 t
-        | Loc loc -> stored sigmas ty loc2 (pointer_val loc)
-      end
-  (**
-     Return a set of equations that express a copy between two memory state.
-
-     [copied sigma ty loc1 loc2] returns a set of formula expressing that the
-     content for an object [ty] is the same in [sigma.pre] at [loc1] and in
-     [sigma.post] at [loc2].
-  *)
-
-  let copied_init sigmas ty loc1 loc2 = (* TOCHECK *) match loc1, loc2 with
-    | Left  ll1, Left  ll2 ->
-      ML.copied_init (Product.sequence_left  sigmas) ty ll1 ll2
-    | Right lr1, Right lr2 ->
-      MR.copied_init (Product.sequence_right sigmas) ty lr1 lr2
-    | _,_ ->
-      stored_init sigmas ty loc2 (load_init sigmas.pre ty loc1)
-  (**
-     Return a set of equations that express a copy of an initialized state
-     between two memory state.
-
-     [copied sigma ty loc1 loc2] returns a set of formula expressing that the
-     initialization status for an object [ty] is the same in [sigma.pre] at
-     [loc1] and in [sigma.post] at [loc2].
-  *)
-
-  let assigned sigma ty divergent_locs =
-    match divergent_locs with
-    (* loc_left *)
-    | Sloc (Left ll) -> ML.assigned (Product.sequence_left sigma) ty (Sloc ll)
-    | Sarray (Left ll, ty, size) -> ML.assigned (Product.sequence_left sigma) ty (Sarray (ll,ty,size))
-    | Srange (Left ll, ty, inf, sup) -> ML.assigned (Product.sequence_left sigma) ty (Srange (ll, ty, inf, sup))
-    | Sdescr (vars, Left ll, p) -> ML.assigned (Product.sequence_left sigma) ty (Sdescr (vars, ll, p))
-    (* loc_right *)
-    | Sloc (Right lr) -> MR.assigned (Product.sequence_right sigma) ty (Sloc lr)
-    | Sarray (Right lr, ty, size) -> MR.assigned (Product.sequence_right sigma) ty (Sarray (lr,ty,size))
-    | Srange (Right lr, ty, inf, sup) -> MR.assigned (Product.sequence_right sigma) ty (Srange (lr, ty, inf, sup))
-    | Sdescr (vars, Right lr, p) -> MR.assigned (Product.sequence_right sigma) ty (Sdescr (vars, lr, p))
-  (**
-     Return a set of formula that express that two memory state are the same
-     except at the given set of memory location.
-
-     This function can over-approximate the set of given memory location (e.g
-     it can return [true] as if the all set of memory location was given).
-  *)
-
-  let is_null l = D.is_null l
-  (** Return the formula that check if a given location is null *)
-
-  let loc_eq loc_a loc_b = (* TODO: déléguer le cas croisé à D ==> plutôt mettre assert false *)
-    match loc_a, loc_b with
-    | Right _, Left _| Left _, Right _ -> p_and (is_null loc_a) (is_null loc_b)
-    | Left  la, Left  lb -> ML.loc_eq la lb
-    | Right la, Right lb -> MR.loc_eq la lb
-  let loc_lt loc_a loc_b = match loc_a, loc_b with
-    | Right _, Left _| Left _, Right _ -> assert false
-    | Left  la, Left  lb -> ML.loc_lt la lb
-    | Right la, Right lb -> MR.loc_lt la lb
-  let loc_neq loc_a loc_b = (* TODO: déléguer le cas croisé à D ==> plutôt mettre assert false *)
-    match loc_a, loc_b with
-    | Right _, Left _| Left _, Right _ -> p_or (p_not (is_null loc_a)) (p_not (is_null loc_b))
-    | Left  la, Left  lb -> ML.loc_neq la lb
-    | Right la, Right lb -> MR.loc_neq la lb
-  let loc_leq loc_a loc_b = match loc_a, loc_b with
-    | Right _, Left _| Left _, Right _ -> assert false
-    | Left  la, Left  lb -> ML.loc_leq la lb
-    | Right la, Right lb -> MR.loc_leq la lb
-  (** Memory location comparisons *)
-
-  let loc_diff ty loc_a loc_b = match loc_a, loc_b with
-    | Right _, Left _| Left _, Right _ -> assert false
-    | Left  la, Left  lb -> ML.loc_diff ty la lb
-    | Right la, Right lb -> MR.loc_diff ty la lb
-  (** Compute the length in bytes between two memory locations *)
-
-  let valid sigma acs = function
-    (* loc_left *)
-    | Rloc (ty, Left  ll) -> ML.valid sigma.left acs (Rloc (ty,ll))
-    | Rrange (Left  ll, ty, inf, sup) -> ML.valid sigma.left  acs (Rrange (ll, ty, inf, sup))
-    (* loc_right *)
-    | Rloc (ty, Right lr) -> MR.valid sigma.right acs (Rloc (ty,lr))
-    | Rrange (Right lr, ty, inf, sup) -> MR.valid sigma.right acs (Rrange (lr, ty, inf, sup))
-  (** Return the formula that tests if a memory state is valid
-      (according to {!acs}) in the given memory state at the given
-      segment.
-  *)
-
-  let frame sigma = List.append (ML.frame sigma.left) (MR.frame sigma.right)
-  (** Assert the memory is a proper heap state preceeding the function
-      entry point. *)
-
-  let alloc sigma vars =
-    let (varl, varr) = partition D.cvar vars in
-    Product.map2 (fun s -> ML.alloc s varl) (fun s -> MR.alloc s varr) sigma
-  (** Allocates new chunk for the validity of variables. *)
-
-  let initialized sigma segment =
-    match segment with
-    (* loc_left *)
-    | Rloc (ty, Left ll) -> ML.initialized sigma.left (Rloc (ty,ll))
-    | Rrange (Left ll, ty, inf, sup) -> ML.initialized sigma.left (Rrange (ll, ty, inf, sup))
-    (* loc_right *)
-    | Rloc (ty, Right lr) -> MR.initialized sigma.right (Rloc (ty,lr))
-    | Rrange (Right lr, ty, inf, sup) -> MR.initialized sigma.right (Rrange (lr, ty, inf, sup))
-  (** Return the formula that tests if a memory state is initialized
-      (according to {!acs}) in the given memory state at the given
-      segment.
-  *)
-
-  let invalid sigma = function
-    (* loc_left *)
-    | Rloc (ty, Left  l) -> ML.invalid sigma.left  (Rloc (ty,l))
-    | Rrange (Left  l, ty, inf, sup) -> ML.invalid sigma.left  (Rrange (l, ty, inf, sup))
-    (* loc_right *)
-    | Rloc (ty, Right l) -> MR.invalid sigma.right (Rloc (ty,l))
-    | Rrange (Right l, ty, inf, sup) -> MR.invalid sigma.right (Rrange (l, ty, inf, sup))
-
-  (** Returns the formula that tests if the entire memory is invalid
-      for write access. *)
-
-  let scope sigma scope vars =
-    let (varl, varr) = partition D.cvar vars in
-    List.append
-      (ML.scope (Product.sequence_left  sigma) scope varl)
-      (MR.scope (Product.sequence_right sigma) scope varr)
-  (** Manage the scope of variables.  Returns the updated memory model
-      and hypotheses modeling the new validity-scope of the variables. *)
-
-  let global sigma p =
-    p_and (ML.global sigma.left p) (MR.global sigma.right p)
-  (** Given a pointer value [p], assumes this pointer [p] (when valid)
-      is allocated outside the function frame under analysis. This means
-      separated from the formals and locals of the function. *)
-
-  let included s1 s2 = (* TODO: dans la construction des range, multiplier la taille de tau1 ou tau2 (ici o1 ou o2) *) match s1, s2 with
-    (* loc_left x2 *)
-    | Rloc (ty1, Left ll1), Rloc (ty2, Left ll2) ->
-      ML.included (Rloc (ty1, ll1)) (Rloc (ty2, ll2))
-    | Rloc (ty1, Left ll1), Rrange (Left ll2, ty2, inf, sup) ->
-      ML.included (Rloc (ty1,ll1)) (Rrange (ll2,ty2,inf,sup))
-    | Rrange (Left ll1, ty1, inf, sup), Rloc (ty2, Left ll2) ->
-      ML.included (Rrange (ll1,ty1,inf,sup)) (Rloc (ty2,ll2))
-    | Rrange (Left ll1, ty1, inf1, sup1), Rrange (Left ll2, ty2, inf2, sup2) ->
-      ML.included (Rrange (ll1,ty1,inf1,sup1)) (Rrange (ll2,ty2,inf2,sup2))
-    (* loc_right x2 *)
-    | Rloc (ty1, Right lr1), Rloc (ty2, Right lr2) ->
-      MR.included (Rloc (ty1, lr1)) (Rloc (ty2, lr2))
-    | Rloc (ty1, Right lr1), Rrange (Right lr2, ty2, inf, sup) ->
-      MR.included (Rloc (ty1,lr1)) (Rrange (lr2,ty2,inf,sup))
-    | Rrange (Right ll1, ty1, inf, sup), Rloc (ty2, Right ll2) ->
-      MR.included (Rrange (ll1,ty1,inf,sup)) (Rloc (ty2,ll2))
-    | Rrange (Right lr1, ty1, inf1, sup1), Rrange (Right lr2, ty2, inf2, sup2) ->
-      MR.included (Rrange (lr1,ty1,inf1,sup1)) (Rrange (lr2,ty2,inf2,sup2))
-    (* Cross case: Rloc x Rloc *)
-    | Rloc (tyl, Left  ll), Rloc (tyr, Right lr) ->
-      p_and (ML.is_null ll) (MR.included (Rloc (tyl, MR.null)) (Rloc (tyr, lr)))
-    | Rloc (tyr, Right lr), Rloc (tyl, Left  ll) ->
-      p_and (MR.is_null lr) (ML.included (Rloc (tyr, ML.null)) (Rloc (tyl, ll)))
-    (* Cross case: Rloc x Rrange *)
-    | Rloc (tyl, Left  ll), Rrange (Right lr, tyr, infr, supr) ->
-      p_and (ML.is_null ll) (MR.included (Rloc (tyl, MR.null)) (Rrange (lr, tyr, infr, supr)))
-    | Rloc (tyr, Right lr), Rrange (Left  ll, tyl, infl, supl) ->
-      p_and (MR.is_null lr) (ML.included (Rloc (tyr, ML.null)) (Rrange (ll, tyl, infl, supl)))
-    (* Cross case: Rrange x Rloc *)
-    | Rrange (Right lr, tyr, infr, supr), Rloc (tyl, Left  ll) ->
-      let r_range : set = [ Range (infr, supr) ] in
-      p_or (Vset.is_empty r_range) (
-        p_and
-          (ML.is_null (ML.base_addr ll))
-          (MR.included (Rrange (lr, tyr, infr, supr)) (Rloc (tyl, MR.null)))
-      )
-    | Rrange (Left  ll, tyl, infl, supl), Rloc (tyr, Right lr) ->
-      let l_range : set = [ Range (infl, supl) ] in
-      p_or (Vset.is_empty l_range) (
-        p_and
-          (MR.is_null (MR.base_addr lr))
-          (ML.included (Rrange (ll, tyl, infl, supl)) (Rloc (tyr, ML.null)))
-      )
-    (* Cross case: Rrange x Rrange *)
-    | Rrange (Right lr, _tyr, infr, supr), Rrange (Left  ll, _tyl, infl, supl) ->
-      let r_range : set = [ Range (infr, supr) ] in
-      let l_range : set = [ Range (infl, supl) ] in
-      (* TOCHECK: should we unify tyl and tyr ? *)
-      p_or (Vset.is_empty r_range) (
-        p_and (ML.is_null (ML.base_addr ll)) (
-          p_and (MR.is_null (MR.base_addr lr))
-            (subset r_range l_range)
-        ))
-    | Rrange (Left  ll, _tyl, infl, supl), Rrange (Right lr, _tyr, infr, supr) ->
-      let r_range : set = [ Range (infr, supr) ] in
-      let l_range : set = [ Range (infl, supl) ] in
-      (* TOCHECK: should we unify tyl and tyr ? *)
-      p_or (Vset.is_empty l_range) (
-        p_and (ML.is_null (ML.base_addr ll)) (
-          p_and (MR.is_null (MR.base_addr lr))
-            (subset l_range r_range)
-        ))
-  (* Rrange left + la..lb , Rrange right + ra..rb ->
-     construire des range avec Vset et faire les tests avec Vset
-     (is_empty la lb)
-     \/ (ML.is_null (base_addr l)
-        /\ MR.is_null (base_addr r)
-        /\ la..lb included in ra..rb)  *)
-  (* Rloc left ,  Rrange right + ra..rb
-     -> ML.is_null left /\ MR.is_null right /\ 0 \in ra..rb *)
-  (** Return the formula that tests if two segment are included *)
-
-  let separated s1 s2 = match s1, s2 with
-    (* loc_left x2 *)
-    | Rloc (ty1, Left ll1), Rloc (ty2, Left ll2) ->
-      ML.separated (Rloc (ty1, ll1)) (Rloc (ty2, ll2))
-    | Rloc (ty1, Left ll1), Rrange (Left ll2, ty2, inf, sup) ->
-      ML.separated (Rloc (ty1,ll1)) (Rrange (ll2,ty2,inf,sup))
-    | Rrange (Left ll2, ty2, inf, sup), Rloc (ty1, Left ll1) ->
-      ML.separated (Rrange (ll2,ty2,inf,sup)) (Rloc (ty1,ll1))
-    | Rrange (Left ll1, ty1, inf1, sup1), Rrange (Left ll2, ty2, inf2, sup2) ->
-      ML.separated (Rrange (ll1,ty1,inf1,sup1)) (Rrange (ll2,ty2,inf2,sup2))
-    (* loc_right x2 *)
-    | Rloc (ty1, Right lr1), Rloc (ty2, Right lr2) ->
-      MR.separated (Rloc (ty1, lr1)) (Rloc (ty2, lr2))
-    | Rloc (ty1, Right lr1), Rrange (Right lr2, ty2, inf, sup) ->
-      MR.separated (Rloc (ty1,lr1)) (Rrange (lr2,ty2,inf,sup))
-    | Rrange (Right lr2, ty2, inf, sup), Rloc (ty1, Right lr1) ->
-      MR.separated (Rrange (lr2,ty2,inf,sup)) (Rloc (ty1,lr1))
-    | Rrange (Right lr1, ty1, inf1, sup1), Rrange (Right lr2, ty2, inf2, sup2) ->
-      MR.separated (Rrange (lr1,ty1,inf1,sup1)) (Rrange (lr2,ty2,inf2,sup2))
-    (* Cross case: Rloc x Rloc *)
-    | Rloc (tyl, Left  ll), Rloc (tyr, Right lr) ->
-      p_imply (ML.is_null ll) (MR.separated (Rloc (tyl, MR.null)) (Rloc (tyr, lr)))
-    | Rloc (tyr, Right lr), Rloc (tyl, Left  ll) ->
-      p_imply (MR.is_null lr) (ML.separated (Rloc (tyr, ML.null)) (Rloc (tyl, ll)))
-    (* Cross case: Rloc x Rrange *)
-    | Rloc (tyl, Left  ll), Rrange (Right lr, tyr, infr, supr) ->
-      p_imply (ML.is_null ll) (MR.separated (Rloc (tyl, MR.null)) (Rrange (lr, tyr, infr, supr)))
-    | Rloc (tyr, Right lr), Rrange (Left  ll, tyl, infl, supl) ->
-      p_imply (MR.is_null lr) (ML.separated (Rloc (tyr, ML.null)) (Rrange (ll, tyl, infl, supl)))
-    (* Cross case: Rrange x Rloc *)
-    | Rrange (Right lr, tyr, infr, supr), Rloc (tyl, Left  ll) ->
-      let r_range : set = [ Range (infr, supr) ] in
-      p_or (Vset.is_empty r_range) (
-        p_and (ML.is_null (ML.base_addr ll)) (MR.included (Rrange (lr, tyr, infr, supr)) (Rloc (tyl, MR.null)))
-      )
-    | Rrange (Left  ll, tyl, infl, supl), Rloc (tyr, Right lr) ->
-      let l_range : set = [ Range (infl, supl) ] in
-      p_or (Vset.is_empty l_range) (
-        p_and (MR.is_null (MR.base_addr lr)) (ML.included (Rrange (ll, tyl, infl, supl)) (Rloc (tyr, ML.null)))
-      )
-    (* Cross case: Rrange x Rrange *)
-    | Rrange (Right lr, _tyr, infr, supr), Rrange (Left  ll, _tyl, infl, supl) ->
-      let r_range : set = [ Range (infr, supr) ] in
-      let l_range : set = [ Range (infl, supl) ] in
-      (* TOCHECK: should we unify tyl and tyr ? *)
-      p_or (Vset.is_empty r_range) (
-        p_and (ML.is_null (ML.base_addr ll)) (
-          p_and (MR.is_null (MR.base_addr lr)) (subset r_range l_range)
-        ))
-    | Rrange (Left  ll, _tyl, infl, supl), Rrange (Right lr, _tyr, infr, supr) ->
-      let r_range : set = [ Range (infr, supr) ] in
-      let l_range : set = [ Range (infl, supl) ] in
-      (* TOCHECK: should we unify tyl and tyr ? *)
-      p_or (Vset.is_empty l_range) (
-        p_and (ML.is_null (ML.base_addr ll)) (
-          p_and (MR.is_null (MR.base_addr lr)) (subset l_range r_range)
-        ))
-      (** Return the formula that tests if two segment are separated *)
-
-end
diff --git a/src/plugins/wp/MemLoader.mli b/src/plugins/wp/MemLoader.mli
index 46d62359db3..6c9818e7da5 100644
--- a/src/plugins/wp/MemLoader.mli
+++ b/src/plugins/wp/MemLoader.mli
@@ -54,8 +54,10 @@ sig
 
   val value_footprint: c_object -> loc -> Sigma.domain
   val init_footprint: c_object -> loc -> Sigma.domain
+  (* toutes les fils qui ne sont pas des points_to *)
 
   val frames : c_object -> loc -> Chunk.t -> frame list
+  (* memBytes *)
 
   val last : Sigma.t -> c_object -> loc -> term
 
diff --git a/src/plugins/wp/MemTyped.ml b/src/plugins/wp/MemTyped.ml
index 473a678b004..661422e6d96 100644
--- a/src/plugins/wp/MemTyped.ml
+++ b/src/plugins/wp/MemTyped.ml
@@ -1265,3 +1265,19 @@ let updates seq domain =
   !pool
 
 (* -------------------------------------------------------------------------- *)
+
+let sizeof = MODEL.sizeof
+let last = MODEL.last
+let havoc = MODEL.havoc
+let sizeof_havoc _ _ = F.e_one
+let eqmem_forall = MODEL.eqmem_forall
+let load_int = MODEL.load_int
+let load_float = MODEL.load_float
+let load_pointer = MODEL.load_pointer
+let store_int = MODEL.store_int
+let store_float = MODEL.store_float
+let store_pointer = MODEL.store_pointer
+let set_init_atom = MODEL.set_init_atom
+let set_init = MODEL.set_init
+let is_init_atom = MODEL.is_init_atom
+let is_init_range = MODEL.is_init_range
diff --git a/src/plugins/wp/MemTyped.mli b/src/plugins/wp/MemTyped.mli
index ccdbfbd0b97..fe4a3929d5f 100644
--- a/src/plugins/wp/MemTyped.mli
+++ b/src/plugins/wp/MemTyped.mli
@@ -20,6 +20,11 @@
 (*                                                                        *)
 (**************************************************************************)
 
+open Cil_types
+open Ctypes
+open Lang.F
+open Sigs
+
 (* -------------------------------------------------------------------------- *)
 (* --- Typed Memory Model                                                 --- *)
 (* -------------------------------------------------------------------------- *)
@@ -28,3 +33,30 @@ include Sigs.Model
 
 type pointer = NoCast | Fits | Unsafe
 val pointer : pointer Context.value
+
+
+val sizeof : c_object -> term
+val last : sigma -> c_object -> loc -> term
+
+val frames : c_object -> loc -> chunk -> frame list
+
+val havoc : c_object -> loc -> length:term -> chunk -> fresh:term -> current:term -> term
+val sizeof_havoc : c_object -> loc -> term
+
+val eqmem_forall : c_object -> loc -> chunk -> term -> term -> var list * pred * pred
+
+val load_int : sigma -> c_int -> loc -> term
+val load_float : sigma -> c_float -> loc -> term
+val load_pointer : sigma -> typ -> loc -> loc
+
+val store_int : sigma -> c_int -> loc -> term -> Chunk.t * term
+val store_float : sigma -> c_float -> loc -> term -> Chunk.t * term
+val store_pointer : sigma -> typ -> loc -> term -> Chunk.t * term
+
+val set_init_atom : sigma -> c_object -> loc -> term -> chunk * term
+val set_init : c_object -> loc -> length:term -> chunk -> current:term -> term
+val is_init_atom : sigma -> c_object -> loc -> term
+val is_init_range : sigma -> c_object -> loc -> term -> pred
+
+val value_footprint : c_object -> loc -> Sigma.domain
+val init_footprint : c_object -> loc -> Sigma.domain
diff --git a/src/plugins/wp/RegionAnalysis.ml b/src/plugins/wp/RegionAnalysis.ml
new file mode 100644
index 00000000000..7028c992e2b
--- /dev/null
+++ b/src/plugins/wp/RegionAnalysis.ml
@@ -0,0 +1,224 @@
+(**************************************************************************)
+(*                                                                        *)
+(*  This file is part of WP plug-in of Frama-C.                           *)
+(*                                                                        *)
+(*  Copyright (C) 2007-2024                                               *)
+(*    CEA (Commissariat a l'energie atomique et aux energies              *)
+(*         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).            *)
+(*                                                                        *)
+(**************************************************************************)
+
+open Cil_types
+open Ctypes
+open Lang.F
+
+
+(* -------------------------------------------------------------------------- *)
+(* --- Region Analysis API for Bornat Memory Model                        --- *)
+(* -------------------------------------------------------------------------- *)
+
+module type API = sig
+  type region
+  val null : unit -> region
+
+
+  val hash : region -> int
+  val equal : region -> region -> bool
+  val compare : region -> region -> int
+  val pretty : Format.formatter -> region -> unit
+
+  type primitive = | Int of c_int | Float of c_float | Ptr
+  type kind = Single of primitive | Many of primitive | Garbled
+  val kind : region -> kind
+  val pp_kind : Format.formatter -> kind -> unit
+
+  val tau_of_region : region -> tau
+  val points_to : region -> region option
+
+  val separated : region -> region -> bool
+  val included : region -> region -> bool
+
+  val cvar : varinfo -> region option
+  val field : region -> fieldinfo -> region option
+  val shift : region -> c_object -> term -> region option
+  val base_addr : region -> region
+
+  val literal : eid:int -> Cstring.cst -> region option
+  val pointer_loc : unit -> region option
+  val loc_of_int : unit -> region option
+
+  val id_of_region : region -> int
+  val region_of_id : int -> region option
+end
+
+
+(* -------------------------------------------------------------------------- *)
+(* --- Region Analysis for Bornat Memory Model                            --- *)
+(* -------------------------------------------------------------------------- *)
+
+module R (*: API*) =
+struct
+
+  type region = Region.node
+
+  let get_map () = match WpContext.get_scope () with
+    | WpContext.Kf f   -> Region.get_map f
+    | WpContext.Global -> Wp_parameters.not_yet_implemented "[WP/RegionAnalysis.ml] get_map: No global region analysis yet"
+
+  let null () : region =
+    Warning.emit ~severe:false ~source:"Region Memory Model"
+      ~effect:"Create null pointer value" "NULL" ;
+    Wp_parameters.not_yet_implemented "[WP/RegionAnalysis.ml] null: cannot create null region"
+
+
+  let id_of_region region = Region.get_uid (get_map ()) region
+
+  let region_of_id id =
+    try Some (Region.get_node (get_map ()) id)
+    with Not_found -> None
+
+  let hash = Region.get_id
+
+  let equal r1 r2 = (Region.get_id r1 = Region.get_id r2)
+
+  let compare r1 r2 = Int.compare (Region.get_id r1) (Region.get_id r2)
+
+  let pretty fmt r = Format.fprintf fmt "R%03d" @@ Region.get_id r
+
+  type primitive = | Int of c_int | Float of c_float | Ptr
+  type kind = Single of primitive | Many of primitive | Garbled
+
+  let pp_primitive fmt = function
+    | Int i -> Ctypes.pp_int fmt i
+    | Float f -> Ctypes.pp_float fmt f
+    | Ptr -> Format.pp_print_string fmt "void*"
+  let pp_kind fmt = function
+    | Many p -> Format.fprintf fmt "[%a]" pp_primitive p
+    | Single p -> pp_primitive fmt p
+    | Garbled -> Format.pp_print_string fmt "Garbled"
+
+  module CollectionCObject = Qed.Collection.Make(struct
+      type t      = Ctypes.c_object
+      let compare = Ctypes.compare
+      let hash    = Ctypes.hash
+      let equal   = Ctypes.equal
+    end)
+
+  module CObjects = CollectionCObject.Set
+
+  let types r =
+    let map = get_map () in
+    let add_type set ty = CObjects.add (Ctypes.object_of ty) set in
+    let types = CObjects.empty in
+    let types = List.fold_left add_type types @@ Region.reads map r in
+    let types = List.fold_left add_type types @@ Region.writes map r in
+    let types = List.fold_left add_type types @@ Region.shifts map r in
+    types
+
+  (** Internal handling of region kinds *)
+  module KindCompile = struct
+    (* Data : WpContext.Data with type key = Key.t *)
+    type key = region
+    type data = kind
+    let name = "WP.RegionAnalysis.R"
+    let compile region : kind = match CObjects.elements @@ types region with
+      | [] ->
+        Warning.emit ~severe:false ~source:"RegionAnalysis.KindCompile.compile"
+          ~effect:"Access type list is empty" "%a" pretty region ;
+        Garbled
+      | [ Ctypes.C_int cint ]     -> Many (Int cint)
+      | [ Ctypes.C_float cfloat ] -> Many (Float cfloat)
+      | [ Ctypes.C_pointer _ ]    -> Many Ptr
+      | [ Ctypes.C_comp _ ]       -> Garbled
+      | [ Ctypes.C_array _ ]      -> Garbled
+      | _ :: _ :: _               -> Garbled
+  end
+
+
+  (* Keeping track of the decision to apply which memory model to each region *)
+  module Kind = WpContext.Generator(struct
+      (* Key : WPContext.Key *)
+      type t = region
+      let compare = compare
+      let pretty = pretty
+    end)(KindCompile)
+
+  let kind = Kind.get
+
+
+  let tau_of_region region : tau = match CObjects.elements @@ types region with
+    | _ :: _ :: _ ->
+      Warning.emit ~severe:false ~source:"RegionAnalysis.tau_of_region"
+        ~effect:"Access type list is more than a singleton" "%a" pretty region ;
+      assert false
+    | [] ->
+      Warning.emit ~severe:false ~source:"RegionAnalysis.tau_of_region"
+        ~effect:"Access type list is empty" "%a" pretty region ;
+      assert false
+    | [ ty ] -> Lang.tau_of_object ty
+
+  let points_to region = Region.points_to (get_map ()) region
+
+  (*
+
+        if not (Layout.fits ~dst:s.post ~src:s.pre) then
+          Warning.emit ~severe:false ~source:"Region Memory Model"
+            ~effect:"Keep pointer value"
+            "%a" pp_mismatch s ; l
+
+
+  *)
+
+  let separated r1 r2 = Region.separated (get_map ()) r1 r2
+
+  let included r1 r2 = Region.included (get_map ()) r1 r2
+
+  let cvar var =
+    try Some (Region.cvar (get_map ()) var)
+    with Not_found ->
+      Warning.emit ~severe:false ~source:"RegionAnalysis.cvar"
+        ~effect:"No region found for C variable" "%a" Printer.pp_varinfo var ;
+      None
+
+  let field (region: region) (fd: fieldinfo) : region option =
+    try Some (Region.field (get_map ()) region fd)
+    with Not_found ->
+      Warning.emit ~severe:false
+        ~source:"RegionAnalysis.field"
+        ~effect:"No region found for field"
+        "No region for field %a from region %a"
+        Printer.pp_field fd pretty region;
+      None
+
+  let shift region ty offset =
+    let rec aux = function
+      | [] ->
+        Warning.emit ~severe:false
+          ~source:"RegionAnalysis.shift"
+          ~effect:"No region found"
+          "No region for shift %a from region %a"
+          QED.pretty offset pretty region;
+        None
+      | typ :: rest ->
+        try Some (Region.index (get_map ()) region typ)
+        with Not_found -> aux rest
+    in aux @@ Ctypes.object_to ty
+
+  let base_addr _ = assert false
+  let literal ~eid _ = ignore eid ; assert false
+  let pointer_loc () = assert false
+  let loc_of_int () = assert false
+
+end
diff --git a/src/plugins/wp/MemDispatch.mli b/src/plugins/wp/RegionAnalysis.mli
similarity index 61%
rename from src/plugins/wp/MemDispatch.mli
rename to src/plugins/wp/RegionAnalysis.mli
index d7915d23a39..057c8124af2 100644
--- a/src/plugins/wp/MemDispatch.mli
+++ b/src/plugins/wp/RegionAnalysis.mli
@@ -20,10 +20,46 @@
 (*                                                                        *)
 (**************************************************************************)
 
+open Cil_types
+open Ctypes
+open Lang.F
+
 (* -------------------------------------------------------------------------- *)
-(* --- Empty Memory Model                                                 --- *)
+(* --- Region Analysis API for Bornat Memory Model                        --- *)
 (* -------------------------------------------------------------------------- *)
 
-open Dispatcher
+module type API = sig
+  type region
+  val null : unit -> region
+
+
+  val hash : region -> int
+  val equal : region -> region -> bool
+  val compare : region -> region -> int
+  val pretty : Format.formatter -> region -> unit
+
+  type primitive = | Int of c_int | Float of c_float | Ptr
+  type kind = Single of primitive | Many of primitive | Garbled
+  val kind : region -> kind
+  val pp_kind : Format.formatter -> kind -> unit
+
+  val tau_of_region : region -> tau
+  val points_to : region -> region option
+
+  val separated : region -> region -> bool
+  val included : region -> region -> bool
+
+  val cvar : varinfo -> region option
+  val field : region -> fieldinfo -> region option
+  val shift : region -> c_object -> term -> region option
+  val base_addr : region -> region
+
+  val literal : eid:int -> Cstring.cst -> region option
+  val pointer_loc : unit -> region option
+  val loc_of_int : unit -> region option
+
+  val id_of_region : region -> int
+  val region_of_id : int -> region option
+end
 
-module Make(_: Dispatcher) : Sigs.Model
+module R : API
diff --git a/src/plugins/wp/ctypes.ml b/src/plugins/wp/ctypes.ml
index eba61ce0010..1ea4a065fff 100644
--- a/src/plugins/wp/ctypes.ml
+++ b/src/plugins/wp/ctypes.ml
@@ -315,6 +315,7 @@ let rec object_of typ =
     C_int (c_int IInt)
   | TNamed (r,_)  -> object_of r.ttype
 
+
 (* ------------------------------------------------------------------------ *)
 (* --- Comparable                                                       --- *)
 (* ------------------------------------------------------------------------ *)
@@ -384,10 +385,36 @@ let () =
     cmp := compare ;
   end
 
+(* -------------------------------------------------------------------------- *)
+(* --- Revert c_object to typ                                             --- *)
+(* -------------------------------------------------------------------------- *)
+
+let ikinds_of cint =
+  let all_ikind = [IBool;IChar;ISChar;IUChar;IInt;IUInt;IShort;IUShort;ILong;IULong;ILongLong;IULongLong] in
+  List.filter (fun ikind -> 0 == compare_c_int cint @@ c_int ikind) all_ikind
+
+let fkinds_of cfloat =
+  let all_fkind = [FFloat;FDouble;FLongDouble] in
+  List.filter (fun fkind -> 0 == compare_c_float cfloat @@ c_float fkind) all_fkind
+
+let object_to = function
+  | C_int cint as ty when equal ty (object_of (TVoid [])) -> (TVoid []) :: (List.map (fun ik -> TInt (ik,[])) @@ ikinds_of cint)
+  | C_int cint -> List.map (fun ik -> TInt (ik,[])) @@ ikinds_of cint
+  | C_float cfloat -> List.map (fun fk -> TFloat (fk,[])) @@ fkinds_of cfloat
+  | C_pointer (TVoid [] as typ) -> [ TBuiltin_va_list [] ; TPtr (typ,[]) ]
+  | C_pointer typ -> [ TPtr (typ,[]) ]
+  | C_comp comp -> [ TComp (comp,[]) ]
+  | C_array arr ->
+    match arr.arr_flat with
+    | None -> [ TArray (arr.arr_element, None, []) ]
+    | Some _e -> [ TArray (arr.arr_element, None (* Some (Cil.integer ~loc:Cil_builder.loc @@ Int64.of_int e) *), [])]
+
+
 (* -------------------------------------------------------------------------- *)
 (* --- Accessor Utilities                                                 --- *)
 (* -------------------------------------------------------------------------- *)
 
+
 let object_of_pointed = function
     C_int _ | C_float _ | C_comp _ as o ->
     Wp_parameters.fatal
diff --git a/src/plugins/wp/ctypes.mli b/src/plugins/wp/ctypes.mli
index f38d4d05826..96664cfbe06 100644
--- a/src/plugins/wp/ctypes.mli
+++ b/src/plugins/wp/ctypes.mli
@@ -98,6 +98,7 @@ val c_float  : fkind -> c_float
 (** Conforms to {!Machine.theMachine} *)
 
 val object_of : typ -> c_object
+val object_to : c_object -> typ list
 
 val is_pointer : c_object -> bool
 
diff --git a/src/plugins/wp/gui/GuiPanel.ml b/src/plugins/wp/gui/GuiPanel.ml
index 4b25d1880a9..50025d407fd 100644
--- a/src/plugins/wp/gui/GuiPanel.ml
+++ b/src/plugins/wp/gui/GuiPanel.ml
@@ -99,7 +99,7 @@ let run_and_prove
 (* ---  Model Panel                                                     --- *)
 (* ------------------------------------------------------------------------ *)
 
-type memory = TREE | HOARE | TYPED | EVA | BYTES
+type memory = TREE | HOARE | TYPED | EVA | BYTES | BORNAT
 
 class model_selector (main : Design.main_window_extension_points) =
   let dialog = new Wpane.dialog
@@ -152,6 +152,7 @@ class model_selector (main : Design.main_window_extension_points) =
          | Typed m -> memory#set TYPED ; c_casts#set (m = MemTyped.Unsafe)
          | Eva -> memory#set EVA
          | Bytes -> memory#set BYTES
+         | Bornat -> memory#set BORNAT
         ) ;
         c_byref#set (s.mvar = Ref) ;
         c_ctxt#set (s.mvar = Caveat) ;
@@ -167,6 +168,7 @@ class model_selector (main : Design.main_window_extension_points) =
                      (if c_casts#get then MemTyped.Unsafe else MemTyped.Fits)
         | EVA -> Eva
         | BYTES -> Bytes
+        | BORNAT -> Bornat
       in {
         mheap = m ;
         mvar = if c_ctxt#get then Caveat else if c_byref#get then Ref else Var ;
-- 
GitLab