(*
 * Copyright (c) 2001 Stefan Kral
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *)


(* This module include the declaration of the data types used within the
 * register allocator and some common functions on them.
 *)

open List
open Util
open VSimdBasics
open P4Basics

type initcodeinstr = 
  | AddIntOnDemandCode of vintreg * p4vinstr list

type riregfileentry =
  | IFree
  | IHolds of vintreg
  | ITmpHoldsProduct of vintreg * int		(* used for reusing EAs *)
  | IVarHoldsProduct of vintreg * vintreg * int

type rsregfileentry =
  | SFree
  | SHolds of vsimdreg

type vsregfileentry =
  | SFresh
  | SDead
  | SDying of p4rmmxreg
  | SIn of p4rmmxreg
  | SInAndOut of p4rmmxreg * int 
  | SInConst of p4rmmxreg * string
  | SOut of int
  | SConst of string
  | SOnDemand of p4vinstr list

type viregfileentry =
  | IFresh
  | IDead
  | IDying of p4rintreg
  | IIn of p4rintreg
  | IInAndOut of p4rintreg * int 
  | IInConst of p4rintreg * string
  | IOut of int
  | IConst of string
  | IOnDemand of p4vinstr list

let vsregfileentryIsFresh = function
  | SFresh -> true
  | _ -> false

let livevsregfileentryToP4rmmxreg = function
  | SIn x 	   -> Some x
  | SInAndOut(x,_) -> Some x
  | SInConst(x,_)  -> Some x
  | SDying _ 	   -> None
  | SOut _ 	   -> None
  | SConst _ 	   -> None
  | SFresh 	   -> None
  | SDead 	   -> failwith "livevsregfileentryToP4rmmxreg: dead register!"
  | SOnDemand _    -> failwith "livevsregfileentryToP4rmmxreg: ondemand reg!"

let vsregfileentryToP4memop = function		(* used only once! *)
  | SIn x 	   -> None
  | SInAndOut(x,_) -> None
  | SInConst(x,_)  -> None
  | SDying _ 	   -> None
  | SOut p 	   -> Some (P4_MStackCell(P4_MMXStack,p))
  | SConst c 	   -> Some (P4_MConst c)
  | SFresh 	   -> None
  | SDead 	   -> failwith "livevsregfileentryToP4rmmxreg: dead register!"
  | SOnDemand _    -> failwith "livevsregfileentryToP4rmmxreg: ondemand reg!"

let vsregfileentryToP4rmmxreg = function
  | SDying x -> Some x
  | x 	     -> livevsregfileentryToP4rmmxreg x

let liveviregfileentryToP4rintreg = function
  | IIn x 	   -> Some x
  | IInAndOut(x,_) -> Some x
  | IInConst(x,_)  -> Some x
  | IDying _ 	   -> None
  | IOut _ 	   -> None
  | IConst _	   -> None
  | IFresh	   -> None
  | IDead 	   -> failwith "liveviregfileentryToP4rintreg: dead register!"
  | IOnDemand _	   -> failwith "liveviregfileentryToP4rintreg: ondemand reg!"

let viregfileentryToP4rintreg = function
  | IDying x -> Some x
  | x 	     -> liveviregfileentryToP4rintreg x

let vsregfileentryToP4rmmxreg' e = optionToValue (vsregfileentryToP4rmmxreg e)
let viregfileentryToP4rintreg' e = optionToValue (viregfileentryToP4rintreg e)

let viregWantsIn viregfile vireg = match VIntRegMap.find vireg viregfile with
  | IOut _	-> true
  | IFresh	-> true
  | IConst _	-> true
  | IInAndOut _	-> false
  | IIn _	-> false
  | IInConst _	-> false
  | IDead	-> failwith "viregWantsIn: using dead register!"
  | IDying _	-> failwith "viregWantsIn: using dying register!"
  | IOnDemand _	-> failwith "viregWantsIn: encountered OnDemand register!"

let vsregWantsIn vsregfile vsreg = match VSimdRegMap.find vsreg vsregfile with
  | SOut _	-> true
  | SFresh	-> true
  | SConst _	-> true
  | SIn _	-> false
  | SInAndOut _	-> false
  | SInConst _	-> false
  | SDead	-> failwith "vsregWantsIn: using dead register!"
  | SDying _	-> failwith "vsregWantsIn: using dying register!"
  | SOnDemand _	-> failwith "vsregWantsIn: encountered OnDemand register!"


let touchSimdDstReg vsreg vsregfile = 
  match livevsregfileentryToP4rmmxreg (VSimdRegMap.find vsreg vsregfile) with
    | Some i -> VSimdRegMap.add vsreg (SIn i) vsregfile
    | None   -> failwith "touchSimdDstReg: register is unmapped!"

let touchIntDstReg vireg viregfile = 
  match liveviregfileentryToP4rintreg (VIntRegMap.find vireg viregfile) with
    | Some i -> VIntRegMap.add vireg (IIn i) viregfile
    | None   -> failwith "touchIntDstReg: register is unmapped!"

  

let vsregfileentryIsFresh = function
  | SFresh -> true
  | _ -> false

let viregfileentryIsFresh = function
  | IFresh -> true
  | _ -> false

let riregfileentryToVireg = function
  | IVarHoldsProduct(v,_,_) -> Some v
  | IHolds v 		    -> Some v
  | IFree		    -> None
  | ITmpHoldsProduct _      -> None

let riregfileentryIsFree x = optionIsNone (riregfileentryToVireg x)
