{-# LANGUAGE DeriveGeneric #-}

module X86.Register
    ( Register(..)
    , reg8
    , reg16
    , reg32
    , reg64
    , reg80
    , reg128
    , reg256
    , real
    , overlapping) where

import           GHC.Generics (Generic)
import qualified Data.Serialize as Cereal
import           Generic.HasSize (HasSize(..))
import           Base (allp)
import           Control.DeepSeq

data Register =
    InvalidRegister
  | RIP
  | EIP
  | RAX
  | EAX
  | AX
  | AH
  | AL
  | RBX
  | EBX
  | BX
  | BH
  | BL
  | RCX
  | ECX
  | CX
  | CH
  | CL
  | RDX
  | EDX
  | DX
  | DH
  | DL
  | RDI
  | EDI
  | DI
  | DIL
  | RSI
  | ESI
  | SI
  | SIL
  | RSP
  | ESP
  | SP
  | SPL
  | RBP
  | EBP
  | BP
  | BPL
  | R15
  | R15D
  | R15W
  | R15B
  | R14
  | R14D
  | R14W
  | R14B
  | R13
  | R13D
  | R13W
  | R13B
  | R12
  | R12D
  | R12W
  | R12B
  | R11
  | R11D
  | R11W
  | R11B
  | R10
  | R10D
  | R10W
  | R10B
  | R9
  | R9D
  | R9W
  | R9B
  | R8
  | R8D
  | R8W
  | R8B
  | CS
  | DS
  | ES
  | FS
  | GS
  | SS
  | EIZ
  | RIZ
  | ST0
  | ST1
  | ST2
  | ST3
  | ST4
  | ST5
  | ST6
  | ST7
  | YMM0
  | YMM1
  | YMM2
  | YMM3
  | YMM4
  | YMM5
  | YMM6
  | YMM7
  | YMM8
  | YMM9
  | YMM10
  | YMM11
  | YMM12
  | YMM13
  | YMM14
  | YMM15
  | XMM0
  | XMM1
  | XMM2
  | XMM3
  | XMM4
  | XMM5
  | XMM6
  | XMM7
  | XMM8
  | XMM9
  | XMM10
  | XMM11
  | XMM12
  | XMM13
  | XMM14
  | XMM15
  | TEMP
  deriving (Int -> Register -> ShowS
[Register] -> ShowS
Register -> String
(Int -> Register -> ShowS)
-> (Register -> String) -> ([Register] -> ShowS) -> Show Register
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Register] -> ShowS
$cshowList :: [Register] -> ShowS
show :: Register -> String
$cshow :: Register -> String
showsPrec :: Int -> Register -> ShowS
$cshowsPrec :: Int -> Register -> ShowS
Show, Register -> Register -> Bool
(Register -> Register -> Bool)
-> (Register -> Register -> Bool) -> Eq Register
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Register -> Register -> Bool
$c/= :: Register -> Register -> Bool
== :: Register -> Register -> Bool
$c== :: Register -> Register -> Bool
Eq, ReadPrec [Register]
ReadPrec Register
Int -> ReadS Register
ReadS [Register]
(Int -> ReadS Register)
-> ReadS [Register]
-> ReadPrec Register
-> ReadPrec [Register]
-> Read Register
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [Register]
$creadListPrec :: ReadPrec [Register]
readPrec :: ReadPrec Register
$creadPrec :: ReadPrec Register
readList :: ReadS [Register]
$creadList :: ReadS [Register]
readsPrec :: Int -> ReadS Register
$creadsPrec :: Int -> ReadS Register
Read, Eq Register
Eq Register
-> (Register -> Register -> Ordering)
-> (Register -> Register -> Bool)
-> (Register -> Register -> Bool)
-> (Register -> Register -> Bool)
-> (Register -> Register -> Bool)
-> (Register -> Register -> Register)
-> (Register -> Register -> Register)
-> Ord Register
Register -> Register -> Bool
Register -> Register -> Ordering
Register -> Register -> Register
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Register -> Register -> Register
$cmin :: Register -> Register -> Register
max :: Register -> Register -> Register
$cmax :: Register -> Register -> Register
>= :: Register -> Register -> Bool
$c>= :: Register -> Register -> Bool
> :: Register -> Register -> Bool
$c> :: Register -> Register -> Bool
<= :: Register -> Register -> Bool
$c<= :: Register -> Register -> Bool
< :: Register -> Register -> Bool
$c< :: Register -> Register -> Bool
compare :: Register -> Register -> Ordering
$ccompare :: Register -> Register -> Ordering
$cp1Ord :: Eq Register
Ord, (forall x. Register -> Rep Register x)
-> (forall x. Rep Register x -> Register) -> Generic Register
forall x. Rep Register x -> Register
forall x. Register -> Rep Register x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep Register x -> Register
$cfrom :: forall x. Register -> Rep Register x
Generic, Int -> Register
Register -> Int
Register -> [Register]
Register -> Register
Register -> Register -> [Register]
Register -> Register -> Register -> [Register]
(Register -> Register)
-> (Register -> Register)
-> (Int -> Register)
-> (Register -> Int)
-> (Register -> [Register])
-> (Register -> Register -> [Register])
-> (Register -> Register -> [Register])
-> (Register -> Register -> Register -> [Register])
-> Enum Register
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: Register -> Register -> Register -> [Register]
$cenumFromThenTo :: Register -> Register -> Register -> [Register]
enumFromTo :: Register -> Register -> [Register]
$cenumFromTo :: Register -> Register -> [Register]
enumFromThen :: Register -> Register -> [Register]
$cenumFromThen :: Register -> Register -> [Register]
enumFrom :: Register -> [Register]
$cenumFrom :: Register -> [Register]
fromEnum :: Register -> Int
$cfromEnum :: Register -> Int
toEnum :: Int -> Register
$ctoEnum :: Int -> Register
pred :: Register -> Register
$cpred :: Register -> Register
succ :: Register -> Register
$csucc :: Register -> Register
Enum, Register
Register -> Register -> Bounded Register
forall a. a -> a -> Bounded a
maxBound :: Register
$cmaxBound :: Register
minBound :: Register
$cminBound :: Register
Bounded)

instance Cereal.Serialize Register
instance NFData Register

-- | List of 256 bit registers
reg256 :: [Register]
reg256 :: [Register]
reg256 =
  [ Register
YMM0
  , Register
YMM1
  , Register
YMM2
  , Register
YMM3
  , Register
YMM4
  , Register
YMM5
  , Register
YMM6
  , Register
YMM7
  , Register
YMM8
  , Register
YMM9
  , Register
YMM10
  , Register
YMM11
  , Register
YMM12
  , Register
YMM13
  , Register
YMM14
  , Register
YMM15]

-- | List of 128 bit registers
reg128 :: [Register]
reg128 :: [Register]
reg128 =
  [ Register
XMM0
  , Register
XMM1
  , Register
XMM2
  , Register
XMM3
  , Register
XMM4
  , Register
XMM5
  , Register
XMM6
  , Register
XMM7
  , Register
XMM8
  , Register
XMM9
  , Register
XMM10
  , Register
XMM11
  , Register
XMM12
  , Register
XMM13
  , Register
XMM14
  , Register
XMM15]

-- | List of 80 bit registers
reg80 :: [Register]
reg80 :: [Register]
reg80 = [Register
ST0, Register
ST1, Register
ST2, Register
ST3, Register
ST4, Register
ST5, Register
ST6, Register
ST7]

reg64 :: [Register]
-- | List of 64 bit registers
reg64 :: [Register]
reg64 =
  [ Register
RAX
  , Register
RBX
  , Register
RCX
  , Register
RDX
  , Register
RSI
  , Register
RDI
  , Register
RSP
  , Register
RBP
  , Register
R8
  , Register
R9
  , Register
R10
  , Register
R11
  , Register
R12
  , Register
R13
  , Register
R14
  , Register
R15
  , Register
RIP
  , Register
CS
  , Register
DS
  , Register
ES
  , Register
FS
  , Register
GS
  , Register
SS]

-- | List of 32 bit registers
reg32 :: [Register]
reg32 :: [Register]
reg32 = [ Register
EAX
        , Register
EBX
        , Register
ECX
        , Register
EDX
        , Register
ESI
        , Register
EDI
        , Register
ESP
        , Register
EBP
        , Register
R8D
        , Register
R9D
        , Register
R10D
        , Register
R11D
        , Register
R12D
        , Register
R13D
        , Register
R14D
        , Register
R15D]

-- | List of 16 bit registers
reg16 :: [Register]
reg16 :: [Register]
reg16 = [ Register
AX
        , Register
BX
        , Register
CX
        , Register
DX
        , Register
SI
        , Register
DI
        , Register
SP
        , Register
BP
        , Register
R8W
        , Register
R9W
        , Register
R10W
        , Register
R11W
        , Register
R12W
        , Register
R13W
        , Register
R14W
        , Register
R15W]

-- | List of 8 bit registers
reg8 :: [Register]
reg8 :: [Register]
reg8 = [ Register
AL
       , Register
BL
       , Register
CL
       , Register
DL
       , Register
SIL
       , Register
DIL
       , Register
SPL
       , Register
BPL
       , Register
R8B
       , Register
R9B
       , Register
R10B
       , Register
R11B
       , Register
R12B
       , Register
R13B
       , Register
R14B
       , Register
R15B]

-- | Matches register names to the real registers
-- E.g.: EAX is actually a part of RAX
real :: Register -> Register
real :: Register -> Register
real Register
EAX = Register
RAX
real Register
EBX = Register
RBX
real Register
ECX = Register
RCX
real Register
EDX = Register
RDX
real Register
ESI = Register
RSI
real Register
EDI = Register
RDI
real Register
ESP = Register
RSP
real Register
EBP = Register
RBP
real Register
R8D = Register
R8
real Register
R9D = Register
R9
real Register
R10D = Register
R10
real Register
R11D = Register
R11
real Register
R12D = Register
R12
real Register
R13D = Register
R13
real Register
R14D = Register
R14
real Register
R15D = Register
R15
real Register
AX = Register
RAX
real Register
BX = Register
RBX
real Register
CX = Register
RCX
real Register
DX = Register
RDX
real Register
SI = Register
RSI
real Register
DI = Register
RDI
real Register
SP = Register
RSP
real Register
BP = Register
RBP
real Register
R8W = Register
R8
real Register
R9W = Register
R9
real Register
R10W = Register
R10
real Register
R11W = Register
R11
real Register
R12W = Register
R12
real Register
R13W = Register
R13
real Register
R14W = Register
R14
real Register
R15W = Register
R15
real Register
AL = Register
RAX
real Register
BL = Register
RBX
real Register
CL = Register
RCX
real Register
DL = Register
RDX
real Register
SIL = Register
RSI
real Register
DIL = Register
RDI
real Register
SPL = Register
RSP
real Register
BPL = Register
RBP
real Register
R8B = Register
R8
real Register
R9B = Register
R9
real Register
R10B = Register
R10
real Register
R11B = Register
R11
real Register
R12B = Register
R12
real Register
R13B = Register
R13
real Register
R14B = Register
R14
real Register
R15B = Register
R15
real Register
XMM0 = Register
YMM0
real Register
XMM1 = Register
YMM1
real Register
XMM2 = Register
YMM2
real Register
XMM3 = Register
YMM3
real Register
XMM4 = Register
YMM4
real Register
XMM5 = Register
YMM5
real Register
XMM6 = Register
YMM6
real Register
XMM7 = Register
YMM7
real Register
XMM8 = Register
YMM8
real Register
XMM9 = Register
YMM9
real Register
XMM10 = Register
YMM10
real Register
XMM11 = Register
YMM11
real Register
XMM12 = Register
YMM12
real Register
XMM13 = Register
YMM13
real Register
XMM14 = Register
YMM14
real Register
XMM15 = Register
YMM15
real Register
ST0 = Register
ST0
real Register
ST1 = Register
ST1
real Register
ST2 = Register
ST2
real Register
ST3 = Register
ST3
real Register
ST4 = Register
ST4
real Register
ST5 = Register
ST5
real Register
ST6 = Register
ST6
real Register
ST7 = Register
ST7
real Register
AH = Register
RAX
real Register
BH = Register
RBX
real Register
CH = Register
RCX
real Register
DH = Register
RDX
real Register
TEMP = Register
TEMP
real Register
r = if Register
r Register -> [Register] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` ([Register]
reg64 [Register] -> [Register] -> [Register]
forall a. [a] -> [a] -> [a]
++ [Register]
reg256)
         then Register
r
         else String -> Register
forall a. HasCallStack => String -> a
error (String -> Register) -> String -> Register
forall a b. (a -> b) -> a -> b
$ String
"Cannot match register " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Register -> String
forall a. Show a => a -> String
show Register
r String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" to real register"

instance HasSize Register where
  sizeof :: Register -> Int
sizeof Register
r
    | Register
r Register -> [Register] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Register]
reg256 = Int
32
    | Register
r Register -> [Register] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Register]
reg128 = Int
16
    | Register
r Register -> [Register] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Register]
reg80 = Int
10
    | Register
r Register -> [Register] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Register]
reg64 = Int
8
    | Register
r Register -> [Register] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Register]
reg32 = Int
4
    | Register
r Register -> [Register] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Register]
reg16 = Int
2
    | Register
r Register -> [Register] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Register]
reg8 [Register] -> [Register] -> [Register]
forall a. [a] -> [a] -> [a]
++ [Register
AH, Register
BH, Register
CH, Register
DH] = Int
1
    | Register
r Register -> [Register] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Register
TEMP] = Int
8
    | Bool
otherwise = String -> Int
forall a. HasCallStack => String -> a
error (String -> Int) -> String -> Int
forall a b. (a -> b) -> a -> b
$ String
"Size of " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Register -> String
forall a. Show a => a -> String
show Register
r String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" unknown"

-- | Finds for a register all register that overlap with it.
-- | These have the same `real` register (apart from special cases).
-- | For example, RAX is overlapping with EAX, AX, AL, AH
-- | AH is only overlapping with RAX, EAX, AX; but not AL
overlapping :: Register -> [Register]
overlapping :: Register -> [Register]
overlapping Register
r =
  (Register -> Bool) -> [Register] -> [Register]
forall a. (a -> Bool) -> [a] -> [a]
filter ([Register -> Bool] -> Register -> Bool
forall a. [a -> Bool] -> a -> Bool
allp [Register -> Register -> Bool
forall a. Eq a => a -> a -> Bool
(/=) Register
r, Register -> Register -> Bool
haveSameRealReg Register
r, Register -> Register -> Bool
areNotSeparate Register
r]) [Register]
allRegisters

allRegisters :: [Register]
allRegisters :: [Register]
allRegisters = [Register
forall a. Bounded a => a
minBound .. Register
forall a. Bounded a => a
maxBound]

hasRealReg :: Register -> Bool
hasRealReg :: Register -> Bool
hasRealReg = (Register -> [Register] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [Register
InvalidRegister, Register
RIP, Register
EIP, Register
RIZ, Register
EIZ, Register
TEMP])

haveSameRealReg :: Register -> Register -> Bool
haveSameRealReg :: Register -> Register -> Bool
haveSameRealReg Register
r1 Register
r2 = Register -> Bool
hasRealReg Register
r2 Bool -> Bool -> Bool
&& (Register -> Register
real Register
r1 Register -> Register -> Bool
forall a. Eq a => a -> a -> Bool
== Register -> Register
real Register
r2)

-- | True if they are not separate in the sense that they have the same real registers,
-- | but their values don't influence each other.
areNotSeparate :: Register -> Register -> Bool
areNotSeparate :: Register -> Register -> Bool
areNotSeparate Register
AH Register
AL = Bool
False
areNotSeparate Register
AL Register
AH = Bool
False
areNotSeparate Register
BH Register
BL = Bool
False
areNotSeparate Register
BL Register
BH = Bool
False
areNotSeparate Register
CH Register
CL = Bool
False
areNotSeparate Register
CL Register
CH = Bool
False
areNotSeparate Register
DH Register
DL = Bool
False
areNotSeparate Register
DL Register
DH = Bool
False
areNotSeparate Register
_ Register
_ = Bool
True