    -- | A description of the register set of the X86.
    --	This isn't used directly in GHC proper.
    --
    --	See RegArchBase.hs for the reference.
    --	See MachRegs.hs for the actual trivColorable function used in GHC.
    --

    module RegAlloc.Graph.ArchX86 (
    	classOfReg,
    	regsOfClass,
    	regName,
    	regAlias,
    	worst,
    	squeese,
    ) where

    import RegAlloc.Graph.ArchBase	(Reg(..), RegSub(..), RegClass(..))

    import UniqSet

    -- | Determine the class of a register
    classOfReg :: Reg -> RegClass
    classOfReg reg
     = case reg of
    	Reg c _		-> c

    	RegSub SubL16 _	-> ClassG16
    	RegSub SubL8  _	-> ClassG8
    	RegSub SubL8H _	-> ClassG8

    -- | Determine all the regs that make up a certain class.
    regsOfClass :: RegClass -> UniqSet Reg
    regsOfClass c
     = case c of
     	ClassG32
    	 -> mkUniqSet	  [ Reg ClassG32  i			| i <- [0..7] ]

    	ClassG16
    	 -> mkUniqSet     [ RegSub SubL16 (Reg ClassG32 i)	| i <- [0..7] ]

    	ClassG8
    	 -> unionUniqSets
    	 	(mkUniqSet [ RegSub SubL8  (Reg ClassG32 i)	| i <- [0..3] ])
    		(mkUniqSet [ RegSub SubL8H (Reg ClassG32 i)	| i <- [0..3] ])

    	ClassF64
    	 -> mkUniqSet 	   [ Reg ClassF64  i			| i <- [0..5] ]

    -- | Determine the common name of a reg
    --	returns Nothing if this reg is not part of the machine.
    regName :: Reg -> Maybe String
    regName reg
     = case reg of
     	Reg ClassG32 i
    	 | i <= 7	-> Just ([ "eax", "ebx", "ecx", "edx", "ebp", "esi", "edi", "esp" ] !! i)

    	RegSub SubL16 (Reg ClassG32 i)
    	 | i <= 7	-> Just ([ "ax", "bx", "cx", "dx", "bp", "si", "di", "sp"] !! i)

    	RegSub SubL8  (Reg ClassG32 i)
    	 | i <= 3	-> Just ([ "al", "bl", "cl", "dl"] !! i)

    	RegSub SubL8H (Reg ClassG32 i)
    	 | i <= 3	-> Just ([ "ah", "bh", "ch", "dh"] !! i)

    	_		-> Nothing

    -- | Which regs alias what other regs
    regAlias :: Reg -> UniqSet Reg
    regAlias reg
     = case reg of

    	-- 32 bit regs alias all of the subregs
    	Reg ClassG32 i

    	 -- for eax, ebx, ecx, eds
    	 |  i <= 3
    	 -> mkUniqSet $ [ Reg ClassG32 i, RegSub SubL16 reg, RegSub SubL8 reg, RegSub SubL8H reg ]

    	 -- for esi, edi, esp, ebp
    	 | 4 <= i && i <= 7
    	 -> mkUniqSet $ [ Reg ClassG32 i, RegSub SubL16 reg ]

    	-- 16 bit subregs alias the whole reg
    	RegSub SubL16 r@(Reg ClassG32 _)
    	 -> 	regAlias r

    	-- 8 bit subregs alias the 32 and 16, but not the other 8 bit subreg
    	RegSub SubL8  r@(Reg ClassG32 _)
    	 -> mkUniqSet $ [ r, RegSub SubL16 r, RegSub SubL8 r ]

    	RegSub SubL8H r@(Reg ClassG32 _)
    	 -> mkUniqSet $ [ r, RegSub SubL16 r, RegSub SubL8H r ]

    	-- fp
    	Reg ClassF64 _
    	 -> unitUniqSet reg

    	_ -> error "regAlias: invalid register"

    -- | Optimised versions of RegColorBase.{worst, squeese} specific to x86

    worst :: Int -> RegClass -> RegClass -> Int
    worst n classN classC
     = case classN of
     	ClassG32
    	 -> case classC of
    	 	ClassG32	-> min n 8
    		ClassG16	-> min n 8
    		ClassG8		-> min n 4
    		ClassF64	-> 0

    	ClassG16
    	 -> case classC of
    	 	ClassG32	-> min n 8
    		ClassG16	-> min n 8
    		ClassG8		-> min n 4
    		ClassF64	-> 0

    	ClassG8
    	 -> case classC of
    		ClassG32	-> min (n*2) 8
    		ClassG16	-> min (n*2) 8
    	 	ClassG8		-> min n 8
    		ClassF64	-> 0

    	ClassF64
    	 -> case classC of
    	 	ClassF64	-> min n 6
    		_		-> 0

    squeese :: RegClass -> [(Int, RegClass)] -> Int
    squeese classN countCs
    	= sum (map (\(i, classC) -> worst i classN classC) countCs)