cgen.ml 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. open Match
  2. type options =
  3. { pfx: string
  4. ; static: bool
  5. ; oc: out_channel }
  6. type side = L | R
  7. type id_pred =
  8. | InBitSet of Int64.t
  9. | Ge of int
  10. | Eq of int
  11. and id_test =
  12. | Pred of (side * id_pred)
  13. | And of id_test * id_test
  14. type case_code =
  15. | Table of ((int * int) * int) list
  16. | IfThen of
  17. { test: id_test
  18. ; cif: case_code
  19. ; cthen: case_code option }
  20. | Return of int
  21. type case =
  22. { swap: bool
  23. ; code: case_code }
  24. let cgen_case tmp nstates map =
  25. let cgen_test ids =
  26. match ids with
  27. | [id] -> Eq id
  28. | _ ->
  29. let min_id =
  30. List.fold_left min max_int ids in
  31. if List.length ids = nstates - min_id
  32. then Ge min_id
  33. else begin
  34. assert (nstates <= 64);
  35. InBitSet
  36. (List.fold_left (fun bs id ->
  37. Int64.logor bs
  38. (Int64.shift_left 1L id))
  39. 0L ids)
  40. end
  41. in
  42. let symmetric =
  43. let inverse ((l, r), x) = ((r, l), x) in
  44. setify map = setify (List.map inverse map) in
  45. let map =
  46. let ordered ((l, r), _) = r <= l in
  47. if symmetric then
  48. List.filter ordered map
  49. else map
  50. in
  51. let exception BailToTable in
  52. try
  53. let st =
  54. match setify (List.map snd map) with
  55. | [st] -> st
  56. | _ -> raise BailToTable
  57. in
  58. (* the operation considered can only
  59. * generate a single state *)
  60. let pairs = List.map fst map in
  61. let ls, rs = List.split pairs in
  62. let ls = setify ls and rs = setify rs in
  63. if List.length ls > 1 && List.length rs > 1 then
  64. raise BailToTable;
  65. { swap = symmetric
  66. ; code =
  67. let pl = Pred (L, cgen_test ls)
  68. and pr = Pred (R, cgen_test rs) in
  69. IfThen
  70. { test = And (pl, pr)
  71. ; cif = Return st
  72. ; cthen = Some (Return tmp) } }
  73. with BailToTable ->
  74. { swap = symmetric
  75. ; code = Table map }
  76. let show_op (_cls, op) =
  77. "O" ^ show_op_base op
  78. let indent oc i =
  79. Printf.fprintf oc "%s" (String.sub "\t\t\t\t\t" 0 i)
  80. let emit_swap oc i =
  81. let pf m = Printf.fprintf oc m in
  82. let pfi n m = indent oc n; pf m in
  83. pfi i "if (l < r)\n";
  84. pfi (i+1) "t = l, l = r, r = t;\n"
  85. let gen_tables oc tmp pfx nstates (op, c) =
  86. let i = 1 in
  87. let pf m = Printf.fprintf oc m in
  88. let pfi n m = indent oc n; pf m in
  89. let ntables = ref 0 in
  90. (* we must follow the order in which
  91. * we visit code in emit_case, or
  92. * else ntables goes out of sync *)
  93. let base = pfx ^ show_op op in
  94. let swap = c.swap in
  95. let rec gen c =
  96. match c with
  97. | Table map ->
  98. let name =
  99. if !ntables = 0 then base else
  100. base ^ string_of_int !ntables
  101. in
  102. assert (nstates <= 256);
  103. if swap then
  104. let n = nstates * (nstates + 1) / 2 in
  105. pfi i "static uchar %stbl[%d] = {\n" name n
  106. else
  107. pfi i "static uchar %stbl[%d][%d] = {\n"
  108. name nstates nstates;
  109. for l = 0 to nstates - 1 do
  110. pfi (i+1) "";
  111. for r = 0 to nstates - 1 do
  112. if not swap || r <= l then
  113. begin
  114. pf "%d"
  115. (try List.assoc (l,r) map
  116. with Not_found -> tmp);
  117. pf ",";
  118. end
  119. done;
  120. pf "\n";
  121. done;
  122. pfi i "};\n"
  123. | IfThen {cif; cthen} ->
  124. gen cif;
  125. Option.iter gen cthen
  126. | Return _ -> ()
  127. in
  128. gen c.code
  129. let emit_case oc pfx no_swap (op, c) =
  130. let fpf = Printf.fprintf in
  131. let pf m = fpf oc m in
  132. let pfi n m = indent oc n; pf m in
  133. let rec side oc = function
  134. | L -> fpf oc "l"
  135. | R -> fpf oc "r"
  136. in
  137. let pred oc (s, pred) =
  138. match pred with
  139. | InBitSet bs -> fpf oc "BIT(%a) & %#Lx" side s bs
  140. | Eq id -> fpf oc "%a == %d" side s id
  141. | Ge id -> fpf oc "%d <= %a" id side s
  142. in
  143. let base = pfx ^ show_op op in
  144. let swap = c.swap in
  145. let ntables = ref 0 in
  146. let rec code i c =
  147. match c with
  148. | Return id -> pfi i "return %d;\n" id
  149. | Table map ->
  150. let name =
  151. if !ntables = 0 then base else
  152. base ^ string_of_int !ntables
  153. in
  154. incr ntables;
  155. if swap then
  156. pfi i "return %stbl[(l + l*l)/2 + r];\n" name
  157. else pfi i "return %stbl[l][r];\n" name
  158. | IfThen ({test = And (And (t1, t2), t3)} as r) ->
  159. code i @@ IfThen
  160. {r with test = And (t1, And (t2, t3))}
  161. | IfThen {test = And (Pred p, t); cif; cthen} ->
  162. pfi i "if (%a)\n" pred p;
  163. code i (IfThen {test = t; cif; cthen})
  164. | IfThen {test = Pred p; cif; cthen} ->
  165. pfi i "if (%a) {\n" pred p;
  166. code (i+1) cif;
  167. pfi i "}\n";
  168. Option.iter (code i) cthen
  169. in
  170. pfi 1 "case %s:\n" (show_op op);
  171. if not no_swap && c.swap then
  172. emit_swap oc 2;
  173. code 2 c.code
  174. let emit_list
  175. ?(limit=60) ?(cut_before_sep=false)
  176. ~col ~indent:i ~sep ~f oc l =
  177. let sl = String.length sep in
  178. let rstripped_sep, rssl =
  179. if sep.[sl - 1] = ' ' then
  180. String.sub sep 0 (sl - 1), sl - 1
  181. else sep, sl
  182. in
  183. let lstripped_sep, lssl =
  184. if sep.[0] = ' ' then
  185. String.sub sep 1 (sl - 1), sl - 1
  186. else sep, sl
  187. in
  188. let rec line col acc = function
  189. | [] -> (List.rev acc, [])
  190. | s :: l ->
  191. let col = col + sl + String.length s in
  192. let no_space =
  193. if cut_before_sep || l = [] then
  194. col > limit
  195. else
  196. col + rssl > limit
  197. in
  198. if no_space then
  199. (List.rev acc, s :: l)
  200. else
  201. line col (s :: acc) l
  202. in
  203. let rec go col l =
  204. if l = [] then () else
  205. let ll, l = line col [] l in
  206. Printf.fprintf oc "%s" (String.concat sep ll);
  207. if l <> [] && cut_before_sep then begin
  208. Printf.fprintf oc "\n";
  209. indent oc i;
  210. Printf.fprintf oc "%s" lstripped_sep;
  211. go (8*i + lssl) l
  212. end else if l <> [] then begin
  213. Printf.fprintf oc "%s\n" rstripped_sep;
  214. indent oc i;
  215. go (8*i) l
  216. end else ()
  217. in
  218. go col (List.map f l)
  219. let emit_numberer opts n =
  220. let pf m = Printf.fprintf opts.oc m in
  221. let tmp = (atom_state n Tmp).id in
  222. let con = (atom_state n AnyCon).id in
  223. let nst = Array.length n.states in
  224. let cases =
  225. StateMap.by_ops n.statemap |>
  226. List.map (fun (op, map) ->
  227. (op, cgen_case tmp nst map))
  228. in
  229. let all_swap =
  230. List.for_all (fun (_, c) -> c.swap) cases in
  231. (* opn() *)
  232. if opts.static then pf "static ";
  233. pf "int\n";
  234. pf "%sopn(int op, int l, int r)\n" opts.pfx;
  235. pf "{\n";
  236. cases |> List.iter
  237. (gen_tables opts.oc tmp opts.pfx nst);
  238. if List.exists (fun (_, c) -> c.swap) cases then
  239. pf "\tint t;\n\n";
  240. if all_swap then emit_swap opts.oc 1;
  241. pf "\tswitch (op) {\n";
  242. cases |> List.iter
  243. (emit_case opts.oc opts.pfx all_swap);
  244. pf "\tdefault:\n";
  245. pf "\t\treturn %d;\n" tmp;
  246. pf "\t}\n";
  247. pf "}\n\n";
  248. (* refn() *)
  249. if opts.static then pf "static ";
  250. pf "int\n";
  251. pf "%srefn(Ref r, Num *tn, Con *con)\n" opts.pfx;
  252. pf "{\n";
  253. let cons =
  254. List.filter_map (function
  255. | (Con c, s) -> Some (c, s.id)
  256. | _ -> None)
  257. n.atoms
  258. in
  259. if cons <> [] then
  260. pf "\tint64_t n;\n\n";
  261. pf "\tswitch (rtype(r)) {\n";
  262. pf "\tcase RTmp:\n";
  263. if tmp <> 0 then begin
  264. assert
  265. (List.exists (fun (_, s) ->
  266. s.id = 0
  267. ) n.atoms &&
  268. (* no temp should ever get state 0 *)
  269. List.for_all (fun (a, s) ->
  270. s.id <> 0 ||
  271. match a with
  272. | AnyCon | Con _ -> true
  273. | _ -> false
  274. ) n.atoms);
  275. pf "\t\tif (!tn[r.val].n)\n";
  276. pf "\t\t\ttn[r.val].n = %d;\n" tmp;
  277. end;
  278. pf "\t\treturn tn[r.val].n;\n";
  279. pf "\tcase RCon:\n";
  280. if cons <> [] then begin
  281. pf "\t\tif (con[r.val].type != CBits)\n";
  282. pf "\t\t\treturn %d;\n" con;
  283. pf "\t\tn = con[r.val].bits.i;\n";
  284. cons |> inverse |> group_by_fst
  285. |> List.iter (fun (id, cs) ->
  286. pf "\t\tif (";
  287. emit_list ~cut_before_sep:true
  288. ~col:20 ~indent:2 ~sep:" || "
  289. ~f:(fun c -> "n == " ^ Int64.to_string c)
  290. opts.oc cs;
  291. pf ")\n";
  292. pf "\t\t\treturn %d;\n" id
  293. );
  294. end;
  295. pf "\t\treturn %d;\n" con;
  296. pf "\tdefault:\n";
  297. pf "\t\treturn INT_MIN;\n";
  298. pf "\t}\n";
  299. pf "}\n\n";
  300. (* match[]: patterns per state *)
  301. if opts.static then pf "static ";
  302. pf "bits %smatch[%d] = {\n" opts.pfx nst;
  303. n.states |> Array.iteri (fun sn s ->
  304. let tops =
  305. List.filter_map (function
  306. | Top ("$" | "%") -> None
  307. | Top r -> Some ("BIT(P" ^ r ^ ")")
  308. | _ -> None) s.point |> setify
  309. in
  310. if tops <> [] then
  311. pf "\t[%d] = %s,\n"
  312. sn (String.concat " | " tops);
  313. );
  314. pf "};\n\n"
  315. let var_id vars f =
  316. List.mapi (fun i x -> (x, i)) vars |>
  317. List.assoc f
  318. let compile_action vars act =
  319. let pcs = Hashtbl.create 100 in
  320. let rec gen pc (act: Action.t) =
  321. try
  322. [10 + Hashtbl.find pcs act.id]
  323. with Not_found ->
  324. let code =
  325. match act.node with
  326. | Action.Stop ->
  327. [0]
  328. | Action.Push (sym, k) ->
  329. let c = if sym then 1 else 2 in
  330. [c] @ gen (pc + 1) k
  331. | Action.Set (v, {node = Action.Pop k; _})
  332. | Action.Set (v, ({node = Action.Stop; _} as k)) ->
  333. let v = var_id vars v in
  334. [3; v] @ gen (pc + 2) k
  335. | Action.Set _ ->
  336. (* for now, only atomic patterns can be
  337. * tied to a variable, so Set must be
  338. * followed by either Pop or Stop *)
  339. assert false
  340. | Action.Pop k ->
  341. [4] @ gen (pc + 1) k
  342. | Action.Switch cases ->
  343. let cases =
  344. inverse cases |> group_by_fst |>
  345. List.sort (fun (_, cs1) (_, cs2) ->
  346. let n1 = List.length cs1
  347. and n2 = List.length cs2 in
  348. compare n2 n1)
  349. in
  350. (* the last case is the one with
  351. * the max number of entries *)
  352. let cases = List.rev (List.tl cases)
  353. and last = fst (List.hd cases) in
  354. let ncases =
  355. List.fold_left (fun n (_, cs) ->
  356. List.length cs + n)
  357. 0 cases
  358. in
  359. let body_off = 2 + 2 * ncases + 1 in
  360. let pc, tbl, body =
  361. List.fold_left
  362. (fun (pc, tbl, body) (a, cs) ->
  363. let ofs = body_off + List.length body in
  364. let case = gen pc a in
  365. let pc = pc + List.length case in
  366. let body = body @ case in
  367. let tbl =
  368. List.fold_left (fun tbl c ->
  369. tbl @ [c; ofs]
  370. ) tbl cs
  371. in
  372. (pc, tbl, body))
  373. (pc + body_off, [], [])
  374. cases
  375. in
  376. let ofs = body_off + List.length body in
  377. let tbl = tbl @ [ofs] in
  378. assert (2 + List.length tbl = body_off);
  379. [5; ncases] @ tbl @ body @ gen pc last
  380. in
  381. if act.node <> Action.Stop then
  382. Hashtbl.replace pcs act.id pc;
  383. code
  384. in
  385. gen 0 act
  386. let emit_matchers opts ms =
  387. let pf m = Printf.fprintf opts.oc m in
  388. if opts.static then pf "static ";
  389. pf "uchar *%smatcher[] = {\n" opts.pfx;
  390. List.iter (fun (vars, pname, m) ->
  391. pf "\t[P%s] = (uchar[]){\n" pname;
  392. pf "\t\t";
  393. let bytes = compile_action vars m in
  394. emit_list
  395. ~col:16 ~indent:2 ~sep:","
  396. ~f:string_of_int opts.oc bytes;
  397. pf "\n";
  398. pf "\t},\n")
  399. ms;
  400. pf "};\n\n"
  401. let emit_c opts n =
  402. emit_numberer opts n