summaryrefslogtreecommitdiff
path: root/compiler/nativeGen/Format.hs
blob: a0e4e99f80909f54dae2521395d51fb304f6658a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
-- | Formats on this architecture
--      A Format is a combination of width and class
--
--      TODO:   Signed vs unsigned?
--
--      TODO:   This module is currenly 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 Format (
    Format(..),
    ScalarFormat(..),
    intFormat,
    floatFormat,
    isFloatFormat,
    isVecFormat,
    cmmTypeFormat,
    formatToWidth,
    formatInBytes
)

where

import GhcPrelude

import Cmm
import Outputable


-- Note [GHC's data format representations]
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--
-- GHC has severals types that represent various aspects of data format.
-- These include:
--
--  * 'CmmType.CmmType': The data classification used throughout the C--
--    pipeline. This is a pair of a CmmCat and a Width.
--
--  * 'CmmType.CmmCat': What the bits in a C-- value mean (e.g. a pointer, integer, or floating-point value)
--
--  * 'CmmType.Width': The width of a C-- value.
--
--  * 'CmmType.Length': The width (measured in number of scalars) of a vector value.
--
--  * 'Format.Format': The data format representation used by much of the backend.
--
--  * 'Format.ScalarFormat': The format of a 'Format.VecFormat'\'s scalar.
--
--  * 'RegClass.RegClass': Whether a register is an integer, float-point, or vector register
--

-- 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
        | VecFormat !Length !ScalarFormat !Width
        deriving (Show, Eq)

data ScalarFormat = FmtInt8
                  | FmtInt16
                  | FmtInt32
                  | FmtInt64
                  | FmtFloat
                  | FmtDouble
                  deriving (Show, Eq)

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


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

        other   -> pprPanic "Format.floatFormat" (ppr other)


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

-- | Check if a format represents a vector
isVecFormat :: Format -> Bool
isVecFormat (VecFormat {}) = True
isVecFormat _              = False

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

vecFormat :: CmmType -> Format
vecFormat ty =
  let l      = vecLength ty
      elemTy = vecElemType ty
   in if isFloatType elemTy
      then case typeWidth elemTy of
             W32 -> VecFormat l FmtFloat  W32
             W64 -> VecFormat l FmtDouble W64
             _   -> pprPanic "Incorrect vector element width" (ppr elemTy)
      else case typeWidth elemTy of
             W8  -> VecFormat l FmtInt8  W8
             W16 -> VecFormat l FmtInt16 W16
             W32 -> VecFormat l FmtInt32 W32
             W64 -> VecFormat l FmtInt64 W64
             _   -> pprPanic "Incorrect vector element width" (ppr elemTy)

-- | Get the Width of a Format.
formatToWidth :: Format -> Width
formatToWidth format
 = case format of
        II8             -> W8
        II16            -> W16
        II32            -> W32
        II64            -> W64
        FF32            -> W32
        FF64            -> W64
        VecFormat l _ w -> widthFromBytes (l*widthInBytes w)

formatInBytes :: Format -> Int
formatInBytes = widthInBytes . formatToWidth