2 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
4 % $Id: CgClosure.lhs,v 1.54 2002/01/02 12:32:18 simonmar Exp $
6 \section[CgClosure]{Code generation for closures}
8 This module provides the support code for @StgToAbstractC@ to deal
9 with {\em closures} on the RHSs of let(rec)s. See also
10 @CgCon@, which deals with constructors.
13 module CgClosure ( cgTopRhsClosure,
16 closureCodeBody ) where
18 #include "HsVersions.h"
20 import {-# SOURCE #-} CgExpr ( cgExpr )
26 import AbsCUtils ( mkAbstractCs, getAmodeRep )
27 import CgBindery ( getCAddrMode, getArgAmodes,
28 getCAddrModeAndInfo, bindNewToNode,
30 bindNewToReg, bindArgsToRegs,
31 stableAmodeIdInfo, heapIdInfo, CgIdInfo
33 import CgUpdate ( pushUpdateFrame )
34 import CgHeapery ( allocDynClosure,
35 fetchAndReschedule, yield, -- HWL
36 fastEntryChecks, thunkChecks
38 import CgStackery ( mkTaggedVirtStkOffsets, freeStackSlots )
39 import CgUsages ( adjustSpAndHp, setRealAndVirtualSp, getVirtSp,
40 getSpRelOffset, getHpRelOffset
42 import CLabel ( CLabel, mkClosureLabel, mkFastEntryLabel,
43 mkRednCountsLabel, mkInfoTableLabel
45 import ClosureInfo -- lots and lots of stuff
46 import CmdLineOpts ( opt_GranMacros, opt_SccProfilingOn, opt_DoTickyProfiling )
48 import Id ( Id, idName, idType, idPrimRep )
49 import Name ( Name, isLocalName )
50 import Module ( Module, pprModule )
51 import ListSetOps ( minusList )
52 import PrimRep ( PrimRep(..) )
53 import PprType ( showTypeCategory )
54 import Util ( isIn, splitAtList )
55 import CmdLineOpts ( opt_SccProfilingOn )
58 import Name ( nameOccName )
59 import OccName ( occNameFS )
60 import FastTypes ( iBox )
63 %********************************************************
65 \subsection[closures-no-free-vars]{Top-level closures}
67 %********************************************************
69 For closures bound at top level, allocate in static space.
70 They should have no free variables.
74 -> CostCentreStack -- Optional cost centre annotation
80 -> FCode (Id, CgIdInfo)
82 cgTopRhsClosure id ccs binder_info srt args body lf_info
85 getSRTInfo srt `thenFC` \ srt_info ->
88 closure_info = layOutStaticNoFVClosure name lf_info srt_info
89 closure_label = mkClosureLabel name
90 cg_id_info = stableAmodeIdInfo id (CLbl closure_label PtrRep) lf_info
93 -- BUILD THE OBJECT (IF NECESSARY)
95 ({- if staticClosureRequired name binder_info lf_info
97 absC (mkStaticClosure closure_info ccs [] True)
103 -- GENERATE THE INFO TABLE (IF NECESSARY)
104 forkClosureBody (closureCodeBody binder_info closure_info
109 returnFC (id, cg_id_info)
113 %********************************************************
115 \subsection[non-top-level-closures]{Non top-level closures}
117 %********************************************************
119 For closures with free vars, allocate in heap.
124 -> CostCentreStack -- Optional cost centre annotation
130 -> [StgArg] -- payload
131 -> FCode (Id, CgIdInfo)
133 cgStdRhsClosure binder cc binder_info fvs args body lf_info payload
134 -- AHA! A STANDARD-FORM THUNK
136 -- LAY OUT THE OBJECT
137 getArgAmodes payload `thenFC` \ amodes ->
139 (closure_info, amodes_w_offsets)
140 = layOutDynClosure (idName binder) getAmodeRep amodes lf_info NoC_SRT
141 -- No SRT for a standard-form closure
143 (use_cc, blame_cc) = chooseDynCostCentres cc args fvs body
146 allocDynClosure closure_info use_cc blame_cc amodes_w_offsets
148 `thenFC` \ heap_offset ->
151 returnFC (binder, heapIdInfo binder heap_offset lf_info)
154 Here's the general case.
158 -> CostCentreStack -- Optional cost centre annotation
165 -> FCode (Id, CgIdInfo)
167 cgRhsClosure binder cc binder_info srt fvs args body lf_info
169 -- LAY OUT THE OBJECT
171 -- If the binder is itself a free variable, then don't store
172 -- it in the closure. Instead, just bind it to Node on entry.
173 -- NB we can be sure that Node will point to it, because we
174 -- havn't told mkClosureLFInfo about this; so if the binder
175 -- *was* a free var of its RHS, mkClosureLFInfo thinks it *is*
176 -- stored in the closure itself, so it will make sure that
177 -- Node points to it...
179 is_elem = isIn "cgRhsClosure"
181 binder_is_a_fv = binder `is_elem` fvs
182 reduced_fvs = if binder_is_a_fv
183 then fvs `minusList` [binder]
186 mapFCs getCAddrModeAndInfo reduced_fvs `thenFC` \ fvs_w_amodes_and_info ->
187 getSRTInfo srt `thenFC` \ srt_info ->
189 closure_info :: ClosureInfo
190 bind_details :: [((Id, CAddrMode, LambdaFormInfo), VirtualHeapOffset)]
192 (closure_info, bind_details)
193 = layOutDynClosure (idName binder) get_kind
194 fvs_w_amodes_and_info lf_info srt_info
196 bind_fv ((id, _, lf_info), offset) = bindNewToNode id offset lf_info
198 amodes_w_offsets = [(amode,offset) | ((_,amode,_), offset) <- bind_details]
200 get_kind (id, _, _) = idPrimRep id
202 -- BUILD ITS INFO TABLE AND CODE
205 mapCs bind_fv bind_details `thenC`
207 -- Bind the binder itself, if it is a free var
208 (if binder_is_a_fv then
209 bindNewToReg binder node lf_info
214 closureCodeBody binder_info closure_info cc args body
219 (use_cc, blame_cc) = chooseDynCostCentres cc args fvs body
221 allocDynClosure closure_info use_cc blame_cc amodes_w_offsets
222 ) `thenFC` \ heap_offset ->
225 returnFC (binder, heapIdInfo binder heap_offset lf_info)
228 %************************************************************************
230 \subsection[code-for-closures]{The code for closures}
232 %************************************************************************
235 closureCodeBody :: StgBinderInfo
236 -> ClosureInfo -- Lots of information about this closure
237 -> CostCentreStack -- Optional cost centre attached to closure
243 There are two main cases for the code for closures. If there are {\em
244 no arguments}, then the closure is a thunk, and not in normal form.
245 So it should set up an update frame (if it is shared). Also, it has
246 no argument satisfaction check, so fast and slow entry-point labels
250 closureCodeBody binder_info closure_info cc [] body
251 = -- thunks cannot have a primitive type!
252 getAbsC body_code `thenFC` \ body_absC ->
253 moduleName `thenFC` \ mod_name ->
255 absC (CClosureInfoAndCode closure_info body_absC Nothing
258 cl_descr mod_name = closureDescription mod_name (closureName closure_info)
260 body_label = entryLabelFromCI closure_info
262 is_box = case body of { StgApp fun [] -> True; _ -> False }
264 body_code = profCtrC SLIT("TICK_ENT_THK") [] `thenC`
265 -- node always points when profiling, so this is ok:
267 thunkWrapper closure_info body_label (
268 -- We only enter cc after setting up update so
269 -- that cc of enclosing scope will be recorded
270 -- in update frame CAF/DICT functions will be
271 -- subsumed by this enclosing cc
272 enterCostCentreCode closure_info cc IsThunk is_box `thenC`
277 If there is {\em at least one argument}, then this closure is in
278 normal form, so there is no need to set up an update frame. On the
279 other hand, we do have to check that there are enough args, and
280 perform an update if not!
282 The Macros for GrAnSim are produced at the beginning of the
283 argSatisfactionCheck (by calling fetchAndReschedule). There info if
284 Node points to closure is available. -- HWL
287 closureCodeBody binder_info closure_info cc all_args body
288 = getEntryConvention name lf_info
289 (map idPrimRep all_args) `thenFC` \ entry_conv ->
291 -- get the current virtual Sp (it might not be zero, eg. if we're
292 -- compiling a let-no-escape).
293 getVirtSp `thenFC` \vSp ->
296 -- Figure out what is needed and what isn't
298 -- SDM: need everything for now in case the heap/stack check refers
300 slow_code_needed = True
301 --slowFunEntryCodeRequired name binder_info entry_conv
302 info_table_needed = True
303 --funInfoTableRequired name binder_info lf_info
305 -- Arg mapping for standard (slow) entry point; all args on stack,
307 (sp_all_args, arg_offsets, _)
308 = mkTaggedVirtStkOffsets vSp idPrimRep all_args
310 -- Arg mapping for the fast entry point; as many args as poss in
311 -- registers; the rest on the stack
312 -- arg_regs are the registers used for arg passing
313 -- stk_args are the args which are passed on the stack
315 -- Args passed on the stack are tagged, but the tags may not
316 -- actually be present (just gaps) if the function is called
317 -- by jumping directly to the fast entry point.
319 arg_regs = case entry_conv of
320 DirectEntry lbl arity regs -> regs
321 other -> [] -- "(HWL ignored; no args passed in regs)"
323 (reg_args, stk_args) = splitAtList arg_regs all_args
325 (sp_stk_args, stk_offsets, stk_tags)
326 = mkTaggedVirtStkOffsets vSp idPrimRep stk_args
328 -- HWL; Note: empty list of live regs in slow entry code
329 -- Old version (reschedule combined with heap check);
330 -- see argSatisfactionCheck for new version
331 --slow_entry_code = forceHeapCheck [node] True slow_entry_code'
332 -- where node = UnusedReg PtrRep 1
333 --slow_entry_code = forceHeapCheck [] True slow_entry_code'
336 = profCtrC SLIT("TICK_ENT_FUN_STD") [
337 CLbl ticky_ctr_label DataPtrRep
340 -- Bind args, and record expected position of stk ptrs
341 mapCs bindNewToStack arg_offsets `thenC`
342 setRealAndVirtualSp sp_all_args `thenC`
344 argSatisfactionCheck closure_info arg_regs `thenC`
346 -- OK, so there are enough args. Now we need to stuff as
347 -- many of them in registers as the fast-entry code
348 -- expects. Note that the zipWith will give up when it hits
349 -- the end of arg_regs.
351 mapFCs getCAddrMode all_args `thenFC` \ stk_amodes ->
352 absC (mkAbstractCs (zipWith assign_to_reg arg_regs stk_amodes))
355 -- Now adjust real stack pointers (no need to adjust Hp,
356 -- but call this function for convenience).
357 adjustSpAndHp sp_stk_args `thenC`
359 absC (CFallThrough (CLbl fast_label CodePtrRep))
361 assign_to_reg reg_id amode = CAssign (CReg reg_id) amode
364 -- Old version (reschedule combined with heap check);
365 -- see argSatisfactionCheck for new version
366 -- fast_entry_code = forceHeapCheck [] True fast_entry_code'
369 mod_name <- moduleName
370 profCtrC SLIT("TICK_CTR") [
371 CLbl ticky_ctr_label DataPtrRep,
372 mkCString (_PK_ (ppr_for_ticky_name mod_name name)),
373 mkIntCLit stg_arity, -- total # of args
374 mkIntCLit sp_stk_args, -- # passed on stk
375 mkCString (_PK_ (map (showTypeCategory . idType) all_args))
378 profCtrC SLIT("TICK_ENT_FUN_DIRECT") [
379 CLbl ticky_ctr_label DataPtrRep
382 -- Nuked for now; see comment at end of file
383 -- CString (_PK_ (show_wrapper_name wrapper_maybe)),
384 -- CString (_PK_ (show_wrapper_arg_kinds wrapper_maybe))
387 -- Bind args to regs/stack as appropriate, and
388 -- record expected position of sps.
389 bindArgsToRegs reg_args arg_regs
390 mapCs bindNewToStack stk_offsets
391 setRealAndVirtualSp sp_stk_args
393 -- free up the stack slots containing tags
394 freeStackSlots (map fst stk_tags)
396 -- Enter the closures cc, if required
397 enterCostCentreCode closure_info cc IsFunction False
400 funWrapper closure_info arg_regs stk_tags info_label
401 (prof >> cgExpr body)
404 setTickyCtrLabel ticky_ctr_label (
406 -- Make a labelled code-block for the slow and fast entry code
407 forkAbsC (if slow_code_needed then slow_entry_code else absC AbsCNop)
408 `thenFC` \ slow_abs_c ->
409 forkAbsC fast_entry_code `thenFC` \ fast_abs_c ->
410 moduleName `thenFC` \ mod_name ->
412 -- Now either construct the info table, or put the fast code in alone
413 -- (We never have slow code without an info table)
414 -- XXX probably need the info table and slow entry code in case of
415 -- a heap check failure.
417 if info_table_needed then
418 CClosureInfoAndCode closure_info slow_abs_c (Just fast_abs_c)
421 CCodeBlock fast_label fast_abs_c
425 ticky_ctr_label = mkRednCountsLabel name
427 stg_arity = length all_args
428 lf_info = closureLFInfo closure_info
430 cl_descr mod_name = closureDescription mod_name name
432 -- Manufacture labels
433 name = closureName closure_info
434 fast_label = mkFastEntryLabel name stg_arity
435 info_label = mkInfoTableLabel name
438 -- When printing the name of a thing in a ticky file, we want to
439 -- give the module name even for *local* things. We print
440 -- just "x (M)" rather that "M.x" to distinguish them from the global kind.
441 ppr_for_ticky_name mod_name name
442 | isLocalName name = showSDocDebug (ppr name <+> (parens (ppr mod_name)))
443 | otherwise = showSDocDebug (ppr name)
446 For lexically scoped profiling we have to load the cost centre from
447 the closure entered, if the costs are not supposed to be inherited.
448 This is done immediately on entering the fast entry point.
450 Load current cost centre from closure, if not inherited.
451 Node is guaranteed to point to it, if profiling and not inherited.
454 data IsThunk = IsThunk | IsFunction -- Bool-like, local
460 :: ClosureInfo -> CostCentreStack
462 -> Bool -- is_box: this closure is a special box introduced by SCCfinal
465 enterCostCentreCode closure_info ccs is_thunk is_box
466 = if not opt_SccProfilingOn then
469 ASSERT2(not (noCCSAttached ccs), ppr (closureName closure_info) <+> ppr ccs)
471 if isSubsumedCCS ccs then
472 ASSERT(isToplevClosure closure_info)
473 ASSERT(is_thunk == IsFunction)
474 costCentresC SLIT("ENTER_CCS_FSUB") []
476 else if isDerivedFromCurrentCCS ccs then
477 if re_entrant && not is_box
478 then costCentresC SLIT("ENTER_CCS_FCL") [CReg node]
479 else costCentresC SLIT("ENTER_CCS_TCL") [CReg node]
481 else if isCafCCS ccs then
482 ASSERT(isToplevClosure closure_info)
483 ASSERT(is_thunk == IsThunk)
484 -- might be a PAP, in which case we want to subsume costs
486 then costCentresC SLIT("ENTER_CCS_FSUB") []
487 else costCentresC SLIT("ENTER_CCS_CAF") c_ccs
489 else panic "enterCostCentreCode"
492 c_ccs = [mkCCostCentreStack ccs]
493 re_entrant = closureReEntrant closure_info
496 %************************************************************************
498 \subsubsection[pre-closure-code-stuff]{Pre-closure-code code}
500 %************************************************************************
502 The argument-satisfaction check code is placed after binding
503 the arguments to their stack locations. Hence, the virtual stack
504 pointer is pointing after all the args, and virtual offset 1 means
505 the base of frame and hence most distant arg. Hence
506 virtual offset 0 is just beyond the most distant argument; the
507 relative offset of this word tells how many words of arguments
511 argSatisfactionCheck :: ClosureInfo -> [MagicId] {-GRAN-} -> Code
513 argSatisfactionCheck closure_info arg_regs
515 = nodeMustPointToIt (closureLFInfo closure_info) `thenFC` \ node_points ->
518 -- emit_gran_macros = opt_GranMacros
522 -- absC (CMacroStmt GRAN_FETCH []) `thenC`
523 -- forceHeapCheck [] node_points (absC AbsCNop) `thenC`
525 -- then if node_points
526 -- then fetchAndReschedule arg_regs node_points
527 -- else yield arg_regs node_points
528 -- else absC AbsCNop) `thenC`
530 getSpRelOffset 0 `thenFC` \ (SpRel sp) ->
533 rel_arg = mkIntCLit off
537 absC (CMacroStmt ARGS_CHK [rel_arg]) -- node already points
539 absC (CMacroStmt ARGS_CHK_LOAD_NODE [rel_arg, set_Node_to_this])
541 -- We must tell the arg-satis macro whether Node is pointing to
542 -- the closure or not. If it isn't so pointing, then we give to
543 -- the macro the (static) address of the closure.
545 set_Node_to_this = CLbl (closureLabelFromCI closure_info) PtrRep
548 %************************************************************************
550 \subsubsection[closure-code-wrappers]{Wrappers around closure code}
552 %************************************************************************
555 thunkWrapper:: ClosureInfo -> CLabel -> Code -> Code
556 thunkWrapper closure_info lbl thunk_code
557 = -- Stack and heap overflow checks
558 nodeMustPointToIt (closureLFInfo closure_info) `thenFC` \ node_points ->
560 -- HWL: insert macros for GrAnSim; 2 versions depending on liveness of node
561 -- (we prefer fetchAndReschedule-style context switches to yield ones)
564 then fetchAndReschedule [] node_points
565 else yield [] node_points
566 else absC AbsCNop) `thenC`
568 -- stack and/or heap checks
569 thunkChecks lbl node_points (
571 -- Overwrite with black hole if necessary
572 blackHoleIt closure_info node_points `thenC`
574 setupUpdate closure_info ( -- setupUpdate *encloses* the rest
576 -- Finally, do the business
580 funWrapper :: ClosureInfo -- Closure whose code body this is
581 -> [MagicId] -- List of argument registers (if any)
582 -> [(VirtualSpOffset,Int)] -- tagged stack slots
583 -> CLabel -- info table for heap check ret.
584 -> Code -- Body of function being compiled
586 funWrapper closure_info arg_regs stk_tags info_label fun_body
587 = -- Stack overflow check
588 nodeMustPointToIt (closureLFInfo closure_info) `thenFC` \ node_points ->
590 -- enter for Ldv profiling
591 (if node_points then ldvEnter else nopC) `thenC`
594 then yield arg_regs node_points
595 else absC AbsCNop) `thenC`
597 -- heap and/or stack checks
598 fastEntryChecks arg_regs stk_tags info_label node_points (
600 -- Finally, do the business
606 %************************************************************************
608 \subsubsubsection[update-and-BHs]{Update and black-hole wrappers}
610 %************************************************************************
614 blackHoleIt :: ClosureInfo -> Bool -> Code -- Only called for closures with no args
616 blackHoleIt closure_info node_points
617 = if blackHoleOnEntry closure_info && node_points
620 info_label = infoTableLabelFromCI closure_info
621 args = [ CLbl info_label DataPtrRep ]
623 absC (if closureSingleEntry(closure_info) then
624 CMacroStmt UPD_BH_SINGLE_ENTRY args
626 CMacroStmt UPD_BH_UPDATABLE args)
632 setupUpdate :: ClosureInfo -> Code -> Code -- Only called for closures with no args
633 -- Nota Bene: this function does not change Node (even if it's a CAF),
634 -- so that the cost centre in the original closure can still be
635 -- extracted by a subsequent ENTER_CC_TCL
637 -- I've tidied up the code for this function, but it should still do the same as
638 -- it did before (modulo ticky stuff). KSW 1999-04.
639 setupUpdate closure_info code
640 = if closureReEntrant closure_info
644 case (closureUpdReqd closure_info, isStaticClosure closure_info) of
645 (False,False) -> profCtrC SLIT("TICK_UPDF_OMITTED") [] `thenC`
647 (False,True ) -> (if opt_DoTickyProfiling
649 -- blackhole the SE CAF
650 link_caf seCafBlackHoleClosureInfo `thenFC` \ _ -> nopC
653 profCtrC SLIT("TICK_UPD_CAF_BH_SINGLE_ENTRY") [mkCString cl_name] `thenC`
654 profCtrC SLIT("TICK_UPDF_OMITTED") [] `thenC`
656 (True ,False) -> pushUpdateFrame (CReg node) code
657 (True ,True ) -> -- blackhole the (updatable) CAF:
658 link_caf cafBlackHoleClosureInfo `thenFC` \ update_closure ->
659 profCtrC SLIT("TICK_UPD_CAF_BH_UPDATABLE") [mkCString cl_name] `thenC`
660 pushUpdateFrame update_closure code
662 cl_name :: FAST_STRING
663 cl_name = (occNameFS . nameOccName . closureName) closure_info
665 link_caf :: (ClosureInfo -> ClosureInfo) -- function yielding BH closure_info
666 -> FCode CAddrMode -- Returns amode for closure to be updated
668 = -- To update a CAF we must allocate a black hole, link the CAF onto the
669 -- CAF list, then update the CAF to point to the fresh black hole.
670 -- This function returns the address of the black hole, so it can be
671 -- updated with the new value when available.
673 -- Alloc black hole specifying CC_HDR(Node) as the cost centre
675 use_cc = CMacroExpr PtrRep CCS_HDR [nodeReg]
678 allocDynClosure (bhCI closure_info) use_cc blame_cc [] `thenFC` \ heap_offset ->
679 getHpRelOffset heap_offset `thenFC` \ hp_rel ->
680 let amode = CAddr hp_rel
682 absC (CMacroStmt UPD_CAF [CReg node, amode]) `thenC`
686 %************************************************************************
688 \subsection[CgClosure-Description]{Profiling Closure Description.}
690 %************************************************************************
692 For "global" data constructors the description is simply occurrence
693 name of the data constructor itself (see \ref{CgConTbls-info-tables}).
695 Otherwise it is determind by @closureDescription@ from the let
699 closureDescription :: Module -- Module
700 -> Name -- Id of closure binding
703 -- Not called for StgRhsCon which have global info tables built in
704 -- CgConTbls.lhs with a description generated from the data constructor
706 closureDescription mod_name name
716 chooseDynCostCentres ccs args fvs body
718 use_cc -- cost-centre we record in the object
719 = if currentOrSubsumedCCS ccs
720 then CReg CurCostCentre
721 else mkCCostCentreStack ccs
723 blame_cc -- cost-centre on whom we blame the allocation
724 = case (args, fvs, body) of
725 ([], _, StgApp fun [{-no args-}])
726 -> mkCCostCentreStack overheadCCS
729 -- if it's an utterly trivial RHS, then it must be
730 -- one introduced by boxHigherOrderArgs for profiling,
731 -- so we charge it to "OVERHEAD".
733 -- This looks like a HACK to me --SDM