[project @ 2000-05-24 12:43:20 by simonpj]
[ghc-hetmet.git] / ghc / compiler / simplCore / Simplify.lhs
index ba847de..f6ccf6a 100644 (file)
@@ -1,4 +1,4 @@
-
+%
 % (c) The AQUA Project, Glasgow University, 1993-1998
 %
 \section[Simplify]{The main module of the simplifier}
@@ -25,7 +25,7 @@ import VarSet
 import Id              ( Id, idType, idInfo, idUnique, isDataConId, isDataConId_maybe,
                          idUnfolding, setIdUnfolding, isExportedId, isDeadBinder,
                          idSpecialisation, setIdSpecialisation,
-                         idDemandInfo, setIdDemandInfo,
+                         idDemandInfo, 
                          setIdInfo,
                          idOccInfo, setIdOccInfo,
                          zapLamIdInfo, zapFragileIdInfo,
@@ -36,7 +36,7 @@ import Id             ( Id, idType, idInfo, idUnique, isDataConId, isDataConId_maybe,
 import IdInfo          ( InlinePragInfo(..), OccInfo(..), StrictnessInfo(..), 
                          ArityInfo(..), atLeastArity, arityLowerBound, unknownArity,
                          specInfo, inlinePragInfo, setArityInfo, setInlinePragInfo, setUnfoldingInfo,
-                         CprInfo(..), cprInfo
+                         CprInfo(..), cprInfo, occInfo
                        )
 import Demand          ( Demand, isStrict, wwLazy )
 import DataCon         ( DataCon, dataConNumInstArgs, dataConRepStrictness, dataConRepArity,
@@ -48,10 +48,10 @@ import CoreFVs              ( exprFreeVars )
 import CoreUnfold      ( Unfolding, mkOtherCon, mkUnfolding, otherCons, maybeUnfoldingTemplate,
                          callSiteInline, hasSomeUnfolding, noUnfolding
                        )
-import CoreUtils       ( cheapEqExpr, exprIsDupable, exprIsCheap, exprIsTrivial,
+import CoreUtils       ( cheapEqExpr, exprIsDupable, exprIsCheap, exprIsTrivial, exprIsConApp_maybe,
                          exprType, coreAltsType, exprArity, exprIsValue, idAppIsCheap,
                          exprOkForSpeculation, etaReduceExpr,
-                         mkCoerce, mkSCC, mkInlineMe
+                         mkCoerce, mkSCC, mkInlineMe, mkAltExpr
                        )
 import Rules           ( lookupRule )
 import CostCentre      ( isSubsumedCCS, currentCCS, isEmptyCC )
@@ -66,7 +66,7 @@ import Subst          ( Subst, mkSubst, emptySubst, substTy, substExpr,
 import TyCon           ( isDataTyCon, tyConDataCons, tyConClass_maybe, tyConArity, isDataTyCon )
 import TysPrim         ( realWorldStatePrimTy )
 import PrelInfo                ( realWorldPrimId )
-import BasicTypes      ( TopLevelFlag(..), isTopLevel )
+import BasicTypes      ( TopLevelFlag(..), isTopLevel, isLoopBreaker )
 import Maybes          ( maybeToBool )
 import Util            ( zipWithEqual, lengthExceeds )
 import PprCore
@@ -226,15 +226,18 @@ simplExprF (App fun arg) cont
     simplExprF fun (ApplyTo NoDup arg se cont)
 
 simplExprF (Case scrut bndr alts) cont
-  = getSubst                   `thenSmpl` \ subst ->
+  = getSubstEnv                        `thenSmpl` \ subst_env ->
     getSwitchChecker           `thenSmpl` \ chkr ->
-    if switchIsOn chkr NoCaseOfCase then
-       -- If case-of-case is off, simply simplify the scrutinee and rebuild
-       simplExprC scrut (Stop (substTy subst (idType bndr)))   `thenSmpl` \ scrut' ->
-       rebuild_case False scrut' bndr alts (substEnv subst) cont
+    if not (switchIsOn chkr NoCaseOfCase) then
+       -- Simplify the scrutinee with a Select continuation
+       simplExprF scrut (Select NoDup bndr alts subst_env cont)
+
     else
-       -- But if it's on, we simplify the scrutinee with a Select continuation
-       simplExprF scrut (Select NoDup bndr alts (substEnv subst) cont)
+       -- If case-of-case is off, simply simplify the case expression
+       -- in a vanilla Stop context, and rebuild the result around it
+       simplExprC scrut (Select NoDup bndr alts subst_env 
+                                (Stop (contResultType cont)))  `thenSmpl` \ case_expr' ->
+       rebuild case_expr' cont
 
 
 simplExprF (Let (Rec pairs) body) cont
@@ -548,12 +551,19 @@ completeBinding old_bndr new_bndr top_lvl black_listed new_rhs thing_inside
        old_info      = idInfo old_bndr
        new_bndr_info = substIdInfo subst old_info (idInfo new_bndr)
                        `setArityInfo` ArityAtLeast (exprArity new_rhs)
-                       `setUnfoldingInfo` mkUnfolding top_lvl (cprInfo old_info) new_rhs
 
-       final_id = new_bndr `setIdInfo` new_bndr_info
+       -- Add the unfolding *only* for non-loop-breakers
+       -- Making loop breakers not have an unfolding at all 
+       -- means that we can avoid tests in exprIsConApp, for example.
+       -- This is important: if exprIsConApp says 'yes' for a recursive
+       -- thing we can get into an infinite loop
+       info_w_unf | isLoopBreaker (occInfo old_info) = new_bndr_info
+                  | otherwise = new_bndr_info `setUnfoldingInfo` mkUnfolding top_lvl new_rhs
+
+       final_id = new_bndr `setIdInfo` info_w_unf
      in
-       -- These seqs force the Ids, and hence the IdInfos, and hence any
-       -- inner substitutions
+       -- These seqs forces the Id, and hence its IdInfo,
+       -- and hence any inner substitutions
      final_id                          `seq`
      addLetBind final_id new_rhs       $
      modifyInScope new_bndr final_id thing_inside
@@ -694,9 +704,14 @@ wantToExpose :: Int -> CoreExpr -> Bool
 --     v = E
 --     z = \w -> g v w
 -- Which is what we want; chances are z will be inlined now.
+--
+-- This defn isn't quite like 
+--     exprIsCheap (it ignores non-cheap args)
+--     exprIsValue (may not say True for a lone variable)
+-- which is slightly weird
 wantToExpose n (Var v)         = idAppIsCheap v n
 wantToExpose n (Lit l)         = True
-wantToExpose n (Lam _ e)       = ASSERT( n==0 ) True   -- We won't have applied \'s
+wantToExpose n (Lam _ e)       = True
 wantToExpose n (Note _ e)      = wantToExpose n e
 wantToExpose n (App f (Type _))        = wantToExpose n f
 wantToExpose n (App f a)       = wantToExpose (n+1) f
@@ -737,10 +752,13 @@ simplVar var cont
 
 completeCall var occ cont
   = getBlackList       `thenSmpl` \ black_list_fn ->
-    getSwitchChecker   `thenSmpl` \ chkr ->
     getInScope         `thenSmpl` \ in_scope ->
+    getSwitchChecker   `thenSmpl` \ chkr ->
     let
-       black_listed                               = black_list_fn var
+       dont_use_rules     = switchIsOn chkr DontApplyRules
+       no_case_of_case    = switchIsOn chkr NoCaseOfCase
+       black_listed       = black_list_fn var
+
        (arg_infos, interesting_cont, inline_call) = analyseCont in_scope cont
        discard_inline_cont | inline_call = discardInline cont
                            | otherwise   = cont
@@ -772,10 +790,10 @@ completeCall var occ cont
        -- won't occur for things that have specialisations till a later phase, so
        -- it's ok to try for inlining first.
 
-    prepareArgs (switchIsOn chkr NoCaseOfCase) var cont        $ \ args' cont' ->
+    prepareArgs no_case_of_case var cont       $ \ args' cont' ->
     let
-       maybe_rule | switchIsOn chkr DontApplyRules = Nothing
-                  | otherwise                      = lookupRule in_scope var args' 
+       maybe_rule | dont_use_rules = Nothing
+                  | otherwise      = lookupRule in_scope var args' 
     in
     case maybe_rule of {
        Just (rule_name, rule_rhs) -> 
@@ -880,7 +898,7 @@ prepareArgs no_case_of_case fun orig_cont thing_inside
        = simplValArg arg_ty dem val_arg se (contResultType cont)       $ \ new_arg ->
                    -- A data constructor whose argument is now non-trivial;
                    -- so let/case bind it.
-         newId arg_ty                                          $ \ arg_id ->
+         newId SLIT("a") arg_ty                                $ \ arg_id ->
          addNonRecBind arg_id new_arg                          $
          go (Var arg_id : acc) ds' res_ty cont
 
@@ -969,8 +987,8 @@ postInlineUnconditionally :: Bool   -- Black listed
 postInlineUnconditionally black_listed occ_info bndr rhs
   | isExportedId bndr  || 
     black_listed       || 
-    loop_breaker       = False                 -- Don't inline these
-  | otherwise          = exprIsTrivial rhs     -- Duplicating is free
+    isLoopBreaker occ_info = False             -- Don't inline these
+  | otherwise             = exprIsTrivial rhs  -- Duplicating is free
        -- Don't inline even WHNFs inside lambdas; doing so may
        -- simply increase allocation when the function is called
        -- This isn't the last chance; see NOTE above.
@@ -982,10 +1000,6 @@ postInlineUnconditionally black_listed occ_info bndr rhs
        -- NB: Even NOINLINEis ignored here: if the rhs is trivial
        -- it's best to inline it anyway.  We often get a=E; b=a
        -- from desugaring, with both a and b marked NOINLINE.
-  where
-    loop_breaker = case occ_info of
-                       IAmALoopBreaker -> True
-                       other           -> False
 \end{code}
 
 
@@ -1026,7 +1040,7 @@ rebuild expr (InlinePlease cont)
   = rebuild (Note InlineCall expr) cont
 
 rebuild scrut (Select _ bndr alts se cont)
-  = rebuild_case True scrut bndr alts se cont
+  = rebuild_case scrut bndr alts se cont
 \end{code}
 
 Case elimination [see the code above]
@@ -1114,7 +1128,7 @@ Blob of helper functions for the "case-of-something-else" situation.
 ---------------------------------------------------------
 --     Eliminate the case if possible
 
-rebuild_case add_eval_info scrut bndr alts se cont
+rebuild_case scrut bndr alts se cont
   | maybeToBool maybe_con_app
   = knownCon scrut (DataAlt con) args bndr alts se cont
 
@@ -1127,29 +1141,12 @@ rebuild_case add_eval_info scrut bndr alts se cont
     simplExprF (head (rhssOfAlts alts)) cont)
 
   | otherwise
-  = complete_case add_eval_info scrut bndr alts se cont
+  = complete_case scrut bndr alts se cont
 
   where
-    maybe_con_app    = analyse (collectArgs scrut)
+    maybe_con_app    = exprIsConApp_maybe scrut
     Just (con, args) = maybe_con_app
 
-    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
-
-    analyse (Var fun, [])
-       = case maybeUnfoldingTemplate (idUnfolding fun) of
-               Nothing  -> Nothing
-               Just unf -> analyse (collectArgs unf)
-
-    analyse other = Nothing
-
        -- See if we can get rid of the case altogether
        -- See the extensive notes on case-elimination above
 canEliminateCase scrut bndr alts
@@ -1192,7 +1189,7 @@ canEliminateCase scrut bndr alts
 ---------------------------------------------------------
 --     Case of something else
 
-complete_case add_eval_info scrut case_bndr alts se cont
+complete_case scrut case_bndr alts se cont
   =    -- Prepare case alternatives
     prepareCaseAlts case_bndr (splitTyConApp_maybe (idType case_bndr))
                    impossible_cons alts                `thenSmpl` \ better_alts ->
@@ -1206,7 +1203,10 @@ complete_case add_eval_info scrut case_bndr alts se cont
        
 
        -- Deal with variable scrutinee
-    (  simplCaseBinder add_eval_info scrut case_bndr   $ \ case_bndr' zap_occ_info ->
+    (  
+        getSwitchChecker                               `thenSmpl` \ chkr ->
+       simplCaseBinder (switchIsOn chkr NoCaseOfCase)
+                       scrut case_bndr                 $ \ case_bndr' zap_occ_info ->
 
        -- Deal with the case alternatives
        simplAlts zap_occ_info impossible_cons
@@ -1283,7 +1283,7 @@ If we eliminate the inner case, we trap it inside the I# v -> arm,
 which might prevent some full laziness happening.  I've seen this
 in action in spectral/cichelli/Prog.hs:
         [(m,n) | m <- [1..max], n <- [1..max]]
-Hence the add_eval_info argument
+Hence the no_case_of_case argument
 
 
 If we do this, then we have to nuke any occurrence info (eg IAmDead)
@@ -1302,8 +1302,8 @@ Urk! b is alive!  Reason: the scrutinee was a variable, and case elimination
 happened.  Hence the zap_occ_info function returned by simplCaseBinder
 
 \begin{code}
-simplCaseBinder add_eval_info (Var v) case_bndr thing_inside
-  | add_eval_info
+simplCaseBinder no_case_of_case (Var v) case_bndr thing_inside
+  | not no_case_of_case
   = simplBinder (zap case_bndr)                                        $ \ case_bndr' ->
     modifyInScope v case_bndr'                                 $
        -- We could extend the substitution instead, but it would be
@@ -1345,10 +1345,10 @@ prepareCaseAlts bndr (Just (tycon, inst_tys)) scrut_cons alts
                   let
                        ex_tyvars' = zipWithEqual "simpl_alt" mk tv_uniqs ex_tyvars
                        mk uniq tv = mkSysTyVar uniq (tyVarKind tv)
+                       arg_tys    = dataConArgTys data_con
+                                                  (inst_tys ++ mkTyVarTys ex_tyvars')
                   in
-                  newIds (dataConArgTys
-                               data_con
-                               (inst_tys ++ mkTyVarTys ex_tyvars'))            $ \ bndrs ->
+                  newIds SLIT("a") arg_tys             $ \ bndrs ->
                   returnSmpl ((DataAlt data_con, ex_tyvars' ++ bndrs, rhs) : alts_no_deflt)
 
        other -> returnSmpl filtered_alts
@@ -1398,7 +1398,7 @@ simplAlts zap_occ_info scrut_cons case_bndr' alts cont'
 
                -- Bind the case-binder to (con args)
          let
-               unfolding = mkUnfolding False NoCPRInfo (mkAltExpr con vs' inst_tys')
+               unfolding = mkUnfolding False (mkAltExpr con vs' inst_tys')
          in
          modifyInScope case_bndr' (case_bndr' `setIdUnfolding` unfolding)      $
          simplExprC rhs cont'          `thenSmpl` \ rhs' ->
@@ -1452,13 +1452,15 @@ mkDupableCont ty (InlinePlease cont) thing_inside
 
 mkDupableCont join_arg_ty (ArgOf _ cont_ty cont_fn) thing_inside
   =    -- Build the RHS of the join point
-    newId join_arg_ty                                  ( \ arg_id ->
+    newId SLIT("a") join_arg_ty                                ( \ arg_id ->
        cont_fn (Var arg_id)                            `thenSmpl` \ (binds, (_, rhs)) ->
        returnSmpl (Lam (setOneShotLambda arg_id) (mkLets binds rhs))
     )                                                  `thenSmpl` \ join_rhs ->
    
        -- Build the join Id and continuation
-    newId (exprType join_rhs)          $ \ join_id ->
+       -- We give it a "$j" name just so that for later amusement
+       -- we can identify any join points that don't end up as let-no-escapes
+    newId SLIT("$j") (exprType join_rhs)               $ \ join_id ->
     let
        new_cont = ArgOf OkToDup cont_ty
                         (\arg' -> rebuild_done (App (Var join_id) arg'))
@@ -1476,9 +1478,9 @@ mkDupableCont ty (ApplyTo _ arg se cont) thing_inside
     if exprIsDupable arg' then
        thing_inside (ApplyTo OkToDup arg' emptySubstEnv cont')
     else
-    newId (exprType arg')                                              $ \ bndr ->
+    newId SLIT("a") (exprType arg')                    $ \ bndr ->
 
-    tick (CaseOfCase bndr)                                             `thenSmpl_`
+    tick (CaseOfCase bndr)                             `thenSmpl_`
        -- Want to tick here so that we go round again,
        -- and maybe copy or inline the code;
        -- not strictly CaseOf Case
@@ -1574,14 +1576,15 @@ mkDupableAlt case_bndr case_bndr' cont alt@(con, bndrs, rhs)
        --                  then 78
        --                  else 5
 
-       then newId realWorldStatePrimTy  $ \ rw_id ->
+       then newId SLIT("w") realWorldStatePrimTy  $ \ rw_id ->
             returnSmpl ([rw_id], [Var realWorldPrimId])
        else 
             returnSmpl (used_bndrs', map varToCoreExpr used_bndrs)
     )
        `thenSmpl` \ (final_bndrs', final_args) ->
 
-    newId (foldr (mkFunTy . idType) rhs_ty' final_bndrs')      $ \ join_bndr ->
+       -- See comment about "$j" name above
+    newId SLIT("$j") (foldr (mkFunTy . idType) rhs_ty' final_bndrs')   $ \ join_bndr ->
 
        -- Notice that we make the lambdas into one-shot-lambdas.  The
        -- join point is sure to be applied at most once, and doing so