2 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1996
4 \section[CgConTbls]{Info tables and update bits for constructors}
7 module CgConTbls ( genStaticConBits ) where
9 #include "HsVersions.h"
14 import AbsCUtils ( mkAbsCStmts, mkAbstractCs, magicIdPrimRep )
15 import Constants ( uF_UPDATEE )
16 import CgHeapery ( heapCheck, allocDynClosure )
17 import CgRetConv ( dataReturnConvAlg, ctrlReturnConvAlg,
18 CtrlReturnConvention(..),
19 DataReturnConvention(..)
21 import CgTailCall ( performReturn, mkStaticAlgReturnCode )
22 import CgUsages ( getHpRelOffset )
23 import CLabel ( mkConEntryLabel, mkStaticClosureLabel,
24 mkConUpdCodePtrVecLabel,
25 mkStdUpdCodePtrVecLabel, mkStdUpdVecTblLabel
27 import ClosureInfo ( layOutStaticClosure, layOutDynCon,
28 layOutPhantomClosure, closurePtrsSize,
29 fitsMinUpdSize, mkConLFInfo,
30 infoTableLabelFromCI, dataConLiveness,
33 import CostCentre ( dontCareCostCentre, CostCentre )
34 import FiniteMap ( fmToList, FiniteMap )
35 import HeapOffs ( zeroOff, VirtualHeapOffset )
36 import Id ( dataConTag, dataConRawArgTys,
37 dataConNumFields, fIRST_TAG,
39 GenId{-instance NamedThing-}, Id
41 import Name ( getOccString )
42 import PrimRep ( getPrimRepSize, PrimRep(..) )
43 import TyCon ( tyConDataCons, mkSpecTyCon, TyCon )
44 import Type ( typePrimRep, Type )
47 mkSameSpecCon = panic "CgConTbls.mkSameSpecCon (ToDo)"
50 For every constructor we generate the following info tables:
51 A static info table, for static instances of the constructor,
53 For constructors which return in registers (and only them),
54 an "inregs" info table. This info table is rather emaciated;
55 it only contains update code and tag.
60 Info tbls & Macro & Kind of constructor \\
62 info & @CONST_INFO_TABLE@& Zero arity (no info -- compiler uses static closure)\\
63 info & @CHARLIKE_INFO_TABLE@& Charlike (no info -- compiler indexes fixed array)\\
64 info & @INTLIKE_INFO_TABLE@& Intlike; the one macro generates both info tbls\\
65 info & @SPEC_INFO_TABLE@& SPECish, and bigger than or equal to @MIN_UPD_SIZE@\\
66 info & @GEN_INFO_TABLE@& GENish (hence bigger than or equal to @MIN_UPD_SIZE@)\\
69 Possible info tables for constructor con:
73 Used for dynamically let(rec)-bound occurrences of
74 the constructor, and for updates. For constructors
75 which are int-like, char-like or nullary, when GC occurs,
76 the closure tries to get rid of itself.
78 \item[@con_inregs_info@:]
79 Used when returning a new constructor in registers.
80 Only for return-in-regs constructors.
81 Macro: @INREGS_INFO_TABLE@.
83 \item[@con_static_info@:]
84 Static occurrences of the constructor
85 macro: @STATIC_INFO_TABLE@.
88 For zero-arity constructors, \tr{con}, we also generate a static closure:
92 A single static copy of the (zero-arity) constructor itself.
95 For charlike and intlike closures there is a fixed array of static
99 genStaticConBits :: CompilationInfo -- global info about the compilation
100 -> [TyCon] -- tycons to generate
101 -> FiniteMap TyCon [(Bool, [Maybe Type])]
102 -- tycon specialisation info
103 -> AbstractC -- output
105 genStaticConBits comp_info gen_tycons tycon_specs
106 = -- for each type constructor:
107 -- grab all its data constructors;
108 -- for each one, generate an info table
109 -- for each specialised type constructor
110 -- for each specialisation of the type constructor
111 -- grab data constructors, and generate info tables
113 -- ToDo: for tycons and specialisations which are not
114 -- declared in this module we must ensure that the
115 -- C labels are local to this module i.e. static
116 -- since they may be duplicated in other modules
118 mkAbstractCs [ gen_for_tycon tc | tc <- gen_tycons ]
120 mkAbstractCs [ mkAbstractCs [ gen_for_spec_tycon tc spec
121 | (imported_spec, spec) <- specs,
122 -- no code generated if spec is imported
125 | (tc, specs) <- fmToList tycon_specs ]
127 gen_for_tycon :: TyCon -> AbstractC
129 = mkAbstractCs (map (genConInfo comp_info tycon) data_cons)
133 data_cons = tyConDataCons tycon
134 tycon_upd_label = mkStdUpdVecTblLabel tycon
137 case ctrlReturnConvAlg tycon of
138 UnvectoredReturn 1 -> CRetUnVector tycon_upd_label
139 (mk_upd_label tycon (head data_cons))
140 UnvectoredReturn _ -> AbsCNop
141 VectoredReturn _ -> CFlatRetVector tycon_upd_label
142 (map (mk_upd_label tycon) data_cons)
144 gen_for_spec_tycon :: TyCon -> [Maybe Type] -> AbstractC
146 gen_for_spec_tycon tycon ty_maybes
147 = mkAbstractCs (map (genConInfo comp_info spec_tycon) spec_data_cons)
149 maybe_spec_tycon_vtbl
151 data_cons = tyConDataCons tycon
153 spec_tycon = mkSpecTyCon tycon ty_maybes
154 spec_data_cons = map (mkSameSpecCon ty_maybes) data_cons
156 spec_tycon_upd_label = mkStdUpdVecTblLabel spec_tycon
158 maybe_spec_tycon_vtbl =
159 case ctrlReturnConvAlg spec_tycon of
160 UnvectoredReturn 1 -> CRetUnVector spec_tycon_upd_label
161 (mk_upd_label spec_tycon (head spec_data_cons))
162 UnvectoredReturn _ -> AbsCNop
163 VectoredReturn _ -> CFlatRetVector spec_tycon_upd_label
164 (map (mk_upd_label spec_tycon) spec_data_cons)
166 mk_upd_label tycon con
168 (case (dataReturnConvAlg con) of
169 ReturnInRegs _ -> mkConUpdCodePtrVecLabel tycon tag
170 ReturnInHeap -> mkStdUpdCodePtrVecLabel tycon tag)
176 %************************************************************************
178 \subsection[CgConTbls-info-tables]{Generating info tables for constructors}
180 %************************************************************************
182 Generate the entry code, info tables, and (for niladic constructor) the
183 static closure, for a constructor.
186 genConInfo :: CompilationInfo -> TyCon -> Id -> AbstractC
188 genConInfo comp_info tycon data_con
195 -- Order of things is to reduce forward references
197 (closure_info, body_code) = mkConCodeAndInfo data_con
199 -- To allow the debuggers, interpreters, etc to cope with static
200 -- data structures (ie those built at compile time), we take care that
201 -- info-table contains the information we need.
202 (static_ci,_) = layOutStaticClosure data_con typePrimRep arg_tys (mkConLFInfo data_con)
204 body = (initC comp_info (
205 profCtrC SLIT("ENT_CON") [CReg node] `thenC`
208 entry_addr = CLbl entry_label CodePtrRep
209 con_descr = getOccString data_con
211 closure_code = CClosureInfoAndCode closure_info body Nothing
213 (dataConLiveness closure_info)
214 static_code = CClosureInfoAndCode static_ci body Nothing
216 (dataConLiveness static_ci)
218 inregs_upd_maybe = genPhantomUpdInfo comp_info tycon data_con
220 stdUpd = CLbl (mkStdUpdCodePtrVecLabel tycon tag) CodePtrRep
222 tag = dataConTag data_con
224 cost_centre = mkCCostCentre dontCareCostCentre -- not worried about static data costs
226 -- For zero-arity data constructors, or, more accurately,
227 -- those which only have VoidRep args (or none):
228 -- We make the closure too (not just info tbl), so that we can share
229 -- one copy throughout.
230 closure_maybe = if not (all zero_size arg_tys) then
233 CStaticClosure closure_label -- Label for closure
234 static_ci -- Info table
236 [{-No args! A slight lie for constrs with VoidRep args-}]
238 zero_size arg_ty = getPrimRepSize (typePrimRep arg_ty) == 0
240 arg_tys = dataConRawArgTys data_con
241 entry_label = mkConEntryLabel data_con
242 closure_label = mkStaticClosureLabel data_con
245 The entry code for a constructor now loads the info ptr by indirecting
246 node. The alternative is to load the info ptr in the enter-via-node
247 sequence. There's is a trade-off here:
249 * If the architecture can perform an indirect jump through a
250 register in one instruction, or if the info ptr is not a
251 real register, then *not* loading the info ptr on an enter
254 * If the enter-via-node code is identical whether we load the
255 info ptr or not, then doing it is a win (it means we don't
258 However, the gratuitous load here is miniscule compared to the
259 gratuitous loads of the info ptr on each enter, so we go for the first
265 mkConCodeAndInfo :: Id -- Data constructor
266 -> (ClosureInfo, Code) -- The info table
269 = case (dataReturnConvAlg con) of
273 (closure_info, regs_w_offsets)
274 = layOutDynCon con magicIdPrimRep regs
277 = profCtrC SLIT("RET_OLD_IN_REGS") [mkIntCLit (length regs_w_offsets)] `thenC`
279 performReturn (mkAbstractCs (load_infoptr : map move_to_reg regs_w_offsets))
280 (mkStaticAlgReturnCode con Nothing {- Info-ptr already loaded-})
281 emptyIdSet{-no live vars-}
283 (closure_info, body_code)
287 arg_tys = dataConRawArgTys con
289 (closure_info, arg_things)
290 = layOutDynCon con typePrimRep arg_tys
293 = -- NB: We don't set CC when entering data (WDP 94/06)
294 profCtrC SLIT("RET_OLD_IN_HEAP") [mkIntCLit (length arg_things)] `thenC`
296 performReturn (mkAbstractCs [load_infoptr]) -- Ptr to thing already in Node
297 (mkStaticAlgReturnCode con Nothing {- Info-ptr already loaded-})
298 emptyIdSet{-no live vars-}
300 (closure_info, body_code)
303 move_to_reg :: (MagicId, VirtualHeapOffset {-from Node-}) -> AbstractC
304 move_to_reg (reg, offset)
305 = CAssign (CReg reg) (CVal (NodeRel offset) (magicIdPrimRep reg))
308 = CAssign (CReg infoptr) (CMacroExpr DataPtrRep INFO_PTR [CReg node])
311 %************************************************************************
313 \subsection[CgConTbls-updates]{Generating update bits for constructors}
315 %************************************************************************
317 Generate the "phantom" info table and update code, iff the constructor returns in regs
321 genPhantomUpdInfo :: CompilationInfo -> TyCon -> Id{-data con-} -> AbstractC
323 genPhantomUpdInfo comp_info tycon data_con
324 = case (dataReturnConvAlg data_con) of
326 ReturnInHeap -> AbsCNop -- No need for a phantom update
330 phantom_itbl = CClosureInfoAndCode phantom_ci AbsCNop Nothing
332 (dataConLiveness phantom_ci)
334 phantom_ci = layOutPhantomClosure data_con (mkConLFInfo data_con)
336 con_descr = getOccString data_con
338 con_arity = dataConNumFields data_con
340 upd_code = CLabelledCode upd_label (mkAbsCStmts build_closure perform_return)
341 upd_label = mkConUpdCodePtrVecLabel tycon tag
342 tag = dataConTag data_con
344 updatee = CVal (SpBRel 0 (- uF_UPDATEE)) PtrRep
346 perform_return = mkAbstractCs
348 CMacroStmt POP_STD_UPD_FRAME [],
349 CReturn (CReg RetReg) return_info
353 case (ctrlReturnConvAlg tycon) of
354 UnvectoredReturn _ -> DirectReturn
355 VectoredReturn _ -> StaticVectoredReturn (tag - fIRST_TAG)
357 -- Determine cost centre for the updated closures CC (and allocation)
358 -- CCC for lexical (now your only choice)
359 use_cc = CReg CurCostCentre -- what to put in the closure
360 blame_cc = use_cc -- who to blame for allocation
362 do_move (reg, virt_offset) =
363 CAssign (CVal (NodeRel virt_offset) (magicIdPrimRep reg)) (CReg reg)
366 -- Code for building a new constructor in place over the updatee
368 = profCtrC SLIT("UPD_CON_IN_PLACE")
369 [mkIntCLit (length regs_w_offsets)] `thenC`
372 CAssign (CReg node) updatee,
374 -- Tell the storage mgr that we intend to update in place
375 -- This may (in complicated mgrs eg generational) cause gc,
376 -- and it may modify Node to point to another place to
377 -- actually update into.
378 CMacroStmt upd_inplace_macro [liveness_mask],
380 -- Initialise the closure pointed to by node
381 CInitHdr closure_info (NodeRel zeroOff) use_cc True,
382 mkAbstractCs (map do_move regs_w_offsets),
383 if con_arity /= 0 then
384 CAssign (CReg infoptr) (CLbl info_label DataPtrRep)
389 upd_inplace_macro = if closurePtrsSize closure_info == 0
390 then UPD_INPLACE_NOPTRS
391 else UPD_INPLACE_PTRS
393 -- Code for allocating a new constructor in the heap
396 amodes_w_offsets = [ (CReg r, o) | (r,o) <- regs_w_offsets ]
398 -- Allocate and build closure specifying upd_new_w_regs
399 allocDynClosure closure_info use_cc blame_cc amodes_w_offsets
400 `thenFC` \ hp_offset ->
401 getHpRelOffset hp_offset `thenFC` \ hp_rel ->
405 profCtrC SLIT("UPD_CON_IN_NEW")
406 [mkIntCLit (length amodes_w_offsets)] `thenC`
408 [ CMacroStmt UPD_IND [updatee, amode],
409 CAssign (CReg node) amode,
410 CAssign (CReg infoptr) (CLbl info_label DataPtrRep)
413 (closure_info, regs_w_offsets) = layOutDynCon data_con magicIdPrimRep regs
414 info_label = infoTableLabelFromCI closure_info
415 liveness_mask = mkIntCLit (mkLiveRegsMask (node:regs))
418 if fitsMinUpdSize closure_info then
419 initC comp_info overwrite_code
421 initC comp_info (heapCheck regs False alloc_code)
423 in CClosureUpdInfo phantom_itbl