{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE DeriveGeneric #-}

module Data.Variable (Variable(..), VariableConversion(..), isSSA, fromRegister) where

import           Data.Maybe (isJust)
import           GHC.Generics (Generic)
import           Base (orElse)
import qualified Data.Serialize as Cereal
import           X86.Register (Register)
import           Generic.HasSize (sizeof)

-- | A mutable or immutable variable
data Variable =
  Variable { Variable -> String
name :: !String       -- ^ Name of the variable
           , Variable -> Maybe Int
index :: !(Maybe Int) -- ^ Index for immutable (SSA) variables, Nothing otherwise
           , Variable -> Int
size :: !Int          -- ^ Size in byte
           }
  deriving (Variable -> Variable -> Bool
(Variable -> Variable -> Bool)
-> (Variable -> Variable -> Bool) -> Eq Variable
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Variable -> Variable -> Bool
$c/= :: Variable -> Variable -> Bool
== :: Variable -> Variable -> Bool
$c== :: Variable -> Variable -> Bool
Eq, Eq Variable
Eq Variable
-> (Variable -> Variable -> Ordering)
-> (Variable -> Variable -> Bool)
-> (Variable -> Variable -> Bool)
-> (Variable -> Variable -> Bool)
-> (Variable -> Variable -> Bool)
-> (Variable -> Variable -> Variable)
-> (Variable -> Variable -> Variable)
-> Ord Variable
Variable -> Variable -> Bool
Variable -> Variable -> Ordering
Variable -> Variable -> Variable
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 :: Variable -> Variable -> Variable
$cmin :: Variable -> Variable -> Variable
max :: Variable -> Variable -> Variable
$cmax :: Variable -> Variable -> Variable
>= :: Variable -> Variable -> Bool
$c>= :: Variable -> Variable -> Bool
> :: Variable -> Variable -> Bool
$c> :: Variable -> Variable -> Bool
<= :: Variable -> Variable -> Bool
$c<= :: Variable -> Variable -> Bool
< :: Variable -> Variable -> Bool
$c< :: Variable -> Variable -> Bool
compare :: Variable -> Variable -> Ordering
$ccompare :: Variable -> Variable -> Ordering
$cp1Ord :: Eq Variable
Ord, (forall x. Variable -> Rep Variable x)
-> (forall x. Rep Variable x -> Variable) -> Generic Variable
forall x. Rep Variable x -> Variable
forall x. Variable -> Rep Variable x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep Variable x -> Variable
$cfrom :: forall x. Variable -> Rep Variable x
Generic)

instance Cereal.Serialize Variable

-- | Copies the value of one variable to another while extracting (or extending) the correct bits
data VariableConversion =
  VariableConversion { VariableConversion -> Variable
source :: !Variable      -- ^ The variable to copy from
                     , VariableConversion -> Variable
destination :: !Variable -- ^ The variable to copy to
                     , VariableConversion -> Bool
isLow :: !Bool           -- ^ Used when we don't want to extract the lowest 8 bits, but rather the highest 8 of the lowest 16 bits
                     }
  deriving (VariableConversion -> VariableConversion -> Bool
(VariableConversion -> VariableConversion -> Bool)
-> (VariableConversion -> VariableConversion -> Bool)
-> Eq VariableConversion
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: VariableConversion -> VariableConversion -> Bool
$c/= :: VariableConversion -> VariableConversion -> Bool
== :: VariableConversion -> VariableConversion -> Bool
$c== :: VariableConversion -> VariableConversion -> Bool
Eq, Eq VariableConversion
Eq VariableConversion
-> (VariableConversion -> VariableConversion -> Ordering)
-> (VariableConversion -> VariableConversion -> Bool)
-> (VariableConversion -> VariableConversion -> Bool)
-> (VariableConversion -> VariableConversion -> Bool)
-> (VariableConversion -> VariableConversion -> Bool)
-> (VariableConversion -> VariableConversion -> VariableConversion)
-> (VariableConversion -> VariableConversion -> VariableConversion)
-> Ord VariableConversion
VariableConversion -> VariableConversion -> Bool
VariableConversion -> VariableConversion -> Ordering
VariableConversion -> VariableConversion -> VariableConversion
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 :: VariableConversion -> VariableConversion -> VariableConversion
$cmin :: VariableConversion -> VariableConversion -> VariableConversion
max :: VariableConversion -> VariableConversion -> VariableConversion
$cmax :: VariableConversion -> VariableConversion -> VariableConversion
>= :: VariableConversion -> VariableConversion -> Bool
$c>= :: VariableConversion -> VariableConversion -> Bool
> :: VariableConversion -> VariableConversion -> Bool
$c> :: VariableConversion -> VariableConversion -> Bool
<= :: VariableConversion -> VariableConversion -> Bool
$c<= :: VariableConversion -> VariableConversion -> Bool
< :: VariableConversion -> VariableConversion -> Bool
$c< :: VariableConversion -> VariableConversion -> Bool
compare :: VariableConversion -> VariableConversion -> Ordering
$ccompare :: VariableConversion -> VariableConversion -> Ordering
$cp1Ord :: Eq VariableConversion
Ord, (forall x. VariableConversion -> Rep VariableConversion x)
-> (forall x. Rep VariableConversion x -> VariableConversion)
-> Generic VariableConversion
forall x. Rep VariableConversion x -> VariableConversion
forall x. VariableConversion -> Rep VariableConversion x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep VariableConversion x -> VariableConversion
$cfrom :: forall x. VariableConversion -> Rep VariableConversion x
Generic)

instance Cereal.Serialize VariableConversion

isSSA :: Variable -> Bool
isSSA :: Variable -> Bool
isSSA Variable { Maybe Int
index :: Maybe Int
index :: Variable -> Maybe Int
index } = Maybe Int -> Bool
forall a. Maybe a -> Bool
isJust Maybe Int
index

fromRegister :: Register -> Variable
fromRegister :: Register -> Variable
fromRegister Register
r = String -> Maybe Int -> Int -> Variable
Variable (Register -> String
forall a. Show a => a -> String
show Register
r) Maybe Int
forall a. Maybe a
Nothing (Register -> Int
forall a. HasSize a => a -> Int
sizeof Register
r)

instance Show Variable where
  show :: Variable -> String
show (Variable String
name Maybe Int
index Int
size) =
    String
"( " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
name String -> ShowS
forall a. [a] -> [a] -> [a]
++ (Int -> String
forall a. Show a => a -> String
show (Int -> String) -> Maybe Int -> Maybe String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe Int
index) Maybe String -> ShowS
forall a. Eq a => Maybe a -> a -> a
`orElse` String
"" String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
": " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
size String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
")"

instance Show VariableConversion where
  show :: VariableConversion -> String
show (VariableConversion Variable
src Variable
dst Bool
isLow) = Variable -> String
forall a. Show a => a -> String
show Variable
dst
    String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" = conv"
    String -> ShowS
forall a. [a] -> [a] -> [a]
++ (if Bool
isLow
        then String
""
        else String
"_high")
    String -> ShowS
forall a. [a] -> [a] -> [a]
++ Variable -> String
forall a. Show a => a -> String
show Variable
src