Big collection of patches for the new codegen branch.
[ghc-hetmet.git] / compiler / cmm / ZipCfgCmmRep.hs
index e030f4b..05203e5 100644 (file)
@@ -1,5 +1,3 @@
-
 -- This module is pure representation and should be imported only by
 -- clients that need to manipulate representation and know what
 -- they're doing.  Clients that need to create flow graphs should
@@ -7,13 +5,12 @@
 
 module ZipCfgCmmRep
   ( CmmZ, CmmTopZ, CmmGraph, CmmBlock, CmmAGraph
-  , Middle(..), Last(..), MidCallTarget(..)
-  , Convention(..), ForeignConvention(..)
+  , Middle(..), Last(..), MidCallTarget(..), UpdFrameOffset
+  , Convention(..), ForeignConvention(..), ForeignSafety(..)
   , ValueDirection(..), ForeignHint(..)
   , CmmBackwardFixedPoint, CmmForwardFixedPoint, pprHinted
   , insertBetween, mapExpMiddle, mapExpLast, mapExpDeepMiddle, mapExpDeepLast
-  , foldExpMiddle, foldExpLast, foldExpDeepMiddle, foldExpDeepLast
-  , joinOuts
+  , foldExpMiddle, foldExpLast, foldExpDeepMiddle, foldExpDeepLast, joinOuts
   )
 where
 
@@ -43,6 +40,7 @@ import Monad
 import Outputable
 import Prelude hiding (zip, unzip, last)
 import qualified Data.List as L
+import SMRep (ByteOff)
 import UniqSupply
 
 ----------------------------------------------------------------------
@@ -56,6 +54,8 @@ type CmmTopZ                 = GenCmmTop CmmStatic CmmInfo CmmGraph
 type CmmBackwardFixedPoint a = DF.BackwardFixedPoint Middle Last a ()
 type CmmForwardFixedPoint  a = DF.ForwardFixedPoint  Middle Last a ()
 
+type UpdFrameOffset = ByteOff
+
 data Middle
   = MidComment FastString
 
@@ -64,18 +64,11 @@ data Middle
   | MidStore  CmmExpr CmmExpr    -- Assign to memory location.  Size is
                                  -- given by cmmExprType of the rhs.
 
-  | MidUnsafeCall                -- An "unsafe" foreign call;
-     MidCallTarget               -- just a fat machine instructoin
+  | MidForeignCall               -- A foreign call;
+     ForeignSafety               -- Is it a safe or unsafe call?
+     MidCallTarget               -- call target and convention
      CmmFormals                  -- zero or more results
      CmmActuals                  -- zero or more arguments
-
-  | MidAddToContext              -- Push a frame on the stack;
-                                 --    I will return to this frame
-     CmmExpr                     -- The frame's return address; it must be
-                                 -- preceded by an info table that describes the
-                                 -- live variables.
-     [CmmExpr]                   -- The frame's live variables, to go on the 
-                                 -- stack with the first one at the young end
   deriving Eq
 
 data Last
@@ -90,13 +83,17 @@ data Last
         --      zero -> first block
         --      one  -> second block etc
         -- Undefined outside range, and when there's a Nothing
-  | LastReturn Int       -- Return from a function; values in previous copy middles
-  | LastJump CmmExpr Int -- Tail call to another procedure; args in a copy middles
-  | LastCall {                      -- A call (native or safe foreign); args in copy middles
-        cml_target :: CmmExpr,      -- never a CmmPrim to a CallishMachOp!
-        cml_cont   :: Maybe BlockId,-- BlockId of continuation, if call returns
-        cml_args   :: Int }     -- liveness info for outgoing args
-  -- All the last nodes that pass arguments carry the size of the outgoing CallArea
+  | LastCall {                   -- A call (native or safe foreign)
+        cml_target  :: CmmExpr,  -- never a CmmPrim to a CallishMachOp!
+        cml_cont    :: Maybe BlockId,
+            -- BlockId of continuation (Nothing for return or tail call)
+        cml_args    :: ByteOff,  -- bytes offset for youngest outgoing arg
+        cml_ret_off :: Maybe UpdFrameOffset}
+          -- stack offset for return (update frames);
+          -- The return offset should be Nothing only if we have to create
+          -- a new call, e.g. for a procpoint, in which case it's an invariant
+          -- that the call does not stand for a return or a tail call,
+          -- and the successor does not need an info table.
 
 data MidCallTarget     -- The target of a MidUnsafeCall
   = ForeignTarget      -- A foreign procedure
@@ -110,6 +107,12 @@ data MidCallTarget -- The target of a MidUnsafeCall
 data Convention
   = Native             -- Native C-- call/return
 
+  | Slow               -- Slow entry points: all args pushed on the stack
+
+  | GC                         -- Entry to the garbage collector: uses the node reg!
+
+  | PrimOp             -- Calling prim ops
+
   | Foreign            -- Foreign call/return
        ForeignConvention
 
@@ -128,6 +131,12 @@ data ForeignConvention
        [ForeignHint]           -- Extra info about the result
   deriving Eq 
 
+data ForeignSafety
+  = Unsafe              -- unsafe call
+  | Safe BlockId        -- making infotable requires: 1. label 
+         UpdFrameOffset --                            2. where the upd frame is
+  deriving Eq
+
 data ValueDirection = Arguments | Results
   -- Arguments go with procedure definitions, jumps, and arguments to calls
   -- Results go with returns and with results of calls.
@@ -161,13 +170,11 @@ insertBetween b ms succId = insert $ goto_end $ unzip b
         insert (h, LastOther (LastSwitch e ks)) =
           do (ids, bs) <- mapAndUnzipM mbNewBlocks ks
              return (zipht h $ ZLast $ LastOther (LastSwitch e ids), join bs)
-        insert (_, LastOther (LastCall _ _ _)) =
+        insert (_, LastOther (LastCall {})) =
           panic "unimp: insertBetween after a call -- probably not a good idea"
-        insert (_, LastOther (LastReturn _)) = panic "cannot insert after return"
-        insert (_, LastOther (LastJump _ _)) = panic "cannot insert after jump"
         insert (_, LastExit) = panic "cannot insert after exit"
         newBlocks = do id <- liftM BlockId $ getUniqueM
-                       return $ (id, [Block id Nothing $
+                       return $ (id, [Block id emptyStackInfo $
                                    foldr ZTail (ZLast (LastOther (LastBranch succId))) ms])
         mbNewBlocks (Just k) = if k == succId then liftM lift newBlocks
                                else return (Just k, [])
@@ -189,33 +196,28 @@ instance LastNode Last where
     branchNodeTarget _ = panic "asked for target of non-branch"
 
 cmmSuccs :: Last -> [BlockId]
-cmmSuccs (LastReturn _)           = []
-cmmSuccs (LastJump {})            = [] 
-cmmSuccs (LastBranch id)          = [id]
-cmmSuccs (LastCall _ (Just id) _) = [id]
-cmmSuccs (LastCall _ Nothing _)   = []
-cmmSuccs (LastCondBranch _ t f)   = [f, t]  -- meets layout constraint
-cmmSuccs (LastSwitch _ edges)     = catMaybes edges
+cmmSuccs (LastBranch id)            = [id]
+cmmSuccs (LastCall _ Nothing _ _)   = []
+cmmSuccs (LastCall _ (Just id) _ _) = [id]
+cmmSuccs (LastCondBranch _ t f)     = [f, t]  -- meets layout constraint
+cmmSuccs (LastSwitch _ edges)       = catMaybes edges
 
 fold_cmm_succs :: (BlockId -> a -> a) -> Last -> a -> a
-fold_cmm_succs _f (LastReturn _)           z = z
-fold_cmm_succs _f (LastJump {})            z = z
-fold_cmm_succs  f (LastBranch id)          z = f id z
-fold_cmm_succs  f (LastCall _ (Just id) _) z = f id z
-fold_cmm_succs _f (LastCall _ Nothing _)   z = z
-fold_cmm_succs  f (LastCondBranch _ te fe) z = f te (f fe z)
-fold_cmm_succs  f (LastSwitch _ edges)     z = foldl (flip f) z $ catMaybes edges
+fold_cmm_succs  f (LastBranch id)            z = f id z
+fold_cmm_succs  _ (LastCall _ Nothing _ _)   z = z
+fold_cmm_succs  f (LastCall _ (Just id) _ _) z = f id z
+fold_cmm_succs  f (LastCondBranch _ te fe)   z = f te (f fe z)
+fold_cmm_succs  f (LastSwitch _ edges)       z = foldl (flip f) z $ catMaybes edges
 
 ----------------------------------------------------------------------
 ----- Instance declarations for register use
 
 instance UserOfLocalRegs Middle where
     foldRegsUsed f z m = middle m
-      where middle (MidComment {})            = z
-            middle (MidAssign _lhs expr)      = fold f z expr
-            middle (MidStore addr rval)       = fold f (fold f z addr) rval
-            middle (MidUnsafeCall tgt _ args) = fold f (fold f z tgt) args
-            middle (MidAddToContext ra args)  = fold f (fold f z ra) args
+      where middle (MidComment {})               = z
+            middle (MidAssign _lhs expr)         = fold f z expr
+            middle (MidStore addr rval)          = fold f (fold f z addr) rval
+            middle (MidForeignCall _ tgt _ args) = fold f (fold f z tgt) args
             fold f z m = foldRegsUsed f z m  -- avoid monomorphism restriction
 
 instance UserOfLocalRegs MidCallTarget where
@@ -226,22 +228,27 @@ instance UserOfSlots MidCallTarget where
   foldSlotsUsed _f z (PrimTarget _)      = z
   foldSlotsUsed f  z (ForeignTarget e _) = foldSlotsUsed f z e
 
+instance (UserOfLocalRegs a) => UserOfLocalRegs (Maybe a) where
+  foldRegsUsed f z (Just x) = foldRegsUsed f z x
+  foldRegsUsed _ z Nothing  = z
+
+instance (UserOfSlots a) => UserOfSlots (Maybe a) where
+  foldSlotsUsed f z (Just x) = foldSlotsUsed f z x
+  foldSlotsUsed _ z Nothing  = z
+
 instance UserOfLocalRegs Last where
     foldRegsUsed f z l = last l
-      where last (LastReturn _)         = z
-            last (LastJump e _)         = foldRegsUsed f z e
-            last (LastBranch _id)       = z
-            last (LastCall tgt _ _)     = foldRegsUsed f z tgt
+      where last (LastBranch _id)       = z
+            last (LastCall tgt _ _ _)   = foldRegsUsed f z tgt
             last (LastCondBranch e _ _) = foldRegsUsed f z e
             last (LastSwitch e _tbl)    = foldRegsUsed f z e
 
 instance DefinerOfLocalRegs Middle where
     foldRegsDefd f z m = middle m
-      where middle (MidComment {})         = z
-            middle (MidAssign _lhs _)      = fold f z _lhs
-            middle (MidStore _ _)          = z
-            middle (MidUnsafeCall _ _ _)   = z
-            middle (MidAddToContext _ _)   = z
+      where middle (MidComment {})            = z
+            middle (MidAssign _lhs _)         = fold f z _lhs
+            middle (MidStore _ _)             = z
+            middle (MidForeignCall _ _ fs _)  = fold f z fs
             fold f z m = foldRegsDefd f z m  -- avoid monomorphism restriction
 
 instance DefinerOfLocalRegs Last where
@@ -253,19 +260,16 @@ instance DefinerOfLocalRegs Last where
 
 instance UserOfSlots Middle where
     foldSlotsUsed f z m = middle m
-      where middle (MidComment {})                = z
-            middle (MidAssign _lhs expr)          = fold f z expr
-            middle (MidStore addr rval)           = fold f (fold f z addr) rval
-            middle (MidUnsafeCall tgt _ress args) = fold f (fold f z tgt) args
-            middle (MidAddToContext ra args)      = fold f (fold f z ra) args
+      where middle (MidComment {})                   = z
+            middle (MidAssign _lhs expr)             = fold f z expr
+            middle (MidStore addr rval)              = fold f (fold f z addr) rval
+            middle (MidForeignCall _ tgt _ress args) = fold f (fold f z tgt) args
             fold f z e = foldSlotsUsed f z e  -- avoid monomorphism restriction
 
 instance UserOfSlots Last where
     foldSlotsUsed f z l = last l
-      where last (LastReturn _)         = z
-            last (LastJump e _)         = foldSlotsUsed f z e
-            last (LastBranch _id)       = z
-            last (LastCall tgt _ _)     = foldSlotsUsed f z tgt
+      where last (LastBranch _id)       = z
+            last (LastCall tgt _ _ _)   = foldSlotsUsed f z tgt
             last (LastCondBranch e _ _) = foldSlotsUsed f z e
             last (LastSwitch e _tbl)    = foldSlotsUsed f z e
 
@@ -275,13 +279,12 @@ instance UserOfSlots l => UserOfSlots (ZLast l) where
 
 instance DefinerOfSlots Middle where
     foldSlotsDefd f z m = middle m
-      where middle (MidComment {})       = z
-            middle (MidAssign _ _)       = z
+      where middle (MidComment {})    = z
+            middle (MidAssign _ _)    = z
+            middle (MidForeignCall {}) = z
             middle (MidStore (CmmStackSlot a i) e) =
               f z (a, i, widthInBytes $ typeWidth $ cmmExprType e)
-            middle (MidStore _ _)        = z
-            middle (MidUnsafeCall _ _ _) = z
-            middle (MidAddToContext _ _) = z
+            middle (MidStore _ _)     = z
 
 instance DefinerOfSlots Last where
     foldSlotsDefd _ z _ = z
@@ -297,32 +300,26 @@ mapExpMiddle :: (CmmExpr -> CmmExpr) -> Middle -> Middle
 mapExpMiddle _   m@(MidComment _)            = m
 mapExpMiddle exp   (MidAssign r e)           = MidAssign r (exp e)
 mapExpMiddle exp   (MidStore addr e)         = MidStore (exp addr) (exp e)
-mapExpMiddle exp   (MidUnsafeCall tgt fs as) =
-  MidUnsafeCall (mapExpMidcall exp tgt) fs (map exp as)
-mapExpMiddle exp   (MidAddToContext e es)    = MidAddToContext (exp e) (map exp es)
+mapExpMiddle exp   (MidForeignCall s tgt fs as) =
+  MidForeignCall s (mapExpMidcall exp tgt) fs (map exp as)
 
 foldExpMiddle :: (CmmExpr -> z -> z) -> Middle -> z -> z
-foldExpMiddle _   (MidComment _)           z = z
-foldExpMiddle exp (MidAssign _ e)          z = exp e z
-foldExpMiddle exp (MidStore addr e)        z = exp addr $ exp e z
-foldExpMiddle exp (MidUnsafeCall tgt _ as) z = foldExpMidcall exp tgt $ foldr exp z as
-foldExpMiddle exp (MidAddToContext e es)   z = exp e $ foldr exp z es
+foldExpMiddle _   (MidComment _)              z = z
+foldExpMiddle exp (MidAssign _ e)             z = exp e z
+foldExpMiddle exp (MidStore addr e)           z = exp addr $ exp e z
+foldExpMiddle exp (MidForeignCall _ tgt _ as) z = foldExpMidcall exp tgt $ foldr exp z as
 
 mapExpLast :: (CmmExpr -> CmmExpr) -> Last -> Last
-mapExpLast _   l@(LastBranch _)         = l
-mapExpLast exp (LastCondBranch e ti fi) = LastCondBranch (exp e) ti fi
-mapExpLast exp (LastSwitch e tbl)       = LastSwitch (exp e) tbl
-mapExpLast exp (LastCall tgt mb_id s)   = LastCall (exp tgt) mb_id s
-mapExpLast exp (LastJump e s)           = LastJump (exp e) s
-mapExpLast _   (LastReturn s)           = LastReturn s
+mapExpLast _   l@(LastBranch _)           = l
+mapExpLast exp (LastCondBranch e ti fi)   = LastCondBranch (exp e) ti fi
+mapExpLast exp (LastSwitch e tbl)         = LastSwitch (exp e) tbl
+mapExpLast exp (LastCall tgt mb_id u s) = LastCall (exp tgt) mb_id u s
 
 foldExpLast :: (CmmExpr -> z -> z) -> Last -> z -> z
 foldExpLast _   (LastBranch _)         z = z
 foldExpLast exp (LastCondBranch e _ _) z = exp e z
 foldExpLast exp (LastSwitch e _)       z = exp e z
-foldExpLast exp (LastCall tgt _ _)     z = exp tgt z
-foldExpLast exp (LastJump e _)         z = exp e z
-foldExpLast _   (LastReturn _)         z = z
+foldExpLast exp (LastCall tgt _ _ _)   z = exp tgt z
 
 mapExpMidcall :: (CmmExpr -> CmmExpr) -> MidCallTarget -> MidCallTarget 
 mapExpMidcall exp   (ForeignTarget e c) = ForeignTarget (exp e) c
@@ -334,8 +331,8 @@ foldExpMidcall _   (PrimTarget _)      z = z
 
 -- Take a transformer on expressions and apply it recursively.
 wrapRecExp :: (CmmExpr -> CmmExpr) -> CmmExpr -> CmmExpr
-wrapRecExp f (CmmMachOp op es)    = f (CmmMachOp op $ map f es)
-wrapRecExp f (CmmLoad addr ty)    = f (CmmLoad (f addr) ty)
+wrapRecExp f (CmmMachOp op es)    = f (CmmMachOp op $ map (wrapRecExp f) es)
+wrapRecExp f (CmmLoad addr ty)    = f (CmmLoad (wrapRecExp f addr) ty)
 wrapRecExp f e                    = f e
 
 mapExpDeepMiddle :: (CmmExpr -> CmmExpr) -> Middle -> Middle
@@ -345,8 +342,8 @@ mapExpDeepLast   f = mapExpLast   $ wrapRecExp f
 
 -- Take a folder on expressions and apply it recursively.
 wrapRecExpf :: (CmmExpr -> z -> z) -> CmmExpr -> z -> z
-wrapRecExpf f e@(CmmMachOp _ es) z = foldr f (f e z) es
-wrapRecExpf f e@(CmmLoad addr _) z = f addr  (f e z)
+wrapRecExpf f e@(CmmMachOp _ es) z = foldr (wrapRecExpf f) (f e z) es
+wrapRecExpf f e@(CmmLoad addr _) z = wrapRecExpf f addr (f e z)
 wrapRecExpf f e                  z = f e z
 
 foldExpDeepMiddle :: (CmmExpr -> z -> z) -> Middle -> z -> z
@@ -362,13 +359,11 @@ joinOuts lattice env l =
   let bot  = fact_bot lattice
       join x y = txVal $ fact_add_to lattice x y
   in case l of
-       (LastReturn _)          -> bot
-       (LastJump _ _)          -> bot
-       (LastBranch id)         -> env id
-       (LastCall _ Nothing _)  -> bot
-       (LastCall _ (Just k) _) -> env k
-       (LastCondBranch _ t f)  -> join (env t) (env f)
-       (LastSwitch _ tbl)      -> foldr join bot (map env $ catMaybes tbl)
+       (LastBranch id)           -> env id
+       (LastCall _ Nothing _ _)  -> bot
+       (LastCall _ (Just k) _ _) -> env k
+       (LastCondBranch _ t f)    -> join (env t) (env f)
+       (LastSwitch _ tbl)        -> foldr join bot (map env $ catMaybes tbl)
 
 ----------------------------------------------------------------------
 ----- Instance declarations for prettyprinting (avoids recursive imports)
@@ -411,30 +406,30 @@ pprMiddle stmt = pp_stmt <+> pp_debug
 
        -- call "ccall" foo(x, y)[r1, r2];
        -- ToDo ppr volatile
-       MidUnsafeCall target results args ->
+       MidForeignCall safety target results args ->
            hsep [ if null results
                      then empty
                      else parens (commafy $ map ppr results) <+> equals,
+                      ppr_safety safety,
                   ptext $ sLit "call", 
                   ppr_call_target target <> parens (commafy $ map ppr args) <> semi]
 
-       MidAddToContext ra args ->
-           hcat [ ptext $ sLit "return via "
-                , ppr_target ra, parens (commafy $ map ppr args), semi ]
-  
     pp_debug =
       if not debugPpr then empty
       else text " //" <+>
            case stmt of
-             MidComment {} -> text "MidComment"
-             MidAssign {}  -> text "MidAssign"
-             MidStore {}   -> text "MidStore"
-             MidUnsafeCall  {} -> text "MidUnsafeCall"
-             MidAddToContext {} -> text "MidAddToContext"
+             MidComment     {} -> text "MidComment"
+             MidAssign      {} -> text "MidAssign"
+             MidStore       {} -> text "MidStore"
+             MidForeignCall {} -> text "MidForeignCall"
 
 ppr_fc :: ForeignConvention -> SDoc
 ppr_fc (ForeignConvention c _ _) = doubleQuotes (ppr c)
 
+ppr_safety :: ForeignSafety -> SDoc
+ppr_safety (Safe bid upd) = text "safe<" <> ppr bid <> text ", " <> ppr upd <> text ">"
+ppr_safety Unsafe         = text "unsafe"
+
 ppr_call_target :: MidCallTarget -> SDoc
 ppr_call_target (ForeignTarget fn c) = ppr_fc c <+> ppr_target fn
 ppr_call_target (PrimTarget op)      = ppr (CmmLabel (mkForeignLabel (mkFastString (show op)) Nothing False))
@@ -452,31 +447,24 @@ pprLast :: Last -> SDoc
 pprLast stmt = pp_stmt <+> pp_debug
   where
     pp_stmt = case stmt of
-       LastBranch ident          -> ptext (sLit "goto") <+> ppr ident <> semi
-       LastCondBranch expr t f   -> genFullCondBranch expr t f
-       LastJump expr _           -> hcat [ ptext (sLit "jump"), space, pprFun expr
-                                         , ptext (sLit "(...)"), semi]
-       LastReturn _              -> hcat [ ptext (sLit "return"), space 
-                                         , ptext (sLit "(...)"), semi]
-       LastSwitch arg ids        -> ppr $ CmmSwitch arg ids
-       LastCall tgt k _          -> genBareCall tgt k
+       LastBranch ident             -> ptext (sLit "goto") <+> ppr ident <> semi
+       LastCondBranch expr t f      -> genFullCondBranch expr t f
+       LastSwitch arg ids           -> ppr $ CmmSwitch arg ids
+       LastCall tgt k off updfr_off -> genBareCall tgt k off updfr_off
 
     pp_debug = text " //" <+> case stmt of
            LastBranch {} -> text "LastBranch"
            LastCondBranch {} -> text "LastCondBranch"
-           LastJump {} -> text "LastJump"
-           LastReturn {} -> text "LastReturn"
            LastSwitch {} -> text "LastSwitch"
            LastCall {} -> text "LastCall"
 
-genBareCall :: CmmExpr -> Maybe BlockId -> SDoc
-genBareCall fn k =
+genBareCall :: CmmExpr -> Maybe BlockId -> Int -> Maybe UpdFrameOffset -> SDoc
+genBareCall fn k off updfr_off =
         hcat [ ptext (sLit "call"), space
              , pprFun fn, ptext (sLit "(...)"), space
-             , case k of Nothing -> ptext (sLit "never returns")
-                         Just k -> ptext (sLit "returns to") <+> ppr k
+             , ptext (sLit "returns to") <+> ppr k <+> parens (ppr off)
+             , ptext (sLit " with update frame") <+> ppr updfr_off
              , semi ]
-        where
 
 pprFun :: CmmExpr -> SDoc
 pprFun f@(CmmLit _) = ppr f
@@ -493,7 +481,10 @@ genFullCondBranch expr t f =
          ]
 
 pprConvention :: Convention -> SDoc
-pprConvention (Native {})  = empty
+pprConvention (Native {})  = text "<native-convention>"
+pprConvention  Slow        = text "<slow-convention>"
+pprConvention  GC          = text "<gc-convention>"
+pprConvention  PrimOp      = text "<primop-convention>"
 pprConvention (Foreign c)  = ppr c
 pprConvention (Private {}) = text "<private-convention>"