%
-% (c) The GRASP/AQUA Project, Glasgow University, 1992-1995
+% (c) The GRASP/AQUA Project, Glasgow University, 1992-1996
%
\section[CgClosure]{Code generation for closures}
@CgCon@, which deals with constructors.
\begin{code}
-#include "HsVersions.h"
-
module CgClosure ( cgTopRhsClosure, cgRhsClosure ) where
-IMP_Ubiq(){-uitous-}
-IMPORT_DELOOPER(CgLoop2) ( cgExpr, cgSccExpr )
+#include "HsVersions.h"
+
+import {-# SOURCE #-} CgExpr ( cgExpr )
import CgMonad
import AbsCSyn
getCAddrModeAndInfo, bindNewToNode,
bindNewToAStack, bindNewToBStack,
bindNewToReg, bindArgsToRegs,
- stableAmodeIdInfo, heapIdInfo
+ stableAmodeIdInfo, heapIdInfo, CgIdInfo
)
-import CgCompInfo ( spARelToInt, spBRelToInt )
+import Constants ( spARelToInt, spBRelToInt )
import CgUpdate ( pushUpdateFrame )
import CgHeapery ( allocDynClosure, heapCheck
, heapCheckOnly, fetchAndReschedule, yield -- HWL
)
-import CgRetConv ( mkLiveRegsMask,
- ctrlReturnConvAlg, dataReturnConvAlg,
+import CgRetConv ( ctrlReturnConvAlg, dataReturnConvAlg,
CtrlReturnConvention(..), DataReturnConvention(..)
)
import CgStackery ( getFinalStackHW, mkVirtStkOffsets,
getSpARelOffset, getSpBRelOffset,
getHpRelOffset
)
-import CLabel ( mkClosureLabel, mkConUpdCodePtrVecLabel,
+import CLabel ( mkClosureLabel, mkConUpdCodePtrVecLabel, mkFastEntryLabel,
mkStdUpdCodePtrVecLabel, mkStdUpdVecTblLabel,
mkErrorStdEntryLabel, mkRednCountsLabel
)
import CmdLineOpts ( opt_ForConcurrent, opt_GranMacros )
import CostCentre ( useCurrentCostCentre, currentOrSubsumedCosts,
noCostCentreAttached, costsAreSubsumed,
- isCafCC, overheadCostCentre
+ isCafCC, isDictCC, overheadCostCentre, showCostCentre,
+ CostCentre
)
-import HeapOffs ( VirtualHeapOffset(..) )
+import HeapOffs ( VirtualHeapOffset )
import Id ( idType, idPrimRep,
showId, getIdStrictness, dataConTag,
emptyIdSet,
- GenId{-instance Outputable-}
+ Id
)
import ListSetOps ( minusList )
import Maybes ( maybeToBool )
-import PprStyle ( PprStyle(..) )
-import PprType ( GenType{-instance Outputable-}, TyCon{-ditto-} )
-import Pretty ( prettyToUn, ppBesides, ppChar, ppPStr )
import PrimRep ( isFollowableRep, PrimRep(..) )
import TyCon ( isPrimTyCon, tyConDataCons )
-import Unpretty ( uppShow )
-import Util ( isIn, panic, pprPanic, assertPanic )
+import Type ( showTypeCategory )
+import Util ( isIn )
+import Outputable
-myWrapperMaybe = panic "CgClosure.myWrapperMaybe (ToDo)"
-showTypeCategory = panic "CgClosure.showTypeCategory (ToDo)"
getWrapperArgTypeCategories = panic "CgClosure.getWrapperArgTypeCategories (ToDo)"
\end{code}
-- Don't build Vap info tables etc for
-- a function whose result is an unboxed type,
-- because we can never have thunks with such a type.
- (if closureReturnsUnboxedType closure_info then
+ (if closureReturnsUnpointedType closure_info then
nopC
else
let
-- Don't build Vap info tables etc for
-- a function whose result is an unboxed type,
-- because we can never have thunks with such a type.
- (if closureReturnsUnboxedType closure_info then
+ (if closureReturnsUnpointedType closure_info then
nopC
else
cgVapInfoTables False {- Not top level -} nopC binder_info binder args lf_info
-- If f is not top-level, then f is one of the free variables too,
-- hence "payload_ids" isn't the same as "arg_ids".
--
- vap_entry_rhs = StgApp (StgVarArg fun) (map StgVarArg args) emptyIdSet
+ stg_args = map StgVarArg args
+ vap_entry_rhs = StgApp (StgVarArg fun) stg_args emptyIdSet
-- Empty live vars
arg_ids_w_info = [(name,mkLFArgument) | name <- args]
payload_ids | fun_in_payload = fun : args -- Sigh; needed for mkClosureLFInfo
| otherwise = args
- vap_lf_info = mkClosureLFInfo False {-not top level-} payload_ids
- upd_flag [] vap_entry_rhs
+ vap_lf_info = mkVapLFInfo payload_ids upd_flag fun stg_args fun_in_payload
-- It's not top level, even if we're currently compiling a top-level
-- function, because any VAP *use* of this function will be for a
-- local thunk, thus
Just (tc,_,_) -> (True, tc)
in
if has_tycon && isPrimTyCon tycon then
- pprPanic "closureCodeBody:thunk:prim type!" (ppr PprDebug tycon)
+ pprPanic "closureCodeBody:thunk:prim type!" (ppr tycon)
else
#endif
getAbsC body_code `thenFC` \ body_absC ->
body_addr = CLbl (entryLabelFromCI closure_info) CodePtrRep
body_code = profCtrC SLIT("ENT_THK") [] `thenC`
- enterCostCentreCode closure_info cc IsThunk `thenC`
- thunkWrapper closure_info (cgSccExpr body)
+ thunkWrapper closure_info (
+ -- We only enter cc after setting up update so that cc
+ -- of enclosing scope will be recorded in update frame
+ -- CAF/DICT functions will be subsumed by this enclosing cc
+ enterCostCentreCode closure_info cc IsThunk `thenC`
+ cgExpr body)
stdUpd = CLbl mkErrorStdEntryLabel CodePtrRep
\end{code}
= getEntryConvention id lf_info
(map idPrimRep all_args) `thenFC` \ entry_conv ->
let
- is_concurrent = opt_ForConcurrent
-
- stg_arity = length all_args
+ -- Figure out what is needed and what isn't
+ slow_code_needed = slowFunEntryCodeRequired id binder_info entry_conv
+ info_table_needed = funInfoTableRequired id binder_info lf_info
-- Arg mapping for standard (slow) entry point; all args on stack
(spA_all_args, spB_all_args, all_bxd_w_offsets, all_ubxd_w_offsets)
-- Old version (reschedule combined with heap check);
-- see argSatisfactionCheck for new version
--slow_entry_code = forceHeapCheck [node] True slow_entry_code'
- -- where node = VanillaReg PtrRep 1
+ -- where node = UnusedReg PtrRep 1
--slow_entry_code = forceHeapCheck [] True slow_entry_code'
slow_entry_code
fast_entry_code
= profCtrC SLIT("ENT_FUN_DIRECT") [
CLbl (mkRednCountsLabel id) PtrRep,
- CString (_PK_ (showId PprDebug id)),
+ CString (_PK_ (showId id)),
mkIntCLit stg_arity, -- total # of args
mkIntCLit spA_stk_args, -- # passed on A stk
mkIntCLit spB_stk_args, -- B stk (rest in regs)
CString (_PK_ (map (showTypeCategory . idType) all_args)),
- CString (_PK_ (show_wrapper_name wrapper_maybe)),
- CString (_PK_ (show_wrapper_arg_kinds wrapper_maybe))
+ CString SLIT(""), CString SLIT("")
+
+-- Nuked for now; see comment at end of file
+-- CString (_PK_ (show_wrapper_name wrapper_maybe)),
+-- CString (_PK_ (show_wrapper_arg_kinds wrapper_maybe))
+
] `thenC`
-- Bind args to regs/stack as appropriate, and
CCodeBlock fast_label fast_abs_c
)
where
+ is_concurrent = opt_ForConcurrent
+ stg_arity = length all_args
lf_info = closureLFInfo closure_info
cl_descr mod_name = closureDescription mod_name id all_args body
- -- Figure out what is needed and what isn't
- slow_code_needed = slowFunEntryCodeRequired id binder_info
- info_table_needed = funInfoTableRequired id binder_info lf_info
-
-- Manufacture labels
id = closureId closure_info
+ fast_label = mkFastEntryLabel id stg_arity
+ stdUpd = CLbl mkErrorStdEntryLabel CodePtrRep
- fast_label = fastLabelFromCI closure_info
-
- stdUpd = CLbl mkErrorStdEntryLabel CodePtrRep
-
+{- OLD... see note at end of file
wrapper_maybe = get_ultimate_wrapper Nothing id
where
get_ultimate_wrapper deflt x -- walk all the way up a "wrapper chain"
- = case (myWrapperMaybe x) of
+ = case myWrapperMaybe x of
Nothing -> deflt
Just xx -> get_ultimate_wrapper (Just xx) xx
show_wrapper_name Nothing = ""
- show_wrapper_name (Just xx) = showId PprDebug xx
+ show_wrapper_name (Just xx) = showId xx
show_wrapper_arg_kinds Nothing = ""
show_wrapper_arg_kinds (Just xx)
= case (getWrapperArgTypeCategories (idType xx) (getIdStrictness xx)) of
Nothing -> ""
Just str -> str
+-}
\end{code}
For lexically scoped profiling we have to load the cost centre from
\begin{code}
data IsThunk = IsThunk | IsFunction -- Bool-like, local
+--#ifdef DEBUG
+ deriving Eq
+--#endif
enterCostCentreCode :: ClosureInfo -> CostCentre -> IsThunk -> Code
= costCentresFlag `thenFC` \ profiling_on ->
if not profiling_on then
nopC
- else -- down to business
+ else
ASSERT(not (noCostCentreAttached cc))
if costsAreSubsumed cc then
- nopC
-
- else if is_current_CC cc then -- fish the CC out of the closure,
- -- where we put it when we alloc'd;
- -- NB: chk defn of "is_current_CC"
- -- if you go to change this! (WDP 94/12)
- costCentresC
- (case is_thunk of
- IsThunk -> SLIT("ENTER_CC_TCL")
- IsFunction -> SLIT("ENTER_CC_FCL"))
- [CReg node]
-
- else if isCafCC cc then
- costCentresC
- SLIT("ENTER_CC_CAF")
- [mkCCostCentre cc]
+ --ASSERT(isToplevClosure closure_info)
+ --ASSERT(is_thunk == IsFunction)
+ (if isToplevClosure closure_info && is_thunk == IsFunction then \x->x else pprTrace "enterCostCenterCode:" (hsep [ppr (is_thunk == IsFunction){-, ppr closure_info-}, text (showCostCentre False cc)])) $
+ costCentresC SLIT("ENTER_CC_FSUB") []
+
+ else if currentOrSubsumedCosts cc then
+ -- i.e. current; subsumed dealt with above
+ -- get CCC out of the closure, where we put it when we alloc'd
+ case is_thunk of
+ IsThunk -> costCentresC SLIT("ENTER_CC_TCL") [CReg node]
+ IsFunction -> costCentresC SLIT("ENTER_CC_FCL") [CReg node]
+
+ else if isCafCC cc && isToplevClosure closure_info then
+ ASSERT(is_thunk == IsThunk)
+ costCentresC SLIT("ENTER_CC_CAF") [mkCCostCentre cc]
else -- we've got a "real" cost centre right here in our hands...
- costCentresC
- (case is_thunk of
- IsThunk -> SLIT("ENTER_CC_T")
- IsFunction -> SLIT("ENTER_CC_F"))
- [mkCCostCentre cc]
- where
- is_current_CC cc
- = currentOrSubsumedCosts cc
- -- but we've already ruled out "subsumed", so it must be "current"!
+ case is_thunk of
+ IsThunk -> costCentresC SLIT("ENTER_CC_T") [mkCCostCentre cc]
+ IsFunction -> if isCafCC cc || isDictCC cc
+ then costCentresC SLIT("ENTER_CC_FCAF") [mkCCostCentre cc]
+ else costCentresC SLIT("ENTER_CC_FLOAD") [mkCCostCentre cc]
\end{code}
%************************************************************************
let
emit_gran_macros = opt_GranMacros
in
- -- HWL: insert macros for GrAnSim; 2 versions depending on liveness of node
- -- (we prefer fetchAndReschedule-style context switches to yield ones)
+ -- HWL: insert macros for GrAnSim; 2 versions depending on liveness of node
+ -- (we prefer fetchAndReschedule-style context switches to yield ones)
(if emit_gran_macros
then if node_points
then fetchAndReschedule [] node_points
stackCheck closure_info [] node_points ( -- stackCheck *encloses* the rest
- -- Must be after stackCheck: if stchk fails new stack
- -- space has to be allocated from the heap
+ -- heapCheck must be after stackCheck: if stchk fails
+ -- new stack space is allocated from the heap which
+ -- would violate any previous heapCheck
- heapCheck [] node_points (
- -- heapCheck *encloses* the rest
- -- The "[]" says there are no live argument registers
+ heapCheck [] node_points ( -- heapCheck *encloses* the rest
+ -- The "[]" says there are no live argument registers
-- Overwrite with black hole if necessary
- blackHoleIt closure_info `thenC`
+ blackHoleIt closure_info `thenC`
- -- Push update frame if necessary
- setupUpdate closure_info ( -- setupUpdate *encloses* the rest
- thunk_code
+ setupUpdate closure_info ( -- setupUpdate *encloses* the rest
+
+ -- Finally, do the business
+ thunk_code
)))
funWrapper :: ClosureInfo -- Closure whose code body this is
then yield arg_regs node_points
else absC AbsCNop) `thenC`
- stackCheck closure_info arg_regs node_points ( -- stackCheck *encloses* the rest
+ stackCheck closure_info arg_regs node_points (
+ -- stackCheck *encloses* the rest
- -- Heap overflow check
heapCheck arg_regs node_points (
- -- heapCheck *encloses* the rest
+ -- heapCheck *encloses* the rest
-- Finally, do the business
fun_body
all_regs = if node_reqd then node:regs else regs
liveness_mask = mkLiveRegsMask all_regs
- returns_prim_type = closureReturnsUnboxedType closure_info
+ returns_prim_type = closureReturnsUnpointedType closure_info
\end{code}
%************************************************************************
-- CgConTbls.lhs with a description generated from the data constructor
closureDescription mod_name name args body
- = uppShow 0 (prettyToUn (
- ppBesides [ppChar '<',
- ppPStr mod_name,
- ppChar '.',
- ppr PprDebug name,
- ppChar '>']))
+ = showSDoc (
+ hcat [char '<',
+ ptext mod_name,
+ char '.',
+ ppr name,
+ char '>'])
\end{code}
\begin{code}
| just1 == fun
-> mkCCostCentre overheadCostCentre
_ -> use_cc
+
-- if it's an utterly trivial RHS, then it must be
-- one introduced by boxHigherOrderArgs for profiling,
-- so we charge it to "OVERHEAD".
in
(use_cc, blame_cc)
\end{code}
+
+
+
+========================================================================
+OLD CODE THAT EMITTED INFORMATON FOR QUANTITATIVE ANALYSIS
+
+It's pretty wierd, so I've nuked it for now. SLPJ Nov 96
+
+\begin{pseudocode}
+getWrapperArgTypeCategories
+ :: Type -- wrapper's type
+ -> StrictnessInfo bdee -- strictness info about its args
+ -> Maybe String
+
+getWrapperArgTypeCategories _ NoStrictnessInfo = Nothing
+getWrapperArgTypeCategories _ BottomGuaranteed
+ = trace "getWrapperArgTypeCategories:BottomGuaranteed!" Nothing -- wrong
+getWrapperArgTypeCategories _ (StrictnessInfo [] _) = Nothing
+
+getWrapperArgTypeCategories ty (StrictnessInfo arg_info _)
+ = Just (mkWrapperArgTypeCategories ty arg_info)
+
+mkWrapperArgTypeCategories
+ :: Type -- wrapper's type
+ -> [Demand] -- info about its arguments
+ -> String -- a string saying lots about the args
+
+mkWrapperArgTypeCategories wrapper_ty wrap_info
+ = case (splitFunTy_maybe wrapper_ty) of { Just (arg_tys,_) ->
+ map do_one (wrap_info `zip` (map showTypeCategory arg_tys)) }
+ where
+ -- ToDo: this needs FIXING UP (it was a hack anyway...)
+ do_one (WwPrim, _) = 'P'
+ do_one (WwEnum, _) = 'E'
+ do_one (WwStrict, arg_ty_char) = arg_ty_char
+ do_one (WwUnpack _ _ _, arg_ty_char)
+ = if arg_ty_char `elem` "CIJFDTS"
+ then toLower arg_ty_char
+ else if arg_ty_char == '+' then 't'
+ else trace ("mkWrapp..:funny char:"++[arg_ty_char]) '-'
+ do_one (other_wrap_info, _) = '-'
+\end{pseudocode}
+