Revert "Save a word in the info table on x86_64"
[ghc.git] / compiler / cmm / CmmInfo.hs
1 {-# LANGUAGE CPP #-}
2 module CmmInfo (
3 mkEmptyContInfoTable,
4 cmmToRawCmm,
5 mkInfoTable,
6 srtEscape,
7
8 -- info table accessors
9 closureInfoPtr,
10 entryCode,
11 getConstrTag,
12 cmmGetClosureType,
13 infoTable,
14 infoTableConstrTag,
15 infoTableSrtBitmap,
16 infoTableClosureType,
17 infoTablePtrs,
18 infoTableNonPtrs,
19 funInfoTable,
20 funInfoArity,
21
22 -- info table sizes and offsets
23 stdInfoTableSizeW,
24 fixedInfoTableSizeW,
25 profInfoTableSizeW,
26 maxStdInfoTableSizeW,
27 maxRetInfoTableSizeW,
28 stdInfoTableSizeB,
29 conInfoTableSizeB,
30 stdSrtBitmapOffset,
31 stdClosureTypeOffset,
32 stdPtrsOffset, stdNonPtrsOffset,
33 ) where
34
35 #include "HsVersions.h"
36
37 import GhcPrelude
38
39 import Cmm
40 import CmmUtils
41 import CLabel
42 import SMRep
43 import Bitmap
44 import Stream (Stream)
45 import qualified Stream
46 import Hoopl.Collections
47
48 import Maybes
49 import DynFlags
50 import Panic
51 import UniqSupply
52 import MonadUtils
53 import Util
54 import Outputable
55
56 import Data.Bits
57 import Data.Word
58
59 -- When we split at proc points, we need an empty info table.
60 mkEmptyContInfoTable :: CLabel -> CmmInfoTable
61 mkEmptyContInfoTable info_lbl
62 = CmmInfoTable { cit_lbl = info_lbl
63 , cit_rep = mkStackRep []
64 , cit_prof = NoProfilingInfo
65 , cit_srt = Nothing }
66
67 cmmToRawCmm :: DynFlags -> Stream IO CmmGroup ()
68 -> IO (Stream IO RawCmmGroup ())
69 cmmToRawCmm dflags cmms
70 = do { uniqs <- mkSplitUniqSupply 'i'
71 ; let do_one uniqs cmm = do
72 case initUs uniqs $ concatMapM (mkInfoTable dflags) cmm of
73 (b,uniqs') -> return (uniqs',b)
74 -- NB. strictness fixes a space leak. DO NOT REMOVE.
75 ; return (Stream.mapAccumL do_one uniqs cmms >> return ())
76 }
77
78 -- Make a concrete info table, represented as a list of CmmStatic
79 -- (it can't be simply a list of Word, because the SRT field is
80 -- represented by a label+offset expression).
81 --
82 -- With tablesNextToCode, the layout is
83 -- <reversed variable part>
84 -- <normal forward StgInfoTable, but without
85 -- an entry point at the front>
86 -- <code>
87 --
88 -- Without tablesNextToCode, the layout of an info table is
89 -- <entry label>
90 -- <normal forward rest of StgInfoTable>
91 -- <forward variable part>
92 --
93 -- See includes/rts/storage/InfoTables.h
94 --
95 -- For return-points these are as follows
96 --
97 -- Tables next to code:
98 --
99 -- <srt slot>
100 -- <standard info table>
101 -- ret-addr --> <entry code (if any)>
102 --
103 -- Not tables-next-to-code:
104 --
105 -- ret-addr --> <ptr to entry code>
106 -- <standard info table>
107 -- <srt slot>
108 --
109 -- * The SRT slot is only there if there is SRT info to record
110
111 mkInfoTable :: DynFlags -> CmmDecl -> UniqSM [RawCmmDecl]
112 mkInfoTable _ (CmmData sec dat)
113 = return [CmmData sec dat]
114
115 mkInfoTable dflags proc@(CmmProc infos entry_lbl live blocks)
116 --
117 -- in the non-tables-next-to-code case, procs can have at most a
118 -- single info table associated with the entry label of the proc.
119 --
120 | not (tablesNextToCode dflags)
121 = case topInfoTable proc of -- must be at most one
122 -- no info table
123 Nothing ->
124 return [CmmProc mapEmpty entry_lbl live blocks]
125
126 Just info@CmmInfoTable { cit_lbl = info_lbl } -> do
127 (top_decls, (std_info, extra_bits)) <-
128 mkInfoTableContents dflags info Nothing
129 let
130 rel_std_info = map (makeRelativeRefTo dflags info_lbl) std_info
131 rel_extra_bits = map (makeRelativeRefTo dflags info_lbl) extra_bits
132 --
133 -- Separately emit info table (with the function entry
134 -- point as first entry) and the entry code
135 --
136 return (top_decls ++
137 [CmmProc mapEmpty entry_lbl live blocks,
138 mkRODataLits info_lbl
139 (CmmLabel entry_lbl : rel_std_info ++ rel_extra_bits)])
140
141 --
142 -- With tables-next-to-code, we can have many info tables,
143 -- associated with some of the BlockIds of the proc. For each info
144 -- table we need to turn it into CmmStatics, and collect any new
145 -- CmmDecls that arise from doing so.
146 --
147 | otherwise
148 = do
149 (top_declss, raw_infos) <-
150 unzip `fmap` mapM do_one_info (mapToList (info_tbls infos))
151 return (concat top_declss ++
152 [CmmProc (mapFromList raw_infos) entry_lbl live blocks])
153
154 where
155 do_one_info (lbl,itbl) = do
156 (top_decls, (std_info, extra_bits)) <-
157 mkInfoTableContents dflags itbl Nothing
158 let
159 info_lbl = cit_lbl itbl
160 rel_std_info = map (makeRelativeRefTo dflags info_lbl) std_info
161 rel_extra_bits = map (makeRelativeRefTo dflags info_lbl) extra_bits
162 --
163 return (top_decls, (lbl, Statics info_lbl $ map CmmStaticLit $
164 reverse rel_extra_bits ++ rel_std_info))
165
166 -----------------------------------------------------
167 type InfoTableContents = ( [CmmLit] -- The standard part
168 , [CmmLit] ) -- The "extra bits"
169 -- These Lits have *not* had mkRelativeTo applied to them
170
171 mkInfoTableContents :: DynFlags
172 -> CmmInfoTable
173 -> Maybe Int -- Override default RTS type tag?
174 -> UniqSM ([RawCmmDecl], -- Auxiliary top decls
175 InfoTableContents) -- Info tbl + extra bits
176
177 mkInfoTableContents dflags
178 info@(CmmInfoTable { cit_lbl = info_lbl
179 , cit_rep = smrep
180 , cit_prof = prof
181 , cit_srt = srt })
182 mb_rts_tag
183 | RTSRep rts_tag rep <- smrep
184 = mkInfoTableContents dflags info{cit_rep = rep} (Just rts_tag)
185 -- Completely override the rts_tag that mkInfoTableContents would
186 -- otherwise compute, with the rts_tag stored in the RTSRep
187 -- (which in turn came from a handwritten .cmm file)
188
189 | StackRep frame <- smrep
190 = do { (prof_lits, prof_data) <- mkProfLits dflags prof
191 ; let (srt_label, srt_bitmap) = mkSRTLit dflags srt
192 ; (liveness_lit, liveness_data) <- mkLivenessBits dflags frame
193 ; let
194 std_info = mkStdInfoTable dflags prof_lits rts_tag srt_bitmap liveness_lit
195 rts_tag | Just tag <- mb_rts_tag = tag
196 | null liveness_data = rET_SMALL -- Fits in extra_bits
197 | otherwise = rET_BIG -- Does not; extra_bits is
198 -- a label
199 ; return (prof_data ++ liveness_data, (std_info, srt_label)) }
200
201 | HeapRep _ ptrs nonptrs closure_type <- smrep
202 = do { let layout = packIntsCLit dflags ptrs nonptrs
203 ; (prof_lits, prof_data) <- mkProfLits dflags prof
204 ; let (srt_label, srt_bitmap) = mkSRTLit dflags srt
205 ; (mb_srt_field, mb_layout, extra_bits, ct_data)
206 <- mk_pieces closure_type srt_label
207 ; let std_info = mkStdInfoTable dflags prof_lits
208 (mb_rts_tag `orElse` rtsClosureType smrep)
209 (mb_srt_field `orElse` srt_bitmap)
210 (mb_layout `orElse` layout)
211 ; return (prof_data ++ ct_data, (std_info, extra_bits)) }
212 where
213 mk_pieces :: ClosureTypeInfo -> [CmmLit]
214 -> UniqSM ( Maybe StgHalfWord -- Override the SRT field with this
215 , Maybe CmmLit -- Override the layout field with this
216 , [CmmLit] -- "Extra bits" for info table
217 , [RawCmmDecl]) -- Auxiliary data decls
218 mk_pieces (Constr con_tag con_descr) _no_srt -- A data constructor
219 = do { (descr_lit, decl) <- newStringLit con_descr
220 ; return ( Just (toStgHalfWord dflags (fromIntegral con_tag))
221 , Nothing, [descr_lit], [decl]) }
222
223 mk_pieces Thunk srt_label
224 = return (Nothing, Nothing, srt_label, [])
225
226 mk_pieces (ThunkSelector offset) _no_srt
227 = return (Just (toStgHalfWord dflags 0), Just (mkWordCLit dflags (fromIntegral offset)), [], [])
228 -- Layout known (one free var); we use the layout field for offset
229
230 mk_pieces (Fun arity (ArgSpec fun_type)) srt_label
231 = do { let extra_bits = packIntsCLit dflags fun_type arity : srt_label
232 ; return (Nothing, Nothing, extra_bits, []) }
233
234 mk_pieces (Fun arity (ArgGen arg_bits)) srt_label
235 = do { (liveness_lit, liveness_data) <- mkLivenessBits dflags arg_bits
236 ; let fun_type | null liveness_data = aRG_GEN
237 | otherwise = aRG_GEN_BIG
238 extra_bits = [ packIntsCLit dflags fun_type arity
239 , srt_lit, liveness_lit, slow_entry ]
240 ; return (Nothing, Nothing, extra_bits, liveness_data) }
241 where
242 slow_entry = CmmLabel (toSlowEntryLbl info_lbl)
243 srt_lit = case srt_label of
244 [] -> mkIntCLit dflags 0
245 (lit:_rest) -> ASSERT( null _rest ) lit
246
247 mk_pieces other _ = pprPanic "mk_pieces" (ppr other)
248
249 mkInfoTableContents _ _ _ = panic "mkInfoTableContents" -- NonInfoTable dealt with earlier
250
251 packIntsCLit :: DynFlags -> Int -> Int -> CmmLit
252 packIntsCLit dflags a b = packHalfWordsCLit dflags
253 (toStgHalfWord dflags (fromIntegral a))
254 (toStgHalfWord dflags (fromIntegral b))
255
256
257 mkSRTLit :: DynFlags
258 -> Maybe CLabel
259 -> ([CmmLit], -- srt_label, if any
260 StgHalfWord) -- srt_bitmap
261 mkSRTLit dflags Nothing = ([], toStgHalfWord dflags 0)
262 mkSRTLit dflags (Just lbl) = ([CmmLabel lbl], toStgHalfWord dflags 1)
263
264 -------------------------------------------------------------------------
265 --
266 -- Lay out the info table and handle relative offsets
267 --
268 -------------------------------------------------------------------------
269
270 -- This function takes
271 -- * the standard info table portion (StgInfoTable)
272 -- * the "extra bits" (StgFunInfoExtraRev etc.)
273 -- * the entry label
274 -- * the code
275 -- and lays them out in memory, producing a list of RawCmmDecl
276
277 -------------------------------------------------------------------------
278 --
279 -- Position independent code
280 --
281 -------------------------------------------------------------------------
282 -- In order to support position independent code, we mustn't put absolute
283 -- references into read-only space. Info tables in the tablesNextToCode
284 -- case must be in .text, which is read-only, so we doctor the CmmLits
285 -- to use relative offsets instead.
286
287 -- Note that this is done even when the -fPIC flag is not specified,
288 -- as we want to keep binary compatibility between PIC and non-PIC.
289
290 makeRelativeRefTo :: DynFlags -> CLabel -> CmmLit -> CmmLit
291
292 makeRelativeRefTo dflags info_lbl (CmmLabel lbl)
293 | tablesNextToCode dflags
294 = CmmLabelDiffOff lbl info_lbl 0 (wordWidth dflags)
295 makeRelativeRefTo dflags info_lbl (CmmLabelOff lbl off)
296 | tablesNextToCode dflags
297 = CmmLabelDiffOff lbl info_lbl off (wordWidth dflags)
298 makeRelativeRefTo _ _ lit = lit
299
300
301 -------------------------------------------------------------------------
302 --
303 -- Build a liveness mask for the stack layout
304 --
305 -------------------------------------------------------------------------
306
307 -- There are four kinds of things on the stack:
308 --
309 -- - pointer variables (bound in the environment)
310 -- - non-pointer variables (bound in the environment)
311 -- - free slots (recorded in the stack free list)
312 -- - non-pointer data slots (recorded in the stack free list)
313 --
314 -- The first two are represented with a 'Just' of a 'LocalReg'.
315 -- The last two with one or more 'Nothing' constructors.
316 -- Each 'Nothing' represents one used word.
317 --
318 -- The head of the stack layout is the top of the stack and
319 -- the least-significant bit.
320
321 mkLivenessBits :: DynFlags -> Liveness -> UniqSM (CmmLit, [RawCmmDecl])
322 -- ^ Returns:
323 -- 1. The bitmap (literal value or label)
324 -- 2. Large bitmap CmmData if needed
325
326 mkLivenessBits dflags liveness
327 | n_bits > mAX_SMALL_BITMAP_SIZE dflags -- does not fit in one word
328 = do { uniq <- getUniqueM
329 ; let bitmap_lbl = mkBitmapLabel uniq
330 ; return (CmmLabel bitmap_lbl,
331 [mkRODataLits bitmap_lbl lits]) }
332
333 | otherwise -- Fits in one word
334 = return (mkStgWordCLit dflags bitmap_word, [])
335 where
336 n_bits = length liveness
337
338 bitmap :: Bitmap
339 bitmap = mkBitmap dflags liveness
340
341 small_bitmap = case bitmap of
342 [] -> toStgWord dflags 0
343 [b] -> b
344 _ -> panic "mkLiveness"
345 bitmap_word = toStgWord dflags (fromIntegral n_bits)
346 .|. (small_bitmap `shiftL` bITMAP_BITS_SHIFT dflags)
347
348 lits = mkWordCLit dflags (fromIntegral n_bits)
349 : map (mkStgWordCLit dflags) bitmap
350 -- The first word is the size. The structure must match
351 -- StgLargeBitmap in includes/rts/storage/InfoTable.h
352
353 -------------------------------------------------------------------------
354 --
355 -- Generating a standard info table
356 --
357 -------------------------------------------------------------------------
358
359 -- The standard bits of an info table. This part of the info table
360 -- corresponds to the StgInfoTable type defined in
361 -- includes/rts/storage/InfoTables.h.
362 --
363 -- Its shape varies with ticky/profiling/tables next to code etc
364 -- so we can't use constant offsets from Constants
365
366 mkStdInfoTable
367 :: DynFlags
368 -> (CmmLit,CmmLit) -- Closure type descr and closure descr (profiling)
369 -> Int -- Closure RTS tag
370 -> StgHalfWord -- SRT length
371 -> CmmLit -- layout field
372 -> [CmmLit]
373
374 mkStdInfoTable dflags (type_descr, closure_descr) cl_type srt_len layout_lit
375 = -- Parallel revertible-black hole field
376 prof_info
377 -- Ticky info (none at present)
378 -- Debug info (none at present)
379 ++ [layout_lit, type_lit]
380
381 where
382 prof_info
383 | gopt Opt_SccProfilingOn dflags = [type_descr, closure_descr]
384 | otherwise = []
385
386 type_lit = packHalfWordsCLit dflags (toStgHalfWord dflags (fromIntegral cl_type)) srt_len
387
388 -------------------------------------------------------------------------
389 --
390 -- Making string literals
391 --
392 -------------------------------------------------------------------------
393
394 mkProfLits :: DynFlags -> ProfilingInfo -> UniqSM ((CmmLit,CmmLit), [RawCmmDecl])
395 mkProfLits dflags NoProfilingInfo = return ((zeroCLit dflags, zeroCLit dflags), [])
396 mkProfLits _ (ProfilingInfo td cd)
397 = do { (td_lit, td_decl) <- newStringLit td
398 ; (cd_lit, cd_decl) <- newStringLit cd
399 ; return ((td_lit,cd_lit), [td_decl,cd_decl]) }
400
401 newStringLit :: [Word8] -> UniqSM (CmmLit, GenCmmDecl CmmStatics info stmt)
402 newStringLit bytes
403 = do { uniq <- getUniqueM
404 ; return (mkByteStringCLit (mkStringLitLabel uniq) bytes) }
405
406
407 -- Misc utils
408
409 -- | Value of the srt field of an info table when using an StgLargeSRT
410 srtEscape :: DynFlags -> StgHalfWord
411 srtEscape dflags = toStgHalfWord dflags (-1)
412
413 -------------------------------------------------------------------------
414 --
415 -- Accessing fields of an info table
416 --
417 -------------------------------------------------------------------------
418
419 -- | Wrap a 'CmmExpr' in an alignment check when @-falignment-sanitisation@ is
420 -- enabled.
421 wordAligned :: DynFlags -> CmmExpr -> CmmExpr
422 wordAligned dflags e
423 | gopt Opt_AlignmentSanitisation dflags
424 = CmmMachOp (MO_AlignmentCheck (wORD_SIZE dflags) (wordWidth dflags)) [e]
425 | otherwise
426 = e
427
428 closureInfoPtr :: DynFlags -> CmmExpr -> CmmExpr
429 -- Takes a closure pointer and returns the info table pointer
430 closureInfoPtr dflags e =
431 CmmLoad (wordAligned dflags e) (bWord dflags)
432
433 entryCode :: DynFlags -> CmmExpr -> CmmExpr
434 -- Takes an info pointer (the first word of a closure)
435 -- and returns its entry code
436 entryCode dflags e
437 | tablesNextToCode dflags = e
438 | otherwise = CmmLoad e (bWord dflags)
439
440 getConstrTag :: DynFlags -> CmmExpr -> CmmExpr
441 -- Takes a closure pointer, and return the *zero-indexed*
442 -- constructor tag obtained from the info table
443 -- This lives in the SRT field of the info table
444 -- (constructors don't need SRTs).
445 getConstrTag dflags closure_ptr
446 = CmmMachOp (MO_UU_Conv (halfWordWidth dflags) (wordWidth dflags)) [infoTableConstrTag dflags info_table]
447 where
448 info_table = infoTable dflags (closureInfoPtr dflags closure_ptr)
449
450 cmmGetClosureType :: DynFlags -> CmmExpr -> CmmExpr
451 -- Takes a closure pointer, and return the closure type
452 -- obtained from the info table
453 cmmGetClosureType dflags closure_ptr
454 = CmmMachOp (MO_UU_Conv (halfWordWidth dflags) (wordWidth dflags)) [infoTableClosureType dflags info_table]
455 where
456 info_table = infoTable dflags (closureInfoPtr dflags closure_ptr)
457
458 infoTable :: DynFlags -> CmmExpr -> CmmExpr
459 -- Takes an info pointer (the first word of a closure)
460 -- and returns a pointer to the first word of the standard-form
461 -- info table, excluding the entry-code word (if present)
462 infoTable dflags info_ptr
463 | tablesNextToCode dflags = cmmOffsetB dflags info_ptr (- stdInfoTableSizeB dflags)
464 | otherwise = cmmOffsetW dflags info_ptr 1 -- Past the entry code pointer
465
466 infoTableConstrTag :: DynFlags -> CmmExpr -> CmmExpr
467 -- Takes an info table pointer (from infoTable) and returns the constr tag
468 -- field of the info table (same as the srt_bitmap field)
469 infoTableConstrTag = infoTableSrtBitmap
470
471 infoTableSrtBitmap :: DynFlags -> CmmExpr -> CmmExpr
472 -- Takes an info table pointer (from infoTable) and returns the srt_bitmap
473 -- field of the info table
474 infoTableSrtBitmap dflags info_tbl
475 = CmmLoad (cmmOffsetB dflags info_tbl (stdSrtBitmapOffset dflags)) (bHalfWord dflags)
476
477 infoTableClosureType :: DynFlags -> CmmExpr -> CmmExpr
478 -- Takes an info table pointer (from infoTable) and returns the closure type
479 -- field of the info table.
480 infoTableClosureType dflags info_tbl
481 = CmmLoad (cmmOffsetB dflags info_tbl (stdClosureTypeOffset dflags)) (bHalfWord dflags)
482
483 infoTablePtrs :: DynFlags -> CmmExpr -> CmmExpr
484 infoTablePtrs dflags info_tbl
485 = CmmLoad (cmmOffsetB dflags info_tbl (stdPtrsOffset dflags)) (bHalfWord dflags)
486
487 infoTableNonPtrs :: DynFlags -> CmmExpr -> CmmExpr
488 infoTableNonPtrs dflags info_tbl
489 = CmmLoad (cmmOffsetB dflags info_tbl (stdNonPtrsOffset dflags)) (bHalfWord dflags)
490
491 funInfoTable :: DynFlags -> CmmExpr -> CmmExpr
492 -- Takes the info pointer of a function,
493 -- and returns a pointer to the first word of the StgFunInfoExtra struct
494 -- in the info table.
495 funInfoTable dflags info_ptr
496 | tablesNextToCode dflags
497 = cmmOffsetB dflags info_ptr (- stdInfoTableSizeB dflags - sIZEOF_StgFunInfoExtraRev dflags)
498 | otherwise
499 = cmmOffsetW dflags info_ptr (1 + stdInfoTableSizeW dflags)
500 -- Past the entry code pointer
501
502 -- Takes the info pointer of a function, returns the function's arity
503 funInfoArity :: DynFlags -> CmmExpr -> CmmExpr
504 funInfoArity dflags iptr
505 = cmmToWord dflags (cmmLoadIndex dflags rep fun_info (offset `div` rep_bytes))
506 where
507 fun_info = funInfoTable dflags iptr
508 rep = cmmBits (widthFromBytes rep_bytes)
509
510 (rep_bytes, offset)
511 | tablesNextToCode dflags = ( pc_REP_StgFunInfoExtraRev_arity pc
512 , oFFSET_StgFunInfoExtraRev_arity dflags )
513 | otherwise = ( pc_REP_StgFunInfoExtraFwd_arity pc
514 , oFFSET_StgFunInfoExtraFwd_arity dflags )
515
516 pc = sPlatformConstants (settings dflags)
517
518 -----------------------------------------------------------------------------
519 --
520 -- Info table sizes & offsets
521 --
522 -----------------------------------------------------------------------------
523
524 stdInfoTableSizeW :: DynFlags -> WordOff
525 -- The size of a standard info table varies with profiling/ticky etc,
526 -- so we can't get it from Constants
527 -- It must vary in sync with mkStdInfoTable
528 stdInfoTableSizeW dflags
529 = fixedInfoTableSizeW
530 + if gopt Opt_SccProfilingOn dflags
531 then profInfoTableSizeW
532 else 0
533
534 fixedInfoTableSizeW :: WordOff
535 fixedInfoTableSizeW = 2 -- layout, type
536
537 profInfoTableSizeW :: WordOff
538 profInfoTableSizeW = 2
539
540 maxStdInfoTableSizeW :: WordOff
541 maxStdInfoTableSizeW =
542 1 {- entry, when !tablesNextToCode -}
543 + fixedInfoTableSizeW
544 + profInfoTableSizeW
545
546 maxRetInfoTableSizeW :: WordOff
547 maxRetInfoTableSizeW =
548 maxStdInfoTableSizeW
549 + 1 {- srt label -}
550
551 stdInfoTableSizeB :: DynFlags -> ByteOff
552 stdInfoTableSizeB dflags = stdInfoTableSizeW dflags * wORD_SIZE dflags
553
554 stdSrtBitmapOffset :: DynFlags -> ByteOff
555 -- Byte offset of the SRT bitmap half-word which is
556 -- in the *higher-addressed* part of the type_lit
557 stdSrtBitmapOffset dflags = stdInfoTableSizeB dflags - hALF_WORD_SIZE dflags
558
559 stdClosureTypeOffset :: DynFlags -> ByteOff
560 -- Byte offset of the closure type half-word
561 stdClosureTypeOffset dflags = stdInfoTableSizeB dflags - wORD_SIZE dflags
562
563 stdPtrsOffset, stdNonPtrsOffset :: DynFlags -> ByteOff
564 stdPtrsOffset dflags = stdInfoTableSizeB dflags - 2 * wORD_SIZE dflags
565 stdNonPtrsOffset dflags = stdInfoTableSizeB dflags - 2 * wORD_SIZE dflags + hALF_WORD_SIZE dflags
566
567 conInfoTableSizeB :: DynFlags -> Int
568 conInfoTableSizeB dflags = stdInfoTableSizeB dflags + wORD_SIZE dflags