|
|
@ -23,12 +23,16 @@ let is_defined_outside loop_nodes reaching_defs var =
|
|
|
|
|> Option.value ~default:true
|
|
|
|
|> Option.value ~default:true
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let is_not_modeled tenv callee_pname =
|
|
|
|
|
|
|
|
match Models.ProcName.dispatch tenv callee_pname with Some _ -> false | None -> true
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let get_purity tenv ~is_inv_by_default callee_pname args =
|
|
|
|
let get_purity tenv ~is_inv_by_default callee_pname args =
|
|
|
|
(* Take into account purity behavior of modeled functions *)
|
|
|
|
(* Take into account purity behavior of modeled functions *)
|
|
|
|
let all_params_modified = PurityDomain.all_params_modified args in
|
|
|
|
|
|
|
|
match Models.ProcName.dispatch tenv callee_pname with
|
|
|
|
match Models.ProcName.dispatch tenv callee_pname with
|
|
|
|
| Some inv ->
|
|
|
|
| Some inv ->
|
|
|
|
PurityDomain.with_purity (InvariantModels.is_invariant inv) all_params_modified
|
|
|
|
PurityDomain.(
|
|
|
|
|
|
|
|
if InvariantModels.is_invariant inv then pure else impure_params (all_params_modified args))
|
|
|
|
| None -> (
|
|
|
|
| None -> (
|
|
|
|
debug "No model for %a \n" Typ.Procname.pp callee_pname ;
|
|
|
|
debug "No model for %a \n" Typ.Procname.pp callee_pname ;
|
|
|
|
(* If there is no model, invoke purity analysis to see if function is pure *)
|
|
|
|
(* If there is no model, invoke purity analysis to see if function is pure *)
|
|
|
@ -36,7 +40,7 @@ let get_purity tenv ~is_inv_by_default callee_pname args =
|
|
|
|
| Some {Summary.payloads= {Payloads.purity= Some purity_summary}} ->
|
|
|
|
| Some {Summary.payloads= {Payloads.purity= Some purity_summary}} ->
|
|
|
|
purity_summary
|
|
|
|
purity_summary
|
|
|
|
| _ ->
|
|
|
|
| _ ->
|
|
|
|
PurityDomain.with_purity is_inv_by_default all_params_modified )
|
|
|
|
if is_inv_by_default then PurityDomain.pure else PurityDomain.impure_global )
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let is_non_primitive typ = Typ.is_pointer typ || Typ.is_struct typ
|
|
|
|
let is_non_primitive typ = Typ.is_pointer typ || Typ.is_struct typ
|
|
|
@ -154,13 +158,14 @@ let get_vars_to_invalidate node loop_head args modified_params invalidated_vars
|
|
|
|
args
|
|
|
|
args
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let all_modified loop_nodes =
|
|
|
|
let all_unmodeled_modified tenv loop_nodes =
|
|
|
|
LoopNodes.fold
|
|
|
|
LoopNodes.fold
|
|
|
|
(fun node acc ->
|
|
|
|
(fun node acc ->
|
|
|
|
Procdesc.Node.get_instrs node
|
|
|
|
Procdesc.Node.get_instrs node
|
|
|
|
|> Instrs.fold ~init:acc ~f:(fun acc instr ->
|
|
|
|
|> Instrs.fold ~init:acc ~f:(fun acc instr ->
|
|
|
|
match instr with
|
|
|
|
match instr with
|
|
|
|
| Sil.Call ((id, _), _, _, _, _) ->
|
|
|
|
| Sil.Call ((id, _), Const (Cfun callee_pname), _, _, _)
|
|
|
|
|
|
|
|
when is_not_modeled tenv callee_pname ->
|
|
|
|
InvalidatedVars.add (Var.of_id id) acc
|
|
|
|
InvalidatedVars.add (Var.of_id id) acc
|
|
|
|
| _ ->
|
|
|
|
| _ ->
|
|
|
|
acc ) )
|
|
|
|
acc ) )
|
|
|
@ -171,7 +176,7 @@ let all_modified loop_nodes =
|
|
|
|
all its non-primitive arguments. Once invalidated, it should be
|
|
|
|
all its non-primitive arguments. Once invalidated, it should be
|
|
|
|
never added again. *)
|
|
|
|
never added again. *)
|
|
|
|
let get_invalidated_vars_in_loop tenv loop_head ~is_inv_by_default loop_nodes =
|
|
|
|
let get_invalidated_vars_in_loop tenv loop_head ~is_inv_by_default loop_nodes =
|
|
|
|
let all_modified = lazy (all_modified loop_nodes) in
|
|
|
|
let all_unmodeled_modified = lazy (all_unmodeled_modified tenv loop_nodes) in
|
|
|
|
LoopNodes.fold
|
|
|
|
LoopNodes.fold
|
|
|
|
(fun node acc ->
|
|
|
|
(fun node acc ->
|
|
|
|
Procdesc.Node.get_instrs node
|
|
|
|
Procdesc.Node.get_instrs node
|
|
|
@ -184,10 +189,11 @@ let get_invalidated_vars_in_loop tenv loop_head ~is_inv_by_default loop_nodes =
|
|
|
|
| AbstractDomain.Types.Top ->
|
|
|
|
| AbstractDomain.Types.Top ->
|
|
|
|
(* modified global *)
|
|
|
|
(* modified global *)
|
|
|
|
(* if one of the callees modifies a global static
|
|
|
|
(* if one of the callees modifies a global static
|
|
|
|
variable, invalidate all the function calls *)
|
|
|
|
variable, invalidate all unmodeled function calls *)
|
|
|
|
InvalidatedVars.union acc (force all_modified)
|
|
|
|
InvalidatedVars.union acc (force all_unmodeled_modified)
|
|
|
|
| AbstractDomain.Types.NonTop modified_params ->
|
|
|
|
| AbstractDomain.Types.NonTop modified_params ->
|
|
|
|
if ModifiedParamIndices.is_empty modified_params then (*pure*) acc
|
|
|
|
if ModifiedParamIndices.is_empty modified_params then (*pure*)
|
|
|
|
|
|
|
|
acc
|
|
|
|
else
|
|
|
|
else
|
|
|
|
get_vars_to_invalidate node loop_head args modified_params
|
|
|
|
get_vars_to_invalidate node loop_head args modified_params
|
|
|
|
(InvalidatedVars.add (Var.of_id id) acc)) )
|
|
|
|
(InvalidatedVars.add (Var.of_id id) acc)) )
|
|
|
|