Snapshot of codegen refactoring to share with simonpj
[ghc.git] / compiler / codeGen / SMRep.lhs
1 %
2 % (c) The University of Glasgow 2006
3 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
4 %
5
6 Storage manager representation of closures
7
8 This is here, rather than in ClosureInfo, just to keep nhc happy.
9 Other modules should access this info through ClosureInfo.
10
11 \begin{code}
12 module SMRep (
13         -- Words and bytes
14         StgWord, StgHalfWord, 
15         hALF_WORD_SIZE, hALF_WORD_SIZE_IN_BITS,
16         WordOff, ByteOff,
17
18         -- Argument/return representations
19         CgRep(..), nonVoidArg,
20         argMachRep, primRepToCgRep, 
21 -- Temp primRepHint, typeHint,
22         isFollowableArg, isVoidArg, 
23         isFloatingArg, is64BitArg,
24         separateByPtrFollowness,
25         cgRepSizeW, cgRepSizeB,
26         retAddrSizeW,
27
28         typeCgRep, idCgRep, tyConCgRep, 
29
30         -- Closure repesentation
31         SMRep(..),      -- CmmInfo sees the rep; no one else does
32         IsStatic, 
33         ClosureTypeInfo(..), ArgDescr(..), Liveness,
34         ConstrDescription, 
35         mkHeapRep, blackHoleRep, mkStackRep,
36
37         isStaticRep, isStaticNoCafCon,
38         heapClosureSize,
39         fixedHdrSize, arrWordsHdrSize, arrPtrsHdrSize,
40         profHdrSize, thunkHdrSize, nonHdrSize,
41
42         rtsClosureType, rET_SMALL, rET_BIG,
43         aRG_GEN, aRG_GEN_BIG,
44
45         -- Operations over [Word8] strings
46         pprWord8String, stringToWord8s
47     ) where
48
49 #include "../HsVersions.h"
50 #include "../includes/MachDeps.h"
51
52 import CmmType
53 import Id
54 import Type
55 import TyCon
56 import StaticFlags
57 import Constants
58 import Outputable
59 import FastString
60
61 import Data.Char( ord )
62 import Data.Word
63 \end{code}
64
65
66 %************************************************************************
67 %*                                                                      *
68                 Words and bytes
69 %*                                                                      *
70 %************************************************************************
71
72 \begin{code}
73 type WordOff = Int      -- Word offset, or word count
74 type ByteOff = Int      -- Byte offset, or byte count
75 \end{code}
76
77 StgWord is a type representing an StgWord on the target platform.
78
79 \begin{code}
80 #if SIZEOF_HSWORD == 4
81 type StgWord     = Word32
82 type StgHalfWord = Word16
83 hALF_WORD_SIZE :: ByteOff
84 hALF_WORD_SIZE = 2
85 hALF_WORD_SIZE_IN_BITS :: Int
86 hALF_WORD_SIZE_IN_BITS = 16
87 #elif SIZEOF_HSWORD == 8
88 type StgWord     = Word64
89 type StgHalfWord = Word32
90 hALF_WORD_SIZE :: ByteOff
91 hALF_WORD_SIZE = 4
92 hALF_WORD_SIZE_IN_BITS :: Int
93 hALF_WORD_SIZE_IN_BITS = 32
94 #else
95 #error unknown SIZEOF_HSWORD
96 #endif
97 \end{code}
98
99
100 %************************************************************************
101 %*                                                                      *
102                         CgRep
103 %*                                                                      *
104 %************************************************************************
105
106 An CgRep is an abstraction of a Type which tells the code generator
107 all it needs to know about the calling convention for arguments (and
108 results) of that type.  In particular, the ArgReps of a function's
109 arguments are used to decide which of the RTS's generic apply
110 functions to call when applying an unknown function.
111
112 It contains more information than the back-end data type MachRep,
113 so one can easily convert from CgRep -> MachRep.  (Except that
114 there's no MachRep for a VoidRep.)
115
116 It distinguishes 
117         pointers from non-pointers (we sort the pointers together
118         when building closures)
119
120         void from other types: a void argument is different from no argument
121
122 All 64-bit types map to the same CgRep, because they're passed in the
123 same register, but a PtrArg is still different from an NonPtrArg
124 because the function's entry convention has to take into account the
125 pointer-hood of arguments for the purposes of describing the stack on
126 entry to the garbage collector.
127
128 \begin{code}
129 data CgRep 
130   = VoidArg     -- Void
131   | PtrArg      -- Word-sized heap pointer, followed
132                 -- by the garbage collector
133   | NonPtrArg   -- Word-sized non-pointer
134                 -- (including addresses not followed by GC)
135   | LongArg     -- 64-bit non-pointer
136   | FloatArg    -- 32-bit float
137   | DoubleArg   -- 64-bit float
138   deriving Eq
139
140 instance Outputable CgRep where
141     ppr VoidArg   = ptext (sLit "V_")
142     ppr PtrArg    = ptext (sLit "P_")
143     ppr NonPtrArg = ptext (sLit "I_")
144     ppr LongArg   = ptext (sLit "L_")
145     ppr FloatArg  = ptext (sLit "F_")
146     ppr DoubleArg = ptext (sLit "D_")
147
148 argMachRep :: CgRep -> CmmType
149 argMachRep PtrArg    = gcWord
150 argMachRep NonPtrArg = bWord
151 argMachRep LongArg   = b64
152 argMachRep FloatArg  = f32
153 argMachRep DoubleArg = f64
154 argMachRep VoidArg   = panic "argMachRep:VoidRep"
155
156 primRepToCgRep :: PrimRep -> CgRep
157 primRepToCgRep VoidRep    = VoidArg
158 primRepToCgRep PtrRep     = PtrArg
159 primRepToCgRep IntRep     = NonPtrArg
160 primRepToCgRep WordRep    = NonPtrArg
161 primRepToCgRep Int64Rep   = LongArg
162 primRepToCgRep Word64Rep  = LongArg
163 primRepToCgRep AddrRep    = NonPtrArg
164 primRepToCgRep FloatRep   = FloatArg
165 primRepToCgRep DoubleRep  = DoubleArg
166
167 idCgRep :: Id -> CgRep
168 idCgRep x = typeCgRep . idType $ x
169
170 tyConCgRep :: TyCon -> CgRep
171 tyConCgRep = primRepToCgRep . tyConPrimRep
172
173 typeCgRep :: Type -> CgRep
174 typeCgRep = primRepToCgRep . typePrimRep 
175 \end{code}
176
177 Whether or not the thing is a pointer that the garbage-collector
178 should follow. Or, to put it another (less confusing) way, whether
179 the object in question is a heap object. 
180
181 Depending on the outcome, this predicate determines what stack
182 the pointer/object possibly will have to be saved onto, and the
183 computation of GC liveness info.
184
185 \begin{code}
186 isFollowableArg :: CgRep -> Bool  -- True <=> points to a heap object
187 isFollowableArg PtrArg  = True
188 isFollowableArg _       = False
189
190 isVoidArg :: CgRep -> Bool
191 isVoidArg VoidArg = True
192 isVoidArg _       = False
193
194 nonVoidArg :: CgRep -> Bool
195 nonVoidArg VoidArg = False
196 nonVoidArg _       = True
197
198 -- isFloatingArg is used to distinguish @Double@ and @Float@ which
199 -- cause inadvertent numeric conversions if you aren't jolly careful.
200 -- See codeGen/CgCon:cgTopRhsCon.
201
202 isFloatingArg :: CgRep -> Bool
203 isFloatingArg DoubleArg = True
204 isFloatingArg FloatArg  = True
205 isFloatingArg _         = False
206
207 is64BitArg :: CgRep -> Bool
208 is64BitArg LongArg = True
209 is64BitArg _       = False
210 \end{code}
211
212 \begin{code}
213 separateByPtrFollowness :: [(CgRep,a)] -> ([(CgRep,a)], [(CgRep,a)])
214 -- Returns (ptrs, non-ptrs)
215 separateByPtrFollowness things
216   = sep_things things [] []
217     -- accumulating params for follow-able and don't-follow things...
218   where
219     sep_things []              bs us = (reverse bs, reverse us)
220     sep_things ((PtrArg,a):ts) bs us = sep_things ts ((PtrArg,a):bs) us
221     sep_things (t         :ts) bs us = sep_things ts bs              (t:us)
222 \end{code}
223
224 \begin{code}
225 cgRepSizeB :: CgRep -> ByteOff
226 cgRepSizeB DoubleArg = dOUBLE_SIZE
227 cgRepSizeB LongArg   = wORD64_SIZE
228 cgRepSizeB VoidArg   = 0
229 cgRepSizeB _         = wORD_SIZE
230
231 cgRepSizeW :: CgRep -> ByteOff
232 cgRepSizeW DoubleArg = dOUBLE_SIZE `quot` wORD_SIZE
233 cgRepSizeW LongArg   = wORD64_SIZE `quot` wORD_SIZE
234 cgRepSizeW VoidArg   = 0
235 cgRepSizeW _         = 1
236
237 retAddrSizeW :: WordOff
238 retAddrSizeW = 1        -- One word
239 \end{code}
240
241 %************************************************************************
242 %*                                                                      *
243 \subsubsection[SMRep-datatype]{@SMRep@---storage manager representation}
244 %*                                                                      *
245 %************************************************************************
246
247 \begin{code}
248 -- | A description of the layout of a closure.  Corresponds directly
249 -- to the closure types in includes/rts/storage/ClosureTypes.h.
250 data SMRep
251   = HeapRep              -- GC routines consult sizes in info tbl
252         IsStatic
253         !WordOff         --  # ptr words
254         !WordOff         --  # non-ptr words INCLUDING SLOP (see mkHeapRep below)
255         ClosureTypeInfo  -- type-specific info
256
257   | StackRep            -- Stack frame (RET_SMALL or RET_BIG)
258         Liveness
259
260 -- | True <=> This is a static closure.  Affects how we garbage-collect it.
261 -- Static closure have an extra static link field at the end.
262 type IsStatic = Bool
263
264 -- From an SMRep you can get to the closure type defined in
265 -- includes/rts/storage/ClosureTypes.h. Described by the function
266 -- rtsClosureType below.
267
268 data ClosureTypeInfo
269   = Constr        ConstrTag ConstrDescription
270   | Fun           FunArity ArgDescr
271   | Thunk
272   | ThunkSelector SelectorOffset
273   | BlackHole
274
275 type ConstrTag         = StgHalfWord
276 type ConstrDescription = [Word8] -- result of dataConIdentity
277 type FunArity          = StgHalfWord
278 type SelectorOffset    = StgWord
279
280 -------------------------
281 -- We represent liveness bitmaps as a Bitmap (whose internal
282 -- representation really is a bitmap).  These are pinned onto case return
283 -- vectors to indicate the state of the stack for the garbage collector.
284 -- 
285 -- In the compiled program, liveness bitmaps that fit inside a single
286 -- word (StgWord) are stored as a single word, while larger bitmaps are
287 -- stored as a pointer to an array of words. 
288
289 type Liveness = [Bool]   -- One Bool per word; True  <=> non-ptr or dead
290                          --                    False <=> ptr
291
292 -------------------------
293 -- An ArgDescr describes the argument pattern of a function
294
295 data ArgDescr
296   = ArgSpec             -- Fits one of the standard patterns
297         !StgHalfWord    -- RTS type identifier ARG_P, ARG_N, ...
298
299   | ArgGen              -- General case
300         Liveness        -- Details about the arguments
301
302
303 -----------------------------------------------------------------------------
304 -- Construction
305
306 mkHeapRep :: IsStatic -> WordOff -> WordOff -> ClosureTypeInfo -> SMRep
307 mkHeapRep is_static ptr_wds nonptr_wds cl_type_info
308   = HeapRep is_static
309             ptr_wds
310             (nonptr_wds + slop_wds)
311             cl_type_info
312   where
313      slop_wds
314       | is_static = 0
315       | otherwise = max 0 (minClosureSize - (hdr_size + payload_size))
316
317      hdr_size     = closureTypeHdrSize cl_type_info
318      payload_size = ptr_wds + nonptr_wds
319
320
321 mkStackRep :: [Bool] -> SMRep
322 mkStackRep = StackRep
323
324 blackHoleRep :: SMRep
325 blackHoleRep = HeapRep False 0 0 BlackHole
326
327 -----------------------------------------------------------------------------
328 -- Size-related things
329
330 -- | Size of a closure header (StgHeader in includes/rts/storage/Closures.h)
331 fixedHdrSize :: WordOff
332 fixedHdrSize = sTD_HDR_SIZE + profHdrSize
333
334 -- | Size of the profiling part of a closure header
335 -- (StgProfHeader in includes/rts/storage/Closures.h)
336 profHdrSize  :: WordOff
337 profHdrSize  | opt_SccProfilingOn   = pROF_HDR_SIZE
338              | otherwise            = 0
339
340 -- | The garbage collector requires that every closure is at least as big as this.
341 minClosureSize :: WordOff
342 minClosureSize = fixedHdrSize + mIN_PAYLOAD_SIZE
343
344 arrWordsHdrSize   :: ByteOff
345 arrWordsHdrSize   = fixedHdrSize*wORD_SIZE + sIZEOF_StgArrWords_NoHdr
346
347 arrPtrsHdrSize    :: ByteOff
348 arrPtrsHdrSize    = fixedHdrSize*wORD_SIZE + sIZEOF_StgMutArrPtrs_NoHdr
349
350 -- Thunks have an extra header word on SMP, so the update doesn't 
351 -- splat the payload.
352 thunkHdrSize :: WordOff
353 thunkHdrSize = fixedHdrSize + smp_hdr
354         where smp_hdr = sIZEOF_StgSMPThunkHeader `quot` wORD_SIZE
355
356
357 isStaticRep :: SMRep -> IsStatic
358 isStaticRep (HeapRep is_static _ _ _) = is_static
359 isStaticRep (StackRep {})                = False
360
361 nonHdrSize :: SMRep -> WordOff
362 nonHdrSize (HeapRep _ p np _) = p + np
363 nonHdrSize (StackRep bs)      = length bs
364
365 heapClosureSize :: SMRep -> WordOff
366 heapClosureSize (HeapRep _ p np ty) = closureTypeHdrSize ty + p + np
367 heapClosureSize _ = panic "SMRep.heapClosureSize"
368
369 closureTypeHdrSize :: ClosureTypeInfo -> WordOff
370 closureTypeHdrSize ty = case ty of
371                   Thunk{}         -> thunkHdrSize
372                   ThunkSelector{} -> thunkHdrSize
373                   BlackHole{}     -> thunkHdrSize
374                   _               -> fixedHdrSize
375         -- All thunks use thunkHdrSize, even if they are non-updatable.
376         -- this is because we don't have separate closure types for
377         -- updatable vs. non-updatable thunks, so the GC can't tell the
378         -- difference.  If we ever have significant numbers of non-
379         -- updatable thunks, it might be worth fixing this.
380
381 -----------------------------------------------------------------------------
382 -- deriving the RTS closure type from an SMRep
383
384 #include "../includes/rts/storage/ClosureTypes.h"
385 #include "../includes/rts/storage/FunTypes.h"
386 -- Defines CONSTR, CONSTR_1_0 etc
387
388 -- | Derives the RTS closure type from an 'SMRep'
389 rtsClosureType :: SMRep -> StgHalfWord
390 rtsClosureType (HeapRep False 1 0 Constr{}) = CONSTR_1_0
391 rtsClosureType (HeapRep False 0 1 Constr{}) = CONSTR_0_1
392 rtsClosureType (HeapRep False 2 0 Constr{}) = CONSTR_2_0
393 rtsClosureType (HeapRep False 1 1 Constr{}) = CONSTR_1_1
394 rtsClosureType (HeapRep False 0 2 Constr{}) = CONSTR_0_2
395 rtsClosureType (HeapRep False _ _ Constr{}) = CONSTR
396
397 rtsClosureType (HeapRep False 1 0 Fun{}) = FUN_1_0
398 rtsClosureType (HeapRep False 0 1 Fun{}) = FUN_0_1
399 rtsClosureType (HeapRep False 2 0 Fun{}) = FUN_2_0
400 rtsClosureType (HeapRep False 1 1 Fun{}) = FUN_1_1
401 rtsClosureType (HeapRep False 0 2 Fun{}) = FUN_0_2
402 rtsClosureType (HeapRep False _ _ Fun{}) = FUN
403
404 rtsClosureType (HeapRep False 1 0 Thunk{}) = THUNK_1_0
405 rtsClosureType (HeapRep False 0 1 Thunk{}) = THUNK_0_1
406 rtsClosureType (HeapRep False 2 0 Thunk{}) = THUNK_2_0
407 rtsClosureType (HeapRep False 1 1 Thunk{}) = THUNK_1_1
408 rtsClosureType (HeapRep False 0 2 Thunk{}) = THUNK_0_2
409 rtsClosureType (HeapRep False _ _ Thunk{}) = THUNK
410
411 rtsClosureType (HeapRep False _ _ ThunkSelector{}) =  THUNK_SELECTOR
412
413 -- Approximation: we use the CONSTR_NOCAF_STATIC type for static constructors
414 -- that have no pointer words only.
415 rtsClosureType (HeapRep True 0 _ Constr{}) = CONSTR_NOCAF_STATIC  -- See isStaticNoCafCon below
416 rtsClosureType (HeapRep True _ _ Constr{}) = CONSTR_STATIC
417 rtsClosureType (HeapRep True _ _ Fun{})    = FUN_STATIC
418 rtsClosureType (HeapRep True _ _ Thunk{})  = THUNK_STATIC
419
420 rtsClosureType (HeapRep False _ _ BlackHole{}) =  BLACKHOLE
421
422 rtsClosureType _ = panic "rtsClosureType"
423
424 isStaticNoCafCon :: SMRep -> Bool
425 -- This should line up exactly with CONSTR_NOCAF_STATIC above
426 -- See Note [Static NoCaf constructors]
427 isStaticNoCafCon (HeapRep True 0 _ Constr{}) = True
428 isStaticNoCafCon _                           = False
429
430 -- We export these ones
431 rET_SMALL, rET_BIG, aRG_GEN, aRG_GEN_BIG :: StgHalfWord
432 rET_SMALL   = RET_SMALL
433 rET_BIG     = RET_BIG
434 aRG_GEN     = ARG_GEN
435 aRG_GEN_BIG = ARG_GEN_BIG
436 \end{code}
437
438 Note [Static NoCaf constructors]
439 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
440 If we know that a top-level binding 'x' is not Caffy (ie no CAFs are 
441 reachable from 'x'), then a statically allocated constructor (Just x)
442 is also not Caffy, and the garbage collector need not follow its
443 argument fields.  Exploiting this would require two static info tables
444 for Just, for the two cases where the argument was Caffy or non-Caffy.
445
446 Currently we don't do this; instead we treat nullary constructors 
447 as non-Caffy, and the others as potentially Caffy.
448
449
450 %************************************************************************
451 %*                                                                      *
452              Pretty printing of SMRep and friends
453 %*                                                                      *
454 %************************************************************************
455
456 \begin{code}
457 instance Outputable ClosureTypeInfo where
458    ppr = pprTypeInfo
459
460 instance Outputable SMRep where
461    ppr (HeapRep static ps nps tyinfo)
462      = hang (header <+> lbrace) 2 (ppr tyinfo <+> rbrace)
463      where
464        header = ptext (sLit "HeapRep")
465                 <+> if static then ptext (sLit "static") else empty
466                 <+> pp_n "ptrs" ps <+> pp_n "nonptrs" nps
467        pp_n :: String -> Int -> SDoc
468        pp_n _ 0 = empty
469        pp_n s n = int n <+> text s
470
471    ppr (StackRep bs) = ptext (sLit "StackRep") <+> ppr bs
472
473 instance Outputable ArgDescr where
474   ppr (ArgSpec n) = ptext (sLit "ArgSpec") <+> integer (toInteger n)
475   ppr (ArgGen ls) = ptext (sLit "ArgGen") <+> ppr ls
476   
477 pprTypeInfo :: ClosureTypeInfo -> SDoc
478 pprTypeInfo (Constr tag descr)
479   = ptext (sLit "Con") <+> 
480     braces (sep [ ptext (sLit "tag:") <+> integer (toInteger tag)
481                 , ptext (sLit "descr:") <> text (show descr) ])
482
483 pprTypeInfo (Fun arity args)
484   = ptext (sLit "Fun") <+> 
485     braces (sep [ ptext (sLit "arity:") <+> integer (toInteger arity)
486                 , ptext (sLit ("fun_type:")) <+> ppr args ])
487
488 pprTypeInfo (ThunkSelector offset) 
489   = ptext (sLit "ThunkSel") <+> integer (toInteger offset)
490
491 pprTypeInfo Thunk     = ptext (sLit "Thunk")
492 pprTypeInfo BlackHole = ptext (sLit "BlackHole")
493
494
495 stringToWord8s :: String -> [Word8]
496 stringToWord8s s = map (fromIntegral . ord) s
497
498 pprWord8String :: [Word8] -> SDoc
499 -- Debug printing.  Not very clever right now.
500 pprWord8String ws = text (show ws)
501 \end{code}