From 8485cd471969b628568ee5c82a363b620b6d6346 Mon Sep 17 00:00:00 2001
From: Allan Blanchard <allan.blanchard@cea.fr>
Date: Mon, 14 Oct 2019 15:31:04 +0200
Subject: [PATCH] [Builtin] Now generates function definitions

---
 src/plugins/builtin/basic_blocks.ml           | 25 +++++++
 src/plugins/builtin/basic_blocks.mli          |  4 ++
 src/plugins/builtin/builtin_cache.ml          | 23 +++---
 src/plugins/builtin/builtin_cache.mli         |  4 +-
 src/plugins/builtin/memcmp.ml                 | 72 ++++++++++---------
 src/plugins/builtin/memcpy.ml                 | 65 +++++++++--------
 src/plugins/builtin/memmove.ml                | 64 +++++++++--------
 .../tests/functions/oracle/memcmp.res.oracle  | 32 +++++++--
 .../tests/functions/oracle/memcpy.res.oracle  | 32 +++++++--
 .../tests/functions/oracle/memmove.res.oracle | 32 +++++++--
 src/plugins/builtin/tests/test_config         |  2 +-
 src/plugins/builtin/transform.ml              | 39 +++++-----
 src/plugins/builtin/transform.mli             |  4 +-
 13 files changed, 257 insertions(+), 141 deletions(-)

diff --git a/src/plugins/builtin/basic_blocks.ml b/src/plugins/builtin/basic_blocks.ml
index 633b0cb10fa..65ae46edd4e 100644
--- a/src/plugins/builtin/basic_blocks.ml
+++ b/src/plugins/builtin/basic_blocks.ml
@@ -31,6 +31,31 @@ let const_of t = Cil.typeAddAttributes [Attr("const", [])] t
 let size_t () =
   Globals.Types.find_type Logic_typing.Typedef "size_t"
 
+let prepare_definition name fun_type =
+  let vi = Cil.makeGlobalVar ~referenced:true name fun_type in
+  let fd = Cil.emptyFunctionFromVI vi in
+  Cil.setFormalsDecl vi fun_type ;
+  fd.sformals <- Cil.getFormalsDecl vi ;
+  fd
+
+let set_function_body fd body =
+  fd.sbody <- body ;
+  fd.svar.vdefined <- true ;
+  File.must_recompute_cfg fd
+
+let call_function lval name args =
+  let open Globals.Functions in
+  let loc  = Cil_datatype.Location.unknown in
+  let vi = get_vi (find_by_name name) in
+  let _, typs, _, _ = Cil.splitFunctionTypeVI vi in
+  let typs = Cil.argsToList typs in
+  let gen_arg exp (_, typ, _) =
+    if Cil_datatype.Typ.equal vi.vtype typ then exp
+    else Cil.mkCast exp typ
+  in
+  let args = List.map2 gen_arg args typs in
+  Call(lval, (Cil.evar vi), args, loc)
+
 let rec string_of_typ_aux = function
   | TInt(IBool, _) -> "bool"
   | TInt(IChar, _) -> "char"
diff --git a/src/plugins/builtin/basic_blocks.mli b/src/plugins/builtin/basic_blocks.mli
index 7ece0de7ecc..642e8c1b69f 100644
--- a/src/plugins/builtin/basic_blocks.mli
+++ b/src/plugins/builtin/basic_blocks.mli
@@ -27,6 +27,10 @@ val const_of: typ -> typ
 
 val size_t: unit -> typ
 
+val prepare_definition: string -> typ -> fundec
+val set_function_body: fundec -> block -> unit
+val call_function: lval option -> string -> exp list -> instr
+
 val string_of_typ: typ -> string
 
 val ttype_of_pointed: logic_type -> logic_type
diff --git a/src/plugins/builtin/builtin_cache.ml b/src/plugins/builtin/builtin_cache.ml
index a4f3ac5ed30..e1ad5716ab7 100644
--- a/src/plugins/builtin/builtin_cache.ml
+++ b/src/plugins/builtin/builtin_cache.ml
@@ -21,19 +21,19 @@
 (**************************************************************************)
 
 module type Table = sig
-  val get_function: Cil_types.typ -> Cil_types.varinfo
+  val get_varinfo: Cil_types.typ -> Cil_types.varinfo
   val get_globals: Cil_types.location -> Cil_types.global list
   val mark_as_computed: ?project:Project.t -> unit -> unit
 end
 
 module type Generator = sig
   val function_name: String.t
-  val build_prototype: Cil_types.typ -> Cil_types.varinfo
+  val build_function: Cil_types.typ -> Cil_types.fundec
   val build_spec: Cil_types.varinfo -> Cil_types.location -> Cil_types.funspec
 end
 
 module Make_internal_table (M: Generator) =
-  (State_builder.Hashtbl(Cil_datatype.Typ.Hashtbl) (Cil_datatype.Varinfo)
+  (State_builder.Hashtbl(Cil_datatype.Typ.Hashtbl) (Cil_datatype.Fundec)
      (struct
        let size = 5
        let dependencies = [Ast.self]
@@ -42,19 +42,20 @@ module Make_internal_table (M: Generator) =
 
 module Make (Generator: Generator) = struct
   module Internal_table = Make_internal_table(Generator)
+  open Cil_types
 
-  let get_function t = try
-      Internal_table.find t
+  let get_varinfo t = try
+      (Internal_table.find t).svar
     with Not_found ->
-      let fct = Generator.build_prototype t in
+      let fct = Generator.build_function t in
       Internal_table.add t fct ;
-      fct
+      fct.svar
 
   let get_globals loc =
-    let finalize vi =
-      let spec = Generator.build_spec vi loc in
-      Globals.Functions.replace_by_declaration spec vi loc ;
-      Cil_types.GFunDecl(Cil.empty_funspec(), vi, loc)
+    let finalize fd =
+      let spec = Generator.build_spec (fd.svar) loc in
+      Globals.Functions.replace_by_definition spec fd loc ;
+      Cil_types.GFun(fd, loc)
     in
     Internal_table.fold (fun _ vi l -> (finalize vi) :: l) []
 
diff --git a/src/plugins/builtin/builtin_cache.mli b/src/plugins/builtin/builtin_cache.mli
index 1252adcfc6f..c8c5c52968d 100644
--- a/src/plugins/builtin/builtin_cache.mli
+++ b/src/plugins/builtin/builtin_cache.mli
@@ -22,12 +22,12 @@
 
 module type Generator = sig
   val function_name: String.t
-  val build_prototype: Cil_types.typ -> Cil_types.varinfo
+  val build_function: Cil_types.typ -> Cil_types.fundec
   val build_spec: Cil_types.varinfo -> Cil_types.location -> Cil_types.funspec
 end
 
 module type Table = sig
-  val get_function: Cil_types.typ -> Cil_types.varinfo
+  val get_varinfo: Cil_types.typ -> Cil_types.varinfo
   val get_globals: Cil_types.location -> Cil_types.global list
   val mark_as_computed: ?project:Project.t -> unit -> unit
 end
diff --git a/src/plugins/builtin/memcmp.ml b/src/plugins/builtin/memcmp.ml
index 89fdc1c43b3..fe1caaaa3f3 100644
--- a/src/plugins/builtin/memcmp.ml
+++ b/src/plugins/builtin/memcmp.ml
@@ -38,14 +38,14 @@ let presult_memcmp ?loc p1 p2 len =
   let res = prel ?loc (Req, (tresult ?loc Cil.intType), (tinteger ?loc 0)) in
   piff ?loc (res, eq)
 
-let generate_assigns loc t s1 s2 len =
+let generate_assigns loc s1 s2 len =
   let indirect_range loc s len =
     let t = { (tunref_range ~loc s len) with term_name = ["indirect"] } in
     new_identified_term t
   in
   let s1_range = indirect_range loc s1 len in
   let s2_range = indirect_range loc s2 len in
-  let result = new_identified_term (tresult t) in
+  let result = new_identified_term (tresult Cil.intType) in
   let res = result, From [s1_range ; s2_range] in
   Writes [ res ]
 
@@ -62,63 +62,69 @@ let generate_spec vi loc =
     | [ s1 ; s2 ; len ] -> s1, s2, len
     | _ -> assert false
   in
-  let t = c_s1.vtype in
   let s1 = cvar_to_tvar c_s1 in
   let s2 = cvar_to_tvar c_s2 in
   let len = cvar_to_tvar clen in
   let requires = generate_requires loc s1 s2 len in
-  let assigns  = generate_assigns loc t s1 s2 len in
+  let assigns  = generate_assigns loc s1 s2 len in
   let ensures  = generate_ensures loc s1 s2 len in
   make_funspec [make_behavior ~requires ~assigns ~ensures ()] ()
 
-let generate_prototype t =
-  let name = function_name ^ "_" ^ (string_of_typ t) in
+let generate_function_type t =
   let t = ptr_of (const_of t) in
   let params = [
     ("s1", t, []) ;
     ("s2", t, []) ;
     ("len", size_t (), [])
   ] in
-  let fun_t = TFun(Cil.intType, Some params, false, []) in
-  let vi = Cil.makeGlobalVar ~referenced:true name fun_t in
-  Cil.setFormalsDecl vi fun_t ;
-  vi
+  TFun(Cil.intType, Some params, false, [])
+
+let generate_body fd =
+  let loc  = Cil_datatype.Location.unknown in
+  let rv   = Cil.makeLocalVar fd "__retres" Cil.intType in
+  let args = List.map Cil.evar fd.sformals in
+  let call = Instr(call_function (Some (Var rv, NoOffset)) function_name args) in
+  let ret  = Return (Some (Cil.evar rv), loc) in
+  let block = Cil.mkBlock (List.map Cil.mkStmt [ call ; ret]) in
+  block.blocals <- [ rv ] ;
+  block
+
+let generate_function t =
+  let name = function_name ^ "_" ^ (string_of_typ t) in
+  let fun_t = generate_function_type t in
+  let fd = prepare_definition name fun_t in
+  set_function_body fd (generate_body fd) ;
+  fd
 
 module Table = Builtin_cache.Make(struct
     let function_name = function_name
-    let build_prototype = generate_prototype
+    let build_function = generate_function
     let build_spec = generate_spec
   end)
 
 let type_from_parameter x =
-  let x = Cil.stripCasts x in
   let xt = Cil.unrollTypeDeep (Cil.typeOf x) in
   let xt = Cil.type_remove_qualifier_attributes_deep xt in
   Cil.typeOf_pointed xt
 
-let well_typed_parameters s1 s2 =
-  let s1_t = type_from_parameter s1 in
-  let s2_t = type_from_parameter s2 in
-  Cil_datatype.Typ.equal s1_t s2_t
-
-let create_call fct (s1, s2, len) =
-  if well_typed_parameters s1 s2 then
-    let typ = type_from_parameter s1 in
-    let fct = Table.get_function typ in
+let replace_call = function
+  | (_fct, [ s1 ; s2 ; len ]) ->
     let s1 = Cil.stripCasts s1 in
     let s2 = Cil.stripCasts s2 in
-    fct, (s1, s2, len)
-  else
-    fct, (s1, s2, len)
-
-let replace_call = function
-  | Call(r, ({ enode = Lval((Var fct), NoOffset) } as e), [ s1 ; s2 ; len ], loc) ->
-    let fct, (s1, s2, len) = create_call fct (s1, s2, len) in
-    Call(r, { e with enode = Lval((Var fct), NoOffset) }, [ s1 ; s2 ; len ], loc)
-  | Local_init(r, ConsInit(fct, [ s1 ; s2 ; len ], Plain_func), loc) ->
-    let fct, (s1, s2, len) = create_call fct (s1, s2, len) in
-    Local_init(r, ConsInit(fct, [ s1 ; s2 ; len ], Plain_func), loc)
-  | _ -> assert false
+    let s1_t = type_from_parameter s1 in
+    let s2_t = type_from_parameter s2 in
+    if Cil_datatype.Typ.equal s1_t s2_t then
+      (Table.get_varinfo s1_t), [ s1 ; s2 ; len ]
+    else
+      let msg =
+        Format.asprintf "incompatible types for %s: src:%a(%a) dest:%a(%a)"
+          function_name
+          Cil_printer.pp_exp s1 Cil_printer.pp_typ s1_t
+          Cil_printer.pp_exp s2 Cil_printer.pp_typ s2_t
+      in
+      raise (Transform.Bad_typing msg)
+  | (_, _) ->
+    raise (Transform.Bad_typing ("Expected 3 arguments for " ^ function_name))
 
 let () = Transform.register (module struct
     let function_name = function_name
diff --git a/src/plugins/builtin/memcpy.ml b/src/plugins/builtin/memcpy.ml
index 5ecf6c306bb..0beafb0463d 100644
--- a/src/plugins/builtin/memcpy.ml
+++ b/src/plugins/builtin/memcpy.ml
@@ -73,8 +73,7 @@ let generate_spec vi loc =
   let ensures  = generate_ensures loc t dest src len in
   make_funspec [make_behavior ~requires ~assigns ~ensures ()] ()
 
-let generate_prototype t =
-  let name = function_name ^ "_" ^ (string_of_typ t) in
+let generate_function_type t =
   let dt = ptr_of t in
   let st = ptr_of (const_of t) in
   let params = [
@@ -82,46 +81,54 @@ let generate_prototype t =
     ("src", st, []) ;
     ("len", size_t (), [])
   ] in
-  let fun_t = TFun(dt, Some params, false, []) in
-  let vi = Cil.makeGlobalVar ~referenced:true name fun_t in
-  Cil.setFormalsDecl vi fun_t ;
-  vi
+  TFun(dt, Some params, false, [])
+
+let generate_body t fd =
+  let loc  = Cil_datatype.Location.unknown in
+  let rv   = Cil.makeLocalVar fd "__retres" (TPtr(t, [])) in
+  let args = List.map Cil.evar fd.sformals in
+  let call = Instr(call_function (Some (Var rv, NoOffset)) function_name args) in
+  let ret  = Return (Some (Cil.evar rv), loc) in
+  let block = Cil.mkBlock (List.map Cil.mkStmt [ call ; ret]) in
+  block.blocals <- [ rv ] ;
+  block
+
+let generate_function t =
+  let name = function_name ^ "_" ^ (string_of_typ t) in
+  let fun_t = generate_function_type t in
+  let fd = prepare_definition name fun_t in
+  set_function_body fd (generate_body t fd) ;
+  fd
 
 module Table = Builtin_cache.Make(struct
     let function_name = function_name
-    let build_prototype = generate_prototype
+    let build_function = generate_function
     let build_spec = generate_spec
   end)
 
 let type_from_parameter x =
-  let x = Cil.stripCasts x in
   let xt = Cil.unrollTypeDeep (Cil.typeOf x) in
   let xt = Cil.type_remove_qualifier_attributes_deep xt in
   Cil.typeOf_pointed xt
 
-let well_typed_parameters dest src =
-  let dt = type_from_parameter dest in
-  let st = type_from_parameter src in
-  Cil_datatype.Typ.equal dt st
-
-let create_call fct (dest, src, len) =
-  if well_typed_parameters dest src then
-    let typ = type_from_parameter dest in
-    let fct = Table.get_function typ in
+let replace_call = function
+  | (_fct, [ dest ; src ; len ]) ->
     let dest = Cil.stripCasts dest in
     let src = Cil.stripCasts src in
-    fct, (dest, src, len)
-  else
-    fct, (dest, src, len)
-
-let replace_call = function
-  | Call(r, ({ enode = Lval((Var fct), NoOffset) } as e), [ dest ; src ; len ], loc) ->
-    let fct, (dest, src, len) = create_call fct (dest, src, len) in
-    Call(r, { e with enode = Lval((Var fct), NoOffset) }, [ dest ; src ; len ], loc)
-  | Local_init(r, ConsInit(fct, [ dest ; src ; len ], Plain_func), loc) ->
-    let fct, (dest, src, len) = create_call fct (dest, src, len) in
-    Local_init(r, ConsInit(fct, [ dest ; src ; len ], Plain_func), loc)
-  | _ -> assert false
+    let dt = type_from_parameter dest in
+    let st = type_from_parameter src in
+    if Cil_datatype.Typ.equal dt st then
+      (Table.get_varinfo dt), [ dest ; src ; len ]
+    else
+      let msg =
+        Format.asprintf "incompatible types for %s: src:%a(%a) dest:%a(%a)"
+          function_name
+          Cil_printer.pp_exp dest Cil_printer.pp_typ dt
+          Cil_printer.pp_exp src Cil_printer.pp_typ st
+      in
+      raise (Transform.Bad_typing msg)
+  | (_, _) ->
+    raise (Transform.Bad_typing ("Expected 3 arguments for " ^ function_name))
 
 let () = Transform.register (module struct
     let function_name = function_name
diff --git a/src/plugins/builtin/memmove.ml b/src/plugins/builtin/memmove.ml
index 0084c68dc78..78f105b3e15 100644
--- a/src/plugins/builtin/memmove.ml
+++ b/src/plugins/builtin/memmove.ml
@@ -68,8 +68,7 @@ let generate_spec vi loc =
   let ensures  = generate_ensures loc t dest src len in
   make_funspec [make_behavior ~requires ~assigns ~ensures ()] ()
 
-let generate_prototype t =
-  let name = function_name ^ "_" ^ (string_of_typ t) in
+let generate_function_type t =
   let dt = ptr_of t in
   let st = ptr_of (const_of t) in
   let params = [
@@ -77,14 +76,28 @@ let generate_prototype t =
     ("src", st, []) ;
     ("len", size_t (), [])
   ] in
-  let fun_t = TFun(dt, Some params, false, []) in
-  let vi = Cil.makeGlobalVar ~referenced:true name fun_t in
-  Cil.setFormalsDecl vi fun_t ;
-  vi
+  TFun(dt, Some params, false, [])
+
+let generate_body t fd =
+  let loc  = Cil_datatype.Location.unknown in
+  let rv   = Cil.makeLocalVar fd "__retres" (TPtr(t, [])) in
+  let args = List.map Cil.evar fd.sformals in
+  let call = Instr(call_function (Some (Var rv, NoOffset)) function_name args) in
+  let ret  = Return (Some (Cil.evar rv), loc) in
+  let block = Cil.mkBlock (List.map Cil.mkStmt [ call ; ret]) in
+  block.blocals <- [ rv ] ;
+  block
+
+let generate_function t =
+  let name = function_name ^ "_" ^ (string_of_typ t) in
+  let fun_t = generate_function_type t in
+  let fd = prepare_definition name fun_t in
+  set_function_body fd (generate_body t fd) ;
+  fd
 
 module Table = Builtin_cache.Make(struct
     let function_name = function_name
-    let build_prototype = generate_prototype
+    let build_function = generate_function
     let build_spec = generate_spec
   end)
 
@@ -94,29 +107,24 @@ let type_from_parameter x =
   let xt = Cil.type_remove_qualifier_attributes_deep xt in
   Cil.typeOf_pointed xt
 
-let well_typed_parameters dest src =
-  let dt = type_from_parameter dest in
-  let st = type_from_parameter src in
-  Cil_datatype.Typ.equal dt st
-
-let create_call fct (dest, src, len) =
-  if well_typed_parameters dest src then
-    let typ = type_from_parameter dest in
-    let fct = Table.get_function typ in
+let replace_call = function
+  | (_fct, [ dest ; src ; len ]) ->
     let dest = Cil.stripCasts dest in
     let src = Cil.stripCasts src in
-    fct, (dest, src, len)
-  else
-    fct, (dest, src, len)
-
-let replace_call = function
-  | Call(r, ({ enode = Lval((Var fct), NoOffset) } as e), [ dest ; src ; len ], loc) ->
-    let fct, (dest, src, len) = create_call fct (dest, src, len) in
-    Call(r, { e with enode = Lval((Var fct), NoOffset) }, [ dest ; src ; len ], loc)
-  | Local_init(r, ConsInit(fct, [ dest ; src ; len ], Plain_func), loc) ->
-    let fct, (dest, src, len) = create_call fct (dest, src, len) in
-    Local_init(r, ConsInit(fct, [ dest ; src ; len ], Plain_func), loc)
-  | _ -> assert false
+    let dt = type_from_parameter dest in
+    let st = type_from_parameter src in
+    if Cil_datatype.Typ.equal dt st then
+      (Table.get_varinfo dt), [ dest ; src ; len ]
+    else
+      let msg =
+        Format.asprintf "incompatible types for %s: src:%a(%a) dest:%a(%a)"
+          function_name
+          Cil_printer.pp_exp dest Cil_printer.pp_typ dt
+          Cil_printer.pp_exp src Cil_printer.pp_typ st
+      in
+      raise (Transform.Bad_typing msg)
+  | (_, _) ->
+    raise (Transform.Bad_typing ("Expected 3 arguments for " ^ function_name))
 
 let () = Transform.register (module struct
     let function_name = function_name
diff --git a/src/plugins/builtin/tests/functions/oracle/memcmp.res.oracle b/src/plugins/builtin/tests/functions/oracle/memcmp.res.oracle
index 456152c88ff..15722b10875 100644
--- a/src/plugins/builtin/tests/functions/oracle/memcmp.res.oracle
+++ b/src/plugins/builtin/tests/functions/oracle/memcmp.res.oracle
@@ -23,7 +23,12 @@
       \from (indirect: (*(s1 + (0 .. len - 1)))[0 .. 10 - 1]),
             (indirect: (*(s2 + (0 .. len - 1)))[0 .. 10 - 1]);
  */
-int memcmp_arr10_int(int const (*s1)[10], int const (*s2)[10], size_t len);
+int memcmp_arr10_int(int const (*s1)[10], int const (*s2)[10], size_t len)
+{
+  int __retres;
+  __retres = memcmp((void const *)s1,(void const *)s2,len);
+  return __retres;
+}
 
 /*@ requires aligned_end: len % 4 ≡ 0;
     requires
@@ -42,7 +47,12 @@ int memcmp_arr10_int(int const (*s1)[10], int const (*s2)[10], size_t len);
       \from (indirect: *(s1 + (0 .. len - 1))),
             (indirect: *(s2 + (0 .. len - 1)));
  */
-int memcmp_int(int const *s1, int const *s2, size_t len);
+int memcmp_int(int const *s1, int const *s2, size_t len)
+{
+  int __retres;
+  __retres = memcmp((void const *)s1,(void const *)s2,len);
+  return __retres;
+}
 
 int main(void)
 {
@@ -65,9 +75,9 @@ int nested(int (*dest)[10], int (*src)[10], size_t n)
 [kernel] Parsing tests/functions/result/memcmp.c (with preprocessing)
 [kernel] Parsing tests/functions/memcmp.c (with preprocessing)
 [kernel] tests/functions/memcmp.c:3: Warning: 
-  def'n of func main at tests/functions/memcmp.c:3 (sum 2855) conflicts with the one at tests/functions/result/memcmp.c:46 (sum 4629); keeping the one at tests/functions/result/memcmp.c:46.
+  def'n of func main at tests/functions/memcmp.c:3 (sum 2855) conflicts with the one at tests/functions/result/memcmp.c:56 (sum 4629); keeping the one at tests/functions/result/memcmp.c:56.
 [kernel] tests/functions/memcmp.c:10: Warning: 
-  def'n of func nested at tests/functions/memcmp.c:10 (sum 1087) conflicts with the one at tests/functions/result/memcmp.c:56 (sum 1974); keeping the one at tests/functions/result/memcmp.c:56.
+  def'n of func nested at tests/functions/memcmp.c:10 (sum 1087) conflicts with the one at tests/functions/result/memcmp.c:66 (sum 1974); keeping the one at tests/functions/result/memcmp.c:66.
 /* Generated by Frama-C */
 #include "stddef.h"
 #include "string.h"
@@ -93,7 +103,12 @@ int nested(int (*dest)[10], int (*src)[10], size_t n)
       \from (indirect: (*(s1 + (0 .. len - 1)))[0 .. 10 - 1]),
             (indirect: (*(s2 + (0 .. len - 1)))[0 .. 10 - 1]);
  */
-int memcmp_arr10_int(int const (*s1)[10], int const (*s2)[10], size_t len);
+int memcmp_arr10_int(int const (*s1)[10], int const (*s2)[10], size_t len)
+{
+  int __retres;
+  __retres = memcmp((void const *)s1,(void const *)s2,len);
+  return __retres;
+}
 
 /*@ requires aligned_end: len % 4 ≡ 0;
     requires
@@ -113,7 +128,12 @@ int memcmp_arr10_int(int const (*s1)[10], int const (*s2)[10], size_t len);
       \from (indirect: *(s1 + (0 .. len - 1))),
             (indirect: *(s2 + (0 .. len - 1)));
  */
-int memcmp_int(int const *s1, int const *s2, size_t len);
+int memcmp_int(int const *s1, int const *s2, size_t len)
+{
+  int __retres;
+  __retres = memcmp((void const *)s1,(void const *)s2,len);
+  return __retres;
+}
 
 int main(void)
 {
diff --git a/src/plugins/builtin/tests/functions/oracle/memcpy.res.oracle b/src/plugins/builtin/tests/functions/oracle/memcpy.res.oracle
index 86774bd9c82..b9fb245dddd 100644
--- a/src/plugins/builtin/tests/functions/oracle/memcpy.res.oracle
+++ b/src/plugins/builtin/tests/functions/oracle/memcpy.res.oracle
@@ -27,7 +27,12 @@
       \from (*(src + (0 .. len - 1)))[0 .. 10 - 1];
     assigns \result \from dest;
  */
-int (*memcpy_arr10_int(int (*dest)[10], int const (*src)[10], size_t len))[10];
+int (*memcpy_arr10_int(int (*dest)[10], int const (*src)[10], size_t len))[10]
+{
+  int (*__retres)[10];
+  __retres = (int (*)[10])memcpy((void *)dest,(void const *)src,len);
+  return __retres;
+}
 
 /*@ requires aligned_end: len % 4 ≡ 0;
     requires
@@ -48,7 +53,12 @@ int (*memcpy_arr10_int(int (*dest)[10], int const (*src)[10], size_t len))[10];
     assigns *(dest + (0 .. len - 1)) \from *(src + (0 .. len - 1));
     assigns \result \from dest;
  */
-int *memcpy_int(int *dest, int const *src, size_t len);
+int *memcpy_int(int *dest, int const *src, size_t len)
+{
+  int *__retres;
+  __retres = (int *)memcpy((void *)dest,(void const *)src,len);
+  return __retres;
+}
 
 int main(void)
 {
@@ -70,9 +80,9 @@ void nested(int (*dest)[10], int (*src)[10], size_t n)
 [kernel] Parsing tests/functions/result/memcpy.c (with preprocessing)
 [kernel] Parsing tests/functions/memcpy.c (with preprocessing)
 [kernel] tests/functions/memcpy.c:3: Warning: 
-  def'n of func main at tests/functions/memcpy.c:3 (sum 1968) conflicts with the one at tests/functions/result/memcpy.c:52 (sum 3742); keeping the one at tests/functions/result/memcpy.c:52.
+  def'n of func main at tests/functions/memcpy.c:3 (sum 1968) conflicts with the one at tests/functions/result/memcpy.c:62 (sum 3742); keeping the one at tests/functions/result/memcpy.c:62.
 [kernel] tests/functions/memcpy.c:10: Warning: 
-  dropping duplicate def'n of func nested at tests/functions/memcpy.c:10 in favor of that at tests/functions/result/memcpy.c:62
+  dropping duplicate def'n of func nested at tests/functions/memcpy.c:10 in favor of that at tests/functions/result/memcpy.c:72
 /* Generated by Frama-C */
 #include "stddef.h"
 #include "string.h"
@@ -102,7 +112,12 @@ void nested(int (*dest)[10], int (*src)[10], size_t n)
       \from (*(src + (0 .. len - 1)))[0 .. 10 - 1];
     assigns \result \from dest;
  */
-int (*memcpy_arr10_int(int (*dest)[10], int const (*src)[10], size_t len))[10];
+int (*memcpy_arr10_int(int (*dest)[10], int const (*src)[10], size_t len))[10]
+{
+  int (*__retres)[10];
+  __retres = (int (*)[10])memcpy((void *)dest,(void const *)src,len);
+  return __retres;
+}
 
 /*@ requires aligned_end: len % 4 ≡ 0;
     requires
@@ -124,7 +139,12 @@ int (*memcpy_arr10_int(int (*dest)[10], int const (*src)[10], size_t len))[10];
     assigns *(dest + (0 .. len - 1)) \from *(src + (0 .. len - 1));
     assigns \result \from dest;
  */
-int *memcpy_int(int *dest, int const *src, size_t len);
+int *memcpy_int(int *dest, int const *src, size_t len)
+{
+  int *__retres;
+  __retres = (int *)memcpy((void *)dest,(void const *)src,len);
+  return __retres;
+}
 
 int main(void)
 {
diff --git a/src/plugins/builtin/tests/functions/oracle/memmove.res.oracle b/src/plugins/builtin/tests/functions/oracle/memmove.res.oracle
index 314166b974d..fc95dbda3e2 100644
--- a/src/plugins/builtin/tests/functions/oracle/memmove.res.oracle
+++ b/src/plugins/builtin/tests/functions/oracle/memmove.res.oracle
@@ -25,7 +25,12 @@
       \from (*(src + (0 .. len - 1)))[0 .. 10 - 1];
     assigns \result \from dest;
  */
-int (*memmove_arr10_int(int (*dest)[10], int const (*src)[10], size_t len))[10];
+int (*memmove_arr10_int(int (*dest)[10], int const (*src)[10], size_t len))[10]
+{
+  int (*__retres)[10];
+  __retres = (int (*)[10])memmove((void *)dest,(void const *)src,len);
+  return __retres;
+}
 
 /*@ requires aligned_end: len % 4 ≡ 0;
     requires
@@ -42,7 +47,12 @@ int (*memmove_arr10_int(int (*dest)[10], int const (*src)[10], size_t len))[10];
     assigns *(dest + (0 .. len - 1)) \from *(src + (0 .. len - 1));
     assigns \result \from dest;
  */
-int *memmove_int(int *dest, int const *src, size_t len);
+int *memmove_int(int *dest, int const *src, size_t len)
+{
+  int *__retres;
+  __retres = (int *)memmove((void *)dest,(void const *)src,len);
+  return __retres;
+}
 
 int main(void)
 {
@@ -69,9 +79,9 @@ int *nested(int (*dest)[10], int (*src)[10], size_t n)
 [kernel] tests/functions/memmove.c:11: Warning: 
   Body of function nested falls-through. Adding a return statement
 [kernel] tests/functions/memmove.c:3: Warning: 
-  def'n of func main at tests/functions/memmove.c:3 (sum 1968) conflicts with the one at tests/functions/result/memmove.c:44 (sum 3742); keeping the one at tests/functions/result/memmove.c:44.
+  def'n of func main at tests/functions/memmove.c:3 (sum 1968) conflicts with the one at tests/functions/result/memmove.c:54 (sum 3742); keeping the one at tests/functions/result/memmove.c:54.
 [kernel] tests/functions/memmove.c:10: Warning: 
-  def'n of func nested at tests/functions/memmove.c:10 (sum 1974) conflicts with the one at tests/functions/result/memmove.c:54 (sum 4635); keeping the one at tests/functions/result/memmove.c:54.
+  def'n of func nested at tests/functions/memmove.c:10 (sum 1974) conflicts with the one at tests/functions/result/memmove.c:64 (sum 4635); keeping the one at tests/functions/result/memmove.c:64.
 /* Generated by Frama-C */
 #include "stddef.h"
 #include "string.h"
@@ -97,7 +107,12 @@ int *nested(int (*dest)[10], int (*src)[10], size_t n)
       \from (*(src + (0 .. len - 1)))[0 .. 10 - 1];
     assigns \result \from dest;
  */
-int (*memmove_arr10_int(int (*dest)[10], int const (*src)[10], size_t len))[10];
+int (*memmove_arr10_int(int (*dest)[10], int const (*src)[10], size_t len))[10]
+{
+  int (*__retres)[10];
+  __retres = (int (*)[10])memmove((void *)dest,(void const *)src,len);
+  return __retres;
+}
 
 /*@ requires aligned_end: len % 4 ≡ 0;
     requires
@@ -115,7 +130,12 @@ int (*memmove_arr10_int(int (*dest)[10], int const (*src)[10], size_t len))[10];
     assigns *(dest + (0 .. len - 1)) \from *(src + (0 .. len - 1));
     assigns \result \from dest;
  */
-int *memmove_int(int *dest, int const *src, size_t len);
+int *memmove_int(int *dest, int const *src, size_t len)
+{
+  int *__retres;
+  __retres = (int *)memmove((void *)dest,(void const *)src,len);
+  return __retres;
+}
 
 int main(void)
 {
diff --git a/src/plugins/builtin/tests/test_config b/src/plugins/builtin/tests/test_config
index c72c35a2465..467fffb4bcb 100644
--- a/src/plugins/builtin/tests/test_config
+++ b/src/plugins/builtin/tests/test_config
@@ -1 +1 @@
-OPT: @PTEST_FILE@ -builtin -print -check -then -ocode @PTEST_DIR@/result/@PTEST_NAME@.c -print -then @PTEST_DIR@/result/@PTEST_NAME@.c @PTEST_FILE@ -ocode="" -print
\ No newline at end of file
+OPT: @PTEST_FILE@ -builtin -print -check -then -ocode @PTEST_DIR@/result/@PTEST_NAME@.c -print -then -no-builtin @PTEST_DIR@/result/@PTEST_NAME@.c @PTEST_FILE@ -ocode="" -print
\ No newline at end of file
diff --git a/src/plugins/builtin/transform.ml b/src/plugins/builtin/transform.ml
index a09358d511d..037c73aaf9a 100644
--- a/src/plugins/builtin/transform.ml
+++ b/src/plugins/builtin/transform.ml
@@ -22,9 +22,11 @@
 
 open Cil_types
 
+exception Bad_typing of string
+
 module type Builtin = sig
   val function_name: string
-  val replace_call: instr -> instr
+  val replace_call: (varinfo * exp list) -> (varinfo * exp list)
   val get_globals: location -> global list
   val mark_as_computed: ?project:Project.t -> unit -> unit
 end
@@ -45,26 +47,20 @@ let get_globals loc =
   in
   Hashtbl.fold (fun _ v l -> (get_globals v) @ l) base []
 
-let called_function = function
-  | Call(_, { enode = Lval((Var fct), NoOffset) }, _, _)
-  | Local_init(_, ConsInit(fct, _, Plain_func), _) -> fct
-  | _ -> assert false
-
-let called_function_name inst =
-  let fct = called_function inst in fct.vname
-
-let find_stdlib_attr_in_call inst =
-  let fct = called_function inst in
+let find_stdlib_attr fct =
   if not (Cil.hasAttribute "fc_stdlib" fct.vattr) then raise Not_found
 
-let replace_call inst =
+let replace_call (fct, args) =
   try
-    find_stdlib_attr_in_call inst ;
-    let name = called_function_name inst in
-    let m = Hashtbl.find base name in
+    find_stdlib_attr fct ;
+    let m = Hashtbl.find base fct.vname in
     let module M = (val m: Builtin) in
-    M.replace_call inst
-  with Not_found -> inst
+    M.replace_call (fct, args)
+  with
+  | Not_found -> (fct, args)
+  | Bad_typing s ->
+    Options.warning ~current:true "Ignored: %s" s ;
+    (fct, args)
 
 class visitor = object(_)
   inherit Visitor.frama_c_inplace
@@ -76,6 +72,8 @@ class visitor = object(_)
       f.globals <- globals @ f.globals ;
       mark_as_computed () ;
       Ast.mark_as_changed () ;
+      Ast.mark_as_grown () ;
+      File.reorder_ast () ;
       f
     in
     Cil.DoChildrenPost after
@@ -83,7 +81,12 @@ class visitor = object(_)
   method! vinst = function
     | Call(_) | Local_init(_, ConsInit(_, _, Plain_func), _) ->
       let change = function
-        | [i] -> [ replace_call i ]
+        | [ Call(r, ({ enode = Lval((Var fct), NoOffset) } as e), args, loc) ] ->
+          let fct, args = replace_call (fct, args) in
+          [ Call(r, { e with enode = Lval((Var fct), NoOffset) }, args, loc) ]
+        | [ Local_init(r, ConsInit(fct, args, Plain_func), loc) ] ->
+          let fct, args = replace_call (fct, args) in
+          [ Local_init(r, ConsInit(fct, args, Plain_func), loc) ]
         | _ -> assert false
       in
       Cil.DoChildrenPost change
diff --git a/src/plugins/builtin/transform.mli b/src/plugins/builtin/transform.mli
index 53d02fbfc2d..12b6647d509 100644
--- a/src/plugins/builtin/transform.mli
+++ b/src/plugins/builtin/transform.mli
@@ -22,9 +22,11 @@
 
 open Cil_types
 
+exception Bad_typing of string
+
 module type Builtin = sig
   val function_name: string
-  val replace_call: instr -> instr
+  val replace_call: (varinfo * exp list) -> (varinfo * exp list)
   val get_globals: location -> global list
   val mark_as_computed: ?project:Project.t -> unit -> unit
 end
-- 
GitLab