[project @ 1999-04-26 16:06:27 by simonm]
[ghc-hetmet.git] / ghc / compiler / stgSyn / CoreToStg.lhs
index a707068..c5de5ed 100644 (file)
@@ -1,5 +1,5 @@
 %
-% (c) The GRASP/AQUA Project, Glasgow University, 1992-1996
+% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
 %
 %************************************************************************
 %*                                                                     *
@@ -9,46 +9,32 @@
 
 Convert a @CoreSyntax@ program to a @StgSyntax@ program.
 
-
 \begin{code}
-#include "HsVersions.h"
-
 module CoreToStg ( topCoreBindsToStg ) where
 
-IMP_Ubiq(){-uitous-}
+#include "HsVersions.h"
 
 import CoreSyn         -- input
 import StgSyn          -- output
 
-import Bag             ( emptyBag, unitBag, unionBags, unionManyBags, bagToList )
 import CoreUtils       ( coreExprType )
-import CostCentre      ( noCostCentre )
-import Id              ( mkSysLocal, idType, isBottomingId,
-                         nullIdEnv, addOneToIdEnv, lookupIdEnv,
-                         IdEnv(..), GenId{-instance NamedThing-}
-                       )
-import Literal         ( mkMachInt, Literal(..) )
-import Name            ( isExported )
-import PrelVals                ( unpackCStringId, unpackCString2Id,
-                         integerZeroId, integerPlusOneId,
-                         integerPlusTwoId, integerMinusOneId
+import SimplUtils      ( findDefault )
+import CostCentre      ( noCCS )
+import Id              ( Id, mkSysLocal, idType,
+                         externallyVisibleId, setIdUnique, idName
                        )
+import DataCon         ( DataCon, dataConName, dataConId )
+import Name            ( Name, nameModule, isLocallyDefinedName )
+import Module          ( isDynamicModule )
+import Const           ( Con(..), Literal, isLitLitLit )
+import VarEnv
+import Const           ( Con(..), isWHNFCon, Literal(..) )
 import PrimOp          ( PrimOp(..) )
-import SpecUtils       ( mkSpecialisedCon )
-import SrcLoc          ( mkUnknownSrcLoc )
-import TyCon           ( TyCon{-instance Uniquable-} )
-import Type            ( maybeAppDataTyCon, getAppDataTyConExpandingDicts )
-import TysWiredIn      ( stringTy )
-import Unique          ( integerTyConKey, ratioTyConKey, Unique{-instance Eq-} )
+import Type            ( isUnLiftedType, isUnboxedTupleType, Type )
+import TysPrim         ( intPrimTy )
+import Unique          ( Unique, Uniquable(..) )
 import UniqSupply      -- all of it, really
-import Util            ( panic, assertPanic, pprTrace{-ToDo:rm-} )
-import Pretty--ToDo:rm
-import PprStyle--ToDo:rm
-import PprType  --ToDo:rm
-import Outputable--ToDo:rm
-import PprEnv--ToDo:rm
-
-isLeakFreeType x y = False -- safe option; ToDo
+import Outputable
 \end{code}
 
 
@@ -62,17 +48,16 @@ The business of this pass is to convert Core to Stg.  On the way:
        x = y t1 t2
   where t1, t2 are types
 
-* We make the representation of NoRep literals explicit, and
-  float their bindings to the top level
+* We don't pin on correct arities any more, because they can be mucked up
+  by the lambda lifter.  In particular, the lambda lifter can take a local
+  letrec-bound variable and make it a lambda argument, which shouldn't have
+  an arity.  So SetStgVarInfo sets arities now.
 
 * We do *not* pin on the correct free/live var info; that's done later.
   Instead we use bOGUS_LVS and _FVS as a placeholder.
 
-* We convert   case x of {...; x' -> ...x'...}
-       to
-               case x of {...; _  -> ...x... }
-
-  See notes in SimplCase.lhs, near simplDefault for the reasoning here.
+[Quite a bit of stuff that used to be here has moved 
+ to tidyCorePgm (SimplCore.lhs) SLPJ Nov 96]
 
 
 %************************************************************************
@@ -81,13 +66,17 @@ The business of this pass is to convert Core to Stg.  On the way:
 %*                                                                     *
 %************************************************************************
 
-Because we're going to come across ``boring'' bindings like
-\tr{let x = /\ tyvars -> y in ...}, we want to keep a small
-environment, so we can just replace all occurrences of \tr{x}
-with \tr{y}.
+March 98: We keep a small environment to give all locally bound
+Names new unique ids, since the code generator assumes that binders
+are unique across a module. (Simplifier doesn't maintain this
+invariant any longer.)
 
 \begin{code}
-type StgEnv = IdEnv StgArg
+type StgEnv = IdEnv Id
+
+data StgFloatBind
+   = LetBind Id StgExpr
+   | CaseBind Id StgExpr
 \end{code}
 
 No free/live variable information is pinned on in this pass; it's added
@@ -104,79 +93,19 @@ bOGUS_FVs = panic "bOGUS_FVs" -- [] (ditto)
 
 \begin{code}
 topCoreBindsToStg :: UniqSupply        -- name supply
-                 -> [CoreBinding]      -- input
+                 -> [CoreBind] -- input
                  -> [StgBinding]       -- output
 
 topCoreBindsToStg us core_binds
-  = case (initUs us (binds_to_stg nullIdEnv core_binds)) of
-      (_, stuff) -> stuff
+  = initUs us (coreBindsToStg emptyVarEnv core_binds)
   where
-    binds_to_stg :: StgEnv -> [CoreBinding] -> UniqSM [StgBinding]
-
-    binds_to_stg env [] = returnUs []
-    binds_to_stg env (b:bs)
-      = do_top_bind  env     b  `thenUs` \ (new_b, new_env, float_binds) ->
-       binds_to_stg new_env bs `thenUs` \ new_bs ->
-       returnUs (bagToList float_binds ++      -- Literals
-                 new_b ++
-                 new_bs)
-
-    do_top_bind env bind@(Rec pairs)
-      = coreBindToStg env bind
-
-    do_top_bind env bind@(NonRec var rhs)
-      = coreBindToStg env bind         `thenUs` \ (stg_binds, new_env, float_binds) ->
-{- TESTING:
-       let
-           ppr_blah xs = ppInterleave ppComma (map pp_x xs)
-           pp_x (u,x) = ppBesides [pprUnique u, ppStr ": ", ppr PprDebug x]
-       in
-       pprTrace "do_top_bind:" (ppAbove (ppr PprDebug stg_binds) (ppr_blah (ufmToList new_env))) $
--}
-       case stg_binds of
-          [StgNonRec var (StgRhsClosure cc bi fvs u [] rhs_body)] ->
-               -- Mega-special case; there's still a binding there
-               -- no fvs (of course), *no args*, "let" rhs
-               let
-                 (extra_float_binds, rhs_body') = seek_liftable [] rhs_body
-               in
-               returnUs (extra_float_binds ++
-                         [StgNonRec var (StgRhsClosure cc bi fvs u [] rhs_body')],
-                         new_env,
-                         float_binds)
-
-          other -> returnUs (stg_binds, new_env, float_binds)
-
-    --------------------
-    -- HACK: look for very simple, obviously-liftable bindings
-    -- that can come up to the top level; those that couldn't
-    -- 'cause they were big-lambda constrained in the Core world.
-
-    seek_liftable :: [StgBinding]      -- accumulator...
-                 -> StgExpr    -- look for top-lev liftables
-                 -> ([StgBinding], StgExpr)    -- result
-
-    seek_liftable acc expr@(StgLet inner_bind body)
-      | is_liftable inner_bind
-      =        seek_liftable (inner_bind : acc) body
-
-    seek_liftable acc other_expr = (reverse acc, other_expr) -- Finished
-
-    --------------------
-    is_liftable (StgNonRec binder (StgRhsClosure _ _ _ _ args body))
-      = not (null args) -- it's manifestly a function...
-       || isLeakFreeType [] (idType binder)
-       || is_whnf body
-       -- ToDo: use a decent manifestlyWHNF function for STG?
-      where
-       is_whnf (StgCon _ _ _)      = True
-       is_whnf (StgApp (StgVarArg v) _ _) = isBottomingId v
-       is_whnf other                       = False
-
-    is_liftable (StgRec [(_, StgRhsClosure _ _ _ _ args body)])
-      = not (null args) -- it's manifestly a (recursive) function...
-
-    is_liftable anything_else = False
+    coreBindsToStg :: StgEnv -> [CoreBind] -> UniqSM [StgBinding]
+
+    coreBindsToStg env [] = returnUs []
+    coreBindsToStg env (b:bs)
+      = coreBindToStg  env b           `thenUs` \ (new_b, new_env) ->
+       coreBindsToStg new_env bs       `thenUs` \ new_bs ->
+       returnUs (new_b ++ new_bs)
 \end{code}
 
 %************************************************************************
@@ -187,45 +116,21 @@ topCoreBindsToStg us core_binds
 
 \begin{code}
 coreBindToStg :: StgEnv
-             -> CoreBinding
+             -> CoreBind
              -> UniqSM ([StgBinding],  -- Empty or singleton
-                        StgEnv,                -- New envt
-                        Bag StgBinding)        -- Floats
+                        StgEnv)        -- Floats
 
 coreBindToStg env (NonRec binder rhs)
-  = coreRhsToStg env rhs       `thenUs` \ (stg_rhs, rhs_binds) ->
-
-    let
-       -- Binds to return if RHS is trivial
-       triv_binds = if isExported binder then
-                       [StgNonRec binder stg_rhs]      -- Retain it
-                    else
-                       []                              -- Discard it
-    in
-    case stg_rhs of
-      StgRhsClosure cc bi fvs upd [] (StgApp atom [] lvs) ->
-               -- Trivial RHS, so augment envt, and ditch the binding
-               returnUs (triv_binds, new_env, rhs_binds)
-          where
-               new_env = addOneToIdEnv env binder atom
-
-      StgRhsCon cc con_id [] ->
-               -- Trivial RHS, so augment envt, and ditch the binding
-               returnUs (triv_binds, new_env, rhs_binds)
-          where
-               new_env = addOneToIdEnv env binder (StgVarArg con_id)
-
-      other ->         -- Non-trivial RHS, so don't augment envt
-               returnUs ([StgNonRec binder stg_rhs], env, rhs_binds)
+  = coreRhsToStg env rhs       `thenUs` \ stg_rhs ->
+    newLocalId env binder      `thenUs` \ (new_env, new_binder) ->
+    returnUs ([StgNonRec new_binder stg_rhs], new_env)
 
 coreBindToStg env (Rec pairs)
-  = -- NB: *** WE DO NOT CHECK FOR TRIV_BINDS in REC BIND ****
-    -- (possibly ToDo)
-    let
-       (binders, rhss) = unzip pairs
-    in
-    mapAndUnzipUs (coreRhsToStg env) rhss `thenUs` \ (stg_rhss, rhs_binds) ->
-    returnUs ([StgRec (binders `zip` stg_rhss)], env, unionManyBags rhs_binds)
+  = newLocalIds env binders            `thenUs` \ (env', binders') ->
+    mapUs (coreRhsToStg env') rhss      `thenUs` \ stg_rhss ->
+    returnUs ([StgRec (binders' `zip` stg_rhss)], env')
+  where
+    (binders, rhss) = unzip pairs
 \end{code}
 
 
@@ -236,174 +141,139 @@ coreBindToStg env (Rec pairs)
 %************************************************************************
 
 \begin{code}
-coreRhsToStg :: StgEnv -> CoreExpr -> UniqSM (StgRhs, Bag StgBinding)
+coreRhsToStg :: StgEnv -> CoreExpr -> UniqSM StgRhs
 
 coreRhsToStg env core_rhs
-  = coreExprToStg env core_rhs         `thenUs` \ (stg_expr, stg_binds) ->
-
-    let stg_rhs = case stg_expr of
-                   StgLet (StgNonRec var1 rhs) (StgApp (StgVarArg var2) [] _)
-                       | var1 == var2 -> rhs
-                       -- This curious stuff is to unravel what a lambda turns into
-                       -- We have to do it this way, rather than spot a lambda in the
-                       -- incoming rhs
+  = coreExprToStg env core_rhs         `thenUs` \ stg_expr ->
+    returnUs (exprToRhs stg_expr)
+
+exprToRhs (StgLet (StgNonRec var1 rhs) (StgApp var2 []))
+  | var1 == var2 
+  = rhs
+       -- This curious stuff is to unravel what a lambda turns into
+       -- We have to do it this way, rather than spot a lambda in the
+       -- incoming rhs.  Why?  Because trivial bindings might conceal
+       -- what the rhs is actually like.
+
+{-
+  We reject the following candidates for 'static constructor'dom:
+  
+    - any dcon that takes a lit-lit as an arg.
+    - [Win32 DLLs only]: any dcon that is (or takes as arg)
+      that's living in a DLL.
+
+  These constraints are necessary to ensure that the code
+  generated in the end for the static constructors, which
+  live in the data segment, remain valid - i.e., it has to
+  be constant. For obvious reasons, that's hard to guarantee
+  with lit-lits. The second case of a constructor referring
+  to static closures hiding out in some DLL is an artifact
+  of the way Win32 DLLs handle global DLL variables. A (data)
+  symbol exported from a DLL  has to be accessed through a
+  level of indirection at the site of use, so whereas
+
+     extern StgClosure y_closure;
+     extern StgClosure z_closure;
+     x = { ..., &y_closure, &z_closure };
+
+  is legal when the symbols are in scope at link-time, it is
+  not when y_closure is in a DLL. So, any potential static
+  closures that refers to stuff that's residing in a DLL
+  will be put in an (updateable) thunk instead.
+
+  An alternative strategy is to support the generation of
+  constructors (ala C++ static class constructors) which will
+  then be run at load time to fix up static closures.
+-}
+exprToRhs (StgCon (DataCon con) args _)
+  | not is_dynamic  &&
+    all  (not.is_lit_lit) args  = StgRhsCon noCCS con args
+ where
+  is_dynamic = isDynCon con || any (isDynArg) args
+
+  is_lit_lit (StgVarArg _) = False
+  is_lit_lit (StgConArg x) =
+     case x of
+       Literal l -> isLitLitLit l
+       _         -> False
+
+exprToRhs expr 
+       = StgRhsClosure noCCS           -- No cost centre (ToDo?)
+                       stgArgOcc       -- safe
+                       noSRT           -- figure out later
+                       bOGUS_FVs
+
+                       Updatable       -- Be pessimistic
+                       []
+                       expr
+
+isDynCon :: DataCon -> Bool
+isDynCon con = isDynName (dataConName con)
+
+isDynArg :: StgArg -> Bool
+isDynArg (StgVarArg v)   = isDynName (idName v)
+isDynArg (StgConArg con) =
+  case con of
+    DataCon dc -> isDynCon dc
+    Literal l  -> isLitLitLit l
+    _          -> False
+
+isDynName :: Name -> Bool
+isDynName nm = 
+      not (isLocallyDefinedName nm) && 
+      isDynamicModule (nameModule nm)
 
-                   StgCon con args _ -> StgRhsCon noCostCentre con args
 
-                   other -> StgRhsClosure noCostCentre -- No cost centre (ToDo?)
-                                          stgArgOcc    -- safe
-                                          bOGUS_FVs
-                                          Updatable    -- Be pessimistic
-                                          []
-                                          stg_expr
-    in
-    returnUs (stg_rhs, stg_binds)
 \end{code}
 
 
 %************************************************************************
 %*                                                                     *
-\subsection[coreToStg-lits]{Converting literals}
+\subsection[coreToStg-atoms{Converting atoms}
 %*                                                                     *
 %************************************************************************
 
-Literals: the NoRep kind need to be de-no-rep'd.
-We always replace them with a simple variable, and float a suitable
-binding out to the top level.
-
-If an Integer is small enough (Haskell implementations must support
-Ints in the range $[-2^29+1, 2^29-1]$), wrap it up in @int2Integer@;
-otherwise, wrap with @litString2Integer@.
-
 \begin{code}
-tARGET_MIN_INT, tARGET_MAX_INT :: Integer
-tARGET_MIN_INT = -536870912
-tARGET_MAX_INT =  536870912
+coreArgsToStg :: StgEnv -> [CoreArg] -> UniqSM ([StgFloatBind], [StgArg])
 
-litToStgArg :: Literal -> UniqSM (StgArg, Bag StgBinding)
+coreArgsToStg env []
+  = returnUs ([], [])
 
-litToStgArg (NoRepStr s)
-  = newStgVar stringTy                 `thenUs` \ var ->
-    let
-       rhs = StgRhsClosure noCostCentre -- No cost centre (ToDo?)
-                           stgArgOcc    -- safe
-                           bOGUS_FVs
-                           Updatable    -- WAS: ReEntrant (see note below)
-                           []           -- No arguments
-                           val
-
--- We used not to update strings, so that they wouldn't clog up the heap,
--- but instead be unpacked each time.  But on some programs that costs a lot
--- [eg hpg], so now we update them.
-
-       val = if (any is_NUL (_UNPK_ s)) then -- must cater for NULs in literal string
-               StgApp (StgVarArg unpackCString2Id)
-                    [StgLitArg (MachStr s),
-                     StgLitArg (mkMachInt (toInteger (_LENGTH_ s)))]
-                    bOGUS_LVs
-             else
-               StgApp (StgVarArg unpackCStringId)
-                    [StgLitArg (MachStr s)]
-                    bOGUS_LVs
-    in
-    returnUs (StgVarArg var, unitBag (StgNonRec var rhs))
-  where
-    is_NUL c = c == '\0'
+coreArgsToStg env (Type ty : as)       -- Discard type arguments
+  = coreArgsToStg env as
 
-litToStgArg (NoRepInteger i integer_ty)
-  -- extremely convenient to look out for a few very common
-  -- Integer literals!
-  | i == 0    = returnUs (StgVarArg integerZeroId,     emptyBag)
-  | i == 1    = returnUs (StgVarArg integerPlusOneId,  emptyBag)
-  | i == 2    = returnUs (StgVarArg integerPlusTwoId,  emptyBag)
-  | i == (-1) = returnUs (StgVarArg integerMinusOneId, emptyBag)
-
-  | otherwise
-  = newStgVar integer_ty       `thenUs` \ var ->
-    let
-       rhs = StgRhsClosure noCostCentre -- No cost centre (ToDo?)
-                           stgArgOcc    -- safe
-                           bOGUS_FVs
-                           Updatable    -- Update an integer
-                           []           -- No arguments
-                           val
-
-       val
-         | i > tARGET_MIN_INT && i < tARGET_MAX_INT
-         =     -- Start from an Int
-           StgPrim Int2IntegerOp [StgLitArg (mkMachInt i)] bOGUS_LVs
-
-         | otherwise
-         =     -- Start from a string
-           StgPrim Addr2IntegerOp [StgLitArg (MachStr (_PK_ (show i)))] bOGUS_LVs
-    in
-    returnUs (StgVarArg var, unitBag (StgNonRec var rhs))
-
-litToStgArg (NoRepRational r rational_ty)
-  = --ASSERT(is_rational_ty)
-    (if is_rational_ty then \x->x else pprTrace "litToStgArg:not rational?" (pprType PprDebug rational_ty)) $
-    litToStgArg (NoRepInteger (numerator   r) integer_ty) `thenUs` \ (num_atom,   binds1) ->
-    litToStgArg (NoRepInteger (denominator r) integer_ty) `thenUs` \ (denom_atom, binds2) ->
-    newStgVar rational_ty                      `thenUs` \ var ->
-    let
-        rhs = StgRhsCon noCostCentre   -- No cost centre (ToDo?)
-                        ratio_data_con -- Constructor
-                        [num_atom, denom_atom]
-    in
-    returnUs (StgVarArg var, binds1 `unionBags`
-                           binds2 `unionBags`
-                           unitBag (StgNonRec var rhs))
-  where
-    (is_rational_ty, ratio_data_con, integer_ty)
-      = case (maybeAppDataTyCon rational_ty) of
-         Just (tycon, [i_ty], [con])
-           -> ASSERT(is_integer_ty i_ty)
-              (uniqueOf tycon == ratioTyConKey, con, i_ty)
-
-         _ -> (False, panic "ratio_data_con", panic "integer_ty")
-
-    is_integer_ty ty
-      = case (maybeAppDataTyCon ty) of
-         Just (tycon, [], _) -> uniqueOf tycon == integerTyConKey
-         _ -> False
-
-litToStgArg other_lit = returnUs (StgLitArg other_lit, emptyBag)
-\end{code}
-
-
-%************************************************************************
-%*                                                                     *
-\subsection[coreToStg-atoms{Converting atoms}
-%*                                                                     *
-%************************************************************************
-
-\begin{code}
-coreArgsToStg :: StgEnv -> [CoreArg] -> UniqSM ([Type], [StgArg], Bag StgBinding)
-
-coreArgsToStg env [] = returnUs ([], [], emptyBag)
 coreArgsToStg env (a:as)
-  = coreArgsToStg env as    `thenUs` \ (tys, args, binds) ->
-    do_arg a tys args binds
-  where
-    do_arg a trest vrest binds
-      = case a of
-         TyArg    t -> returnUs (t:trest, vrest, binds)
-         UsageArg u -> returnUs (trest, vrest, binds)
-         VarArg   v -> returnUs (trest, stgLookup env v : vrest, binds)
-         LitArg   i -> litToStgArg i `thenUs` \ (v, bs) ->
-                       returnUs (trest, v:vrest, bs `unionBags` binds)
-\end{code}
+  = coreArgToStg env a         `thenUs` \ (bs1, a') ->
+    coreArgsToStg env as       `thenUs` \ (bs2, as') ->
+    returnUs (bs1 ++ bs2, a' : as')
+
+-- This is where we arrange that a non-trivial argument is let-bound
+
+coreArgToStg :: StgEnv -> CoreArg -> UniqSM ([StgFloatBind], StgArg)
+
+coreArgToStg env arg
+  = coreExprToStgFloat env arg `thenUs` \ (binds, arg') ->
+    case (binds, arg') of
+       ([], StgCon con [] _) | isWHNFCon con -> returnUs ([], StgConArg con)
+       ([], StgApp v [])                     -> returnUs ([], StgVarArg v)
+
+       -- A non-trivial argument: we must let (or case-bind)
+       -- We don't do the case part here... we leave that to mkStgBinds
+
+       -- Further complication: if we're converting this binding into
+       -- a case,  then try to avoid generating any case-of-case
+       -- expressions by pulling out the floats.
+       (_, other) ->
+                newStgVar ty   `thenUs` \ v ->
+                if isUnLiftedType ty
+                  then returnUs (binds ++ [CaseBind v arg'], StgVarArg v)
+                  else returnUs ([LetBind v (mkStgBinds binds arg')], StgVarArg v)
+         where 
+               ty = coreExprType arg
 
-There's not anything interesting we can ASSERT about \tr{var} if it
-isn't in the StgEnv. (WDP 94/06)
-\begin{code}
-stgLookup :: StgEnv -> Id -> StgArg
-
-stgLookup env var = case (lookupIdEnv env var) of
-                     Nothing   -> StgVarArg var
-                     Just atom -> atom
 \end{code}
 
+
 %************************************************************************
 %*                                                                     *
 \subsection[coreToStg-exprs]{Converting core expressions}
@@ -411,30 +281,11 @@ stgLookup env var = case (lookupIdEnv env var) of
 %************************************************************************
 
 \begin{code}
-coreExprToStg :: StgEnv
-             -> CoreExpr
-             -> UniqSM (StgExpr,               -- Result
-                        Bag StgBinding)        -- Float these to top level
-\end{code}
-
-\begin{code}
-coreExprToStg env (Lit lit)
-  = litToStgArg lit    `thenUs` \ (atom, binds) ->
-    returnUs (StgApp atom [] bOGUS_LVs, binds)
+coreExprToStg :: StgEnv -> CoreExpr -> UniqSM StgExpr
 
 coreExprToStg env (Var var)
-  = returnUs (StgApp (stgLookup env var) [] bOGUS_LVs, emptyBag)
+  = returnUs (StgApp (stgLookup env var) [])
 
-coreExprToStg env (Con con args)
-  = coreArgsToStg env args  `thenUs` \ (types, stg_atoms, stg_binds) ->
-    let
-       spec_con = mkSpecialisedCon con types
-    in
-    returnUs (StgCon spec_con stg_atoms bOGUS_LVs, stg_binds)
-
-coreExprToStg env (Prim op args)
-  = coreArgsToStg env args  `thenUs` \ (_, stg_atoms, stg_binds) ->
-    returnUs (StgPrim op stg_atoms bOGUS_LVs, stg_binds)
 \end{code}
 
 %************************************************************************
@@ -446,23 +297,83 @@ coreExprToStg env (Prim op args)
 \begin{code}
 coreExprToStg env expr@(Lam _ _)
   = let
-       (_,_, binders, body) = collectBinders expr
+       (binders, body) = collectBinders expr
+       id_binders      = filter isId binders
     in
-    coreExprToStg env body             `thenUs` \ stuff@(stg_body, binds) ->
+    newLocalIds env id_binders         `thenUs` \ (env', binders') ->
+    coreExprToStg env' body             `thenUs` \ stg_body ->
 
-    if null binders then -- it was all type/usage binders; tossed
-       returnUs stuff
+    if null id_binders then -- it was all type/usage binders; tossed
+       returnUs stg_body
     else
+    case stg_body of
+
+      -- if the body reduced to a lambda too...
+      (StgLet (StgNonRec var (StgRhsClosure cc bi srt fvs uf args body))
+             (StgApp var' []))
+       | var == var' ->
+       returnUs (StgLet (StgNonRec var 
+                           (StgRhsClosure noCCS
+                               stgArgOcc
+                               noSRT
+                               bOGUS_FVs
+                               ReEntrant
+                               (binders' ++ args)
+                               body))
+               (StgApp var []))
+                                   
+      other ->
+
+       -- We must let-bind the lambda
        newStgVar (coreExprType expr)   `thenUs` \ var ->
        returnUs
-         (StgLet (StgNonRec var (StgRhsClosure noCostCentre
+         (StgLet (StgNonRec var (StgRhsClosure noCCS
                                  stgArgOcc
+                                 noSRT
                                  bOGUS_FVs
                                  ReEntrant     -- binders is non-empty
-                                 binders
+                                 binders'
                                  stg_body))
-          (StgApp (StgVarArg var) [] bOGUS_LVs),
-          binds)
+          (StgApp var []))
+\end{code}
+
+%************************************************************************
+%*                                                                     *
+\subsubsection[coreToStg-let(rec)]{Let and letrec expressions}
+%*                                                                     *
+%************************************************************************
+
+\begin{code}
+coreExprToStg env (Let bind body)
+  = coreBindToStg env     bind   `thenUs` \ (stg_binds, new_env) ->
+    coreExprToStg new_env body   `thenUs` \ stg_body ->
+    returnUs (foldr StgLet stg_body stg_binds)
+\end{code}
+
+
+%************************************************************************
+%*                                                                     *
+\subsubsection[coreToStg-scc]{SCC expressions}
+%*                                                                     *
+%************************************************************************
+
+Covert core @scc@ expression directly to STG @scc@ expression.
+\begin{code}
+coreExprToStg env (Note (SCC cc) expr)
+  = coreExprToStg env expr   `thenUs` \ stg_expr ->
+    returnUs (StgSCC cc stg_expr)
+\end{code}
+
+\begin{code}
+coreExprToStg env (Note other_note expr) = coreExprToStg env expr
+\end{code}
+
+The rest are handled by coreExprStgFloat.
+
+\begin{code}
+coreExprToStg env expr
+  = coreExprToStgFloat env expr  `thenUs` \ (binds,stg_expr) ->
+    returnUs (mkStgBinds binds stg_expr)
 \end{code}
 
 %************************************************************************
@@ -472,204 +383,192 @@ coreExprToStg env expr@(Lam _ _)
 %************************************************************************
 
 \begin{code}
-coreExprToStg env expr@(App _ _)
+coreExprToStgFloat env expr@(App _ _)
   = let
-       (fun, _, _, args) = collectArgs expr
+       (fun,args)    = collect_args expr []
     in
-       -- Deal with the arguments
-    coreArgsToStg env args `thenUs` \ (_, stg_args, arg_binds) ->
+    coreArgsToStg env args             `thenUs` \ (binds, stg_args) ->
 
        -- Now deal with the function
-    case fun of
-      Var fun_id -> returnUs (StgApp (stgLookup env fun_id) stg_args bOGUS_LVs, arg_binds)
+    case (fun, stg_args) of
+      (Var fun_id, _) ->       -- A function Id, so do an StgApp; it's ok if
+                               -- there are no arguments.
+                           returnUs (binds, 
+                                  StgApp (stgLookup env fun_id) stg_args)
+
+      (non_var_fun, []) ->     -- No value args, so recurse into the function
+                           ASSERT( null binds )
+                           coreExprToStg env non_var_fun `thenUs` \e ->
+                           returnUs ([], e)
 
       other -> -- A non-variable applied to things; better let-bind it.
                newStgVar (coreExprType fun)    `thenUs` \ fun_id ->
-               coreExprToStg env fun           `thenUs` \ (stg_fun, fun_binds) ->
+               coreExprToStg env fun           `thenUs` \ (stg_fun) ->
                let
-                  fun_rhs = StgRhsClosure noCostCentre -- No cost centre (ToDo?)
+                  fun_rhs = StgRhsClosure noCCS    -- No cost centre (ToDo?)
                                           stgArgOcc
+                                          noSRT
                                           bOGUS_FVs
                                           SingleEntry  -- Only entered once
                                           []
                                           stg_fun
                in
-               returnUs (StgLet (StgNonRec fun_id fun_rhs)
-                                 (StgApp (StgVarArg fun_id) stg_args bOGUS_LVs),
-                          arg_binds `unionBags` fun_binds)
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsubsection[coreToStg-cases]{Case expressions}
-%*                                                                     *
-%************************************************************************
-
-At this point, we *mangle* cases involving fork# and par# in the
-discriminant.  The original templates for these primops (see
-@PrelVals.lhs@) constructed case expressions with boolean results
-solely to fool the strictness analyzer, the simplifier, and anyone
-else who might want to fool with the evaluation order.  Now, we
-believe that once the translation to STG code is performed, our
-evaluation order is safe.  Therefore, we convert expressions of the
-form:
-
-    case par# e of
-      True -> rhs
-      False -> parError#
-
-to
-
-    case par# e of
-      _ -> rhs
-
-\begin{code}
-
-coreExprToStg env (Case discrim@(Prim op _) alts)
-  | funnyParallelOp op
-  = getUnique                  `thenUs` \ uniq ->
-    coreExprToStg env discrim  `thenUs` \ (stg_discrim, discrim_binds) ->
-    alts_to_stg alts           `thenUs` \ (stg_alts, alts_binds) ->
-    returnUs (
-       StgCase stg_discrim
-               bOGUS_LVs
-               bOGUS_LVs
-               uniq
-               stg_alts,
-       discrim_binds `unionBags` alts_binds
-    )
-  where
-    funnyParallelOp SeqOp  = True
-    funnyParallelOp ParOp  = True
-    funnyParallelOp ForkOp = True
-    funnyParallelOp _      = False
-
-    discrim_ty = coreExprType discrim
-
-    alts_to_stg (PrimAlts _ (BindDefault binder rhs))
-      =        coreExprToStg env rhs  `thenUs` \ (stg_rhs, rhs_binds) ->
-       let
-           stg_deflt = StgBindDefault binder False stg_rhs
-       in
-           returnUs (StgPrimAlts discrim_ty [] stg_deflt, rhs_binds)
-
--- OK, back to real life...
-
-coreExprToStg env (Case discrim alts)
-  = coreExprToStg env discrim          `thenUs` \ (stg_discrim, discrim_binds) ->
-    alts_to_stg discrim alts   `thenUs` \ (stg_alts, alts_binds) ->
-    getUnique                          `thenUs` \ uniq ->
-    returnUs (
-       StgCase stg_discrim
-               bOGUS_LVs
-               bOGUS_LVs
-               uniq
-               stg_alts,
-       discrim_binds `unionBags` alts_binds
-    )
+               returnUs (binds,
+                         StgLet (StgNonRec fun_id fun_rhs) $
+                         StgApp fun_id stg_args)
   where
-    discrim_ty             = coreExprType discrim
-    (_, discrim_ty_args, _) = getAppDataTyConExpandingDicts discrim_ty
-
-    alts_to_stg discrim (AlgAlts alts deflt)
-      = default_to_stg discrim deflt           `thenUs` \ (stg_deflt, deflt_binds) ->
-       mapAndUnzipUs boxed_alt_to_stg alts     `thenUs` \ (stg_alts, alts_binds)  ->
-       returnUs (StgAlgAlts discrim_ty stg_alts stg_deflt,
-                 deflt_binds `unionBags` unionManyBags alts_binds)
-      where
-       boxed_alt_to_stg (con, bs, rhs)
-         = coreExprToStg env rhs    `thenUs` \ (stg_rhs, rhs_binds) ->
-           returnUs ((spec_con, bs, [ True | b <- bs ]{-bogus use mask-}, stg_rhs),
-                      rhs_binds)
-         where
-           spec_con = mkSpecialisedCon con discrim_ty_args
-
-    alts_to_stg discrim (PrimAlts alts deflt)
-      = default_to_stg discrim deflt           `thenUs` \ (stg_deflt,deflt_binds) ->
-       mapAndUnzipUs unboxed_alt_to_stg alts   `thenUs` \ (stg_alts, alts_binds)  ->
-       returnUs (StgPrimAlts discrim_ty stg_alts stg_deflt,
-                 deflt_binds `unionBags` unionManyBags alts_binds)
-      where
-       unboxed_alt_to_stg (lit, rhs)
-         = coreExprToStg env rhs    `thenUs` \ (stg_rhs, rhs_binds) ->
-           returnUs ((lit, stg_rhs), rhs_binds)
-
-    default_to_stg discrim NoDefault
-      = returnUs (StgNoDefault, emptyBag)
-
-    default_to_stg discrim (BindDefault binder rhs)
-      = coreExprToStg new_env rhs    `thenUs` \ (stg_rhs, rhs_binds) ->
-       returnUs (StgBindDefault binder True{-used? no it is lying-} stg_rhs,
-                 rhs_binds)
-      where
-       --
-       -- We convert   case x of {...; x' -> ...x'...}
-       --      to
-       --              case x of {...; _  -> ...x... }
-       --
-       -- See notes in SimplCase.lhs, near simplDefault for the reasoning.
-       -- It's quite easily done: simply extend the environment to bind the
-       -- default binder to the scrutinee.
-       --
-       new_env = case discrim of
-                   Var v -> addOneToIdEnv env binder (stgLookup env v)
-                   other   -> env
+       -- Collect arguments
+    collect_args (App fun arg)            args = collect_args fun (arg:args)
+    collect_args (Note (Coerce _ _) expr) args = collect_args expr args
+    collect_args (Note InlineCall   expr) args = collect_args expr args
+    collect_args fun                      args = (fun, args)
 \end{code}
 
 %************************************************************************
 %*                                                                     *
-\subsubsection[coreToStg-let(rec)]{Let and letrec expressions}
+\subsubsection[coreToStg-con]{Constructors}
 %*                                                                     *
 %************************************************************************
 
 \begin{code}
-coreExprToStg env (Let bind body)
-  = coreBindToStg env     bind   `thenUs` \ (stg_binds, new_env, float_binds1) ->
-    coreExprToStg new_env body   `thenUs` \ (stg_body, float_binds2) ->
-    returnUs (mkStgLets stg_binds stg_body, float_binds1 `unionBags` float_binds2)
+coreExprToStgFloat env expr@(Con (PrimOp (CCallOp (Right _) a b c)) args)
+  = getUniqueUs                        `thenUs` \ u ->
+    coreArgsToStg env args      `thenUs` \ (binds, stg_atoms) ->
+    let con' = PrimOp (CCallOp (Right u) a b c) in
+    returnUs (binds, StgCon con' stg_atoms (coreExprType expr))
+
+coreExprToStgFloat env expr@(Con con args)
+  = coreArgsToStg env args     `thenUs` \ (binds, stg_atoms) ->
+    returnUs (binds, StgCon con stg_atoms (coreExprType expr))
 \end{code}
 
-
 %************************************************************************
 %*                                                                     *
-\subsubsection[coreToStg-scc]{SCC expressions}
+\subsubsection[coreToStg-cases]{Case expressions}
 %*                                                                     *
 %************************************************************************
 
-Covert core @scc@ expression directly to STG @scc@ expression.
 \begin{code}
-coreExprToStg env (SCC cc expr)
-  = coreExprToStg env expr   `thenUs` \ (stg_expr, binds) ->
-    returnUs (StgSCC (coreExprType expr) cc stg_expr, binds)
+coreExprToStgFloat env expr@(Case scrut bndr alts)
+  = coreExprToStgFloat env scrut               `thenUs` \ (binds, scrut') ->
+    newLocalId env bndr                                `thenUs` \ (env', bndr') ->
+    alts_to_stg env' (findDefault alts)                `thenUs` \ alts' ->
+    returnUs (binds, mkStgCase scrut' bndr' alts')
+  where
+    scrut_ty  = idType bndr
+    prim_case = isUnLiftedType scrut_ty && not (isUnboxedTupleType scrut_ty)
+
+    alts_to_stg env (alts, deflt)
+      | prim_case
+      = default_to_stg env deflt               `thenUs` \ deflt' ->
+       mapUs (prim_alt_to_stg env) alts        `thenUs` \ alts' ->
+       returnUs (StgPrimAlts scrut_ty alts' deflt')
+
+      | otherwise
+      = default_to_stg env deflt               `thenUs` \ deflt' ->
+       mapUs (alg_alt_to_stg env) alts         `thenUs` \ alts' ->
+       returnUs (StgAlgAlts scrut_ty alts' deflt')
+
+    alg_alt_to_stg env (DataCon con, bs, rhs)
+         = coreExprToStg env rhs    `thenUs` \ stg_rhs ->
+           returnUs (con, filter isId bs, [ True | b <- bs ]{-bogus use mask-}, stg_rhs)
+               -- NB the filter isId.  Some of the binders may be
+               -- existential type variables, which STG doesn't care about
+
+    prim_alt_to_stg env (Literal lit, args, rhs)
+         = ASSERT( null args )
+           coreExprToStg env rhs    `thenUs` \ stg_rhs ->
+           returnUs (lit, stg_rhs)
+
+    default_to_stg env Nothing
+      = returnUs StgNoDefault
+
+    default_to_stg env (Just rhs)
+      = coreExprToStg env rhs    `thenUs` \ stg_rhs ->
+       returnUs (StgBindDefault stg_rhs)
+               -- The binder is used for prim cases and not otherwise
+               -- (hack for old code gen)
 \end{code}
 
 \begin{code}
-coreExprToStg env (Coerce c ty expr)
-  = coreExprToStg env expr  -- `thenUs` \ (stg_expr, binds) ->
---  returnUs (StgSCC (coreExprType expr) cc stg_expr, binds)
+coreExprToStgFloat env expr
+  = coreExprToStg env expr `thenUs` \stg_expr ->
+    returnUs ([], stg_expr)
 \end{code}
 
-
 %************************************************************************
 %*                                                                     *
 \subsection[coreToStg-misc]{Miscellaneous helping functions}
 %*                                                                     *
 %************************************************************************
 
-Utilities.
+There's not anything interesting we can ASSERT about \tr{var} if it
+isn't in the StgEnv. (WDP 94/06)
+
+\begin{code}
+stgLookup :: StgEnv -> Id -> Id
+stgLookup env var = case (lookupVarEnv env var) of
+                     Nothing  -> var
+                     Just var -> var
+\end{code}
 
 Invent a fresh @Id@:
 \begin{code}
 newStgVar :: Type -> UniqSM Id
 newStgVar ty
- = getUnique                   `thenUs` \ uniq ->
-   returnUs (mkSysLocal SLIT("stg") uniq ty mkUnknownSrcLoc)
+ = getUniqueUs                 `thenUs` \ uniq ->
+   returnUs (mkSysLocal SLIT("stg") uniq ty)
+\end{code}
+
+\begin{code}
+newLocalId env id
+  | externallyVisibleId id
+  = returnUs (env, id)
+
+  | otherwise
+  =    -- Local binder, give it a new unique Id.
+    getUniqueUs                        `thenUs` \ uniq ->
+    let
+      id'     = setIdUnique id uniq
+      new_env = extendVarEnv env id id'
+    in
+    returnUs (new_env, id')
+
+newLocalIds :: StgEnv -> [Id] -> UniqSM (StgEnv, [Id])
+newLocalIds env []
+  = returnUs (env, [])
+newLocalIds env (b:bs)
+  = newLocalId env b   `thenUs` \ (env', b') ->
+    newLocalIds env' bs        `thenUs` \ (env'', bs') ->
+    returnUs (env'', b':bs')
 \end{code}
 
+
 \begin{code}
-mkStgLets ::   [StgBinding]
-           -> StgExpr  -- body of let
-           -> StgExpr
+mkStgBinds :: [StgFloatBind] -> StgExpr -> StgExpr
+mkStgBinds binds body = foldr mkStgBind body binds
+
+mkStgBind (CaseBind bndr rhs) body
+  | isUnLiftedType bndr_ty
+  = mkStgCase rhs bndr (StgPrimAlts bndr_ty [] (StgBindDefault body))
+  | otherwise
+  = mkStgCase rhs bndr (StgAlgAlts bndr_ty [] (StgBindDefault body))
+  where
+    bndr_ty = idType bndr
+
+mkStgBind (LetBind bndr rhs) body
+  | isUnboxedTupleType bndr_ty
+  = panic "mkStgBinds: unboxed tuple"
+  | isUnLiftedType bndr_ty
+  = mkStgCase rhs bndr (StgPrimAlts bndr_ty [] (StgBindDefault body))
+
+  | otherwise
+  = StgLet (StgNonRec bndr (exprToRhs rhs)) body
+  where
+    bndr_ty = idType bndr
 
-mkStgLets binds body = foldr StgLet body binds
+mkStgCase (StgLet bind expr) bndr alts
+  = StgLet bind (mkStgCase expr bndr alts)
+mkStgCase scrut bndr alts
+  = StgCase scrut bOGUS_LVs bOGUS_LVs bndr noSRT alts
 \end{code}