Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
F
frama-c
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Deploy
Releases
Container Registry
Model registry
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
pub
frama-c
Commits
a1337eff
Commit
a1337eff
authored
4 years ago
by
David Bühler
Browse files
Options
Downloads
Patches
Plain Diff
[Eva] Fixes the automatic loop unrolling on loops with goto statements.
parent
f34b55a3
No related branches found
No related tags found
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
src/plugins/value/partitioning/auto_loop_unroll.ml
+28
-29
28 additions, 29 deletions
src/plugins/value/partitioning/auto_loop_unroll.ml
with
28 additions
and
29 deletions
src/plugins/value/partitioning/auto_loop_unroll.ml
+
28
−
29
View file @
a1337eff
...
@@ -202,40 +202,39 @@ let is_safe_instruction lval = function
...
@@ -202,40 +202,39 @@ let is_safe_instruction lval = function
(* Returns true if the statement may assign [lval] during an iteration of the
(* Returns true if the statement may assign [lval] during an iteration of the
loop [loop]. [lval] is a candidate for the automatic loop unroll heuristic,
loop [loop]. [lval] is a candidate for the automatic loop unroll heuristic,
and thus is modified within the loop. *)
and thus is modified within the loop. *)
let
is_safe
lval
~
loop
stmt
=
let
is_safe
lval
kf
~
loop
stmt
=
(* The current block being checked for a goto statement. *)
let
rec
is_safe_stmt
~
goto
stmt
=
let
current_block
=
ref
None
in
let
rec
is_safe_stmt
stmt
=
match
stmt
.
skind
with
match
stmt
.
skind
with
|
Instr
instr
->
is_safe_instruction
lval
instr
|
Instr
instr
->
is_safe_instruction
lval
instr
|
Return
_
|
Break
_
|
Continue
_
->
true
|
Return
_
|
Break
_
|
Continue
_
->
true
|
If
(
_
,
b_then
,
b_else
,
_
)
->
is_safe_block
b_then
&&
is_safe_block
b_else
|
If
(
_
,
b_then
,
b_else
,
_
)
->
is_safe_block
~
goto
b_then
&&
is_safe_block
~
goto
b_else
|
Block
b
|
Block
b
|
Switch
(
_
,
b
,
_
,
_
)
|
Switch
(
_
,
b
,
_
,
_
)
|
Loop
(
_
,
b
,
_
,
_
,
_
)
->
is_safe_block
b
|
Loop
(
_
,
b
,
_
,
_
,
_
)
->
is_safe_block
~
goto
b
|
UnspecifiedSequence
list
->
|
UnspecifiedSequence
list
->
List
.
for_all
(
fun
(
stmt
,
_
,
_
,
_
,
_
)
->
is_safe_stmt
stmt
)
list
List
.
for_all
(
fun
(
stmt
,
_
,
_
,
_
,
_
)
->
is_safe_stmt
~
goto
stmt
)
list
|
Goto
(
dest
,
_
)
->
begin
|
Goto
(
dest
,
_
)
->
let
dest_blocks
=
Kernel_function
.
find_all_enclosing_blocks
!
dest
in
(* If [goto] holds, we are already checking a block for a [goto]. Do not
(* If the goto leaves the loop, then it is saf
e. *)
process goto statements again her
e. *)
if
List
.
mem
loop
dest_blocks
then
true
else
goto
||
(* If the goto moves into the block currently being checked, then it
let
first_stmt
=
List
.
hd
loop
.
bstmts
in
is safe i
f the
b
lo
ck is safe (which we are currently checking)
. *)
(* I
f the lo
op cannot be reached from [dest], then it is safe
. *)
match
!
current_block
with
not
(
Stmts_graph
.
stmt_can_reach
kf
!
dest
first_stmt
)
||
|
Some
current_block
when
List
.
mem
current_block
dest_blocks
->
true
(* Otherwise, if the goto leaves the loop, then it forms another loop
|
_
->
that contains the current loop, which we don't want to unroll. *)
(* Otherwise, we need to check that the whole block englob
in
g
let
dest_blocks
=
Kernel_function
.
find_all_enclosing_blocks
!
dest
in
both the source and the destination of the goto is safe. *)
List
.
exists
(
Cil_datatype
.
Block
.
equal
loop
)
dest_blocks
&&
let
block
=
Kernel_function
.
common_block
!
dest
stmt
in
(* Otherwise, the goto stays within the loop: check that the block
current_block
:=
Some
block
;
englobing both the source and the destination is safe. *)
(* If this block is the loop itself, then it is not safe, as [lval]
let
block
=
Kernel_function
.
common_block
!
dest
stmt
in
is modified wi
th
i
n
the loop. *)
(* If this block is the loop itself,
th
e
n
it is not safe,
not
(
block
=
loop
)
&&
is_safe_block
block
as [lval] is modified within the loop. *)
end
not
(
block
==
loop
)
&&
is_safe_block
~
goto
:
true
block
|
_
->
false
|
_
->
false
(* A block is safe if all its statements are safe. *)
(* A block is safe if all its statements are safe. *)
and
is_safe_block
block
=
List
.
for_all
is_safe_stmt
block
.
bstmts
in
and
is_safe_block
~
goto
b
=
List
.
for_all
(
is_safe_stmt
~
goto
)
b
.
bstmts
in
is_safe_stmt
stmt
is_safe_stmt
~
goto
:
false
stmt
module
Make
(
Abstract
:
Abstractions
.
Eva
)
=
struct
module
Make
(
Abstract
:
Abstractions
.
Eva
)
=
struct
...
@@ -393,7 +392,7 @@ module Make (Abstract: Abstractions.Eva) = struct
...
@@ -393,7 +392,7 @@ module Make (Abstract: Abstractions.Eva) = struct
should be a direct access to a variable whose address is not taken,
should be a direct access to a variable whose address is not taken,
and which should not be global if the loop contains function calls.
and which should not be global if the loop contains function calls.
Returns None if no increment can be computed. *)
Returns None if no increment can be computed. *)
let
compute_delta
lval
loop
=
let
compute_delta
kf
lval
loop
=
let
rec
delta_stmt
acc
stmt
=
let
rec
delta_stmt
acc
stmt
=
match
stmt
.
skind
with
match
stmt
.
skind
with
|
Instr
instr
->
delta_instruction
lval
acc
instr
|
Instr
instr
->
delta_instruction
lval
acc
instr
...
@@ -410,7 +409,7 @@ module Make (Abstract: Abstractions.Eva) = struct
...
@@ -410,7 +409,7 @@ module Make (Abstract: Abstractions.Eva) = struct
List
.
fold_left
(
fun
acc
(
s
,
_
,
_
,
_
,
_
)
->
delta_stmt
acc
s
)
acc
list
List
.
fold_left
(
fun
acc
(
s
,
_
,
_
,
_
,
_
)
->
delta_stmt
acc
s
)
acc
list
|
_
->
|
_
->
(* For other statements, we only check that they do not modify [lval]. *)
(* For other statements, we only check that they do not modify [lval]. *)
if
is_safe
lval
~
loop
stmt
then
acc
else
raise
NoIncrement
if
is_safe
lval
kf
~
loop
stmt
then
acc
else
raise
NoIncrement
and
delta_block
acc
block
=
and
delta_block
acc
block
=
List
.
fold_left
delta_stmt
acc
block
.
bstmts
List
.
fold_left
delta_stmt
acc
block
.
bstmts
in
in
...
@@ -508,7 +507,7 @@ module Make (Abstract: Abstractions.Eva) = struct
...
@@ -508,7 +507,7 @@ module Make (Abstract: Abstractions.Eva) = struct
evaluate_lvalue
state
lval
>>:
fun
v_init
->
evaluate_lvalue
state
lval
>>:
fun
v_init
->
(* Computes an over-approximation [v_delta] of the increment of [lval]
(* Computes an over-approximation [v_delta] of the increment of [lval]
in one iteration of the loop. *)
in one iteration of the loop. *)
compute_delta
lval
loop_block
>>:
fun
v_delta
->
compute_delta
kf
lval
loop_block
>>:
fun
v_delta
->
let
typ
=
Cil
.
typeOfLval
lval
in
let
typ
=
Cil
.
typeOfLval
lval
in
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. *)
(* Possible iterations numbers to exit the loop. *)
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment