2 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
4 % $Id: CgClosure.lhs,v 1.28 1999/04/23 09:51:24 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 is_box = case body of { StgApp fun [] -> True; _ -> False }
272 body_code = profCtrC SLIT("TICK_ENT_THK") [] `thenC`
273 thunkWrapper closure_info body_label (
274 -- We only enter cc after setting up update so that cc
275 -- of enclosing scope will be recorded in update frame
276 -- CAF/DICT functions will be subsumed by this enclosing cc
277 enterCostCentreCode closure_info cc IsThunk is_box `thenC`
281 If there is {\em at least one argument}, then this closure is in
282 normal form, so there is no need to set up an update frame. On the
283 other hand, we do have to check that there are enough args, and
284 perform an update if not!
286 The Macros for GrAnSim are produced at the beginning of the
287 argSatisfactionCheck (by calling fetchAndReschedule). There info if
288 Node points to closure is available. -- HWL
291 closureCodeBody binder_info closure_info cc all_args body
292 = getEntryConvention name lf_info
293 (map idPrimRep all_args) `thenFC` \ entry_conv ->
295 -- get the current virtual Sp (it might not be zero, eg. if we're
296 -- compiling a let-no-escape).
297 getVirtSp `thenFC` \vSp ->
299 -- Figure out what is needed and what isn't
301 -- SDM: need everything for now in case the heap/stack check refers
303 slow_code_needed = True
304 --slowFunEntryCodeRequired name binder_info entry_conv
305 info_table_needed = True
306 --funInfoTableRequired name binder_info lf_info
308 -- Arg mapping for standard (slow) entry point; all args on stack,
310 (sp_all_args, arg_offsets, arg_tags)
311 = mkTaggedVirtStkOffsets vSp idPrimRep all_args
313 -- Arg mapping for the fast entry point; as many args as poss in
314 -- registers; the rest on the stack
315 -- arg_regs are the registers used for arg passing
316 -- stk_args are the args which are passed on the stack
318 -- Args passed on the stack are tagged, but the tags may not
319 -- actually be present (just gaps) if the function is called
320 -- by jumping directly to the fast entry point.
322 arg_regs = case entry_conv of
323 DirectEntry lbl arity regs -> regs
324 other -> panic "closureCodeBody:arg_regs"
326 num_arg_regs = length arg_regs
328 (reg_args, stk_args) = splitAt num_arg_regs all_args
330 (sp_stk_args, stk_offsets, stk_tags)
331 = mkTaggedVirtStkOffsets vSp idPrimRep stk_args
333 -- HWL; Note: empty list of live regs in slow entry code
334 -- Old version (reschedule combined with heap check);
335 -- see argSatisfactionCheck for new version
336 --slow_entry_code = forceHeapCheck [node] True slow_entry_code'
337 -- where node = UnusedReg PtrRep 1
338 --slow_entry_code = forceHeapCheck [] True slow_entry_code'
341 = profCtrC SLIT("TICK_ENT_FUN_STD") [] `thenC`
343 -- Bind args, and record expected position of stk ptrs
344 mapCs bindNewToStack arg_offsets `thenC`
345 setRealAndVirtualSp sp_all_args `thenC`
347 argSatisfactionCheck closure_info `thenC`
349 -- OK, so there are enough args. Now we need to stuff as
350 -- many of them in registers as the fast-entry code
351 -- expects. Note that the zipWith will give up when it hits
352 -- the end of arg_regs.
354 mapFCs getCAddrMode all_args `thenFC` \ stk_amodes ->
355 absC (mkAbstractCs (zipWith assign_to_reg arg_regs stk_amodes))
358 -- Now adjust real stack pointers
359 adjustRealSp sp_stk_args `thenC`
361 absC (CFallThrough (CLbl fast_label CodePtrRep))
363 assign_to_reg reg_id amode = CAssign (CReg reg_id) amode
366 -- Old version (reschedule combined with heap check);
367 -- see argSatisfactionCheck for new version
368 -- fast_entry_code = forceHeapCheck [] True fast_entry_code'
371 = profCtrC SLIT("TICK_ENT_FUN_DIRECT") [
372 mkIntCLit stg_arity -- total # of args
374 {- CLbl (mkRednCountsLabel name) PtrRep,
375 CString (_PK_ (showSDoc (ppr name))),
376 mkIntCLit stg_arity, -- total # of args
377 mkIntCLit sp_stk_args, -- # passed on stk
378 CString (_PK_ (map (showTypeCategory . idType) all_args)),
379 CString SLIT(""), CString SLIT("")
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))
388 -- Bind args to regs/stack as appropriate, and
389 -- record expected position of sps.
390 bindArgsToRegs reg_args arg_regs `thenC`
391 mapCs bindNewToStack stk_offsets `thenC`
392 setRealAndVirtualSp sp_stk_args `thenC`
394 -- free up the stack slots containing tags
395 freeStackSlots (map fst stk_tags) `thenC`
397 -- Enter the closures cc, if required
398 enterCostCentreCode closure_info cc IsFunction False `thenC`
401 funWrapper closure_info arg_regs stk_tags slow_label (cgExpr body)
403 -- Make a labelled code-block for the slow and fast entry code
404 forkAbsC (if slow_code_needed then slow_entry_code else absC AbsCNop)
405 `thenFC` \ slow_abs_c ->
406 forkAbsC fast_entry_code `thenFC` \ fast_abs_c ->
407 moduleName `thenFC` \ mod_name ->
409 -- Now either construct the info table, or put the fast code in alone
410 -- (We never have slow code without an info table)
411 -- XXX probably need the info table and slow entry code in case of
412 -- a heap check failure.
414 if info_table_needed then
415 CClosureInfoAndCode closure_info slow_abs_c (Just fast_abs_c)
418 CCodeBlock fast_label fast_abs_c
421 stg_arity = length all_args
422 lf_info = closureLFInfo closure_info
424 cl_descr mod_name = closureDescription mod_name name
426 -- Manufacture labels
427 name = closureName closure_info
428 fast_label = mkFastEntryLabel name stg_arity
429 slow_label = mkStdEntryLabel name
432 For lexically scoped profiling we have to load the cost centre from
433 the closure entered, if the costs are not supposed to be inherited.
434 This is done immediately on entering the fast entry point.
436 Load current cost centre from closure, if not inherited.
437 Node is guaranteed to point to it, if profiling and not inherited.
440 data IsThunk = IsThunk | IsFunction -- Bool-like, local
446 :: ClosureInfo -> CostCentreStack
448 -> Bool -- is_box: this closure is a special box introduced by SCCfinal
451 enterCostCentreCode closure_info ccs is_thunk is_box
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 costCentresC SLIT("ENTER_CCS_FSUB") []
462 else if isCurrentCCS ccs then
463 if re_entrant && not is_box
464 then costCentresC SLIT("ENTER_CCS_FCL") [CReg node]
465 else costCentresC SLIT("ENTER_CCS_TCL") [CReg node]
467 else if isCafCCS ccs then
468 ASSERT(isToplevClosure closure_info)
469 ASSERT(is_thunk == IsThunk)
470 -- might be a PAP, in which case we want to subsume costs
472 then costCentresC SLIT("ENTER_CCS_FSUB") []
473 else costCentresC SLIT("ENTER_CCS_CAF") c_ccs
475 else panic "enterCostCentreCode"
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 ([], _, StgApp fun [{-no args-}])
694 -> mkCCostCentreStack overheadCCS
697 -- if it's an utterly trivial RHS, then it must be
698 -- one introduced by boxHigherOrderArgs for profiling,
699 -- so we charge it to "OVERHEAD".
701 -- This looks like a HACK to me --SDM
708 ========================================================================
709 OLD CODE THAT EMITTED INFORMATON FOR QUANTITATIVE ANALYSIS
711 It's pretty wierd, so I've nuked it for now. SLPJ Nov 96
714 getWrapperArgTypeCategories
715 :: Type -- wrapper's type
716 -> StrictnessInfo bdee -- strictness info about its args
719 getWrapperArgTypeCategories _ NoStrictnessInfo = Nothing
720 getWrapperArgTypeCategories _ BottomGuaranteed
721 = trace "getWrapperArgTypeCategories:BottomGuaranteed!" Nothing -- wrong
722 getWrapperArgTypeCategories _ (StrictnessInfo [] _) = Nothing
724 getWrapperArgTypeCategories ty (StrictnessInfo arg_info _)
725 = Just (mkWrapperArgTypeCategories ty arg_info)
727 mkWrapperArgTypeCategories
728 :: Type -- wrapper's type
729 -> [Demand] -- info about its arguments
730 -> String -- a string saying lots about the args
732 mkWrapperArgTypeCategories wrapper_ty wrap_info
733 = case (splitFunTy_maybe wrapper_ty) of { Just (arg_tys,_) ->
734 map do_one (wrap_info `zip` (map showTypeCategory arg_tys)) }
736 -- ToDo: this needs FIXING UP (it was a hack anyway...)
737 do_one (WwPrim, _) = 'P'
738 do_one (WwEnum, _) = 'E'
739 do_one (WwStrict, arg_ty_char) = arg_ty_char
740 do_one (WwUnpack _ _ _, arg_ty_char)
741 = if arg_ty_char `elem` "CIJFDTS"
742 then toLower arg_ty_char
743 else if arg_ty_char == '+' then 't'
744 else trace ("mkWrapp..:funny char:"++[arg_ty_char]) '-'
745 do_one (other_wrap_info, _) = '-'