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 gc_target Nothing (CmmInfoTable prof cl_type info)
94 ClosureInfo { closureName = name,
95 closureLFInfo = lf_info,
97 return $ CmmInfo gc_target Nothing (CmmInfoTable prof 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
151 (ProfilingInfo zeroCLit zeroCLit)
152 rET_SMALL -- cmmToRawCmm may convert it to rET_BIG
153 (ContInfo frame srt_info))
154 ; emitInfoTableAndCode info_lbl info args blks
157 args = {- trace "emitReturnTarget: missing args" -} []
158 uniq = getUnique name
159 info_lbl = mkReturnInfoLabel uniq
161 -- The gc_target is to inform the CPS pass when it inserts a stack check.
162 -- Since that pass isn't used yet we'll punt for now.
163 -- When the CPS pass is fully integrated, this should
164 -- be replaced by the label that any heap check jumped to,
165 -- so that branch can be shared by both the heap (from codeGen)
166 -- and stack checks (from the CPS pass).
167 gc_target = panic "TODO: gc_target"
170 -- Build stack layout information from the state of the 'FCode' monad.
171 -- Should go away once 'codeGen' starts using the CPS conversion
172 -- pass to handle the stack. Until then, this is really just
173 -- here to convert from the 'codeGen' representation of the stack
174 -- to the 'CmmInfo' representation of the stack.
176 -- See 'CmmInfo.mkLiveness' for where this is converted to a bitmap.
179 This seems to be a very error prone part of the code.
180 It is surprisingly prone to off-by-one errors, because
181 it converts between offset form (codeGen) and list form (CmmInfo).
182 Thus a bit of explanation is in order.
183 Fortunately, this code should go away once the code generator
184 starts using the CPS conversion pass to handle the stack.
186 The stack looks like this:
190 frame_sp --> | return addr |
198 real_sp --> | return addr |
201 Both 'frame_sp' and 'real_sp' are measured downwards
202 (i.e. larger frame_sp means smaller memory address).
204 For that frame we want a result like: [Just a, Just b, Nothing]
205 Note that the 'head' of the list is the top
206 of the stack, and that the return address
207 is not present in the list (it is always assumed).
209 mkStackLayout :: FCode [Maybe LocalReg]
211 StackUsage { realSp = real_sp,
212 frameSp = frame_sp } <- getStkUsage
213 binds <- getLiveStackBindings
214 let frame_size = real_sp - frame_sp - retAddrSizeW
215 rel_binds = reverse $ sortWith fst
216 [(offset - frame_sp - retAddrSizeW, b)
217 | (offset, b) <- binds]
219 WARN( not (all (\bind -> fst bind >= 0) rel_binds),
220 ppr binds $$ ppr rel_binds $$
221 ppr frame_size $$ ppr real_sp $$ ppr frame_sp )
222 return $ stack_layout rel_binds frame_size
224 stack_layout :: [(VirtualSpOffset, CgIdInfo)]
227 stack_layout [] sizeW = replicate sizeW Nothing
228 stack_layout ((off, bind):binds) sizeW | off == sizeW - 1 =
229 (Just stack_bind) : (stack_layout binds (sizeW - rep_size))
231 rep_size = cgRepSizeW (cgIdInfoArgRep bind)
232 stack_bind = LocalReg unique machRep kind
233 unique = getUnique (cgIdInfoId bind)
234 machRep = argMachRep (cgIdInfoArgRep bind)
235 kind = if isFollowableArg (cgIdInfoArgRep bind)
238 stack_layout binds@((off, _):_) sizeW | otherwise =
239 Nothing : (stack_layout binds (sizeW - 1))
241 {- Another way to write the function that might be less error prone (untested)
242 stack_layout offsets sizeW = result
244 y = map (flip lookup offsets) [0..]
245 -- offsets -> nothing and just (each slot is one word)
246 x = take sizeW y -- set the frame size
247 z = clip x -- account for multi-word slots
248 result = map mk_reg z
251 clip list@(x : _) = x : clip (drop count list)
252 ASSERT(all isNothing (tail (take count list)))
255 count (Just x) = cgRepSizeW (cgIdInfoArgRep x)
257 mk_reg Nothing = Nothing
258 mk_reg (Just x) = LocalReg unique machRep kind
260 unique = getUnique (cgIdInfoId x)
261 machRep = argMachrep (cgIdInfoArgRep bind)
262 kind = if isFollowableArg (cgIdInfoArgRep bind)
268 :: Name -- Just for its unique
269 -> [(ConTagZ, CgStmts)] -- Tagged branches
270 -> Maybe CgStmts -- Default branch (if any)
271 -> Int -- family size
272 -> FCode (CLabel, SemiTaggingStuff)
274 emitAlgReturnTarget name branches mb_deflt fam_sz
275 = do { blks <- getCgStmts $
276 emitSwitch tag_expr branches mb_deflt 0 (fam_sz - 1)
277 -- NB: tag_expr is zero-based
278 ; lbl <- emitReturnTarget name blks
279 ; return (lbl, Nothing) }
280 -- Nothing: the internal branches in the switch don't have
281 -- global labels, so we can't use them at the 'call site'
283 tag_expr = getConstrTag (CmmReg nodeReg)
285 --------------------------------
286 emitReturnInstr :: Code
288 = do { info_amode <- getSequelAmode
289 ; stmtC (CmmJump (entryCode info_amode) []) }
291 -----------------------------------------------------------------------------
293 -- Info table offsets
295 -----------------------------------------------------------------------------
297 stdInfoTableSizeW :: WordOff
298 -- The size of a standard info table varies with profiling/ticky etc,
299 -- so we can't get it from Constants
300 -- It must vary in sync with mkStdInfoTable
302 = size_fixed + size_prof
304 size_fixed = 2 -- layout, type
305 size_prof | opt_SccProfilingOn = 2
308 stdInfoTableSizeB = stdInfoTableSizeW * wORD_SIZE :: ByteOff
310 stdSrtBitmapOffset :: ByteOff
311 -- Byte offset of the SRT bitmap half-word which is
312 -- in the *higher-addressed* part of the type_lit
313 stdSrtBitmapOffset = stdInfoTableSizeB - hALF_WORD_SIZE
315 stdClosureTypeOffset :: ByteOff
316 -- Byte offset of the closure type half-word
317 stdClosureTypeOffset = stdInfoTableSizeB - wORD_SIZE
319 stdPtrsOffset, stdNonPtrsOffset :: ByteOff
320 stdPtrsOffset = stdInfoTableSizeB - 2*wORD_SIZE
321 stdNonPtrsOffset = stdInfoTableSizeB - 2*wORD_SIZE + hALF_WORD_SIZE
323 -------------------------------------------------------------------------
325 -- Accessing fields of an info table
327 -------------------------------------------------------------------------
329 closureInfoPtr :: CmmExpr -> CmmExpr
330 -- Takes a closure pointer and returns the info table pointer
331 closureInfoPtr e = CmmLoad e wordRep
333 entryCode :: CmmExpr -> CmmExpr
334 -- Takes an info pointer (the first word of a closure)
335 -- and returns its entry code
336 entryCode e | tablesNextToCode = e
337 | otherwise = CmmLoad e wordRep
339 getConstrTag :: CmmExpr -> CmmExpr
340 -- Takes a closure pointer, and return the *zero-indexed*
341 -- constructor tag obtained from the info table
342 -- This lives in the SRT field of the info table
343 -- (constructors don't need SRTs).
344 getConstrTag closure_ptr
345 = CmmMachOp (MO_U_Conv halfWordRep wordRep) [infoTableConstrTag info_table]
347 info_table = infoTable (closureInfoPtr closure_ptr)
349 infoTable :: CmmExpr -> CmmExpr
350 -- Takes an info pointer (the first word of a closure)
351 -- and returns a pointer to the first word of the standard-form
352 -- info table, excluding the entry-code word (if present)
354 | tablesNextToCode = cmmOffsetB info_ptr (- stdInfoTableSizeB)
355 | otherwise = cmmOffsetW info_ptr 1 -- Past the entry code pointer
357 infoTableConstrTag :: CmmExpr -> CmmExpr
358 -- Takes an info table pointer (from infoTable) and returns the constr tag
359 -- field of the info table (same as the srt_bitmap field)
360 infoTableConstrTag = infoTableSrtBitmap
362 infoTableSrtBitmap :: CmmExpr -> CmmExpr
363 -- Takes an info table pointer (from infoTable) and returns the srt_bitmap
364 -- field of the info table
365 infoTableSrtBitmap info_tbl
366 = CmmLoad (cmmOffsetB info_tbl stdSrtBitmapOffset) halfWordRep
368 infoTableClosureType :: CmmExpr -> CmmExpr
369 -- Takes an info table pointer (from infoTable) and returns the closure type
370 -- field of the info table.
371 infoTableClosureType info_tbl
372 = CmmLoad (cmmOffsetB info_tbl stdClosureTypeOffset) halfWordRep
374 infoTablePtrs :: CmmExpr -> CmmExpr
375 infoTablePtrs info_tbl
376 = CmmLoad (cmmOffsetB info_tbl stdPtrsOffset) halfWordRep
378 infoTableNonPtrs :: CmmExpr -> CmmExpr
379 infoTableNonPtrs info_tbl
380 = CmmLoad (cmmOffsetB info_tbl stdNonPtrsOffset) halfWordRep
382 funInfoTable :: CmmExpr -> CmmExpr
383 -- Takes the info pointer of a function,
384 -- and returns a pointer to the first word of the StgFunInfoExtra struct
385 -- in the info table.
386 funInfoTable info_ptr
388 = cmmOffsetB info_ptr (- stdInfoTableSizeB - sIZEOF_StgFunInfoExtraRev)
390 = cmmOffsetW info_ptr (1 + stdInfoTableSizeW)
391 -- Past the entry code pointer
393 -------------------------------------------------------------------------
395 -- Emit the code for a closure (or return address)
396 -- and its associated info table
398 -------------------------------------------------------------------------
400 -- The complication here concerns whether or not we can
401 -- put the info table next to the code
404 :: CLabel -- Label of info table
405 -> CmmInfo -- ...the info table
406 -> CmmFormals -- ...args
407 -> [CmmBasicBlock] -- ...and body
410 emitInfoTableAndCode info_lbl info args blocks
411 = emitProc info entry_lbl args blocks
413 entry_lbl = infoLblToEntryLbl info_lbl
415 -------------------------------------------------------------------------
417 -- Static reference tables
419 -------------------------------------------------------------------------
421 srtLabelAndLength :: C_SRT -> CLabel -> (CmmLit, StgHalfWord)
422 srtLabelAndLength NoC_SRT _
424 srtLabelAndLength (C_SRT lbl off bitmap) info_lbl
425 = (makeRelativeRefTo info_lbl $ cmmLabelOffW lbl off, bitmap)
427 -------------------------------------------------------------------------
429 -- Position independent code
431 -------------------------------------------------------------------------
432 -- In order to support position independent code, we mustn't put absolute
433 -- references into read-only space. Info tables in the tablesNextToCode
434 -- case must be in .text, which is read-only, so we doctor the CmmLits
435 -- to use relative offsets instead.
437 -- Note that this is done even when the -fPIC flag is not specified,
438 -- as we want to keep binary compatibility between PIC and non-PIC.
440 makeRelativeRefTo :: CLabel -> CmmLit -> CmmLit
442 makeRelativeRefTo info_lbl (CmmLabel lbl)
444 = CmmLabelDiffOff lbl info_lbl 0
445 makeRelativeRefTo info_lbl (CmmLabelOff lbl off)
447 = CmmLabelDiffOff lbl info_lbl off
448 makeRelativeRefTo _ lit = lit