let compute_using_cfg kf ~call_kinstr initial_state =
match kf.fundec with
| Declaration _ -> assert false
| Definition (f,_loc) ->
(*if let (_,_,variadic,_) = splitFunctionTypeVI f.svar in variadic
then raise Leaf (* Do not visit variadic bodies *)
else *)
begin
let module Computer =
Computer(struct
let stmt_can_reach = Stmts_graph.stmt_can_reach kf
let is_natural_loop = Loop.is_natural kf
let non_linear_assignments =
match kf.fundec with
Declaration(_funspec,_varinfo,_,_) -> dummy_non_linear_assignment
| Definition (fundec,_location) ->
let varinfo = fundec.svar in
(try
Non_linear_assignments.find varinfo
with
Not_found ->
let n = compute_non_linear_assignments f in
Non_linear_assignments.add varinfo n;
n)
let blocks_closed_by_edge =
Kernel_function.blocks_closed_by_edge
end)
in
let module Compute = Dataflow.ForwardsDataFlow(Computer) in
List.iter
(function {called_kf = g} ->
if kf == g
then begin
Value_parameters.warning ~current:true ~once:true
"ignoring recursive call during value analysis of %a (%a)"
Kernel_function.pretty_name kf
pretty_call_stack !call_stack ;
raise Leaf
end)
!call_stack;
push_call_stack {called_kf = kf;
call_site = call_kinstr;
called_merge_current = Computer.merge_current};
match f.sbody.bstmts with
[] -> assert false
| start :: _ ->
let ret_id = Kernel_function.find_return kf in
(* We start with only the start block *)
Computer.StmtStartData.add
start.sid
(Computer.computeFirstPredecessor
start
{
Computer.counter_unroll = 0;
value = initial_state});
begin try
Compute.compute [start]
with Db.Value.Aborted as e ->
(* Computation was aborted: pop the call stack and inform
the caller *)
pop_call_stack ();
raise e
end;
let last_ret,last_s,last_clob as last_state =
try
let _,state,_ as result =
try
Computer.externalize (Kstmt ret_id) kf
with Not_found -> assert false
in
if Relations_type.Model.is_reachable state
then begin
if hasAttribute "noreturn" (Kernel_function.get_vi kf).vattr
then
Value_parameters.warning ~current:true ~once:true
"function %a may terminate but has the noreturn attribute"
Kernel_function.pretty_name kf;
Kf_state.mark_as_terminates kf
end
else raise Not_found;
result
with Not_found -> begin
(
(* Computer.merge_current (); this may already have been
done by externalize, and should not be done twice
because the callbacks are done there.
TODO: examine the usefulness of this statement
(* Save the values computed even
if the function does not terminate *) *)
Kf_state.mark_as_never_terminates kf);
None,
Relations_type.Model.bottom,
Location_Bits.Top_Param.bottom
end
in
Value_parameters.debug
"@[RESULT FOR %a <-%a:@\n\\result -> %a@\n%a@\nClobered set:%a@]"
Kernel_function.pretty_name kf
pretty_call_stack !call_stack
(fun fmt v ->
match v with
| None -> ()
| Some v -> V_Offsetmap.pretty fmt v)
last_ret
Relations_type.Model.pretty last_s
Location_Bits.Top_Param.pretty
last_clob;
pop_call_stack ();
last_state
end