Skip to content

Commit a40ef51

Browse files
committed
Improve escape analysis for built-in atomic functions
1 parent 541d4ca commit a40ef51

File tree

4 files changed

+48
-23
lines changed

4 files changed

+48
-23
lines changed

common/src/concurrency_model/ConcurrencyModel.ml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,3 +118,6 @@ let classify_stmt stmt = match stmt.skind with
118118
| Instr instr -> classify_instr instr
119119
| Return _ -> Return
120120
| _ -> Other
121+
122+
let is_atomic_fn var =
123+
AtomicFunctions.exists (fun a -> Str.string_match (Str.regexp a) var.vname 0)

common/src/concurrency_model/ConcurrencyModel.mli

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,5 @@ type stmt =
3838
| Other
3939

4040
val classify_stmt : Stmt.t -> stmt
41+
42+
val is_atomic_fn : Varinfo.t -> bool

common/src/concurrency_model/ConcurrencyModel_load.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ let load_model value =
140140
load_or_skip load_conditions "Conditions" value
141141

142142
let load path =
143-
Format.printf "Loading %s\n" path;
143+
Core0.debug "Loading %s\n" path;
144144
let content = In_channel.with_open_text path In_channel.input_all in
145145
let yaml = Yaml.of_string_exn content in
146146
load_model yaml

common/src/value_analysis/BaseUtils.ml

Lines changed: 42 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -52,36 +52,56 @@ let is_thread_local base =
5252
end
5353
| _ -> false
5454

55-
(*
56-
class is_referenced = object
57-
inherit Visitor.frama_in_place
55+
let cache = ref (None : Varinfo.Set.t option)
5856

59-
module M = Base.Map
57+
class escapes_expr = object
58+
inherit Visitor.frama_c_inplace
6059

61-
val mutable cache = M.empty
62-
val mutable res = (None : bool option)
60+
method! vexpr e = match (Cil.stripCasts e).enode with
61+
| AddrOf (Var v, _) -> begin match !cache with
62+
| None -> failwith "Internal error"
63+
| Some c ->
64+
Logger.debug ~level:5 "Adding escaping variable: %a" Varinfo.pretty v;
65+
cache := Some (Varinfo.Set.add v c); DoChildren
6366

64-
method! vexpr e = match e.enode with
65-
| Lval (Var var', NoOffset) ->
66-
if Varinfo.equal var var' then ChangeTo {e with enode = Const const}
67-
else DoChildren
67+
end
6868
| _ -> DoChildren
6969

70-
let is_referenced =
71-
let cache := ref M.empty in
72-
fun base ->
73-
try M.find base !cache
74-
with Not_found ->
70+
end
7571

76-
77-
class substitution = object
72+
class is_referenced_visitor = object
7873
inherit Visitor.frama_c_inplace
79-
*)
80-
(** Very simple approximation of escape analysis:
81-
- All referenced variables can escape
82-
- All dynamically allocated bases can escape *)
74+
75+
method! vstmt stmt =
76+
let exprs = match stmt.skind with
77+
| Instr (Set (lval, expr, _)) -> [expr]
78+
| Instr (Call (_, {enode = Lval (Var fn, NoOffset); _}, exprs, _)) ->
79+
if ConcurrencyModel.is_atomic_fn fn then []
80+
else exprs
81+
| Instr (Call (_, _, exprs, _)) -> exprs
82+
| Instr (Local_init (_, ConsInit (fn, exprs, _), _)) ->
83+
if ConcurrencyModel.is_atomic_fn fn then []
84+
else exprs
85+
| _ -> []
86+
in
87+
let check_expr = (fun e -> ignore @@ (new escapes_expr)#vexpr e) in
88+
List.iter check_expr exprs;
89+
DoChildren
90+
91+
end
92+
93+
let is_referenced var =
94+
match !cache with
95+
| None ->
96+
let _ = cache := Some Varinfo.Set.empty in
97+
let file = Ast.get () in
98+
let _ = Visitor.visitFramacFileSameGlobals (new is_referenced_visitor) file in
99+
Varinfo.Set.mem var (Option.get !cache)
100+
| Some _ -> Varinfo.Set.mem var (Option.get !cache)
101+
102+
(** Simple escape analysis *)
83103
let may_escape = function
84-
| Var (var, _) -> var.vaddrof
104+
| Var (var, _) -> is_referenced var
85105
| Allocated (var, _, _) -> true
86106
(*
87107
begin match Cil_utils.find_allocation_target var with

0 commit comments

Comments
 (0)