Skip to content
Snippets Groups Projects
Commit ff4cd3b7 authored by David Bühler's avatar David Bühler Committed by Andre Maroneze
Browse files

[Inout] Avoids folding implicit zero-initializers of large arrays.

Fixes a performance issue.
parent 477c8e21
No related branches found
No related tags found
No related merge requests found
...@@ -23,6 +23,18 @@ ...@@ -23,6 +23,18 @@
open Cil_types open Cil_types
open Visitor open Visitor
(* To avoid a performance issue, do not fold implicit zero-initializers of large
arrays. For arrays of scalar elements, the outputs of an initializer is
exactly the zone covered by the array. For arrays containing structs with
padding bits, this is an over-approximation, so we prefer folding the
initializer if the array is not too big (the 100 cells limit is arbitrary).
We still need to fold the explicit initializers to collect the inputs. *)
let fold_implicit_initializer typ =
not
(Cil.isArrayType typ &&
(Cil.isArithmeticOrPointerType (Cil.typeOf_array_elem typ)
|| Ast_info.array_size typ > (Integer.of_int 100)))
let specialize_state_on_call ?stmt kf = let specialize_state_on_call ?stmt kf =
match stmt with match stmt with
| Some ({ skind = Instr (Call (_, _, l, _)) } as stmt) -> | Some ({ skind = Instr (Call (_, _, l, _)) } as stmt) ->
......
...@@ -32,6 +32,10 @@ open Cil_types ...@@ -32,6 +32,10 @@ open Cil_types
can be gathered using a Cil visitor). can be gathered using a Cil visitor).
*) *)
(** Should implicit zero-initializers for [typ] be folded? False for big arrays
to avoid a performance issue. *)
val fold_implicit_initializer: typ -> bool
val specialize_state_on_call: ?stmt:stmt -> kernel_function -> Db.Value.state val specialize_state_on_call: ?stmt:stmt -> kernel_function -> Db.Value.state
(** If the given statement is a call to the given function, (** If the given statement is a call to the given function,
......
...@@ -96,7 +96,9 @@ class virtual do_it_ = object(self) ...@@ -96,7 +96,9 @@ class virtual do_it_ = object(self)
self#do_assign lv; self#do_assign lv;
ignore (visitFramacExpr (self:>frama_c_visitor) e) ignore (visitFramacExpr (self:>frama_c_visitor) e)
| CompoundInit (ct,initl) -> | CompoundInit (ct,initl) ->
let implicit = true in (* No need to consider implicit zero-initializers, for which
nothing is read. *)
let implicit = false in
let doinit o i _ () = let doinit o i _ () =
ignore (visitFramacOffset (self:>frama_c_visitor) o); ignore (visitFramacOffset (self:>frama_c_visitor) o);
aux (Cil.addOffsetLval o lv) i aux (Cil.addOffsetLval o lv) i
......
...@@ -283,7 +283,6 @@ end) = struct ...@@ -283,7 +283,6 @@ end) = struct
let new_inputs = Zone.diff inputs data.under_outputs_d in let new_inputs = Zone.diff inputs data.under_outputs_d in
store_non_terminating_inputs new_inputs; store_non_terminating_inputs new_inputs;
{data with over_inputs_d = Zone.join data.over_inputs_d new_inputs} {data with over_inputs_d = Zone.join data.over_inputs_d new_inputs}
;;
(* Initialized const variables should be included as outputs of the function, (* Initialized const variables should be included as outputs of the function,
so [for_writing] must be false for local initializations. It should be so [for_writing] must be false for local initializations. It should be
...@@ -302,8 +301,8 @@ end) = struct ...@@ -302,8 +301,8 @@ end) = struct
Add it into the under-approximated outputs. *) Add it into the under-approximated outputs. *)
Zone.link data.under_outputs_d new_outs Zone.link data.under_outputs_d new_outs
else data.under_outputs_d else data.under_outputs_d
in { in
under_outputs_d = new_sure_outs; { under_outputs_d = new_sure_outs;
over_inputs_d = Zone.join data.over_inputs_d new_inputs; over_inputs_d = Zone.join data.over_inputs_d new_inputs;
over_outputs_d = Zone.join data.over_outputs_d new_outs } over_outputs_d = Zone.join data.over_outputs_d new_outs }
...@@ -372,9 +371,16 @@ end) = struct ...@@ -372,9 +371,16 @@ end) = struct
let e_inputs = !Db.From.find_deps_no_transitivity_state state e in let e_inputs = !Db.From.find_deps_no_transitivity_state state e in
add_out ~for_writing:false state lv e_inputs acc add_out ~for_writing:false state lv e_inputs acc
| CompoundInit(ct, initl) -> | CompoundInit(ct, initl) ->
let implicit = true in (* Avoid folding implicit zero-initializer of large arrays. *)
let implicit = Cumulative_analysis.fold_implicit_initializer ct in
let doinit o i _ data = aux (Cil.addOffsetLval o lv) i data in let doinit o i _ data = aux (Cil.addOffsetLval o lv) i data in
Cil.foldLeftCompound ~implicit ~doinit ~ct ~initl ~acc let data = Cil.foldLeftCompound ~implicit ~doinit ~ct ~initl ~acc in
if implicit then data else
(* If the implicit zero-initializers hade been skipped, add the
zone of the array as outputs. It is exactly the written zone for
arrays of scalar elements. Nothing is read by zero-initializers,
so the inputs are empty. *)
add_out ~for_writing:false state lv Zone.bottom acc
in in
aux (Cil.var v) i data aux (Cil.var v) i data
| Call (lvaloption,funcexp,argl,loc) -> | Call (lvaloption,funcexp,argl,loc) ->
......
...@@ -89,10 +89,19 @@ class virtual do_it_ = object(self) ...@@ -89,10 +89,19 @@ class virtual do_it_ = object(self)
let rec aux lv = function let rec aux lv = function
| SingleInit _ -> self#do_assign ~for_writing:false lv | SingleInit _ -> self#do_assign ~for_writing:false lv
| CompoundInit (ct, initl) -> | CompoundInit (ct, initl) ->
let implicit = true in (* Avoid folding the implicit zero-initializers of large arrays. *)
let doinit o i _ () = aux (Cil.addOffsetLval o lv) i in if Cumulative_analysis.fold_implicit_initializer ct
Cil.foldLeftCompound ~implicit ~doinit ~ct ~initl ~acc:() then
in aux (Cil.var v) i let implicit = true in
let doinit o i _ () = aux (Cil.addOffsetLval o lv) i in
Cil.foldLeftCompound ~implicit ~doinit ~ct ~initl ~acc:()
else
(* For arrays of scalar elements, all the zone covered by the
array is written. For arrays of structs containing padding
bits, this is a sound over-approximation. *)
self#do_assign ~for_writing:false lv
in
aux (Cil.var v) i
| Local_init (v, ConsInit(f, _, _),_) -> | Local_init (v, ConsInit(f, _, _),_) ->
let state = Db.Value.get_state self#current_kinstr in let state = Db.Value.get_state self#current_kinstr in
if Cvalue.Model.is_top state then self#join Zone.top if Cvalue.Model.is_top state then self#join Zone.top
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment