[project @ 2004-08-10 09:02:36 by simonmar]
[ghc-hetmet.git] / ghc / compiler / codeGen / CgCase.lhs
index 92d5bba..c805aaa 100644 (file)
@@ -1,7 +1,7 @@
 %
 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
 %
-% $Id: CgCase.lhs,v 1.64 2003/07/02 13:18:24 simonpj Exp $
+% $Id: CgCase.lhs,v 1.68 2004/08/10 09:02:38 simonmar Exp $
 %
 %********************************************************
 %*                                                     *
@@ -22,7 +22,8 @@ import CgMonad
 import StgSyn
 import AbsCSyn
 
-import AbsCUtils       ( mkAbstractCs, mkAbsCStmts, mkAlgAltsCSwitch, getAmodeRep )
+import AbsCUtils       ( mkAbstractCs, mkAbsCStmts, mkAlgAltsCSwitch,
+                         getAmodeRep, shimFCallArg )
 import CgBindery       ( getVolatileRegs, getArgAmodes,
                          bindNewToReg, bindNewToTemp,
                          getCAddrModeAndInfo,
@@ -53,6 +54,7 @@ import PrimRep                ( getPrimRepSize, retPrimRepSize, PrimRep(..)
                        )
 import TyCon           ( TyCon, isEnumerationTyCon, tyConPrimRep       )
 import Unique           ( Unique, Uniquable(..), newTagUnique )
+import ForeignCall
 import Util            ( only )
 import List            ( sortBy )
 import Outputable
@@ -145,16 +147,21 @@ cgCase (StgApp v []) live_in_whole_case live_in_alts bndr srt
     bindNewToTemp bndr                 `thenFC` \ tmp_amode ->
     absC (CAssign tmp_amode amode)     `thenC`
     cgPrimAlts NoGC tmp_amode alts alt_type
-\end{code}     
+\end{code}
 
-Special case #3: inline PrimOps.
+Special case #3: inline PrimOps and foreign calls.
 
 \begin{code}
-cgCase (StgOpApp op@(StgPrimOp primop) args _) 
+cgCase (StgOpApp op args _) 
        live_in_whole_case live_in_alts bndr srt alt_type alts
-  | not (primOpOutOfLine primop)
+  | inline_primop
   =    -- Get amodes for the arguments and results
-    getArgAmodes args                  `thenFC` \ arg_amodes ->
+    getArgAmodes args                  `thenFC` \ arg_amodes1 ->
+    let 
+       arg_amodes
+         | StgFCallOp{} <- op = zipWith shimFCallArg args arg_amodes1
+         | otherwise          = arg_amodes1
+    in
     getVolatileRegs live_in_alts        `thenFC` \ vol_regs ->
 
     case alt_type of 
@@ -175,7 +182,30 @@ cgCase (StgOpApp op@(StgPrimOp primop) args _)
           [(_, res_ids, _, rhs)] = alts
 
       AlgAlt tycon     -- ENUMERATION TYPE RETURN
+        | StgPrimOp primop <- op
        -> ASSERT( isEnumerationTyCon tycon )
+          let
+            do_enum_primop :: PrimOp -> FCode CAddrMode        -- Returns amode for result
+            do_enum_primop TagToEnumOp -- No code!
+               = returnFC (only arg_amodes)
+            
+            do_enum_primop primop
+             = absC (COpStmt [tag_amode] op arg_amodes vol_regs)       `thenC`
+               returnFC tag_amode
+             where                     
+               tag_amode = CTemp (newTagUnique (getUnique bndr) 'C') IntRep
+                       -- Being a bit short of uniques for temporary
+                       -- variables here, we use newTagUnique to
+                       -- generate a new unique from the case binder.
+                       -- The case binder's unique will presumably
+                       -- have the 'c' tag (generated by CoreToStg),
+                       -- so we just change its tag to 'C' (for
+                       -- 'case') to ensure it doesn't clash with
+                       -- anything else.  We can't use the unique
+                       -- from the case binder, becaus e this is used
+                       -- to hold the actual result closure (via the
+                       -- call to bindNewToTemp)
+          in
           do_enum_primop primop                `thenFC` \ tag_amode ->
 
                -- Bind the default binder if necessary
@@ -194,27 +224,15 @@ cgCase (StgOpApp op@(StgPrimOp primop) args _)
 
                -- Do the switch
           absC (mkAlgAltsCSwitch tag_amode tagged_alts)
-       where
-          do_enum_primop :: PrimOp -> FCode CAddrMode  -- Returns amode for result
-          do_enum_primop TagToEnumOp   -- No code!
-             = returnFC (only arg_amodes)
-
-          do_enum_primop primop
-             = absC (COpStmt [tag_amode] op arg_amodes vol_regs)       `thenC`
-               returnFC tag_amode
-             where                     
-               tag_amode = CTemp (newTagUnique (getUnique bndr) 'C') IntRep
-                       -- Being a bit short of uniques for temporary variables here, 
-                       -- we use newTagUnique to generate a new unique from the case 
-                       -- binder.  The case binder's unique will presumably have 
-                       -- the 'c' tag (generated by CoreToStg), so we just change 
-                       -- its tag to 'C' (for 'case') to ensure it doesn't clash with 
-                       -- anything else.
-                       -- We can't use the unique from the case binder, becaus e
-                       -- this is used to hold the actual result closure
-                       -- (via the call to bindNewToTemp)
 
       other -> pprPanic "cgCase: case of primop has strange alt type" (ppr alt_type)
+  where
+   inline_primop = case op of
+       StgPrimOp primop  -> not (primOpOutOfLine primop)
+       --StgFCallOp (CCall (CCallSpec _ _ PlayRisky)) _ -> True
+                -- unsafe foreign calls are "inline"
+       _otherwise -> False
+
 \end{code}
 
 TODO: Case-of-case of primop can probably be done inline too (but
@@ -361,20 +379,22 @@ cgEvalAlts cc_slot bndr srt (UbxTupAlt _) [(con,args,_,rhs)]
     
     forkAbsC ( -- forkAbsC for the RHS, so that the envt is
                -- not changed for the mkRetDirect call
-       restoreCurrentCostCentre cc_slot        `thenC` 
        bindUnboxedTupleComponents args         `thenFC` \ (live_regs, ptrs, nptrs, _) ->
+               -- restore the CC *after* binding the tuple components, so that we
+               -- get the stack offset of the saved CC right.
+       restoreCurrentCostCentre cc_slot True   `thenC` 
                -- Generate a heap check if necessary
-       unbxTupleHeapCheck live_regs ptrs nptrs AbsCNop $
+       unbxTupleHeapCheck live_regs ptrs nptrs AbsCNop (
                -- And finally the code for the alternative
        cgExpr rhs
-    )                                          `thenFC` \ abs_c ->
+    ))                                         `thenFC` \ abs_c ->
     mkRetDirectTarget bndr abs_c srt           `thenFC` \ lbl ->
     returnFC (CaseAlts lbl Nothing False)
 
 cgEvalAlts cc_slot bndr srt alt_type@(PrimAlt tycon) alts
   = forkAbsC ( -- forkAbsC for the RHS, so that the envt is
                -- not changed for the mkRetDirect call
-       restoreCurrentCostCentre cc_slot                `thenC` 
+       restoreCurrentCostCentre cc_slot True           `thenC` 
        bindNewToReg bndr reg (mkLFArgument bndr)       `thenC`
        cgPrimAlts GCMayHappen (CReg reg) alts alt_type
     )                                          `thenFC` \ abs_c ->
@@ -463,7 +483,7 @@ cgAlgAlt :: GCFlag
 cgAlgAlt gc_flag uniq cc_slot must_label_branch
          alt_type (con, args, use_mask, rhs)
   = getAbsC (bind_con_args con args            `thenFC` \ _ ->
-            restoreCurrentCostCentre cc_slot   `thenC`
+            restoreCurrentCostCentre cc_slot True      `thenC`
             maybeAltHeapCheck gc_flag alt_type (cgExpr rhs)
     )                                          `thenFC` \ abs_c -> 
     let
@@ -655,11 +675,13 @@ saveCurrentCostCentre
        returnFC (Just slot,
                  CAssign (CVal sp_rel CostCentreRep) (CReg CurCostCentre))
 
-restoreCurrentCostCentre :: Maybe VirtualSpOffset -> Code
-restoreCurrentCostCentre Nothing = nopC
-restoreCurrentCostCentre (Just slot)
- = getSpRelOffset slot                          `thenFC` \ sp_rel ->
-   freeStackSlots [slot]                        `thenC`
+-- Sometimes we don't free the slot containing the cost centre after restoring it
+-- (see CgLetNoEscape.cgLetNoEscapeBody).
+restoreCurrentCostCentre :: Maybe VirtualSpOffset -> Bool -> Code
+restoreCurrentCostCentre Nothing     _freeit = nopC
+restoreCurrentCostCentre (Just slot) freeit
+ = getSpRelOffset slot                              `thenFC` \ sp_rel ->
+   (if freeit then freeStackSlots [slot] else nopC)  `thenC`
    absC (CCallProfCCMacro FSLIT("RESTORE_CCCS") [CVal sp_rel CostCentreRep])
     -- we use the RESTORE_CCCS macro, rather than just
     -- assigning into CurCostCentre, in case RESTORE_CCCS