adding new files to do with new cmm functionality
[ghc-hetmet.git] / compiler / cmm / ZipCfgCmm.hs
diff --git a/compiler/cmm/ZipCfgCmm.hs b/compiler/cmm/ZipCfgCmm.hs
new file mode 100644 (file)
index 0000000..367d952
--- /dev/null
@@ -0,0 +1,302 @@
+{-# OPTIONS -Wall -fno-warn-name-shadowing #-}
+module ZipCfgCmm
+  ( mkNop, mkAssign, mkStore, mkCall, mkUnsafeCall, mkFinalCall
+         , mkJump, mkCbranch, mkSwitch, mkReturn, mkComment, mkCmmIfThenElse
+         , mkCmmWhileDo
+  , mkCopyIn, mkCopyOut
+  , CmmZ, CmmTopZ, CmmGraph, CmmBlock, CmmAGraph, Middle(..), Last(..), Convention(..)
+  )
+where
+
+#include "HsVersions.h"
+
+import CmmExpr
+import Cmm ( GenCmm(..), GenCmmTop(..), CmmStatic, CmmInfo
+           , CmmCallTarget(..), CmmActuals, CmmFormals, CmmHintFormals
+           , CmmStmt(CmmJump, CmmSwitch, CmmReturn) -- imported in order to call ppr
+           )
+import PprCmm()
+
+import CLabel
+import ClosureInfo
+import FastString
+import ForeignCall
+import Maybes
+import Outputable hiding (empty)
+import qualified Outputable as PP
+import Prelude hiding (zip, unzip, last)
+import ZipCfg 
+import MkZipCfg
+
+type CmmGraph  = LGraph Middle Last
+type CmmAGraph = AGraph Middle Last
+type CmmBlock  = Block  Middle Last
+type CmmZ      = GenCmm    CmmStatic CmmInfo CmmGraph
+type CmmTopZ   = GenCmmTop CmmStatic CmmInfo CmmGraph
+
+mkNop        :: CmmAGraph
+mkAssign     :: CmmReg  -> CmmExpr -> CmmAGraph
+mkStore      :: CmmExpr -> CmmExpr -> CmmAGraph
+mkCall       :: CmmCallTarget -> CmmHintFormals -> CmmActuals -> C_SRT -> CmmAGraph
+mkUnsafeCall :: CmmCallTarget -> CmmHintFormals -> CmmActuals -> CmmAGraph
+mkFinalCall  :: CmmCallTarget -> CmmActuals -> CmmAGraph -- never returns
+mkJump       :: CmmExpr -> CmmActuals -> CmmAGraph
+mkCbranch    :: CmmExpr -> BlockId -> BlockId -> CmmAGraph
+mkSwitch     :: CmmExpr -> [Maybe BlockId] -> CmmAGraph
+mkReturn     :: CmmActuals -> CmmAGraph
+mkComment    :: FastString -> CmmAGraph
+
+-- Not to be forgotten, but exported by MkZipCfg:
+--mkBranch      :: BlockId -> CmmAGraph
+--mkLabel       :: BlockId -> CmmAGraph
+mkCmmIfThenElse :: CmmExpr -> CmmAGraph -> CmmAGraph -> CmmAGraph
+mkCmmWhileDo    :: CmmExpr -> CmmAGraph -> CmmAGraph 
+
+--------------------------------------------------------------------------
+
+mkCmmIfThenElse e = mkIfThenElse (mkCbranch e)
+mkCmmWhileDo    e = mkWhileDo    (mkCbranch e)
+
+mkCopyIn     :: Convention -> CmmHintFormals -> C_SRT -> CmmAGraph
+mkCopyOut    :: Convention -> CmmHintFormals -> CmmAGraph
+
+  -- ^ XXX: Simon or Simon thinks maybe the hints are being abused and
+  -- we should have CmmFormals here, but for now it is CmmHintFormals
+  -- for consistency with the rest of the back end ---NR
+
+mkComment fs = mkMiddle (MidComment fs)
+
+data Middle
+  = MidNop
+  | MidComment FastString
+
+  | MidAssign CmmReg CmmExpr     -- Assign to register
+
+  | MidStore CmmExpr CmmExpr     -- Assign to memory location.  Size is
+                                 -- given by cmmExprRep of the rhs.
+
+  | MidUnsafeCall                -- An "unsafe" foreign call;
+     CmmCallTarget               -- just a fat machine instructoin
+     CmmHintFormals              -- zero or more results
+     CmmActuals                  -- zero or more arguments
+
+  | CopyIn    -- Move parameters or results from conventional locations to registers
+              -- Note [CopyIn invariant]
+        Convention 
+        CmmHintFormals      
+        C_SRT           -- Static things kept alive by this block
+  | CopyOut Convention CmmHintFormals 
+
+data Last
+  = LastReturn CmmActuals          -- Return from a function,
+                                  -- with these return values.
+
+  | LastJump   CmmExpr CmmActuals
+        -- Tail call to another procedure
+
+  | LastBranch BlockId CmmFormals
+        -- To another block in the same procedure
+        -- The parameters are unused at present.
+
+  | LastCall {                   -- A call (native or safe foreign)
+        cml_target :: CmmCallTarget,
+        cml_actual :: CmmActuals,        -- Zero or more arguments
+        cml_next   :: Maybe BlockId }  -- BlockId of continuation, if call returns
+
+  | LastCondBranch {            -- conditional branch
+        cml_pred :: CmmExpr,
+        cml_true, cml_false :: BlockId
+    }
+
+  | LastSwitch CmmExpr [Maybe BlockId]   -- Table branch
+        -- The scrutinee is zero-based; 
+        --      zero -> first block
+        --      one  -> second block etc
+        -- Undefined outside range, and when there's a Nothing
+
+data Convention
+  = Argument CCallConv  -- Used for function formal params
+  | Result CCallConv    -- Used for function results
+
+  | Local       -- Used for control transfers within a (pre-CPS) procedure
+                -- All jump sites known, never pushed on the stack (hence no SRT)
+                -- You can choose whatever calling convention
+                -- you please (provided you make sure
+                -- all the call sites agree)!
+  deriving Eq
+
+-- ^ In a complete LGraph for a procedure, the [[Exit]] node should not
+-- appear, but it is useful in a subgraph (e.g., replacement for a node).
+
+{-
+Note [CopyIn invariant]
+~~~~~~~~~~~~~~~~~~~~~~~
+In principle, CopyIn ought to be a First node, but in practice, the
+possibility raises all sorts of hairy issues with graph splicing,
+rewriting, and so on.  In the end, NR finds it better to make the
+placement of CopyIn a dynamic invariant.  This change will complicate
+the dataflow fact for the proc-point calculation, but it should make
+things easier in many other respects.  
+-}
+
+
+-- ================ IMPLEMENTATION ================--
+
+mkNop                     = mkMiddle $ MidNop
+mkAssign l r              = mkMiddle $ MidAssign l r
+mkStore  l r              = mkMiddle $ MidStore  l r
+mkCopyIn  conv args srt   = mkMiddle $ CopyIn  conv args srt
+mkCopyOut conv args       = mkMiddle $ CopyOut conv args 
+
+mkJump e args             = mkLast   $ LastJump e args
+mkCbranch pred ifso ifnot = mkLast   $ LastCondBranch pred ifso ifnot
+mkReturn actuals          = mkLast   $ LastReturn actuals
+mkSwitch e tbl            = mkLast   $ LastSwitch e tbl
+
+mkUnsafeCall tgt results actuals = mkMiddle $ MidUnsafeCall tgt results actuals
+mkFinalCall  tgt actuals         = mkLast   $ LastCall      tgt actuals Nothing
+
+mkCall tgt results actuals srt =
+  withFreshLabel "call successor" $ \k ->
+    mkLast (LastCall tgt actuals (Just k)) <*>
+    mkLabel k <*>
+    mkCopyIn (Result CmmCallConv) results srt
+
+instance HavingSuccessors Last where
+    succs = cmmSuccs
+    fold_succs = fold_cmm_succs
+
+instance LastNode Last where
+    mkBranchNode id = LastBranch id []
+    isBranchNode (LastBranch _ []) = True
+    isBranchNode _ = False
+    branchNodeTarget (LastBranch id []) = id
+    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
+
+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
+
+
+----------------------------------------------------------------
+-- prettyprinting (avoids recursive imports)
+
+instance Outputable Middle where
+    ppr s = pprMiddle s
+
+instance Outputable Last where
+    ppr s = pprLast s
+
+instance Outputable Convention where
+    ppr = pprConvention
+
+pprMiddle :: Middle -> SDoc    
+pprMiddle stmt = case stmt of
+
+    MidNop -> semi
+
+    CopyIn conv args _ ->
+        if null args then ptext SLIT("empty CopyIn")
+        else commafy (map ppr args) <+> equals <+>
+             ptext SLIT("foreign") <+> doubleQuotes(ppr conv) <+> ptext SLIT("...")
+
+    CopyOut conv args ->
+        if null args then PP.empty
+        else ptext SLIT("CopyOut") <+> doubleQuotes(ppr conv) <+>
+             parens (commafy (map ppr args))
+
+    --  // text
+    MidComment s -> text "//" <+> ftext s
+
+    -- reg = expr;
+    MidAssign reg expr -> ppr reg <+> equals <+> ppr expr <> semi
+
+    -- rep[lv] = expr;
+    MidStore lv expr -> rep <> brackets(ppr lv) <+> equals <+> ppr expr <> semi
+        where
+          rep = ppr ( cmmExprRep expr )
+
+    -- call "ccall" foo(x, y)[r1, r2];
+    -- ToDo ppr volatile
+    MidUnsafeCall (CmmCallee fn cconv) results args ->
+        hcat [ if null results
+                  then PP.empty
+                  else parens (commafy $ map ppr results) <>
+                       ptext SLIT(" = "),
+               ptext SLIT("call"), space, 
+               doubleQuotes(ppr cconv), space,
+               target fn, parens  ( commafy $ map ppr args ),
+               semi ]
+        where
+            target t@(CmmLit _) = ppr t
+            target fn'          = parens (ppr fn')
+
+    MidUnsafeCall (CmmPrim op) results args ->
+        pprMiddle (MidUnsafeCall (CmmCallee (CmmLit lbl) CCallConv) results args)
+        where
+          lbl = CmmLabel (mkForeignLabel (mkFastString (show op)) Nothing False)
+
+
+pprLast :: Last -> SDoc    
+pprLast stmt = case stmt of
+
+    LastBranch ident args     -> genBranchWithArgs ident args
+    LastCondBranch expr t f   -> genFullCondBranch expr t f
+    LastJump expr params      -> ppr $ CmmJump expr params
+    LastReturn params         -> ppr $ CmmReturn params
+    LastSwitch arg ids        -> ppr $ CmmSwitch arg ids
+    LastCall tgt params k     -> genCall tgt params k
+
+genCall :: CmmCallTarget -> CmmActuals -> Maybe BlockId -> SDoc
+genCall (CmmCallee fn cconv) args k =
+        hcat [ ptext SLIT("foreign"), space, 
+               doubleQuotes(ppr cconv), space,
+               target fn, parens  ( commafy $ map ppr args ),
+               case k of Nothing -> ptext SLIT("never returns")
+                         Just k -> ptext SLIT("returns to") <+> ppr k,
+               semi ]
+        where
+            target t@(CmmLit _) = ppr t
+            target fn'          = parens (ppr fn')
+
+genCall (CmmPrim op) args k =
+    hcat [ text "%", text (show op), parens  ( commafy $ map ppr args ),
+           ptext SLIT("returns to"), space, ppr k,
+           semi ]
+
+genBranchWithArgs :: (Outputable id, Outputable arg) => id -> [arg] -> SDoc
+genBranchWithArgs ident [] = ptext SLIT("goto") <+> ppr ident <> semi
+genBranchWithArgs ident args = ptext SLIT("goto") <+> ppr ident <+>
+                               parens (commafy (map ppr args)) <> semi
+
+genFullCondBranch :: Outputable id => CmmExpr -> id -> id -> SDoc
+genFullCondBranch expr t f =
+    hsep [ ptext SLIT("if")
+         , parens(ppr expr)
+         , ptext SLIT("goto")
+         , ppr t <> semi
+         , ptext SLIT("else goto")
+         , ppr f <> semi
+         ]
+
+pprConvention :: Convention -> SDoc
+pprConvention (Argument c) = ppr c
+pprConvention (Result c) = ppr c
+pprConvention Local = text "<local>"
+
+commafy :: [SDoc] -> SDoc
+commafy xs = hsep $ punctuate comma xs