[project @ 2001-05-24 15:10:19 by dsyme]
[ghc-hetmet.git] / ghc / compiler / coreSyn / CoreUtils.lhs
index 00d5723..e513548 100644 (file)
@@ -19,7 +19,7 @@ module CoreUtils (
        exprIsValue,exprOkForSpeculation, exprIsBig, 
        exprIsConApp_maybe, exprIsAtom,
        idAppIsBottom, idAppIsCheap,
-       exprArity,
+       exprArity, isRuntimeVar, isRuntimeArg, 
 
        -- Expr transformation
        etaReduce, etaExpand,
@@ -49,11 +49,10 @@ import VarEnv
 import Name            ( hashName )
 import Literal         ( hashLiteral, literalType, litIsDupable )
 import DataCon         ( DataCon, dataConRepArity )
-import PrimOp          ( primOpOkForSpeculation, primOpIsCheap, 
-                         primOpIsDupable )
+import PrimOp          ( primOpOkForSpeculation, primOpIsCheap )
 import Id              ( Id, idType, globalIdDetails, idStrictness, idLBVarInfo, 
                          mkWildId, idArity, idName, idUnfolding, idInfo, isOneShotLambda,
-                         isDataConId_maybe, isPrimOpId_maybe, mkSysLocal, hasNoBinding
+                         isDataConId_maybe, mkSysLocal, hasNoBinding
                        )
 import IdInfo          ( LBVarInfo(..),  
                          GlobalIdDetails(..),
@@ -61,14 +60,14 @@ import IdInfo               ( LBVarInfo(..),
 import Demand          ( appIsBottom )
 import Type            ( Type, mkFunTy, mkForAllTy, splitFunTy_maybe, 
                          applyTys, isUnLiftedType, seqType, mkUTy, mkTyVarTy,
-                         splitForAllTy_maybe, splitNewType_maybe
+                         splitForAllTy_maybe, splitNewType_maybe, isForAllTy
                        )
 import TysWiredIn      ( boolTy, trueDataCon, falseDataCon )
 import CostCentre      ( CostCentre )
 import UniqSupply      ( UniqSupply, splitUniqSupply, uniqFromSupply )
-import Maybes          ( maybeToBool )
 import Outputable
 import TysPrim         ( alphaTy )     -- Debugging only
+import CmdLineOpts     ( opt_KeepStgTypes )
 \end{code}
 
 
@@ -199,11 +198,12 @@ mkCoerce to_ty from_ty expr
 \begin{code}
 mkSCC :: CostCentre -> Expr b -> Expr b
        -- Note: Nested SCC's *are* preserved for the benefit of
-       --       cost centre stack profiling (Durham)
-
-mkSCC cc (Lit lit) = Lit lit
-mkSCC cc (Lam x e) = Lam x (mkSCC cc e)        -- Move _scc_ inside lambda
-mkSCC cc expr     = Note (SCC cc) expr
+       --       cost centre stack profiling
+mkSCC cc (Lit lit)         = Lit lit
+mkSCC cc (Lam x e)         = Lam x (mkSCC cc e)  -- Move _scc_ inside lambda
+mkSCC cc (Note (SCC cc') e) = Note (SCC cc) (Note (SCC cc') e)
+mkSCC cc (Note n e)        = Note n (mkSCC cc e) -- Move _scc_ inside notes
+mkSCC cc expr              = Note (SCC cc) expr
 \end{code}
 
 
@@ -304,9 +304,9 @@ exprIsTrivial (Var v)
   | otherwise                          = True
 exprIsTrivial (Type _)                = True
 exprIsTrivial (Lit lit)               = True
-exprIsTrivial (App e arg)             = isTypeArg arg && exprIsTrivial e
+exprIsTrivial (App e arg)             = not (isRuntimeArg arg) && exprIsTrivial e
 exprIsTrivial (Note _ e)              = exprIsTrivial e
-exprIsTrivial (Lam b body) | isTyVar b = exprIsTrivial body
+exprIsTrivial (Lam b body)             = not (isRuntimeVar b) && exprIsTrivial body
 exprIsTrivial other                   = False
 
 exprIsAtom :: CoreExpr -> Bool
@@ -386,7 +386,7 @@ exprIsCheap (Type _)                  = True
 exprIsCheap (Var _)              = True
 exprIsCheap (Note InlineMe e)            = True
 exprIsCheap (Note _ e)           = exprIsCheap e
-exprIsCheap (Lam x e)            = if isId x then True else exprIsCheap e
+exprIsCheap (Lam x e)            = isRuntimeVar x || exprIsCheap e
 exprIsCheap (Case e _ alts)       = exprIsCheap e && 
                                    and [exprIsCheap rhs | (_,_,rhs) <- alts]
        -- Experimentally, treat (case x of ...) as cheap
@@ -412,7 +412,7 @@ exprIsCheap other_expr
                        -- because it certainly doesn't need to be shared!
        
     go (App f a) n_args args_cheap 
-       | isTypeArg a = go f n_args       args_cheap
+       | not (isRuntimeArg a) = go f n_args      args_cheap
        | otherwise   = go f (n_args + 1) (exprIsCheap a && args_cheap)
 
     go other   n_args args_cheap = False
@@ -482,7 +482,7 @@ exprOkForSpeculation other_expr
          other -> False
        
     go (App f a) n_args args_ok 
-       | isTypeArg a = go f n_args       args_ok
+       | not (isRuntimeArg a) = go f n_args      args_ok
        | otherwise   = go f (n_args + 1) (exprOkForSpeculation a && args_ok)
 
     go other n_args args_ok = False
@@ -531,7 +531,7 @@ exprIsValue :: CoreExpr -> Bool             -- True => Value-lambda, constructor, PAP
 exprIsValue (Type ty)    = True        -- Types are honorary Values; we don't mind
                                        -- copying them
 exprIsValue (Lit l)      = True
-exprIsValue (Lam b e)            = isId b || exprIsValue e
+exprIsValue (Lam b e)            = isRuntimeVar b || exprIsValue e
 exprIsValue (Note _ e)           = exprIsValue e
 exprIsValue other_expr
   = go other_expr 0
@@ -539,7 +539,7 @@ exprIsValue other_expr
     go (Var f) n_args = idAppIsValue f n_args
        
     go (App f a) n_args
-       | isTypeArg a = go f n_args
+       | not (isRuntimeArg a) = go f n_args
        | otherwise   = go f (n_args + 1) 
 
     go (Note _ f) n_args = go f n_args
@@ -557,10 +557,28 @@ idAppIsValue id n_val_args
        -- then we could get an infinite loop...
 \end{code}
 
+@isRuntimeVar v@ returns if (Lam v _) really becomes a lambda at runtime,
+i.e. if type applications are actual lambdas because types are kept around
+at runtime.
+
+\begin{code}
+isRuntimeVar :: Var -> Bool
+isRuntimeVar v = opt_KeepStgTypes || isId v
+isRuntimeArg :: CoreExpr -> Bool
+isRuntimeArg v = opt_KeepStgTypes || isTypeArg v
+\end{code}
+
 \begin{code}
+
+
 exprIsConApp_maybe :: CoreExpr -> Maybe (DataCon, [CoreExpr])
-exprIsConApp_maybe expr
-  = analyse (collectArgs expr)
+exprIsConApp_maybe (Note InlineMe expr) = exprIsConApp_maybe expr
+    -- We ignore InlineMe notes in case we have
+    -- x = __inline_me__ (a,b)
+    -- All part of making sure that INLINE pragmas never hurt
+    -- Marcin tripped on this one when making dictionaries more inlinable
+
+exprIsConApp_maybe expr = analyse (collectArgs expr)
   where
     analyse (Var fun, args)
        | Just con <- isDataConId_maybe fun,
@@ -578,20 +596,6 @@ exprIsConApp_maybe expr
     analyse other = Nothing
 \end{code}
 
-The arity of an expression (in the code-generator sense, i.e. the
-number of lambdas at the beginning).
-
-\begin{code}
-exprArity :: CoreExpr -> Int
-exprArity (Lam x e)
-  | isTyVar x = exprArity e
-  | otherwise = 1 + exprArity e
-exprArity (Note _ e)
-  -- Ignore coercions.   Top level sccs are removed by the final 
-  -- profiling pass, so we ignore those too.
-  = exprArity e
-exprArity _ = 0
-\end{code}
 
 
 %************************************************************************
@@ -652,7 +656,8 @@ exprEtaExpandArity :: CoreExpr -> (Int, Bool)
 --
 -- Consider    let x = expensive in \y z -> E
 -- We want this to have arity 2 if the \y-abstraction is a 1-shot lambda
--- Hence the extra Bool returned by go1
+-- 
+-- Hence the list of Bools returned by go1
 --     NB: this is particularly important/useful for IO state 
 --     transformers, where we often get
 --             let x = E in \ s -> ...
@@ -680,7 +685,7 @@ exprEtaExpandArity e
     go1 (Note n e) | ok_note n = go1 e
     go1 (Var v)                        = replicate (idArity v) False   -- When the type of the Id
                                                                -- encodes one-shot-ness, use
-                                                               -- th iinfo here
+                                                               -- the idinfo here
 
        -- Lambdas; increase arity
     go1 (Lam x e)  | isId x     = isOneShotLambda x : go1 e
@@ -707,7 +712,7 @@ exprEtaExpandArity e
     ok_note InlineCall   = True
     ok_note other        = False
            -- Notice that we do not look through __inline_me__
-           -- This one is a bit more surprising, but consider
+           -- This may seem surprising, but consider
            --  f = _inline_me (\x -> e)
            -- We DO NOT want to eta expand this to
            --  f = \x -> (_inline_me (\x -> e)) x
@@ -747,10 +752,17 @@ etaExpand :: Int          -- Add this number of value args
 -- would return
 --     (/\b. coerce T (\y::A -> (coerce (A->B) (E b) y)
 
--- (case x of { I# x -> /\ a -> coerce T E)
-
 etaExpand n us expr ty
-  | n == 0     -- Saturated, so nothing to do
+  | n == 0 && 
+    -- The ILX code generator requires eta expansion for type arguments
+    -- too, but alas the 'n' doesn't tell us how many of them there 
+    -- may be.  So we eagerly eta expand any big lambdas, and just
+    -- cross our fingers about possible loss of sharing in the
+    -- ILX case. 
+    -- The Right Thing is probably to make 'arity' include
+    -- type variables throughout the compiler.  (ToDo.)
+    not (isForAllTy ty)        
+    -- Saturated, so nothing to do
   = expr
 
   | otherwise  -- An unsaturated constructor or primop; eta expand it
@@ -776,6 +788,42 @@ etaExpand n us expr ty
 \end{code}
 
 
+exprArity is a cheap-and-cheerful version of exprEtaExpandArity.
+It tells how many things the expression can be applied to before doing
+any work.  It doesn't look inside cases, lets, etc.  The idea is that
+exprEtaExpandArity will do the hard work, leaving something that's easy
+for exprArity to grapple with.  In particular, Simplify uses exprArity to
+compute the ArityInfo for the Id. 
+
+Originally I thought that it was enough just to look for top-level lambdas, but
+it isn't.  I've seen this
+
+       foo = PrelBase.timesInt
+
+We want foo to get arity 2 even though the eta-expander will leave it
+unchanged, in the expectation that it'll be inlined.  But occasionally it
+isn't, because foo is blacklisted (used in a rule).  
+
+Similarly, see the ok_note check in exprEtaExpandArity.  So 
+       f = __inline_me (\x -> e)
+won't be eta-expanded.
+
+And in any case it seems more robust to have exprArity be a bit more intelligent.
+
+\begin{code}
+exprArity :: CoreExpr -> Int
+exprArity e = go e `max` 0
+           where
+             go (Lam x e) | isId x    = go e + 1
+                          | otherwise = go e
+             go (Note _ e)            = go e
+             go (App e (Type t))      = go e
+             go (App f a)             = go f - 1
+             go (Var v)               = idArity v
+             go _                     = 0
+\end{code}
+
+
 %************************************************************************
 %*                                                                     *
 \subsection{Equality}