[project @ 1997-12-08 10:06:34 by simonm]
[ghc-hetmet.git] / ghc / compiler / codeGen / CgExpr.lhs
index 5974df6..b600193 100644 (file)
 \begin{code}
 #include "HsVersions.h"
 
-module CgExpr (
-       cgExpr, cgSccExpr, getPrimOpArgAmodes,
+module CgExpr ( cgExpr, getPrimOpArgAmodes ) where
 
-       -- and to make the interface self-sufficient...
-       StgExpr, Id, CgState
-    ) where
-
-IMPORT_Trace           -- NB: not just for debugging
-import Outputable      -- ToDo: rm (just for debugging)
-import Pretty          -- ToDo: rm (just for debugging)
+IMP_Ubiq(){-uitous-}
+#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ <= 201
+IMPORT_DELOOPER(CgLoop2)       -- here for paranoia-checking
+#endif
 
+import Constants       ( mAX_SPEC_SELECTEE_SIZE )
 import StgSyn
 import CgMonad
 import AbsCSyn
 
-import AbsPrel         ( PrimOp(..), PrimOpResultInfo(..), HeapRequirement(..), 
-                         primOpHeapReq, getPrimOpResultInfo, PrimKind, 
-                         primOpCanTriggerGC
-                         IF_ATTACK_PRAGMAS(COMMA tagOf_PrimOp)
-                         IF_ATTACK_PRAGMAS(COMMA pprPrimOp)
-                       )
-import AbsUniType      ( isPrimType, getTyConDataCons )
-import CLabelInfo      ( CLabel, mkPhantomInfoTableLabel, mkInfoTableVecTblLabel )
-import ClosureInfo     ( LambdaFormInfo, mkClosureLFInfo )
-import CgBindery       ( getAtomAmodes )
+import AbsCUtils       ( mkAbsCStmts, mkAbstractCs )
+import CgBindery       ( getArgAmodes, getCAddrModeAndInfo, CgIdInfo )
 import CgCase          ( cgCase, saveVolatileVarsAndRegs )
 import CgClosure       ( cgRhsClosure )
 import CgCon           ( buildDynCon, cgReturnDataCon )
 import CgHeapery       ( allocHeap )
 import CgLetNoEscape   ( cgLetNoEscapeClosure )
-import CgRetConv       -- various things...
-import CgTailCall      ( cgTailCall, performReturn, mkDynamicAlgReturnCode,
-                          mkPrimReturnCode
-                        )
-import CostCentre      ( setToAbleCostCentre, isDupdCC, CostCentre )
-import Maybes          ( Maybe(..) )
-import PrimKind                ( getKindSize )
-import UniqSet
-import Util
+import CgRetConv       ( dataReturnConvAlg, ctrlReturnConvAlg,
+                         DataReturnConvention(..), CtrlReturnConvention(..),
+                         assignPrimOpResultRegs, makePrimOpArgsRobust
+                       )
+import CgTailCall      ( cgTailCall, performReturn,
+                         mkDynamicAlgReturnCode, mkPrimReturnCode
+                       )
+import CLabel          ( mkPhantomInfoTableLabel, mkInfoTableVecTblLabel )
+import ClosureInfo     ( mkClosureLFInfo, mkSelectorLFInfo, mkVapLFInfo,
+                         layOutDynCon )
+import CostCentre      ( sccAbleCostCentre, isDictCC, isSccCountCostCentre )
+import HeapOffs                ( SYN_IE(VirtualSpBOffset), intOffsetIntoGoods )
+import Id              ( dataConTyCon, idPrimRep, getIdArity, 
+                         mkIdSet, unionIdSets, GenId{-instance Outputable-},
+                         SYN_IE(Id)
+                       )
+import IdInfo          ( ArityInfo(..) )
+import Name            ( isLocallyDefined )
+import Outputable      ( PprStyle(..), Outputable(..) )
+import Pretty          ( Doc )
+import PrimOp          ( primOpCanTriggerGC, primOpHeapReq, HeapRequirement(..),
+                         getPrimOpResultInfo, PrimOp(..), PrimOpResultInfo(..)
+                       )
+import PrimRep         ( getPrimRepSize, PrimRep(..) )
+import TyCon           ( tyConDataCons, maybeTyConSingleCon  )
+import Maybes          ( assocMaybe, maybeToBool )
+import Util            ( panic, isIn, pprPanic, assertPanic )
 \end{code}
 
 This module provides the support code for @StgToAbstractC@ to deal
@@ -56,7 +63,7 @@ with STG {\em expressions}.  See also @CgClosure@, which deals
 with closures, and @CgCon@, which deals with constructors.
 
 \begin{code}
-cgExpr :: PlainStgExpr         -- input
+cgExpr :: StgExpr              -- input
        -> Code                 -- output
 \end{code}
 
@@ -68,7 +75,7 @@ cgExpr        :: PlainStgExpr         -- input
 
 ``Applications'' mean {\em tail calls}, a service provided by module
 @CgTailCall@.  This includes literals, which show up as
-@(STGApp (StgLitAtom 42) [])@.
+@(STGApp (StgLitArg 42) [])@.
 
 \begin{code}
 cgExpr (StgApp fun args live_vars) = cgTailCall fun args live_vars
@@ -81,11 +88,11 @@ cgExpr (StgApp fun args live_vars) = cgTailCall fun args live_vars
 %********************************************************
 
 \begin{code}
-cgExpr (StgConApp con args live_vars)
-  = getAtomAmodes args `thenFC` \ amodes ->
+cgExpr (StgCon con args live_vars)
+  = getArgAmodes args `thenFC` \ amodes ->
     cgReturnDataCon con amodes (all zero_size args) live_vars
   where
-    zero_size atom = getKindSize (getAtomKind atom) == 0
+    zero_size atom = getPrimRepSize (getArgPrimRep atom) == 0
 \end{code}
 
 %********************************************************
@@ -97,9 +104,9 @@ cgExpr (StgConApp con args live_vars)
 Here is where we insert real live machine instructions.
 
 \begin{code}
-cgExpr x@(StgPrimApp op args live_vars)
-  = -- trace ("cgExpr:PrimApp:"++(ppShow 80 (ppr PprDebug x))) (
-    getPrimOpArgAmodes op args                 `thenFC` \ arg_amodes ->
+cgExpr x@(StgPrim op args live_vars)
+  = ASSERT(op /= SeqOp) -- can't handle SeqOp
+    getPrimOpArgAmodes op args `thenFC` \ arg_amodes ->
     let
        result_regs   = assignPrimOpResultRegs op
        result_amodes = map CReg result_regs
@@ -112,20 +119,17 @@ cgExpr x@(StgPrimApp op args live_vars)
        -- Use registers for args, and assign args to the regs
        -- (Can-trigger-gc primops guarantee to have their args in regs)
        let
-           (arg_robust_amodes, liveness_mask, arg_assts) 
+           (arg_robust_amodes, liveness_mask, arg_assts)
              = makePrimOpArgsRobust op arg_amodes
 
            liveness_arg = mkIntCLit liveness_mask
        in
        returnFC (
            arg_assts,
-           mkAbstractCs [
-             spat_prim_macro,
-             COpStmt result_amodes op
-                     (pin_liveness op liveness_arg arg_robust_amodes)
-                     liveness_mask
-                     [{-no vol_regs-}],
-             spat_prim_stop_macro ]
+           COpStmt result_amodes op
+                   (pin_liveness op liveness_arg arg_robust_amodes)
+                   liveness_mask
+                   [{-no vol_regs-}]
        )
      else
        -- Use args from their current amodes.
@@ -133,13 +137,8 @@ cgExpr x@(StgPrimApp op args live_vars)
          liveness_mask = panic "cgExpr: liveness of non-GC-ing primop touched\n"
        in
        returnFC (
---       DO NOT want CCallProfMacros in CSimultaneous stuff.  Yurgh.  (WDP 95/01)
---             Arises in compiling PreludeGlaST (and elsewhere??)
---       mkAbstractCs [
---         spat_prim_macro,
            COpStmt result_amodes op arg_amodes liveness_mask [{-no vol_regs-}],
---         spat_prim_stop_macro ],
-         AbsCNop
+           AbsCNop
        )
     )                          `thenFC` \ (do_before_stack_cleanup,
                                             do_just_before_jump) ->
@@ -148,7 +147,7 @@ cgExpr x@(StgPrimApp op args live_vars)
 
        ReturnsPrim kind ->
            performReturn do_before_stack_cleanup
-                         (\ sequel -> robustifySequel may_gc sequel    
+                         (\ sequel -> robustifySequel may_gc sequel
                                                        `thenFC` \ (ret_asst, sequel') ->
                           absC (ret_asst `mkAbsCStmts` do_just_before_jump)
                                                        `thenC`
@@ -156,14 +155,13 @@ cgExpr x@(StgPrimApp op args live_vars)
                          live_vars
 
        ReturnsAlg tycon ->
---OLD:     evalCostCentreC "SET_RetCC" [CReg CurCostCentre]    `thenC` 
-           profCtrC SLIT("RET_NEW_IN_REGS") []                 `thenC`
+           profCtrC SLIT("RET_NEW_IN_REGS") [num_of_fields]    `thenC`
 
            performReturn do_before_stack_cleanup
                          (\ sequel -> robustifySequel may_gc sequel
                                                        `thenFC` \ (ret_asst, sequel') ->
-                          absC (mkAbstractCs [ret_asst, 
-                                               do_just_before_jump, 
+                          absC (mkAbstractCs [ret_asst,
+                                              do_just_before_jump,
                                               info_ptr_assign])
                        -- Must load info ptr here, not in do_just_before_stack_cleanup,
                        -- because the info-ptr reg clashes with argument registers
@@ -179,22 +177,25 @@ cgExpr x@(StgPrimApp op args live_vars)
                info_ptr_assign = CAssign (CReg infoptr) info_lbl
 
                info_lbl
-                 = -- OLD: pprTrace "ctrlReturn7:" (ppr PprDebug tycon) (
-                   case (ctrlReturnConvAlg tycon) of
-                     VectoredReturn _   -> vec_lbl
+                 = case (ctrlReturnConvAlg tycon) of
+                     VectoredReturn   _ -> vec_lbl
                      UnvectoredReturn _ -> dir_lbl
-                   -- )
-
-               vec_lbl  = CTableEntry (CLbl (mkInfoTableVecTblLabel tycon) DataPtrKind) 
-                               dyn_tag DataPtrKind
-
-               data_con = head (getTyConDataCons tycon)
-               dir_lbl  = case dataReturnConvAlg data_con of
-                               ReturnInRegs _ -> CLbl (mkPhantomInfoTableLabel data_con) 
-                                                      DataPtrKind
-                               ReturnInHeap   -> panic "CgExpr: can't return prim in heap"
-                                         -- Never used, and no point in generating
-                                         -- the code for it!
+
+               vec_lbl  = CTableEntry (CLbl (mkInfoTableVecTblLabel tycon) DataPtrRep)
+                               dyn_tag DataPtrRep
+
+               data_con = head (tyConDataCons tycon)
+
+               (dir_lbl, num_of_fields)
+                 = case (dataReturnConvAlg data_con) of
+                     ReturnInRegs rs
+                       -> (CLbl (mkPhantomInfoTableLabel data_con) DataPtrRep,
+                           mkIntCLit (length rs)) -- for ticky-ticky only
+
+                     ReturnInHeap
+                       -> pprPanic "CgExpr: can't return prim in heap:" (ppr PprDebug data_con)
+                         -- Never used, and no point in generating
+                         -- the code for it!
   where
     -- for all PrimOps except ccalls, we pin the liveness info
     -- on as the first "argument"
@@ -208,14 +209,10 @@ cgExpr x@(StgPrimApp op args live_vars)
     -- sequel is OnStack.  If that's the case, arrange to pull the
     -- sequel out into RetReg before performing the primOp.
 
-    robustifySequel True sequel@(OnStack _) = 
+    robustifySequel True sequel@(OnStack _) =
        sequelToAmode sequel                    `thenFC` \ amode ->
        returnFC (CAssign (CReg RetReg) amode, InRetReg)
     robustifySequel _ sequel = returnFC (AbsCNop, sequel)
-    
-    spat_prim_macro     = CCallProfCtrMacro SLIT("SET_ACTIVITY") [CLitLit SLIT("ACT_PRIM") IntKind]
-    spat_prim_stop_macro = CCallProfCtrMacro SLIT("SET_ACTIVITY") [CLitLit SLIT("ACT_PRIM_STOP") IntKind]
-
 \end{code}
 
 %********************************************************
@@ -258,12 +255,12 @@ cgExpr (StgLet (StgRec pairs) expr)
 cgExpr (StgLetNoEscape live_in_whole_let live_in_rhss bindings body)
   =            -- Figure out what volatile variables to save
     nukeDeadBindings live_in_whole_let `thenC`
-    saveVolatileVarsAndRegs live_in_rhss 
+    saveVolatileVarsAndRegs live_in_rhss
            `thenFC` \ (save_assts, rhs_eob_info, maybe_cc_slot) ->
 
        -- ToDo: cost centre???
 
-       -- Save those variables right now!      
+       -- Save those variables right now!
     absC save_assts                            `thenC`
 
        -- Produce code for the rhss
@@ -284,32 +281,17 @@ cgExpr (StgLetNoEscape live_in_whole_let live_in_rhss bindings body)
 
 SCC expressions are treated specially. They set the current cost
 centre.
-
-For evaluation scoping we also need to save the cost centre in an
-``restore CC frame''. We only need to do this once before setting all
-nested SCCs.
-
 \begin{code}
-cgExpr scc_expr@(StgSCC ty cc expr)
---OLD:WDP:94/06  = evalPushRCCFrame (isPrimType ty) (cgSccExpr scc_expr)
-  = cgSccExpr scc_expr
+cgExpr (StgSCC ty cc expr)
+  = ASSERT(sccAbleCostCentre cc)
+    costCentresC
+       (if isDictCC cc then SLIT("SET_DICT_CCC") else SLIT("SET_CCC"))
+       [mkCCostCentre cc, mkIntCLit (if isSccCountCostCentre cc then 1 else 0)]
+    `thenC`
+    cgExpr expr
 \end{code}
 
-@cgSccExpr@ (also used in \tr{CgClosure}):
-We *don't* set the cost centre for CAF/Dict cost centres
-[Likewise Subsumed and NoCostCentre, but they probably
-don't exist in an StgSCC expression.]
-\begin{code}
-cgSccExpr (StgSCC ty cc expr)
-  = (if setToAbleCostCentre cc then
-       costCentresC SLIT("SET_CCC")
-           [mkCCostCentre cc, mkIntCLit (if isDupdCC cc then 1 else 0)]
-     else
-       nopC)           `thenC`
-    cgSccExpr expr
-cgSccExpr other
-  = cgExpr other
-\end{code}
+ToDo: counting of dict sccs ...
 
 %********************************************************
 %*                                                     *
@@ -318,55 +300,158 @@ cgSccExpr other
 %********************************************************
 \subsection[non-top-level-bindings]{Converting non-top-level bindings}
 
-@cgBinding@ is only used for let/letrec, not for unboxed bindings.
-So the kind should always be @PtrKind@.
-
 We rely on the support code in @CgCon@ (to do constructors) and
 in @CgClosure@ (to do closures).
 
 \begin{code}
-cgRhs :: Id -> PlainStgRhs -> FCode (Id, CgIdInfo)
+cgRhs :: Id -> StgRhs -> FCode (Id, CgIdInfo)
        -- the Id is passed along so a binding can be set up
 
 cgRhs name (StgRhsCon maybe_cc con args)
-  = getAtomAmodes args         `thenFC` \ amodes ->
+  = getArgAmodes args          `thenFC` \ amodes ->
     buildDynCon name maybe_cc con amodes (all zero_size args)
                                `thenFC` \ idinfo ->
     returnFC (name, idinfo)
   where
-    zero_size atom = getKindSize (getAtomKind atom) == 0
+    zero_size atom = getPrimRepSize (getArgPrimRep atom) == 0
 
 cgRhs name (StgRhsClosure cc bi fvs upd_flag args body)
   = cgRhsClosure name cc bi fvs args body lf_info
   where
-    lf_info = mkClosureLFInfo False{-not top level-} fvs upd_flag args body
+    lf_info = mkRhsLFInfo fvs upd_flag args body
+    
+\end{code}
+
+mkRhsLFInfo looks for two special forms of the right-hand side:
+       a) selector thunks.
+       b) VAP thunks
+
+If neither happens, it just calls mkClosureLFInfo.  You might think
+that mkClosureLFInfo should do all this, but
+
+       (a) it seems wrong for the latter to look at the structure 
+               of an expression
+
+       [March 97: item (b) is no longer true, but I've left mkRhsLFInfo here
+        anyway because of (a).]
+
+       (b) mkRhsLFInfo has to be in the monad since it looks up in
+               the environment, and it's very tiresome for mkClosureLFInfo to
+               be.  Apart from anything else it would make a loop between
+               CgBindery and ClosureInfo.
+
+Selectors
+~~~~~~~~~
+We look at the body of the closure to see if it's a selector---turgid,
+but nothing deep.  We are looking for a closure of {\em exactly} the
+form:
+\begin{verbatim}
+...  = [the_fv] \ u [] ->
+        case the_fv of
+          con a_1 ... a_n -> a_i
+\end{verbatim}
+
+\begin{code}
+mkRhsLFInfo    [the_fv]                -- Just one free var
+               Updatable               -- Updatable thunk
+               []                      -- A thunk
+               (StgCase (StgApp (StgVarArg scrutinee) [{-no args-}] _)
+                     _ _ _   -- ignore live vars and uniq...
+                     (StgAlgAlts case_ty
+                        [(con, params, use_mask,
+                           (StgApp (StgVarArg selectee) [{-no args-}] _))]
+                        StgNoDefault))
+  |  the_fv == scrutinee                       -- Scrutinee is the only free variable
+  && maybeToBool maybe_offset                  -- Selectee is a component of the tuple
+  && maybeToBool offset_into_int_maybe
+  && offset_into_int <= mAX_SPEC_SELECTEE_SIZE -- Offset is small enough
+  = -- ASSERT(is_single_constructor)           -- Should be true, but causes error for SpecTyCon
+    mkSelectorLFInfo scrutinee con offset_into_int
+  where
+    (_, params_w_offsets) = layOutDynCon con idPrimRep params
+    maybe_offset         = assocMaybe params_w_offsets selectee
+    Just the_offset      = maybe_offset
+    offset_into_int_maybe = intOffsetIntoGoods the_offset
+    Just offset_into_int  = offset_into_int_maybe
+    is_single_constructor = maybeToBool (maybeTyConSingleCon tycon)
+    tycon                = dataConTyCon con
 \end{code}
 
+
+Vap thunks
+~~~~~~~~~~
+Same kind of thing, looking for vector-apply thunks, of the form:
+
+       x = [...] \ .. [] -> f a1 .. an
+
+where f has arity n.  We rely on the arity info inside the Id being correct.
+
+\begin{code}
+mkRhsLFInfo    fvs
+               upd_flag
+               []                      -- No args; a thunk
+               (StgApp (StgVarArg fun_id) args _)
+  | isLocallyDefined fun_id            -- Must be defined in this module
+  =    -- Get the arity of the fun_id.  It's guaranteed to be correct (by setStgVarInfo).
+     let
+       arity_maybe = case getIdArity fun_id of
+                       ArityExactly n  -> Just n
+                       other           -> Nothing
+     in
+     case arity_maybe of
+               Just arity
+                   | arity > 0 &&                      -- It'd better be a function!
+                     arity == length args              -- Saturated application
+                   ->          -- Ha!  A VAP thunk
+                       mkVapLFInfo fvs upd_flag fun_id args store_fun_in_vap
+
+               other -> mkClosureLFInfo False{-not top level-} fvs upd_flag []
+  where        
+       -- If the function is a free variable then it must be stored
+       -- in the thunk too; if it isn't a free variable it must be
+       -- because it's constant, so it doesn't need to be stored in the thunk
+    store_fun_in_vap = fun_id `is_elem` fvs
+    is_elem         = isIn "mkClosureLFInfo"
+\end{code}
+
+The default case
+~~~~~~~~~~~~~~~~
+\begin{code}
+mkRhsLFInfo fvs upd_flag args body
+  = mkClosureLFInfo False{-not top level-} fvs upd_flag args
+\end{code}
+
+
+%********************************************************
+%*                                                     *
+%*             Let-no-escape bindings
+%*                                                     *
+%********************************************************
 \begin{code}
 cgLetNoEscapeBindings live_in_rhss rhs_eob_info maybe_cc_slot (StgNonRec binder rhs)
-  = cgLetNoEscapeRhs live_in_rhss rhs_eob_info maybe_cc_slot binder rhs        
+  = cgLetNoEscapeRhs live_in_rhss rhs_eob_info maybe_cc_slot binder rhs
                                `thenFC` \ (binder, info) ->
     addBindC binder info
 
 cgLetNoEscapeBindings live_in_rhss rhs_eob_info maybe_cc_slot (StgRec pairs)
   = fixC (\ new_bindings ->
                addBindsC new_bindings  `thenC`
-               listFCs [ cgLetNoEscapeRhs full_live_in_rhss rhs_eob_info 
-                          maybe_cc_slot b e | (b,e) <- pairs ]
+               listFCs [ cgLetNoEscapeRhs full_live_in_rhss rhs_eob_info
+                         maybe_cc_slot b e | (b,e) <- pairs ]
     ) `thenFC` \ new_bindings ->
 
     addBindsC new_bindings
   where
     -- We add the binders to the live-in-rhss set so that we don't
     -- delete the bindings for the binder from the environment!
-    full_live_in_rhss = live_in_rhss `unionUniqSets` (mkUniqSet [b | (b,r) <- pairs])
+    full_live_in_rhss = live_in_rhss `unionIdSets` (mkIdSet [b | (b,r) <- pairs])
 
-cgLetNoEscapeRhs 
-    :: PlainStgLiveVars        -- Live in rhss
-    -> EndOfBlockInfo 
+cgLetNoEscapeRhs
+    :: StgLiveVars     -- Live in rhss
+    -> EndOfBlockInfo
     -> Maybe VirtualSpBOffset
     -> Id
-    -> PlainStgRhs
+    -> StgRhs
     -> FCode (Id, CgIdInfo)
 
 cgLetNoEscapeRhs full_live_in_rhss rhs_eob_info maybe_cc_slot binder
@@ -378,14 +463,14 @@ cgLetNoEscapeRhs full_live_in_rhss rhs_eob_info maybe_cc_slot binder
     --     other     -> cgLetNoEscapeClosure binder cc bi live_in_whole_let live_in_rhss args body
     cgLetNoEscapeClosure binder cc bi full_live_in_rhss rhs_eob_info maybe_cc_slot args body
 
--- For a constructor RHS we want to generate a single chunk of code which 
+-- For a constructor RHS we want to generate a single chunk of code which
 -- can be jumped to from many places, which will return the constructor.
 -- It's easy; just behave as if it was an StgRhsClosure with a ConApp inside!
 cgLetNoEscapeRhs full_live_in_rhss rhs_eob_info maybe_cc_slot binder
                 (StgRhsCon cc con args)
   = cgLetNoEscapeClosure binder cc stgArgOcc{-safe-} full_live_in_rhss rhs_eob_info maybe_cc_slot
        []      --No args; the binder is data structure, not a function
-       (StgConApp con args full_live_in_rhss)
+       (StgCon con args full_live_in_rhss)
 \end{code}
 
 Some PrimOps require a {\em fixed} amount of heap allocation.  Rather
@@ -401,14 +486,13 @@ Main current use: allocating SynchVars.
 
 \begin{code}
 getPrimOpArgAmodes op args
-  = getAtomAmodes args         `thenFC` \ arg_amodes ->
+  = getArgAmodes args          `thenFC` \ arg_amodes ->
 
     case primOpHeapReq op of
-
        FixedHeapRequired size -> allocHeap size `thenFC` \ amode ->
                                  returnFC (amode : arg_amodes)
 
-       _                      -> returnFC arg_amodes    
+       _                      -> returnFC arg_amodes
 \end{code}