My working unpac repository
at opam/upstream/seq 217 lines 7.4 kB view raw
1(**************************************************************************) 2(* *) 3(* OCaml *) 4(* *) 5(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *) 6(* *) 7(* Copyright 1996 Institut National de Recherche en Informatique et *) 8(* en Automatique. *) 9(* *) 10(* All rights reserved. This file is distributed under the terms of *) 11(* the GNU Lesser General Public License version 2.1, with the *) 12(* special exception on linking described in the file LICENSE. *) 13(* *) 14(**************************************************************************) 15 16(* Renaming of registers at reload points to split live ranges. *) 17 18open Reg 19open Mach 20 21(* Substitutions are represented by register maps *) 22 23type subst = Reg.t Reg.Map.t 24 25let subst_reg r (sub : subst) = 26 try 27 Reg.Map.find r sub 28 with Not_found -> 29 r 30 31let subst_regs rv sub = 32 match sub with 33 None -> rv 34 | Some s -> 35 let n = Array.length rv in 36 let nv = Array.make n Reg.dummy in 37 for i = 0 to n-1 do nv.(i) <- subst_reg rv.(i) s done; 38 nv 39 40(* We maintain equivalence classes of registers using a standard 41 union-find algorithm *) 42 43let equiv_classes = ref (Reg.Map.empty : Reg.t Reg.Map.t) 44 45let rec repres_reg r = 46 try 47 repres_reg(Reg.Map.find r !equiv_classes) 48 with Not_found -> 49 r 50 51let repres_regs rv = 52 let n = Array.length rv in 53 for i = 0 to n-1 do rv.(i) <- repres_reg rv.(i) done 54 55(* Identify two registers. 56 The second register is chosen as canonical representative. *) 57 58let identify r1 r2 = 59 let repres1 = repres_reg r1 in 60 let repres2 = repres_reg r2 in 61 if repres1.stamp = repres2.stamp then () else begin 62 equiv_classes := Reg.Map.add repres1 repres2 !equiv_classes 63 end 64 65(* Identify the image of a register by two substitutions. 66 Be careful to use the original register as canonical representative 67 in case it does not belong to the domain of one of the substitutions. *) 68 69let identify_sub sub1 sub2 reg = 70 try 71 let r1 = Reg.Map.find reg sub1 in 72 try 73 let r2 = Reg.Map.find reg sub2 in 74 identify r1 r2 75 with Not_found -> 76 identify r1 reg 77 with Not_found -> 78 try 79 let r2 = Reg.Map.find reg sub2 in 80 identify r2 reg 81 with Not_found -> 82 () 83 84(* Identify registers so that the two substitutions agree on the 85 registers live before the given instruction. *) 86 87let merge_substs sub1 sub2 i = 88 match (sub1, sub2) with 89 (None, None) -> None 90 | (Some _, None) -> sub1 91 | (None, Some _) -> sub2 92 | (Some s1, Some s2) -> 93 Reg.Set.iter (identify_sub s1 s2) (Reg.add_set_array i.live i.arg); 94 sub1 95 96(* Same, for N substitutions *) 97 98let merge_subst_array subv instr = 99 let rec find_one_subst i = 100 if i >= Array.length subv then None else begin 101 match subv.(i) with 102 None -> find_one_subst (i+1) 103 | Some si as sub -> 104 for j = i+1 to Array.length subv - 1 do 105 match subv.(j) with 106 None -> () 107 | Some sj -> 108 Reg.Set.iter (identify_sub si sj) 109 (Reg.add_set_array instr.live instr.arg) 110 done; 111 sub 112 end in 113 find_one_subst 0 114 115(* First pass: rename registers at reload points *) 116 117let exit_subst = ref [] 118 119let find_exit_subst k = 120 try 121 List.assoc k !exit_subst with 122 | Not_found -> Misc.fatal_error "Split.find_exit_subst" 123 124let rec rename i sub = 125 match i.desc with 126 Iend -> 127 (i, sub) 128 | Ireturn | Iop(Itailcall_ind) | Iop(Itailcall_imm _) -> 129 (instr_cons_debug i.desc (subst_regs i.arg sub) [||] i.dbg i.next, 130 None) 131 | Iop Ireload when i.res.(0).loc = Unknown -> 132 begin match sub with 133 None -> rename i.next sub 134 | Some s -> 135 let oldr = i.res.(0) in 136 let newr = Reg.clone i.res.(0) in 137 let (new_next, sub_next) = 138 rename i.next (Some(Reg.Map.add oldr newr s)) in 139 (instr_cons i.desc i.arg [|newr|] new_next, 140 sub_next) 141 end 142 | Iop _ -> 143 let (new_next, sub_next) = rename i.next sub in 144 (instr_cons_debug i.desc (subst_regs i.arg sub) (subst_regs i.res sub) 145 i.dbg new_next, 146 sub_next) 147 | Iifthenelse(tst, ifso, ifnot) -> 148 let (new_ifso, sub_ifso) = rename ifso sub in 149 let (new_ifnot, sub_ifnot) = rename ifnot sub in 150 let (new_next, sub_next) = 151 rename i.next (merge_substs sub_ifso sub_ifnot i.next) in 152 (instr_cons (Iifthenelse(tst, new_ifso, new_ifnot)) 153 (subst_regs i.arg sub) [||] new_next, 154 sub_next) 155 | Iswitch(index, cases) -> 156 let new_sub_cases = Array.map (fun c -> rename c sub) cases in 157 let sub_merge = 158 merge_subst_array (Array.map (fun (_n, s) -> s) new_sub_cases) i.next in 159 let (new_next, sub_next) = rename i.next sub_merge in 160 (instr_cons (Iswitch(index, Array.map (fun (n, _s) -> n) new_sub_cases)) 161 (subst_regs i.arg sub) [||] new_next, 162 sub_next) 163 | Icatch(rec_flag, handlers, body) -> 164 let new_subst = List.map (fun (nfail, _) -> nfail, ref None) 165 handlers in 166 let previous_exit_subst = !exit_subst in 167 exit_subst := new_subst @ !exit_subst; 168 let (new_body, sub_body) = rename body sub in 169 let res = 170 List.map2 (fun (_, handler) (_, new_subst) -> rename handler !new_subst) 171 handlers new_subst in 172 exit_subst := previous_exit_subst; 173 let merged_subst = 174 List.fold_left (fun acc (_, sub_handler) -> 175 merge_substs acc sub_handler i.next) 176 sub_body res in 177 let (new_next, sub_next) = rename i.next merged_subst in 178 let new_handlers = List.map2 (fun (nfail, _) (handler, _) -> 179 (nfail, handler)) handlers res in 180 (instr_cons 181 (Icatch(rec_flag, new_handlers, new_body)) [||] [||] new_next, 182 sub_next) 183 | Iexit nfail -> 184 let r = find_exit_subst nfail in 185 r := merge_substs !r sub i; 186 (i, None) 187 | Itrywith(body, handler) -> 188 let (new_body, sub_body) = rename body sub in 189 let (new_handler, sub_handler) = rename handler sub in 190 let (new_next, sub_next) = 191 rename i.next (merge_substs sub_body sub_handler i.next) in 192 (instr_cons (Itrywith(new_body, new_handler)) [||] [||] new_next, 193 sub_next) 194 | Iraise k -> 195 (instr_cons_debug (Iraise k) (subst_regs i.arg sub) [||] i.dbg i.next, 196 None) 197 198(* Second pass: replace registers by their final representatives *) 199 200let set_repres i = 201 instr_iter (fun i -> repres_regs i.arg; repres_regs i.res) i 202 203(* Entry point *) 204 205let reset () = 206 equiv_classes := Reg.Map.empty; 207 exit_subst := [] 208 209let fundecl f = 210 reset (); 211 212 let new_args = Array.copy f.fun_args in 213 let (new_body, _sub_body) = rename f.fun_body (Some Reg.Map.empty) in 214 repres_regs new_args; 215 set_repres new_body; 216 equiv_classes := Reg.Map.empty; 217 { f with fun_args = new_args; fun_body = new_body }