11(* * Does all sorts of optimizations. *)
22
33open Riscv_ssa
4+ module Vec = Basic_vec
45
56(* * Instruction in SSA form; feel free to change it to anything you'd like *)
67type instruction = Riscv_ssa .t
78
89(* * Note: `body` does not include the label before instructions. *)
910type basic_block = {
10- mutable body : instruction Basic_vec .t ;
11- succ : string Basic_vec .t ;
12- pred : string Basic_vec .t ;
11+ mutable body : instruction Vec .t ;
12+ succ : string Vec .t ;
13+ mutable pred : string Vec .t ;
1314}
1415
1516let make () =
1617 {
17- body = Basic_vec . empty () ;
18- succ = Basic_vec . empty () ;
19- pred = Basic_vec . empty () ;
18+ body = Vec . empty () ;
19+ succ = Vec . empty () ;
20+ pred = Vec . empty () ;
2021 }
2122
2223
@@ -33,7 +34,7 @@ let (params: (string, var list) Hashtbl.t) = Hashtbl.create 256
3334let block_of name = Hashtbl. find basic_blocks name
3435
3536(* * Get the body of a basic block. *)
36- let body_of name = (block_of name).body |> Basic_vec . to_list
37+ let body_of name = (block_of name).body |> Vec . to_list
3738
3839(* *
3940Builds control flow graph.
@@ -47,48 +48,50 @@ let build_cfg fn body =
4748 (* The first basic block in each function is unnamed, *)
4849 (* so we take the function name as its name. *)
4950 let name = ref fn in
50- let vec = ref (Basic_vec . empty () ) in
51+ let vec = ref (Vec . empty () ) in
5152
5253 (* There might be multiple jumps at end of each basic block. *)
5354 (* Clean them up. *)
54- let tidy (vec : instruction Basic_vec.t ) =
55- let rec iter () =
56- let len = Basic_vec. length vec in
57- if len < = 1 then ()
58-
59- (* Check penultimate instruction, and pop the last according to it *)
60- else let x = Basic_vec. get vec (len - 2 ) in
55+ let tidy (vec : instruction Vec.t ) =
56+ let tidied = Vec. empty () in
57+ let len = Vec. length vec in
58+ let rec iter i =
59+ Vec. push tidied (Vec. get vec i);
60+
61+ if i = len - 1 then ()
62+
63+ else let x = Vec. get vec i in
6164 match x with
62- | Jump _ -> Basic_vec. pop vec |> ignore; iter ()
63- | Branch _ -> Basic_vec. pop vec |> ignore; iter ()
64- | Return _ -> Basic_vec. pop vec |> ignore; iter ()
65- | JumpIndirect _ -> Basic_vec. pop vec |> ignore; iter ()
66- | _ -> ( )
65+ | Jump _
66+ | Branch _
67+ | Return _
68+ | JumpIndirect _ -> ()
69+ | _ -> iter (i + 1 )
6770 in
68- iter () ;
69- vec
71+ iter 0 ;
72+ tidied
7073 in
7174
7275 let separate_basic_block (inst : instruction ) =
7376 (match inst with
7477 | Label label ->
7578 Hashtbl. add basic_blocks ! name (make () );
76- Basic_vec . append (block_of ! name).body (tidy ! vec);
79+ Vec . append (block_of ! name).body (tidy ! vec);
7780
78- (* Clear the instructions; Basic_vec does not offer clear() or something alike *)
79- vec := Basic_vec . empty () ;
81+ (* Clear the instructions; Vec does not offer clear() or something alike *)
82+ vec := Vec . empty () ;
8083 name := label
8184
82- | x -> Basic_vec . push ! vec x)
85+ | x -> Vec . push ! vec x)
8386 in
8487 List. iter separate_basic_block body;
8588
8689 (* The last basic block is missed by `separate_basic_block` *)
8790 (* Manually add it *)
8891 Hashtbl. add basic_blocks ! name (make () );
89- Basic_vec . append (block_of ! name).body (! vec);
92+ Vec . append (block_of ! name).body (! vec);
9093
91- Hashtbl. add exit_fn fn (Basic_vec . empty () );
94+ Hashtbl. add exit_fn fn (Vec . empty () );
9295
9396 (* Find successors of each block. *)
9497
@@ -98,23 +101,29 @@ let build_cfg fn body =
98101 (* So we just look at them. *)
99102 let rec find_succ name =
100103 let block = block_of name in
101- if Basic_vec . is_empty block.succ then
104+ if Vec . is_empty block.succ then
102105 let successors =
103- (match Basic_vec . last block.body with
106+ (match Vec . last block.body with
104107 | Jump target -> [target]
105108 | Branch { ifso; ifnot } -> [ifso; ifnot]
106- | Return _ -> Basic_vec . push (Hashtbl. find exit_fn fn) name; []
109+ | Return _ -> Vec . push (Hashtbl. find exit_fn fn) name; []
107110 | JumpIndirect { possibilities; _ } -> possibilities
108111 | _ -> failwith " riscv_opt.ml: malformed SSA" )
109112 in
110- Basic_vec . append block.succ (Basic_vec . of_list successors);
113+ Vec . append block.succ (Vec . of_list successors);
111114 List. iter find_succ successors
112115 in
113116 find_succ fn;
114117
115118 (* Find predecessors *)
116119 Hashtbl. iter (fun name block ->
117- Basic_vec. iter (fun succ -> Basic_vec. push (block_of succ).pred name) block.succ
120+ Vec. iter (fun succ -> Vec. push (block_of succ).pred name) block.succ
121+ ) basic_blocks;
122+
123+ (* Deduplicate *)
124+ Hashtbl. iter (fun name block ->
125+ block.pred < -
126+ block.pred |> Vec. to_list |> Stringset. of_list |> Stringset. to_seq |> List. of_seq |> Vec. of_list
118127 ) basic_blocks
119128
120129
@@ -147,16 +156,16 @@ let map_fn f ssa =
147156
148157(* * Find all basic blocks in function `fn`, in depth-first order. *)
149158let get_blocks fn =
150- let blocks = Basic_vec . empty () in
159+ let blocks = Vec . empty () in
151160 let visited = ref Stringset. empty in
152161 let rec aux x =
153162 if not (Stringset. mem x ! visited) then
154- (Basic_vec . push blocks x;
163+ (Vec . push blocks x;
155164 visited := Stringset. add x ! visited;
156- Basic_vec . iter aux (block_of x).succ)
165+ Vec . iter aux (block_of x).succ)
157166 in
158167 aux fn;
159- blocks |> Basic_vec . to_list
168+ blocks |> Vec . to_list
160169
161170(* *
162171Liveness analysis.
@@ -204,7 +213,7 @@ let liveness_analysis fn =
204213 let phidef = ref Stringset. empty in
205214 let phiuse = ref Stringset. empty in
206215
207- Basic_vec . iter (fun inst ->
216+ Vec . iter (fun inst ->
208217 match inst with
209218 | Phi { rd; rs } ->
210219 phidef += rd.name;
@@ -225,7 +234,7 @@ let liveness_analysis fn =
225234
226235 (* Keep doing until fixed point is reached *)
227236 let rec iterate worklist =
228- let last_item = Basic_vec . pop_opt worklist in
237+ let last_item = Vec . pop_opt worklist in
229238 match last_item with
230239 | None -> ()
231240 | Some fn ->
@@ -238,7 +247,7 @@ let liveness_analysis fn =
238247 let new_live_out =
239248 Stringset. union (List. fold_left (fun x s ->
240249 Stringset. union x (Stringset. diff (Hashtbl. find live_in s) (Hashtbl. find phidefs s))
241- ) Stringset. empty (Basic_vec . to_list block.succ)) (Hashtbl. find phiuses name)
250+ ) Stringset. empty (Vec . to_list block.succ)) (Hashtbl. find phiuses name)
242251 in
243252
244253 Hashtbl. replace live_out name new_live_out;
@@ -253,21 +262,21 @@ let liveness_analysis fn =
253262 (* Push all of them into worklist *)
254263 if not (Stringset. equal old_live_in new_live_in) then
255264 (Hashtbl. replace live_in name new_live_in;
256- Basic_vec . append worklist block.pred)
265+ Vec . append worklist block.pred)
257266 ) blocks;
258267 iterate worklist
259268 in
260269 (* Must clone a vector, otherwise `exit_fn` will become empty *)
261- iterate (Hashtbl. find exit_fn fn |> Basic_vec . to_list |> Basic_vec . of_list);
270+ iterate (Hashtbl. find exit_fn fn |> Vec . to_list |> Vec . of_list);
262271
263272 live_out
264273
265274(* * Converts the optimized control flow graph back into SSA. *)
266275let ssa_of_cfg fn =
267- let inst = Basic_vec . empty () in
276+ let inst = Vec . empty () in
268277 let blocks = get_blocks fn in
269278 List. iter (fun x ->
270- Basic_vec . push inst (Riscv_ssa. Label x);
271- Basic_vec . append inst (block_of x).body
279+ Vec . push inst (Riscv_ssa. Label x);
280+ Vec . append inst (block_of x).body
272281 ) blocks;
273- inst |> Basic_vec . to_list
282+ inst |> Vec . to_list
0 commit comments