(**************************************************************************) (* *) (* OCaml *) (* *) (* Marcell Fischbach, University of Siegen *) (* Benedikt Meurer, University of Siegen *) (* *) (* Copyright 2011 Lehrstuhl für Compilerbau und Softwareanalyse, *) (* Universität Siegen. *) (* *) (* All rights reserved. This file is distributed under the terms of *) (* the GNU Lesser General Public License version 2.1, with the *) (* special exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (* Live intervals for the linear scan register allocator. *) open Mach open Reg type range = { mutable rbegin: int; mutable rend: int; } type t = { mutable reg: Reg.t; mutable ibegin: int; mutable iend: int; mutable ranges: range list; } type kind = Result | Argument | Live let interval_list = ref ([] : t list) let fixed_interval_list = ref ([] : t list) let all_intervals() = !interval_list let all_fixed_intervals() = !fixed_interval_list (* Check if two intervals overlap *) let overlap i0 i1 = let rec overlap_ranges rl0 rl1 = match rl0, rl1 with r0 :: rl0', r1 :: rl1' -> if r0.rend >= r1.rbegin && r1.rend >= r0.rbegin then true else if r0.rend < r1.rend then overlap_ranges rl0' rl1 else if r0.rend > r1.rend then overlap_ranges rl0 rl1' else overlap_ranges rl0' rl1' | _ -> false in overlap_ranges i0.ranges i1.ranges let is_live i pos = let rec is_live_in_ranges = function [] -> false | r :: rl -> if pos < r.rbegin then false else if pos <= r.rend then true else is_live_in_ranges rl in is_live_in_ranges i.ranges let remove_expired_ranges i pos = let rec filter = function [] -> [] | r :: rl' as rl -> if pos < r.rend then rl else filter rl' in i.ranges <- filter i.ranges let update_interval_position intervals pos kind reg = let i = intervals.(reg.stamp) in let on = pos lsl 1 in let off = on + 1 in let rbegin = (match kind with Result -> off | _ -> on) in let rend = (match kind with Argument -> on | _ -> off) in if i.iend = 0 then begin i.ibegin <- rbegin; i.reg <- reg; i.ranges <- [{rbegin = rbegin; rend = rend}] end else begin let r = List.hd i.ranges in let ridx = r.rend asr 1 in if pos - ridx <= 1 then r.rend <- rend else i.ranges <- {rbegin = rbegin; rend = rend} :: i.ranges end; i.iend <- rend let update_interval_position_by_array intervals regs pos kind = Array.iter (update_interval_position intervals pos kind) regs let update_interval_position_by_set intervals regs pos kind = Set.iter (update_interval_position intervals pos kind) regs let update_interval_position_by_instr intervals instr pos = update_interval_position_by_array intervals instr.arg pos Argument; update_interval_position_by_array intervals instr.res pos Result; update_interval_position_by_set intervals instr.live pos Live let insert_destroyed_at_oper intervals instr pos = let destroyed = Proc.destroyed_at_oper instr.desc in if Array.length destroyed > 0 then update_interval_position_by_array intervals destroyed pos Result let insert_destroyed_at_raise intervals pos = let destroyed = Proc.destroyed_at_raise in if Array.length destroyed > 0 then update_interval_position_by_array intervals destroyed pos Result (* Build all intervals. The intervals will be expanded by one step at the start and end of a basic block. *) let build_intervals fd = let intervals = Array.init (Reg.num_registers()) (fun _ -> { reg = Reg.dummy; ibegin = 0; iend = 0; ranges = []; }) in let pos = ref 0 in let rec walk_instruction i = incr pos; update_interval_position_by_instr intervals i !pos; begin match i.desc with Iend -> () | Iop(Icall_ind | Icall_imm _ | Iextcall{alloc = true; _} | Itailcall_ind | Itailcall_imm _) -> walk_instruction i.next | Iop _ -> insert_destroyed_at_oper intervals i !pos; walk_instruction i.next | Ireturn -> insert_destroyed_at_oper intervals i !pos; walk_instruction i.next | Iifthenelse(_, ifso, ifnot) -> insert_destroyed_at_oper intervals i !pos; walk_instruction ifso; walk_instruction ifnot; walk_instruction i.next | Iswitch(_, cases) -> insert_destroyed_at_oper intervals i !pos; Array.iter walk_instruction cases; walk_instruction i.next | Icatch(_, handlers, body) -> insert_destroyed_at_oper intervals i !pos; List.iter (fun (_, i) -> walk_instruction i) handlers; walk_instruction body; walk_instruction i.next | Iexit _ -> insert_destroyed_at_oper intervals i !pos; walk_instruction i.next | Itrywith(body, handler) -> insert_destroyed_at_oper intervals i !pos; walk_instruction body; insert_destroyed_at_raise intervals !pos; walk_instruction handler; walk_instruction i.next | Iraise _ -> walk_instruction i.next end in walk_instruction fd.fun_body; (* Generate the interval and fixed interval lists *) interval_list := []; fixed_interval_list := []; Array.iter (fun i -> if i.iend != 0 then begin i.ranges <- List.rev i.ranges; begin match i.reg.loc with Reg _ -> fixed_interval_list := i :: !fixed_interval_list | _ -> interval_list := i :: !interval_list end end) intervals; (* Sort the intervals according to their start position *) interval_list := List.sort (fun i0 i1 -> i0.ibegin - i1.ibegin) !interval_list