Skip to content
Snippets Groups Projects
Commit 1630079c authored by David Bühler's avatar David Bühler
Browse files

[Eva] Slightly better heuristic for automatic loop unroll on some conditions.

parent c81253b8
No related branches found
No related tags found
No related merge requests found
...@@ -51,6 +51,10 @@ ...@@ -51,6 +51,10 @@
open Cil_types open Cil_types
let is_true = function
| `True | `TrueReduced _ -> true
| _ -> false
(* Is a statement a loop exit condition? If so, returns the condition and (* Is a statement a loop exit condition? If so, returns the condition and
whether the condition must hold to exit the loop. Otherwise, returns None. *) whether the condition must hold to exit the loop. Otherwise, returns None. *)
let is_conditional_break stmt = let is_conditional_break stmt =
...@@ -262,9 +266,23 @@ module Make (Abstract: Abstractions.Eva) = struct ...@@ -262,9 +266,23 @@ module Make (Abstract: Abstractions.Eva) = struct
(* If the new value of [expr] is top, no reduction has been performed. *) (* If the new value of [expr] is top, no reduction has been performed. *)
if Val.(equal top value) then None else Some (value, record) if Val.(equal top value) then None else Some (value, record)
in in
(* Different strategies whether cvalue is present. *) (* Assumes that [condition] is [positive]. Returns an over-approximation
match Val.get Main_values.CVal.key with of the values for which [condition] is [positive]. *)
| Some get_cvalue -> reduce positive >>= fun (value, record) ->
(* Evaluates [condition] with the hypothesis [expr] ∈ [value], to check
whether [expr] ∈ [value] ⇒ [condition] = [positive]. *)
let valuation = Valuation.add valuation expr record in
fst (Eval.evaluate ~valuation ~reduction:false state condition)
>> fun (_valuation, v) ->
let satisfied =
if positive
then not Val.(is_included zero v)
else Val.(equal zero v)
in
(* If the condition is satisfied, returns [value]. Otherwise, uses a
specific feature to cvalue (if possible) to compute a better value. *)
if satisfied then Some value else
Val.get Main_values.CVal.key >>= fun get_cvalue ->
(* Assumes that [condition] is NOT [positive]. *) (* Assumes that [condition] is NOT [positive]. *)
reduce (not positive) >>= fun (value, _record) -> reduce (not positive) >>= fun (value, _record) ->
(* [value] is an over-approximation of the values of [expr] for which (* [value] is an over-approximation of the values of [expr] for which
...@@ -273,21 +291,6 @@ module Make (Abstract: Abstractions.Eva) = struct ...@@ -273,21 +291,6 @@ module Make (Abstract: Abstractions.Eva) = struct
let cvalue = get_cvalue value in let cvalue = get_cvalue value in
cvalue_complement (Cil.typeOf expr) cvalue >>= fun cvalue -> cvalue_complement (Cil.typeOf expr) cvalue >>= fun cvalue ->
Some (Val.set Main_values.CVal.key cvalue Val.top) Some (Val.set Main_values.CVal.key cvalue Val.top)
| None ->
(* Assumes that [condition] is [positive]. Returns an over-approximation
of the values for which [condition] is [positive]. *)
reduce positive >>= fun (value, record) ->
(* Evaluates [condition] with the hypothesis [expr] ∈ [value], to check
whether [expr] ∈ [value] ⇒ [condition] = [positive]. *)
let valuation = Valuation.add valuation expr record in
fst (Eval.evaluate ~valuation ~reduction:false state condition)
>> fun (_valuation, v) ->
let satisfied =
if positive
then not Val.(is_included zero v)
else Val.(equal zero v)
in
if satisfied then Some value else None
(* Same as [reduce_to_expr] above, but builds the proper valuation from the (* Same as [reduce_to_expr] above, but builds the proper valuation from the
[state]. [state] is the entry state of the loop, and [expr] is the only [state]. [state] is the entry state of the loop, and [expr] is the only
...@@ -431,9 +434,18 @@ module Make (Abstract: Abstractions.Eva) = struct ...@@ -431,9 +434,18 @@ module Make (Abstract: Abstractions.Eva) = struct
in one iteration of the loop. *) in one iteration of the loop. *)
compute_delta lval loop_block >>= fun v_delta -> compute_delta lval loop_block >>= fun v_delta ->
let typ = Cil.typeOfLval lval in let typ = Cil.typeOfLval lval in
let limit = Val.inject_int typ (Integer.of_int limit) in
(* Checks whether [v_init] + [limit] × [v_delta] ⊂ [v_exit]. *)
let binop op v1 v2 = Bottom.non_bottom (Val.forward_binop typ op v1 v2) in let binop op v1 v2 = Bottom.non_bottom (Val.forward_binop typ op v1 v2) in
(* Possible iterations numbers to exit the loop. *)
let iter_nb = binop Div (binop MinusA v_exit v_init) v_delta in
let bound = Abstract_value.Int (Integer.of_int limit) in
(* Use the iteration number if it is always smaller than the [limit].
Otherwise use [limit]. *)
let limit =
if is_true (Val.assume_bounded Alarms.Upper_bound bound iter_nb)
then iter_nb
else Val.inject_int typ (Integer.of_int limit)
in
(* Checks whether [v_init] + [limit] × [v_delta] ⊂ [v_exit]. *)
let value = binop PlusA v_init (binop Mult limit v_delta) in let value = binop PlusA v_init (binop Mult limit v_delta) in
Some (Val.is_included value v_exit) Some (Val.is_included value v_exit)
......
...@@ -341,14 +341,10 @@ ...@@ -341,14 +341,10 @@
[eva] Done for function complex_loops [eva] Done for function complex_loops
[eva] computing for function various_conditions <- main. [eva] computing for function various_conditions <- main.
Called from tests/value/auto_loop_unroll.c:251. Called from tests/value/auto_loop_unroll.c:251.
[eva] tests/value/auto_loop_unroll.c:192: starting to merge loop iterations [eva:loop-unroll] tests/value/auto_loop_unroll.c:192: Automatic loop unrolling.
[eva:alarm] tests/value/auto_loop_unroll.c:193: Warning: [eva] tests/value/auto_loop_unroll.c:195: Frama_C_show_each_11: {11}
signed overflow. assert res + 1 ≤ 2147483647; [eva:loop-unroll] tests/value/auto_loop_unroll.c:197: Automatic loop unrolling.
[eva] tests/value/auto_loop_unroll.c:195: Frama_C_show_each_11: [0..2147483647] [eva] tests/value/auto_loop_unroll.c:200: Frama_C_show_each_12: {12}
[eva] tests/value/auto_loop_unroll.c:197: starting to merge loop iterations
[eva:alarm] tests/value/auto_loop_unroll.c:198: Warning:
signed overflow. assert res + 1 ≤ 2147483647;
[eva] tests/value/auto_loop_unroll.c:200: Frama_C_show_each_12: [0..2147483647]
[eva] tests/value/auto_loop_unroll.c:203: starting to merge loop iterations [eva] tests/value/auto_loop_unroll.c:203: starting to merge loop iterations
[eva:alarm] tests/value/auto_loop_unroll.c:204: Warning: [eva:alarm] tests/value/auto_loop_unroll.c:204: Warning:
signed overflow. assert res + 1 ≤ 2147483647; signed overflow. assert res + 1 ≤ 2147483647;
......
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