16 | Pred
of (side
* id_pred
)
17 | And
of id_test
* id_test
20 | Table
of ((int * int) * int) list
24 ; cthen
: case_code
option }
31 let cgen_case tmp nstates map
=
37 List.fold_left min max_int ids
in
38 if List.length ids
= nstates
- min_id
41 assert (nstates
<= 64);
43 (List.fold_left
(fun bs id
->
45 (Int64.shift_left
1L id
))
50 let inverse ((l
, r
), x
) = ((r
, l
), x
) in
51 setify map
= setify
(List.map
inverse map
) in
53 let ordered ((l
, r
), _
) = r
<= l
in
55 List.filter
ordered map
58 let exception BailToTable
in
61 match setify
(List.map snd
map) with
63 | _
-> raise BailToTable
65 (* the operation considered can only
66 * generate a single state *)
67 let pairs = List.map fst
map in
68 let ls, rs
= List.split
pairs in
69 let ls = setify
ls and rs
= setify rs
in
70 if List.length
ls > 1 && List.length rs
> 1 then
74 let pl = Pred
(L
, cgen_test ls)
75 and pr
= Pred
(R
, cgen_test rs
) in
79 ; cthen
= Some
(Return tmp
) } }
84 let show_op (_cls
, op
) =
88 Printf.fprintf oc
"%s" (String.sub
"\t\t\t\t\t" 0 i
)
91 let pf m
= Printf.fprintf oc m
in
92 let pfi n m
= indent oc n
; pf m
in
94 pfi (i
+1) "t = l, l = r, r = t;\n"
96 let gen_tables oc tmp pfx nstates
(op
, c
) =
98 let pf m
= Printf.fprintf oc m
in
99 let pfi n m
= indent oc n
; pf m
in
100 let ntables = ref 0 in
101 (* we must follow the order in which
102 * we visit code in emit_case, or
103 * else ntables goes out of sync *)
104 let base = pfx ^
show_op op
in
110 if !ntables = 0 then base else
111 base ^ string_of_int
!ntables
113 assert (nstates
<= 256);
115 let n = nstates
* (nstates
+ 1) / 2 in
116 pfi i "static uchar %stbl[%d] = {\n" name n
118 pfi i "static uchar %stbl[%d][%d] = {\n"
119 name nstates nstates
;
120 for l
= 0 to nstates
- 1 do
122 for r
= 0 to nstates
- 1 do
123 if not
swap || r
<= l
then
126 (try List.assoc
(l
,r
) map
127 with Not_found
-> tmp
);
134 | IfThen
{cif
; cthen
} ->
136 Option.iter
gen cthen
141 let emit_case oc pfx no_swap
(op
, c
) =
142 let fpf = Printf.fprintf
in
143 let pf m
= fpf oc m
in
144 let pfi n m
= indent oc
n; pf m
in
145 let rec side oc
= function
149 let pred oc
(s
, pred) =
151 | InBitSet bs
-> fpf oc
"BIT(%a) & %#Lx" side s bs
152 | Eq id
-> fpf oc
"%a == %d" side s id
153 | Ge id
-> fpf oc
"%d <= %a" id
side s
155 let base = pfx ^
show_op op
in
157 let ntables = ref 0 in
160 | Return id
-> pfi i "return %d;\n" id
163 if !ntables = 0 then base else
164 base ^ string_of_int
!ntables
168 pfi i "return %stbl[(l + l*l)/2 + r];\n" name
169 else pfi i "return %stbl[l][r];\n" name
170 | IfThen
({test
= And
(And
(t1
, t2
), t3
)} as r
) ->
172 {r
with test
= And
(t1
, And
(t2
, t3
))}
173 | IfThen
{test
= And
(Pred p
, t
); cif
; cthen
} ->
174 pfi i "if (%a)\n" pred p
;
175 code i (IfThen
{test
= t
; cif
; cthen
})
176 | IfThen
{test
= Pred p
; cif
; cthen
} ->
177 pfi i "if (%a) {\n" pred p
;
180 Option.iter
(code i) cthen
182 pfi 1 "case %s:\n" (show_op op
);
183 if not no_swap
&& c
.swap then
188 ?
(limit
=60) ?
(cut_before_sep
=false)
189 ~col ~
indent:i ~sep ~f oc l
=
190 let sl = String.length sep
in
191 let rstripped_sep, rssl
=
192 if sep
.[sl - 1] = ' '
then
193 String.sub sep
0 (sl - 1), sl - 1
196 let lstripped_sep, lssl
=
197 if sep
.[0] = ' '
then
198 String.sub sep
1 (sl - 1), sl - 1
201 let rec line col acc
= function
202 | [] -> (List.rev acc
, [])
204 let col = col + sl + String.length s
in
206 if cut_before_sep
|| l
= [] then
212 (List.rev acc
, s
:: l
)
214 line col (s
:: acc
) l
217 if l
= [] then () else
218 let ll, l
= line col [] l
in
219 Printf.fprintf oc
"%s" (String.concat sep
ll);
220 if l
<> [] && cut_before_sep
then begin
221 Printf.fprintf oc
"\n";
223 Printf.fprintf oc
"%s" lstripped_sep;
225 end else if l
<> [] then begin
226 Printf.fprintf oc
"%s\n" rstripped_sep;
231 go col (List.map f l
)
233 let emit_numberer opts
n =
234 let pf m
= Printf.fprintf opts
.oc m
in
235 let tmp = (atom_state
n Tmp
).id
in
236 let con = (atom_state
n AnyCon
).id
in
237 let nst = Array.length
n.states
in
239 StateMap.by_ops
n.statemap
|>
240 List.map (fun (op
, map) ->
241 (op
, cgen_case tmp nst map))
244 List.for_all
(fun (_
, c
) -> c
.swap) cases in
246 if opts
.static
then pf "static ";
248 pf "%sopn(int op, int l, int r)\n" opts
.pfx
;
251 (gen_tables opts
.oc
tmp opts
.pfx
nst);
252 if List.exists
(fun (_
, c
) -> c
.swap) cases then
254 if all_swap then emit_swap opts
.oc
1;
255 pf "\tswitch (op) {\n";
257 (emit_case opts
.oc opts
.pfx
all_swap);
259 pf "\t\treturn %d;\n" tmp;
263 if opts
.static
then pf "static ";
265 pf "%srefn(Ref r, Num *tn, Con *con)\n" opts
.pfx
;
268 List.filter_map
(function
269 | (Con c
, s
) -> Some
(c
, s
.id
)
274 pf "\tint64_t n;\n\n";
275 pf "\tswitch (rtype(r)) {\n";
277 if tmp <> 0 then begin
279 (List.exists
(fun (_
, s
) ->
282 (* no temp should ever get state 0 *)
283 List.for_all
(fun (a
, s
) ->
286 | AnyCon
| Con _
-> true
289 pf "\t\tif (!tn[r.val].n)\n";
290 pf "\t\t\ttn[r.val].n = %d;\n" tmp;
292 pf "\t\treturn tn[r.val].n;\n";
294 if cons <> [] then begin
295 pf "\t\tif (con[r.val].type != CBits)\n";
296 pf "\t\t\treturn %d;\n" con;
297 pf "\t\tn = con[r.val].bits.i;\n";
298 cons |> inverse |> group_by_fst
299 |> List.iter
(fun (id
, cs
) ->
301 emit_list ~cut_before_sep
:true
302 ~
col:20 ~
indent:2 ~sep
:" || "
303 ~f
:(fun c
-> "n == " ^
Int64.to_string c
)
306 pf "\t\t\treturn %d;\n" id
309 pf "\t\treturn %d;\n" con;
311 pf "\t\treturn INT_MIN;\n";
314 (* match[]: patterns per state *)
315 if opts
.static
then pf "static ";
316 pf "bits %smatch[%d] = {\n" opts
.pfx
nst;
317 n.states
|> Array.iteri
(fun sn s
->
319 List.filter_map
(function
320 | Top
("$" | "%") -> None
321 | Top r
-> Some
("BIT(P" ^ r ^
")")
322 | _
-> None
) s
.point
|> setify
326 sn
(String.concat
" | " tops);
331 List.mapi
(fun i x
-> (x
, i)) vars
|>
334 let compile_action vars act
=
335 let pcs = Hashtbl.create
100 in
336 let rec gen pc
(act
: Action.t
) =
338 [10 + Hashtbl.find
pcs act
.id
]
344 | Action.Push
(sym
, k
) ->
345 let c = if sym
then 1 else 2 in
347 | Action.Set
(v
, {node
= Action.Pop k
; _
})
348 | Action.Set
(v
, ({node
= Action.Stop
; _
} as k
)) ->
349 let v = var_id vars
v in
350 [3; v] @ gen (pc
+ 2) k
352 (* for now, only atomic patterns can be
353 * tied to a variable, so Set must be
354 * followed by either Pop or Stop *)
358 | Action.Switch
cases ->
360 inverse cases |> group_by_fst
|>
361 List.sort
(fun (_
, cs1
) (_
, cs2
) ->
362 let n1 = List.length cs1
363 and n2
= List.length cs2
in
366 (* the last case is the one with
367 * the max number of entries *)
368 let cases = List.rev
(List.tl
cases)
369 and last
= fst
(List.hd
cases) in
371 List.fold_left
(fun n (_
, cs
) ->
375 let body_off = 2 + 2 * ncases + 1 in
378 (fun (pc, tbl
, body
) (a
, cs
) ->
379 let ofs = body_off + List.length body
in
380 let case = gen pc a
in
381 let pc = pc + List.length
case in
382 let body = body @ case in
384 List.fold_left
(fun tbl c ->
389 (pc + body_off, [], [])
392 let ofs = body_off + List.length
body in
393 let tbl = tbl @ [ofs] in
394 assert (2 + List.length
tbl = body_off);
395 [5; ncases] @ tbl @ body @ gen pc last
397 if act
.node
<> Action.Stop
then
398 Hashtbl.replace
pcs act
.id
pc;
403 let emit_matchers opts ms
=
404 let pf m
= Printf.fprintf opts
.oc m
in
405 if opts
.static
then pf "static ";
406 pf "uchar *%smatcher[] = {\n" opts
.pfx
;
407 List.iter
(fun (vars
, pname
, m
) ->
408 pf "\t[P%s] = (uchar[]){\n" pname
;
410 let bytes = compile_action vars m
in
412 ~
col:16 ~
indent:2 ~sep
:","
413 ~f
:string_of_int opts
.oc
bytes;