-
Notifications
You must be signed in to change notification settings - Fork 0
/
toARMC.ml
333 lines (297 loc) · 10.9 KB
/
toARMC.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
(* translation to ARMC *)
module C = FixConstraint
module StrMap = Map.Make (struct type t = string let compare = compare end)
module StrSet = Set.Make (struct type t = string let compare = compare end)
open Misc.Ops
(* Andrey: TODO get rid of grd in t? grd p is a binding v:{v:b|p} *)
(* Andrey: TODO move to fixConstraint.ml? *)
(* Andrey: TODO move to ast.ml? *)
let pred_is_atomic (p, _) =
match p with
| Ast.True | Ast.False | Ast.Bexp _ | Ast.Atom _ -> true
| Ast.And _ | Ast.Or _ | Ast.Not _ | Ast.Imp _ | Ast.Forall _ -> false
(*
let negate_brel = function
| Ast.Eq -> Ast.Ne
| Ast.Ne -> Ast.Eq
| Ast.Gt -> Ast.Le
| Ast.Ge -> Ast.Lt
| Ast.Lt -> Ast.Ge
| Ast.Le -> Ast.Gt
let deep_negate_pred (p, t) =
match p with
| Ast.True -> Ast.pFalse
| Ast.False -> Ast.pTrue
| Ast.Atom (e1, r, e2) -> Ast.pAtom (e1, negate_brel r, e2)
| _ -> Ast.pNot (p, t)
*)
let start_pc = "start"
let loop_pc = "loop"
let error_pc = "error"
let val_vname = "VVVV"
let card_vname = "CARD"
let exists_kv = "EX"
let primed_suffix = "p"
let str__cil_tmp = "__cil_tmp"
type kv_scope = {
kvs : string list;
kv_scope : string list StrMap.t
}
let sanitize_symbol s =
Str.global_replace (Str.regexp "@") "_at_" s |> Str.global_replace (Str.regexp "#") "_hash_"
let symbol_to_armc s = Ast.Symbol.to_string s |> sanitize_symbol
let mk_data_var ?(suffix = "") kv v =
Printf.sprintf "_%s_%s%s%s"
(sanitize_symbol kv) (sanitize_symbol v) (if suffix = "" then "" else "_") suffix
let constant_to_armc = Ast.Constant.to_string
let bop_to_armc = function
| Ast.Plus -> "+"
| Ast.Minus -> "-"
| Ast.Times -> "*"
| Ast.Div -> "/"
let brel_to_armc = function
| Ast.Eq -> "="
| Ast.Ne -> "=\\="
| Ast.Gt -> ">" (* ">= 1+" *)
| Ast.Ge -> ">="
| Ast.Lt -> "<" (* "+1 =<" *)
| Ast.Le -> "=<"
let bind_to_armc (s, t) = (* Andrey: TODO support binders *)
Printf.sprintf "%s:%s" (symbol_to_armc s) (Ast.Sort.to_string t |> sanitize_symbol)
let rec expr_to_armc (e, _) =
match e with
| Ast.Con c -> constant_to_armc c
| Ast.Var s -> mk_data_var exists_kv (symbol_to_armc s)
| Ast.App (s, es) ->
let str = symbol_to_armc s in
if es = [] then str else
Printf.sprintf "f_%s(%s)" str (List.map expr_to_armc es |> String.concat ", ")
| Ast.Bin (e1, op, e2) ->
Printf.sprintf "(%s %s %s)"
(expr_to_armc e1) (bop_to_armc op) (expr_to_armc e2)
| Ast.Ite (ip, te, ee) ->
Printf.sprintf "ite(%s, %s, %s)"
(pred_to_armc ip) (expr_to_armc te) (expr_to_armc ee)
| Ast.Fld (s, e) ->
Printf.sprintf "fld(%s, %s)" (expr_to_armc e) (symbol_to_armc s)
and pred_to_armc (p, _) =
match p with
| Ast.True -> "1=1"
| Ast.False -> "0=1"
| Ast.Bexp e -> expr_to_armc e
| Ast.Not p -> Printf.sprintf "neg(%s)" (pred_to_armc p)
| Ast.Imp (p1, p2) -> Printf.sprintf "(neg(%s); %s)" (pred_to_armc p1) (pred_to_armc p2)
| Ast.And [] -> "1=1"
| Ast.And [p] -> pred_to_armc p
| Ast.And (_::_ as ps) -> Printf.sprintf "(%s)" (List.map pred_to_armc ps |> String.concat ", ")
| Ast.Or [] -> "0=1"
| Ast.Or [p] -> pred_to_armc p
| Ast.Or (_::_ as ps) -> Printf.sprintf "(%s)" (List.map pred_to_armc ps |> String.concat "; ")
| Ast.Atom (e1, r, e2) ->
Printf.sprintf "%s %s %s"
(expr_to_armc e1) (brel_to_armc r) (expr_to_armc e2)
| Ast.Forall (qs,p) -> (* Andrey: TODO support forall *)
Printf.sprintf "forall([%s], %s)"
(List.map bind_to_armc qs |> String.concat ", ")
(pred_to_armc p)
let mk_kv_scope out ts wfs =
output_string out "% kv -> scope:\n";
let kvs = List.map C.kvars_of_t ts |> List.flatten |> List.map snd
|> List.map symbol_to_armc |> Misc.sort_and_compact in
let kv_scope =
List.fold_left
(fun m wf ->
match C.reft_of_wf wf |> C.ras_of_reft with
| [C.Kvar([], kvar)] ->
let v = symbol_to_armc kvar in
let scope =
card_vname :: val_vname ::
(C.env_of_wf wf |> C.bindings_of_env |> List.map fst |> List.map symbol_to_armc
|> List.filter (fun s -> not (Misc.is_prefix str__cil_tmp s)) |> List.sort compare) in
Printf.fprintf out "%% %s -> %s\n"
v (String.concat ", " scope);
StrMap.add v scope m
| _ -> (* Andrey: TODO print ill-formed wf *)
failure "ERROR: kname_scope_map: ill-formed wf"
) StrMap.empty wfs in
{kvs = kvs; kv_scope = kv_scope}
let mk_data ?(suffix = "") ?(skip_kvs = []) s =
Printf.sprintf "[%s]"
(List.map
(fun kv ->
try
StrMap.find kv s.kv_scope |>
List.map (mk_data_var ~suffix:(if List.mem kv skip_kvs then "" else suffix) kv)
with Not_found -> failure "ERROR: rel_state_vs: scope not found for %s" kv
) s.kvs |> List.flatten |> String.concat ", ")
let mk_var2names state =
List.map
(fun kv ->
List.map
(fun v ->
Printf.sprintf "(%s, \'%s_%s\')"
(mk_data_var kv v) kv v
) (StrMap.find kv state.kv_scope) |> String.concat ", "
) state.kvs |> String.concat ", "
let mk_skip_update state kvs =
if kvs = [] then "1=1" else
List.map
(fun kv ->
List.map
(fun v ->
Printf.sprintf "%s = %s"
(mk_data_var ~suffix:primed_suffix kv v) (mk_data_var kv v)
) (StrMap.find kv state.kv_scope) |> String.concat ", "
) kvs |> String.concat ", "
let mk_update_str from_vs to_vs updates =
List.map2
(fun v vp ->
Printf.sprintf "%s = %s" vp (try StrMap.find v updates with Not_found -> v)
) from_vs to_vs |> String.concat ", "
let split_scope scope =
match scope with
| card :: value :: data -> card, value, data
| _ -> failure "ERROR: split_scope: empty scope %s" (String.concat ", " scope)
let reft_to_armc ?(suffix = "") state reft =
let vv = C.vv_of_reft reft |> symbol_to_armc in
let rs = C.ras_of_reft reft in
if rs = [] then "1=1" else
List.map
(function
| C.Conc pred -> pred_to_armc pred
| C.Kvar (subs, sym) ->
let subs_map = List.fold_left
(fun m (s, e) -> StrMap.add (symbol_to_armc s) e m) StrMap.empty subs in
let find_subst v default =
try StrMap.find v subs_map |> expr_to_armc with Not_found -> default in
let kv = symbol_to_armc sym in
let card, value, data = StrMap.find kv state.kv_scope |> split_scope in
Printf.sprintf "%s = 1" (mk_data_var ~suffix:suffix kv card)
:: Printf.sprintf "%s = %s"
(mk_data_var ~suffix:suffix kv value)
(find_subst vv (mk_data_var exists_kv vv))
:: List.map
(fun v ->
Printf.sprintf "%s = %s"
(mk_data_var ~suffix:suffix kv v)
(find_subst v (mk_data_var exists_kv v))
) data |> String.concat ", "
) rs |> String.concat ", "
let mk_rule from_pc from_data to_pc to_data annot_guards annot_updates id =
(*
let unless_error l = if to_pc = error_pc then to_pc else l in
let from_pc, to_pc =
if id = "t_init" then
from_pc, unless_error "l0"
else if List.mem id ["11"; "12"; "13"; "14"; "15"; "16"; "17"; "18"; "19"] then
"l0", unless_error "l1"
else if List.mem id ["1"; "2"; "3"; "4"; "5"; "6"; "7"; "8"; "9"; "10"; "20"; "21"; "22"; "23"; "24"; "25"; "26"; "27"; "28"] then
"l1", unless_error "l1"
else if List.mem id ["29"; "30"; "31"; "32"; "33"; "34"; "35"; "36"; "37"; "38"; "39"; "40"; "41"; "42"; "43"; "44"; "45"] then
"l1", unless_error "l2"
else
"l2", unless_error "l2"
in
*)
let rec annot_conj_to_armc = function
| (g, a) :: rest ->
if rest = [] then Printf.sprintf "\n %s \t%% %s\n ]," g a
else Printf.sprintf "\n %s, \t%% %s%s" g a (annot_conj_to_armc rest)
| [] -> "],"
in
Printf.sprintf
"
r(p(pc(%s), data(%s)),
p(pc(%s), data(%s)),
[%s
[%s
%s).
"
from_pc from_data to_pc to_data
(annot_conj_to_armc annot_guards)
(annot_conj_to_armc annot_updates)
id
let t_to_armc from_data to_data state t =
let grd = C.grd_of_t t in
let lhs = C.lhs_of_t t in
let rhs = C.rhs_of_t t in
let rhs_s = C.reft_to_string rhs in
let tag = try string_of_int (C.id_of_t t) with _ ->
failure "ERROR: t_to_armc: anonymous constraint %s" (C.to_string t) in
let annot_guards =
List.map
(fun (bv, reft) ->
reft_to_armc state (C.theta [(C.vv_of_reft reft, Ast.eVar bv)] reft),
C.binding_to_string (bv, reft)
) (C.env_of_t t |> C.bindings_of_env)
++ [(pred_to_armc grd, Ast.Predicate.to_string grd);
(reft_to_armc state lhs, "|- " ^ (C.reft_to_string lhs))] in
let ps, kvs =
List.fold_left (fun (ps', kvs') refa ->
match refa with
| C.Conc p -> p::ps', kvs'
| C.Kvar (subs, sym) -> ps', (subs, sym)::kvs'
) ([], []) (C.ras_of_reft rhs) in
(if ps <> [] then
[mk_rule loop_pc from_data error_pc to_data annot_guards
[(Ast.pAnd ps |> Ast.pNot |> pred_to_armc, "<: " ^ rhs_s)]
tag]
else
[])
++
(List.map
(fun (_, sym) ->
let kv = symbol_to_armc sym in
let skip_kvs = List.filter (fun kv' -> kv <> kv') state.kvs in
mk_rule loop_pc from_data loop_pc
(mk_data ~suffix:primed_suffix ~skip_kvs:skip_kvs state)
annot_guards
[(reft_to_armc ~suffix:primed_suffix state rhs, "<: " ^ rhs_s)]
tag
) kvs)
let to_armc out ts wfs =
print_endline "Translating to ARMC.";
let state = mk_kv_scope out ts wfs in
let from_data = mk_data state in
let to_data = mk_data ~suffix:primed_suffix state in
Printf.fprintf out
":- multifile r/5,implicit_updates/0,var2names/2,preds/2,trans_preds/3,cube_size/1,start/1,error/1,refinement/1,cutpoint/1,invgen_template/2,invgen_template/1,cfg_exit_relation/1,stmtsrc/2,strengthening/2.
refinement(inter).
cube_size(1).
start(pc(%s)).
error(pc(%s)).
cutpoint(pc(%s)).
preds(p(_, data(%s)), [%s]).
trans_preds(p(_, data(%s)), p(_, data(%s)), []).
var2names(p(_, data(%s)), [%s]).
"
start_pc error_pc loop_pc
from_data (List.map (fun kv ->
let card, _, _ = StrMap.find kv state.kv_scope |> split_scope in
let kv_card = mk_data_var kv card in
Printf.sprintf "%s = 0, %s = 1" kv_card kv_card
) state.kvs |> String.concat ", ") (* preds *)
from_data to_data (* trans_preds *)
from_data (mk_var2names state); (* var2names *)
output_string out
(mk_rule start_pc from_data loop_pc to_data []
[(List.map
(fun kv ->
let card, _, _ = StrMap.find kv state.kv_scope |> split_scope in
Printf.sprintf "%s = 0" (mk_data_var ~suffix:primed_suffix kv card)
) state.kvs |> String.concat ", ",
"")]
"t_init");
List.iter (fun t -> t_to_armc from_data to_data state t |> List.iter (output_string out)) ts
(*
make -f Makefile.fixtop && ./f -latex /tmp/main.tex -armc /tmp/a.pl tests/pldi08-max.fq && cat /tmp/a.pl
tests:
for file in `ls pldi08-*-atom.fq`; do ../f -latex /tmp/main.tex -armc /tmp/a.pl $file; head -n 1 /tmp/a.pl; armc a.pl | grep correct; done
pldi08-arraymax-atom.fq pass
pldi08-max-atom.fq pass
pldi08-foldn-atom.fq pass
pldi08-sum-atom.fq pass
mask-atom.fq pass
samples-atom.fq pass
test00.c pass
*)