2 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
4 % $Id: CgClosure.lhs,v 1.24 1999/03/02 14:34:36 sof 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
79 -> FCode (Id, CgIdInfo)
81 cgTopRhsClosure id ccs binder_info srt args body lf_info
82 = -- LAY OUT THE OBJECT
84 closure_info = layOutStaticNoFVClosure name lf_info
87 -- BUILD THE OBJECT (IF NECESSARY)
88 ({- if staticClosureRequired name binder_info lf_info
90 (if opt_SccProfilingOn
93 closure_label -- Labelled with the name on lhs of defn
95 (mkCCostCentreStack ccs)
99 closure_label -- Labelled with the name on lhs of defn
109 -- GENERATE THE INFO TABLE (IF NECESSARY)
110 forkClosureBody (closureCodeBody binder_info srt closure_info
115 returnFC (id, cg_id_info)
118 closure_label = mkClosureLabel name
119 cg_id_info = stableAmodeIdInfo id (CLbl closure_label PtrRep) lf_info
122 %********************************************************
124 \subsection[non-top-level-closures]{Non top-level closures}
126 %********************************************************
128 For closures with free vars, allocate in heap.
133 -> CostCentreStack -- Optional cost centre annotation
140 -> [StgArg] -- payload
141 -> FCode (Id, CgIdInfo)
143 cgStdRhsClosure binder cc binder_info srt fvs args body lf_info payload
144 -- AHA! A STANDARD-FORM THUNK
146 -- LAY OUT THE OBJECT
147 getArgAmodes payload `thenFC` \ amodes ->
149 (closure_info, amodes_w_offsets)
150 = layOutDynClosure (idName binder) getAmodeRep amodes lf_info
152 (use_cc, blame_cc) = chooseDynCostCentres cc args fvs body
155 allocDynClosure closure_info use_cc blame_cc amodes_w_offsets
157 `thenFC` \ heap_offset ->
160 returnFC (binder, heapIdInfo binder heap_offset lf_info)
163 is_std_thunk = isStandardFormThunk lf_info
166 Here's the general case.
170 -> CostCentreStack -- Optional cost centre annotation
177 -> FCode (Id, CgIdInfo)
179 cgRhsClosure binder cc binder_info srt fvs args body lf_info
181 -- LAY OUT THE OBJECT
183 -- If the binder is itself a free variable, then don't store
184 -- it in the closure. Instead, just bind it to Node on entry.
185 -- NB we can be sure that Node will point to it, because we
186 -- havn't told mkClosureLFInfo about this; so if the binder
187 -- *was* a free var of its RHS, mkClosureLFInfo thinks it *is*
188 -- stored in the closure itself, so it will make sure that
189 -- Node points to it...
191 is_elem = isIn "cgRhsClosure"
193 binder_is_a_fv = binder `is_elem` fvs
194 reduced_fvs = if binder_is_a_fv
195 then fvs `minusList` [binder]
198 mapFCs getCAddrModeAndInfo reduced_fvs `thenFC` \ amodes_and_info ->
200 fvs_w_amodes_and_info = reduced_fvs `zip` amodes_and_info
202 closure_info :: ClosureInfo
203 bind_details :: [((Id, (CAddrMode, LambdaFormInfo)), VirtualHeapOffset)]
205 (closure_info, bind_details)
206 = layOutDynClosure (idName binder) get_kind fvs_w_amodes_and_info lf_info
208 bind_fv ((id, (_, lf_info)), offset) = bindNewToNode id offset lf_info
210 amodes_w_offsets = [(amode,offset) | ((_, (amode,_)), offset) <- bind_details]
212 get_kind (id, amode_and_info) = idPrimRep id
214 -- BUILD ITS INFO TABLE AND CODE
217 mapCs bind_fv bind_details `thenC`
219 -- Bind the binder itself, if it is a free var
220 (if binder_is_a_fv then
221 bindNewToReg binder node lf_info
226 closureCodeBody binder_info srt closure_info cc args body
231 (use_cc, blame_cc) = chooseDynCostCentres cc args fvs body
233 allocDynClosure closure_info use_cc blame_cc amodes_w_offsets
234 ) `thenFC` \ heap_offset ->
237 returnFC (binder, heapIdInfo binder heap_offset lf_info)
240 %************************************************************************
242 \subsection[code-for-closures]{The code for closures}
244 %************************************************************************
247 closureCodeBody :: StgBinderInfo
249 -> ClosureInfo -- Lots of information about this closure
250 -> CostCentreStack -- Optional cost centre attached to closure
256 There are two main cases for the code for closures. If there are {\em
257 no arguments}, then the closure is a thunk, and not in normal form.
258 So it should set up an update frame (if it is shared). Also, it has
259 no argument satisfaction check, so fast and slow entry-point labels
263 closureCodeBody binder_info srt closure_info cc [] body
264 = -- thunks cannot have a primitive type!
265 getAbsC body_code `thenFC` \ body_absC ->
266 moduleName `thenFC` \ mod_name ->
267 getSRTLabel `thenFC` \ srt_label ->
269 absC (CClosureInfoAndCode closure_info body_absC Nothing
270 (srt_label, srt) (cl_descr mod_name))
272 cl_descr mod_name = closureDescription mod_name (closureName closure_info)
274 body_label = entryLabelFromCI closure_info
275 body_code = profCtrC SLIT("TICK_ENT_THK") [] `thenC`
276 thunkWrapper closure_info body_label (
277 -- We only enter cc after setting up update so that cc
278 -- of enclosing scope will be recorded in update frame
279 -- CAF/DICT functions will be subsumed by this enclosing cc
280 enterCostCentreCode closure_info cc IsThunk `thenC`
284 If there is {\em at least one argument}, then this closure is in
285 normal form, so there is no need to set up an update frame. On the
286 other hand, we do have to check that there are enough args, and
287 perform an update if not!
289 The Macros for GrAnSim are produced at the beginning of the
290 argSatisfactionCheck (by calling fetchAndReschedule). There info if
291 Node points to closure is available. -- HWL
294 closureCodeBody binder_info srt closure_info cc all_args body
295 = getEntryConvention name lf_info
296 (map idPrimRep all_args) `thenFC` \ entry_conv ->
298 -- get the current virtual Sp (it might not be zero, eg. if we're
299 -- compiling a let-no-escape).
300 getVirtSp `thenFC` \vSp ->
302 -- Figure out what is needed and what isn't
304 -- SDM: need everything for now in case the heap/stack check refers
306 slow_code_needed = True
307 --slowFunEntryCodeRequired name binder_info entry_conv
308 info_table_needed = True
309 --funInfoTableRequired name binder_info lf_info
311 -- Arg mapping for standard (slow) entry point; all args on stack,
313 (sp_all_args, arg_offsets, arg_tags)
314 = mkTaggedVirtStkOffsets vSp idPrimRep all_args
316 -- Arg mapping for the fast entry point; as many args as poss in
317 -- registers; the rest on the stack
318 -- arg_regs are the registers used for arg passing
319 -- stk_args are the args which are passed on the stack
321 -- Args passed on the stack are tagged, but the tags may not
322 -- actually be present (just gaps) if the function is called
323 -- by jumping directly to the fast entry point.
325 arg_regs = case entry_conv of
326 DirectEntry lbl arity regs -> regs
327 other -> panic "closureCodeBody:arg_regs"
329 num_arg_regs = length arg_regs
331 (reg_args, stk_args) = splitAt num_arg_regs all_args
333 (sp_stk_args, stk_offsets, stk_tags)
334 = mkTaggedVirtStkOffsets vSp idPrimRep stk_args
336 -- HWL; Note: empty list of live regs in slow entry code
337 -- Old version (reschedule combined with heap check);
338 -- see argSatisfactionCheck for new version
339 --slow_entry_code = forceHeapCheck [node] True slow_entry_code'
340 -- where node = UnusedReg PtrRep 1
341 --slow_entry_code = forceHeapCheck [] True slow_entry_code'
344 = profCtrC SLIT("TICK_ENT_FUN_STD") [] `thenC`
346 -- Bind args, and record expected position of stk ptrs
347 mapCs bindNewToStack arg_offsets `thenC`
348 setRealAndVirtualSp sp_all_args `thenC`
350 argSatisfactionCheck closure_info `thenC`
352 -- OK, so there are enough args. Now we need to stuff as
353 -- many of them in registers as the fast-entry code
354 -- expects. Note that the zipWith will give up when it hits
355 -- the end of arg_regs.
357 mapFCs getCAddrMode all_args `thenFC` \ stk_amodes ->
358 absC (mkAbstractCs (zipWith assign_to_reg arg_regs stk_amodes))
361 -- Now adjust real stack pointers
362 adjustRealSp sp_stk_args `thenC`
364 absC (CFallThrough (CLbl fast_label CodePtrRep))
366 assign_to_reg reg_id amode = CAssign (CReg reg_id) amode
369 -- Old version (reschedule combined with heap check);
370 -- see argSatisfactionCheck for new version
371 -- fast_entry_code = forceHeapCheck [] True fast_entry_code'
374 = profCtrC SLIT("TICK_ENT_FUN_DIRECT") [
375 mkIntCLit stg_arity -- total # of args
377 {- CLbl (mkRednCountsLabel name) PtrRep,
378 CString (_PK_ (showSDoc (ppr name))),
379 mkIntCLit stg_arity, -- total # of args
380 mkIntCLit sp_stk_args, -- # passed on stk
381 CString (_PK_ (map (showTypeCategory . idType) all_args)),
382 CString SLIT(""), CString SLIT("")
385 -- Nuked for now; see comment at end of file
386 -- CString (_PK_ (show_wrapper_name wrapper_maybe)),
387 -- CString (_PK_ (show_wrapper_arg_kinds wrapper_maybe))
391 -- Bind args to regs/stack as appropriate, and
392 -- record expected position of sps.
393 bindArgsToRegs reg_args arg_regs `thenC`
394 mapCs bindNewToStack stk_offsets `thenC`
395 setRealAndVirtualSp sp_stk_args `thenC`
397 -- free up the stack slots containing tags
398 freeStackSlots (map fst stk_tags) `thenC`
400 -- Enter the closures cc, if required
401 enterCostCentreCode closure_info cc IsFunction `thenC`
404 funWrapper closure_info arg_regs stk_tags slow_label (cgExpr body)
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 ->
411 getSRTLabel `thenFC` \ srt_label ->
413 -- Now either construct the info table, or put the fast code in alone
414 -- (We never have slow code without an info table)
415 -- XXX probably need the info table and slow entry code in case of
416 -- a heap check failure.
418 if info_table_needed then
419 CClosureInfoAndCode closure_info slow_abs_c (Just fast_abs_c)
420 (srt_label, srt) (cl_descr mod_name)
422 CCodeBlock fast_label fast_abs_c
425 stg_arity = length all_args
426 lf_info = closureLFInfo closure_info
428 cl_descr mod_name = closureDescription mod_name name
430 -- Manufacture labels
431 name = closureName closure_info
432 fast_label = mkFastEntryLabel name stg_arity
433 slow_label = mkStdEntryLabel name
436 For lexically scoped profiling we have to load the cost centre from
437 the closure entered, if the costs are not supposed to be inherited.
438 This is done immediately on entering the fast entry point.
440 Load current cost centre from closure, if not inherited.
441 Node is guaranteed to point to it, if profiling and not inherited.
444 data IsThunk = IsThunk | IsFunction -- Bool-like, local
449 enterCostCentreCode :: ClosureInfo -> CostCentreStack -> IsThunk -> Code
451 enterCostCentreCode closure_info ccs is_thunk
452 = if not opt_SccProfilingOn then
455 ASSERT(not (noCCSAttached ccs))
457 if isSubsumedCCS ccs then
458 --ASSERT(isToplevClosure closure_info)
459 --ASSERT(is_thunk == IsFunction)
460 (if isToplevClosure closure_info && is_thunk == IsFunction then \x->x
461 else pprTrace "enterCostCenterCode:" (hsep [ppr (is_thunk == IsFunction),
463 costCentresC SLIT("ENTER_CCS_FSUB") []
465 else if isCurrentCCS ccs then
466 -- get CCC out of the closure, where we put it when we alloc'd
468 IsThunk -> costCentresC SLIT("ENTER_CCS_TCL") [CReg node]
469 IsFunction -> costCentresC SLIT("ENTER_CCS_FCL") [CReg node]
471 else if isCafCCS ccs && isToplevClosure closure_info then
472 ASSERT(is_thunk == IsThunk)
473 costCentresC SLIT("ENTER_CCS_CAF") c_ccs
475 else -- we've got a "real" cost centre right here in our hands...
477 IsThunk -> costCentresC SLIT("ENTER_CCS_T") c_ccs
478 IsFunction -> if isCafCCS ccs-- || isDictCC ccs
479 then costCentresC SLIT("ENTER_CCS_FCAF") c_ccs
480 else costCentresC SLIT("ENTER_CCS_FLOAD") c_ccs
482 c_ccs = [mkCCostCentreStack ccs]
485 %************************************************************************
487 \subsubsection[pre-closure-code-stuff]{Pre-closure-code code}
489 %************************************************************************
491 The argument-satisfaction check code is placed after binding
492 the arguments to their stack locations. Hence, the virtual stack
493 pointer is pointing after all the args, and virtual offset 1 means
494 the base of frame and hence most distant arg. Hence
495 virtual offset 0 is just beyond the most distant argument; the
496 relative offset of this word tells how many words of arguments
500 argSatisfactionCheck :: ClosureInfo -> Code
502 argSatisfactionCheck closure_info
504 = nodeMustPointToIt (closureLFInfo closure_info) `thenFC` \ node_points ->
507 emit_gran_macros = opt_GranMacros
511 -- absC (CMacroStmt GRAN_FETCH []) `thenC`
512 -- forceHeapCheck [] node_points (absC AbsCNop) `thenC`
515 then fetchAndReschedule [] node_points
516 else yield [] node_points
517 else absC AbsCNop) `thenC`
519 getSpRelOffset 0 `thenFC` \ (SpRel sp) ->
522 rel_arg = mkIntCLit off
526 absC (CMacroStmt ARGS_CHK [rel_arg]) -- node already points
528 absC (CMacroStmt ARGS_CHK_LOAD_NODE [rel_arg, set_Node_to_this])
530 -- We must tell the arg-satis macro whether Node is pointing to
531 -- the closure or not. If it isn't so pointing, then we give to
532 -- the macro the (static) address of the closure.
534 set_Node_to_this = CLbl (closureLabelFromCI closure_info) PtrRep
537 %************************************************************************
539 \subsubsection[closure-code-wrappers]{Wrappers around closure code}
541 %************************************************************************
544 thunkWrapper:: ClosureInfo -> CLabel -> Code -> Code
545 thunkWrapper closure_info label thunk_code
546 = -- Stack and heap overflow checks
547 nodeMustPointToIt (closureLFInfo closure_info) `thenFC` \ node_points ->
550 emit_gran_macros = opt_GranMacros
552 -- HWL: insert macros for GrAnSim; 2 versions depending on liveness of node
553 -- (we prefer fetchAndReschedule-style context switches to yield ones)
556 then fetchAndReschedule [] node_points
557 else yield [] node_points
558 else absC AbsCNop) `thenC`
560 -- stack and/or heap checks
561 thunkChecks label node_points (
563 -- Overwrite with black hole if necessary
564 blackHoleIt closure_info node_points `thenC`
566 setupUpdate closure_info ( -- setupUpdate *encloses* the rest
568 -- Finally, do the business
572 funWrapper :: ClosureInfo -- Closure whose code body this is
573 -> [MagicId] -- List of argument registers (if any)
574 -> [(VirtualSpOffset,Int)] -- tagged stack slots
575 -> CLabel -- slow entry point for heap check ret.
576 -> Code -- Body of function being compiled
578 funWrapper closure_info arg_regs stk_tags slow_label fun_body
579 = -- Stack overflow check
580 nodeMustPointToIt (closureLFInfo closure_info) `thenFC` \ node_points ->
582 emit_gran_macros = opt_GranMacros
586 then yield arg_regs node_points
587 else absC AbsCNop) `thenC`
589 -- heap and/or stack checks
590 fastEntryChecks arg_regs stk_tags slow_label node_points (
592 -- Finally, do the business
598 %************************************************************************
600 \subsubsubsection[update-and-BHs]{Update and black-hole wrappers}
602 %************************************************************************
606 blackHoleIt :: ClosureInfo -> Bool -> Code -- Only called for thunks
607 blackHoleIt closure_info node_points
608 = if blackHoleOnEntry closure_info && node_points
610 absC (if closureSingleEntry(closure_info) then
611 CMacroStmt UPD_BH_SINGLE_ENTRY [CReg node]
613 CMacroStmt UPD_BH_UPDATABLE [CReg node])
619 setupUpdate :: ClosureInfo -> Code -> Code -- Only called for thunks
620 -- Nota Bene: this function does not change Node (even if it's a CAF),
621 -- so that the cost centre in the original closure can still be
622 -- extracted by a subsequent ENTER_CC_TCL
624 setupUpdate closure_info code
625 = if (closureUpdReqd closure_info) then
626 link_caf_if_needed `thenFC` \ update_closure ->
627 pushUpdateFrame update_closure code
629 profCtrC SLIT("TICK_UPDF_OMITTED") [] `thenC`
632 link_caf_if_needed :: FCode CAddrMode -- Returns amode for closure to be updated
634 = if not (isStaticClosure closure_info) then
638 -- First we must allocate a black hole, and link the
639 -- CAF onto the CAF list
641 -- Alloc black hole specifying CC_HDR(Node) as the cost centre
642 -- Hack Warning: Using a CLitLit to get CAddrMode !
644 use_cc = CLitLit SLIT("CCS_HDR(R1.p)") PtrRep
647 allocDynClosure (blackHoleClosureInfo closure_info) use_cc blame_cc []
648 `thenFC` \ heap_offset ->
649 getHpRelOffset heap_offset `thenFC` \ hp_rel ->
650 let amode = CAddr hp_rel
652 absC (CMacroStmt UPD_CAF [CReg node, amode])
657 %************************************************************************
659 \subsection[CgClosure-Description]{Profiling Closure Description.}
661 %************************************************************************
663 For "global" data constructors the description is simply occurrence
664 name of the data constructor itself (see \ref{CgConTbls-info-tables}).
666 Otherwise it is determind by @closureDescription@ from the let
670 closureDescription :: Module -- Module
671 -> Name -- Id of closure binding
674 -- Not called for StgRhsCon which have global info tables built in
675 -- CgConTbls.lhs with a description generated from the data constructor
677 closureDescription mod_name name
687 chooseDynCostCentres ccs args fvs body
689 use_cc -- cost-centre we record in the object
690 = if currentOrSubsumedCCS ccs
691 then CReg CurCostCentre
692 else mkCCostCentreStack ccs
694 blame_cc -- cost-centre on whom we blame the allocation
695 = case (args, fvs, body) of
696 ([], [just1], StgApp fun [{-no args-}])
698 -> mkCCostCentreStack overheadCCS
701 -- if it's an utterly trivial RHS, then it must be
702 -- one introduced by boxHigherOrderArgs for profiling,
703 -- so we charge it to "OVERHEAD".
705 -- This looks like a HACK to me --SDM
712 ========================================================================
713 OLD CODE THAT EMITTED INFORMATON FOR QUANTITATIVE ANALYSIS
715 It's pretty wierd, so I've nuked it for now. SLPJ Nov 96
718 getWrapperArgTypeCategories
719 :: Type -- wrapper's type
720 -> StrictnessInfo bdee -- strictness info about its args
723 getWrapperArgTypeCategories _ NoStrictnessInfo = Nothing
724 getWrapperArgTypeCategories _ BottomGuaranteed
725 = trace "getWrapperArgTypeCategories:BottomGuaranteed!" Nothing -- wrong
726 getWrapperArgTypeCategories _ (StrictnessInfo [] _) = Nothing
728 getWrapperArgTypeCategories ty (StrictnessInfo arg_info _)
729 = Just (mkWrapperArgTypeCategories ty arg_info)
731 mkWrapperArgTypeCategories
732 :: Type -- wrapper's type
733 -> [Demand] -- info about its arguments
734 -> String -- a string saying lots about the args
736 mkWrapperArgTypeCategories wrapper_ty wrap_info
737 = case (splitFunTy_maybe wrapper_ty) of { Just (arg_tys,_) ->
738 map do_one (wrap_info `zip` (map showTypeCategory arg_tys)) }
740 -- ToDo: this needs FIXING UP (it was a hack anyway...)
741 do_one (WwPrim, _) = 'P'
742 do_one (WwEnum, _) = 'E'
743 do_one (WwStrict, arg_ty_char) = arg_ty_char
744 do_one (WwUnpack _ _ _, arg_ty_char)
745 = if arg_ty_char `elem` "CIJFDTS"
746 then toLower arg_ty_char
747 else if arg_ty_char == '+' then 't'
748 else trace ("mkWrapp..:funny char:"++[arg_ty_char]) '-'
749 do_one (other_wrap_info, _) = '-'