1 -----------------------------------------------------------------------------
3 -- Building info tables.
5 -- (c) The University of Glasgow 2004-2006
7 -----------------------------------------------------------------------------
10 emitClosureCodeAndInfoTable,
13 emitReturnTarget, emitAlgReturnTarget,
16 entryCode, closureInfoPtr,
18 infoTable, infoTableClosureType,
19 infoTablePtrs, infoTableNonPtrs,
20 funInfoTable, makeRelativeRefTo
24 #include "HsVersions.h"
49 -------------------------------------------------------------------------
51 -- Generating the info table and code for a closure
53 -------------------------------------------------------------------------
55 -- Here we make an info table of type 'CmmInfo'. The concrete
56 -- representation as a list of 'CmmAddr' is handled later
57 -- in the pipeline by 'cmmToRawCmm'.
59 emitClosureCodeAndInfoTable :: ClosureInfo -> CmmFormals -> CgStmts -> Code
60 emitClosureCodeAndInfoTable cl_info args body
61 = do { blks <- cgStmtsToBlocks body
62 ; info <- mkCmmInfo cl_info
63 ; emitInfoTableAndCode info_lbl info args blks }
65 info_lbl = infoTableLabelFromCI cl_info
67 -- We keep the *zero-indexed* tag in the srt_len field of the info
68 -- table of a data constructor.
69 dataConTagZ :: DataCon -> ConTagZ
70 dataConTagZ con = dataConTag con - fIRST_TAG
72 -- Convert from 'ClosureInfo' to 'CmmInfo'.
73 -- Not used for return points. (The 'smRepClosureTypeInt' call would panic.)
74 mkCmmInfo :: ClosureInfo -> FCode CmmInfo
75 mkCmmInfo cl_info = do
78 then do ty_descr_lit <- mkStringCLit (closureTypeDescr cl_info)
79 cl_descr_lit <- mkStringCLit (closureValDescr cl_info)
80 return $ ProfilingInfo
81 (makeRelativeRefTo info_lbl ty_descr_lit)
82 (makeRelativeRefTo info_lbl cl_descr_lit)
83 else return $ ProfilingInfo (mkIntCLit 0) (mkIntCLit 0)
86 ConInfo { closureCon = con } -> do
87 cstr <- mkByteStringCLit $ dataConIdentity con
88 let conName = makeRelativeRefTo info_lbl cstr
89 info = ConstrInfo (ptrs, nptrs)
90 (fromIntegral (dataConTagZ con))
92 return $ CmmInfo prof gc_target cl_type info
94 ClosureInfo { closureName = name,
95 closureLFInfo = lf_info,
97 return $ CmmInfo prof gc_target cl_type info
101 LFReEntrant _ arity _ arg_descr ->
102 FunInfo (ptrs, nptrs)
104 (argDescrType arg_descr)
107 (CmmLabel (mkSlowEntryLabel name))
108 LFThunk _ _ _ (SelectorThunk offset) _ ->
109 ThunkSelectorInfo (fromIntegral offset) srt
111 ThunkInfo (ptrs, nptrs) srt
112 _ -> panic "unexpected lambda form in mkCmmInfo"
114 info_lbl = infoTableLabelFromCI cl_info
116 cl_type = smRepClosureTypeInt (closureSMRep cl_info)
118 ptrs = fromIntegral $ closurePtrsSize cl_info
119 size = fromIntegral $ closureNonHdrSize cl_info
122 -- The gc_target is to inform the CPS pass when it inserts a stack check.
123 -- Since that pass isn't used yet we'll punt for now.
124 -- When the CPS pass is fully integrated, this should
125 -- be replaced by the label that any heap check jumped to,
126 -- so that branch can be shared by both the heap (from codeGen)
127 -- and stack checks (from the CPS pass).
128 gc_target = panic "TODO: gc_target"
130 -------------------------------------------------------------------------
132 -- Generating the info table and code for a return point
134 -------------------------------------------------------------------------
136 -- The concrete representation as a list of 'CmmAddr' is handled later
137 -- in the pipeline by 'cmmToRawCmm'.
141 -> CgStmts -- The direct-return code (if any)
143 emitReturnTarget name stmts
144 = do { srt_info <- getSRTInfo
145 ; blks <- cgStmtsToBlocks stmts
146 ; frame <- mkStackLayout
148 (ProfilingInfo zeroCLit zeroCLit)
150 rET_SMALL -- cmmToRawCmm may convert it to rET_BIG
151 (ContInfo frame srt_info)
152 ; emitInfoTableAndCode info_lbl info args blks
155 args = {- trace "emitReturnTarget: missing args" -} []
156 uniq = getUnique name
157 info_lbl = mkReturnInfoLabel uniq
159 -- The gc_target is to inform the CPS pass when it inserts a stack check.
160 -- Since that pass isn't used yet we'll punt for now.
161 -- When the CPS pass is fully integrated, this should
162 -- be replaced by the label that any heap check jumped to,
163 -- so that branch can be shared by both the heap (from codeGen)
164 -- and stack checks (from the CPS pass).
165 gc_target = panic "TODO: gc_target"
168 -- Build stack layout information from the state of the 'FCode' monad.
169 -- Should go away once 'codeGen' starts using the CPS conversion
170 -- pass to handle the stack. Until then, this is really just
171 -- here to convert from the 'codeGen' representation of the stack
172 -- to the 'CmmInfo' representation of the stack.
174 -- See 'CmmInfo.mkLiveness' for where this is converted to a bitmap.
177 This seems to be a very error prone part of the code.
178 It is surprisingly prone to off-by-one errors, because
179 it converts between offset form (codeGen) and list form (CmmInfo).
180 Thus a bit of explanation is in order.
181 Fortunately, this code should go away once the code generator
182 starts using the CPS conversion pass to handle the stack.
184 The stack looks like this:
188 frame_sp --> | return addr |
196 real_sp --> | return addr |
199 Both 'frame_sp' and 'real_sp' are measured downwards
200 (i.e. larger frame_sp means smaller memory address).
202 For that frame we want a result like: [Just a, Just b, Nothing]
203 Note that the 'head' of the list is the top
204 of the stack, and that the return address
205 is not present in the list (it is always assumed).
207 mkStackLayout :: FCode [Maybe LocalReg]
209 StackUsage { realSp = real_sp,
210 frameSp = frame_sp } <- getStkUsage
211 binds <- getLiveStackBindings
212 let frame_size = real_sp - frame_sp - retAddrSizeW
213 rel_binds = reverse $ sortWith fst
214 [(offset - frame_sp - retAddrSizeW, b)
215 | (offset, b) <- binds]
217 WARN( not (all (\bind -> fst bind >= 0) rel_binds),
218 ppr binds $$ ppr rel_binds $$
219 ppr frame_size $$ ppr real_sp $$ ppr frame_sp )
220 return $ stack_layout rel_binds frame_size
222 stack_layout :: [(VirtualSpOffset, CgIdInfo)]
225 stack_layout [] sizeW = replicate sizeW Nothing
226 stack_layout ((off, bind):binds) sizeW | off == sizeW - 1 =
227 (Just stack_bind) : (stack_layout binds (sizeW - rep_size))
229 rep_size = cgRepSizeW (cgIdInfoArgRep bind)
230 stack_bind = LocalReg unique machRep kind
231 unique = getUnique (cgIdInfoId bind)
232 machRep = argMachRep (cgIdInfoArgRep bind)
233 kind = if isFollowableArg (cgIdInfoArgRep bind)
236 stack_layout binds@((off, _):_) sizeW | otherwise =
237 Nothing : (stack_layout binds (sizeW - 1))
239 {- Another way to write the function that might be less error prone (untested)
240 stack_layout offsets sizeW = result
242 y = map (flip lookup offsets) [0..]
243 -- offsets -> nothing and just (each slot is one word)
244 x = take sizeW y -- set the frame size
245 z = clip x -- account for multi-word slots
246 result = map mk_reg z
249 clip list@(x : _) = x : clip (drop count list)
250 ASSERT(all isNothing (tail (take count list)))
253 count (Just x) = cgRepSizeW (cgIdInfoArgRep x)
255 mk_reg Nothing = Nothing
256 mk_reg (Just x) = LocalReg unique machRep kind
258 unique = getUnique (cgIdInfoId x)
259 machRep = argMachrep (cgIdInfoArgRep bind)
260 kind = if isFollowableArg (cgIdInfoArgRep bind)
266 :: Name -- Just for its unique
267 -> [(ConTagZ, CgStmts)] -- Tagged branches
268 -> Maybe CgStmts -- Default branch (if any)
269 -> Int -- family size
270 -> FCode (CLabel, SemiTaggingStuff)
272 emitAlgReturnTarget name branches mb_deflt fam_sz
273 = do { blks <- getCgStmts $
274 emitSwitch tag_expr branches mb_deflt 0 (fam_sz - 1)
275 -- NB: tag_expr is zero-based
276 ; lbl <- emitReturnTarget name blks
277 ; return (lbl, Nothing) }
278 -- Nothing: the internal branches in the switch don't have
279 -- global labels, so we can't use them at the 'call site'
281 tag_expr = getConstrTag (CmmReg nodeReg)
283 --------------------------------
284 emitReturnInstr :: Code
286 = do { info_amode <- getSequelAmode
287 ; stmtC (CmmJump (entryCode info_amode) []) }
289 -----------------------------------------------------------------------------
291 -- Info table offsets
293 -----------------------------------------------------------------------------
295 stdInfoTableSizeW :: WordOff
296 -- The size of a standard info table varies with profiling/ticky etc,
297 -- so we can't get it from Constants
298 -- It must vary in sync with mkStdInfoTable
300 = size_fixed + size_prof
302 size_fixed = 2 -- layout, type
303 size_prof | opt_SccProfilingOn = 2
306 stdInfoTableSizeB = stdInfoTableSizeW * wORD_SIZE :: ByteOff
308 stdSrtBitmapOffset :: ByteOff
309 -- Byte offset of the SRT bitmap half-word which is
310 -- in the *higher-addressed* part of the type_lit
311 stdSrtBitmapOffset = stdInfoTableSizeB - hALF_WORD_SIZE
313 stdClosureTypeOffset :: ByteOff
314 -- Byte offset of the closure type half-word
315 stdClosureTypeOffset = stdInfoTableSizeB - wORD_SIZE
317 stdPtrsOffset, stdNonPtrsOffset :: ByteOff
318 stdPtrsOffset = stdInfoTableSizeB - 2*wORD_SIZE
319 stdNonPtrsOffset = stdInfoTableSizeB - 2*wORD_SIZE + hALF_WORD_SIZE
321 -------------------------------------------------------------------------
323 -- Accessing fields of an info table
325 -------------------------------------------------------------------------
327 closureInfoPtr :: CmmExpr -> CmmExpr
328 -- Takes a closure pointer and returns the info table pointer
329 closureInfoPtr e = CmmLoad e wordRep
331 entryCode :: CmmExpr -> CmmExpr
332 -- Takes an info pointer (the first word of a closure)
333 -- and returns its entry code
334 entryCode e | tablesNextToCode = e
335 | otherwise = CmmLoad e wordRep
337 getConstrTag :: CmmExpr -> CmmExpr
338 -- Takes a closure pointer, and return the *zero-indexed*
339 -- constructor tag obtained from the info table
340 -- This lives in the SRT field of the info table
341 -- (constructors don't need SRTs).
342 getConstrTag closure_ptr
343 = CmmMachOp (MO_U_Conv halfWordRep wordRep) [infoTableConstrTag info_table]
345 info_table = infoTable (closureInfoPtr closure_ptr)
347 infoTable :: CmmExpr -> CmmExpr
348 -- Takes an info pointer (the first word of a closure)
349 -- and returns a pointer to the first word of the standard-form
350 -- info table, excluding the entry-code word (if present)
352 | tablesNextToCode = cmmOffsetB info_ptr (- stdInfoTableSizeB)
353 | otherwise = cmmOffsetW info_ptr 1 -- Past the entry code pointer
355 infoTableConstrTag :: CmmExpr -> CmmExpr
356 -- Takes an info table pointer (from infoTable) and returns the constr tag
357 -- field of the info table (same as the srt_bitmap field)
358 infoTableConstrTag = infoTableSrtBitmap
360 infoTableSrtBitmap :: CmmExpr -> CmmExpr
361 -- Takes an info table pointer (from infoTable) and returns the srt_bitmap
362 -- field of the info table
363 infoTableSrtBitmap info_tbl
364 = CmmLoad (cmmOffsetB info_tbl stdSrtBitmapOffset) halfWordRep
366 infoTableClosureType :: CmmExpr -> CmmExpr
367 -- Takes an info table pointer (from infoTable) and returns the closure type
368 -- field of the info table.
369 infoTableClosureType info_tbl
370 = CmmLoad (cmmOffsetB info_tbl stdClosureTypeOffset) halfWordRep
372 infoTablePtrs :: CmmExpr -> CmmExpr
373 infoTablePtrs info_tbl
374 = CmmLoad (cmmOffsetB info_tbl stdPtrsOffset) halfWordRep
376 infoTableNonPtrs :: CmmExpr -> CmmExpr
377 infoTableNonPtrs info_tbl
378 = CmmLoad (cmmOffsetB info_tbl stdNonPtrsOffset) halfWordRep
380 funInfoTable :: CmmExpr -> CmmExpr
381 -- Takes the info pointer of a function,
382 -- and returns a pointer to the first word of the StgFunInfoExtra struct
383 -- in the info table.
384 funInfoTable info_ptr
386 = cmmOffsetB info_ptr (- stdInfoTableSizeB - sIZEOF_StgFunInfoExtraRev)
388 = cmmOffsetW info_ptr (1 + stdInfoTableSizeW)
389 -- Past the entry code pointer
391 -------------------------------------------------------------------------
393 -- Emit the code for a closure (or return address)
394 -- and its associated info table
396 -------------------------------------------------------------------------
398 -- The complication here concerns whether or not we can
399 -- put the info table next to the code
402 :: CLabel -- Label of info table
403 -> CmmInfo -- ...the info table
404 -> CmmFormals -- ...args
405 -> [CmmBasicBlock] -- ...and body
408 emitInfoTableAndCode info_lbl info args blocks
409 = emitProc info entry_lbl args blocks
411 entry_lbl = infoLblToEntryLbl info_lbl
413 -------------------------------------------------------------------------
415 -- Static reference tables
417 -------------------------------------------------------------------------
419 srtLabelAndLength :: C_SRT -> CLabel -> (CmmLit, StgHalfWord)
420 srtLabelAndLength NoC_SRT _
422 srtLabelAndLength (C_SRT lbl off bitmap) info_lbl
423 = (makeRelativeRefTo info_lbl $ cmmLabelOffW lbl off, bitmap)
425 -------------------------------------------------------------------------
427 -- Position independent code
429 -------------------------------------------------------------------------
430 -- In order to support position independent code, we mustn't put absolute
431 -- references into read-only space. Info tables in the tablesNextToCode
432 -- case must be in .text, which is read-only, so we doctor the CmmLits
433 -- to use relative offsets instead.
435 -- Note that this is done even when the -fPIC flag is not specified,
436 -- as we want to keep binary compatibility between PIC and non-PIC.
438 makeRelativeRefTo :: CLabel -> CmmLit -> CmmLit
440 makeRelativeRefTo info_lbl (CmmLabel lbl)
442 = CmmLabelDiffOff lbl info_lbl 0
443 makeRelativeRefTo info_lbl (CmmLabelOff lbl off)
445 = CmmLabelDiffOff lbl info_lbl off
446 makeRelativeRefTo _ lit = lit