open ERTL
let instruction_successors (i : instruction) =
  match i with
  | IReturn _
  | ITailCall _ ->
      Label.Set.empty
  | INewFrame l
  | IDeleteFrame l
  | IGetHwReg (_, _, l)
  | ISetHwReg (_, _, l)
  | IGetStack (_, _, l)
  | ISetStack (_, _, l)
  | IGetGlobal (_, _, l)
  | ISetGlobal (_, _, l)
  | IConst (_, _, l)
  | IUnOp (_, _, _, l)
  | IBinOp (_, _, _, _, l)
  | ICall (_, _, l)
  | ILoad (_, _, _, l)
  | IStore (_, _, _, l)
  | IGoto l ->
      Label.Set.singleton l
  | IUnBranch (_, _, l1, l2)
  | IBinBranch (_, _, _, l1, l2) ->
      Label.Set.couple l1 l2
module L = struct
  
  type t =
      Register.Set.t * MIPS.RegisterSet.t
  type property =
      t
  let bottom =
    Register.Set.empty, MIPS.RegisterSet.empty
  let psingleton r =
    Register.Set.singleton r, MIPS.RegisterSet.empty
  let hsingleton hwr =
    Register.Set.empty, MIPS.RegisterSet.singleton hwr
  let join (rset1, hwrset1) (rset2, hwrset2) =
    (Register.Set.union rset1 rset2, MIPS.RegisterSet.union hwrset1 hwrset2)
  let diff (rset1, hwrset1) (rset2, hwrset2) =
    (Register.Set.diff rset1 rset2, MIPS.RegisterSet.diff hwrset1 hwrset2)
  let equal (rset1, hwrset1) (rset2, hwrset2) =
    Register.Set.equal rset1 rset2 && MIPS.RegisterSet.equal hwrset1 hwrset2
  let is_maximal _ =
    false
end
module F = Fix.Make (Label.ImperativeMap) (L)
let defined (i : instruction) : L.t =
  match i with
  | IGetHwReg (r, _, _)
  | IGetStack (r, _, _)
  | IConst (r, _, _)
  | IUnOp (_, r, _, _)
  | IBinOp (_, r, _, _, _)
  | ILoad (r, _, _, _)
  | IGetGlobal (r, _, _) ->
      L.psingleton r
  | ICall _ ->
      
      Register.Set.empty, MIPS.caller_saved
  | ISetHwReg (hwr, _, _) ->
      L.hsingleton hwr
  | INewFrame _
  | IDeleteFrame _
  | ISetStack _
  | IStore _
  | ISetGlobal _
  | IGoto _
  | IUnBranch _
  | IBinBranch _
  | IReturn _
  | ITailCall _ ->
      L.bottom
let saved =
  MIPS.RegisterSet.add MIPS.ra MIPS.callee_saved
let used (i : instruction) : L.t =
  match i with
  | IGetHwReg (_, hwr, _) ->
      L.hsingleton hwr
  | INewFrame _
  | IDeleteFrame _
  | IGetStack _
  | IConst _
  | IGoto _
  | IGetGlobal _ ->
      L.bottom
  | ISetHwReg (_, r, _)
  | ISetStack (_, r, _)
  | IUnOp (_, _, r, _)
  | ILoad (_, r, _, _)
  | ISetGlobal (_, r, _)
  | IUnBranch (_, r, _, _) ->
      L.psingleton r
  | IBinOp (_, _, r1, r2, _)
  | IStore (r1, _, r2, _)
  | IBinBranch (_, r1, r2, _, _) ->
      Register.Set.couple r1 r2, MIPS.RegisterSet.empty
  | ICall (_, nparams, _) ->
      
        
      Register.Set.empty,
      MIPS.RegisterSet.of_list (Misc.prefix nparams MIPS.parameters)
  | IReturn false ->
      
        
      
        
        
        
        
      Register.Set.empty,
      saved
  | IReturn true ->
      Register.Set.empty,
      MIPS.RegisterSet.add MIPS.result saved
  | ITailCall (_, nparams) ->
      Register.Set.empty,
      MIPS.RegisterSet.union
        saved
        (MIPS.RegisterSet.of_list (Misc.prefix nparams MIPS.parameters))
let eliminable ((pliveafter, hliveafter) : L.t) (i : instruction) : Label.t option =
  match i with
  | IGetHwReg (r, _, l)
  | IGetStack (r, _, l)
  | IGetGlobal (r, _, l)
  | IConst (r, _, l)
  | IUnOp (_, r, _, l)
  | IBinOp (_, r, _, _, l)
  | ILoad (r, _, _, l) ->
      if Register.Set.mem r pliveafter then None else Some l
  | ISetHwReg (hwr, _, l) ->
      if MIPS.RegisterSet.mem hwr hliveafter then None else Some l
  | IReturn _
  | ITailCall _
  | INewFrame _
  | IDeleteFrame _
  | ISetStack _
  | ISetGlobal _
  | ICall _
  | IStore _
  | IGoto _
  | IUnBranch _
  | IBinBranch _ ->
      None
let instruction_semantics (i : instruction) (liveafter : L.t) : L.t =
  match eliminable liveafter i with
  | None ->
      L.join (L.diff liveafter (defined i)) (used i)
  | Some _ ->
      liveafter
type valuation =
    Label.t -> L.t
let analyze (proc : procedure) : valuation =
  
  
  
  let livebefore label (liveafter : valuation) : L.t =
    let i : instruction = Label.Map.find label proc.graph in
    instruction_semantics i (liveafter label)
  in
  
  let liveafter label (liveafter : valuation) : L.t =
    let i : instruction = Label.Map.find label proc.graph in
    Label.Set.fold (fun successor accu ->
      L.join (livebefore successor liveafter) accu
    ) (instruction_successors i) L.bottom
  in
  
  F.lfp liveafter