import CLabel
import FastString
import ForeignCall
-import qualified ZipCfg as Z
import qualified ZipDataflow as DF
import ZipCfg
import MkZipCfg
import BasicTypes
import Maybes
-import Monad
+import Control.Monad
import Outputable
import Prelude hiding (zip, unzip, last)
-import qualified Data.List as L
import SMRep (ByteOff)
import UniqSupply
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
+type CmmStackInfo = (ByteOff, Maybe ByteOff)
+ -- probably want a record; (SP offset on entry, update frame space)
+type CmmZ = GenCmm CmmStatic CmmInfo (CmmStackInfo, CmmGraph)
+type CmmTopZ = GenCmmTop CmmStatic CmmInfo (CmmStackInfo, CmmGraph)
type CmmBackwardFixedPoint a = DF.BackwardFixedPoint Middle Last a ()
type CmmForwardFixedPoint a = DF.ForwardFixedPoint Middle Last a ()
-- one -> second block etc
-- Undefined outside range, and when there's a Nothing
| LastCall { -- A call (native or safe foreign)
- cml_target :: CmmExpr, -- never a CmmPrim to a CallishMachOp!
- cml_cont :: Maybe BlockId,
+ 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, -- byte offset for youngest outgoing arg
- -- (includes update frame, which must be younger)
- 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
- CmmExpr -- Its address
- ForeignConvention -- Its calling convention
-
- | PrimTarget -- A possibly-side-effecting machine operation
- CallishMachOp -- Which one
+
+ cml_args :: ByteOff,
+ -- Byte offset, from the *old* end of the Area associated with
+ -- the BlockId (if cml_cont = Nothing, then Old area), of
+ -- youngest outgoing arg. Set the stack pointer to this before
+ -- transferring control.
+ -- (NB: an update frame might also have been stored in the Old
+ -- area, but it'll be in an older part than the args.)
+
+ cml_ret_args :: ByteOff,
+ -- For calls *only*, the byte offset for youngest returned value
+ -- This is really needed at the *return* point rather than here
+ -- at the call, but in practice it's convenient to record it here.
+
+ cml_ret_off :: Maybe ByteOff
+ -- For calls *only*, the byte offset of the base of the frame that
+ -- must be described by the info table for the return point.
+ -- The older words are an update frames, which have their own
+ -- info-table and layout information
+
+ -- From a liveness point of view, the stack words older than
+ -- cml_ret_off are treated as live, even if the sequel of
+ -- the call goes into a loop.
+ }
+
+data MidCallTarget -- The target of a MidUnsafeCall
+ = ForeignTarget -- A foreign procedure
+ CmmExpr -- Its address
+ ForeignConvention -- Its calling convention
+
+ | PrimTarget -- A possibly-side-effecting machine operation
+ CallishMachOp -- Which one
deriving Eq
data Convention
- = Native -- Native C-- call/return
+ = NativeDirectCall -- Native C-- call skipping the node (closure) argument
+
+ | NativeNodeCall -- Native C-- call including the node argument
+
+ | NativeReturn -- Native C-- return
+
+ | Slow -- Slow entry points: all args pushed on the stack
- | Slow -- Slow entry points: all args pushed on the stack
+ | GC -- Entry to the garbage collector: uses the node reg!
- | GC -- Entry to the garbage collector: uses the node reg!
+ | PrimOpCall -- Calling prim ops
- | PrimOp -- Calling prim ops
+ | PrimOpReturn -- Returning from prim ops
- | Foreign -- Foreign call/return
- ForeignConvention
+ | Foreign -- Foreign call/return
+ ForeignConvention
| Private
-- Used for control transfers within a (pre-CPS) procedure All
panic "unimp: insertBetween after a call -- probably not a good idea"
insert (_, LastExit) = panic "cannot insert after exit"
newBlocks = do id <- liftM BlockId $ getUniqueM
- return $ (id, [Block id emptyStackInfo $
+ return $ (id, [Block id $
foldr ZTail (ZLast (LastOther (LastBranch succId))) ms])
mbNewBlocks (Just k) = if k == succId then liftM lift newBlocks
else return (Just k, [])
branchNodeTarget _ = panic "asked for target of non-branch"
cmmSuccs :: Last -> [BlockId]
-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
+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 (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
+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
foldRegsUsed f z (ForeignTarget e _) = foldRegsUsed f z e
instance UserOfSlots MidCallTarget where
+ foldSlotsUsed f z (ForeignTarget e _) = foldSlotsUsed f z e
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
instance UserOfLocalRegs Last where
foldRegsUsed f z l = last l
where last (LastBranch _id) = z
- last (LastCall tgt _ _ _) = foldRegsUsed f z tgt
+ 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 (MidForeignCall _ _ fs _) = fold f z fs
+ 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
instance UserOfSlots Last where
foldSlotsUsed f z l = last l
where last (LastBranch _id) = z
- last (LastCall tgt _ _ _) = foldSlotsUsed f z tgt
+ last (LastCall tgt _ _ _ _) = foldSlotsUsed f z tgt
last (LastCondBranch e _ _) = foldSlotsUsed f z e
last (LastSwitch e _tbl) = foldSlotsUsed f z e
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
+mapExpLast exp (LastCall tgt mb_id o i s) = LastCall (exp tgt) mb_id o i 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 (LastCall tgt _ _ _ _) z = exp tgt z
mapExpMidcall :: (CmmExpr -> CmmExpr) -> MidCallTarget -> MidCallTarget
mapExpMidcall exp (ForeignTarget e c) = ForeignTarget (exp e) c
let bot = fact_bot lattice
join x y = txVal $ fact_add_to lattice x y
in case l of
- (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)
-- call "ccall" foo(x, y)[r1, r2];
-- ToDo ppr volatile
MidForeignCall safety target results args ->
- hsep [ if null results
- then empty
- else parens (commafy $ map ppr results) <+> equals,
- ppr_safety safety,
+ hsep [ ppUnless (null results) $
+ parens (commafy $ map ppr results) <+> equals,
+ ppr_safety safety,
ptext $ sLit "call",
ppr_call_target target <> parens (commafy $ map ppr args) <> semi]
MidForeignCall {} -> text "MidForeignCall"
ppr_fc :: ForeignConvention -> SDoc
-ppr_fc (ForeignConvention c _ _) = doubleQuotes (ppr c)
+ppr_fc (ForeignConvention c args res) =
+ doubleQuotes (ppr c) <+> text "args: " <+> ppr args <+> text " results: " <+> ppr res
ppr_safety :: ForeignSafety -> SDoc
ppr_safety (Safe bid upd) = text "safe<" <> ppr bid <> text ", " <> ppr upd <> text ">"
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 IsFunction))
+ppr_call_target (PrimTarget op)
+ -- HACK: We're just using a ForeignLabel to get this printed, the label
+ -- might not really be foreign.
+ = ppr (CmmLabel (mkForeignLabel
+ (mkFastString (show op))
+ Nothing ForeignLabelInThisPackage IsFunction))
ppr_target :: CmmExpr -> SDoc
ppr_target t@(CmmLit _) = ppr t
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
- LastSwitch arg ids -> ppr $ CmmSwitch arg ids
- LastCall tgt k off updfr_off -> genBareCall tgt k off updfr_off
+ 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 out res updfr_off -> genBareCall tgt k out res updfr_off
pp_debug = text " //" <+> case stmt of
LastBranch {} -> text "LastBranch"
LastSwitch {} -> text "LastSwitch"
LastCall {} -> text "LastCall"
-genBareCall :: CmmExpr -> Maybe BlockId -> Int -> Maybe UpdFrameOffset -> SDoc
-genBareCall fn k off updfr_off =
+genBareCall :: CmmExpr -> Maybe BlockId -> ByteOff -> ByteOff ->
+ Maybe UpdFrameOffset -> SDoc
+genBareCall fn k out res updfr_off =
hcat [ ptext (sLit "call"), space
, pprFun fn, ptext (sLit "(...)"), space
- , ptext (sLit "returns to") <+> ppr k <+> parens (ppr off)
+ , ptext (sLit "returns to") <+> ppr k <+> parens (ppr out)
+ <+> parens (ppr res)
, ptext (sLit " with update frame") <+> ppr updfr_off
, semi ]
]
pprConvention :: Convention -> SDoc
-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>"
+pprConvention (NativeNodeCall {}) = text "<native-node-call-convention>"
+pprConvention (NativeDirectCall {}) = text "<native-direct-call-convention>"
+pprConvention (NativeReturn {}) = text "<native-ret-convention>"
+pprConvention Slow = text "<slow-convention>"
+pprConvention GC = text "<gc-convention>"
+pprConvention PrimOpCall = text "<primop-call-convention>"
+pprConvention PrimOpReturn = text "<primop-ret-convention>"
+pprConvention (Foreign c) = ppr c
+pprConvention (Private {}) = text "<private-convention>"
pprForeignConvention :: ForeignConvention -> SDoc
pprForeignConvention (ForeignConvention c as rs) = ppr c <> ppr as <> ppr rs