%
% (c) The University of Glasgow 2006
% (c) The GRASP/AQUA Project, Glasgow University, 1998
%
\section[Literal]{@Literal@: Machine literals (unboxed, of course)}
\begin{code}
module Literal
(
Literal(..)
, mkMachInt, mkMachWord
, mkMachInt64, mkMachWord64
, mkMachFloat, mkMachDouble
, mkMachChar, mkMachString
, literalType
, hashLiteral
, litIsDupable, litIsTrivial
, inIntRange, inWordRange, tARGET_MAX_INT, inCharRange
, isZeroLit
, litFitsInChar
, word2IntLit, int2WordLit
, narrow8IntLit, narrow16IntLit, narrow32IntLit
, narrow8WordLit, narrow16WordLit, narrow32WordLit
, char2IntLit, int2CharLit
, float2IntLit, int2FloatLit, double2IntLit, int2DoubleLit
, nullAddrLit, float2DoubleLit, double2FloatLit
) where
import TysPrim
import Type
import Outputable
import FastTypes
import FastString
import BasicTypes
import Binary
import Constants
import Data.Int
import Data.Ratio
import Data.Word
import Data.Char
\end{code}
%************************************************************************
%* *
\subsection{Literals}
%* *
%************************************************************************
\begin{code}
data Literal
=
MachChar Char
| MachStr FastString
| MachNullAddr
| MachInt Integer
| MachInt64 Integer
| MachWord Integer
| MachWord64 Integer
| MachFloat Rational
| MachDouble Rational
| MachLabel FastString
(Maybe Int)
FunctionOrData
\end{code}
Binary instance
\begin{code}
instance Binary Literal where
put_ bh (MachChar aa) = do putByte bh 0; put_ bh aa
put_ bh (MachStr ab) = do putByte bh 1; put_ bh ab
put_ bh (MachNullAddr) = do putByte bh 2
put_ bh (MachInt ad) = do putByte bh 3; put_ bh ad
put_ bh (MachInt64 ae) = do putByte bh 4; put_ bh ae
put_ bh (MachWord af) = do putByte bh 5; put_ bh af
put_ bh (MachWord64 ag) = do putByte bh 6; put_ bh ag
put_ bh (MachFloat ah) = do putByte bh 7; put_ bh ah
put_ bh (MachDouble ai) = do putByte bh 8; put_ bh ai
put_ bh (MachLabel aj mb fod)
= do putByte bh 9
put_ bh aj
put_ bh mb
put_ bh fod
get bh = do
h <- getByte bh
case h of
0 -> do
aa <- get bh
return (MachChar aa)
1 -> do
ab <- get bh
return (MachStr ab)
2 -> do
return (MachNullAddr)
3 -> do
ad <- get bh
return (MachInt ad)
4 -> do
ae <- get bh
return (MachInt64 ae)
5 -> do
af <- get bh
return (MachWord af)
6 -> do
ag <- get bh
return (MachWord64 ag)
7 -> do
ah <- get bh
return (MachFloat ah)
8 -> do
ai <- get bh
return (MachDouble ai)
9 -> do
aj <- get bh
mb <- get bh
fod <- get bh
return (MachLabel aj mb fod)
\end{code}
\begin{code}
instance Outputable Literal where
ppr lit = pprLit lit
instance Show Literal where
showsPrec p lit = showsPrecSDoc p (ppr lit)
instance Eq Literal where
a == b = case (a `compare` b) of { EQ -> True; _ -> False }
a /= b = case (a `compare` b) of { EQ -> False; _ -> True }
instance Ord Literal where
a <= b = case (a `compare` b) of { LT -> True; EQ -> True; GT -> False }
a < b = case (a `compare` b) of { LT -> True; EQ -> False; GT -> False }
a >= b = case (a `compare` b) of { LT -> False; EQ -> True; GT -> True }
a > b = case (a `compare` b) of { LT -> False; EQ -> False; GT -> True }
compare a b = cmpLit a b
\end{code}
Construction
~~~~~~~~~~~~
\begin{code}
mkMachInt :: Integer -> Literal
mkMachInt x =
MachInt x
mkMachWord :: Integer -> Literal
mkMachWord x =
MachWord x
mkMachInt64 :: Integer -> Literal
mkMachInt64 x = MachInt64 x
mkMachWord64 :: Integer -> Literal
mkMachWord64 x = MachWord64 x
mkMachFloat :: Rational -> Literal
mkMachFloat = MachFloat
mkMachDouble :: Rational -> Literal
mkMachDouble = MachDouble
mkMachChar :: Char -> Literal
mkMachChar = MachChar
mkMachString :: String -> Literal
mkMachString s = MachStr (mkFastString s)
inIntRange, inWordRange :: Integer -> Bool
inIntRange x = x >= tARGET_MIN_INT && x <= tARGET_MAX_INT
inWordRange x = x >= 0 && x <= tARGET_MAX_WORD
inCharRange :: Char -> Bool
inCharRange c = c >= '\0' && c <= chr tARGET_MAX_CHAR
isZeroLit :: Literal -> Bool
isZeroLit (MachInt 0) = True
isZeroLit (MachInt64 0) = True
isZeroLit (MachWord 0) = True
isZeroLit (MachWord64 0) = True
isZeroLit (MachFloat 0) = True
isZeroLit (MachDouble 0) = True
isZeroLit _ = False
\end{code}
Coercions
~~~~~~~~~
\begin{code}
word2IntLit, int2WordLit,
narrow8IntLit, narrow16IntLit, narrow32IntLit,
narrow8WordLit, narrow16WordLit, narrow32WordLit,
char2IntLit, int2CharLit,
float2IntLit, int2FloatLit, double2IntLit, int2DoubleLit,
float2DoubleLit, double2FloatLit
:: Literal -> Literal
word2IntLit (MachWord w)
| w > tARGET_MAX_INT = MachInt (w tARGET_MAX_WORD 1)
| otherwise = MachInt w
int2WordLit (MachInt i)
| i < 0 = MachWord (1 + tARGET_MAX_WORD + i)
| otherwise = MachWord i
narrow8IntLit (MachInt i) = MachInt (toInteger (fromInteger i :: Int8))
narrow16IntLit (MachInt i) = MachInt (toInteger (fromInteger i :: Int16))
narrow32IntLit (MachInt i) = MachInt (toInteger (fromInteger i :: Int32))
narrow8WordLit (MachWord w) = MachWord (toInteger (fromInteger w :: Word8))
narrow16WordLit (MachWord w) = MachWord (toInteger (fromInteger w :: Word16))
narrow32WordLit (MachWord w) = MachWord (toInteger (fromInteger w :: Word32))
char2IntLit (MachChar c) = MachInt (toInteger (ord c))
int2CharLit (MachInt i) = MachChar (chr (fromInteger i))
float2IntLit (MachFloat f) = MachInt (truncate f)
int2FloatLit (MachInt i) = MachFloat (fromInteger i)
double2IntLit (MachDouble f) = MachInt (truncate f)
int2DoubleLit (MachInt i) = MachDouble (fromInteger i)
float2DoubleLit (MachFloat f) = MachDouble f
double2FloatLit (MachDouble d) = MachFloat d
nullAddrLit :: Literal
nullAddrLit = MachNullAddr
\end{code}
Predicates
~~~~~~~~~~
\begin{code}
litIsTrivial :: Literal -> Bool
litIsTrivial (MachStr _) = False
litIsTrivial _ = True
litIsDupable :: Literal -> Bool
litIsDupable (MachStr _) = False
litIsDupable _ = True
litFitsInChar :: Literal -> Bool
litFitsInChar (MachInt i)
= fromInteger i <= ord minBound
&& fromInteger i >= ord maxBound
litFitsInChar _ = False
\end{code}
Types
~~~~~
\begin{code}
literalType :: Literal -> Type
literalType MachNullAddr = addrPrimTy
literalType (MachChar _) = charPrimTy
literalType (MachStr _) = addrPrimTy
literalType (MachInt _) = intPrimTy
literalType (MachWord _) = wordPrimTy
literalType (MachInt64 _) = int64PrimTy
literalType (MachWord64 _) = word64PrimTy
literalType (MachFloat _) = floatPrimTy
literalType (MachDouble _) = doublePrimTy
literalType (MachLabel _ _ _) = addrPrimTy
\end{code}
Comparison
~~~~~~~~~~
\begin{code}
cmpLit :: Literal -> Literal -> Ordering
cmpLit (MachChar a) (MachChar b) = a `compare` b
cmpLit (MachStr a) (MachStr b) = a `compare` b
cmpLit (MachNullAddr) (MachNullAddr) = EQ
cmpLit (MachInt a) (MachInt b) = a `compare` b
cmpLit (MachWord a) (MachWord b) = a `compare` b
cmpLit (MachInt64 a) (MachInt64 b) = a `compare` b
cmpLit (MachWord64 a) (MachWord64 b) = a `compare` b
cmpLit (MachFloat a) (MachFloat b) = a `compare` b
cmpLit (MachDouble a) (MachDouble b) = a `compare` b
cmpLit (MachLabel a _ _) (MachLabel b _ _) = a `compare` b
cmpLit lit1 lit2 | litTag lit1 <# litTag lit2 = LT
| otherwise = GT
litTag :: Literal -> FastInt
litTag (MachChar _) = _ILIT(1)
litTag (MachStr _) = _ILIT(2)
litTag (MachNullAddr) = _ILIT(3)
litTag (MachInt _) = _ILIT(4)
litTag (MachWord _) = _ILIT(5)
litTag (MachInt64 _) = _ILIT(6)
litTag (MachWord64 _) = _ILIT(7)
litTag (MachFloat _) = _ILIT(8)
litTag (MachDouble _) = _ILIT(9)
litTag (MachLabel _ _ _) = _ILIT(10)
\end{code}
Printing
~~~~~~~~
* MachX (i.e. unboxed) things are printed unadornded (e.g. 3, 'a', "foo")
exceptions: MachFloat gets an initial keyword prefix.
\begin{code}
pprLit :: Literal -> SDoc
pprLit (MachChar ch) = pprHsChar ch
pprLit (MachStr s) = pprHsString s
pprLit (MachInt i) = pprIntVal i
pprLit (MachInt64 i) = ptext (sLit "__int64") <+> integer i
pprLit (MachWord w) = ptext (sLit "__word") <+> integer w
pprLit (MachWord64 w) = ptext (sLit "__word64") <+> integer w
pprLit (MachFloat f) = ptext (sLit "__float") <+> rational f
pprLit (MachDouble d) = rational d
pprLit (MachNullAddr) = ptext (sLit "__NULL")
pprLit (MachLabel l mb fod) = ptext (sLit "__label") <+> b <+> ppr fod
where b = case mb of
Nothing -> pprHsString l
Just x -> doubleQuotes (text (unpackFS l ++ '@':show x))
pprIntVal :: Integer -> SDoc
pprIntVal i | i < 0 = parens (integer i)
| otherwise = integer i
\end{code}
%************************************************************************
%* *
\subsection{Hashing}
%* *
%************************************************************************
Hash values should be zero or a positive integer. No negatives please.
(They mess up the UniqFM for some reason.)
\begin{code}
hashLiteral :: Literal -> Int
hashLiteral (MachChar c) = ord c + 1000
hashLiteral (MachStr s) = hashFS s
hashLiteral (MachNullAddr) = 0
hashLiteral (MachInt i) = hashInteger i
hashLiteral (MachInt64 i) = hashInteger i
hashLiteral (MachWord i) = hashInteger i
hashLiteral (MachWord64 i) = hashInteger i
hashLiteral (MachFloat r) = hashRational r
hashLiteral (MachDouble r) = hashRational r
hashLiteral (MachLabel s _ _) = hashFS s
hashRational :: Rational -> Int
hashRational r = hashInteger (numerator r)
hashInteger :: Integer -> Int
hashInteger i = 1 + abs (fromInteger (i `rem` 10000))
hashFS :: FastString -> Int
hashFS s = iBox (uniqueOfFS s)
\end{code}