diff --git a/.Makefile.lint b/.Makefile.lint
index 66084f3fb8c3d315c6cea8f263594c13633ad5d9..5028a0c6648db3b43fe38ed4c82e3c7244270ebe 100644
--- a/.Makefile.lint
+++ b/.Makefile.lint
@@ -134,7 +134,6 @@ ML_LINT_KO+=src/kernel_services/ast_transformations/clone.ml
 ML_LINT_KO+=src/kernel_services/ast_transformations/clone.mli
 ML_LINT_KO+=src/kernel_services/ast_transformations/filter.ml
 ML_LINT_KO+=src/kernel_services/ast_transformations/filter.mli
-ML_LINT_KO+=src/kernel_services/ast_transformations/inline.ml
 ML_LINT_KO+=src/kernel_services/cmdline_parameters/cmdline.ml
 ML_LINT_KO+=src/kernel_services/cmdline_parameters/cmdline.mli
 ML_LINT_KO+=src/kernel_services/cmdline_parameters/parameter_builder.ml
diff --git a/src/kernel_services/ast_transformations/inline.ml b/src/kernel_services/ast_transformations/inline.ml
index 70979b5c048ee8277af349d95333e9319cbb7372..1b9e32b076f7eb78f846eb68d87c0b9ae307f281 100644
--- a/src/kernel_services/ast_transformations/inline.ml
+++ b/src/kernel_services/ast_transformations/inline.ml
@@ -170,16 +170,16 @@ let inliner functions_to_inline = object (self)
     let callee =
       try Globals.Functions.get f
       with Not_found ->
-          Kernel.fatal
-            ~current:true "Expecting a function, got %a" Printer.pp_varinfo f
+        Kernel.fatal
+          ~current:true "Expecting a function, got %a" Printer.pp_varinfo f
     in
     if Kernel_function.Set.mem callee functions_to_inline &&
        not (self#recursive_call_limit callee)
     then begin
       if is_variadic_function f then begin
         Kernel.warning ~wkey ~current:true ~once:true
-        "Ignoring inlining option for variadic function %a"
-        Printer.pp_varinfo f;
+          "Ignoring inlining option for variadic function %a"
+          Printer.pp_varinfo f;
         Cil.DoChildren
       end else
         begin
@@ -256,7 +256,7 @@ let inliner functions_to_inline = object (self)
              the current kf. Otherwise, each subsequent call to a recursive
              inlined function would be inlined once again. *)
           if Cil_datatype.Kf.Set.mem callee already_visited then
-            Cil.ChangeToPost (stmt, do_after) 
+            Cil.ChangeToPost (stmt, do_after)
           else
             Cil.DoChildrenPost do_after
         end
@@ -322,3 +322,196 @@ let () =
   Kernel_file.add_code_transformation_after_cleanup
     ~deps:[(module InlineCalls.As_string:Parameter_sig.S)]
     inline_transform inline_calls
+
+(* -------------------------------------------------------------------------- *)
+(*                Inlining of predicates and logic functions                  *)
+(* -------------------------------------------------------------------------- *)
+
+open Cil_datatype
+
+exception CannotInline
+
+type inline_env = {
+  (** Returns true for predicate and logic functions to be inlined. Other
+      predicates and functions are left unchanged. *)
+  inline: logic_info -> bool;
+
+  (** logic argument of the predicate -> term that replaces it, plus the label
+      at which it must be evaluated. *)
+  map_param: (term * logic_label) Logic_var.Map.t;
+
+  (** logic label of the predicate -> label at call site *)
+  map_label: logic_label Logic_label.Map.t;
+
+  (** predicates and functions already inlined once, to prevent loops on
+      recursive definitions *)
+  already_seen: Logic_info.Set.t;
+
+  (** current default label, Here at the beginning *)
+  curr_label: logic_label;
+}
+
+(* Specification of the following inliner: the resulting term/predicate
+   contains only Papp or Tapp nodes for which [env.inline] does not hold.
+   Hence, an evaluation engine that understands these functions and predicates
+   can fully evaluate the inlined predicate/term.
+
+   To implement this specification, we fail eagerly when encountering a
+   recursive definition, or a fully unknown predicate/function without a body.*)
+
+(**  Visitors for inlining defined predicates and logical function *)
+class logic_inliner env = object (self)
+  inherit Visitor.frama_c_copy(Project.current())
+
+  method! vlogic_label label =
+    match Logic_label.Map.find label env.map_label with
+    | exception Not_found -> Cil.JustCopy
+    | x -> Cil.ChangeTo x
+
+  method private inline_label l =
+    try Logic_label.Map.find l env.map_label with Not_found -> l
+
+  method private inline_labels labels =
+    List.map self#inline_label labels
+
+  method private inline_args args =
+    let one t = Visitor.visitFramacTerm (self :> Visitor.frama_c_copy) t in
+    List.map one args
+
+  (* Builds the environnement to enter into the body of [li] with actual
+     labels and arguments [labels] and [args] respectively. Assumes that
+     both have already been inlined. *)
+  method private new_env li args labels =
+    let map_param =
+      List.fold_left2
+        (fun m v t -> Logic_var.Map.add v (t, env.curr_label) m)
+        Logic_var.Map.empty li.l_profile args
+    in
+    let map_label =
+      List.fold_left2
+        (fun m l1 l2 -> Logic_label.Map.add l1 l2 m)
+        Logic_label.Map.empty li.l_labels labels
+    in {
+      env with (* only inline and curr_label is kept *)
+      map_param;
+      map_label;
+      already_seen = Logic_info.Set.add li env.already_seen;
+    }
+
+  (* 'Freeze' [off] so that its evaluation occurs at the given label.
+      Does something only for [TIndex]. *)
+  method private freeze_off off lbl =
+    match off with
+    | TNoOffset -> TNoOffset
+    | TField (fi, o) -> TField (fi, self#freeze_off o lbl)
+    | TModel (mi, o) -> TModel (mi, self#freeze_off o lbl)
+    | TIndex (i, o) ->
+      let i' = Logic_const.tat ~loc:i.term_loc (i, lbl) in
+      TIndex (i', self#freeze_off o lbl)
+
+  method private add_at t lbl =
+    if Logic_label.equal lbl env.curr_label
+    then t
+    else Logic_const.tat ~loc:t.term_loc (t, lbl)
+
+  method! vterm t =
+    match t.term_node with
+    | Tat (t', l) ->
+      let l = self#inline_label l in
+      let vis = new logic_inliner { env with curr_label = l } in
+      let t' = Visitor.visitFramacTerm vis t' in
+      Cil.ChangeTo (self#add_at t' l)
+    | TLval (TVar v, TNoOffset) -> begin
+        match Logic_var.Map.find v env.map_param with
+        | exception Not_found -> Cil.JustCopy
+        | (x, lbl)  ->
+          (* Replace [v] by [x], making sure it is evaluated at [lbl] *)
+          Cil.ChangeTo (self#add_at x lbl)
+      end
+    | TLval (TVar v, off) -> begin
+        match Logic_var.Map.find v env.map_param with
+        | exception Not_found -> Cil.DoChildren
+        | (x, lbl)  ->
+          match x.term_node with
+          | TLval (h, offx) ->
+            (* First, inline inside [off] *)
+            let off =
+              Visitor.visitFramacTermOffset (self :> Visitor.frama_c_copy) off
+            in
+            (* We need to compute [h ++ offx ++ off] with the proper labels.
+               [h ++ offx] must be evaluated at [lbl], [off] at the current
+               label. Thus, we build [\at (h ++ offx ++ \at(off, cur), lbl)]. *)
+            let off' =
+              if Logic_label.equal env.curr_label lbl then off
+              else self#freeze_off off env.curr_label
+            in
+            let offx' = Logic_const.addTermOffset off' offx in
+            let x' = {t with term_node = TLval(h, offx')} in
+            Cil.ChangeTo (self#add_at x' lbl)
+          | _ -> (* we cannot handle casts on aggregates, functions
+                    returning aggregates, etc, because we cannot buid
+                    the corresponding term without a TLet *)
+            raise CannotInline
+      end
+    | Tapp({ l_body = LBterm body } as li, labels, args) -> begin
+        if Logic_info.Set.mem li env.already_seen then raise CannotInline;
+        let args =   self#inline_args args in
+        let labels = self#inline_labels labels in
+        if env.inline li
+        then
+          let env = self#new_env li args labels in
+          let vis = new logic_inliner env in
+          Cil.ChangeTo (Visitor.visitFramacTerm vis body)
+        else Cil.ChangeTo {t with term_node = Tapp(li, labels, args) }
+      end
+    | Tapp (li, _, _) when env.inline li ->
+      raise CannotInline
+    | _ -> Cil.DoChildren
+
+  method! vpredicate p =
+    match p.pred_content with
+    | Pat (p', l) ->
+      let l = self#inline_label l in
+      let vis = new logic_inliner { env with curr_label = l } in
+      let p' = Visitor.visitFramacPredicate vis p' in
+      Cil.ChangeTo (Logic_const.pat ~loc:p.pred_loc (p', l))
+    | Papp ({ l_body = LBpred body } as li, labels, args) -> begin
+        if Logic_info.Set.mem li env.already_seen then raise CannotInline;
+        let args =   self#inline_args args in
+        let labels = self#inline_labels labels in
+        if env.inline li
+        then
+          let env = self#new_env li args labels in
+          let vis = new logic_inliner env in
+          Cil.ChangeTo (Visitor.visitFramacPredicate vis body)
+        else Cil.ChangeTo {p with pred_content = Papp(li, labels, args) }
+      end
+    | Papp (li, _, _) when env.inline li ->
+      raise CannotInline
+    | _ -> Cil.DoChildren
+
+end
+
+let inliner curr_label inline =
+  new logic_inliner {
+    inline;
+    map_param = Logic_var.Map.empty;
+    map_label = Logic_label.Map.empty;
+    already_seen = Logic_info.Set.empty;
+    curr_label = curr_label;
+  }
+
+let inline_term ~inline ?(current = BuiltinLabel Here) term =
+  let current_loc = Cil_const.CurrentLoc.get () in
+  try Some (Visitor.visitFramacTerm (inliner current inline) term)
+  with CannotInline ->
+    (* The visitor changes and resets the reference to the current location.
+       If an exception is raised during the visit, the current location must be
+       reset by the caller. *)
+    Cil_const.CurrentLoc.set current_loc;
+    None
+
+let inline_predicate ~inline ?(current = BuiltinLabel Here) pred =
+  let current_loc = Cil_const.CurrentLoc.get () in
+  try Some (Visitor.visitFramacPredicate (inliner current inline) pred)
+  with CannotInline ->  Cil_const.CurrentLoc.set current_loc; None
diff --git a/src/kernel_services/ast_transformations/inline.mli b/src/kernel_services/ast_transformations/inline.mli
index e36a1038264255393e92d404e42634833cff9389..5571b25c71a8e08c1799e7e7905d395b8cea9d64 100644
--- a/src/kernel_services/ast_transformations/inline.mli
+++ b/src/kernel_services/ast_transformations/inline.mli
@@ -20,4 +20,20 @@
 (*                                                                        *)
 (**************************************************************************)
 
-val inline_calls : Cil_types.file -> unit
+open Cil_types
+
+val inline_calls : file -> unit
+
+(** [inline_term ~inline term] inlines in [term] the application of predicates
+    and logic functions for which [inline] is true. If provided, [current] is
+    the current label of the term; it is [Here] by default. Returns [None]
+    if the inlining of a predicate or a logic function fails, in particular
+    when they are recursive or have no direct definitiion. *)
+val inline_term:
+  inline:(logic_info -> bool) -> ?current:logic_label -> term -> term option
+
+(** Inlines predicates and logic functions in a predicate. See [inline_term]
+    for details. *)
+val inline_predicate:
+  inline:(logic_info -> bool) -> ?current:logic_label ->
+  predicate -> predicate option
diff --git a/src/plugins/value/legacy/eval_terms.ml b/src/plugins/value/legacy/eval_terms.ml
index 81df02d653aab56af8818bd290ec73627e32b0b9..c29e3bdde8129514d0e129ef27199a4400eec849 100644
--- a/src/plugins/value/legacy/eval_terms.ml
+++ b/src/plugins/value/legacy/eval_terms.ml
@@ -651,188 +651,9 @@ let is_known_logic_fun_pred known lvi =
 let is_known_logic_fun = is_known_logic_fun_pred known_logic_funs
 let is_known_predicate = is_known_logic_fun_pred known_predicates
 
-exception CannotInline
-
-type inline_env = {
-  (** logic argument of the predicate -> term that replaces it, plus the label
-      at which it must be evaluated. *)
-  ie_map_param: (term * logic_label) Logic_var.Map.t;
-
-  (** logic label of the predicate -> label at call site *)
-  ie_map_label: logic_label Logic_label.Map.t;
-
-  (** predicates and functions already inlined once, to prevent loops on
-      recursive definitions *)
-  ie_already_seen: Logic_info.Set.t;
-
-  (** current default label, Here at the beginning *)
-  ie_curr_label: logic_label;
-}
-
-(* Specification of the following inliner: the resulting term/predicate
-   contains only Papp or Tapp nodes for which [is_known_logic_fun] and
-   [is_known_pred] hold. Hence, an evaluation engine that understands the
-   predicates/functions that verify [is_known_...] can fully evaluate the
-   inlined predicate/term.
-
-   To implement this specification, we fail eargerly when encountering a
-   recursive definition, or a fully unknown predicate/function without a body.*)
-
-(**  Visitors for inlining defined predicates and logical function *)
-class inliner env = object (self)
-  inherit Visitor.frama_c_copy(Project.current())
-
-  method! vlogic_label label =
-    match Logic_label.Map.find label env.ie_map_label with
-    | exception Not_found -> Cil.JustCopy
-    | x -> Cil.ChangeTo x
-
-  method private inline_label l =
-    try Logic_label.Map.find l env.ie_map_label with Not_found -> l
-
-  method private inline_labels labels =
-    List.map self#inline_label labels
-
-  method private inline_args args =
-    let one t = Visitor.visitFramacTerm (self :> Visitor.frama_c_copy) t in
-    List.map one args
-
-  (* Builds the environnement to enter into the body of [li] with actual
-     labels and arguments [labels] and [args] respectively. Assumes that
-     both have already been inlined. *)
-  method private new_env li args labels =
-    let ie_map_param =
-      List.fold_left2
-        (fun m v t -> Logic_var.Map.add v (t, env.ie_curr_label) m)
-        Logic_var.Map.empty li.l_profile args
-    in
-    let ie_map_label =
-      List.fold_left2
-        (fun m l1 l2 -> Logic_label.Map.add l1 l2 m)
-        Logic_label.Map.empty li.l_labels labels
-    in {
-      env with (* only curr_label is kept *)
-      ie_map_param;
-      ie_map_label;
-      ie_already_seen = Logic_info.Set.add li env.ie_already_seen;
-    }
-
-  (* 'Freeze' [off] so that its evaluation occurs at the given label.
-      Does something only for [TIndex]. *)
-  method private freeze_off off lbl =
-    match off with
-    | TNoOffset -> TNoOffset
-    | TField (fi, o) -> TField (fi, self#freeze_off o lbl)
-    | TModel (mi, o) -> TModel (mi, self#freeze_off o lbl)
-    | TIndex (i, o) ->
-      let i' = Logic_const.tat ~loc:i.term_loc (i, lbl) in
-      TIndex (i', self#freeze_off o lbl)
-
-  method private add_at t lbl =
-    if Logic_label.equal lbl env.ie_curr_label
-    then t
-    else Logic_const.tat ~loc:t.term_loc (t, lbl)
-
-  method! vterm t =
-    match t.term_node with
-    | Tat (t', l) ->
-      let l = self#inline_label l in
-      let vis = new inliner { env with ie_curr_label = l } in
-      let t' = Visitor.visitFramacTerm vis t' in
-      Cil.ChangeTo (self#add_at t' l)
-    | TLval (TVar v, TNoOffset) -> begin
-        match Logic_var.Map.find v env.ie_map_param with
-        | exception Not_found -> Cil.JustCopy
-        | (x, lbl)  ->
-          (* Replace [v] by [x], making sure it is evaluated at [lbl] *)
-          Cil.ChangeTo (self#add_at x lbl)
-      end
-    | TLval (TVar v, off) -> begin
-        match Logic_var.Map.find v env.ie_map_param with
-        | exception Not_found -> Cil.DoChildren
-        | (x, lbl)  ->
-          match x.term_node with
-          | TLval (h, offx) ->
-            (* First, inline inside [off] *)
-            let off =
-              Visitor.visitFramacTermOffset (self :> Visitor.frama_c_copy) off
-            in
-            (* We need to compute [h ++ offx ++ off] with the proper labels.
-               [h ++ offx] must be evaluated at [lbl], [off] at the current
-               label. Thus, we build [\at (h ++ offx ++ \at(off, cur), lbl)]. *)
-            let off' =
-              if Logic_label.equal env.ie_curr_label lbl then off
-              else self#freeze_off off env.ie_curr_label
-            in
-            let offx' = Logic_const.addTermOffset off' offx in
-            let x' = {t with term_node = TLval(h, offx')} in
-            Cil.ChangeTo (self#add_at x' lbl)
-          | _ -> (* we cannot handle casts on aggregates, functions
-                    returning aggregates, etc, because we cannot buid
-                    the corresponding term without a TLet *)
-            raise CannotInline
-      end
-    | Tapp({ l_body = LBterm body } as li, labels, args) -> begin
-        if Logic_info.Set.mem li env.ie_already_seen then raise CannotInline;
-        let args =   self#inline_args args in
-        let labels = self#inline_labels labels in
-        if is_known_logic_fun li.l_var_info then
-          Cil.ChangeTo {t with term_node = Tapp(li, labels, args) }
-        else
-          let env = self#new_env li args labels in
-          let vis = new inliner env in
-          Cil.ChangeTo (Visitor.visitFramacTerm vis body)
-      end
-    | Tapp (li, _, _) when not (is_known_logic_fun li.l_var_info) ->
-      raise CannotInline
-    | _ -> Cil.DoChildren
-
-  method! vpredicate p =
-    match p.pred_content with
-    | Pat (p', l) ->
-      let l = self#inline_label l in
-      let vis = new inliner { env with ie_curr_label = l } in
-      let p' = Visitor.visitFramacPredicate vis p' in
-      Cil.ChangeTo (Logic_const.pat ~loc:p.pred_loc (p', l))
-    | Papp ({ l_body = LBpred body } as li, labels, args) -> begin
-        if Logic_info.Set.mem li env.ie_already_seen then raise CannotInline;
-        let args =   self#inline_args args in
-        let labels = self#inline_labels labels in
-        if is_known_predicate li.l_var_info then
-          Cil.ChangeTo {p with pred_content = Papp(li, labels, args) }
-        else
-          let env = self#new_env li args labels in
-          let vis = new inliner env in
-          Cil.ChangeTo (Visitor.visitFramacPredicate vis body)
-      end
-    | Papp (li, _, _) when not (is_known_predicate li.l_var_info) ->
-      raise CannotInline
-    | _ -> Cil.DoChildren
-
-end
-
-let inliner curr_label =
-  new inliner {
-    ie_map_param = Logic_var.Map.empty;
-    ie_map_label = Logic_label.Map.empty;
-    ie_already_seen = Logic_info.Set.empty;
-    ie_curr_label = curr_label;
-  }
-
-let inline_term t cl =
-  let current_loc = Cil_const.CurrentLoc.get () in
-  try Some (Visitor.visitFramacTerm (inliner cl) t)
-  with CannotInline ->
-    (* The visitor changes and resets the reference to the current location.
-       If an exception is raised during the visit, the current location must be
-       reset by the caller. *)
-    Cil_const.CurrentLoc.set current_loc;
-    None
-
-let inline_predicate p cl =
-  let current_loc = Cil_const.CurrentLoc.get () in
-  try Some (Visitor.visitFramacPredicate (inliner cl) p)
-  with CannotInline ->  Cil_const.CurrentLoc.set current_loc; None
+let inline logic_info =
+  let logic_var = logic_info.l_var_info in
+  not (is_known_logic_fun logic_var || is_known_predicate logic_var)
 
 (* We evaluate the ACSL sign type as integers 1 or -1. Sign values can only be
    constructed through the \sign function (handled in eval_known_logic_function)
@@ -1132,7 +953,7 @@ let rec eval_term ~alarm_mode env t =
       if is_known_logic_fun li.l_var_info then
         eval_known_logic_function ~alarm_mode env li labels args
       else
-        match inline_term t env.e_cur with
+        match Inline.inline_term ~inline ~current:env.e_cur t with
         | Some t' -> eval_term ~alarm_mode env t'
         | None ->
           let s =
@@ -2068,7 +1889,7 @@ let rec reduce_by_predicate ~alarm_mode env positive p =
         if is_known_predicate li.l_var_info then
           reduce_by_known_papp env positive li labels args
         else
-          match inline_predicate p env.e_cur with
+          match Inline.inline_predicate ~inline ~current:env.e_cur p with
           | None -> env
           | Some p' ->
             reduce_by_predicate_content env positive p'.pred_content
@@ -2325,7 +2146,7 @@ and eval_predicate env pred =
         if is_known_predicate li.l_var_info then
           eval_known_papp env li labels args
         else
-          match inline_predicate p env.e_cur with
+          match Inline.inline_predicate ~inline ~current:env.e_cur p with
           | None -> Unknown
           | Some p' -> do_eval env p'
       end
@@ -2494,7 +2315,7 @@ let predicate_deps env pred =
           assert false (* TODO! Must evaluate the arguments, plus the
                           dependencies of the predicate itself. *)
         else
-          match inline_predicate p env.e_cur with
+          match Inline.inline_predicate ~inline ~current:env.e_cur p with
           | None -> assert false
           | Some p' -> do_eval env p'
       end