Skip to content

Commit 9f677d7

Browse files
Merge pull request #772 from leunam99/master
Autotuning of Configuration
2 parents 42fa549 + b6b7cde commit 9f677d7

28 files changed

+1846
-429
lines changed

docs/user-guide/annotating.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,30 @@ The following string arguments are supported:
2626
4. `apron.context`/`apron.no-context` to override the `ana.apron.context` option.
2727
5. `widen`/`no-widen` to override the `ana.context.widen` option.
2828
29+
### Apron attributes
30+
The Apron library can be set to only track variables with the attribute `goblint_apron_track`
31+
32+
### Array attributes
33+
Arrays can be annotated with the domain that should be used for it ("unroll", "partitioned", or "trivial"):
34+
35+
```c
36+
int x[4] __attribute__((goblint_array_domain("unroll")));
37+
__attribute__((goblint_array_domain("trivial"))) int x[4];
38+
39+
struct array {
40+
int arr[5] __attribute__((goblint_array_domain("partitioned")));
41+
};
42+
```
43+
It is also possible to annotate a type, so that all arrays of this type without an own attribute will use this one:
44+
45+
```c
46+
typedef int unrollInt __attribute__((goblint_array_domain("trivial")));
47+
unrollInt x[4];
48+
```
49+
50+
One can also annotate pointer parameters. Inside the function of the parameter, Goblint tries to use the annotated domain for the arrays pointed at by that pointer. This is not guaranteed to work, as following the pointers is done only in the first analyzed function context.
51+
52+
2953
3054
## Functions
3155
Goblint-specific functions can be called in the code, where they assist the analyzer but have no runtime effect.

src/analyses/apron/apronAnalysis.apron.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ struct
147147
)
148148
else (
149149
let v_out = Goblintutil.create_var @@ makeVarinfo false (v.vname ^ "#out") v.vtype in (* temporary local g#out for global g *)
150+
v_out.vattr <- v.vattr; (*copy the attributes because the tracking may depend on them. Otherwise an assertion fails *)
150151
let st = {st with apr = AD.add_vars st.apr [V.local v_out]} in (* add temporary g#out *)
151152
let st' = {st with apr = f st v_out} in (* g#out = e; *)
152153
if M.tracing then M.trace "apron" "write_global %a %a\n" d_varinfo v d_varinfo v_out;

src/analyses/base.ml

Lines changed: 60 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -87,14 +87,50 @@ struct
8787

8888
let is_privglob v = GobConfig.get_bool "annotation.int.privglobs" && v.vglob
8989

90-
let project_val p_opt value is_glob =
91-
match GobConfig.get_bool "annotation.int.enabled", is_glob, p_opt with
92-
| true, true, _ -> VD.project PU.max_int_precision value
93-
| true, false, Some p -> VD.project p value
94-
| _ -> value
90+
(*This is a bit of a hack to be able to change array domains if a pointer to an array is given as an argument*)
91+
(*We have to prevent different domains to be used at the same time for the same array*)
92+
(*After a function call, the domain has to be the same as before and we can not depend on the pointers staying the same*)
93+
(*-> we determine the arrays a pointer can point to once at the beginning of a function*)
94+
(*There surely is a better way, because this means that often the wrong one gets chosen*)
95+
module VarH = Hashtbl.Make(CilType.Varinfo)
96+
module VarMap = Map.Make(CilType.Varinfo)
97+
let array_map = VarH.create 20
98+
99+
let add_to_array_map fundec arguments =
100+
let rec pointedArrayMap = function
101+
| [] -> VarMap.empty
102+
| (info,value)::xs -> (
103+
match value with
104+
| `Address t when hasAttribute "goblint_array_domain" info.vattr -> (
105+
let possibleVars = PreValueDomain.AD.to_var_may t in
106+
List.fold_left (fun map arr -> VarMap.add arr (info.vattr) map) (pointedArrayMap xs) @@ List.filter (fun info -> isArrayType info.vtype) possibleVars
107+
)
108+
| _ -> pointedArrayMap xs
109+
)
110+
in
111+
match VarH.find_option array_map fundec.svar with
112+
| Some _ -> () (*We already have something -> do not change it*)
113+
| None -> VarH.add array_map fundec.svar (pointedArrayMap arguments)
114+
115+
let attributes_varinfo info fundec =
116+
let map = VarH.find array_map fundec.svar in
117+
match VarMap.find_opt info map with
118+
| Some attr -> Some (attr, typeAttrs (info.vtype)) (*if the function has a different domain for this array, use it*)
119+
| None -> Some (info.vattr, typeAttrs (info.vtype))
120+
121+
let project_val ask array_attr p_opt value is_glob =
122+
let p = if GobConfig.get_bool "annotation.int.enabled" then (
123+
if is_glob then
124+
Some PU.max_int_precision
125+
else p_opt
126+
) else None
127+
in
128+
let a = if GobConfig.get_bool "annotation.goblint_array_domain" then array_attr else None in
129+
VD.project ask p a value
95130

96-
let project p_opt cpa =
97-
CPA.mapi (fun varinfo value -> project_val p_opt value (is_privglob varinfo)) cpa
131+
let project ask p_opt cpa fundec =
132+
CPA.mapi (fun varinfo value -> project_val ask (attributes_varinfo varinfo fundec) p_opt value (is_privglob varinfo))
133+
cpa
98134

99135

100136
(**************************************************************************
@@ -120,7 +156,8 @@ struct
120156
Priv.init ()
121157

122158
let finalize () =
123-
Priv.finalize ()
159+
Priv.finalize ();
160+
VarH.clear array_map
124161

125162
(**************************************************************************
126163
* Abstract evaluation functions
@@ -1298,7 +1335,7 @@ struct
12981335

12991336
let update_variable variable typ value cpa =
13001337
if ((get_bool "exp.volatiles_are_top") && (is_always_unknown variable)) then
1301-
CPA.add variable (VD.top_value typ) cpa
1338+
CPA.add variable (VD.top_value ~varAttr:variable.vattr typ) cpa
13021339
else
13031340
CPA.add variable value cpa
13041341

@@ -1355,8 +1392,8 @@ struct
13551392
lval_type
13561393
in
13571394
let update_offset old_value =
1358-
(* Projection to highest Precision *)
1359-
let projected_value = project_val None value (is_global a x) in
1395+
(* Projection globals to highest Precision *)
1396+
let projected_value = project_val a None None value (is_global a x) in
13601397
let new_value = VD.update_offset a old_value offs projected_value lval_raw ((Var x), cil_offset) t in
13611398
if WeakUpdates.mem x st.weak then
13621399
VD.join old_value new_value
@@ -1384,7 +1421,7 @@ struct
13841421
The case when invariant = true requires the old_value to be sound for the meet.
13851422
Allocated blocks are representend by Blobs with additional information, so they need to be looked-up. *)
13861423
let old_value = if not invariant && Cil.isIntegralType x.vtype && not (a.f (IsHeapVar x)) && offs = `NoOffset then begin
1387-
VD.bot_value lval_type
1424+
VD.bot_value ~varAttr:x.vattr lval_type
13881425
end else
13891426
Priv.read_global a priv_getg st x
13901427
in
@@ -2166,7 +2203,7 @@ struct
21662203
begin match Addr.to_var_offset (AD.choose lval_val) with
21672204
| Some (x,offs) ->
21682205
let t = v.vtype in
2169-
let iv = VD.bot_value t in (* correct bottom value for top level variable *)
2206+
let iv = VD.bot_value ~varAttr:v.vattr t in (* correct bottom value for top level variable *)
21702207
if M.tracing then M.tracel "set" "init bot value: %a\n" VD.pretty iv;
21712208
let nv = VD.update_offset (Analyses.ask_of_ctx ctx) iv offs rval_val (Some (Lval lval)) lval t in (* do desired update to value *)
21722209
set_savetop ~ctx (Analyses.ask_of_ctx ctx) ctx.global ctx.local (AD.from_var v) lval_t nv ~lval_raw:lval ~rval_raw:rval (* set top-level variable to updated value *)
@@ -2227,7 +2264,7 @@ struct
22272264

22282265
let body ctx f =
22292266
(* First we create a variable-initvalue pair for each variable *)
2230-
let init_var v = (AD.from_var v, v.vtype, VD.init_value v.vtype) in
2267+
let init_var v = (AD.from_var v, v.vtype, VD.init_value ~varAttr:v.vattr v.vtype) in
22312268
(* Apply it to all the locals and then assign them all *)
22322269
let inits = List.map init_var f.slocals in
22332270
set_many ~ctx (Analyses.ask_of_ctx ctx) ctx.global ctx.local inits
@@ -2350,6 +2387,7 @@ struct
23502387
in
23512388
(* Assign parameters to arguments *)
23522389
let pa = GobList.combine_short fundec.sformals vals in (* TODO: is it right to ignore missing formals/args? *)
2390+
add_to_array_map fundec pa;
23532391
let new_cpa = CPA.add_list pa st'.cpa in
23542392
(* List of reachable variables *)
23552393
let reachable = List.concat_map AD.to_var_may (reachable_vars (Analyses.ask_of_ctx ctx) (get_ptrs vals) ctx.global st) in
@@ -2358,7 +2396,7 @@ struct
23582396

23592397
(* Projection to Precision of the Callee *)
23602398
let p = PU.int_precision_from_fundec fundec in
2361-
let new_cpa = project (Some p) new_cpa in
2399+
let new_cpa = project (Analyses.ask_of_ctx ctx) (Some p) new_cpa fundec in
23622400

23632401
(* Identify locals of this fundec for which an outer copy (from a call down the callstack) is reachable *)
23642402
let reachable_other_copies = List.filter (fun v -> match Cilfacade.find_scope_fundec v with Some scope -> CilType.Fundec.equal scope fundec | None -> false) reachable in
@@ -2720,9 +2758,13 @@ struct
27202758
let nst = add_globals st fun_st in
27212759

27222760
(* Projection to Precision of the Caller *)
2723-
let p = PrecisionUtil.int_precision_from_node () in (* Since f is the fundec of the Callee we have to get the fundec of the current Node instead *)
2724-
let return_val = project_val (Some p) return_val (is_privglob (return_varinfo ())) in
2725-
let cpa' = project (Some p) nst.cpa in
2761+
let p = PrecisionUtil.int_precision_from_node ()in (* Since f is the fundec of the Callee we have to get the fundec of the current Node instead *)
2762+
let callerFundec = match !MyCFG.current_node with
2763+
| Some n -> Node.find_fundec n
2764+
| None -> failwith "callerfundec not found"
2765+
in
2766+
let return_val = project_val (Analyses.ask_of_ctx ctx) (attributes_varinfo (return_varinfo ()) callerFundec) (Some p) return_val (is_privglob (return_varinfo ())) in
2767+
let cpa' = project (Analyses.ask_of_ctx ctx) (Some p) nst.cpa callerFundec in
27262768

27272769
let st = { nst with cpa = cpa'; weak = st.weak } in (* keep weak from caller *)
27282770
match lval with

0 commit comments

Comments
 (0)