diff --git a/src/plugins/value/domains/domain_builder.ml b/src/plugins/value/domains/domain_builder.ml
index 62f4e168dc79228f58b3c8650cec68a6b6f12a1a..0c5e09da764e81ee6ed1bd33f195255a9ed31e96 100644
--- a/src/plugins/value/domains/domain_builder.ml
+++ b/src/plugins/value/domains/domain_builder.ml
@@ -48,8 +48,7 @@ let simplify_call call =
   { kf = call.Eval.kf;
     arguments = List.map simplify_argument call.Eval.arguments;
     rest = List.map fst call.Eval.rest;
-    return = call.Eval.return;
-    recursive = call.Eval.recursive }
+    return = call.Eval.return; }
 
 module Make_Minimal
     (Value: Abstract_value.S)
diff --git a/src/plugins/value/domains/simpler_domains.mli b/src/plugins/value/domains/simpler_domains.mli
index 37a1209a79b929a90d05f63ff1c3afd2adf57773..ba32d0d3d2e0fd94a2c579e668e52ec73563e775 100644
--- a/src/plugins/value/domains/simpler_domains.mli
+++ b/src/plugins/value/domains/simpler_domains.mli
@@ -42,7 +42,6 @@ type simple_call = {
   rest: exp list;                     (* Extra arguments. *)
   return: varinfo option;             (* Fake varinfo where the result of the
                                          call is stored. *)
-  recursive: bool;                    (* Is the call recursive? *)
 }
 
 (** Simplest interface for an abstract domain. No exchange of information with
diff --git a/src/plugins/value/engine/compute_functions.ml b/src/plugins/value/engine/compute_functions.ml
index 8eaabed066410ff3309ad58a961f42d4faafd31f..4a438739080c1c4b727319ce9c5efbb0c5a3b8db 100644
--- a/src/plugins/value/engine/compute_functions.ml
+++ b/src/plugins/value/engine/compute_functions.ml
@@ -154,21 +154,13 @@ module Make (Abstract: Abstractions.Eva) = struct
     | None -> fun _ -> assert false
     | Some get -> fun location -> get location
 
-  let unroll_recursive_call kf =
-    let call_stack = Value_util.call_stack () in
-    let previous_calls = List.filter (fun (f, _) -> f == kf) call_stack in
-    let depth = List.length previous_calls in
-    assert (depth > 0);
-    let limit = Value_parameters.RecursiveUnroll.get () in
-    depth <= limit
-
   (* Compute a call to [kf] in the state [state]. The evaluation will
      be done either using the body of [kf] or its specification, depending
      on whether the body exists and on option [-eva-use-spec]. [call_kinstr]
      is the instruction at which the call takes place, and is used to update
      the statuses of the preconditions of [kf]. If [show_progress] is true,
      the callstack and additional information are printed. *)
-  let compute_using_spec_or_body call_kinstr call state =
+  let compute_using_spec_or_body call_kinstr call recursion state =
     let kf = call.kf in
     Value_results.mark_kf_as_called kf;
     let global = match call_kinstr with Kglobal -> true | _ -> false in
@@ -180,9 +172,10 @@ module Make (Abstract: Abstractions.Eva) = struct
         Value_types.Callstack.pretty_short call_stack
         Cil_datatype.Location.pretty (Cil_datatype.Kinstr.loc call_kinstr);
     let use_spec =
-      if call.recursive && not (unroll_recursive_call kf) then
+      match recursion with
+      | Some { depth } when depth >= Value_parameters.RecursiveUnroll.get () ->
         `Spec (Recursion.recursive_spec kf)
-      else
+      | _ ->
         match kf.fundec with
         | Declaration (_,_,_,_) -> `Spec (Annotations.funspec kf)
         | Definition (def, _) ->
@@ -218,8 +211,10 @@ module Make (Abstract: Abstractions.Eva) = struct
 
   module MemExec = Mem_exec.Make (Abstract.Val) (Abstract.Dom)
 
-  let compute_and_cache_call stmt call init_state =
-    let default () = compute_using_spec_or_body (Kstmt stmt) call init_state in
+  let compute_and_cache_call stmt call recursion init_state =
+    let default () =
+      compute_using_spec_or_body (Kstmt stmt) call recursion init_state
+    in
     if Value_parameters.MemExecAll.get () then
       let args =
         List.map (fun {avalue} -> Eval.value_assigned avalue) call.arguments
@@ -280,9 +275,9 @@ module Make (Abstract: Abstractions.Eva) = struct
     | [state] -> `Value state
     | s :: l  -> `Value (List.fold_left Abstract.Dom.join s l)
 
-  let compute_call_or_builtin stmt call state =
+  let compute_call_or_builtin stmt call recursion state =
     match Builtins.find_builtin_override call.kf with
-    | None -> compute_and_cache_call stmt call state
+    | None -> compute_and_cache_call stmt call recursion state
     | Some (name, builtin, cacheable, spec) ->
       Value_results.mark_kf_as_called call.kf;
       let kinstr = Kstmt stmt in
@@ -336,11 +331,10 @@ module Make (Abstract: Abstractions.Eva) = struct
     try
       Value_util.push_call_stack kf Kglobal;
       store_initial_state kf init_state;
-      let call =
-        {kf; arguments = []; rest = []; return = None;
-         recursive = false; }
+      let call = { kf; arguments = []; rest = []; return = None; } in
+      let final_result =
+        compute_using_spec_or_body Kglobal call None init_state
       in
-      let final_result = compute_using_spec_or_body Kglobal call init_state in
       let final_states = final_result.Transfer.states in
       let final_state = PowersetDomain.(final_states >>-: of_list >>- join) in
       Value_util.pop_call_stack ();
diff --git a/src/plugins/value/engine/recursion.ml b/src/plugins/value/engine/recursion.ml
index 83133b6a202d3be19b18d13144971ec5c664b475..ea0471737a5b6efb8eabab0d7b40d181edf6369d 100644
--- a/src/plugins/value/engine/recursion.ml
+++ b/src/plugins/value/engine/recursion.ml
@@ -21,6 +21,7 @@
 (**************************************************************************)
 
 open Cil_types
+open Eval
 
 (** Recursion *)
 
@@ -54,14 +55,6 @@ let recursive_spec kf =
       Kernel_function.pretty kf
   else funspec
 
-(* Check whether the function at the top of the call-stack starts a
-   recursive call. *)
-let is_recursive_call kf =
-  let call_stack = Value_util.call_stack () in
-  if List.exists (fun (f, _) -> f == kf) call_stack
-  then (warn_recursive_call kf; true)
-  else false
-
 (* Find a spec for a function [kf] that begins a recursive call. If [kf]
    has no existing specification, generate (an incorrect) one, and warn
    loudly. *)
@@ -106,7 +99,7 @@ let _empty_spec_for_recursive_call kf =
 
 module CallDepth =
   Datatype.Pair_with_collections (Kernel_function) (Datatype.Int)
-    (struct let module_name = "RecDepth" end)
+    (struct let module_name = "CallDepth" end)
 
 module VarCopies =
   Datatype.List (Datatype.Pair (Cil_datatype.Varinfo) (Cil_datatype.Varinfo))
@@ -151,22 +144,28 @@ let make_stack (kf, depth) =
 
 let get_stack kf depth = VarStack.memo make_stack (kf, depth)
 
-let make_recursive_call kf =
-  let call_stack = Value_util.call_stack () in
-  let previous_calls = List.filter (fun (f, _) -> f == kf) call_stack in
-  let depth = List.length previous_calls in
+let make_recursion kf depth =
+  warn_recursive_call kf;
   let substitution, withdrawal = get_stack kf depth in
   let base_of_varinfo (v1, v2) = Base.of_varinfo v1, Base.of_varinfo v2 in
   let list_substitution = List.map base_of_varinfo substitution in
   let base_substitution = Base.substitution_from_list list_substitution in
   let list_withdrawal = List.map Base.of_varinfo withdrawal in
   let base_withdrawal = Base.Hptset.of_list list_withdrawal in
-  Eval.{ depth; substitution; base_substitution; withdrawal; base_withdrawal; }
+  { depth; substitution; base_substitution; withdrawal; base_withdrawal; }
+
+let get_recursion kf =
+  let call_stack = Value_util.call_stack () in
+  let previous_calls = List.filter (fun (f, _) -> f == kf) call_stack in
+  let depth = List.length previous_calls in
+  if depth > 0
+  then Some (make_recursion kf depth)
+  else None
 
 let revert_recursion recursion =
   let revert (v1, v2) = v2, v1 in
-  let substitution = List.map revert recursion.Eval.substitution in
+  let substitution = List.map revert recursion.substitution in
   let base_of_varinfo (v1, v2) = Base.of_varinfo v1, Base.of_varinfo v2 in
   let list = List.map base_of_varinfo substitution in
   let base_substitution = Base.substitution_from_list list in
-  Eval.{ recursion with substitution; base_substitution; }
+  { recursion with substitution; base_substitution; }
diff --git a/src/plugins/value/engine/recursion.mli b/src/plugins/value/engine/recursion.mli
index a446573aca8c6858c701f14993c1beef7baaae3f..3a83fbd0023ba10437f65d193719b4cb8730741e 100644
--- a/src/plugins/value/engine/recursion.mli
+++ b/src/plugins/value/engine/recursion.mli
@@ -23,14 +23,11 @@
 (** Handling of recursion cycles in the callgraph *)
 
 open Cil_types
+open Eval
 
 val recursive_spec: kernel_function -> funspec
 
-val is_recursive_call: kernel_function -> bool
-(** Given  the current state of the call stack, detect whether the
-    given given function would start a recursive cycle. *)
-
 (** TODO *)
-val make_recursive_call: kernel_function -> Eval.recursion
+val get_recursion: kernel_function -> recursion option
 
-val revert_recursion: Eval.recursion -> Eval.recursion
+val revert_recursion: recursion -> recursion
diff --git a/src/plugins/value/engine/transfer_stmt.ml b/src/plugins/value/engine/transfer_stmt.ml
index 10fd7aad07a7a8f2bad9703f492797dc77d931e3..eaaaca8f6733d99e76d54f3c5fae6dada4135fa8 100644
--- a/src/plugins/value/engine/transfer_stmt.ml
+++ b/src/plugins/value/engine/transfer_stmt.ml
@@ -27,7 +27,7 @@ open Eval
 module type S = sig
   type state
   type value
-  type location
+  type loc
   val assign: state -> kinstr -> lval -> exp -> state or_bottom
   val assume: state -> stmt -> exp -> bool -> state or_bottom
   val call:
@@ -44,7 +44,7 @@ module type S = sig
     builtin: bool;
   }
   val compute_call_ref:
-    (stmt -> (location, value) call -> state -> call_result) ref
+    (stmt -> (loc, value) call -> recursion option ->state -> call_result) ref
 end
 
 (* Reference filled in by the callwise-inout callback *)
@@ -105,6 +105,17 @@ module DumpFileCounters =
       let name = "Transfer_stmt.DumpFileCounters"
     end)
 
+module VarHashtbl = Cil_datatype.Varinfo.Hashtbl
+
+let substitution_visitor table = object
+  inherit Visitor.frama_c_copy (Project.current ())
+
+  method! vvrbl varinfo =
+    match VarHashtbl.find_opt table varinfo with
+    | None -> Cil.JustCopy
+    | Some lval -> Cil.ChangeTo lval
+end
+
 module Make (Abstract: Abstractions.Eva) = struct
 
   module Value = Abstract.Val
@@ -114,7 +125,7 @@ module Make (Abstract: Abstractions.Eva) = struct
 
   type state = Domain.t
   type value = Value.t
-  type location = Location.location
+  type loc = Location.location
 
   (* When using a product of domains, a product of states may have no
      concretization (if the domains have inferred incompatible properties)
@@ -295,8 +306,8 @@ module Make (Abstract: Abstractions.Eva) = struct
   }
 
   (* Forward reference to [Eval_funs.compute_call] *)
-  let compute_call_ref
-    : (stmt -> (location, value) call -> Domain.state -> call_result) ref
+  let compute_call_ref :
+    (stmt -> (loc, value) call -> recursion option -> state -> call_result) ref
     = ref (fun _ -> assert false)
 
   (* Returns the result of a call, and a boolean that indicates whether a
@@ -315,7 +326,7 @@ module Make (Abstract: Abstractions.Eva) = struct
         match Domain.start_call stmt call recursion domain_valuation state with
         | `Value state ->
           Domain.Store.register_initial_state (Value_util.call_stack ()) state;
-          !compute_call_ref stmt call state
+          !compute_call_ref stmt call recursion state
         | `Bottom ->
           { states = `Bottom; cacheable = Cacheable; builtin=false }
       in
@@ -526,7 +537,6 @@ module Make (Abstract: Abstractions.Eva) = struct
 
   (* Create an Eval.call *)
   let create_call kf args =
-    let recursive = Recursion.is_recursive_call kf in
     let return = Library_functions.get_retres_vi kf in
     let arguments, rest =
       let formals = Kernel_function.get_formals kf in
@@ -541,9 +551,9 @@ module Make (Abstract: Abstractions.Eva) = struct
       let arguments = List.rev arguments in
       arguments, rest
     in
-    {kf; arguments; rest; return; recursive; }
+    {kf; arguments; rest; return; }
 
-  let substitute_assigned_value substitution = function
+  let replace_value substitution = function
     | Assign value -> Assign (Value.replace_base substitution value)
     | Copy (loc, flagged) ->
       let v = flagged.v >>-: Value.replace_base substitution in
@@ -551,13 +561,17 @@ module Make (Abstract: Abstractions.Eva) = struct
       (* TODO: replace base in [loc] *)
       Copy (loc, flagged)
 
-  let substitute_argument substitution argument =
-    let avalue = substitute_assigned_value substitution argument.avalue in
-    { argument with avalue }
-
-  let substitute_call substitution call =
-    let arguments = List.map (substitute_argument substitution) call.arguments in
-    { call with arguments }
+  let replace_recursive_call recursion call =
+    let tbl = VarHashtbl.create 9 in
+    List.iter (fun (v1, v2) -> VarHashtbl.add tbl v1 v2) recursion.substitution;
+    let visitor = substitution_visitor tbl in
+    let replace_arg argument =
+      let concrete = Visitor.visitFramacExpr visitor argument.concrete in
+      let avalue = replace_value recursion.base_substitution argument.avalue in
+      { argument with concrete; avalue }
+    in
+    let arguments = List.map replace_arg call.arguments in
+    { call with arguments; }
 
   let make_call ~subdivnb kf arguments valuation state =
     (* Evaluate the arguments of the call. *)
@@ -565,16 +579,8 @@ module Make (Abstract: Abstractions.Eva) = struct
     compute_actuals ~subdivnb ~determinate valuation state arguments
     >>=: fun (args, valuation) ->
     let call = create_call kf args in
-    let recursion =
-      if call.recursive
-      then Some (Recursion.make_recursive_call call.kf)
-      else None
-    in
-    let call =
-      match recursion with
-      | None -> call
-      | Some recursion -> substitute_call recursion.base_substitution call
-    in
+    let recursion = Recursion.get_recursion kf in
+    let call = Extlib.opt_fold replace_recursive_call recursion call in
     call, recursion, valuation
 
   (* ----------------- show_each and dump_each directives ------------------- *)
diff --git a/src/plugins/value/engine/transfer_stmt.mli b/src/plugins/value/engine/transfer_stmt.mli
index af7e5fa3e7383125abfbb9101e64a23d5b8f9baf..87c505e24111ca06f51ce4a9cb5ee3fe9178c788 100644
--- a/src/plugins/value/engine/transfer_stmt.mli
+++ b/src/plugins/value/engine/transfer_stmt.mli
@@ -29,7 +29,7 @@ module type S = sig
 
   type state
   type value
-  type location
+  type loc
 
   val assign: state -> kinstr -> lval -> exp -> state or_bottom
 
@@ -55,13 +55,13 @@ module type S = sig
   }
 
   val compute_call_ref:
-    (stmt -> (location, value) call -> state -> call_result) ref
+    (stmt -> (loc, value) call -> recursion option -> state -> call_result) ref
 end
 
 module Make (Abstract: Abstractions.Eva)
   : S with type state = Abstract.Dom.t
        and type value = Abstract.Val.t
-       and type location = Abstract.Loc.location
+       and type loc = Abstract.Loc.location
 
 (*
 Local Variables:
diff --git a/src/plugins/value/eval.ml b/src/plugins/value/eval.ml
index ab4e77305f48391e739b76186615836e4bda4c36..74eb76353824f011548ccc8fe7727b42262cda2e 100644
--- a/src/plugins/value/eval.ml
+++ b/src/plugins/value/eval.ml
@@ -245,7 +245,6 @@ type ('loc, 'value) call = {
   arguments: ('loc, 'value) argument list;
   rest: (exp * ('loc, 'value) assigned) list;
   return: varinfo option;
-  recursive: bool;
 }
 
 type recursion = {
diff --git a/src/plugins/value/eval.mli b/src/plugins/value/eval.mli
index ef1a1937757b26c68da7c2857e2bf350e902f857..c64f692b7bd70ac3b95eee342519317c3e0cb11a 100644
--- a/src/plugins/value/eval.mli
+++ b/src/plugins/value/eval.mli
@@ -231,7 +231,6 @@ type ('loc, 'value) call = {
                                                   return value of the call.
                                                   Same varinfo for every
                                                   call to a given function. *)
-  recursive: bool;
 }
 
 (** Information needed to interpret a recursive call.