let doInstr stmt (i: instr) (d: t) =
!Db.progress ();
let add_with_additional_var lv v d =
let deps, target =
(* The modified location is [target],
whose address is computed from [deps]. *)
!Values_To_Use.lval_to_loc_with_deps
~with_alarms:CilE.warn_none_mode
~deps:Zone.bottom
stmt
lv
in
let deps = Zone.join
v
(Lmap_bitwise.From_Model.find d.deps_table deps)
in
let r = !Db.From.update
target
(Zone.join
d.additional_deps
deps)
d.deps_table
in
{d with deps_table=r; }
in
match i with
| Set (lv, exp, _) ->
Dataflow.Post
(fun state ->
let comp_vars = find_deps stmt state.deps_table exp in
let result = add_with_additional_var lv comp_vars state in
result
)
| Call (lvaloption,funcexp,argl,_) ->
Dataflow.Post
(fun state ->
!Db.progress ();
let funcexp_deps, called_vinfos =
resolv_func_vinfo
~with_alarms:CilE.warn_none_mode
~deps:Zone.bottom
stmt
funcexp
in
let funcexp_deps =
(* dependencies for the evaluation of [funcexp] *)
!Db.From.access funcexp_deps state.deps_table in
let additional_deps =
Zone.join d.additional_deps funcexp_deps
in
let args_froms =
List.map
(fun arg ->
match arg with
(* TODO : optimize the dependencies on subfields
| Lval lv ->
Lvalue
(From_Model.LBase.find
(Interp_loc.lval_to_loc_with_deps kinstr lv))
*)
| _ ->
Froms (find_deps stmt d.deps_table arg))
argl
in
let states_with_formals = ref [] in
let do_on kernel_function =
let called_vinfo = Kernel_function.get_vi kernel_function in
if Ast_info.is_cea_function called_vinfo.vname then
state
else
let { Function_Froms.deps_return = return_from;
deps_table = called_func_froms } =
Froms_To_Use.get kernel_function (Kstmt stmt)
in
let formal_args =
Kernel_function.get_formals kernel_function
in
let state_with_formals = ref state.deps_table in
begin try
List.iter2
(fun vi from ->
match from with
Froms from ->
let zvi = Locations.zone_of_varinfo vi in
state_with_formals :=
Lmap_bitwise.From_Model.add_binding
~exact:true
!state_with_formals
zvi
from
| Lvalue _ -> assert false)
formal_args
args_froms;
with Invalid_argument "List.iter2" ->
From_parameters.warning ~once:true ~current:true
"variadic call detected. Using only %d argument(s)."
(min
(List.length formal_args)
(List.length args_froms))
end;
if not (Db.From.Record_From_Callbacks.is_empty ())
then
states_with_formals :=
(kernel_function, !state_with_formals) ::
!states_with_formals;
let substitute =
cached_substitute
!state_with_formals
additional_deps
in
let new_state =
(* From state just after the call,
but before the result assigment *)
{state with
deps_table =
Lmap_bitwise.From_Model.map_and_merge substitute
called_func_froms
state.deps_table}
in
(* Treatement for the possible assignement
of the call result *)
(match lvaloption with
| None -> new_state
| Some lv ->
let first = ref true in
(try
Lmap_bitwise.From_Model.LOffset.fold
(fun _itv (_,x) acc ->
if not !first
then
(* treatment below only compatible with
imprecise handling
of Return elsewhere in this file *)
raise Not_found;
first := false;
let res = substitute x in
let deps, loc =
!Values_To_Use.lval_to_loc_with_deps
~with_alarms:CilE.warn_none_mode
~deps:Zone.bottom
stmt
lv
in
let deps =
Lmap_bitwise.From_Model.find
acc.deps_table
deps
in
let deps = Zone.join res deps in
let deps = Zone.join deps acc.additional_deps in
{ acc with deps_table =
!Db.From.update
loc
deps
acc.deps_table})
return_from
new_state
with Not_found -> (* from find_lonely_binding *)
let vars =
Lmap_bitwise.From_Model.LOffset.map
(fun (b,x) -> (b,substitute x))
return_from
in
add_with_additional_var
lv
(Lmap_bitwise.From_Model.LOffset.collapse vars)
new_state
))
in
let f f acc =
let p = do_on f in
match acc with
None -> Some p
| Some acc_memory ->
Some
{state with
deps_table = Lmap_bitwise.From_Model.join
p.deps_table
acc_memory.deps_table}
in
let result =
try
( match Kernel_function.Hptset.fold f called_vinfos None with
None -> state
| Some s -> s);
with Call_did_not_take_place -> state
in
if not (Db.From.Record_From_Callbacks.is_empty ())
then
Stmt.Hashtbl.replace
callwise_states_with_formals
stmt
!states_with_formals;
result
)
| _ -> Dataflow.Default