[project @ 2001-03-19 16:20:44 by simonpj]
[ghc-hetmet.git] / ghc / compiler / coreSyn / CoreUtils.lhs
index baae2ba..00d5723 100644 (file)
@@ -10,6 +10,9 @@ module CoreUtils (
        bindNonRec, mkIfThenElse, mkAltExpr,
         mkPiType,
 
+       -- Taking expressions apart
+       findDefault, findAlt,
+
        -- Properties of expressions
        exprType, coreAltsType, 
        exprIsBottom, exprIsDupable, exprIsTrivial, exprIsCheap, 
@@ -44,16 +47,16 @@ import Var          ( Var, isId, isTyVar )
 import VarSet
 import VarEnv
 import Name            ( hashName )
-import Literal         ( hashLiteral, literalType, litSize, litIsDupable )
+import Literal         ( hashLiteral, literalType, litIsDupable )
 import DataCon         ( DataCon, dataConRepArity )
 import PrimOp          ( primOpOkForSpeculation, primOpIsCheap, 
                          primOpIsDupable )
-import Id              ( Id, idType, idFlavour, idStrictness, idLBVarInfo, 
-                         mkWildId, idArity, idName, idUnfolding, idInfo, 
-                         isDataConId_maybe, isPrimOpId_maybe, mkSysLocal
+import Id              ( Id, idType, globalIdDetails, idStrictness, idLBVarInfo, 
+                         mkWildId, idArity, idName, idUnfolding, idInfo, isOneShotLambda,
+                         isDataConId_maybe, isPrimOpId_maybe, mkSysLocal, hasNoBinding
                        )
 import IdInfo          ( LBVarInfo(..),  
-                         IdFlavour(..),
+                         GlobalIdDetails(..),
                          megaSeqIdInfo )
 import Demand          ( appIsBottom )
 import Type            ( Type, mkFunTy, mkForAllTy, splitFunTy_maybe, 
@@ -242,6 +245,35 @@ mkIfThenElse guard then_expr else_expr
           (DataAlt falseDataCon, [], else_expr) ]
 \end{code}
 
+
+%************************************************************************
+%*                                                                     *
+\subsection{Taking expressions apart}
+%*                                                                     *
+%************************************************************************
+
+
+\begin{code}
+findDefault :: [CoreAlt] -> ([CoreAlt], Maybe CoreExpr)
+findDefault []                         = ([], Nothing)
+findDefault ((DEFAULT,args,rhs) : alts) = ASSERT( null alts && null args ) 
+                                         ([], Just rhs)
+findDefault (alt : alts)               = case findDefault alts of 
+                                           (alts', deflt) -> (alt : alts', deflt)
+
+findAlt :: AltCon -> [CoreAlt] -> CoreAlt
+findAlt con alts
+  = go alts
+  where
+    go []          = pprPanic "Missing alternative" (ppr con $$ vcat (map ppr alts))
+    go (alt : alts) | matches alt = alt
+                   | otherwise   = go alts
+
+    matches (DEFAULT, _, _) = True
+    matches (con1, _, _)    = con == con1
+\end{code}
+
+
 %************************************************************************
 %*                                                                     *
 \subsection{Figuring out things about expressions}
@@ -258,7 +290,17 @@ mkIfThenElse guard then_expr else_expr
 
 \begin{code}
 exprIsTrivial (Var v)
-  | Just op <- isPrimOpId_maybe v      = primOpIsDupable op
+  | hasNoBinding v                    = idArity v == 0
+       -- WAS: | Just op <- isPrimOpId_maybe v      = primOpIsDupable op
+       -- The idea here is that a constructor worker, like $wJust, is
+       -- really short for (\x -> $wJust x), becuase $wJust has no binding.
+       -- So it should be treated like a lambda.
+       -- Ditto unsaturated primops.
+       -- This came up when dealing with eta expansion/reduction for
+       --      x = $wJust
+       -- Here we want to eta-expand.  This looks like an optimisation,
+       -- but it's important (albeit tiresome) that CoreSat doesn't increase 
+       -- anything's arity
   | otherwise                          = True
 exprIsTrivial (Type _)                = True
 exprIsTrivial (Lit lit)               = True
@@ -273,6 +315,7 @@ exprIsAtom :: CoreExpr -> Bool
 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}
@@ -290,10 +333,11 @@ exprIsAtom other      = False
 
 
 \begin{code}
-exprIsDupable (Type _)      = True
-exprIsDupable (Var v)       = True
-exprIsDupable (Lit lit)      = litIsDupable lit
-exprIsDupable (Note _ e)     = exprIsDupable e
+exprIsDupable (Type _)         = True
+exprIsDupable (Var v)          = True
+exprIsDupable (Lit lit)        = litIsDupable lit
+exprIsDupable (Note InlineMe e) = True
+exprIsDupable (Note _ e)        = exprIsDupable e
 exprIsDupable expr          
   = go expr 0
   where
@@ -340,6 +384,7 @@ exprIsCheap :: CoreExpr -> Bool
 exprIsCheap (Lit lit)            = True
 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 (Case e _ alts)       = exprIsCheap e && 
@@ -377,7 +422,7 @@ idAppIsCheap id n_val_args
   | n_val_args == 0 = True     -- Just a type application of
                                -- a variable (f t1 t2 t3)
                                -- counts as WHNF
-  | otherwise = case idFlavour id of
+  | otherwise = case globalIdDetails id of
                  DataConId _   -> True                 
                  RecordSelId _ -> True                 -- I'm experimenting with making record selection
                                                        -- look cheap, so we will substitute it inside a
@@ -425,7 +470,7 @@ exprOkForSpeculation other_expr
   = go other_expr 0 True
   where
     go (Var f) n_args args_ok 
-      = case idFlavour f of
+      = case globalIdDetails f of
          DataConId _ -> True   -- The strictness of the constructor has already
                                -- been expressed by its "wrapper", so we don't need
                                -- to take the arguments into account
@@ -467,7 +512,19 @@ evaluated to WHNF.  This is used to decide wether it's ok to change
 
 and to decide whether it's safe to discard a `seq`
 
-So, it does *not* treat variables as evaluated, unless they say they are
+So, it does *not* treat variables as evaluated, unless they say they are.
+
+But it *does* treat partial applications and constructor applications
+as values, even if their arguments are non-trivial; 
+       e.g.  (:) (f x) (map f xs)      is a value
+             map (...redex...)         is a value
+Because `seq` on such things completes immediately
+
+A possible worry: constructors with unboxed args:
+               C (f x :: Int#)
+Suppose (f x) diverges; then C (f x) is not a value.  True, but
+this form is illegal (see the invariants in CoreSyn).  Args of unboxed
+type must be ok-for-speculation (or trivial).
 
 \begin{code}
 exprIsValue :: CoreExpr -> Bool                -- True => Value-lambda, constructor, PAP
@@ -491,7 +548,7 @@ exprIsValue other_expr
 
 idAppIsValue :: Id -> Int -> Bool
 idAppIsValue id n_val_args 
-  = case idFlavour id of
+  = case globalIdDetails id of
        DataConId _ -> True
        PrimOpId _  -> n_val_args < idArity id
        other | n_val_args == 0 -> isEvaldUnfolding (idUnfolding id)
@@ -506,18 +563,17 @@ exprIsConApp_maybe expr
   = analyse (collectArgs expr)
   where
     analyse (Var fun, args)
-       | maybeToBool maybe_con_app = maybe_con_app
-       where
-         maybe_con_app = case isDataConId_maybe fun of
-                               Just con | length args >= dataConRepArity con 
-                                       -- Might be > because the arity excludes type args
-                                        -> Just (con, args)
-                               other    -> Nothing
+       | Just con <- isDataConId_maybe fun,
+         length args >= dataConRepArity con
+               -- Might be > because the arity excludes type args
+       = Just (con,args)
 
+       -- Look through unfoldings, but only cheap ones, because
+       -- we are effectively duplicating the unfolding
     analyse (Var fun, [])
-       = case maybeUnfoldingTemplate (idUnfolding fun) of
-               Nothing  -> Nothing
-               Just unf -> exprIsConApp_maybe unf
+       | let unf = idUnfolding fun,
+         isCheapUnfolding unf
+       = exprIsConApp_maybe (unfoldingTemplate unf)
 
     analyse other = Nothing
 \end{code}
@@ -593,30 +649,59 @@ exprEtaExpandArity :: CoreExpr -> (Int, Bool)
 --     case x of p -> \s -> ...
 -- because for I/O ish things we really want to get that \s to the top.
 -- We are prepared to evaluate x each time round the loop in order to get that
--- Hence "generous" arity
+--
+-- 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
+--     NB: this is particularly important/useful for IO state 
+--     transformers, where we often get
+--             let x = E in \ s -> ...
+--     and the \s is a real-world state token abstraction.  Such 
+--     abstractions are almost invariably 1-shot, so we want to
+--     pull the \s out, past the let x=E.  
+--     The hack is in Id.isOneShotLambda
 
 exprEtaExpandArity e
   = go 0 e
   where
+    go :: Int -> CoreExpr -> (Int,Bool)
     go ar (Lam x e)  | isId x          = go (ar+1) e
                     | otherwise        = go ar e
     go ar (Note n e) | ok_note n       = go ar e
     go ar other                        = (ar + ar', ar' == 0)
                                        where
-                                         ar' = go1 other `max` 0
-
-    go1 (Var v)                                = idArity v
-    go1 (Lam x e)  | isId x            = go1 e + 1
-                  | otherwise          = go1 e
-    go1 (Note n e) | ok_note n         = go1 e
-    go1 (App f (Type _))                       = go1 f
-    go1 (App f a)  | exprIsCheap a     = go1 f - 1
-    go1 (Case scrut _ alts)
-      | exprIsCheap scrut              = min_zero [go1 rhs | (_,_,rhs) <- alts]
-    go1 (Let b e)      
-      | all exprIsCheap (rhssOfBind b) = go1 e
-    
-    go1 other                          = 0
+                                         ar' = length (go1 other)
+
+    go1 :: CoreExpr -> [Bool]
+       -- (go1 e) = [b1,..,bn]
+       -- means expression can be rewritten \x_b1 -> ... \x_bn -> body
+       -- where bi is True <=> the lambda is one-shot
+
+    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
+
+       -- Lambdas; increase arity
+    go1 (Lam x e)  | isId x     = isOneShotLambda x : go1 e
+                  | otherwise  = go1 e
+
+       -- Applications; decrease arity
+    go1 (App f (Type _))       = go1 f
+    go1 (App f a)              = case go1 f of
+                                   (one_shot : xs) | one_shot || exprIsCheap a -> xs
+                                   other                                       -> []
+                                                          
+       -- Case/Let; keep arity if either the expression is cheap
+       -- or it's a 1-shot lambda
+    go1 (Case scrut _ alts) = case foldr1 (zipWith (&&)) [go1 rhs | (_,_,rhs) <- alts] of
+                               xs@(one_shot : _) | one_shot || exprIsCheap scrut -> xs
+                               other                                             -> []
+    go1 (Let b e) = case go1 e of
+                     xs@(one_shot : _) | one_shot || all exprIsCheap (rhssOfBind b) -> xs
+                     other                                                          -> []
+
+    go1 other = []
     
     ok_note (Coerce _ _) = True
     ok_note InlineCall   = True