MLIR DAG rewriter w/ SSA IR, dominance and CFG analysis passes
1open Ir
2
3let read_lines path =
4 let ic = open_in path in
5 let lines = ref [] in
6 (try
7 while true do lines := input_line ic :: !lines done
8 with End_of_file -> close_in ic);
9 List.rev !lines
10
11let parse_func (lines : string list) : func =
12 let blocks = ref [] in
13 let current_id = ref 0 in
14 let current_insts = ref [] in
15 let finish_block () =
16 if !current_id <> 0 then
17 blocks := mk_block !current_id (List.rev !current_insts) :: !blocks;
18 current_id := 0;
19 current_insts := []
20 in
21 let parse_instr s =
22 (* Tokenize: split on whitespace and standalone commas, but keep a
23 parenthesized group (e.g. "(10,2)") as a single token. This lets
24 "load 200, 100" and "phi 7 (10,2) (20,3)" both parse cleanly. *)
25 let tokens = ref [] in
26 let buf = Buffer.create 16 in
27 let depth = ref 0 in
28 let flush () =
29 if Buffer.length buf > 0 then begin
30 tokens := String.trim (Buffer.contents buf) :: !tokens;
31 Buffer.clear buf
32 end
33 in
34 String.iter (fun c ->
35 match c with
36 | '(' -> incr depth; Buffer.add_char buf c
37 | ')' -> decr depth; Buffer.add_char buf c
38 | (' ' | '\t' | '\n' | ',') when !depth = 0 ->
39 flush ()
40 | _ -> Buffer.add_char buf c
41 ) s;
42 flush ();
43 let parts = List.rev !tokens in
44 match parts with
45 | "alloca" :: id :: [] -> Alloca (int_of_string id)
46 | "load" :: r :: p :: [] -> Load (int_of_string r, int_of_string p)
47 | "store" :: v :: p :: [] -> Store (int_of_string v, int_of_string p)
48 | "move" :: r :: v :: [] -> Move (int_of_string r, int_of_string v)
49 | "binop" :: r :: v1 :: v2 :: [] -> BinOp (int_of_string r, int_of_string v1, int_of_string v2)
50 | "phi" :: r :: ops ->
51 (* Each op is a parenthesized "(v,b)"; strip parens and split on ','. *)
52 let parse_op op =
53 (* Drop the surrounding parentheses, then split on ','. *)
54 let inner = String.sub op 1 (String.length op - 2) in
55 match String.split_on_char ',' inner with
56 | [v; b] -> (int_of_string (String.trim v), int_of_string (String.trim b))
57 | _ -> failwith ("Bad phi operand: " ^ op)
58 in
59 Phi (int_of_string r, List.map parse_op ops)
60 | "ret" :: [] -> Ret None
61 | "ret" :: v :: [] -> Ret (Some (int_of_string v))
62 | "br" :: t :: [] -> Br (int_of_string t)
63 | "condbr" :: c :: t1 :: t2 :: [] -> CondBr (int_of_string c, int_of_string t1, int_of_string t2)
64 | _ -> failwith ("Unknown instr: " ^ s)
65 in
66 List.iter (fun line ->
67 let trimmed = String.trim line in
68 if trimmed = "" then ()
69 else if String.ends_with ~suffix:":" trimmed then
70 let label = String.sub trimmed 0 (String.length trimmed - 1) in
71 (* Accept either "1" or "block 1" style headers. *)
72 let id_str =
73 if String.starts_with ~prefix:"block " label
74 then String.sub label 6 (String.length label - 6)
75 else label
76 in
77 finish_block ();
78 current_id := int_of_string id_str
79 else
80 current_insts := parse_instr trimmed :: !current_insts
81 ) lines;
82 finish_block ();
83 let blocks = List.rev !blocks in
84 let entry = match blocks with
85 | [] -> 0
86 | b :: _ -> b.id
87 in
88 { blocks; entry }
89
90let parse_func_from_file path : func =
91 parse_func (read_lines path)