summaryrefslogtreecommitdiff
path: root/ghc/compiler/codeGen/CgConTbls.lhs
diff options
context:
space:
mode:
Diffstat (limited to 'ghc/compiler/codeGen/CgConTbls.lhs')
-rw-r--r--ghc/compiler/codeGen/CgConTbls.lhs430
1 files changed, 430 insertions, 0 deletions
diff --git a/ghc/compiler/codeGen/CgConTbls.lhs b/ghc/compiler/codeGen/CgConTbls.lhs
new file mode 100644
index 0000000000..b37689f197
--- /dev/null
+++ b/ghc/compiler/codeGen/CgConTbls.lhs
@@ -0,0 +1,430 @@
+%
+% (c) The GRASP/AQUA Project, Glasgow University, 1992-1995
+%
+\section[CgConTbls]{Info tables and update bits for constructors}
+
+\begin{code}
+#include "HsVersions.h"
+
+module CgConTbls (
+ genStaticConBits,
+
+ -- and to complete the interface...
+ TCE(..), UniqFM, CompilationInfo, AbstractC
+ ) where
+
+import Pretty -- ToDo: rm (debugging)
+import Outputable
+
+import AbsCSyn
+import CgMonad
+
+import AbsUniType ( getTyConDataCons, kindFromType,
+ maybeIntLikeTyCon,
+ mkSpecTyCon, isLocalSpecTyCon,
+ TyVarTemplate, TyCon, Class,
+ TauType(..), UniType, ThetaType(..)
+ IF_ATTACK_PRAGMAS(COMMA cmpTyCon COMMA cmpClass)
+ IF_ATTACK_PRAGMAS(COMMA cmpUniType)
+ )
+import CgHeapery ( heapCheck, allocDynClosure )
+import CgRetConv ( dataReturnConvAlg, ctrlReturnConvAlg,
+ mkLiveRegsBitMask,
+ CtrlReturnConvention(..),
+ DataReturnConvention(..)
+ )
+import CgTailCall ( performReturn, mkStaticAlgReturnCode )
+import CgUsages ( getHpRelOffset )
+import CLabelInfo ( mkConEntryLabel, mkStaticConEntryLabel,
+ mkInfoTableLabel,
+ mkClosureLabel, --UNUSED: mkConUpdCodePtrUnvecLabel,
+ mkConUpdCodePtrVecLabel, mkStdUpdCodePtrVecLabel,
+ mkStdUpdVecTblLabel, CLabel
+ )
+import ClosureInfo ( layOutStaticClosure, layOutDynCon,
+ closureSizeWithoutFixedHdr, closurePtrsSize,
+ fitsMinUpdSize, mkConLFInfo, layOutPhantomClosure,
+ infoTableLabelFromCI
+ )
+import CmdLineOpts ( GlobalSwitch(..) )
+import FiniteMap
+import Id ( getDataConTag, getDataConSig, getDataConTyCon,
+ mkSameSpecCon,
+ getDataConArity, fIRST_TAG, ConTag(..),
+ DataCon(..)
+ )
+import CgCompInfo ( uF_UPDATEE )
+import Maybes ( maybeToBool, Maybe(..) )
+import PrimKind ( getKindSize, retKindSize )
+import CostCentre
+import UniqSet -- ( emptyUniqSet, UniqSet(..) )
+import TCE ( rngTCE, TCE(..), UniqFM )
+import Util
+\end{code}
+
+For every constructor we generate the following info tables:
+ A static info table, for static instances of the constructor,
+
+ For constructors which return in registers (and only them),
+ an "inregs" info table. This info table is rather emaciated;
+ it only contains update code and tag.
+
+ Plus:
+
+\begin{tabular}{lll}
+Info tbls & Macro & Kind of constructor \\
+\hline
+info & @CONST_INFO_TABLE@& Zero arity (no info -- compiler uses static closure)\\
+info & @CHARLIKE_INFO_TABLE@& Charlike (no info -- compiler indexes fixed array)\\
+info & @INTLIKE_INFO_TABLE@& Intlike; the one macro generates both info tbls\\
+info & @SPEC_INFO_TABLE@& SPECish, and bigger than or equal to @MIN_UPD_SIZE@\\
+info & @GEN_INFO_TABLE@& GENish (hence bigger than or equal to @MIN_UPD_SIZE@)\\
+\end{tabular}
+
+Possible info tables for constructor con:
+
+\begin{description}
+\item[@con_info@:]
+Used for dynamically let(rec)-bound occurrences of
+the constructor, and for updates. For constructors
+which are int-like, char-like or nullary, when GC occurs,
+the closure tries to get rid of itself.
+
+\item[@con_inregs_info@:]
+Used when returning a new constructor in registers.
+Only for return-in-regs constructors.
+Macro: @INREGS_INFO_TABLE@.
+
+\item[@con_static_info@:]
+Static occurrences of the constructor
+macro: @STATIC_INFO_TABLE@.
+\end{description}
+
+For zero-arity constructors, \tr{con}, we also generate a static closure:
+
+\begin{description}
+\item[@con_closure@:]
+A single static copy of the (zero-arity) constructor itself.
+\end{description}
+
+For charlike and intlike closures there is a fixed array of static
+closures predeclared.
+
+\begin{code}
+genStaticConBits :: CompilationInfo -- global info about the compilation
+ -> [TyCon] -- tycons to generate
+ -> FiniteMap TyCon [[Maybe UniType]]
+ -- tycon specialisation info
+ -> AbstractC -- output
+
+genStaticConBits comp_info gen_tycons tycon_specs
+ = -- for each type constructor:
+ -- grab all its data constructors;
+ -- for each one, generate an info table
+ -- for each specialised type constructor
+ -- for each specialisation of the type constructor
+ -- grab data constructors, and generate info tables
+
+ -- ToDo: for tycons and specialisations which are not
+ -- declared in this module we must ensure that the
+ -- C labels are local to this module i.e. static
+
+ mkAbstractCs [ gen_for_tycon tc | tc <- gen_tycons ]
+ `mkAbsCStmts`
+ mkAbstractCs [ mkAbstractCs [ gen_for_spec_tycon tc spec
+ | spec <- specs ]
+ | (tc, specs) <- fmToList tycon_specs,
+ isLocalSpecTyCon (sw_chkr CompilingPrelude) tc
+ ]
+ where
+ gen_for_tycon :: TyCon -> AbstractC
+ gen_for_tycon tycon
+ = mkAbstractCs (map (genConInfo comp_info tycon) data_cons)
+ `mkAbsCStmts` maybe_tycon_vtbl
+
+ where
+ data_cons = getTyConDataCons tycon
+ tycon_upd_label = mkStdUpdVecTblLabel tycon
+
+ maybe_tycon_vtbl =
+ case ctrlReturnConvAlg tycon of
+ UnvectoredReturn 1 -> CRetUnVector tycon_upd_label
+ (mk_upd_label tycon (head data_cons))
+ UnvectoredReturn _ -> AbsCNop
+ VectoredReturn _ -> CFlatRetVector tycon_upd_label
+ (map (mk_upd_label tycon) data_cons)
+ ------------------
+ gen_for_spec_tycon :: TyCon -> [Maybe UniType] -> AbstractC
+
+ gen_for_spec_tycon tycon ty_maybes
+ = mkAbstractCs (map (genConInfo comp_info tycon) spec_data_cons)
+ `mkAbsCStmts`
+ maybe_spec_tycon_vtbl
+ where
+ data_cons = getTyConDataCons tycon
+
+ spec_tycon = mkSpecTyCon tycon ty_maybes
+ spec_data_cons = map (mkSameSpecCon ty_maybes) data_cons
+
+ spec_tycon_upd_label = mkStdUpdVecTblLabel spec_tycon
+
+ maybe_spec_tycon_vtbl =
+ case ctrlReturnConvAlg spec_tycon of
+ UnvectoredReturn 1 -> CRetUnVector spec_tycon_upd_label
+ (mk_upd_label spec_tycon (head spec_data_cons))
+ UnvectoredReturn _ -> AbsCNop
+ VectoredReturn _ -> CFlatRetVector spec_tycon_upd_label
+ (map (mk_upd_label spec_tycon) spec_data_cons)
+ ------------------
+ mk_upd_label tycon con
+ = case dataReturnConvAlg con of
+ ReturnInRegs _ -> CLbl (mkConUpdCodePtrVecLabel tycon tag) CodePtrKind
+ ReturnInHeap -> CLbl (mkStdUpdCodePtrVecLabel tycon tag) CodePtrKind
+ where
+ tag = getDataConTag con
+
+ ------------------
+ (MkCompInfo sw_chkr _) = comp_info
+\end{code}
+
+%************************************************************************
+%* *
+\subsection[CgConTbls-info-tables]{Generating info tables for constructors}
+%* *
+%************************************************************************
+
+Generate the entry code, info tables, and (for niladic constructor) the
+static closure, for a constructor.
+
+\begin{code}
+genConInfo :: CompilationInfo -> TyCon -> Id -> AbstractC
+
+genConInfo comp_info tycon data_con
+ = mkAbstractCs [
+#ifndef DPH
+ CSplitMarker,
+ inregs_upd_maybe,
+ closure_code,
+ static_code,
+#else
+ info_table,
+ CSplitMarker,
+ static_info_table,
+#endif {- Data Parallel Haskell -}
+ closure_maybe]
+ -- Order of things is to reduce forward references
+ where
+ (closure_info, body_code) = mkConCodeAndInfo data_con
+
+ -- To allow the debuggers, interpreters, etc to cope with static
+ -- data structures (ie those built at compile time), we take care that
+ -- info-table contains the information we need.
+ (static_ci,_) = layOutStaticClosure data_con kindFromType arg_tys (mkConLFInfo data_con)
+
+ body = (initC comp_info (
+ profCtrC SLIT("ENT_CON") [CReg node] `thenC`
+ body_code))
+
+ entry_addr = CLbl entry_label CodePtrKind
+ con_descr = _UNPK_ (getOccurrenceName data_con)
+
+#ifndef DPH
+ closure_code = CClosureInfoAndCode closure_info body Nothing stdUpd con_descr
+ static_code = CClosureInfoAndCode static_ci body Nothing stdUpd con_descr
+
+ inregs_upd_maybe = genPhantomUpdInfo comp_info tycon data_con
+
+ stdUpd = CLbl (mkStdUpdCodePtrVecLabel tycon tag) CodePtrKind
+
+ tag = getDataConTag data_con
+
+#else
+ info_table
+ = CNativeInfoTableAndCode closure_info con_descr entry_code
+ static_info_table
+ = CNativeInfoTableAndCode static_ci con_descr (CJump entry_addr)
+#endif {- Data Parallel Haskell -}
+
+ cost_centre = mkCCostCentre dontCareCostCentre -- not worried about static data costs
+
+ -- For zero-arity data constructors, or, more accurately,
+ -- those which only have VoidKind args (or none):
+ -- We make the closure too (not just info tbl), so that we can share
+ -- one copy throughout.
+ closure_maybe = -- OLD: if con_arity /= 0 then
+ if not (all zero_size arg_tys) then
+ AbsCNop
+ else
+ CStaticClosure closure_label -- Label for closure
+ static_ci -- Info table
+ cost_centre
+ [{-No args! A slight lie for constrs with VoidKind args-}]
+
+ zero_size arg_ty = getKindSize (kindFromType arg_ty) == 0
+
+ (_,_,arg_tys,_) = getDataConSig data_con
+ con_arity = getDataConArity data_con
+ entry_label = mkConEntryLabel data_con
+ closure_label = mkClosureLabel data_con
+\end{code}
+
+\begin{code}
+mkConCodeAndInfo :: Id -- Data constructor
+ -> (ClosureInfo, Code) -- The info table
+
+mkConCodeAndInfo con
+ = case (dataReturnConvAlg con) of
+
+ ReturnInRegs regs ->
+ let
+ (closure_info, regs_w_offsets)
+ = layOutDynCon con kindFromMagicId regs
+
+ body_code
+ = -- OLD: We don't set CC when entering data any more (WDP 94/06)
+ -- lexCostCentreC "ENTER_CC_DCL" [CReg node] `thenC`
+ -- evalCostCentreC "SET_RetCC_CL" [CReg node] `thenC`
+ profCtrC SLIT("RET_OLD_IN_REGS") [] `thenC`
+
+ performReturn (mkAbstractCs (map move_to_reg regs_w_offsets))
+ (mkStaticAlgReturnCode con Nothing {- Info-ptr already loaded-})
+ emptyUniqSet{-no live vars-}
+ in
+ (closure_info, body_code)
+
+ ReturnInHeap ->
+ let
+ (_, _, arg_tys, _) = getDataConSig con
+
+ (closure_info, _)
+ = layOutDynCon con kindFromType arg_tys
+
+ body_code
+ = -- OLD: We don't set CC when entering data any more (WDP 94/06)
+ -- lexCostCentreC "ENTER_CC_DCL" [CReg node] `thenC`
+ profCtrC SLIT("RET_OLD_IN_HEAP") [] `thenC`
+
+ performReturn AbsCNop -- Ptr to thing already in Node
+ (mkStaticAlgReturnCode con Nothing {- Info-ptr already loaded-})
+ emptyUniqSet{-no live vars-}
+ in
+ (closure_info, body_code)
+
+ where
+ move_to_reg :: (MagicId, VirtualHeapOffset {-from Node-}) -> AbstractC
+ move_to_reg (reg, offset)
+ = CAssign (CReg reg) (CVal (NodeRel offset) (kindFromMagicId reg))
+\end{code}
+
+%************************************************************************
+%* *
+\subsection[CgConTbls-updates]{Generating update bits for constructors}
+%* *
+%************************************************************************
+
+Generate the "phantom" info table and update code, iff the constructor returns in regs
+
+\begin{code}
+
+genPhantomUpdInfo :: CompilationInfo -> TyCon -> Id{-data con-} -> AbstractC
+genPhantomUpdInfo comp_info tycon data_con
+ = case dataReturnConvAlg data_con of
+
+ ReturnInHeap -> AbsCNop -- No need for a phantom update
+
+ ReturnInRegs regs ->
+
+ let
+ phantom_itbl = CClosureInfoAndCode phantom_ci AbsCNop Nothing upd_code con_descr
+ phantom_ci = layOutPhantomClosure data_con (mkConLFInfo data_con)
+
+ con_descr = _UNPK_ (getOccurrenceName data_con)
+
+ con_arity = getDataConArity data_con
+
+ upd_code = CLabelledCode upd_label (mkAbsCStmts build_closure perform_return)
+ upd_label = mkConUpdCodePtrVecLabel tycon tag
+ tag = getDataConTag data_con
+
+ updatee = CVal (SpBRel 0 (-uF_UPDATEE)) PtrKind
+
+ perform_return = mkAbstractCs
+ [
+ CMacroStmt POP_STD_UPD_FRAME [],
+ CReturn (CReg RetReg) return_info
+ ]
+
+ return_info =
+ -- OLD: pprTrace "ctrlReturn6:" (ppr PprDebug tycon) (
+ case (ctrlReturnConvAlg tycon) of
+ UnvectoredReturn _ -> DirectReturn
+ VectoredReturn _ -> StaticVectoredReturn (tag - fIRST_TAG)
+ -- )
+
+ -- Determine cost centre for the updated closures CC (and allocation)
+ -- CCC for lexical (now your only choice)
+ use_cc = CReg CurCostCentre -- what to put in the closure
+ blame_cc = use_cc -- who to blame for allocation
+
+ do_move (reg, virt_offset) =
+ CAssign (CVal (NodeRel virt_offset) (kindFromMagicId reg)) (CReg reg)
+
+
+ -- Code for building a new constructor in place over the updatee
+ overwrite_code = profCtrC SLIT("UPD_CON_IN_PLACE") [] `thenC`
+ absC (mkAbstractCs
+ [
+ CAssign (CReg node) updatee,
+
+ -- Tell the storage mgr that we intend to update in place
+ -- This may (in complicated mgrs eg generational) cause gc,
+ -- and it may modify Node to point to another place to
+ -- actually update into.
+ CMacroStmt upd_inplace_macro [liveness_mask],
+
+ -- Initialise the closure pointed to by node
+ CInitHdr closure_info (NodeRel zeroOff) use_cc True,
+ mkAbstractCs (map do_move regs_w_offsets),
+ if con_arity /= 0 then
+ CAssign (CReg infoptr) (CLbl info_label DataPtrKind)
+ else
+ AbsCNop
+ ])
+
+ upd_inplace_macro = if closurePtrsSize closure_info == 0
+ then UPD_INPLACE_NOPTRS
+ else UPD_INPLACE_PTRS
+
+ -- Code for allocating a new constructor in the heap
+ alloc_code =
+ let amodes_w_offsets = [ (CReg r, o) | (r,o) <- regs_w_offsets ]
+ in
+ -- Allocate and build closure specifying upd_new_w_regs
+ allocDynClosure closure_info use_cc blame_cc amodes_w_offsets
+ `thenFC` \ hp_offset ->
+ getHpRelOffset hp_offset `thenFC` \ hp_rel ->
+ let
+ amode = CAddr hp_rel
+ in
+ profCtrC SLIT("UPD_CON_IN_NEW") [] `thenC`
+ absC (mkAbstractCs
+ [
+ CMacroStmt UPD_IND [updatee, amode],
+ CAssign (CReg node) amode,
+ CAssign (CReg infoptr) (CLbl info_label DataPtrKind)
+ ])
+
+ (closure_info, regs_w_offsets) = layOutDynCon data_con kindFromMagicId regs
+ info_label = infoTableLabelFromCI closure_info
+ liveness_mask = mkIntCLit (mkLiveRegsBitMask (node:regs))
+
+ build_closure =
+ if fitsMinUpdSize closure_info then
+ initC comp_info overwrite_code
+ else
+ initC comp_info (heapCheck regs False alloc_code)
+
+ in CClosureUpdInfo phantom_itbl
+
+\end{code}
+