-- | Formats on this architecture
--      A Format is a combination of width and class
--
--      TODO:   Signed vs unsigned?
--
--      TODO:   This module is currently shared by all architectures because
--              NCGMonad need to know about it to make a VReg. It would be better
--              to have architecture specific formats, and do the overloading
--              properly. eg SPARC doesn't care about FF80.
--
module GHC.CmmToAsm.Format (
    Format(..),
    intFormat,
    floatFormat,
    isIntFormat,
    isFloatFormat,
    cmmTypeFormat,
    formatToWidth,
    formatInBytes
)

where

import GHC.Prelude

import GHC.Cmm
import GHC.Utils.Outputable
import GHC.Utils.Panic

-- It looks very like the old MachRep, but it's now of purely local
-- significance, here in the native code generator.  You can change it
-- without global consequences.
--
-- A major use is as an opcode qualifier; thus the opcode
--      mov.l a b
-- might be encoded
--      MOV II32 a b
-- where the Format field encodes the ".l" part.

-- ToDo: it's not clear to me that we need separate signed-vs-unsigned formats
--        here.  I've removed them from the x86 version, we'll see what happens --SDM

-- ToDo: quite a few occurrences of Format could usefully be replaced by Width

data Format
        = II8
        | II16
        | II32
        | II64
        | FF32
        | FF64
        deriving (Int -> Format -> ShowS
[Format] -> ShowS
Format -> String
(Int -> Format -> ShowS)
-> (Format -> String) -> ([Format] -> ShowS) -> Show Format
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Format -> ShowS
showsPrec :: Int -> Format -> ShowS
$cshow :: Format -> String
show :: Format -> String
$cshowList :: [Format] -> ShowS
showList :: [Format] -> ShowS
Show, Format -> Format -> Bool
(Format -> Format -> Bool)
-> (Format -> Format -> Bool) -> Eq Format
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Format -> Format -> Bool
== :: Format -> Format -> Bool
$c/= :: Format -> Format -> Bool
/= :: Format -> Format -> Bool
Eq)


-- | Get the integer format of this width.
intFormat :: Width -> Format
intFormat :: Width -> Format
intFormat Width
width
 = case Width
width of
        Width
W8      -> Format
II8
        Width
W16     -> Format
II16
        Width
W32     -> Format
II32
        Width
W64     -> Format
II64
        Width
other   -> String -> Format
forall a. String -> a
sorry (String -> Format) -> String -> Format
forall a b. (a -> b) -> a -> b
$ String
"The native code generator cannot " String -> ShowS
forall a. [a] -> [a] -> [a]
++
            String
"produce code for Format.intFormat " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Width -> String
forall a. Show a => a -> String
show Width
other
            String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"\n\tConsider using the llvm backend with -fllvm"


-- | Get the float format of this width.
floatFormat :: Width -> Format
floatFormat :: Width -> Format
floatFormat Width
width
 = case Width
width of
        Width
W32     -> Format
FF32
        Width
W64     -> Format
FF64

        Width
other   -> String -> SDoc -> Format
forall a. HasCallStack => String -> SDoc -> a
pprPanic String
"Format.floatFormat" (Width -> SDoc
forall a. Outputable a => a -> SDoc
ppr Width
other)

-- | Check if a format represent an integer value.
isIntFormat :: Format -> Bool
isIntFormat :: Format -> Bool
isIntFormat = Bool -> Bool
not (Bool -> Bool) -> (Format -> Bool) -> Format -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Format -> Bool
isFloatFormat

-- | Check if a format represents a floating point value.
isFloatFormat :: Format -> Bool
isFloatFormat :: Format -> Bool
isFloatFormat Format
format
 = case Format
format of
        Format
FF32    -> Bool
True
        Format
FF64    -> Bool
True
        Format
_       -> Bool
False


-- | Convert a Cmm type to a Format.
cmmTypeFormat :: CmmType -> Format
cmmTypeFormat :: CmmType -> Format
cmmTypeFormat CmmType
ty
        | CmmType -> Bool
isFloatType CmmType
ty        = Width -> Format
floatFormat (CmmType -> Width
typeWidth CmmType
ty)
        | Bool
otherwise             = Width -> Format
intFormat (CmmType -> Width
typeWidth CmmType
ty)


-- | Get the Width of a Format.
formatToWidth :: Format -> Width
formatToWidth :: Format -> Width
formatToWidth Format
format
 = case Format
format of
        Format
II8             -> Width
W8
        Format
II16            -> Width
W16
        Format
II32            -> Width
W32
        Format
II64            -> Width
W64
        Format
FF32            -> Width
W32
        Format
FF64            -> Width
W64


formatInBytes :: Format -> Int
formatInBytes :: Format -> Int
formatInBytes = Width -> Int
widthInBytes (Width -> Int) -> (Format -> Width) -> Format -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Format -> Width
formatToWidth