[project @ 2001-06-28 08:36:30 by simonpj]
[ghc-hetmet.git] / ghc / compiler / coreSyn / CoreUtils.lhs
index 4d3ae6d..bea8316 100644 (file)
@@ -11,7 +11,7 @@ module CoreUtils (
         mkPiType,
 
        -- Taking expressions apart
-       findDefault, findAlt,
+       findDefault, findAlt, hasDefault,
 
        -- Properties of expressions
        exprType, coreAltsType, 
@@ -19,7 +19,7 @@ module CoreUtils (
        exprIsValue,exprOkForSpeculation, exprIsBig, 
        exprIsConApp_maybe, exprIsAtom,
        idAppIsBottom, idAppIsCheap,
-       exprArity,
+       exprArity, 
 
        -- 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,12 +60,11 @@ import IdInfo               ( LBVarInfo(..),
 import Demand          ( appIsBottom )
 import Type            ( Type, mkFunTy, mkForAllTy, splitFunTy_maybe, 
                          applyTys, isUnLiftedType, seqType, mkUTy, mkTyVarTy,
-                         splitForAllTy_maybe, splitNewType_maybe
+                         splitForAllTy_maybe, isForAllTy, eqType
                        )
 import TysWiredIn      ( boolTy, trueDataCon, falseDataCon )
 import CostCentre      ( CostCentre )
 import UniqSupply      ( UniqSupply, splitUniqSupply, uniqFromSupply )
-import Maybes          ( maybeToBool )
 import Outputable
 import TysPrim         ( alphaTy )     -- Debugging only
 \end{code}
@@ -187,13 +185,13 @@ mkInlineMe e         = Note InlineMe e
 mkCoerce :: Type -> Type -> CoreExpr -> CoreExpr
 
 mkCoerce to_ty from_ty (Note (Coerce to_ty2 from_ty2) expr)
-  = ASSERT( from_ty == to_ty2 )
+  = ASSERT( from_ty `eqType` to_ty2 )
     mkCoerce to_ty from_ty2 expr
 
 mkCoerce to_ty from_ty expr
-  | to_ty == from_ty = expr
-  | otherwise       = ASSERT( from_ty == exprType expr )
-                      Note (Coerce to_ty from_ty) expr
+  | to_ty `eqType` from_ty = expr
+  | otherwise             = ASSERT( from_ty `eqType` exprType expr )
+                            Note (Coerce to_ty from_ty) expr
 \end{code}
 
 \begin{code}
@@ -253,25 +251,31 @@ mkIfThenElse guard then_expr else_expr
 %*                                                                     *
 %************************************************************************
 
+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 []                         = ([], 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)
+findDefault ((DEFAULT,args,rhs) : alts) = ASSERT( null args ) (alts, Just rhs)
+findDefault alts                       =                     (alts, Nothing)
 
 findAlt :: AltCon -> [CoreAlt] -> CoreAlt
 findAlt con alts
-  = go alts
+  = case alts of
+       (deflt@(DEFAULT,_,_):alts) -> go alts deflt
+       other                      -> go alts panic_deflt
+
   where
-    go []          = pprPanic "Missing alternative" (ppr con $$ vcat (map ppr alts))
-    go (alt : alts) | matches alt = alt
-                   | otherwise   = go alts
+    panic_deflt = pprPanic "Missing alternative" (ppr con $$ vcat (map ppr alts))
 
-    matches (DEFAULT, _, _) = True
-    matches (con1, _, _)    = con == con1
+    go []                     deflt               = deflt
+    go (alt@(con1,_,_) : alts) deflt | con == con1 = alt
+                                    | otherwise   = ASSERT( not (con1 == DEFAULT) )
+                                                    go alts deflt
 \end{code}
 
 
@@ -305,9 +309,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
@@ -387,7 +391,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
@@ -413,8 +417,8 @@ 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
-       | otherwise   = go f (n_args + 1) (exprIsCheap a && 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
 
@@ -483,8 +487,8 @@ exprOkForSpeculation other_expr
          other -> False
        
     go (App f a) n_args args_ok 
-       | isTypeArg a = go f n_args       args_ok
-       | otherwise   = go f (n_args + 1) (exprOkForSpeculation a && 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
 \end{code}
@@ -508,7 +512,7 @@ idAppIsBottom id n_val_args = appIsBottom (idStrictness id) n_val_args
 \end{code}
 
 @exprIsValue@ returns true for expressions that are certainly *already* 
-evaluated to WHNF.  This is used to decide wether it's ok to change
+evaluated to WHNF.  This is used to decide whether it's ok to change
        case x of _ -> e   ===>   e
 
 and to decide whether it's safe to discard a `seq`
@@ -532,7 +536,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
@@ -540,8 +544,8 @@ exprIsValue other_expr
     go (Var f) n_args = idAppIsValue f n_args
        
     go (App f a) n_args
-       | isTypeArg a = go f n_args
-       | otherwise   = go f (n_args + 1) 
+       | not (isRuntimeArg a) = go f n_args
+       | otherwise            = go f (n_args + 1) 
 
     go (Note _ f) n_args = go f n_args
 
@@ -708,15 +712,6 @@ exprEtaExpandArity e
            -- giving just
            --  f = \x -> e
            -- A Bad Idea
-
-min_zero :: [Int] -> Int       -- Find the minimum, but zero is the smallest
-min_zero (x:xs) = go x xs
-               where
-                 go 0   xs                 = 0         -- Nothing beats zero
-                 go min []                 = min
-                 go min (x:xs) | x < min   = go x xs
-                               | otherwise = go min xs 
-
 \end{code}
 
 
@@ -741,7 +736,16 @@ etaExpand :: Int           -- Add this number of value args
 --     (/\b. coerce T (\y::A -> (coerce (A->B) (E b) y)
 
 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
@@ -757,13 +761,8 @@ etaExpand n us expr ty
                                   (us1, us2) = splitUniqSupply us
                                   uniq       = uniqFromSupply us1 
                                   
-       ; Nothing -> 
-  
-       case splitNewType_maybe ty of {
-         Just ty' -> mkCoerce ty ty' (etaExpand n us (mkCoerce ty' ty expr) ty') ;
-  
-         Nothing -> pprTrace "Bad eta expand" (ppr expr $$ ppr ty) expr
-       }}}
+       ; Nothing -> pprTrace "Bad eta expand" (ppr expr $$ ppr ty) expr
+       }}
 \end{code}
 
 
@@ -793,13 +792,15 @@ And in any case it seems more robust to have exprArity be a bit more intelligent
 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
+             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) | exprIsCheap a = go f - 1
+               -- Important!  f (fac x) does not have arity 2, 
+               --             even if f does!
+             go (Var v)                   = idArity v
+             go _                         = 0
 \end{code}
 
 
@@ -818,7 +819,7 @@ cheapEqExpr :: Expr b -> Expr b -> Bool
 
 cheapEqExpr (Var v1)   (Var v2)   = v1==v2
 cheapEqExpr (Lit lit1) (Lit lit2) = lit1 == lit2
-cheapEqExpr (Type t1)  (Type t2)  = t1 == t2
+cheapEqExpr (Type t1)  (Type t2)  = t1 `eqType` t2
 
 cheapEqExpr (App f1 a1) (App f2 a2)
   = f1 `cheapEqExpr` f2 && a1 `cheapEqExpr` a2
@@ -838,6 +839,9 @@ exprIsBig other            = True
 \begin{code}
 eqExpr :: CoreExpr -> CoreExpr -> Bool
        -- Works ok at more general type, but only needed at CoreExpr
+       -- Used in rule matching, so when we find a type we use
+       -- eqTcType, which doesn't look through newtypes
+       -- [And it doesn't risk falling into a black hole either.]
 eqExpr e1 e2
   = eq emptyVarEnv e1 e2
   where
@@ -868,7 +872,7 @@ eqExpr e1 e2
                                       env' = extendVarEnv env v1 v2
 
     eq env (Note n1 e1) (Note n2 e2) = eq_note env n1 n2 && eq env e1 e2
-    eq env (Type t1)    (Type t2)    = t1 == t2
+    eq env (Type t1)    (Type t2)    = t1 `eqType` t2
     eq env e1          e2           = False
                                         
     eq_list env []      []       = True
@@ -879,7 +883,7 @@ eqExpr e1 e2
                                         eq (extendVarEnvList env (vs1 `zip` vs2)) r1 r2
 
     eq_note env (SCC cc1)      (SCC cc2)      = cc1 == cc2
-    eq_note env (Coerce t1 f1) (Coerce t2 f2) = t1==t2 && f1==f2
+    eq_note env (Coerce t1 f1) (Coerce t2 f2) = t1 `eqType` t2 && f1 `eqType` f2
     eq_note env InlineCall     InlineCall     = True
     eq_note env other1        other2         = False
 \end{code}