diff --git a/src/kernel_services/ast_queries/ast_diff.ml b/src/kernel_services/ast_queries/ast_diff.ml index e24d70335ddaa4d882ac8287717042d8820c2a5b..681d837239132b2999fd3cbd735646628887e3df 100644 --- a/src/kernel_services/ast_queries/ast_diff.ml +++ b/src/kernel_services/ast_queries/ast_diff.ml @@ -77,10 +77,57 @@ module Correspondance = end ) +(* for kernel function, we are a bit more precise than a yes/no answer. + More precisely, we check whether a function has the same spec, + the same body, and whether its callees have changed (provided + the body itself is identical, otherwise, there's no point in checking + the callees. +*) +type partial_correspondance = + [ `Spec_changed (* body and callees haven't changed *) + | `Body_changed (* spec hasn't changed *) + | `Callees_changed (* spec and body haven't changed *) + | `Callees_spec_changed (* body hasn't changed *) + ] + +type body_correspondance = + [ `Body_changed + | `Callees_changed + | `Same_body + ] + +let (<=>) res (cmp,x,y) = if res <> 0 then res else cmp x y + +let compare_pc pc1 pc2 = + match pc1, pc2 with + | `Spec_changed, `Spec_changed -> 0 + | `Spec_changed, _ -> -1 + | _, `Spec_changed -> 1 + | `Body_changed, `Body_changed -> 0 + | `Body_changed, _ -> -1 + | _, `Body_changed -> 1 + | `Callees_changed, `Callees_changed -> -1 + | `Callees_changed, _ -> -1 + | _, `Callees_changed -> 1 + | `Callees_spec_changed, `Callees_spec_changed -> 0 + +let string_of_pc = function + | `Spec_changed -> "Spec_changed" + | `Body_changed -> "Body_changed" + | `Callees_changed -> "Callees_changed" + | `Callees_spec_changed -> "Callees_spec_changed" + +let pretty_pc fmt = + let open Format in + function + | `Spec_changed -> pp_print_string fmt "(spec changed)" + | `Body_changed -> pp_print_string fmt "(body_changed)" + | `Callees_changed -> pp_print_string fmt "(callees changed)" + | `Callees_spec_changed -> pp_print_string fmt "(callees and spec changed)" + type kf_correspondance = [ kernel_function correspondance - | `Same_spec of kernel_function (** body has changed, but spec is identical *) - | `Different_calls of kernel_function + | `Partial of kernel_function * partial_correspondance ] module Kf_correspondance = @@ -92,40 +139,34 @@ module Kf_correspondance = type t = kf_correspondance let reprs = let kf = List.hd Kernel_function.reprs in - `Same_spec kf :: (C.reprs :> t list) + `Partial (kf,`Spec_changed) + :: (C.reprs :> t list) let compare x y = match x,y with - | `Same_spec f1, `Same_spec f2 -> Kernel_function.compare f1 f2 - | `Same_spec _, _ -> 1 - | _, `Same_spec _ -> -1 - | `Different_calls f1, `Different_calls f2 -> Kernel_function.compare f1 f2 - | `Different_calls _, _ -> 1 - | _, `Different_calls _ -> -1 + | `Partial (kf1,flags1), `Partial(kf2,flags2) -> + Kernel_function.compare kf1 kf2 <=> (compare_pc,flags1,flags2) + | `Partial _, _ -> 1 + | _, `Partial _ -> -1 | (#correspondance as x), (#correspondance as y) -> C.compare x y let equal = Datatype.from_compare let hash = function - | `Same_spec f -> 57 * (Kernel_function.hash f) - | `Different_calls f -> 79 * (Kernel_function.hash f) + | `Partial(kf,_) -> 57 * (Kernel_function.hash kf) | #correspondance as x -> C.hash x let internal_pretty_code p fmt = function - | `Same_spec f -> + | `Partial (kf,flags) -> let pp fmt = - Format.fprintf fmt "`Same_spec %a" - (Kernel_function.internal_pretty_code Type.Call) f - in - Type.par p Call fmt pp - | `Different_calls f -> - let pp fmt = - Format.fprintf fmt "`Different_calls %a" - (Kernel_function.internal_pretty_code Type.Call) f + Format.fprintf fmt + "`Partial (%a,%s)" + (Kernel_function.internal_pretty_code Type.Call) kf + (string_of_pc flags) in Type.par p Call fmt pp | #correspondance as x -> C.internal_pretty_code p fmt x let pretty fmt = function - | `Same_spec f -> - Format.fprintf fmt "-> (contract) %a" Kernel_function.pretty f - | `Different_calls f -> - Format.fprintf fmt " -> (callees differ) %a" Kernel_function.pretty f + | `Partial(kf,flags) -> + Format.fprintf fmt "-> %a %a" + Kernel_function.pretty kf + pretty_pc flags | #correspondance as x -> C.pretty fmt x end) @@ -236,6 +277,11 @@ let find_candidate_varinfo ?loc:_loc vi where = Some (Globals.Vars.find_from_astinfo vi.vname where) with Not_found -> None +let find_candidate_func ?loc:_loc kf = + try + Some (Globals.Functions.find_by_name (Kf.get_name kf)) + with Not_found -> None + let (&&>) (res,env) f = if res then f env else false, env let (&&|) env f = f env let (&&&) (res,env) b = res && b, env @@ -314,6 +360,11 @@ and is_same_exp _e _e' env = false, env and is_same_offset _o _o' env = false, env +and is_same_funspec _s1 _s2 env = false, env + +and is_same_fundec _f1 _f2 env: body_correspondance*is_same_env = + `Body_changed, env + and typeinfo_correspondance ?loc ti env = let add ti env = match find_candidate_type ?loc ti with @@ -329,6 +380,9 @@ and compinfo_correspondance ?loc ci env = match find_candidate_compinfo ?loc ci with | None -> `Not_present, env | Some ci' -> + let env = + {env with compinfo = Cil_datatype.Compinfo.Map.add ci ci' env.compinfo} + in let res, env = is_same_compinfo ci ci' env in (if res then `Same ci' else `Not_present), env in @@ -346,6 +400,44 @@ and enuminfo_correspondance ?loc ei env = in Enuminfo.memo_env add ei env +and gfun_correspondance ?loc vi env = + let selection = + State_selection.( + union + (with_dependencies Kernel_function.self) + (union + (with_dependencies Annotations.funspec_state) + (with_dependencies Annotations.code_annot_state))) + in + let kf = + Project.on ~selection (Orig_project.get()) Globals.Functions.get vi + in + let add kf env = + match find_candidate_func ?loc kf with + | None -> `Not_present, env + | Some kf' -> + let env = + { env with kernel_function = Kf.Map.add kf kf' env.kernel_function } + in + let same_spec, env = is_same_funspec kf.spec kf'.spec env in + let same_body, env = + match (Kf.has_definition kf, Kf.has_definition kf') with + | false, false -> `Same_body, env + | false, true | true, false -> `Body_changed, env + | true, true -> + is_same_fundec (Kf.get_definition kf) (Kf.get_definition kf') env + in + match same_spec, same_body with + | false, `Body_changed -> `Not_present, env + | false, `Callees_changed -> `Partial(kf',`Callees_spec_changed), env + | false, `Same_body -> `Partial(kf', `Spec_changed), env + | true, `Same_body -> `Same kf', env + | true, ((`Body_changed|`Callees_changed) as c) -> `Partial(kf', c), env + in + match Kf.Map.find_opt kf env.kernel_function with + | Some kf' -> `Same kf', env + | None -> Kernel_function.memo_env add kf env + let gvar_correspondance ?loc vi = let add vi = match find_candidate_varinfo ?loc vi Cil_types.VGlobal with @@ -370,8 +462,8 @@ let global_correspondance g = ignore (enuminfo_correspondance ~loc ei empty_env) | GVar(vi,_,loc) | GVarDecl(vi,loc) -> ignore (gvar_correspondance ~loc vi) - | GFunDecl(_,_vi,_loc) -> () - | GFun(_f,_loc) -> () + | GFunDecl(_,vi,loc) -> ignore (gfun_correspondance ~loc vi empty_env) + | GFun(f,loc) -> ignore (gfun_correspondance ~loc f.svar empty_env) | _ -> () let compare_ast prj = diff --git a/src/kernel_services/ast_queries/ast_diff.mli b/src/kernel_services/ast_queries/ast_diff.mli index 8aa926a5d3ab036f021c8d9faaf902a30003b79e..5b6b03c0a39d477873c8061093fbead6932d8fc1 100644 --- a/src/kernel_services/ast_queries/ast_diff.mli +++ b/src/kernel_services/ast_queries/ast_diff.mli @@ -36,12 +36,22 @@ type 'a correspondance = | `Not_present (** no correspondance *) ] -(** specific correspondance for kernel functions *) +(** for kernel function, we are a bit more precise than a yes/no answer. + More precisely, we check whether a function has the same spec, + the same body, and whether its callees have changed (provided + the body itself is identical, otherwise, there's no point in checking + the callees. +*) +type partial_correspondance = + [ `Spec_changed (** body and callees haven't changed *) + | `Body_changed (** spec hasn't changed *) + | `Callees_changed (** spec and body haven't changed *) + | `Callees_spec_changed (** body hasn't changed *) + ] + type kf_correspondance = [ kernel_function correspondance - | `Same_spec of kernel_function (** body has changed, but spec is identical *) - | `Different_calls of kernel_function - (** body is identical, but there are calls to functions that have changed. *) + | `Partial of kernel_function * partial_correspondance ] (** varinfos correspondances *)