2 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
4 % $Id: CgClosure.lhs,v 1.26 1999/03/22 16:58:19 simonm 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 )
25 import BasicTypes ( TopLevelFlag(..) )
27 import AbsCUtils ( mkAbstractCs, getAmodeRep )
28 import CgBindery ( getCAddrMode, getArgAmodes,
29 getCAddrModeAndInfo, bindNewToNode,
31 bindNewToReg, bindArgsToRegs,
32 stableAmodeIdInfo, heapIdInfo, CgIdInfo
34 import CgUpdate ( pushUpdateFrame )
35 import CgHeapery ( allocDynClosure,
36 fetchAndReschedule, yield, -- HWL
37 fastEntryChecks, thunkChecks
39 import CgStackery ( adjustRealSp, mkTaggedVirtStkOffsets, freeStackSlots )
40 import CgUsages ( setRealAndVirtualSp, getVirtSp,
41 getSpRelOffset, getHpRelOffset
43 import CLabel ( CLabel, mkClosureLabel, mkFastEntryLabel,
44 mkRednCountsLabel, mkStdEntryLabel
46 import ClosureInfo -- lots and lots of stuff
47 import CmdLineOpts ( opt_GranMacros, opt_SccProfilingOn )
49 import Id ( Id, idName, idType, idPrimRep )
51 import Module ( Module, pprModule )
52 import ListSetOps ( minusList )
53 import PrimRep ( PrimRep(..) )
54 import PprType ( showTypeCategory )
56 import CmdLineOpts ( opt_SccProfilingOn )
59 getWrapperArgTypeCategories = panic "CgClosure.getWrapperArgTypeCategories (ToDo)"
62 %********************************************************
64 \subsection[closures-no-free-vars]{Top-level closures}
66 %********************************************************
68 For closures bound at top level, allocate in static space.
69 They should have no free variables.
73 -> CostCentreStack -- Optional cost centre annotation
78 -> FCode (Id, CgIdInfo)
80 cgTopRhsClosure id ccs binder_info args body lf_info
81 = -- LAY OUT THE OBJECT
83 closure_info = layOutStaticNoFVClosure name lf_info
86 -- BUILD THE OBJECT (IF NECESSARY)
87 ({- if staticClosureRequired name binder_info lf_info
89 (if opt_SccProfilingOn
92 closure_label -- Labelled with the name on lhs of defn
94 (mkCCostCentreStack ccs)
98 closure_label -- Labelled with the name on lhs of defn
108 -- GENERATE THE INFO TABLE (IF NECESSARY)
109 forkClosureBody (closureCodeBody binder_info closure_info
114 returnFC (id, cg_id_info)
117 closure_label = mkClosureLabel name
118 cg_id_info = stableAmodeIdInfo id (CLbl closure_label PtrRep) lf_info
121 %********************************************************
123 \subsection[non-top-level-closures]{Non top-level closures}
125 %********************************************************
127 For closures with free vars, allocate in heap.
132 -> CostCentreStack -- Optional cost centre annotation
138 -> [StgArg] -- payload
139 -> FCode (Id, CgIdInfo)
141 cgStdRhsClosure binder cc binder_info fvs args body lf_info payload
142 -- AHA! A STANDARD-FORM THUNK
144 -- LAY OUT THE OBJECT
145 getArgAmodes payload `thenFC` \ amodes ->
147 (closure_info, amodes_w_offsets)
148 = layOutDynClosure (idName binder) getAmodeRep amodes lf_info
150 (use_cc, blame_cc) = chooseDynCostCentres cc args fvs body
153 allocDynClosure closure_info use_cc blame_cc amodes_w_offsets
155 `thenFC` \ heap_offset ->
158 returnFC (binder, heapIdInfo binder heap_offset lf_info)
161 is_std_thunk = isStandardFormThunk lf_info
164 Here's the general case.
168 -> CostCentreStack -- Optional cost centre annotation
174 -> FCode (Id, CgIdInfo)
176 cgRhsClosure binder cc binder_info fvs args body lf_info
178 -- LAY OUT THE OBJECT
180 -- If the binder is itself a free variable, then don't store
181 -- it in the closure. Instead, just bind it to Node on entry.
182 -- NB we can be sure that Node will point to it, because we
183 -- havn't told mkClosureLFInfo about this; so if the binder
184 -- *was* a free var of its RHS, mkClosureLFInfo thinks it *is*
185 -- stored in the closure itself, so it will make sure that
186 -- Node points to it...
188 is_elem = isIn "cgRhsClosure"
190 binder_is_a_fv = binder `is_elem` fvs
191 reduced_fvs = if binder_is_a_fv
192 then fvs `minusList` [binder]
195 mapFCs getCAddrModeAndInfo reduced_fvs `thenFC` \ amodes_and_info ->
197 fvs_w_amodes_and_info = reduced_fvs `zip` amodes_and_info
199 closure_info :: ClosureInfo
200 bind_details :: [((Id, (CAddrMode, LambdaFormInfo)), VirtualHeapOffset)]
202 (closure_info, bind_details)
203 = layOutDynClosure (idName binder) get_kind fvs_w_amodes_and_info lf_info
205 bind_fv ((id, (_, lf_info)), offset) = bindNewToNode id offset lf_info
207 amodes_w_offsets = [(amode,offset) | ((_, (amode,_)), offset) <- bind_details]
209 get_kind (id, amode_and_info) = idPrimRep id
211 -- BUILD ITS INFO TABLE AND CODE
214 mapCs bind_fv bind_details `thenC`
216 -- Bind the binder itself, if it is a free var
217 (if binder_is_a_fv then
218 bindNewToReg binder node lf_info
223 closureCodeBody binder_info closure_info cc args body
228 (use_cc, blame_cc) = chooseDynCostCentres cc args fvs body
230 allocDynClosure closure_info use_cc blame_cc amodes_w_offsets
231 ) `thenFC` \ heap_offset ->
234 returnFC (binder, heapIdInfo binder heap_offset lf_info)
237 %************************************************************************
239 \subsection[code-for-closures]{The code for closures}
241 %************************************************************************
244 closureCodeBody :: StgBinderInfo
245 -> ClosureInfo -- Lots of information about this closure
246 -> CostCentreStack -- Optional cost centre attached to closure
252 There are two main cases for the code for closures. If there are {\em
253 no arguments}, then the closure is a thunk, and not in normal form.
254 So it should set up an update frame (if it is shared). Also, it has
255 no argument satisfaction check, so fast and slow entry-point labels
259 closureCodeBody binder_info closure_info cc [] body
260 = -- thunks cannot have a primitive type!
261 getAbsC body_code `thenFC` \ body_absC ->
262 moduleName `thenFC` \ mod_name ->
264 absC (CClosureInfoAndCode closure_info body_absC Nothing
267 cl_descr mod_name = closureDescription mod_name (closureName closure_info)
269 body_label = entryLabelFromCI closure_info
270 body_code = profCtrC SLIT("TICK_ENT_THK") [] `thenC`
271 thunkWrapper closure_info body_label (
272 -- We only enter cc after setting up update so that cc
273 -- of enclosing scope will be recorded in update frame
274 -- CAF/DICT functions will be subsumed by this enclosing cc
275 enterCostCentreCode closure_info cc IsThunk `thenC`
279 If there is {\em at least one argument}, then this closure is in
280 normal form, so there is no need to set up an update frame. On the
281 other hand, we do have to check that there are enough args, and
282 perform an update if not!
284 The Macros for GrAnSim are produced at the beginning of the
285 argSatisfactionCheck (by calling fetchAndReschedule). There info if
286 Node points to closure is available. -- HWL
289 closureCodeBody binder_info closure_info cc all_args body
290 = getEntryConvention name lf_info
291 (map idPrimRep all_args) `thenFC` \ entry_conv ->
293 -- get the current virtual Sp (it might not be zero, eg. if we're
294 -- compiling a let-no-escape).
295 getVirtSp `thenFC` \vSp ->
297 -- Figure out what is needed and what isn't
299 -- SDM: need everything for now in case the heap/stack check refers
301 slow_code_needed = True
302 --slowFunEntryCodeRequired name binder_info entry_conv
303 info_table_needed = True
304 --funInfoTableRequired name binder_info lf_info
306 -- Arg mapping for standard (slow) entry point; all args on stack,
308 (sp_all_args, arg_offsets, arg_tags)
309 = mkTaggedVirtStkOffsets vSp idPrimRep all_args
311 -- Arg mapping for the fast entry point; as many args as poss in
312 -- registers; the rest on the stack
313 -- arg_regs are the registers used for arg passing
314 -- stk_args are the args which are passed on the stack
316 -- Args passed on the stack are tagged, but the tags may not
317 -- actually be present (just gaps) if the function is called
318 -- by jumping directly to the fast entry point.
320 arg_regs = case entry_conv of
321 DirectEntry lbl arity regs -> regs
322 other -> panic "closureCodeBody:arg_regs"
324 num_arg_regs = length arg_regs
326 (reg_args, stk_args) = splitAt num_arg_regs all_args
328 (sp_stk_args, stk_offsets, stk_tags)
329 = mkTaggedVirtStkOffsets vSp idPrimRep stk_args
331 -- HWL; Note: empty list of live regs in slow entry code
332 -- Old version (reschedule combined with heap check);
333 -- see argSatisfactionCheck for new version
334 --slow_entry_code = forceHeapCheck [node] True slow_entry_code'
335 -- where node = UnusedReg PtrRep 1
336 --slow_entry_code = forceHeapCheck [] True slow_entry_code'
339 = profCtrC SLIT("TICK_ENT_FUN_STD") [] `thenC`
341 -- Bind args, and record expected position of stk ptrs
342 mapCs bindNewToStack arg_offsets `thenC`
343 setRealAndVirtualSp sp_all_args `thenC`
345 argSatisfactionCheck closure_info `thenC`
347 -- OK, so there are enough args. Now we need to stuff as
348 -- many of them in registers as the fast-entry code
349 -- expects. Note that the zipWith will give up when it hits
350 -- the end of arg_regs.
352 mapFCs getCAddrMode all_args `thenFC` \ stk_amodes ->
353 absC (mkAbstractCs (zipWith assign_to_reg arg_regs stk_amodes))
356 -- Now adjust real stack pointers
357 adjustRealSp 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 = profCtrC SLIT("TICK_ENT_FUN_DIRECT") [
370 mkIntCLit stg_arity -- total # of args
372 {- CLbl (mkRednCountsLabel name) PtrRep,
373 CString (_PK_ (showSDoc (ppr name))),
374 mkIntCLit stg_arity, -- total # of args
375 mkIntCLit sp_stk_args, -- # passed on stk
376 CString (_PK_ (map (showTypeCategory . idType) all_args)),
377 CString SLIT(""), CString SLIT("")
380 -- Nuked for now; see comment at end of file
381 -- CString (_PK_ (show_wrapper_name wrapper_maybe)),
382 -- CString (_PK_ (show_wrapper_arg_kinds wrapper_maybe))
386 -- Bind args to regs/stack as appropriate, and
387 -- record expected position of sps.
388 bindArgsToRegs reg_args arg_regs `thenC`
389 mapCs bindNewToStack stk_offsets `thenC`
390 setRealAndVirtualSp sp_stk_args `thenC`
392 -- free up the stack slots containing tags
393 freeStackSlots (map fst stk_tags) `thenC`
395 -- Enter the closures cc, if required
396 enterCostCentreCode closure_info cc IsFunction `thenC`
399 funWrapper closure_info arg_regs stk_tags slow_label (cgExpr body)
401 -- Make a labelled code-block for the slow and fast entry code
402 forkAbsC (if slow_code_needed then slow_entry_code else absC AbsCNop)
403 `thenFC` \ slow_abs_c ->
404 forkAbsC fast_entry_code `thenFC` \ fast_abs_c ->
405 moduleName `thenFC` \ mod_name ->
407 -- Now either construct the info table, or put the fast code in alone
408 -- (We never have slow code without an info table)
409 -- XXX probably need the info table and slow entry code in case of
410 -- a heap check failure.
412 if info_table_needed then
413 CClosureInfoAndCode closure_info slow_abs_c (Just fast_abs_c)
416 CCodeBlock fast_label fast_abs_c
419 stg_arity = length all_args
420 lf_info = closureLFInfo closure_info
422 cl_descr mod_name = closureDescription mod_name name
424 -- Manufacture labels
425 name = closureName closure_info
426 fast_label = mkFastEntryLabel name stg_arity
427 slow_label = mkStdEntryLabel name
430 For lexically scoped profiling we have to load the cost centre from
431 the closure entered, if the costs are not supposed to be inherited.
432 This is done immediately on entering the fast entry point.
434 Load current cost centre from closure, if not inherited.
435 Node is guaranteed to point to it, if profiling and not inherited.
438 data IsThunk = IsThunk | IsFunction -- Bool-like, local
443 enterCostCentreCode :: ClosureInfo -> CostCentreStack -> IsThunk -> Code
445 enterCostCentreCode closure_info ccs is_thunk
446 = if not opt_SccProfilingOn then
449 ASSERT(not (noCCSAttached ccs))
451 if isSubsumedCCS ccs then
452 --ASSERT(isToplevClosure closure_info)
453 --ASSERT(is_thunk == IsFunction)
454 (if isToplevClosure closure_info && is_thunk == IsFunction then \x->x
455 else pprTrace "enterCostCenterCode:" (hsep [ppr (is_thunk == IsFunction),
457 costCentresC SLIT("ENTER_CCS_FSUB") []
459 else if isCurrentCCS ccs then
461 then costCentresC SLIT("ENTER_CCS_FCL") [CReg node]
462 else costCentresC SLIT("ENTER_CCS_TCL") [CReg node]
464 else if isCafCCS ccs && isToplevClosure closure_info then
465 ASSERT(is_thunk == IsThunk)
466 -- might be a PAP, in which case we want to subsume costs
468 then costCentresC SLIT("ENTER_CCS_FSUB") []
469 else costCentresC SLIT("ENTER_CCS_CAF") c_ccs
471 else -- we've got a "real" cost centre right here in our hands...
473 IsThunk -> costCentresC SLIT("ENTER_CCS_T") c_ccs
474 IsFunction -> if isCafCCS ccs-- || isDictCC ccs
475 then costCentresC SLIT("ENTER_CCS_FCAF") c_ccs
476 else costCentresC SLIT("ENTER_CCS_FLOAD") c_ccs
478 c_ccs = [mkCCostCentreStack ccs]
479 re_entrant = closureReEntrant closure_info
482 %************************************************************************
484 \subsubsection[pre-closure-code-stuff]{Pre-closure-code code}
486 %************************************************************************
488 The argument-satisfaction check code is placed after binding
489 the arguments to their stack locations. Hence, the virtual stack
490 pointer is pointing after all the args, and virtual offset 1 means
491 the base of frame and hence most distant arg. Hence
492 virtual offset 0 is just beyond the most distant argument; the
493 relative offset of this word tells how many words of arguments
497 argSatisfactionCheck :: ClosureInfo -> Code
499 argSatisfactionCheck closure_info
501 = nodeMustPointToIt (closureLFInfo closure_info) `thenFC` \ node_points ->
504 emit_gran_macros = opt_GranMacros
508 -- absC (CMacroStmt GRAN_FETCH []) `thenC`
509 -- forceHeapCheck [] node_points (absC AbsCNop) `thenC`
512 then fetchAndReschedule [] node_points
513 else yield [] node_points
514 else absC AbsCNop) `thenC`
516 getSpRelOffset 0 `thenFC` \ (SpRel sp) ->
519 rel_arg = mkIntCLit off
523 absC (CMacroStmt ARGS_CHK [rel_arg]) -- node already points
525 absC (CMacroStmt ARGS_CHK_LOAD_NODE [rel_arg, set_Node_to_this])
527 -- We must tell the arg-satis macro whether Node is pointing to
528 -- the closure or not. If it isn't so pointing, then we give to
529 -- the macro the (static) address of the closure.
531 set_Node_to_this = CLbl (closureLabelFromCI closure_info) PtrRep
534 %************************************************************************
536 \subsubsection[closure-code-wrappers]{Wrappers around closure code}
538 %************************************************************************
541 thunkWrapper:: ClosureInfo -> CLabel -> Code -> Code
542 thunkWrapper closure_info label thunk_code
543 = -- Stack and heap overflow checks
544 nodeMustPointToIt (closureLFInfo closure_info) `thenFC` \ node_points ->
547 emit_gran_macros = opt_GranMacros
549 -- HWL: insert macros for GrAnSim; 2 versions depending on liveness of node
550 -- (we prefer fetchAndReschedule-style context switches to yield ones)
553 then fetchAndReschedule [] node_points
554 else yield [] node_points
555 else absC AbsCNop) `thenC`
557 -- stack and/or heap checks
558 thunkChecks label node_points (
560 -- Overwrite with black hole if necessary
561 blackHoleIt closure_info node_points `thenC`
563 setupUpdate closure_info ( -- setupUpdate *encloses* the rest
565 -- Finally, do the business
569 funWrapper :: ClosureInfo -- Closure whose code body this is
570 -> [MagicId] -- List of argument registers (if any)
571 -> [(VirtualSpOffset,Int)] -- tagged stack slots
572 -> CLabel -- slow entry point for heap check ret.
573 -> Code -- Body of function being compiled
575 funWrapper closure_info arg_regs stk_tags slow_label fun_body
576 = -- Stack overflow check
577 nodeMustPointToIt (closureLFInfo closure_info) `thenFC` \ node_points ->
579 emit_gran_macros = opt_GranMacros
583 then yield arg_regs node_points
584 else absC AbsCNop) `thenC`
586 -- heap and/or stack checks
587 fastEntryChecks arg_regs stk_tags slow_label node_points (
589 -- Finally, do the business
595 %************************************************************************
597 \subsubsubsection[update-and-BHs]{Update and black-hole wrappers}
599 %************************************************************************
603 blackHoleIt :: ClosureInfo -> Bool -> Code -- Only called for thunks
604 blackHoleIt closure_info node_points
605 = if blackHoleOnEntry closure_info && node_points
607 absC (if closureSingleEntry(closure_info) then
608 CMacroStmt UPD_BH_SINGLE_ENTRY [CReg node]
610 CMacroStmt UPD_BH_UPDATABLE [CReg node])
616 setupUpdate :: ClosureInfo -> Code -> Code -- Only called for thunks
617 -- Nota Bene: this function does not change Node (even if it's a CAF),
618 -- so that the cost centre in the original closure can still be
619 -- extracted by a subsequent ENTER_CC_TCL
621 setupUpdate closure_info code
622 = if (closureUpdReqd closure_info) then
623 link_caf_if_needed `thenFC` \ update_closure ->
624 pushUpdateFrame update_closure code
626 profCtrC SLIT("TICK_UPDF_OMITTED") [] `thenC`
629 link_caf_if_needed :: FCode CAddrMode -- Returns amode for closure to be updated
631 = if not (isStaticClosure closure_info) then
635 -- First we must allocate a black hole, and link the
636 -- CAF onto the CAF list
638 -- Alloc black hole specifying CC_HDR(Node) as the cost centre
639 -- Hack Warning: Using a CLitLit to get CAddrMode !
641 use_cc = CLitLit SLIT("CCS_HDR(R1.p)") PtrRep
644 allocDynClosure (blackHoleClosureInfo closure_info) use_cc blame_cc []
645 `thenFC` \ heap_offset ->
646 getHpRelOffset heap_offset `thenFC` \ hp_rel ->
647 let amode = CAddr hp_rel
649 absC (CMacroStmt UPD_CAF [CReg node, amode])
654 %************************************************************************
656 \subsection[CgClosure-Description]{Profiling Closure Description.}
658 %************************************************************************
660 For "global" data constructors the description is simply occurrence
661 name of the data constructor itself (see \ref{CgConTbls-info-tables}).
663 Otherwise it is determind by @closureDescription@ from the let
667 closureDescription :: Module -- Module
668 -> Name -- Id of closure binding
671 -- Not called for StgRhsCon which have global info tables built in
672 -- CgConTbls.lhs with a description generated from the data constructor
674 closureDescription mod_name name
684 chooseDynCostCentres ccs args fvs body
686 use_cc -- cost-centre we record in the object
687 = if currentOrSubsumedCCS ccs
688 then CReg CurCostCentre
689 else mkCCostCentreStack ccs
691 blame_cc -- cost-centre on whom we blame the allocation
692 = case (args, fvs, body) of
693 ([], [just1], StgApp fun [{-no args-}])
695 -> mkCCostCentreStack overheadCCS
698 -- if it's an utterly trivial RHS, then it must be
699 -- one introduced by boxHigherOrderArgs for profiling,
700 -- so we charge it to "OVERHEAD".
702 -- This looks like a HACK to me --SDM
709 ========================================================================
710 OLD CODE THAT EMITTED INFORMATON FOR QUANTITATIVE ANALYSIS
712 It's pretty wierd, so I've nuked it for now. SLPJ Nov 96
715 getWrapperArgTypeCategories
716 :: Type -- wrapper's type
717 -> StrictnessInfo bdee -- strictness info about its args
720 getWrapperArgTypeCategories _ NoStrictnessInfo = Nothing
721 getWrapperArgTypeCategories _ BottomGuaranteed
722 = trace "getWrapperArgTypeCategories:BottomGuaranteed!" Nothing -- wrong
723 getWrapperArgTypeCategories _ (StrictnessInfo [] _) = Nothing
725 getWrapperArgTypeCategories ty (StrictnessInfo arg_info _)
726 = Just (mkWrapperArgTypeCategories ty arg_info)
728 mkWrapperArgTypeCategories
729 :: Type -- wrapper's type
730 -> [Demand] -- info about its arguments
731 -> String -- a string saying lots about the args
733 mkWrapperArgTypeCategories wrapper_ty wrap_info
734 = case (splitFunTy_maybe wrapper_ty) of { Just (arg_tys,_) ->
735 map do_one (wrap_info `zip` (map showTypeCategory arg_tys)) }
737 -- ToDo: this needs FIXING UP (it was a hack anyway...)
738 do_one (WwPrim, _) = 'P'
739 do_one (WwEnum, _) = 'E'
740 do_one (WwStrict, arg_ty_char) = arg_ty_char
741 do_one (WwUnpack _ _ _, arg_ty_char)
742 = if arg_ty_char `elem` "CIJFDTS"
743 then toLower arg_ty_char
744 else if arg_ty_char == '+' then 't'
745 else trace ("mkWrapp..:funny char:"++[arg_ty_char]) '-'
746 do_one (other_wrap_info, _) = '-'