(* frame.ml *)
(* 15-411 *)
(* by Arthur O'Dwyer *)
(* @version $Id: frame.ml,v 1.2 2004/11/01 09:21:32 ajo Exp $ *)

module A = Absyn
module T = Ir
module TP = Temp

(*
   This module and |Finalize| between them ought to contain all the 
   target-specific parts of the compiler.  Module |Frame| knows the 
   number of available registers (|nregs|) and how to deal with the
   stack frame.  |Finalize| knows the prelude and postlude code and
   the names of all the registers.
*)
exception InternalError

(*
   The number of registers in this architecture available
   for register allocation.
*)
let nregs = 6


(*
   Code related to allocation of variables on the current stack frame,
   as opposed to in register-allocatable temps.  The routine |allocLocal|
   is called by the compiler's main routines whenever a variable name
   is encountered.
*)
type frame = FrameTemp of TP.temp
           | FrameStack of int
           | FrameNil

let stack_counter = ref 0
let simpStack () = (stack_counter := !stack_counter+1; !stack_counter)

let allLocals : (string * bool * frame) list ref = ref []


let clear () = (allLocals := []; stack_counter := 0)
let size () = !stack_counter

let allocLocal id escaped = (
  let rec help = function
  | [] -> [(id, escaped, FrameNil)]
  | (s,b,f)::t -> if (s = id) then (s, b || escaped, f)::t
                  else (s, b, f)::(help t)
  in
    allLocals := help !allLocals
)

let assign () = (
  let help (s,escaped,_) = (
    if escaped then (s,escaped,FrameStack(simpStack()))
    else (s,escaped,FrameTemp(TP.simpTemp()))
  )
  in allLocals := List.map help !allLocals;
  List.iter (function (s,b,f) ->
               Printf.printf "(%s, %s, %s)\n"
                 s (if b then "true" else "false")
                 (match f with FrameNil -> "nil"
                  | FrameStack n -> Printf.sprintf "stack %d" n
                  | FrameTemp n -> Printf.sprintf "temp %d" n
                 )
            ) !allLocals
)

let getLocal id = (
  let (s,b,f) = List.find (function (s,_,_) -> s=id) !allLocals
  in f
)

let localIR id = (
  match (getLocal id) with
  | FrameTemp t -> T.TEMP(t)
  | FrameStack n ->
      T.UNOP(A.DEREF,
             T.BINOP(A.PLUS,
                     T.REG_EBP, T.CONST(Int32.of_int (-4*n))
            )       )
  | FrameNil -> raise InternalError
)