diff --git a/src/kernel_internals/typing/cabs2cil.ml b/src/kernel_internals/typing/cabs2cil.ml index 6cd61cd0df72fb115ee8edbb12bbbf1ab8c7bd68..84a71d10ca39d12752179023986396adb48e1d0d 100644 --- a/src/kernel_internals/typing/cabs2cil.ml +++ b/src/kernel_internals/typing/cabs2cil.ml @@ -2888,8 +2888,8 @@ let makeGlobalVarinfo (isadef: bool) (vi: varinfo) : varinfo * bool = * local. This can happen when we declare an extern variable with * global scope but we are in a local scope. *) Kernel.debug ~dkey:Kernel.dkey_typing_global - "makeGlobalVarinfo isadef=%B vi.vname=%s(%d)" - isadef vi.vname vi.vid; + "makeGlobalVarinfo isadef=%B vi.vname=%s(%d), vreferenced=%B" + isadef vi.vname vi.vid vi.vreferenced; (* This may throw an exception Not_found *) let oldvi, oldloc = lookupGlobalVar vi.vname in Kernel.debug ~dkey:Kernel.dkey_typing_global @@ -4650,6 +4650,7 @@ and makeVarInfoCabs ~(isformal: bool) ~(isglobal: bool) ?(isgenerated=false) + ?(referenced=false) (ldecl : location) (bt, sto, inline, attrs) (n,ndt,a) @@ -4666,7 +4667,8 @@ and makeVarInfoCabs Kernel.error ~once:true ~current:true "inline for a non-function: %s" n; checkRestrictQualifierDeep vtype; (* log "Looking at %s(%b): (%a)@." n isformal d_attrlist nattr;*) - let vi = makeVarinfo ~temp:isgenerated isglobal isformal n vtype in + let vi = makeVarinfo ~referenced ~temp:isgenerated isglobal isformal n vtype + in vi.vstorage <- sto; vi.vattr <- nattr; vi.vdecl <- ldecl; @@ -8224,11 +8226,17 @@ and createGlobal ghost logic_spec ((t,s,b,attr_list) : (typ * storage * bool * A let is_fc_builtin {A.expr_node=enode} = match enode with A.VARIABLE "FC_BUILTIN" -> true | _ -> false in + let is_fc_stdlib {A.expr_node=enode} = + match enode with A.VARIABLE v when v = fc_stdlib -> true | _ -> false + in let isgenerated = List.exists (fun (_,el) -> List.exists is_fc_builtin el) a in + let islibc = + List.exists (fun (_,el) -> List.exists is_fc_stdlib el) a + in (* Make a first version of the varinfo *) - let vi = makeVarInfoCabs ~ghost ~isformal:false + let vi = makeVarInfoCabs ~ghost ~isformal:false ~referenced:islibc ~isglobal:true ~isgenerated (convLoc cloc) (t,s,b,attr_list) (n,ndt,a) in (* Add the variable to the environment before doing the initializer diff --git a/src/kernel_internals/typing/rmtmps.ml b/src/kernel_internals/typing/rmtmps.ml index c15193c0bc6ecb6c428627a689f7314d63359795..3ecc19e5a442e4ca82162a50cbe27b477aa3f44e 100644 --- a/src/kernel_internals/typing/rmtmps.ml +++ b/src/kernel_internals/typing/rmtmps.ml @@ -80,6 +80,12 @@ let rmUnusedStatic = ref false let is_reachable t r = try InfoHashtbl.find t r with Not_found -> false +let pp_info fmt = function + | Type ti -> Format.fprintf fmt "%s" ti.tname + | Enum ei -> Format.fprintf fmt "%s" ei.ename + | Comp ci -> Format.fprintf fmt "%s" ci.cname + | Var vi -> Format.fprintf fmt "%s" vi.vname + (*********************************************************************** * @@ -277,7 +283,8 @@ let isExportedRoot global = Cil.hasAttribute "FC_BUILTIN" e.eattr -> e.ename, true, "has FC_BUILTIN attribute" | _ -> - "", false, "neither function nor variable nor annotation" + (Format.asprintf "%a" Cil_types_debug.pp_global global), false, + "neither fundef nor vardef nor annotation" in Kernel.debug ~dkey "isExportedRoot %s -> %B, %s" name result reason; @@ -328,14 +335,17 @@ class markReachableVisitor method! vglob = function | GType (typeinfo, _) -> + Kernel.debug ~dkey "marking reachable: type %s" typeinfo.tname; InfoHashtbl.replace reachable_tbl (Type typeinfo) true; DoChildren | GCompTag (compinfo, _) | GCompTagDecl (compinfo, _) -> + Kernel.debug ~dkey "marking reachable: comp decl %s" compinfo.cname; InfoHashtbl.replace reachable_tbl (Comp compinfo) true; DoChildren | GEnumTag (enuminfo, _) | GEnumTagDecl (enuminfo, _) -> + Kernel.debug ~dkey "marking reachable: enum decl %s" enuminfo.ename; InfoHashtbl.replace reachable_tbl (Enum enuminfo) true; DoChildren | GVar (varinfo, _, _) @@ -343,7 +353,10 @@ class markReachableVisitor | GFunDecl (_,varinfo, _) | GFun ({svar = varinfo}, _) -> if not (hasAttribute "FC_BUILTIN" varinfo.vattr) then - InfoHashtbl.replace reachable_tbl (Var varinfo) true; + begin + Kernel.debug ~dkey "marking reachable: function %s" varinfo.vname; + InfoHashtbl.replace reachable_tbl (Var varinfo) true; + end; DoChildren | GAnnot _ -> DoChildren | _ -> @@ -388,16 +401,16 @@ class markReachableVisitor begin let name = v.vname in if v.vglob then - Kernel.debug ~dkey "marking transitive use: global %s" name + Kernel.debug ~dkey "marking transitive use: global %s (%d)" name v.vid else - Kernel.debug ~dkey "marking transitive use: local %s" name; + Kernel.debug ~dkey "marking transitive use: local %s (%d)" name v.vid; (* If this is a global, we need to keep everything used in its * definition and declarations. *) InfoHashtbl.replace reachable_tbl (Var v) true; if v.vglob then begin - Kernel.debug ~dkey "descending: global %s" name; + Kernel.debug ~dkey "descending: global %s (%d)" name v.vid; let descend global = ignore (visitCilGlobal (self :> cilVisitor) global) in @@ -410,14 +423,14 @@ class markReachableVisitor method private mark_enum e = if not (is_reachable reachable_tbl (Enum e)) then begin - Kernel.debug ~dkey "marking transitive use: enum %s\n" e.ename; + Kernel.debug ~dkey "marking transitive use: enum %s" e.ename; InfoHashtbl.replace reachable_tbl (Enum e) true; self#visitAttrs e.eattr; (* Must visit the value attributed to the enum constants *) ignore (visitCilEnumInfo (self:>cilVisitor) e); end else - Kernel.debug ~dkey "not marking transitive use: enum %s\n" e.ename; + Kernel.debug ~dkey "not marking transitive use: enum %s" e.ename; method! vexpr e = match e.enode with @@ -442,7 +455,7 @@ class markReachableVisitor let old = is_reachable reachable_tbl (Comp c) in if not old then begin - Kernel.debug ~dkey "marking transitive use: compound %s\n" + Kernel.debug ~dkey "marking transitive use: compound %s" c.cname; InfoHashtbl.replace reachable_tbl (Comp c) true; @@ -457,7 +470,7 @@ class markReachableVisitor let old = (is_reachable reachable_tbl (Type ti)) in if not old then begin - Kernel.debug ~dkey "marking transitive use: typedef %s\n" + Kernel.debug ~dkey "marking transitive use: typedef %s" ti.tname; InfoHashtbl.replace reachable_tbl (Type ti) true; (* recurse deeper into the type referred-to by the typedef *) @@ -478,6 +491,38 @@ class markReachableVisitor self#visitAttrs a ); SkipChildren + + method! vlogic_var_decl lv = + Kernel.debug ~dkey "markReachable: found LOGIC VAR DECL for: %s (%d)\n" lv.lv_name lv.lv_id; + DoChildren + + method! vlogic_var_use lv = + Kernel.debug ~dkey "markReachable: found LOGIC VAR USE for: %s (%d)\n" lv.lv_name lv.lv_id; + match lv.lv_origin with + | None -> SkipChildren + | Some v -> + if not (is_reachable reachable_tbl (Var v)) then + begin + let name = v.vname in + if v.vglob then + Kernel.debug ~dkey "marking transitive use for logic var: global %s (%d)" name v.vid + else + Kernel.debug ~dkey "marking transitive use for logic var: local %s (%d)" name v.vid; + + (* If this is a global, we need to keep everything used in its + * definition and declarations. *) + InfoHashtbl.replace reachable_tbl (Var v) true; + if v.vglob then + begin + Kernel.debug ~dkey "descending: global %s (%d)" name v.vid; + let descend global = + ignore (visitCilGlobal (self :> cilVisitor) global) + in + let globals = Hashtbl.find_all globalMap name in + List.iter descend globals + end + end; + SkipChildren end @@ -522,28 +567,50 @@ let markReachable isRoot ast reachable_tbl = * **********************************************************************) +let global_type_and_name = function + | GType (t, _) -> "type " ^ t.tname + | GCompTag (c,_) -> "comp " ^ c.cname + | GCompTagDecl (c,_) -> "comp decl " ^ c.cname + | GEnumTag (e, _) -> "enum " ^ e.ename + | GEnumTagDecl (e,_) -> "enum decl " ^ e.ename + | GVarDecl(v,_) -> "var decl " ^ v.vname + | GFunDecl(_,v,_) -> "fun decl " ^ v.vname + | GVar (v, _, _) -> "var " ^ v.vname + | GFun ({svar = v}, _) -> "fun " ^ v.vname + | GAsm _ -> "<asm>" + | GPragma _ -> "<pragma>" + | GText _ -> "<text>" + | GAnnot _ -> "<annot>" + class markReferencedVisitor = object inherit nopCilVisitor + val dkey = Kernel.dkey_referenced + val inside_exp : exp Stack.t = Stack.create () val inside_typ : typ Stack.t = Stack.create () method! vglob = function - | GType (typeinfo, _loc) -> + | GType (typeinfo, loc) -> + Kernel.debug ~source:(fst loc) ~dkey "referenced: type %s" typeinfo.tname; typeinfo.treferenced <- true; DoChildren - | GCompTag (compinfo, _loc) - | GCompTagDecl (compinfo, _loc) -> + | GCompTag (compinfo, loc) + | GCompTagDecl (compinfo, loc) -> + Kernel.debug ~source:(fst loc) ~dkey "referenced: comp %s" compinfo.cname; compinfo.creferenced <- true; DoChildren - | GEnumTag (enuminfo, _loc) - | GEnumTagDecl (enuminfo, _loc) -> + | GEnumTag (enuminfo, loc) + | GEnumTagDecl (enuminfo, loc) -> + Kernel.debug ~source:(fst loc) ~dkey "referenced: enum %s" enuminfo.ename; enuminfo.ereferenced <- true; DoChildren - | GVar (varinfo, _, _loc) - | GVarDecl (varinfo, _loc) - | GFunDecl (_,varinfo, _loc) - | GFun ({svar = varinfo}, _loc) -> + | GVar (varinfo, _, loc) + | GVarDecl (varinfo, loc) + | GFunDecl (_,varinfo, loc) + | GFun ({svar = varinfo}, loc) -> + Kernel.debug ~dkey "referenced: var/fun %s@." varinfo.vname; + Kernel.debug ~source:(fst loc) ~dkey "referenced: fun %s" varinfo.vname; varinfo.vreferenced <- true; DoChildren | GAnnot _ -> DoChildren @@ -553,16 +620,19 @@ class markReferencedVisitor = object method! vtype = function | TNamed (ti, _) -> if not (Stack.is_empty inside_typ) then begin + Kernel.debug ~current:true ~dkey "referenced: type %s" ti.tname; ti.treferenced <- true; end; DoChildren | TComp (ci, _, _) -> if not (Stack.is_empty inside_typ) then begin + Kernel.debug ~current:true ~dkey "referenced: comp %s" ci.cname; ci.creferenced <- true; end; DoChildren | TEnum (ei, _) -> if not (Stack.is_empty inside_typ) then begin + Kernel.debug ~current:true ~dkey "referenced: enum %s" ei.ename; ei.ereferenced <- true; end; DoChildren @@ -585,6 +655,7 @@ class markReferencedVisitor = object method! vvrbl v = if not (Stack.is_empty inside_exp) then begin + Kernel.debug ~current:true ~dkey "referenced: var %s" v.vname; v.vreferenced <- true; end; SkipChildren @@ -592,7 +663,10 @@ class markReferencedVisitor = object end let markReferenced ast = - visitCilFileSameGlobals (new markReferencedVisitor) ast + Kernel.debug ~dkey "starting markReferenced (AST has %d globals)" + (List.length ast.globals); + visitCilFileSameGlobals (new markReferencedVisitor) ast; + Kernel.debug ~dkey "finished markReferenced" (********************************************************************** * @@ -778,7 +852,7 @@ let removeUnmarked isRoot ast reachable_tbl = begin (* along the way, record the interesting locals that were removed *) let name = local.vname in - (Kernel.debug ~dkey "removing local: %s\n" name); + (Kernel.debug ~dkey "removing local: %s" name); if not (Str.string_match uninteresting name 0) then removedLocals := (func.svar.vname ^ "::" ^ name) :: !removedLocals; @@ -803,8 +877,28 @@ let removeUnmarked isRoot ast reachable_tbl = (* all other globals are retained *) | _ -> true in - let keptGlobals, _removedGlobals = List.partition filterGlobal ast.globals in + let keptGlobals, removedGlobals = List.partition filterGlobal ast.globals in ast.globals <- keptGlobals; + if Kernel.is_debug_key_enabled dkey then + List.iter (fun rg -> + Kernel.debug ~dkey "removing global: %s" (global_type_and_name rg) + ) removedGlobals; + if Kernel.is_debug_key_enabled dkey then + List.iter (fun rg -> + begin + match rg with + | GFunDecl (_s, vi, _) -> + begin + try + let kf = Globals.Functions.get vi in + Kernel.debug ~dkey "GFunDecl: %a@." Kernel_function.pretty_code kf + with Not_found -> + Kernel.debug ~dkey "GFunDecl: not found for %a@." Printer.pp_varinfo vi; + end + | _ -> () + end; + Kernel.debug ~dkey "kept global %s (%a)" (global_type_and_name rg) Printer.pp_global rg + ) keptGlobals; !removedLocals @@ -835,6 +929,13 @@ let removeUnusedTemps ?(isRoot : rootsFilter = isExportedRoot) ast = (* mark everything reachable from the global roots *) markReachable isRoot ast reachable_tbl; + let elements = + InfoHashtbl.fold (fun k v acc -> Format.asprintf "%a:%B" pp_info k v :: acc) + reachable_tbl [] + in + Kernel.debug ~dkey "reachable_tbl: %a" + (Pretty_utils.pp_list ~sep:"@\n" Format.pp_print_string) elements; + markReferenced ast; (* take out the trash *) diff --git a/src/kernel_services/ast_queries/cil.ml b/src/kernel_services/ast_queries/cil.ml index 79da27bd41da6e97700185a0d1cf6801b9f1c812..c5e01b7134df44a227c6d801e2ab9e1e6f2c0da0 100644 --- a/src/kernel_services/ast_queries/cil.ml +++ b/src/kernel_services/ast_queries/cil.ml @@ -578,7 +578,7 @@ type attributeClass = | x -> x (* Make a varinfo. Used mostly as a helper function below *) - let makeVarinfo ?(source=true) ?(temp=false) global formal name typ = + let makeVarinfo ?(source=true) ?(temp=false) ?(referenced=false) global formal name typ = let vi = { vorig_name = name; vname = name; @@ -593,7 +593,7 @@ type attributeClass = vattr = []; vstorage = NoStorage; vaddrof = false; - vreferenced = false; + vreferenced = referenced; vdescr = None; vdescrpure = true; vghost = false; @@ -6280,16 +6280,16 @@ let need_cast ?(force=false) oldt newt = let refresh_local_name fdec vi = let new_name = findUniqueName fdec vi.vname in vi.vname <- new_name - let makeLocal ?(temp=false) ?(formal=false) fdec name typ = + let makeLocal ?(temp=false) ?referenced ?(formal=false) fdec name typ = (* a helper function *) let name = findUniqueName fdec name in fdec.smaxid <- 1 + fdec.smaxid; - let vi = makeVarinfo ~temp false formal name typ in + let vi = makeVarinfo ~temp ?referenced false formal name typ in vi (* Make a local variable and add it to a function *) - let makeLocalVar fdec ?scope ?(temp=false) ?(insert = true) name typ = - let vi = makeLocal ~temp fdec name typ in + let makeLocalVar fdec ?scope ?(temp=false) ?referenced ?(insert = true) name typ = + let vi = makeLocal ~temp ?referenced fdec name typ in refresh_local_name fdec vi; if insert then begin @@ -6377,8 +6377,8 @@ let need_cast ?(force=false) oldt newt = (* Make a global variable. Your responsibility to make sure that the name * is unique *) - let makeGlobalVar ?source ?temp name typ = - makeVarinfo ?source ?temp true false name typ + let makeGlobalVar ?source ?temp ?referenced name typ = + makeVarinfo ?source ?temp ?referenced true false name typ let mkPureExprInstr ~fundec ~scope ?loc e = let loc = match loc with None -> e.eloc | Some l -> l in diff --git a/src/kernel_services/ast_queries/cil.mli b/src/kernel_services/ast_queries/cil.mli index 799986722ec0afbc0e43e5acc5cffcd8fb59c5a0..60819b3c6ef5382920d8c8ae345a4d829dbd443e 100644 --- a/src/kernel_services/ast_queries/cil.mli +++ b/src/kernel_services/ast_queries/cil.mli @@ -672,10 +672,13 @@ val splitFunctionTypeVI: [vtemp] field in type {!Cil_types.varinfo}. The [source] argument defaults to [true], and corresponds to the field [vsource] . + The [referenced] argument defaults to [false], and corresponds to the field + [vreferenced] . The first unnamed argument specifies whether the varinfo is for a global and the second is for formals. *) val makeVarinfo: - ?source:bool -> ?temp:bool -> bool -> bool -> string -> typ -> varinfo + ?source:bool -> ?temp:bool -> ?referenced:bool -> bool -> bool -> string -> + typ -> varinfo (** Make a formal variable for a function declaration. Insert it in both the sformals and the type of the function. You can optionally specify where to @@ -696,7 +699,7 @@ val makeFormalVar: fundec -> ?where:string -> string -> typ -> varinfo @modify Chlorine-20180501 the name of the variable is guaranteed to be fresh. *) val makeLocalVar: - fundec -> ?scope:block -> ?temp:bool -> ?insert:bool + fundec -> ?scope:block -> ?temp:bool -> ?referenced:bool -> ?insert:bool -> string -> typ -> varinfo (** if needed, rename the given varinfo so that its [vname] does not @@ -720,7 +723,8 @@ val makeTempVar: fundec -> ?insert:bool -> ?name:string -> ?descr:string -> (** Make a global variable. Your responsibility to make sure that the name is unique. [source] defaults to [true]. [temp] defaults to [false].*) -val makeGlobalVar: ?source:bool -> ?temp:bool -> string -> typ -> varinfo +val makeGlobalVar: ?source:bool -> ?temp:bool -> ?referenced:bool -> string -> + typ -> varinfo (** Make a shallow copy of a [varinfo] and assign a new identifier. If the original varinfo has an associated logic var, it is copied too and diff --git a/src/kernel_services/plugin_entry_points/kernel.ml b/src/kernel_services/plugin_entry_points/kernel.ml index 0c95ee14a2c78bdc8ccf69d66875628a261e63c9..9c4a3b5306acdf51c56a02afc958a2132237bf28 100644 --- a/src/kernel_services/plugin_entry_points/kernel.ml +++ b/src/kernel_services/plugin_entry_points/kernel.ml @@ -82,6 +82,7 @@ let dkey_loops = register_category "natural-loops" let dkey_parser = register_category "parser" let dkey_rmtmps = register_category "parser:rmtmps" +let dkey_referenced = register_category "parser:referenced" let dkey_pp = register_category "pp" let dkey_compilation_db = register_category "pp:compilation-db" diff --git a/src/kernel_services/plugin_entry_points/kernel.mli b/src/kernel_services/plugin_entry_points/kernel.mli index 06e4720e294a3e4c737f3c4adce2f988dbe72670..c837fb5a0919eddb59eabfe811336a46ccf66629 100644 --- a/src/kernel_services/plugin_entry_points/kernel.mli +++ b/src/kernel_services/plugin_entry_points/kernel.mli @@ -109,6 +109,8 @@ val dkey_prop_status_reg: category val dkey_rmtmps: category +val dkey_referenced: category + val dkey_task: category val dkey_typing_global: category diff --git a/src/plugins/variadic/va_build.ml b/src/plugins/variadic/va_build.ml index 77f3bbaf0475a97369a8dfdd005d54874ffa7cd4..a5852d4a84d93ea6f773325fb1ed5b2bfa2fccb3 100644 --- a/src/plugins/variadic/va_build.ml +++ b/src/plugins/variadic/va_build.ml @@ -28,7 +28,7 @@ open Cil let function_declaration ?vattr ~loc name typ mk_spec = (* Build the varinfo *) - let vi = makeGlobalVar name typ in + let vi = makeGlobalVar ~referenced:true name typ in Extlib.may (fun extra_vattr -> vi.vattr <- vi.vattr @ extra_vattr) vattr; vi.vdecl <- loc; (* Build the formals *)