module Reg (
        RegNo,
        Reg(..),
        regPair,
        regSingle,
        isRealReg,      takeRealReg,
        isVirtualReg,   takeVirtualReg,
        VirtualReg(..),
        renameVirtualReg,
        classOfVirtualReg,
        getHiVirtualRegFromLo,
        getHiVRegFromLo,
        RealReg(..),
        regNosOfRealReg,
        realRegsAlias,
        liftPatchFnToRegReg
)
where
import GhcPrelude
import Outputable
import Unique
import RegClass
import Data.List
type RegNo
        = Int
data VirtualReg
        = VirtualRegI  {-# UNPACK #-} !Unique
        | VirtualRegHi {-# UNPACK #-} !Unique  
        | VirtualRegF  {-# UNPACK #-} !Unique
        | VirtualRegD  {-# UNPACK #-} !Unique
        deriving (Eq, Show)
instance Ord VirtualReg where
  compare (VirtualRegI a) (VirtualRegI b) = nonDetCmpUnique a b
  compare (VirtualRegHi a) (VirtualRegHi b) = nonDetCmpUnique a b
  compare (VirtualRegF a) (VirtualRegF b) = nonDetCmpUnique a b
  compare (VirtualRegD a) (VirtualRegD b) = nonDetCmpUnique a b
  compare VirtualRegI{} _ = LT
  compare _ VirtualRegI{} = GT
  compare VirtualRegHi{} _ = LT
  compare _ VirtualRegHi{} = GT
  compare VirtualRegF{} _ = LT
  compare _ VirtualRegF{} = GT
instance Uniquable VirtualReg where
        getUnique reg
         = case reg of
                VirtualRegI u   -> u
                VirtualRegHi u  -> u
                VirtualRegF u   -> u
                VirtualRegD u   -> u
instance Outputable VirtualReg where
        ppr reg
         = case reg of
                VirtualRegI  u  -> text "%vI_"   <> pprUniqueAlways u
                VirtualRegHi u  -> text "%vHi_"  <> pprUniqueAlways u
                
                
                
                VirtualRegF  u  -> text "%vFloat_"   <> pprUniqueAlways u
                VirtualRegD  u  -> text "%vDouble_"   <> pprUniqueAlways u
renameVirtualReg :: Unique -> VirtualReg -> VirtualReg
renameVirtualReg u r
 = case r of
        VirtualRegI _   -> VirtualRegI  u
        VirtualRegHi _  -> VirtualRegHi u
        VirtualRegF _   -> VirtualRegF  u
        VirtualRegD _   -> VirtualRegD  u
classOfVirtualReg :: VirtualReg -> RegClass
classOfVirtualReg vr
 = case vr of
        VirtualRegI{}   -> RcInteger
        VirtualRegHi{}  -> RcInteger
        VirtualRegF{}   -> RcFloat
        VirtualRegD{}   -> RcDouble
getHiVirtualRegFromLo :: VirtualReg -> VirtualReg
getHiVirtualRegFromLo reg
 = case reg of
        
        VirtualRegI u   -> VirtualRegHi (newTagUnique u 'H')
        _               -> panic "Reg.getHiVirtualRegFromLo"
getHiVRegFromLo :: Reg -> Reg
getHiVRegFromLo reg
 = case reg of
        RegVirtual  vr  -> RegVirtual (getHiVirtualRegFromLo vr)
        RegReal _       -> panic "Reg.getHiVRegFromLo"
data RealReg
        = RealRegSingle {-# UNPACK #-} !RegNo
        | RealRegPair   {-# UNPACK #-} !RegNo {-# UNPACK #-} !RegNo
        deriving (Eq, Show, Ord)
instance Uniquable RealReg where
        getUnique reg
         = case reg of
                RealRegSingle i         -> mkRegSingleUnique i
                RealRegPair r1 r2       -> mkRegPairUnique (r1 * 65536 + r2)
instance Outputable RealReg where
        ppr reg
         = case reg of
                RealRegSingle i         -> text "%r"  <> int i
                RealRegPair r1 r2       -> text "%r(" <> int r1
                                           <> vbar <> int r2 <> text ")"
regNosOfRealReg :: RealReg -> [RegNo]
regNosOfRealReg rr
 = case rr of
        RealRegSingle r1        -> [r1]
        RealRegPair   r1 r2     -> [r1, r2]
realRegsAlias :: RealReg -> RealReg -> Bool
realRegsAlias rr1 rr2
        = not $ null $ intersect (regNosOfRealReg rr1) (regNosOfRealReg rr2)
data Reg
        = RegVirtual !VirtualReg
        | RegReal    !RealReg
        deriving (Eq, Ord)
regSingle :: RegNo -> Reg
regSingle regNo         = RegReal $ RealRegSingle regNo
regPair :: RegNo -> RegNo -> Reg
regPair regNo1 regNo2   = RegReal $ RealRegPair regNo1 regNo2
instance Uniquable Reg where
        getUnique reg
         = case reg of
                RegVirtual vr   -> getUnique vr
                RegReal    rr   -> getUnique rr
instance Outputable Reg where
        ppr reg
         = case reg of
                RegVirtual vr   -> ppr vr
                RegReal    rr   -> ppr rr
isRealReg :: Reg -> Bool
isRealReg reg
 = case reg of
        RegReal _       -> True
        RegVirtual _    -> False
takeRealReg :: Reg -> Maybe RealReg
takeRealReg reg
 = case reg of
        RegReal rr      -> Just rr
        _               -> Nothing
isVirtualReg :: Reg -> Bool
isVirtualReg reg
 = case reg of
        RegReal _       -> False
        RegVirtual _    -> True
takeVirtualReg :: Reg -> Maybe VirtualReg
takeVirtualReg reg
 = case reg of
        RegReal _       -> Nothing
        RegVirtual vr   -> Just vr
liftPatchFnToRegReg  :: (VirtualReg -> RealReg) -> (Reg -> Reg)
liftPatchFnToRegReg patchF reg
 = case reg of
        RegVirtual vr   -> RegReal (patchF vr)
        RegReal _       -> reg