[project @ 1999-06-24 13:04:13 by simonmar]
[ghc-hetmet.git] / ghc / compiler / codeGen / CgCase.lhs
index 99eb1ab..c4afa17 100644 (file)
@@ -1,7 +1,7 @@
 %
 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
 %
-% $Id: CgCase.lhs,v 1.25 1999/03/22 16:57:10 simonm Exp $
+% $Id: CgCase.lhs,v 1.33 1999/06/24 13:04:16 simonmar Exp $
 %
 %********************************************************
 %*                                                     *
@@ -10,9 +10,8 @@
 %********************************************************
 
 \begin{code}
-module CgCase (        cgCase, saveVolatileVarsAndRegs, 
-               restoreCurrentCostCentre, freeCostCentreSlot,
-               splitTyConAppThroughNewTypes ) where
+module CgCase (        cgCase, saveVolatileVarsAndRegs, restoreCurrentCostCentre
+       ) where
 
 #include "HsVersions.h"
 
@@ -25,14 +24,13 @@ import AbsCSyn
 import AbsCUtils       ( mkAbstractCs, mkAbsCStmts, mkAlgAltsCSwitch,
                          getAmodeRep, nonemptyAbsC
                        )
-import CoreSyn         ( isDeadBinder )
 import CgUpdate                ( reserveSeqFrame )
-import CgBindery       ( getVolatileRegs, getArgAmodes,
+import CgBindery       ( getVolatileRegs, getArgAmodes, getArgAmode,
                          bindNewToReg, bindNewToTemp,
                          bindNewPrimToAmode,
                          rebindToStack, getCAddrMode,
                          getCAddrModeAndInfo, getCAddrModeIfVolatile,
-                         buildContLivenessMask, nukeDeadBindings
+                         buildContLivenessMask, nukeDeadBindings,
                        )
 import CgCon           ( bindConArgs, bindUnboxedTupleComponents )
 import CgHeapery       ( altHeapCheck, yield )
@@ -40,7 +38,7 @@ import CgRetConv      ( dataReturnConvPrim, ctrlReturnConvAlg,
                          CtrlReturnConvention(..)
                        )
 import CgStackery      ( allocPrimStack, allocStackTop,
-                         deAllocStackTop, freeStackSlots
+                         deAllocStackTop, freeStackSlots, dataStackSlots
                        )
 import CgTailCall      ( tailCallFun )
 import CgUsages                ( getSpRelOffset, getRealSp )
@@ -51,6 +49,7 @@ import CLabel         ( CLabel, mkVecTblLabel, mkReturnPtLabel,
 import ClosureInfo     ( mkLFArgument )
 import CmdLineOpts     ( opt_SccProfilingOn, opt_GranMacros )
 import CostCentre      ( CostCentre )
+import CoreSyn         ( isDeadBinder )
 import Id              ( Id, idPrimRep )
 import DataCon         ( DataCon, dataConTag, fIRST_TAG, ConTag,
                          isUnboxedTupleCon, dataConType )
@@ -62,10 +61,11 @@ import PrimRep              ( getPrimRepSize, retPrimRepSize, PrimRep(..)
 import TyCon           ( TyCon, isEnumerationTyCon, isUnboxedTupleTyCon,
                          isNewTyCon, isAlgTyCon, isFunTyCon, isPrimTyCon,
                          tyConDataCons, tyConFamilySize )
-import Type            ( Type, typePrimRep, splitAlgTyConApp, splitTyConApp_maybe,
-                         splitFunTys, applyTys )
-import Unique           ( Unique, Uniquable(..) )
+import Type            ( Type, typePrimRep, splitAlgTyConApp, 
+                         splitTyConApp_maybe, splitRepTyConApp_maybe )
+import Unique           ( Unique, Uniquable(..), mkBuiltinUnique )
 import Maybes          ( maybeToBool )
+import Util
 import Outputable
 \end{code}
 
@@ -116,14 +116,6 @@ Against:
 
        This never hurts us if there is only one alternative.
 
-
-*** NOT YET DONE ***  The difficulty is that \tr{!B!}, \tr{!C!} need
-to take account of what is live, and that includes all live volatile
-variables, even if they also have stable analogues.  Furthermore, the
-stack pointers must be lined up properly so that GC sees tidy stacks.
-If these things are done, then the heap checks can be done at \tr{!B!} and
-\tr{!C!} without a full save-volatile-vars sequence.
-
 \begin{code}
 cgCase :: StgExpr
        -> StgLiveVars
@@ -134,10 +126,73 @@ cgCase    :: StgExpr
        -> Code
 \end{code}
 
-Several special cases for inline primitive operations.
+Special case #1:  PrimOps returning enumeration types.
+
+For enumeration types, we invent a temporary (builtin-unique 1) to
+hold the tag, and cross our fingers that this doesn't clash with
+anything else.  Builtin-unique 0 is used for a similar reason when
+compiling enumerated-type primops in CgExpr.lhs.  We can't use the
+unique from the case binder, because this is used to hold the actual
+closure (when the case binder is live, that is).
+
+There is an extra special case for
+
+       case tagToEnum# x of
+               ...
+
+which generates no code for the primop, unless x is used in the
+alternatives (in which case we lookup the tag in the relevant closure
+table to get the closure).
+
+\begin{code}
+cgCase (StgCon (PrimOp op) args res_ty)
+         live_in_whole_case live_in_alts bndr srt (StgAlgAlts ty alts deflt)
+  | isEnumerationTyCon tycon
+  = getArgAmodes args `thenFC` \ arg_amodes ->
+
+    let tag_amode = case op of 
+                       TagToEnumOp -> only arg_amodes
+                       _ -> CTemp (mkBuiltinUnique 1) IntRep
+
+       closure = CVal (CIndex (CLbl (mkClosureTblLabel tycon) PtrRep) tag_amode PtrRep) PtrRep
+    in
+
+    case op of {
+       TagToEnumOp -> nopC;  -- no code!
+
+       _ ->    -- Perform the operation
+              getVolatileRegs live_in_alts     `thenFC` \ vol_regs ->
+
+              absC (COpStmt [tag_amode] op
+                arg_amodes -- note: no liveness arg
+                vol_regs)
+    }                                          `thenC`
+
+       -- bind the default binder if necessary
+    (if (isDeadBinder bndr)
+       then nopC
+       else bindNewToTemp bndr                 `thenFC` \ bndr_amode ->
+            absC (CAssign bndr_amode closure))
+                                               `thenC`
+
+       -- compile the alts
+    cgAlgAlts NoGC uniq Nothing{-cc_slot-} False{-no semi-tagging-}
+               False{-not poly case-} alts deflt
+                False{-don't emit yield-}      `thenFC` \ (tagged_alts, deflt_c) ->
+
+       -- Do the switch
+    absC (mkAlgAltsCSwitch tag_amode tagged_alts deflt_c)
+
+   where
+       (Just (tycon,_)) = splitTyConApp_maybe res_ty
+       uniq = getUnique bndr
+\end{code}
+
+Special case #2: inline PrimOps.
 
 \begin{code}
-cgCase (StgCon (PrimOp op) args res_ty) live_in_whole_case live_in_alts bndr srt alts
+cgCase (StgCon (PrimOp op) args res_ty) 
+       live_in_whole_case live_in_alts bndr srt alts
   | not (primOpOutOfLine op)
   =
        -- Get amodes for the arguments and results
@@ -181,10 +236,8 @@ cgCase (StgApp v []) live_in_whole_case live_in_alts bndr srt
        two bindings pointing at the same stack locn doesn't work (it
        confuses nukeDeadBindings).  Hence, use a new temp.
     -}
-    (if (isDeadBinder bndr)
-       then nopC
-       else bindNewToTemp bndr  `thenFC`  \deflt_amode ->
-            absC (CAssign deflt_amode amode)) `thenC`
+    bindNewToTemp bndr                 `thenFC`  \deflt_amode ->
+    absC (CAssign deflt_amode amode)   `thenC`
 
     cgPrimAlts NoGC amode alts deflt []
 \end{code}
@@ -336,43 +389,8 @@ getPrimAppResultAmodes
        :: Unique
        -> StgCaseAlts
        -> [CAddrMode]
-\end{code}
-
-\begin{code}
--- If there's an StgBindDefault which does use the bound
--- variable, then we can only handle it if the type involved is
--- an enumeration type.   That's important in the case
--- of comparisions:
---
---     case x ># y of
---       r -> f r
---
--- The only reason for the restriction to *enumeration* types is our
--- inability to invent suitable temporaries to hold the results;
--- Elaborating the CTemp addr mode to have a second uniq field
--- (which would simply count from 1) would solve the problem.
--- Anyway, cgInlineAlts is now capable of handling all cases;
--- it's only this function which is being wimpish.
-
-getPrimAppResultAmodes uniq (StgAlgAlts ty alts 
-                               (StgBindDefault rhs))
-  | isEnumerationTyCon spec_tycon = [tag_amode]
-  | otherwise                    = pprPanic "getPrimAppResultAmodes: non-enumeration algebraic alternatives with default" (ppr uniq <+> ppr rhs)
-  where
-    -- A temporary variable to hold the tag; this is unaffected by GC because
-    -- the heap-checks in the branches occur after the switch
-    tag_amode     = CTemp uniq IntRep
-    (spec_tycon, _, _) = splitAlgTyConApp ty
-\end{code}
-
-If we don't have a default case, we could be scrutinising an unboxed
-tuple, or an enumeration type...
-
-\begin{code}
-getPrimAppResultAmodes uniq (StgAlgAlts ty alts other_default)
-       -- Default is either StgNoDefault or StgBindDefault with unused binder
 
-  | isEnumerationTyCon tycon = [CTemp uniq IntRep]
+getPrimAppResultAmodes uniq (StgAlgAlts ty alts some_default)
 
   | isUnboxedTupleTyCon tycon = 
        case alts of 
@@ -383,12 +401,10 @@ getPrimAppResultAmodes uniq (StgAlgAlts ty alts other_default)
   | otherwise = panic ("getPrimAppResultAmodes: case of primop has strange type: " ++ showSDoc (ppr ty))
 
   where (tycon, _, _) = splitAlgTyConApp ty
-\end{code}
 
-The situation is simpler for primitive results, because there is only
-one!
+-- The situation is simpler for primitive results, because there is only
+-- one!
 
-\begin{code}
 getPrimAppResultAmodes uniq (StgPrimAlts ty _ _)
   = [CTemp uniq (typePrimRep ty)]
 \end{code}
@@ -417,9 +433,6 @@ cgEvalAlts cc_slot bndr srt alts
   =    
     let uniq = getUnique bndr in
 
-    -- get the stack liveness for the info table (after the CC slot has
-    -- been freed - this is important).
-    freeCostCentreSlot cc_slot         `thenC`
     buildContLivenessMask uniq         `thenFC` \ liveness_mask ->
 
     case alts of
@@ -428,9 +441,7 @@ cgEvalAlts cc_slot bndr srt alts
       (StgAlgAlts ty alts deflt) ->
 
           -- bind the default binder (it covers all the alternatives)
-       (if (isDeadBinder bndr)
-               then nopC
-               else bindNewToReg bndr node mkLFArgument) `thenC`
+       bindNewToReg bndr node mkLFArgument      `thenC`
 
        -- Generate sequel info for use downstream
        -- At the moment, we only do it if the type is vector-returnable.
@@ -450,7 +461,7 @@ cgEvalAlts cc_slot bndr srt alts
        if is_alg && isUnboxedTupleTyCon spec_tycon then
            case alts of 
                [alt] -> let lbl = mkReturnInfoLabel uniq in
-                        cgUnboxedTupleAlt lbl cc_slot True alt
+                        cgUnboxedTupleAlt uniq cc_slot True alt
                                `thenFC` \ abs_c ->
                         getSRTLabel `thenFC` \srt_label -> 
                         absC (CRetDirect uniq abs_c (srt_label, srt) 
@@ -485,17 +496,19 @@ cgEvalAlts cc_slot bndr srt alts
       -- primitive alts...
       (StgPrimAlts ty alts deflt) ->
 
+       -- Restore the cost centre
+       restoreCurrentCostCentre cc_slot        `thenFC` \ cc_restore ->
+
        -- Generate the switch
        getAbsC (cgPrimEvalAlts bndr ty alts deflt)     `thenFC` \ abs_c ->
 
        -- Generate the labelled block, starting with restore-cost-centre
        getSRTLabel                                     `thenFC` \srt_label ->
-       restoreCurrentCostCentre cc_slot        `thenFC` \ cc_restore ->
        absC (CRetDirect uniq (cc_restore `mkAbsCStmts` abs_c) 
                        (srt_label,srt) liveness_mask)  `thenC`
 
        -- Return an amode for the block
-       returnFC (CaseAlts (CLbl (mkReturnPtLabel uniq) RetRep) Nothing)
+       returnFC (CaseAlts (CLbl (mkReturnInfoLabel uniq) RetRep) Nothing)
 \end{code}
 
 
@@ -524,49 +537,6 @@ cgInlineAlts bndr (StgAlgAlts ty [alt@(con,args,use_mask,rhs)] StgNoDefault)
   = panic "cgInlineAlts: single alternative, not an unboxed tuple"
 \end{code}
 
-Hack: to deal with 
-
-       case <# x y of z {
-          DEFAULT -> ...
-        }
-
-\begin{code}
-cgInlineAlts bndr (StgAlgAlts ty [] (StgBindDefault rhs))
-  = bindNewToTemp bndr                 `thenFC` \amode ->
-    let
-       (tycon, _, _) = splitAlgTyConApp ty
-       closure_lbl = CTableEntry (CLbl (mkClosureTblLabel tycon) PtrRep) amode PtrRep
-    in
-    absC (CAssign amode closure_lbl)   `thenC`
-    cgExpr rhs
-\end{code}
-
-Second case: algebraic case, several alternatives.
-Tag is held in a temporary.
-
-\begin{code}
-cgInlineAlts bndr (StgAlgAlts ty alts deflt)
-  =       -- bind the default binder (it covers all the alternatives)
-
-       -- ToDo: BUG! bndr isn't bound in the alternatives
-       -- Shows up when compiling Word.lhs
-       --      case cmp# a b of r {
-       --              True  -> f1 r
-       --              False -> f2 r
-
-    cgAlgAlts NoGC uniq Nothing{-cc_slot-} False{-no semi-tagging-}
-               False{-not poly case-} alts deflt
-                False{-don't emit yield-}      `thenFC` \ (tagged_alts, deflt_c) ->
-
-       -- Do the switch
-    absC (mkAlgAltsCSwitch tag_amode tagged_alts deflt_c)
- where
-    -- A temporary variable to hold the tag; this is unaffected by GC because
-    -- the heap-checks in the branches occur after the switch
-    tag_amode = CTemp uniq IntRep
-    uniq = getUnique bndr
-\end{code}
-
 Third (real) case: primitive result type.
 
 \begin{code}
@@ -574,7 +544,6 @@ cgInlineAlts bndr (StgPrimAlts ty alts deflt)
   = cgPrimInlineAlts bndr ty alts deflt
 \end{code}
 
-
 %************************************************************************
 %*                                                                     *
 \subsection[CgCase-alg-alts]{Algebraic alternatives}
@@ -678,7 +647,7 @@ cgAlgAlt gc_flag uniq cc_slot must_label_branch
     lbl = mkAltLabel uniq tag
 
 cgUnboxedTupleAlt
-       :: CLabel                       -- label of the alternative
+       :: Unique                       -- unique for label of the alternative
        -> Maybe VirtualSpOffset        -- Restore cost centre
        -> Bool                         -- ctxt switch
        -> (DataCon, [Id], [Bool], StgExpr) -- alternative
@@ -776,14 +745,13 @@ cgPrimInlineAlts bndr ty alts deflt
 cgPrimEvalAlts bndr ty alts deflt
   = cgPrimAltsWithDefault bndr GCMayHappen (CReg reg) alts deflt [reg]
   where
-       reg = dataReturnConvPrim kind
+       reg  = WARN( case kind of { PtrRep -> True; other -> False }, text "cgPrimEE" <+> ppr bndr <+> ppr ty  )
+              dataReturnConvPrim kind
        kind = typePrimRep ty
 
 cgPrimAltsWithDefault bndr gc_flag scrutinee alts deflt regs
   =    -- first bind the default if necessary
-    (if isDeadBinder bndr 
-       then nopC
-       else bindNewPrimToAmode bndr scrutinee)         `thenC`
+    bindNewPrimToAmode bndr scrutinee          `thenC`
     cgPrimAlts gc_flag scrutinee alts deflt regs
 
 cgPrimAlts gc_flag scrutinee alts deflt regs
@@ -886,19 +854,17 @@ saveCurrentCostCentre
   = if not opt_SccProfilingOn then
        returnFC (Nothing, AbsCNop)
     else
-       allocPrimStack (getPrimRepSize CostCentreRep)  `thenFC` \ slot ->
+       allocPrimStack (getPrimRepSize CostCentreRep) `thenFC` \ slot ->
+       dataStackSlots [slot]                         `thenC`
        getSpRelOffset slot                           `thenFC` \ sp_rel ->
        returnFC (Just slot,
                  CAssign (CVal sp_rel CostCentreRep) (CReg CurCostCentre))
 
-freeCostCentreSlot :: Maybe VirtualSpOffset -> Code
-freeCostCentreSlot Nothing = nopC
-freeCostCentreSlot (Just slot) = freeStackSlots [slot]
-
 restoreCurrentCostCentre :: Maybe VirtualSpOffset -> FCode AbstractC
 restoreCurrentCostCentre Nothing = returnFC AbsCNop
 restoreCurrentCostCentre (Just slot)
  = getSpRelOffset slot                          `thenFC` \ sp_rel ->
+   freeStackSlots [slot]                        `thenC`
    returnFC (CCallProfCCMacro SLIT("RESTORE_CCCS") [CVal sp_rel CostCentreRep])
     -- we use the RESTORE_CCCS macro, rather than just
     -- assigning into CurCostCentre, in case RESTORE_CCC
@@ -1002,7 +968,7 @@ possibleHeapCheck
        -> Bool                         --  True <=> algebraic case
        -> [MagicId]                    --  live registers
        -> [(VirtualSpOffset,Int)]      --  stack slots to tag
-       -> Maybe CLabel                 --  return address
+       -> Maybe Unique                 --  return address unique
        -> Code                         --  continuation
        -> Code
 
@@ -1012,41 +978,14 @@ possibleHeapCheck NoGC   _ _ tags lbl code
   = code
 \end{code}
 
-splitTyConAppThroughNewTypes is like splitTyConApp_maybe except
-that it looks through newtypes in addition to synonyms.  It's
-useful in the back end where we're not interested in newtypes
-anymore.
-
-Sometimes, we've thrown away the constructors during pruning in the
-renamer.  In these cases, we emit a warning and fall back to using a
-SEQ_FRAME to evaluate the case scrutinee.
-
 \begin{code}
 getScrutineeTyCon :: Type -> Maybe TyCon
 getScrutineeTyCon ty =
-   case (splitTyConAppThroughNewTypes ty) of
+   case splitRepTyConApp_maybe ty of
        Nothing -> Nothing
        Just (tc,_) -> 
                if isFunTyCon tc  then Nothing else     -- not interested in funs
                if isPrimTyCon tc then Just tc else     -- return primitive tycons
                        -- otherwise (algebraic tycons) check the no. of constructors
-               case (tyConFamilySize tc) of
-                       0 -> pprTrace "Warning" (hcat [
-                               text "constructors for ",
-                               ppr tc,
-                               text " not available.\n\tUse -fno-prune-tydecls to fix."
-                               ]) Nothing
-                       _ -> Just tc
-
-splitTyConAppThroughNewTypes  :: Type -> Maybe (TyCon, [Type])
-splitTyConAppThroughNewTypes ty
-  = case splitTyConApp_maybe ty of
-      Just (tc, tys)
-       | isNewTyCon tc ->  splitTyConAppThroughNewTypes ty
-       | otherwise     ->  Just (tc, tys)
-       where
-         ([ty], _) = splitFunTys (applyTys (dataConType (head (tyConDataCons tc))) tys)
-
-      other  -> Nothing
-
+               Just tc
 \end{code}