From 6c45c7a3b66a35874ee4386445c0535888e76a81 Mon Sep 17 00:00:00 2001
From: Fonenantsoa Maurica <maurica.fonenantsoa@gmail.com>
Date: Fri, 5 Oct 2018 14:41:20 +0200
Subject: [PATCH] Memory instrumentation moved in Mmodel_translate.

---
 src/plugins/e-acsl/Makefile.in          |   1 +
 src/plugins/e-acsl/misc.ml              |   5 +
 src/plugins/e-acsl/misc.mli             |   4 +
 src/plugins/e-acsl/mmodel_translate.ml  | 359 ++++++++++++++++++++++++
 src/plugins/e-acsl/mmodel_translate.mli |  60 ++++
 src/plugins/e-acsl/translate.ml         | 356 ++---------------------
 6 files changed, 458 insertions(+), 327 deletions(-)
 create mode 100644 src/plugins/e-acsl/mmodel_translate.ml
 create mode 100644 src/plugins/e-acsl/mmodel_translate.mli

diff --git a/src/plugins/e-acsl/Makefile.in b/src/plugins/e-acsl/Makefile.in
index 13768e6bfbc..935abd3c882 100644
--- a/src/plugins/e-acsl/Makefile.in
+++ b/src/plugins/e-acsl/Makefile.in
@@ -78,6 +78,7 @@ PLUGIN_CMO:= local_config \
 	loops \
 	quantif \
 	at_with_lscope \
+	mmodel_translate \
 	translate \
 	temporal \
 	prepare_ast \
diff --git a/src/plugins/e-acsl/misc.ml b/src/plugins/e-acsl/misc.ml
index 89ff5794ca4..e4971d0f5b5 100644
--- a/src/plugins/e-acsl/misc.ml
+++ b/src/plugins/e-acsl/misc.ml
@@ -306,6 +306,11 @@ let term_has_lv_from_vi t =
 
 type pred_or_term = PoT_pred of predicate | PoT_term of term
 
+let mk_ptr_sizeof typ loc =
+  match Cil.unrollType typ with
+  | TPtr (t', _) -> Cil.new_exp ~loc (SizeOf t')
+  | _ -> assert false
+
 (*
 Local Variables:
 compile-command: "make"
diff --git a/src/plugins/e-acsl/misc.mli b/src/plugins/e-acsl/misc.mli
index 006fa6d4383..6c61e732290 100644
--- a/src/plugins/e-acsl/misc.mli
+++ b/src/plugins/e-acsl/misc.mli
@@ -120,6 +120,10 @@ val term_has_lv_from_vi: term -> bool
 
 type pred_or_term = PoT_pred of predicate | PoT_term of term
 
+val mk_ptr_sizeof: typ -> location -> exp
+(* [mk_ptr_sizeof ptr_typ loc] takes the pointer typ [ptr_typ] that points
+   to a [typ] typ and returns [sizeof(typ)]. *)
+
 (*
 Local Variables:
 compile-command: "make"
diff --git a/src/plugins/e-acsl/mmodel_translate.ml b/src/plugins/e-acsl/mmodel_translate.ml
new file mode 100644
index 00000000000..1172ffc3301
--- /dev/null
+++ b/src/plugins/e-acsl/mmodel_translate.ml
@@ -0,0 +1,359 @@
+(**************************************************************************)
+(*                                                                        *)
+(*  This file is part of Frama-C.                                         *)
+(*                                                                        *)
+(*  Copyright (C) 2007-2018                                               *)
+(*    CEA (Commissariat à l'énergie atomique et aux énergies              *)
+(*         alternatives)                                                  *)
+(*                                                                        *)
+(*  you can redistribute it and/or modify it under the terms of the GNU   *)
+(*  Lesser General Public License as published by the Free Software       *)
+(*  Foundation, version 2.1.                                              *)
+(*                                                                        *)
+(*  It is distributed in the hope that it will be useful,                 *)
+(*  but WITHOUT ANY WARRANTY; without even the implied warranty of        *)
+(*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *)
+(*  GNU Lesser General Public License for more details.                   *)
+(*                                                                        *)
+(*  See the GNU Lesser General Public License version 2.1                 *)
+(*  for more details (enclosed in the file licenses/LGPLv2.1).            *)
+(*                                                                        *)
+(**************************************************************************)
+
+open Cil_types
+
+(**************************************************************************)
+(********************** Forward references ********************************)
+(**************************************************************************)
+
+let predicate_to_exp_ref
+  : (kernel_function -> Env.t -> predicate -> exp * Env.t) ref
+  = Extlib.mk_fun "named_predicate_to_exp_ref"
+
+let term_to_exp_ref
+  : (kernel_function -> Env.t -> term -> exp * Env.t) ref
+  = Extlib.mk_fun "term_to_exp_ref"
+
+(*****************************************************************************)
+(****************************** Ranges Elimination ***************************)
+(*****************************************************************************)
+
+(* We call Range Elimination the operation through which ranges are
+  substituted by universally quantified logic variables.
+  Example:
+    [\valid(&t[(n-1)..(n+2)][1][0..1])] can be soundly transformed into
+    [\forall integer q1; n-1 <= q1 <= n+2 ==>
+      \forall integer q2; 0 <= q2 <= 1 ==>
+        \valid(&t[q1][1][q2])]
+  However, the substition can be unsound,
+  in which case [Range_elimination_exception] must be raised.
+  Example:
+    [\valid(&t[(0..2)==(0..2) ? 0 : 1])] is equivalent to [\valid(&t[0])]
+      since [==] refers to set equality when applied on ranges.
+    But Range Elimination will give a predicate equivalent to [\valid(&t[1])]
+      since [\forall 0 <= q1,q2 <= 2: q1==q2] is false.
+    Hence [Range_elimination_exception] must be raised. *)
+exception Range_elimination_exception
+
+(* Takes a [toffset] and checks whether it contains an index that is a set *)
+let rec has_set_as_index = function
+  | TNoOffset ->
+    false
+  | TIndex(t, toffset) ->
+    Logic_const.is_set_type t.term_type || has_set_as_index toffset
+  | TModel(_, toffset) | TField(_, toffset) ->
+    has_set_as_index toffset
+
+(* Performs Range Elimination on index [TIndex(term, offset)]. Term part.
+  Raises [Range_elimination_exception] if whether the operation is unsound or
+  if we don't support the construction yet. *)
+let eliminate_ranges_from_index_of_term ~loc t =
+  match t.term_node with
+  | Trange(Some n1, Some n2) ->
+    let name = Env.Varname.get ~scope:Env.Local_block "range" in
+    let lv = Cil_const.make_logic_var_kind name LVQuant Linteger in
+    let tlv = Logic_const.tvar ~loc lv in
+    tlv, (n1, lv, n2)
+  | _ ->
+    raise Range_elimination_exception
+
+(* Performs Range Elimination on index [TIndex(term, offset)]. Offset part.
+  Raises [Range_elimination_exception], through [eliminate_ranges_from_
+  index_of_term], if whether the operation is unsound or
+  if we don't support the construction yet. *)
+let rec eliminate_ranges_from_index_of_toffset ~loc toffset quantifiers =
+  match toffset with
+  | TIndex(t, toffset') ->
+    if Misc.is_range_free t then
+      let toffset', quantifiers' =
+        eliminate_ranges_from_index_of_toffset ~loc toffset' quantifiers
+      in
+      TIndex(t, toffset'), quantifiers'
+    else
+      (* Attempt Range Elimination on [t] *)
+      let t1, quantifiers1 =
+        eliminate_ranges_from_index_of_term ~loc t
+      in
+      let toffset2, quantifiers2 =
+        eliminate_ranges_from_index_of_toffset ~loc toffset' quantifiers
+      in
+      let toffset3 = TIndex(t1, toffset2) in
+      toffset3, quantifiers1 :: quantifiers2
+  | TNoOffset ->
+    toffset, quantifiers
+  | TModel _ ->
+    Error.not_yet "range elimination on TModel"
+  | TField _ ->
+    Error.not_yet "range elimination on TField"
+
+(*****************************************************************************)
+(********************** Calls without Range Elimination **********************)
+(************** \base_addr, \block_length, \offset, \freeable ****************)
+(*****************************************************************************)
+
+(* \base_addr, \block_length, \offset and \freeable *)
+let call ~loc kf name ctx env t =
+  assert (name = "base_addr" || name = "block_length"
+    || name = "offset" || name ="freeable");
+  let term_to_exp = !term_to_exp_ref in
+  let e, env = term_to_exp kf (Env.rte env true) t in
+  let _, res, env =
+    Env.new_var
+      ~loc
+      ~name
+      env
+      None
+      ctx
+      (fun v _ ->
+        let name = Functions.RTL.mk_api_name name in
+        [ Misc.mk_call ~loc ~result:(Cil.var v) name [ e ] ])
+  in
+  res, env
+
+(*****************************************************************************)
+(************************* Calls with Range Elimination **********************)
+(********************** \initialized, \valid, \valid_read ********************)
+(*****************************************************************************)
+
+(* Call to [__e_acsl_<name>] for terms of the form [p + r]
+  when [<name> = valid or initialized or valid_read] and
+  where [p] is an address and [r] a range offset *)
+let call_memory_block ~loc kf name ctx env p r =
+  let n1, n2 = match r.term_node with
+    | Trange(Some n1, Some n2) ->
+      n1, n2
+    | Trange(None, _) | Trange(_, None) ->
+      Options.abort "unbounded ranges are not part of E-ACSL"
+    | _ ->
+      assert false
+  in
+  (* s *)
+  let ty = match Cil.unrollType (Misc.cty p.term_type) with
+    | TPtr(ty, _) | TArray(ty, _, _, _) -> ty
+    | _ -> assert false
+  in
+  let s = Logic_const.term ~loc (TSizeOf ty) Linteger in
+  (* ptr *)
+  let typ_charptr = Cil.charPtrType in
+  let ptr = Logic_const.term
+    ~loc
+    (TBinOp(
+      PlusPI,
+      Logic_utils.mk_cast ~loc ~force:false typ_charptr p,
+      Logic_const.term ~loc (TBinOp(Mult, s, n1)) Linteger))
+    (Ctype typ_charptr)
+  in
+  Typing.type_term ~use_gmp_opt:false ~ctx:Typing.other ptr;
+  let term_to_exp = !term_to_exp_ref in
+  let ptr, env = term_to_exp kf (Env.rte env true) ptr in
+  (* size *)
+  let size = Logic_const.term
+    ~loc
+    (TBinOp(
+      Mult,
+      s,
+      Logic_const.term ~loc (TBinOp(MinusA, n2, n1)) Linteger))
+    Linteger
+  in
+  let ctx_ity = Typing.integer_ty_of_typ ctx in
+  Typing.type_term ~use_gmp_opt:false ~ctx:ctx_ity size;
+  let ity = Typing.get_integer_ty size in
+  if ity = Typing.gmp then Error.not_yet "size of memory area in GMP";
+  let size, env = term_to_exp kf env size in
+  let size = Cil.constFold false size in
+  (* base and base_addr *)
+  let base, _ = Misc.ptr_index ~loc ptr in
+  let base_addr  = match base.enode with
+    | AddrOf _ | Const _ -> Cil.zero ~loc
+    | Lval lv | StartOf lv -> Cil.mkAddrOrStartOf ~loc lv
+    | _ -> assert false
+  in
+  (* generating env *)
+  let _, e, env =
+    Env.new_var
+      ~loc
+      ~name
+      env
+      None
+      ctx
+      (fun v _ ->
+        let fname = Functions.RTL.mk_api_name name in
+        let args = match name with
+        | "valid" | "valid_read" -> [ ptr; size; base; base_addr ]
+        | "initialized" -> [ ptr; size ]
+        | _ -> Error.not_yet ("builtin " ^ name)
+        in
+        [ Misc.mk_call ~loc ~result:(Cil.var v) fname args ])
+  in
+  e, env
+
+(* [call_with_ranges] handles ranges in [t] when calling builtin [name].
+  It only supports the following cases for the time being:
+    A: [\builtin(p+r)] where [p] is an address and [r] a range or
+       [\builtin(t[r])] or
+       [\builtin(t[i_1]...[i_n])] where [t] is dynamically allocated
+                                  and all the indexes are integers,
+                                  except the last one which is a range
+       The generated code is a SINGLE call to the corresponding E-ACSL builtin
+    B: [\builtin(t[i_1]...[i_n])] where [t] is NOT dynamically allocated
+                                  and the indexes are integers or ranges
+       The generated code is a SET OF calls to the corresponding E-ACSL builtin
+    C: Any other use of ranges/No range
+       Call [call_default] which performs the translation for
+       range free terms, and raises Not_yet if it ever encouters a range.
+  Example for case:
+    A: [\valid(&t[3..5])]
+       Contiguous locations -> a single call to [__e_acsl_valid]
+    B: [\valid(&t[4][3..5][2])]
+       NON-contiguous locations -> multiple calls (3) to [__e_acsl_valid] *)
+let call_with_ranges ~loc kf name ctx env t call_default =
+  if Misc.is_bitfield_pointers t.term_type then
+    Error.not_yet "bitfield pointer";
+  match t.term_node with
+  | TBinOp((PlusPI | IndexPI), p, ({ term_node = Trange _ } as r)) ->
+    if Misc.is_set_of_ptr_or_array p.term_type then
+      Error.not_yet "arithmetic over set of pointers or arrays"
+    else
+      (* Case A *)
+      call_memory_block ~loc kf name ctx env p r
+  | TAddrOf(TVar lv, TIndex({ term_node = Trange _ } as r, TNoOffset)) ->
+    (* Case A *)
+    assert (Logic_const.is_set_type t.term_type);
+    let lty_noset = Logic_const.type_of_element t.term_type in
+    let p = Logic_const.taddrof ~loc (TVar lv, TNoOffset) lty_noset in
+    call_memory_block ~loc kf name ctx env p r
+  | TAddrOf(TVar ({ lv_type = Ctype (TArray _) } as lv), toffset) ->
+    if has_set_as_index toffset then
+      (* Case B *)
+      try
+        let toffset', quantifiers =
+          eliminate_ranges_from_index_of_toffset ~loc toffset []
+        in
+        let lty_noset =
+          if Logic_const.is_set_type t.term_type then
+            Logic_const.type_of_element t.term_type
+          else
+            t.term_type
+        in
+        let t' = Logic_const.taddrof ~loc (TVar lv, toffset') lty_noset in
+        let p_quantified =
+          (* [loc] prevents a type error with eta-expansion and label *)
+          let loc = Some loc in
+          let call f = f ?loc (Logic_const.here_label, t') in
+          match name with
+          | "valid" -> call Logic_const.pvalid
+          | "initialized" -> call Logic_const.pinitialized
+          | "valid_read" -> call Logic_const.pvalid_read
+          | _ -> Options.fatal "[call_with_ranges] unexpected builtin"
+          in
+          let p_quantified = List.fold_left
+            (fun p (tmin, lv, tmax) ->
+              (* \forall integer tlv; tmin <= tlv <= tmax ==> p *)
+              let tlv = Logic_const.tvar ~loc lv in
+              let lower_bound = Logic_const.prel ~loc (Rle, tmin, tlv) in
+              let upper_bound = Logic_const.prel ~loc (Rle, tlv, tmax) in
+              let bound = Logic_const.pand ~loc (lower_bound, upper_bound) in
+              let bound_imp_p = Logic_const.pimplies ~loc (bound, p) in
+              Logic_const.pforall ~loc ([lv], bound_imp_p))
+            p_quantified
+            quantifiers
+        in
+        Typing.type_named_predicate ~must_clear:true p_quantified;
+        let named_predicate_to_exp = !predicate_to_exp_ref in
+        named_predicate_to_exp kf env p_quantified
+      with Range_elimination_exception ->
+        (* Case C *)
+        call_default ~loc kf name ctx env t
+    else
+      (* Case C *)
+      call_default ~loc kf name ctx env t
+  | _ ->
+    (* Case C *)
+    call_default ~loc kf name ctx env t
+
+(* \initialized *)
+let call_with_size ~loc kf name ctx env t =
+  assert (name = "initialized");
+  let call_for_unsupported_constructs ~loc kf name ctx env t =
+    let term_to_exp = !term_to_exp_ref in
+    let e, env = term_to_exp kf (Env.rte env true) t in
+    let _, res, env =
+      Env.new_var
+        ~loc
+        ~name
+        env
+        None
+        ctx
+        (fun v _ ->
+          let ty = Misc.cty t.term_type in
+          let sizeof = Misc.mk_ptr_sizeof ty loc in
+          let fname = Functions.RTL.mk_api_name name in
+          [ Misc.mk_call ~loc ~result:(Cil.var v) fname [ e; sizeof ] ])
+    in
+    res, env
+  in
+  call_with_ranges
+    ~loc
+    kf
+    name
+    ctx
+    env
+    t
+    call_for_unsupported_constructs
+
+(* \valid and \valid_read *)
+let call_valid ~loc kf name ctx env t =
+  assert (name = "valid" || name = "valid_read");
+  let call_for_unsupported_constructs ~loc kf name ctx env t =
+    let term_to_exp = !term_to_exp_ref in
+    let e, env = term_to_exp kf (Env.rte env true) t in
+    let base, _ = Misc.ptr_index ~loc e in
+    let base_addr  = match base.enode with
+      | AddrOf _ | Const _ -> Cil.zero ~loc
+      | Lval lv | StartOf lv -> Cil.mkAddrOrStartOf ~loc lv
+      | _ -> assert false
+    in
+    let _, res, env =
+      Env.new_var
+        ~loc
+        ~name
+        env
+        None
+        ctx
+        (fun v _ ->
+          let ty = Misc.cty t.term_type in
+          let sizeof = Misc.mk_ptr_sizeof ty loc in
+          let fname = Functions.RTL.mk_api_name name in
+          let args = [ e; sizeof; base; base_addr ] in
+          [ Misc.mk_call ~loc ~result:(Cil.var v) fname args ])
+    in
+    res, env
+  in
+  call_with_ranges
+    ~loc
+    kf
+    name
+    ctx
+    env
+    t
+    call_for_unsupported_constructs
\ No newline at end of file
diff --git a/src/plugins/e-acsl/mmodel_translate.mli b/src/plugins/e-acsl/mmodel_translate.mli
new file mode 100644
index 00000000000..eeed2bc1120
--- /dev/null
+++ b/src/plugins/e-acsl/mmodel_translate.mli
@@ -0,0 +1,60 @@
+(**************************************************************************)
+(*                                                                        *)
+(*  This file is part of Frama-C.                                         *)
+(*                                                                        *)
+(*  Copyright (C) 2007-2018                                               *)
+(*    CEA (Commissariat à l'énergie atomique et aux énergies              *)
+(*         alternatives)                                                  *)
+(*                                                                        *)
+(*  you can redistribute it and/or modify it under the terms of the GNU   *)
+(*  Lesser General Public License as published by the Free Software       *)
+(*  Foundation, version 2.1.                                              *)
+(*                                                                        *)
+(*  It is distributed in the hope that it will be useful,                 *)
+(*  but WITHOUT ANY WARRANTY; without even the implied warranty of        *)
+(*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *)
+(*  GNU Lesser General Public License for more details.                   *)
+(*                                                                        *)
+(*  See the GNU Lesser General Public License version 2.1                 *)
+(*  for more details (enclosed in the file licenses/LGPLv2.1).            *)
+(*                                                                        *)
+(**************************************************************************)
+
+open Cil_types
+
+(* Create calls to a few memory builtins.
+   Partial support for ranges is provided. *)
+
+val call:
+  loc:location -> kernel_function -> string -> typ -> Env.t -> term ->
+  exp * Env.t
+(* [call ~loc kf name ctx env t] creates a call to the E-ACSL memory builtin
+   identified by [name] which only requires a single argument, namely the
+   pointer under study. The supported builtins are:
+   [base_addr], [block_length], [offset] and [freeable]. *)
+
+val call_with_size:
+  loc:location -> kernel_function -> string -> typ -> Env.t -> term ->
+  exp * Env.t
+(* [call_with_size ~loc kf name ctx env t] creates a call to the E-ACSL memory
+   builtin identified by [name] which requires two arguments, namely
+   the pointer under study and a size in bytes.
+   The only supported builtin is: [initialized].
+   [t] can denote ranges of memory locations. *)
+
+val call_valid:
+  loc:location -> kernel_function -> string -> typ -> Env.t -> term ->
+  exp * Env.t
+(* [call_valid ~loc kf name ctx env t] creates a call to the E-ACSL memory
+   builtin [valid] or [valid_read] according to [name].
+   [t] can denote ranges of memory locations. *)
+
+(**************************************************************************)
+(********************** Forward references ********************************)
+(**************************************************************************)
+
+val predicate_to_exp_ref:
+  (kernel_function -> Env.t -> predicate -> exp * Env.t) ref
+
+val term_to_exp_ref:
+  (kernel_function -> Env.t -> term -> exp * Env.t) ref
\ No newline at end of file
diff --git a/src/plugins/e-acsl/translate.ml b/src/plugins/e-acsl/translate.ml
index d77e94913a3..e57580f53f2 100644
--- a/src/plugins/e-acsl/translate.ml
+++ b/src/plugins/e-acsl/translate.ml
@@ -39,78 +39,6 @@ let handle_error f env =
    It is [true] iff we are currently visiting \valid. *)
 let is_visiting_valid = ref false
 
-(*****************************************************************************)
-(*************************** Ranges in a few builtins ************************)
-(*****************************************************************************)
-
-(* We call Range Elimination the operation through which ranges are
-  substituted by universally quantified logic variables.
-  Example:
-    [\valid(&t[(n-1)..(n+2)][1][0..1])] can be soundly transformed into
-    [\forall integer q1; n-1 <= q1 <= n+2 ==>
-      \forall integer q2; 0 <= q2 <= 1 ==>
-        \valid(&t[q1][1][q2])]
-  However, the substition can be unsound,
-  in which case [Range_elimination_exception] must be raised.
-  Example:
-    [\valid(&t[(0..2)==(0..2) ? 0 : 1])] is equivalent to [\valid(&t[0])]
-      since [==] refers to set equality when applied on ranges.
-    But Range Elimination will give a predicate equivalent to [\valid(&t[1])]
-      since [\forall 0 <= q1,q2 <= 2: q1==q2] is false.
-    Hence [Range_elimination_exception] must be raised. *)
-exception Range_elimination_exception
-
-(* Takes a [toffset] and checks whether it contains an index that is a set *)
-let rec has_set_as_index = function
-  | TNoOffset ->
-    false
-  | TIndex(t, toffset) ->
-    Logic_const.is_set_type t.term_type || has_set_as_index toffset
-  | TModel(_, toffset) | TField(_, toffset) ->
-    has_set_as_index toffset
-
-(* Performs Range Elimination on index [TIndex(term, offset)]. Term part.
-  Raises [Range_elimination_exception] if whether the operation is unsound or
-  if we don't support the construction yet. *)
-let eliminate_ranges_from_index_of_term ~loc t =
-  match t.term_node with
-  | Trange(Some n1, Some n2) ->
-    let name = Env.Varname.get ~scope:Env.Local_block "range" in
-    let lv = Cil_const.make_logic_var_kind name LVQuant Linteger in
-    let tlv = Logic_const.tvar ~loc lv in
-    tlv, (n1, lv, n2)
-  | _ ->
-    raise Range_elimination_exception
-
-(* Performs Range Elimination on index [TIndex(term, offset)]. Offset part.
-  Raises [Range_elimination_exception], through [eliminate_ranges_from_
-  index_of_term], if whether the operation is unsound or
-  if we don't support the construction yet. *)
-let rec eliminate_ranges_from_index_of_toffset ~loc toffset quantifiers =
-  match toffset with
-  | TIndex(t, toffset') ->
-    if Misc.is_range_free t then
-      let toffset', quantifiers' =
-        eliminate_ranges_from_index_of_toffset ~loc toffset' quantifiers
-      in
-      TIndex(t, toffset'), quantifiers'
-    else
-      (* Attempt Range Elimination on [t] *)
-      let t1, quantifiers1 =
-        eliminate_ranges_from_index_of_term ~loc t
-      in
-      let toffset2, quantifiers2 =
-        eliminate_ranges_from_index_of_toffset ~loc toffset' quantifiers
-      in
-      let toffset3 = TIndex(t1, toffset2) in
-      toffset3, quantifiers1 :: quantifiers2
-  | TNoOffset ->
-    toffset, quantifiers
-  | TModel _ ->
-    Error.not_yet "range elimination on TModel"
-  | TField _ ->
-    Error.not_yet "range elimination on TField"
-
 (* ************************************************************************** *)
 (* Transforming terms and predicates into C expressions (if any) *)
 (* ************************************************************************** *)
@@ -572,15 +500,21 @@ and context_insensitive_term_to_exp kf env t =
       let e, env, is_mpz_string = at_to_exp_no_lscope env (Some t) label e in
       e, env, is_mpz_string, ""
   | Tbase_addr(BuiltinLabel Here, t) ->
-    mmodel_call ~loc kf "base_addr" Cil.voidPtrType env t
+    let name = "base_addr" in
+    let e, env = Mmodel_translate.call ~loc kf name Cil.voidPtrType env t in
+    e, env, false, name
   | Tbase_addr _ -> not_yet env "labeled \\base_addr"
   | Toffset(BuiltinLabel Here, t) ->
     let size_t = Cil.theMachine.Cil.typeOfSizeOf in
-    mmodel_call ~loc kf "offset" size_t env t
+    let name = "offset" in
+    let e, env = Mmodel_translate.call ~loc kf name size_t env t in
+    e, env, false, name
   | Toffset _ -> not_yet env "labeled \\offset"
   | Tblock_length(BuiltinLabel Here, t) ->
     let size_t = Cil.theMachine.Cil.typeOfSizeOf in
-    mmodel_call ~loc kf "block_length" size_t env t
+    let name = "block_length" in
+    let e, env = Mmodel_translate.call ~loc kf name size_t env t in
+    e, env, false, name
   | Tblock_length _ -> not_yet env "labeled \\block_length"
   | Tnull -> Cil.mkCast (Cil.zero ~loc) (TPtr(TVoid [], [])), env, false, "null"
   | TCoerce _ -> Error.untypable "coercion" (* Jessie specific *)
@@ -652,247 +586,6 @@ and comparison_to_exp
   | Typing.C_type _ | Typing.Other ->
     Cil.mkBinOp ~loc bop e1 e2, env
 
-(* \base_addr, \block_length and \freeable annotations *)
-and mmodel_call ~loc kf name ctx env t =
-  let e, env = term_to_exp kf (Env.rte env true) t in
-  let _, res, env =
-    Env.new_var
-      ~loc
-      ~name
-      env
-      None
-      ctx
-      (fun v _ ->
-        let name = Functions.RTL.mk_api_name name in
-        [ Misc.mk_call ~loc ~result:(Cil.var v) name [ e ] ])
-  in
-  res, env, false, name
-
-and get_c_term_type = function
-  | Ctype ty -> ty
-  | _ -> assert false
-
-and mk_ptr_sizeof typ loc =
-  match Cil.unrollType typ with
-  | TPtr (t', _) -> Cil.new_exp ~loc (SizeOf t')
-  | _ -> assert false
-
-(* \valid, \offset and \initialized annotations *)
-and mmodel_call_with_size ~loc kf name ctx env t =
-  let call_for_unsupported_constructs ~loc kf name ctx env t =
-    let e, env = term_to_exp kf (Env.rte env true) t in
-    let _, res, env =
-      Env.new_var
-        ~loc
-        ~name
-        env
-        None
-        ctx
-        (fun v _ ->
-          let ty = get_c_term_type t.term_type in
-          let sizeof = mk_ptr_sizeof ty loc in
-          let fname = Functions.RTL.mk_api_name name in
-          [ Misc.mk_call ~loc ~result:(Cil.var v) fname [ e; sizeof ] ])
-    in
-    res, env
-  in
-  mmodel_call_with_ranges
-    ~loc
-    kf
-    name
-    ctx
-    env
-    t
-    call_for_unsupported_constructs
-
-and mmodel_call_valid ~loc kf name ctx env t =
-  let call_for_unsupported_constructs ~loc kf name ctx env t =
-    let e, env = term_to_exp kf (Env.rte env true) t in
-    let base, _ = Misc.ptr_index ~loc e in
-    let base_addr  = match base.enode with
-      | AddrOf _ | Const _ -> Cil.zero ~loc
-      | Lval lv | StartOf lv -> Cil.mkAddrOrStartOf ~loc lv
-      | _ -> assert false
-    in
-    let _, res, env =
-      Env.new_var
-        ~loc
-        ~name
-        env
-        None
-        ctx
-        (fun v _ ->
-          let ty = get_c_term_type t.term_type in
-          let sizeof = mk_ptr_sizeof ty loc in
-          let fname = Functions.RTL.mk_api_name name in
-          let args = [ e; sizeof; base; base_addr ] in
-          [ Misc.mk_call ~loc ~result:(Cil.var v) fname args ])
-    in
-    res, env
-  in
-  mmodel_call_with_ranges
-    ~loc
-    kf
-    name
-    ctx
-    env
-    t
-    call_for_unsupported_constructs
-
-(* [mmodel_call_with_ranges] handles ranges in [t] when calling builtin [name].
-  It only supports the following cases for the time being:
-    A: [\builtin(p+r)] where [p] is an address and [r] a range or
-       [\builtin(t[r])] or
-       [\builtin(t[i_1]...[i_n])] where [t] is dynamically allocated
-                                  and all the indexes are integers,
-                                  except the last one which is a range
-       The generated code is a SINGLE call to the corresponding E-ACSL builtin
-    B: [\builtin(t[i_1]...[i_n])] where [t] is NOT dynamically allocated
-                                  and the indexes are integers or ranges
-       The generated code is a SET OF calls to the corresponding E-ACSL builtin
-    C: Any other use of ranges/No range
-       Call [mmodel_call_default] which performs the translation for
-       range free terms, and raises Not_yet if it ever encouters a range.
-  Example for case:
-    A: [\valid(&t[3..5])]
-       Contiguous locations -> a single call to [__e_acsl_valid]
-    B: [\valid(&t[4][3..5][2])]
-       NON-contiguous locations -> multiple calls (3) to [__e_acsl_valid] *)
-and mmodel_call_with_ranges ~loc kf name ctx env t mmodel_call_default =
-  if Misc.is_bitfield_pointers t.term_type then
-    not_yet env "bitfield pointer";
-  match t.term_node with
-  | TBinOp((PlusPI | IndexPI), p, ({ term_node = Trange _ } as r)) ->
-    if Misc.is_set_of_ptr_or_array p.term_type then
-      not_yet env "arithmetic over set of pointers or arrays"
-    else
-      (* Case A *)
-      mmodel_call_memory_block ~loc kf name ctx env p r
-  | TAddrOf(TVar lv, TIndex({ term_node = Trange _ } as r, TNoOffset)) ->
-    (* Case A *)
-    assert (Logic_const.is_set_type t.term_type);
-    let lty_noset = Logic_const.type_of_element t.term_type in
-    let p = Logic_const.taddrof ~loc (TVar lv, TNoOffset) lty_noset in
-    mmodel_call_memory_block ~loc kf name ctx env p r
-  | TAddrOf(TVar ({ lv_type = Ctype (TArray _) } as lv), toffset) ->
-    if has_set_as_index toffset then
-      (* Case B *)
-      try
-        let toffset', quantifiers =
-          eliminate_ranges_from_index_of_toffset ~loc toffset []
-        in
-        let lty_noset =
-          if Logic_const.is_set_type t.term_type then
-            Logic_const.type_of_element t.term_type
-          else
-            t.term_type
-        in
-        let t' = Logic_const.taddrof ~loc (TVar lv, toffset') lty_noset in
-        let p_quantified =
-          (* [loc] prevents a type error with eta-expansion and label *)
-          let loc = Some loc in
-          let call f = f ?loc (Logic_const.here_label, t') in
-          match name with
-          | "valid" -> call Logic_const.pvalid
-          | "initialized" -> call Logic_const.pinitialized
-          | "valid_read" -> call Logic_const.pvalid_read
-          | _ -> Options.fatal "[mmodel_call_with_ranges] unexpected builtin"
-          in
-          let p_quantified = List.fold_left
-            (fun p (tmin, lv, tmax) ->
-              (* \forall integer tlv; tmin <= tlv <= tmax ==> p *)
-              let tlv = Logic_const.tvar ~loc lv in
-              let lower_bound = Logic_const.prel ~loc (Rle, tmin, tlv) in
-              let upper_bound = Logic_const.prel ~loc (Rle, tlv, tmax) in
-              let bound = Logic_const.pand ~loc (lower_bound, upper_bound) in
-              let bound_imp_p = Logic_const.pimplies ~loc (bound, p) in
-              Logic_const.pforall ~loc ([lv], bound_imp_p))
-            p_quantified
-            quantifiers
-        in
-        Typing.type_named_predicate ~must_clear:true p_quantified;
-        named_predicate_to_exp kf env p_quantified
-      with Range_elimination_exception ->
-        (* Case C *)
-        mmodel_call_default ~loc kf name ctx env t
-    else
-      (* Case C *)
-      mmodel_call_default ~loc kf name ctx env t
-  | _ ->
-    (* Case C *)
-    mmodel_call_default ~loc kf name ctx env t
-
-(* Call to [__e_acsl_<name>] for terms of the form [p + r]
-  when [<name> = valid or initialized or valid_read] and
-  where [p] is an address and [r] a range offset *)
-and mmodel_call_memory_block ~loc kf name ctx env p r =
-  let n1, n2 = match r.term_node with
-    | Trange(Some n1, Some n2) ->
-      n1, n2
-    | Trange(None, _) | Trange(_, None) ->
-      Options.abort "unbounded ranges are not part of E-ACSL"
-    | _ ->
-      assert false
-  in
-  (* s *)
-  let ty = match Cil.unrollType (get_c_term_type p.term_type) with
-    | TPtr(ty, _) | TArray(ty, _, _, _) -> ty
-    | _ -> assert false
-  in
-  let s = Logic_const.term ~loc (TSizeOf ty) Linteger in
-  (* ptr *)
-  let typ_charptr = Cil.charPtrType in
-  let ptr = Logic_const.term
-    ~loc
-    (TBinOp(
-      PlusPI,
-      Logic_utils.mk_cast ~loc ~force:false typ_charptr p,
-      Logic_const.term ~loc (TBinOp(Mult, s, n1)) Linteger))
-    (Ctype typ_charptr)
-  in
-  Typing.type_term ~use_gmp_opt:false ~ctx:Typing.other ptr;
-  let ptr, env = term_to_exp kf (Env.rte env true) ptr in
-  (* size *)
-  let size = Logic_const.term
-    ~loc
-    (TBinOp(
-      Mult,
-      s,
-      Logic_const.term ~loc (TBinOp(MinusA, n2, n1)) Linteger))
-    Linteger
-  in
-  let ctx_ity = Typing.integer_ty_of_typ ctx in
-  Typing.type_term ~use_gmp_opt:false ~ctx:ctx_ity size;
-  let ity = Typing.get_integer_ty size in
-  if ity = Typing.gmp then not_yet env "size of memory area in GMP";
-  let size, env = term_to_exp kf env size in
-  let size = Cil.constFold false size in
-  (* base and base_addr *)
-  let base, _ = Misc.ptr_index ~loc ptr in
-  let base_addr  = match base.enode with
-    | AddrOf _ | Const _ -> Cil.zero ~loc
-    | Lval lv | StartOf lv -> Cil.mkAddrOrStartOf ~loc lv
-    | _ -> assert false
-  in
-  (* generating env *)
-  let _, e, env =
-    Env.new_var
-      ~loc
-      ~name
-      env
-      None
-      ctx
-      (fun v _ ->
-        let fname = Functions.RTL.mk_api_name name in
-        let args = match name with
-        | "valid" | "valid_read" -> [ ptr; size; base; base_addr ]
-        | "initialized" -> [ ptr; size ]
-        | _ -> not_yet env ("builtin " ^ name)
-        in
-        [ Misc.mk_call ~loc ~result:(Cil.var v) fname args ])
-  in
-  e, env
-
 and at_to_exp_no_lscope env t_opt label e =
   let stmt = E_acsl_label.get_stmt (Env.get_visitor env) label in
   (* generate a new variable denoting [\at(t',label)].
@@ -1029,15 +722,15 @@ and named_predicate_content_to_exp ?name kf env p =
   | (Pvalid(BuiltinLabel Here as llabel, t) as pc) ->
     let call_valid t =
       let name = match pc with
-	| Pvalid _ -> "valid"
-	| Pvalid_read _ -> "valid_read"
-	| _ -> assert false
+        | Pvalid _ -> "valid"
+        | Pvalid_read _ -> "valid_read"
+        | _ -> assert false
       in
-      mmodel_call_valid ~loc kf name Cil.intType env t
+      Mmodel_translate.call_valid ~loc kf name Cil.intType env t
     in
     if !is_visiting_valid then begin
       (* we already transformed \valid(t) into \initialized(&t) && \valid(t):
-	 now convert this right-most valid. *)
+         now convert this right-most valid. *)
       is_visiting_valid := false;
       call_valid t
     end else begin
@@ -1050,7 +743,8 @@ and named_predicate_content_to_exp ?name kf env p =
         let p = Logic_const.pand ~loc (init, p) in
         is_visiting_valid := true;
         named_predicate_to_exp kf env p
-      | _ -> call_valid t
+      | _ ->
+        call_valid t
     end
   | Pvalid _ -> not_yet env "labeled \\valid"
   | Pvalid_read _ -> not_yet env "labeled \\valid_read"
@@ -1059,15 +753,21 @@ and named_predicate_content_to_exp ?name kf env p =
     (* optimisation when we know that the initialisation is ok *)
     | TAddrOf (TResult _, TNoOffset) -> Cil.one ~loc, env
     | TAddrOf (TVar { lv_origin = Some vi }, TNoOffset)
-	when vi.vformal || vi.vglob || Functions.RTL.is_generated_name vi.vname ->
+      when
+        vi.vformal || vi.vglob || Functions.RTL.is_generated_name vi.vname ->
       Cil.one ~loc, env
     | _ ->
-      mmodel_call_with_size ~loc kf "initialized" Cil.intType env t)
+      Mmodel_translate.call_with_size
+        ~loc
+        kf
+        "initialized"
+        Cil.intType
+        env
+        t)
   | Pinitialized _ -> not_yet env "labeled \\initialized"
   | Pallocable _ -> not_yet env "\\allocate"
   | Pfreeable(BuiltinLabel Here, t) ->
-    let res, env, _, _ = mmodel_call ~loc kf "freeable" Cil.intType env t in
-    res, env
+    Mmodel_translate.call ~loc kf "freeable" Cil.intType env t
   | Pfreeable _ -> not_yet env "labeled \\freeable"
   | Pfresh _ -> not_yet env "\\fresh"
   | Psubtype _ -> Error.untypable "subtyping relation" (* Jessie specific *)
@@ -1141,7 +841,9 @@ let () =
   Loops.translate_named_predicate_ref := translate_named_predicate;
   Quantif.predicate_to_exp_ref := named_predicate_to_exp;
   At_with_lscope.term_to_exp_ref := term_to_exp;
-  At_with_lscope.predicate_to_exp_ref := named_predicate_to_exp
+  At_with_lscope.predicate_to_exp_ref := named_predicate_to_exp;
+  Mmodel_translate.term_to_exp_ref := term_to_exp;
+  Mmodel_translate.predicate_to_exp_ref := named_predicate_to_exp
 
 (* This function is used by Guillaume.
    However, it is correct to use it only in specific contexts. *)
-- 
GitLab