[project @ 2000-11-24 09:51:38 by simonpj]
[ghc-hetmet.git] / ghc / compiler / simplStg / StgVarInfo.lhs
index f185c19..624a89c 100644 (file)
@@ -13,14 +13,16 @@ module StgVarInfo ( setStgVarInfo ) where
 
 import StgSyn
 
-import Id              ( setIdArity, getIdArity, Id )
+import Id              ( isLocalId, setIdArityInfo, idArity, setIdOccInfo, Id )
 import VarSet
 import VarEnv
 import Var
-import IdInfo          ( ArityInfo(..), InlinePragInfo(..), 
-                         setInlinePragInfo )
-import Maybes          ( maybeToBool )
-import Name            ( isLocallyDefined )
+import IdInfo          ( ArityInfo(..), OccInfo(..) )
+import PrimOp          ( PrimOp(..), ccallMayGC )
+import TysWiredIn       ( isForeignObjTy )
+import Maybes          ( maybeToBool, orElse )
+import Name            ( getOccName )
+import OccName         ( occNameUserString )
 import BasicTypes       ( Arity )
 import Outputable
 
@@ -126,7 +128,7 @@ varsTopBinds (bind:binds)
                        StgNonRec binder rhs -> [(binder,rhs)]
                        StgRec pairs         -> pairs
 
-    binders' = [ binder `setIdArity` ArityExactly (rhsArity rhs) 
+    binders' = [ binder `setIdArityInfo` ArityExactly (rhsArity rhs) 
               | (binder, rhs) <- pairs
               ]
 
@@ -209,13 +211,8 @@ to do it before the SRT pass to save the SRT entries associated with
 any top-level PAPs.
 
 \begin{code}
-isPAP (StgApp f args) 
-  = case getIdArity f of
-          ArityExactly n -> n > n_args
-          ArityAtLeast n -> n > n_args
-          _              -> False
-   where n_args = length args
-isPAP _ = False
+isPAP (StgApp f args) = idArity f > length args
+isPAP _              = False
 \end{code}
 
 \begin{code}
@@ -229,10 +226,10 @@ varsAtoms atoms
   = mapAndUnzipLne var_atom atoms      `thenLne` \ (args', fvs_lists) ->
     returnLne (args', unionFVInfos fvs_lists)
   where
-    var_atom a@(StgConArg _) = returnLne (a, emptyFVInfo)
     var_atom a@(StgVarArg v)
       = lookupVarLne v `thenLne` \ (v', how_bound) ->
        returnLne (StgVarArg v', singletonFVInfo v' how_bound stgArgOcc)
+    var_atom a = returnLne (a, emptyFVInfo)
 \end{code}
 
 %************************************************************************
@@ -269,12 +266,17 @@ on these components, but it in turn is not scrutinised as the basis for any
 decisions.  Hence no black holes.
 
 \begin{code}
+varsExpr (StgLit l)     = returnLne (StgLit l, emptyFVInfo, emptyVarSet)
+
 varsExpr (StgApp f args) = varsApp Nothing f args
 
-varsExpr (StgCon con args res_ty)
-  = getVarsLiveInCont          `thenLne` \ live_in_cont ->
-    varsAtoms args             `thenLne` \ (args', args_fvs) ->
-    returnLne (StgCon con args' res_ty, args_fvs, getFVSet args_fvs)
+varsExpr (StgConApp con args)
+  = varsAtoms args             `thenLne` \ (args', args_fvs) ->
+    returnLne (StgConApp con args', args_fvs, getFVSet args_fvs)
+
+varsExpr (StgPrimApp op args res_ty)
+  = varsAtoms args             `thenLne` \ (args', args_fvs) ->
+    returnLne (StgPrimApp op args' res_ty, args_fvs, getFVSet args_fvs)
 
 varsExpr (StgSCC cc expr)
   = varsExpr expr              `thenLne` ( \ (expr2, fvs, escs) ->
@@ -291,14 +293,25 @@ varsExpr (StgCase scrut _ _ bndr srt alts)
     let
        -- determine whether the default binder is dead or not
        bndr'= if (bndr `elementOfFVInfo` alts_fvs) 
-                 then modifyIdInfo (`setInlinePragInfo` NoInlinePragInfo) bndr
-                 else modifyIdInfo (`setInlinePragInfo` IAmDead)          bndr
+                 then bndr `setIdOccInfo` NoOccInfo
+                 else bndr `setIdOccInfo` IAmDead
+
+        -- for a _ccall_GC_, some of the *arguments* need to live across the
+        -- call (see findLiveArgs comments.), so we annotate them as being live
+        -- in the alts to achieve the desired effect.
+       mb_live_across_case =
+         case scrut of
+           StgPrimApp (CCallOp ccall)  args _
+               |  ccallMayGC ccall
+               -> Just (foldl findLiveArgs emptyVarSet args)
+           _   -> Nothing
 
        -- don't consider the default binder as being 'live in alts',
        -- since this is from the point of view of the case expr, where
        -- the default binder is not free.
-       live_in_alts = live_in_cont `unionVarSet` 
-                               (alts_lvs `minusVarSet` unitVarSet bndr)
+       live_in_alts = orElse (FMAP unionVarSet mb_live_across_case) id $
+                      live_in_cont `unionVarSet` 
+                      (alts_lvs `minusVarSet` unitVarSet bndr)
     in
        -- we tell the scrutinee that everything live in the alts
        -- is live in it, too.
@@ -319,7 +332,7 @@ varsExpr (StgCase scrut _ _ bndr srt alts)
       )
     )
   where
-    vars_alts (StgAlgAlts ty alts deflt)
+    vars_alts (StgAlgAlts tycon alts deflt)
       = mapAndUnzip3Lne vars_alg_alt alts
                        `thenLne` \ (alts2,  alts_fvs_list,  alts_escs_list) ->
        let
@@ -328,7 +341,7 @@ varsExpr (StgCase scrut _ _ bndr srt alts)
        in
        vars_deflt deflt `thenLne` \ (deflt2, deflt_fvs, deflt_escs) ->
        returnLne (
-           StgAlgAlts ty alts2 deflt2,
+           StgAlgAlts tycon alts2 deflt2,
            alts_fvs  `unionFVInfo`   deflt_fvs,
            alts_escs `unionVarSet` deflt_escs
        )
@@ -348,7 +361,7 @@ varsExpr (StgCase scrut _ _ bndr srt alts)
                                                        -- any of these binders
            ))
 
-    vars_alts (StgPrimAlts ty alts deflt)
+    vars_alts (StgPrimAlts tycon alts deflt)
       = mapAndUnzip3Lne vars_prim_alt alts
                        `thenLne` \ (alts2,  alts_fvs_list,  alts_escs_list) ->
        let
@@ -357,7 +370,7 @@ varsExpr (StgCase scrut _ _ bndr srt alts)
        in
        vars_deflt deflt `thenLne` \ (deflt2, deflt_fvs, deflt_escs) ->
        returnLne (
-           StgPrimAlts ty alts2 deflt2,
+           StgPrimAlts tycon alts2 deflt2,
            alts_fvs  `unionFVInfo`   deflt_fvs,
            alts_escs `unionVarSet` deflt_escs
        )
@@ -394,6 +407,19 @@ varsExpr (StgLet bind body)
     returnLne (new_let, fvs, escs)
 \end{code}
 
+If we've got a case containing a _ccall_GC_ primop, we need to
+ensure that the arguments are kept live for the duration of the
+call. This only an issue
+
+\begin{code}
+findLiveArgs :: StgLiveVars -> StgArg -> StgLiveVars
+findLiveArgs lvs (StgVarArg x) 
+   | isForeignObjTy (idType x) = extendVarSet lvs x
+   | otherwise                = lvs
+findLiveArgs lvs arg          = lvs
+\end{code}
+
+
 Applications:
 \begin{code}
 varsApp :: Maybe UpdateFlag            -- Just upd <=> this application is
@@ -414,42 +440,35 @@ varsApp maybe_thunk_body f args
     let
        n_args           = length args
        not_letrec_bound = not (isLetrecBound how_bound)
-       f_arity          = getIdArity f'
+       f_arity          = idArity f'   -- Will have an exact arity by now
        fun_fvs          = singletonFVInfo f' how_bound fun_occ
 
        fun_occ 
-         | not_letrec_bound
-         = NoStgBinderInfo             -- Uninteresting variable
-
-         | otherwise                   -- Letrec bound; must have its arity
-         = case f_arity of
-             ArityExactly arity
-               | n_args == 0 -> stgFakeFunAppOcc   -- Function Application
-                                                   -- with no arguments.
-                                                   -- used by the lambda lifter.
-               | arity > n_args -> stgUnsatOcc     -- Unsaturated
-
-
-               | arity == n_args &&
-                 maybeToBool maybe_thunk_body ->   -- Exactly saturated,
-                                                   -- and rhs of thunk
-                       case maybe_thunk_body of
-                               Just Updatable   -> stgStdHeapOcc
-                               Just SingleEntry -> stgNoUpdHeapOcc
-                               other            -> panic "varsApp"
-
-               | otherwise ->  stgNormalOcc
+         | not_letrec_bound = NoStgBinderInfo          -- Uninteresting variable
+               
+               -- Otherwise it is letrec bound; must have its arity
+         | n_args == 0 = stgFakeFunAppOcc      -- Function Application
+                                               -- with no arguments.
+                                               -- used by the lambda lifter.
+         | f_arity > n_args = stgUnsatOcc      -- Unsaturated
+
+
+         | f_arity == n_args &&
+           maybeToBool maybe_thunk_body        -- Exactly saturated,
+                                               -- and rhs of thunk
+         = case maybe_thunk_body of
+               Just Updatable   -> stgStdHeapOcc
+               Just SingleEntry -> stgNoUpdHeapOcc
+               other            -> panic "varsApp"
+
+         | otherwise =  stgNormalOcc
                                -- Record only that it occurs free
 
        myself = unitVarSet f'
 
-       fun_escs | not_letrec_bound = emptyVarSet       -- Only letrec-bound escapees are interesting
-                | otherwise        = case f_arity of   -- Letrec bound, so must have its arity
-                                       ArityExactly arity
-                                         | arity == n_args -> emptyVarSet
-                                               -- Function doesn't escape
-                                         | otherwise -> myself
-                                               -- Inexact application; it does escape
+       fun_escs | not_letrec_bound  = emptyVarSet      -- Only letrec-bound escapees are interesting
+                | f_arity == n_args = emptyVarSet      -- Function doesn't escape
+                | otherwise         = myself           -- Inexact application; it does escape
 
        -- At the moment of the call:
 
@@ -524,12 +543,8 @@ vars_let let_no_escape bind body
 
        -- Compute the new let-expression
     let
-       new_let = if let_no_escape then
-                    -- trace "StgLetNoEscape!" (
-                    StgLetNoEscape live_in_whole_let bind_lvs bind2 body2
-                    -- )
-                 else
-                    StgLet bind2 body2
+       new_let | let_no_escape = StgLetNoEscape live_in_whole_let bind_lvs bind2 body2
+               | otherwise     = StgLet bind2 body2
 
        free_in_whole_let
          = (bind_fvs `unionFVInfo` body_fvs) `minusFVBinders` binders
@@ -549,6 +564,18 @@ vars_let let_no_escape bind body
                                                -- this let(rec)
 
        no_binder_escapes = isEmptyVarSet (set_of_binders `intersectVarSet` all_escs)
+
+#ifdef DEBUG
+       -- Debugging code as requested by Andrew Kennedy
+       checked_no_binder_escapes
+               | not no_binder_escapes && any is_join_var binders
+               = pprTrace "Interesting!  A join var that isn't let-no-escaped" (ppr binders)
+                 False
+               | otherwise = no_binder_escapes
+#else
+       checked_no_binder_escapes = no_binder_escapes
+#endif
+                           
                -- Mustn't depend on the passed-in let_no_escape flag, since
                -- no_binder_escapes is used by the caller to derive the flag!
     in
@@ -556,7 +583,7 @@ vars_let let_no_escape bind body
        new_let,
        free_in_whole_let,
        let_escs,
-       no_binder_escapes
+       checked_no_binder_escapes
     ))
   where
     set_of_binders = mkVarSet binders
@@ -565,7 +592,7 @@ vars_let let_no_escape bind body
                        StgRec pairs         -> map fst pairs
 
     mk_binding bind_lvs (binder,rhs)
-       = (binder `setIdArity` ArityExactly (stgArity rhs),
+       = (binder `setIdArityInfo` ArityExactly (stgArity rhs),
           LetrecBound  False           -- Not top level
                        live_vars
          )
@@ -607,6 +634,11 @@ vars_let let_no_escape bind body
                in
                returnLne (StgRec (binders' `zip` rhss2), fvs, escs, env_ext)
        ))
+
+is_join_var :: Id -> Bool
+-- A hack (used only for compiler debuggging) to tell if
+-- a variable started life as a join point ($j)
+is_join_var j = occNameUserString (getOccName j) == "$j"
 \end{code}
 
 %************************************************************************
@@ -734,10 +766,10 @@ lookupLiveVarsForSet fvs sw env lvs_cont
              sw env lvs_cont
   where
     do_one v
-      = if isLocallyDefined v then
+      = if isLocalId v then
            case (lookupVarEnv env v) of
              Just (_, LetrecBound _ lvs) -> extendVarSet lvs v
-             Just _                        -> unitVarSet v
+             Just _                      -> unitVarSet v
              Nothing -> pprPanic "lookupVarEnv/do_one:" (ppr v)
        else
            emptyVarSet
@@ -808,7 +840,7 @@ rhsArity (StgRhsCon _ _ _)              = 0
 rhsArity (StgRhsClosure _ _ _ _ _ args _) = length args
 
 zapArity :: Id -> Id
-zapArity id = id `setIdArity` UnknownArity
+zapArity id = id `setIdArityInfo` UnknownArity
 \end{code}