Skip to content

Commit 1f2bb69

Browse files
authored
Merge pull request #1582 from goblint/refactor-loopUnroll
Refactor loopUnrolling autotuner
2 parents 815336e + 3e9f3cd commit 1f2bb69

1 file changed

Lines changed: 74 additions & 72 deletions

File tree

src/util/loopUnrolling.ml

Lines changed: 74 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -210,89 +210,91 @@ let constBefore var loop f =
210210
in
211211
fst @@ lastAssignmentToVarBeforeLoop (Some Z.zero) f.sbody.bstmts (*the top level call should never return false*)
212212

213-
let rec loopIterations start diff comp =
214-
let flip = function
215-
| Lt -> Gt
216-
| Gt -> Lt
217-
| Ge -> Le
218-
| Le -> Ge
219-
| s -> s
220-
in let loopIterations' goal shouldBeExact =
221-
let range = Z.sub goal start in
222-
if Z.equal diff Z.zero || Z.equal range Z.zero || (Z.gt diff Z.zero && Z.lt range Z.zero) || (Z.lt diff Z.zero && Z.gt range Z.zero) then
223-
None (*unfitting parameters*)
224-
else (
225-
let roundedDown = Z.div range diff in
226-
let isExact = Z.equal (Z.mul roundedDown diff) range in
227-
if isExact then
228-
Some roundedDown
229-
else if shouldBeExact then
230-
None
231-
else
232-
Some (Z.succ roundedDown)
233-
)
234-
in
235-
match comp with
236-
| BinOp (op, (Const _ as c), var, t) -> loopIterations start diff (BinOp (flip op, var, c, t))
237-
| BinOp (Lt, _, (Const (CInt (cint,_,_) )), _) -> if Z.lt diff Z.zero then None else loopIterations' cint false
238-
| BinOp (Gt, _, (Const (CInt (cint,_,_) )), _) -> if Z.gt diff Z.zero then None else loopIterations' cint false
239-
| BinOp (Le, _, (Const (CInt (cint,_,_) )), _) -> if Z.lt diff Z.zero then None else loopIterations' (Z.succ cint) false
240-
| BinOp (Ge, _, (Const (CInt (cint,_,_) )), _) -> if Z.gt diff Z.zero then None else loopIterations' (Z.pred cint) false
241-
| BinOp (Ne, _, (Const (CInt (cint,_,_) )), _) -> loopIterations' cint true
213+
(*find a single break in the else branch of a toplevel if*)
214+
let findBreakComparison loopStatement =
215+
try
216+
let compOption = ref None in
217+
let visitor = new findBreakVisitor (compOption) in
218+
ignore @@ visitCilBlock visitor (loopBody loopStatement);
219+
!compOption
220+
with WrongOrMultiple ->
221+
None
222+
223+
let getLoopVar = function
224+
| BinOp (op, (Const (CInt (goal, _, _) )), Lval ((Var varinfo), NoOffset), (TInt _)) when isCompare op && not varinfo.vglob ->
225+
(* TODO: define isCompare and flip in cilfacade and refactor to use instead of the many separately defined similar functions *)
226+
let flip = function | Lt -> Gt | Gt -> Lt | Ge -> Le | Le -> Ge | s -> s in
227+
Some (flip op, varinfo, goal)
228+
| BinOp (op, Lval ((Var varinfo), NoOffset), (Const (CInt (goal, _, _) )), (TInt _)) when isCompare op && not varinfo.vglob ->
229+
Some (op, varinfo, goal)
230+
| _ -> None
231+
232+
let getsPointedAt var func =
233+
try
234+
let visitor = new isPointedAtVisitor (var) in
235+
ignore @@ visitCilFunction visitor func;
236+
false
237+
with Found ->
238+
true
239+
240+
let assignmentDifference loop var =
241+
try
242+
let diff = ref None in
243+
let visitor = new findAssignmentConstDiff (diff, var) in
244+
ignore @@ visitCilBlock visitor loop;
245+
!diff
246+
with WrongOrMultiple ->
247+
None
248+
249+
let adjustGoal diff goal op =
250+
match op with
251+
| Lt -> if Z.lt diff Z.zero then None else Some goal
252+
| Gt -> if Z.gt diff Z.zero then None else Some goal
253+
| Le -> if Z.lt diff Z.zero then None else Some (Z.succ goal)
254+
| Ge -> if Z.gt diff Z.zero then None else Some (Z.pred goal)
255+
| Ne -> Some goal
242256
| _ -> failwith "unexpected comparison in loopIterations"
243257

244-
let ( >>= ) = Option.bind
245-
let fixedLoopSize loopStatement func =
246-
let findBreakComparison = try (*find a single break in the else branch of a toplevel if*)
247-
let compOption = ref None in
248-
let visitor = new findBreakVisitor(compOption) in
249-
ignore @@ visitCilBlock visitor (loopBody loopStatement);
250-
!compOption
251-
with | WrongOrMultiple -> None
252-
in let getLoopVar = function
253-
| BinOp (op, (Const (CInt _ )), Lval ((Var info), NoOffset), (TInt _))
254-
| BinOp (op, Lval ((Var info), NoOffset), (Const (CInt _ )), (TInt _)) when isCompare op && not info.vglob->
255-
Some info
256-
| _ -> None
257-
in let getsPointedAt var = try
258-
let visitor = new isPointedAtVisitor(var) in
259-
ignore @@ visitCilFunction visitor func;
260-
false
261-
with | Found -> true
262-
in let assignmentDifference loop var = try
263-
let diff = ref None in
264-
let visitor = new findAssignmentConstDiff(diff, var) in
265-
ignore @@ visitCilBlock visitor loop;
266-
!diff
267-
with | WrongOrMultiple -> None
268-
in
258+
let loopIterations start diff goal shouldBeExact =
259+
let range = Z.sub goal start in
260+
if Z.equal diff Z.zero || Z.equal range Z.zero || (Z.gt diff Z.zero && Z.lt range Z.zero) || (Z.lt diff Z.zero && Z.gt range Z.zero) then
261+
None (*unfitting parameters*)
262+
else (
263+
let roundedDown = Z.div range diff in
264+
let isExact = Z.equal (Z.mul roundedDown diff) range in
265+
if isExact then
266+
Some roundedDown
267+
else if shouldBeExact then
268+
None
269+
else
270+
Some (Z.succ roundedDown)
271+
)
269272

270-
findBreakComparison >>= fun comparison ->
271-
getLoopVar comparison >>= fun var ->
272-
if getsPointedAt var then
273+
let fixedLoopSize loopStatement func =
274+
let open GobOption.Syntax in
275+
let* comparison = findBreakComparison loopStatement in
276+
let* op, var, goal = getLoopVar comparison in
277+
if getsPointedAt var func then
273278
None
274279
else
275-
constBefore var loopStatement func >>= fun start ->
276-
assignmentDifference (loopBody loopStatement) var >>= fun diff ->
277-
Logs.debug "comparison: ";
278-
Pretty.fprint stderr (dn_exp () comparison) ~width:max_int;
279-
Logs.debug "";
280-
Logs.debug "variable: ";
281-
Logs.debug "%s" var.vname;
282-
Logs.debug "start:";
283-
Logs.debug "%s" @@ Z.to_string start;
284-
Logs.debug "diff:";
285-
Logs.debug "%s" @@ Z.to_string diff;
286-
let iterations = loopIterations start diff comparison in
280+
let* start = constBefore var loopStatement func in
281+
let* diff = assignmentDifference (loopBody loopStatement) var in
282+
let* goal = adjustGoal diff goal op in
283+
let iterations = loopIterations start diff goal (op=Ne) in
284+
Logs.debug "comparison: %a" CilType.Exp.pretty comparison;
285+
Logs.debug "variable: %s" var.vname;
286+
Logs.debug "start: %a" GobZ.pretty start;
287+
Logs.debug "diff: %a" GobZ.pretty diff;
287288
match iterations with
288289
| None -> Logs.debug "iterations failed"; None
289290
| Some s ->
290291
try
291292
let s' = Z.to_int s in
292-
Logs.debug "iterations:";
293-
Logs.debug "%d" s';
293+
Logs.debug "iterations: %d" s';
294294
Some s'
295-
with Z.Overflow -> Logs.debug "iterations too big for integer"; None
295+
with Z.Overflow ->
296+
Logs.debug "iterations too big for integer";
297+
None
296298

297299

298300
class arrayVisitor = object

0 commit comments

Comments
 (0)