2 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
4 % $Id: CgClosure.lhs,v 1.25 1999/03/11 11:32:25 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
460 -- get CCC out of the closure, where we put it when we alloc'd
462 IsThunk -> costCentresC SLIT("ENTER_CCS_TCL") [CReg node]
463 IsFunction -> costCentresC SLIT("ENTER_CCS_FCL") [CReg node]
465 else if isCafCCS ccs && isToplevClosure closure_info then
466 ASSERT(is_thunk == IsThunk)
467 costCentresC SLIT("ENTER_CCS_CAF") c_ccs
469 else -- we've got a "real" cost centre right here in our hands...
471 IsThunk -> costCentresC SLIT("ENTER_CCS_T") c_ccs
472 IsFunction -> if isCafCCS ccs-- || isDictCC ccs
473 then costCentresC SLIT("ENTER_CCS_FCAF") c_ccs
474 else costCentresC SLIT("ENTER_CCS_FLOAD") c_ccs
476 c_ccs = [mkCCostCentreStack ccs]
479 %************************************************************************
481 \subsubsection[pre-closure-code-stuff]{Pre-closure-code code}
483 %************************************************************************
485 The argument-satisfaction check code is placed after binding
486 the arguments to their stack locations. Hence, the virtual stack
487 pointer is pointing after all the args, and virtual offset 1 means
488 the base of frame and hence most distant arg. Hence
489 virtual offset 0 is just beyond the most distant argument; the
490 relative offset of this word tells how many words of arguments
494 argSatisfactionCheck :: ClosureInfo -> Code
496 argSatisfactionCheck closure_info
498 = nodeMustPointToIt (closureLFInfo closure_info) `thenFC` \ node_points ->
501 emit_gran_macros = opt_GranMacros
505 -- absC (CMacroStmt GRAN_FETCH []) `thenC`
506 -- forceHeapCheck [] node_points (absC AbsCNop) `thenC`
509 then fetchAndReschedule [] node_points
510 else yield [] node_points
511 else absC AbsCNop) `thenC`
513 getSpRelOffset 0 `thenFC` \ (SpRel sp) ->
516 rel_arg = mkIntCLit off
520 absC (CMacroStmt ARGS_CHK [rel_arg]) -- node already points
522 absC (CMacroStmt ARGS_CHK_LOAD_NODE [rel_arg, set_Node_to_this])
524 -- We must tell the arg-satis macro whether Node is pointing to
525 -- the closure or not. If it isn't so pointing, then we give to
526 -- the macro the (static) address of the closure.
528 set_Node_to_this = CLbl (closureLabelFromCI closure_info) PtrRep
531 %************************************************************************
533 \subsubsection[closure-code-wrappers]{Wrappers around closure code}
535 %************************************************************************
538 thunkWrapper:: ClosureInfo -> CLabel -> Code -> Code
539 thunkWrapper closure_info label thunk_code
540 = -- Stack and heap overflow checks
541 nodeMustPointToIt (closureLFInfo closure_info) `thenFC` \ node_points ->
544 emit_gran_macros = opt_GranMacros
546 -- HWL: insert macros for GrAnSim; 2 versions depending on liveness of node
547 -- (we prefer fetchAndReschedule-style context switches to yield ones)
550 then fetchAndReschedule [] node_points
551 else yield [] node_points
552 else absC AbsCNop) `thenC`
554 -- stack and/or heap checks
555 thunkChecks label node_points (
557 -- Overwrite with black hole if necessary
558 blackHoleIt closure_info node_points `thenC`
560 setupUpdate closure_info ( -- setupUpdate *encloses* the rest
562 -- Finally, do the business
566 funWrapper :: ClosureInfo -- Closure whose code body this is
567 -> [MagicId] -- List of argument registers (if any)
568 -> [(VirtualSpOffset,Int)] -- tagged stack slots
569 -> CLabel -- slow entry point for heap check ret.
570 -> Code -- Body of function being compiled
572 funWrapper closure_info arg_regs stk_tags slow_label fun_body
573 = -- Stack overflow check
574 nodeMustPointToIt (closureLFInfo closure_info) `thenFC` \ node_points ->
576 emit_gran_macros = opt_GranMacros
580 then yield arg_regs node_points
581 else absC AbsCNop) `thenC`
583 -- heap and/or stack checks
584 fastEntryChecks arg_regs stk_tags slow_label node_points (
586 -- Finally, do the business
592 %************************************************************************
594 \subsubsubsection[update-and-BHs]{Update and black-hole wrappers}
596 %************************************************************************
600 blackHoleIt :: ClosureInfo -> Bool -> Code -- Only called for thunks
601 blackHoleIt closure_info node_points
602 = if blackHoleOnEntry closure_info && node_points
604 absC (if closureSingleEntry(closure_info) then
605 CMacroStmt UPD_BH_SINGLE_ENTRY [CReg node]
607 CMacroStmt UPD_BH_UPDATABLE [CReg node])
613 setupUpdate :: ClosureInfo -> Code -> Code -- Only called for thunks
614 -- Nota Bene: this function does not change Node (even if it's a CAF),
615 -- so that the cost centre in the original closure can still be
616 -- extracted by a subsequent ENTER_CC_TCL
618 setupUpdate closure_info code
619 = if (closureUpdReqd closure_info) then
620 link_caf_if_needed `thenFC` \ update_closure ->
621 pushUpdateFrame update_closure code
623 profCtrC SLIT("TICK_UPDF_OMITTED") [] `thenC`
626 link_caf_if_needed :: FCode CAddrMode -- Returns amode for closure to be updated
628 = if not (isStaticClosure closure_info) then
632 -- First we must allocate a black hole, and link the
633 -- CAF onto the CAF list
635 -- Alloc black hole specifying CC_HDR(Node) as the cost centre
636 -- Hack Warning: Using a CLitLit to get CAddrMode !
638 use_cc = CLitLit SLIT("CCS_HDR(R1.p)") PtrRep
641 allocDynClosure (blackHoleClosureInfo closure_info) use_cc blame_cc []
642 `thenFC` \ heap_offset ->
643 getHpRelOffset heap_offset `thenFC` \ hp_rel ->
644 let amode = CAddr hp_rel
646 absC (CMacroStmt UPD_CAF [CReg node, amode])
651 %************************************************************************
653 \subsection[CgClosure-Description]{Profiling Closure Description.}
655 %************************************************************************
657 For "global" data constructors the description is simply occurrence
658 name of the data constructor itself (see \ref{CgConTbls-info-tables}).
660 Otherwise it is determind by @closureDescription@ from the let
664 closureDescription :: Module -- Module
665 -> Name -- Id of closure binding
668 -- Not called for StgRhsCon which have global info tables built in
669 -- CgConTbls.lhs with a description generated from the data constructor
671 closureDescription mod_name name
681 chooseDynCostCentres ccs args fvs body
683 use_cc -- cost-centre we record in the object
684 = if currentOrSubsumedCCS ccs
685 then CReg CurCostCentre
686 else mkCCostCentreStack ccs
688 blame_cc -- cost-centre on whom we blame the allocation
689 = case (args, fvs, body) of
690 ([], [just1], StgApp fun [{-no args-}])
692 -> mkCCostCentreStack overheadCCS
695 -- if it's an utterly trivial RHS, then it must be
696 -- one introduced by boxHigherOrderArgs for profiling,
697 -- so we charge it to "OVERHEAD".
699 -- This looks like a HACK to me --SDM
706 ========================================================================
707 OLD CODE THAT EMITTED INFORMATON FOR QUANTITATIVE ANALYSIS
709 It's pretty wierd, so I've nuked it for now. SLPJ Nov 96
712 getWrapperArgTypeCategories
713 :: Type -- wrapper's type
714 -> StrictnessInfo bdee -- strictness info about its args
717 getWrapperArgTypeCategories _ NoStrictnessInfo = Nothing
718 getWrapperArgTypeCategories _ BottomGuaranteed
719 = trace "getWrapperArgTypeCategories:BottomGuaranteed!" Nothing -- wrong
720 getWrapperArgTypeCategories _ (StrictnessInfo [] _) = Nothing
722 getWrapperArgTypeCategories ty (StrictnessInfo arg_info _)
723 = Just (mkWrapperArgTypeCategories ty arg_info)
725 mkWrapperArgTypeCategories
726 :: Type -- wrapper's type
727 -> [Demand] -- info about its arguments
728 -> String -- a string saying lots about the args
730 mkWrapperArgTypeCategories wrapper_ty wrap_info
731 = case (splitFunTy_maybe wrapper_ty) of { Just (arg_tys,_) ->
732 map do_one (wrap_info `zip` (map showTypeCategory arg_tys)) }
734 -- ToDo: this needs FIXING UP (it was a hack anyway...)
735 do_one (WwPrim, _) = 'P'
736 do_one (WwEnum, _) = 'E'
737 do_one (WwStrict, arg_ty_char) = arg_ty_char
738 do_one (WwUnpack _ _ _, arg_ty_char)
739 = if arg_ty_char `elem` "CIJFDTS"
740 then toLower arg_ty_char
741 else if arg_ty_char == '+' then 't'
742 else trace ("mkWrapp..:funny char:"++[arg_ty_char]) '-'
743 do_one (other_wrap_info, _) = '-'