[project @ 2003-11-17 14:23:30 by simonmar]
[ghc-hetmet.git] / ghc / compiler / coreSyn / CoreUtils.lhs
index 91981c2..67d1610 100644 (file)
@@ -6,19 +6,19 @@
 \begin{code}
 module CoreUtils (
        -- Construction
-       mkNote, mkInlineMe, mkSCC, mkCoerce, mkCoerce2,
+       mkInlineMe, mkSCC, mkCoerce, mkCoerce2,
        bindNonRec, needsCaseBinding,
        mkIfThenElse, mkAltExpr, mkPiType, mkPiTypes,
 
        -- Taking expressions apart
-       findDefault, findAlt, hasDefault,
+       findDefault, findAlt,
 
        -- Properties of expressions
-       exprType, coreAltsType, 
-       exprIsBottom, exprIsDupable, exprIsTrivial, exprIsCheap, 
+       exprType,
+       exprIsDupable, exprIsTrivial, exprIsCheap, 
        exprIsValue,exprOkForSpeculation, exprIsBig, 
-       exprIsConApp_maybe, exprIsAtom,
-       idAppIsBottom, idAppIsCheap, rhsIsNonUpd,
+       exprIsConApp_maybe, 
+       rhsIsStatic,
 
        -- Arity and eta expansion
        manifestArity, exprArity, 
@@ -31,10 +31,7 @@ module CoreUtils (
        hashExpr,
 
        -- Equality
-       cheapEqExpr, eqExpr, applyTypeToArgs, applyTypeToArg,
-
-       -- Cross-DLL references
-       isCrossDllConApp,
+       cheapEqExpr, eqExpr, applyTypeToArgs, applyTypeToArg
     ) where
 
 #include "HsVersions.h"
@@ -48,9 +45,9 @@ import Var            ( Var, isId, isTyVar )
 import VarEnv
 import Name            ( hashName, isDllName )
 import Literal         ( hashLiteral, literalType, litIsDupable, 
-                         litIsTrivial, isZeroLit, isLitLitLit )
+                         litIsTrivial, isZeroLit )
 import DataCon         ( DataCon, dataConRepArity, dataConArgTys,
-                         isExistentialDataCon, dataConTyCon, dataConName )
+                         isExistentialDataCon, dataConTyCon )
 import PrimOp          ( PrimOp(..), primOpOkForSpeculation, primOpIsCheap )
 import Id              ( Id, idType, globalIdDetails, idNewStrictness, 
                          mkWildId, idArity, idName, idUnfolding, idInfo,
@@ -62,7 +59,7 @@ import NewDemand      ( appIsBottom )
 import Type            ( Type, mkFunTy, mkForAllTy, splitFunTy_maybe,
                          splitFunTy,
                          applyTys, isUnLiftedType, seqType, mkTyVarTy,
-                         splitForAllTy_maybe, isForAllTy, splitNewType_maybe, 
+                         splitForAllTy_maybe, isForAllTy, splitRecNewType_maybe, 
                          splitTyConApp_maybe, eqType, funResultTy, applyTy,
                          funResultTy, applyTy
                        )
@@ -157,11 +154,13 @@ applyTypeToArgs e op_ty (other_arg : args)
 mkNote removes redundant coercions, and SCCs where possible
 
 \begin{code}
+#ifdef UNUSED
 mkNote :: Note -> CoreExpr -> CoreExpr
 mkNote (Coerce to_ty from_ty) expr = mkCoerce2 to_ty from_ty expr
 mkNote (SCC cc)        expr               = mkSCC cc expr
 mkNote InlineMe expr              = mkInlineMe expr
 mkNote note     expr              = Note note expr
+#endif
 
 -- Slide InlineCall in around the function
 --     No longer necessary I think (SLPJ Apr 99)
@@ -279,10 +278,6 @@ The default alternative must be first, if it exists at all.
 This makes it easy to find, though it makes matching marginally harder.
 
 \begin{code}
-hasDefault :: [CoreAlt] -> Bool
-hasDefault ((DEFAULT,_,_) : alts) = True
-hasDefault _                     = False
-
 findDefault :: [CoreAlt] -> ([CoreAlt], Maybe CoreExpr)
 findDefault ((DEFAULT,args,rhs) : alts) = ASSERT( null args ) (alts, Just rhs)
 findDefault alts                       =                     (alts, Nothing)
@@ -328,24 +323,20 @@ completely un-applied primops and foreign-call Ids are sufficiently
 rare that I plan to allow them to be duplicated and put up with
 saturating them.
 
+SCC notes.  We do not treat (_scc_ "foo" x) as trivial, because 
+  a) it really generates code, (and a heap object when it's 
+     a function arg) to capture the cost centre
+  b) see the note [SCC-and-exprIsTrivial] in Simplify.simplLazyBind
+
 \begin{code}
 exprIsTrivial (Var v)     = True       -- See notes above
 exprIsTrivial (Type _)    = True
 exprIsTrivial (Lit lit)    = litIsTrivial lit
 exprIsTrivial (App e arg)  = not (isRuntimeArg arg) && exprIsTrivial e
-exprIsTrivial (Note _ e)   = exprIsTrivial e
+exprIsTrivial (Note (SCC _) e) = False         -- See notes above
+exprIsTrivial (Note _       e) = exprIsTrivial e
 exprIsTrivial (Lam b body) = not (isRuntimeVar b) && exprIsTrivial body
 exprIsTrivial other       = False
-
-exprIsAtom :: CoreExpr -> Bool
--- Used to decide whether to let-binding an STG argument
--- when compiling to ILX => type applications are not allowed
-exprIsAtom (Var v)    = True   -- primOpIsDupable?
-exprIsAtom (Lit lit)  = True
-exprIsAtom (Type ty)  = True
-exprIsAtom (Note (SCC _) e) = False
-exprIsAtom (Note _ e) = exprIsAtom e
-exprIsAtom other      = False
 \end{code}
 
 
@@ -939,13 +930,15 @@ eta_expand n us expr ty
        ; Nothing ->
 
                -- Given this:
-               --      newtype T = MkT (Int -> Int)
+               --      newtype T = MkT ([T] -> Int)
                -- Consider eta-expanding this
                --      eta_expand 1 e T
                -- We want to get
-               --      coerce T (\x::Int -> (coerce (Int->Int) e) x)
+               --      coerce T (\x::[T] -> (coerce ([T]->Int) e) x)
+               -- Only try this for recursive newtypes; the non-recursive kind
+               -- are transparent anyway
 
-       case splitNewType_maybe ty of {
+       case splitRecNewType_maybe ty of {
          Just ty' -> mkCoerce2 ty ty' (eta_expand n us (mkCoerce2 ty' ty expr) ty') ;
          Nothing  -> pprTrace "Bad eta expand" (ppr expr $$ ppr ty) expr
        }}}
@@ -1160,49 +1153,67 @@ hashId id = hashName (idName id)
 
 %************************************************************************
 %*                                                                     *
-\subsection{Cross-DLL references}
+\subsection{Determining non-updatable right-hand-sides}
 %*                                                                     *
 %************************************************************************
 
-Top-level constructor applications can usually be allocated 
-statically, but they can't if 
-   a) the constructor, or any of the arguments, come from another DLL
-   b) any of the arguments are LitLits
-(because we can't refer to static labels in other DLLs).
+Top-level constructor applications can usually be allocated
+statically, but they can't if the constructor, or any of the
+arguments, come from another DLL (because we can't refer to static
+labels in other DLLs).
 
 If this happens we simply make the RHS into an updatable thunk, 
 and 'exectute' it rather than allocating it statically.
 
-We also catch lit-lit arguments here, because those cannot be used in
-static constructors either.  (litlits are deprecated, so I'm not going
-to bother cleaning up this infelicity --SDM).
-
 \begin{code}
-isCrossDllConApp :: DataCon -> [CoreExpr] -> Bool
-isCrossDllConApp con args =
-  isDllName (dataConName con) || any isCrossDllArg args
-
-isCrossDllArg :: CoreExpr -> Bool
--- True if somewhere in the expression there's a cross-DLL reference
-isCrossDllArg (Type _)    = False
-isCrossDllArg (Var v)     = isDllName (idName v)
-isCrossDllArg (Note _ e)  = isCrossDllArg e
-isCrossDllArg (Lit lit)   = isLitLitLit lit
-isCrossDllArg (App e1 e2) = isCrossDllArg e1 || isCrossDllArg e2
-                               -- must be a type app
-isCrossDllArg (Lam v e)   = isCrossDllArg e
-                               -- must be a type lam
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection{Determining non-updatable right-hand-sides}
-%*                                                                     *
-%************************************************************************
-
-\begin{code}
-rhsIsNonUpd :: CoreExpr -> Bool
--- True => Value-lambda, saturated constructor
+rhsIsStatic :: CoreExpr -> Bool
+-- This function is called only on *top-level* right-hand sides
+-- Returns True if the RHS can be allocated statically, with
+-- no thunks involved at all.
+--
+-- It's called (i) in TidyPgm.hasCafRefs to decide if the rhs is, or
+-- refers to, CAFs; and (ii) in CoreToStg to decide whether to put an
+-- update flag on it.
+--
+-- The basic idea is that rhsIsStatic returns True only if the RHS is
+--     (a) a value lambda
+--     (b) a saturated constructor application with static args
+--
+-- BUT watch out for
+--  (i)        Any cross-DLL references kill static-ness completely
+--     because they must be 'executed' not statically allocated
+--
+-- (ii) We treat partial applications as redexes, because in fact we 
+--     make a thunk for them that runs and builds a PAP
+--     at run-time.  The only appliations that are treated as 
+--     static are *saturated* applications of constructors.
+
+-- We used to try to be clever with nested structures like this:
+--             ys = (:) w ((:) w [])
+-- on the grounds that CorePrep will flatten ANF-ise it later.
+-- But supporting this special case made the function much more 
+-- complicated, because the special case only applies if there are no 
+-- enclosing type lambdas:
+--             ys = /\ a -> Foo (Baz ([] a))
+-- Here the nested (Baz []) won't float out to top level in CorePrep.
+--
+-- But in fact, even without -O, nested structures at top level are 
+-- flattened by the simplifier, so we don't need to be super-clever here.
+--
+-- Examples
+--
+--     f = \x::Int. x+7        TRUE
+--     p = (True,False)        TRUE
+--
+--     d = (fst p, False)      FALSE because there's a redex inside
+--                             (this particular one doesn't happen but...)
+--
+--     h = D# (1.0## /## 2.0##)        FALSE (redex again)
+--     n = /\a. Nil a                  TRUE
+--
+--     t = /\a. (:) (case w a of ...) (Nil a)  FALSE (redex)
+--
+--
 -- This is a bit like CoreUtils.exprIsValue, with the following differences:
 --    a) scc "foo" (\x -> ...) is updatable (so we catch the right SCC)
 --
@@ -1213,39 +1224,49 @@ rhsIsNonUpd :: CoreExpr -> Bool
 --
 -- When opt_RuntimeTypes is on, we keep type lambdas and treat
 -- them as making the RHS re-entrant (non-updatable).
---
-rhsIsNonUpd (Lam b e)          = isRuntimeVar b || rhsIsNonUpd e
-rhsIsNonUpd (Note (SCC _) e)   = False
-rhsIsNonUpd (Note _ e)         = rhsIsNonUpd e
-rhsIsNonUpd other_expr
-  = go other_expr 0 []
+
+rhsIsStatic rhs = is_static False rhs
+
+is_static :: Bool      -- True <=> in a constructor argument; must be atomic
+         -> CoreExpr -> Bool
+
+is_static False (Lam b e) = isRuntimeVar b || is_static False e
+
+is_static in_arg (Note (SCC _) e) = False
+is_static in_arg (Note _ e)       = is_static in_arg e
+is_static in_arg (Lit lit)        = True
+
+is_static in_arg other_expr = go other_expr 0
   where
-    go (Var f) n_args args = idAppIsNonUpd f n_args args
-       
-    go (App f a) n_args args
-       | isTypeArg a = go f n_args args
-       | otherwise   = go f (n_args + 1) (a:args)
-
-    go (Note (SCC _) f) n_args args = False
-    go (Note _ f) n_args args       = go f n_args args
-
-    go other n_args args = False
-
-idAppIsNonUpd :: Id -> Int -> [CoreExpr] -> Bool
-idAppIsNonUpd id n_val_args args
-  -- saturated constructors are not updatable
-  | Just con <- isDataConWorkId_maybe id,
-    n_val_args == dataConRepArity con,
-    not (isCrossDllConApp con args),
-    all exprIsAtom args
-    = True
-   -- NB. args sometimes not atomic.  eg.
-   --   x = D# (1.0## /## 2.0##)
-   -- can't float because /## can fail.
-
-  | otherwise = False
-    -- Historical note: we used to make partial applications
-    -- non-updatable, so they behaved just like PAPs, but this
-    -- doesn't work too well with eval/apply so it is disabled
-    -- now.
+    go (Var f) n_val_args
+       | not (isDllName (idName f))
+       =  saturated_data_con f n_val_args
+       || (in_arg && n_val_args == 0)  
+               -- A naked un-applied variable is *not* deemed a static RHS
+               -- E.g.         f = g
+               -- Reason: better to update so that the indirection gets shorted
+               --         out, and the true value will be seen
+               -- NB: if you change this, you'll break the invariant that THUNK_STATICs
+               --     are always updatable.  If you do so, make sure that non-updatable
+               --     ones have enough space for their static link field!
+
+    go (App f a) n_val_args
+       | isTypeArg a                    = go f n_val_args
+       | not in_arg && is_static True a = go f (n_val_args + 1)
+       -- The (not in_arg) checks that we aren't in a constructor argument;
+       -- if we are, we don't allow (value) applications of any sort
+       -- 
+        -- NB. In case you wonder, args are sometimes not atomic.  eg.
+        --   x = D# (1.0## /## 2.0##)
+        -- can't float because /## can fail.
+
+    go (Note (SCC _) f) n_val_args = False
+    go (Note _ f) n_val_args       = go f n_val_args
+
+    go other n_val_args = False
+
+    saturated_data_con f n_val_args
+       = case isDataConWorkId_maybe f of
+           Just dc -> n_val_args == dataConRepArity dc
+           Nothing -> False
 \end{code}