1 (***********************************************************************)
5 (* Xavier Leroy, projet Cristal, INRIA Rocquencourt *)
7 (* Copyright 1996 Institut National de Recherche en Informatique et *)
8 (* en Automatique. All rights reserved. This file is distributed *)
9 (* under the terms of the Q Public License version 1.0. *)
11 (***********************************************************************)
13 (* $Id: split.ml 7812 2007-01-29 12:11:18Z xleroy $ *)
15 (* Renaming of registers at reload points to split live ranges. *)
20 (* Substitutions are represented by register maps *)
22 type subst = Reg.t Reg.Map.t
30 let subst_regs rv sub =
34 let n = Array.length rv in
35 let nv = Array.create n Reg.dummy in
36 for i = 0 to n-1 do nv.(i) <- subst_reg rv.(i) s done;
39 (* We maintain equivalence classes of registers using a standard
40 union-find algorithm *)
42 let equiv_classes = ref (Reg.Map.empty : Reg.t Reg.Map.t)
44 let rec repres_reg r =
46 repres_reg(Reg.Map.find r !equiv_classes)
51 let n = Array.length rv in
52 for i = 0 to n-1 do rv.(i) <- repres_reg rv.(i) done
54 (* Identify two registers.
55 The second register is chosen as canonical representative. *)
58 let repres1 = repres_reg r1 in
59 let repres2 = repres_reg r2 in
60 if repres1.stamp = repres2.stamp then () else begin
61 equiv_classes := Reg.Map.add repres1 repres2 !equiv_classes
64 (* Identify the image of a register by two substitutions.
65 Be careful to use the original register as canonical representative
66 in case it does not belong to the domain of one of the substitutions. *)
68 let identify_sub sub1 sub2 reg =
70 let r1 = Reg.Map.find reg sub1 in
72 let r2 = Reg.Map.find reg sub2 in
78 let r2 = Reg.Map.find reg sub2 in
83 (* Identify registers so that the two substitutions agree on the
84 registers live before the given instruction. *)
86 let merge_substs sub1 sub2 i =
87 match (sub1, sub2) with
89 | (Some s1, None) -> sub1
90 | (None, Some s2) -> sub2
91 | (Some s1, Some s2) ->
92 Reg.Set.iter (identify_sub s1 s2) (Reg.add_set_array i.live i.arg);
95 (* Same, for N substitutions *)
97 let merge_subst_array subv instr =
98 let rec find_one_subst i =
99 if i >= Array.length subv then None else begin
101 None -> find_one_subst (i+1)
103 for j = i+1 to Array.length subv - 1 do
107 Reg.Set.iter (identify_sub si sj)
108 (Reg.add_set_array instr.live instr.arg)
114 (* First pass: rename registers at reload points *)
116 let exit_subst = ref []
118 let find_exit_subst k =
120 List.assoc k !exit_subst with
121 | Not_found -> Misc.fatal_error "Split.find_exit_subst"
123 let rec rename i sub =
127 | Ireturn | Iop(Itailcall_ind) | Iop(Itailcall_imm _) ->
128 (instr_cons i.desc (subst_regs i.arg sub) [||] i.next,
130 | Iop Ireload when i.res.(0).loc = Unknown ->
132 None -> rename i.next sub
134 let oldr = i.res.(0) in
135 let newr = Reg.clone i.res.(0) in
136 let (new_next, sub_next) =
137 rename i.next (Some(Reg.Map.add oldr newr s)) in
138 (instr_cons i.desc i.arg [|newr|] new_next,
142 let (new_next, sub_next) = rename i.next sub in
143 (instr_cons_debug i.desc (subst_regs i.arg sub) (subst_regs i.res sub)
146 | Iifthenelse(tst, ifso, ifnot) ->
147 let (new_ifso, sub_ifso) = rename ifso sub in
148 let (new_ifnot, sub_ifnot) = rename ifnot sub in
149 let (new_next, sub_next) =
150 rename i.next (merge_substs sub_ifso sub_ifnot i.next) in
151 (instr_cons (Iifthenelse(tst, new_ifso, new_ifnot))
152 (subst_regs i.arg sub) [||] new_next,
154 | Iswitch(index, cases) ->
155 let new_sub_cases = Array.map (fun c -> rename c sub) cases in
157 merge_subst_array (Array.map (fun (n, s) -> s) new_sub_cases) i.next in
158 let (new_next, sub_next) = rename i.next sub_merge in
159 (instr_cons (Iswitch(index, Array.map (fun (n, s) -> n) new_sub_cases))
160 (subst_regs i.arg sub) [||] new_next,
163 let (new_body, sub_body) = rename body sub in
164 let (new_next, sub_next) = rename i.next (merge_substs sub sub_body i) in
165 (instr_cons (Iloop(new_body)) [||] [||] new_next,
167 | Icatch(nfail, body, handler) ->
168 let new_subst = ref None in
169 exit_subst := (nfail, new_subst) :: !exit_subst ;
170 let (new_body, sub_body) = rename body sub in
171 let sub_entry_handler = !new_subst in
172 exit_subst := List.tl !exit_subst;
173 let (new_handler, sub_handler) = rename handler sub_entry_handler in
174 let (new_next, sub_next) =
175 rename i.next (merge_substs sub_body sub_handler i.next) in
176 (instr_cons (Icatch(nfail, new_body, new_handler)) [||] [||] new_next,
179 let r = find_exit_subst nfail in
180 r := merge_substs !r sub i;
182 | Itrywith(body, handler) ->
183 let (new_body, sub_body) = rename body sub in
184 let (new_handler, sub_handler) = rename handler sub in
185 let (new_next, sub_next) =
186 rename i.next (merge_substs sub_body sub_handler i.next) in
187 (instr_cons (Itrywith(new_body, new_handler)) [||] [||] new_next,
190 (instr_cons_debug Iraise (subst_regs i.arg sub) [||] i.dbg i.next,
193 (* Second pass: replace registers by their final representatives *)
196 instr_iter (fun i -> repres_regs i.arg; repres_regs i.res) i
201 equiv_classes := Reg.Map.empty;
202 let new_args = Array.copy f.fun_args in
203 let (new_body, sub_body) = rename f.fun_body (Some Reg.Map.empty) in
204 repres_regs new_args;
206 equiv_classes := Reg.Map.empty;
207 { fun_name = f.fun_name;
210 fun_fast = f.fun_fast }