@@ -8,12 +8,13 @@ open TerminationPreprocessing
88let loop_counters : stmt VarToStmt.t ref = ref VarToStmt. empty
99
1010(* * Checks whether a variable can be bounded. *)
11- let check_bounded man varinfo =
11+ let ask_bound man varinfo =
1212 let open IntDomain.IntDomTuple in
1313 let exp = Lval (Var varinfo, NoOffset ) in
1414 match man.ask (EvalInt exp) with
15- | `Top -> false
16- | `Lifted v -> not (is_top_of (ikind v) v)
15+ | `Top -> `Top
16+ | `Lifted v when is_top_of (ikind v) v -> `Top
17+ | `Lifted v -> `Lifted v
1718 | `Bot -> failwith " Loop counter variable is Bot."
1819
1920(* * We want to record termination information of loops and use the loop
@@ -41,28 +42,33 @@ struct
4142 let startstate _ = ()
4243 let exitstate = startstate
4344
44- let find_loop ~loop_counter =
45- VarToStmt. find loop_counter ! loop_counters
46-
4745 (* * Recognizes a call of [__goblint_bounded] to check the EvalInt of the
4846 * respective loop counter variable at that position. *)
4947 let special man (lval : lval option ) (f : varinfo ) (arglist : exp list ) =
50- if ! AnalysisState. postsolving then
48+ if ! AnalysisState. postsolving then (
5149 match f.vname, arglist with
52- "__goblint_bounded" , [Lval (Var loop_counter, NoOffset )] ->
53- (try
54- let loop_statement = find_loop ~loop_counter in
55- let is_bounded = check_bounded man loop_counter in
56- man.sideg () (G. add (`Lifted loop_statement) is_bounded (man.global () ));
57- (* In case the loop is not bounded, a warning is created. *)
58- if not (is_bounded) then (
59- M. warn ~loc: (M.Location. CilLocation (Cilfacade. get_stmtLoc loop_statement)) ~category: Termination " The program might not terminate! (Loop analysis)"
60- );
61- ()
62- with Not_found ->
63- failwith " Encountered a call to __goblint_bounded with an unknown loop counter variable." )
50+ | "__goblint_bounded" , [Lval (Var loop_counter, NoOffset )] ->
51+ begin match VarToStmt. find_opt loop_counter ! loop_counters with
52+ | Some loop_statement ->
53+ let bound = ask_bound man loop_counter in
54+ let is_bounded = bound <> `Top in
55+ man.sideg () (G. add (`Lifted loop_statement) is_bounded (man.global () ));
56+ let loc = M.Location. CilLocation (Cilfacade. get_stmtLoc loop_statement) in
57+ begin match bound with
58+ | `Top ->
59+ M. warn ~category: Termination ~loc " The program might not terminate! (Loop analysis)"
60+ | `Lifted bound ->
61+ (* TODO: aggregate these per loop (if unrolled) and warn using WarnGlobal? *)
62+ if GobConfig. get_bool " dbg.termination-bounds" then
63+ M. success ~category: Termination ~loc " Loop terminates: bounded by %a iteration(s)" IntDomain.IntDomTuple. pretty bound;
64+ end
65+ | None ->
66+ failwith " Encountered a call to __goblint_bounded with an unknown loop counter variable."
67+ end
68+ | "__goblint_bounded" , _ ->
69+ failwith " __goblint_bounded call unexpected arguments"
6470 | _ -> ()
65- else ( )
71+ )
6672
6773 let query man (type a ) (q : a Queries.t ): a Queries.result =
6874 match q with
0 commit comments