    -- | An architecture independent description of a register.
    --	This needs to stay architecture independent because it is used
    --	by NCGMonad and the register allocators, which are shared
    --	by all architectures.
    --
    module Reg (
    	RegNo,
    	Reg(..),
    	regPair,
    	regSingle,
    	isRealReg,	takeRealReg,
    	isVirtualReg,	takeVirtualReg,

    	VirtualReg(..),
    	renameVirtualReg,
    	classOfVirtualReg,
    	getHiVirtualRegFromLo,
    	getHiVRegFromLo,

    	RealReg(..),
    	regNosOfRealReg,
    	realRegsAlias,

    	liftPatchFnToRegReg
    )

    where

    import Outputable
    import Unique
    import RegClass
    import Data.List

    -- | An identifier for a primitive real machine register.
    type RegNo
    	= Int

    -- VirtualRegs are virtual registers.  The register allocator will
    -- 	eventually have to map them into RealRegs, or into spill slots.
    --
    -- 	VirtualRegs are allocated on the fly, usually to represent a single
    -- 	value in the abstract assembly code (i.e. dynamic registers are
    -- 	usually single assignment).
    --
    --	The  single assignment restriction isn't necessary to get correct code,
    -- 	although a better register allocation will result if single
    -- 	assignment is used -- because the allocator maps a VirtualReg into
    -- 	a single RealReg, even if the VirtualReg has multiple live ranges.
    --
    -- 	Virtual regs can be of either class, so that info is attached.
    --
    data VirtualReg
    	= VirtualRegI  {-# UNPACK #-} !Unique
    	| VirtualRegHi {-# UNPACK #-} !Unique  -- High part of 2-word register
    	| VirtualRegF  {-# UNPACK #-} !Unique
    	| VirtualRegD  {-# UNPACK #-} !Unique
    	| VirtualRegSSE {-# UNPACK #-} !Unique
    	deriving (Eq, Show, Ord)

    instance Uniquable VirtualReg where
    	getUnique reg
    	 = case reg of
    	 	VirtualRegI u	-> u
    		VirtualRegHi u	-> u
    		VirtualRegF u	-> u
    		VirtualRegD u	-> u
    		VirtualRegSSE u	-> u

    instance Outputable VirtualReg where
    	ppr reg
    	 = case reg of
    		VirtualRegI  u  -> text "%vI_" 	<> pprUnique u
    		VirtualRegHi u  -> text "%vHi_" <> pprUnique u
    		VirtualRegF  u  -> text "%vF_" 	<> pprUnique u
    		VirtualRegD  u  -> text "%vD_" 	<> pprUnique u
    		VirtualRegSSE u -> text "%vSSE_" <> pprUnique u

    renameVirtualReg :: Unique -> VirtualReg -> VirtualReg
    renameVirtualReg u r
     = case r of
    	VirtualRegI _	-> VirtualRegI  u
    	VirtualRegHi _	-> VirtualRegHi u
    	VirtualRegF _	-> VirtualRegF  u
    	VirtualRegD _	-> VirtualRegD  u
    	VirtualRegSSE _	-> VirtualRegSSE u

    classOfVirtualReg :: VirtualReg -> RegClass
    classOfVirtualReg vr
     = case vr of
     	VirtualRegI{}	-> RcInteger
    	VirtualRegHi{}	-> RcInteger
    	VirtualRegF{}	-> RcFloat
    	VirtualRegD{}	-> RcDouble
    	VirtualRegSSE{}	-> RcDoubleSSE

    -- Determine the upper-half vreg for a 64-bit quantity on a 32-bit platform
    -- when supplied with the vreg for the lower-half of the quantity.
    -- (NB. Not reversible).
    getHiVirtualRegFromLo :: VirtualReg -> VirtualReg
    getHiVirtualRegFromLo reg
     = case reg of
    	-- makes a pseudo-unique with tag 'H'
     	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"

    ------------------------------------------------------------------------------------
    -- | RealRegs are machine regs which are available for allocation, in
    -- 	the usual way.  We know what class they are, because that's part of
    -- 	the processor's architecture.
    --
    -- 	RealRegPairs are pairs of real registers that are allocated together
    --	to hold a larger value, such as with Double regs on SPARC.
    --
    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 <> text "|" <> 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)

    --------------------------------------------------------------------------------
    -- | A register, either virtual or real
    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

    -- We like to have Uniques for Reg so that we can make UniqFM and UniqSets
    -- in the register allocator.
    instance Uniquable Reg where
    	getUnique reg
    	 = case reg of
    	 	RegVirtual vr	-> getUnique vr
    		RegReal    rr	-> getUnique rr

    -- | Print a reg in a generic manner
    --	If you want the architecture specific names, then use the pprReg
    --	function from the appropriate Ppr module.
    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

    -- | The patch function supplied by the allocator maps VirtualReg to RealReg
    --	regs, but sometimes we want to apply it to plain old Reg.
    --
    liftPatchFnToRegReg  :: (VirtualReg -> RealReg) -> (Reg -> Reg)
    liftPatchFnToRegReg patchF reg
     = case reg of
     	RegVirtual vr	-> RegReal (patchF vr)
    	RegReal _	-> reg