diff --git a/src/plugins/value/engine/iterator.ml b/src/plugins/value/engine/iterator.ml index 8300fb92d130d1f72e0304d3fbe8d6267a33a098..df784153c29a4e34694fe08b3941d9e8fe23d2a4 100644 --- a/src/plugins/value/engine/iterator.ml +++ b/src/plugins/value/engine/iterator.ml @@ -88,10 +88,10 @@ module Make_Dataflow (* Ideally, the slevel parameter should not be used anymore in this file but it is still required for logic interpretation *) - let slevel, history_size = + let slevel, call_return_policy = let module P = Partitioning_parameters.Make (AnalysisParam) in P.slevel, - P.history_size + P.call_return_policy (* --- Abstract values storage --- *) @@ -282,8 +282,8 @@ module Make_Dataflow (* Propagate info that the current call cannot be cached either *) cacheable := Eval.NoCacheCallers; (* Recombine callee partitioning keys with caller key *) - let recombine = Partition.Key.recombine ~history_size in - List.map (fun (k,s) -> recombine key k, s) result + let recombine = Partition.Key.recombine ~policy:call_return_policy in + List.map (fun (k,s) -> recombine ~caller:key ~callee:k, s) result let transfer_instr (stmt : stmt) (instr : instr) : transfer_function = match instr with diff --git a/src/plugins/value/partitioning/partition.ml b/src/plugins/value/partitioning/partition.ml index 49a4ef331b83d4b862831806ca665ff6f46e3189..32ea6246dbdaa5f561516fa9770f632980e6e9f7 100644 --- a/src/plugins/value/partitioning/partition.ml +++ b/src/plugins/value/partitioning/partition.ml @@ -161,6 +161,13 @@ type key = { dynamic_splits : split_monitor SplitMap.t; (* term -> monitor *) } +type call_return_policy = { + policy_keep_callee_splits: bool; + policy_keep_callee_history: bool; + policy_keep_caller_history: bool; + policy_history_size: int; +} + module Key = struct open Datatype @@ -243,19 +250,27 @@ struct let exceed_rationing key = key.ration_stamp = None - let recombine ~history_size k1 k2 = - let merge_split _ v1 v2 = + let recombine ~policy ~caller ~callee = + let keep_second _ v1 v2 = match v1, v2 with | None, None -> None - | Some v, None | None, Some v -> Some v - | Some _v1, Some v2 -> Some v2 (* Keep the newest split value *) + | Some x, None | (Some _ | None), Some x -> Some x in { ration_stamp = None; - branches = Extlib.list_first_n history_size (k2.branches @ k1.branches); - loops = k1.loops; - splits = SplitMap.merge merge_split k1.splits k2.splits; + branches = + Extlib.list_first_n policy.policy_history_size ( + (if policy.policy_keep_callee_history then callee.branches else []) @ + (if policy.policy_keep_caller_history then caller.branches else []) + ); + loops = caller.loops; + splits = + if policy.policy_keep_callee_splits + then SplitMap.merge keep_second caller.splits callee.splits + else caller.splits; dynamic_splits = - SplitMap.merge merge_split k1.dynamic_splits k2.dynamic_splits; + if policy.policy_keep_callee_splits + then SplitMap.merge keep_second caller.dynamic_splits callee.dynamic_splits + else caller.dynamic_splits; } end diff --git a/src/plugins/value/partitioning/partition.mli b/src/plugins/value/partitioning/partition.mli index d894e23fc842b42ee9882356bc48aee8607e71f5..7ef819e2a779b6ef05f25c41fc802b8616413f65 100644 --- a/src/plugins/value/partitioning/partition.mli +++ b/src/plugins/value/partitioning/partition.mli @@ -41,12 +41,19 @@ (** Partitioning keys attached to states. *) type key +type call_return_policy = { + policy_keep_callee_splits: bool; + policy_keep_callee_history: bool; + policy_keep_caller_history: bool; + policy_history_size: int; +} + module Key : sig include Datatype.S_with_collections with type t = key val zero : t (** Initial key: no partitioning. *) val exceed_rationing: t -> bool - val recombine : history_size:int -> - t -> t -> t (** Recombinaison of keys after a call *) + val recombine : policy:call_return_policy -> + caller:t -> callee:t -> t (** Recombinaison of keys after a call *) end (** Collection of states, each identified by a unique key. *) diff --git a/src/plugins/value/partitioning/partitioning_parameters.ml b/src/plugins/value/partitioning/partitioning_parameters.ml index 4ddcf1835217ca9caa6cdfdd8bd8c3f28c1979ce..60f8b52616c673f009f0a9bd971e059944ef38cf 100644 --- a/src/plugins/value/partitioning/partitioning_parameters.ml +++ b/src/plugins/value/partitioning/partitioning_parameters.ml @@ -139,4 +139,13 @@ struct acc (* Impossible to convert term to lval *) in List.fold_left map_annot [] (get_flow_annot stmt) + + let call_return_policy = { + Partition.policy_keep_callee_splits = + Value_parameters.InterproceduralPartitioningKeepSplits.get (); + policy_keep_callee_history = + Value_parameters.InterproceduralPartitioningKeepHistory.get (); + policy_keep_caller_history = true; + policy_history_size = history_size; + } end diff --git a/src/plugins/value/partitioning/partitioning_parameters.mli b/src/plugins/value/partitioning/partitioning_parameters.mli index 891a2b72b6f988cd8a56f2495f90d55f87a71be1..636eabc5bcf6a76ace74f4b637c1cb8c9d51851a 100644 --- a/src/plugins/value/partitioning/partitioning_parameters.mli +++ b/src/plugins/value/partitioning/partitioning_parameters.mli @@ -31,4 +31,5 @@ module Make (Kf : sig val kf: kernel_function end) : sig val history_size : int val universal_splits : Partition.action list val flow_actions : stmt -> Partition.action list + val call_return_policy : Partition.call_return_policy end diff --git a/src/plugins/value/value_parameters.ml b/src/plugins/value/value_parameters.ml index c1a44a5949f45fbb30df7eb57e360f70bc44e22d..324cb0f02f98b6d146f2e27a16e5ca41e25a285c 100644 --- a/src/plugins/value/value_parameters.ml +++ b/src/plugins/value/value_parameters.ml @@ -791,6 +791,26 @@ module SplitLimit = let () = add_precision_dep SplitLimit.parameter let () = SplitLimit.set_range 0 max_int +let () = Parameter_customize.set_group precision_tuning +let () = Parameter_customize.is_invisible () +module InterproceduralPartitioningKeepSplits = + False + (struct + let option_name = "-eva-interprocedural-partitioning-keep-splits" + let help = "Keep partitioning splits through function returns" + end) +let () = add_precision_dep InterproceduralPartitioningKeepSplits.parameter + +let () = Parameter_customize.set_group precision_tuning +let () = Parameter_customize.is_invisible () +module InterproceduralPartitioningKeepHistory = + False + (struct + let option_name = "-eva-interprocedural-partitioning-keep-history" + let help = "Keep partitioning history through function returns" + end) +let () = add_precision_dep InterproceduralPartitioningKeepHistory.parameter + let () = Parameter_customize.set_group precision_tuning let () = Parameter_customize.argument_may_be_fundecl () module SplitReturnFunction = diff --git a/src/plugins/value/value_parameters.mli b/src/plugins/value/value_parameters.mli index 0442dbcc0bb22414545f59df80dc386b49b15061..dca2eb2210838753fa044d046fcc2d01ffe24f54 100644 --- a/src/plugins/value/value_parameters.mli +++ b/src/plugins/value/value_parameters.mli @@ -79,6 +79,8 @@ module DefaultLoopUnroll : Parameter_sig.Int module HistoryPartitioning : Parameter_sig.Int module ValuePartitioning : Parameter_sig.String_set module SplitLimit : Parameter_sig.Int +module InterproceduralPartitioningKeepSplits : Parameter_sig.Bool +module InterproceduralPartitioningKeepHistory : Parameter_sig.Bool module ArrayPrecisionLevel: Parameter_sig.Int diff --git a/tests/value/partitioning-interproc.c b/tests/value/partitioning-interproc.c index 1b42df1bfba7061ececa7ef34666b14ae84a40c2..7cb9dc220aa9c4b3ac751b632251ca2cd4edecee 100644 --- a/tests/value/partitioning-interproc.c +++ b/tests/value/partitioning-interproc.c @@ -1,7 +1,7 @@ /* run.config* GCC: - STDOPT: #"-main cassign_test -eva-partition-history 1" - STDOPT: #"-main fabs_test -eva-partition-history 1 -eva-domains equality" + STDOPT: #"-main cassign_test -eva-partition-history 1 -eva-interprocedural-partitioning-keep-history" + STDOPT: #"-main fabs_test -eva-partition-history 1 -eva-domains equality -eva-interprocedural-partitioning-keep-history" */ #include "__fc_builtin.h"