X-Git-Url: http://git.megacz.com/?p=ghc-hetmet.git;a=blobdiff_plain;f=compiler%2Fcmm%2FZipCfgCmmRep.hs;h=31c1fdff494a8702969232a471931f3813c09136;hp=8c1b46156ef10c7400e3e38a78c6e57fb65e1656;hb=25628e2771424cae1b3366322e8ce6f8a85440f9;hpb=d76b6a05ab36066e8aeb67d58e25992d1ef83a8a diff --git a/compiler/cmm/ZipCfgCmmRep.hs b/compiler/cmm/ZipCfgCmmRep.hs index 8c1b461..31c1fdf 100644 --- a/compiler/cmm/ZipCfgCmmRep.hs +++ b/compiler/cmm/ZipCfgCmmRep.hs @@ -7,51 +7,62 @@ module ZipCfgCmmRep ( CmmZ, CmmTopZ, CmmGraph, CmmBlock, CmmAGraph, Middle(..), Last(..), Convention(..) - , ValueDirection(..) + , ValueDirection(..), CmmBackwardFixedPoint, CmmForwardFixedPoint + , insertBetween, pprCmmGraphLikeCmm ) where -#include "HsVersions.h" - import CmmExpr import Cmm ( GenCmm(..), GenCmmTop(..), CmmStatic, CmmInfo - , CmmCallTarget(..), CmmActuals, CmmFormals, CmmHinted(..) - , CmmStmt(CmmSwitch) -- imported in order to call ppr + , CmmCallTarget(..), CmmActuals, CmmFormals, CmmKinded(..) + , CmmStmt(..) -- imported in order to call ppr on Switch and to + -- implement pprCmmGraphLikeCmm + , CmmSafety(CmmSafe) -- for pprCmmGraphLikeCmm + , CmmReturnInfo(CmmMayReturn) -- for pprCmmGraphLikeCmm ) import PprCmm() import CLabel +import CmmZipUtil import ClosureInfo import FastString import ForeignCall import MachOp -import qualified ZipDataflow0 as DF +import StackSlot +import qualified ZipCfg as Z +import qualified ZipDataflow as DF import ZipCfg import MkZipCfg +import Util import Maybes +import Monad import Outputable import Prelude hiding (zip, unzip, last) +import UniqSet +import UniqSupply ---------------------------------------------------------------------- ----- Type synonyms and definitions -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 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 CmmBackwardFixedPoint a = DF.BackwardFixedPoint Middle Last a () +type CmmForwardFixedPoint a = DF.ForwardFixedPoint Middle Last a () data Middle = MidComment FastString | MidAssign CmmReg CmmExpr -- Assign to register - | MidStore CmmExpr CmmExpr -- Assign to memory location. Size is + | 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 + CmmCallTarget -- just a fat machine instruction CmmFormals -- zero or more results CmmActuals -- zero or more arguments @@ -78,6 +89,7 @@ data Middle -- matching 'CopyOut' in the same basic block. -- As above, '[CmmKind]' will migrate into the foreign calling -- convention, leaving the actuals as '[CmmExpr]'. + deriving Eq data Last = LastBranch BlockId -- Goto another block in the same procedure @@ -128,6 +140,53 @@ Middle node in the basic block in which it occurs. -} ---------------------------------------------------------------------- +----- Splicing between blocks +-- Given a middle node, a block, and a successor BlockId, +-- we can insert the middle node between the block and the successor. +-- We return the updated block and a list of new blocks that must be added +-- to the graph. +-- The semantics is a bit tricky. We consider cases on the last node: +-- o For a branch, we can just insert before the branch, +-- but sometimes the optimizer does better if we actually insert +-- a fresh basic block, enabling some common blockification. +-- o For a conditional branch, switch statement, or call, we must insert +-- a new basic block. +-- o For a jump, or return, this operation is impossible. + +insertBetween :: MonadUnique m => CmmBlock -> [Middle] -> BlockId -> m (CmmBlock, [CmmBlock]) +insertBetween b ms succId = insert $ goto_end $ unzip b + where insert (h, LastOther (LastBranch bid)) = + if bid == succId then + do (bid', bs) <- newBlocks + return (zipht h $ ZLast $ LastOther (LastBranch bid'), bs) + else panic "tried to insert between non-adjacent blocks" + insert (h, LastOther (LastCondBranch c t f)) = + do (t', tbs) <- if t == succId then newBlocks else return $ (t, []) + (f', fbs) <- if f == succId then newBlocks else return $ (f, []) + return (zipht h $ ZLast $ LastOther (LastCondBranch c t' f'), tbs ++ fbs) + insert (h, LastOther (LastCall e (Just k))) = + if k == succId then + do (id', bs) <- newBlocks + return (zipht h $ ZLast $ LastOther (LastCall e (Just id')), bs) + else panic "tried to insert between non-adjacent blocks" + insert (_, LastOther (LastCall _ Nothing)) = + panic "cannot insert after non-returning call" + insert (h, LastOther (LastSwitch e ks)) = + do (ids, bs) <- mapAndUnzipM mbNewBlocks ks + return (zipht h $ ZLast $ LastOther (LastSwitch e ids), join bs) + 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 $ + foldr ZTail (ZLast (LastOther (LastBranch succId))) ms]) + mbNewBlocks (Just k) = if k == succId then liftM lift newBlocks + else return (Just k, []) + mbNewBlocks Nothing = return (Nothing, []) + lift (id, bs) = (Just id, bs) + + +---------------------------------------------------------------------- ----- Instance declarations for control flow instance HavingSuccessors Last where @@ -174,7 +233,7 @@ instance UserOfLocalRegs Middle where fold f z m = foldRegsUsed f z m -- avoid monomorphism restriction instance UserOfLocalRegs Last where - foldRegsUsed f z m = last m + foldRegsUsed f z l = last l where last (LastReturn) = z last (LastJump e) = foldRegsUsed f z e last (LastBranch _id) = z @@ -182,6 +241,25 @@ instance UserOfLocalRegs Last where 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 + middle (CopyIn _ _formals _) = fold f z _formals + middle (CopyOut _ _) = z + fold f z m = foldRegsDefd f z m -- avoid monomorphism restriction + +instance DefinerOfLocalRegs Last where + foldRegsDefd _ z l = last l + where last (LastReturn) = z + last (LastJump _) = z + last (LastBranch _) = z + last (LastCall _ _) = z + last (LastCondBranch _ _ _) = z + last (LastSwitch _ _) = z ---------------------------------------------------------------------- ----- Instance declarations for prettyprinting (avoids recursive imports) @@ -201,16 +279,18 @@ debugPpr :: Bool debugPpr = debugIsOn pprMiddle :: Middle -> SDoc -pprMiddle stmt = (case stmt of +pprMiddle stmt = pp_stmt <+> pp_debug + where + pp_stmt = case stmt of CopyIn conv args _ -> - if null args then ptext SLIT("empty CopyIn") - else commafy (map pprHinted args) <+> equals <+> - ptext SLIT("foreign") <+> doubleQuotes(ppr conv) <+> ptext SLIT("...") + if null args then ptext (sLit "empty CopyIn") + else commafy (map pprKinded args) <+> equals <+> + ptext (sLit "foreign") <+> doubleQuotes(ppr conv) <+> ptext (sLit "...") CopyOut conv args -> - ptext SLIT("next, pass") <+> doubleQuotes(ppr conv) <+> - parens (commafy (map pprHinted args)) + ptext (sLit "PreCopyOut: next, pass") <+> doubleQuotes(ppr conv) <+> + parens (commafy (map pprKinded args)) -- // text MidComment s -> text "//" <+> ftext s @@ -229,8 +309,8 @@ pprMiddle stmt = (case stmt of hcat [ if null results then empty else parens (commafy $ map ppr results) <> - ptext SLIT(" = "), - ptext SLIT("call"), space, + ptext (sLit " = "), + ptext (sLit "call"), space, doubleQuotes(ppr cconv), space, ppr_target fn, parens ( commafy $ map ppr args ), semi ] @@ -241,20 +321,20 @@ pprMiddle stmt = (case stmt of lbl = CmmLabel (mkForeignLabel (mkFastString (show op)) Nothing False) MidAddToContext ra args -> - hcat [ ptext SLIT("return via ") + hcat [ ptext (sLit "return via ") , ppr_target ra, parens (commafy $ map ppr args), semi ] - ) <> - if debugPpr then empty - else text " //" <+> - case stmt of - CopyIn {} -> text "CopyIn" - CopyOut {} -> text "CopyOut" - MidComment {} -> text "MidComment" - MidAssign {} -> text "MidAssign" - MidStore {} -> text "MidStore" - MidUnsafeCall {} -> text "MidUnsafeCall" - MidAddToContext {} -> text "MidAddToContext" + pp_debug = + if not debugPpr then empty + else text " //" <+> + case stmt of + CopyIn {} -> text "CopyIn" + CopyOut {} -> text "CopyOut" + MidComment {} -> text "MidComment" + MidAssign {} -> text "MidAssign" + MidStore {} -> text "MidStore" + MidUnsafeCall {} -> text "MidUnsafeCall" + MidAddToContext {} -> text "MidAddToContext" ppr_target :: CmmExpr -> SDoc @@ -262,20 +342,20 @@ ppr_target t@(CmmLit _) = ppr t ppr_target fn' = parens (ppr fn') -pprHinted :: Outputable a => CmmHinted a -> SDoc -pprHinted (CmmHinted a NoHint) = ppr a -pprHinted (CmmHinted a PtrHint) = doubleQuotes (text "address") <+> ppr a -pprHinted (CmmHinted a SignedHint) = doubleQuotes (text "signed") <+> ppr a -pprHinted (CmmHinted a FloatHint) = doubleQuotes (text "float") <+> ppr a +pprKinded :: Outputable a => CmmKinded a -> SDoc +pprKinded (CmmKinded a NoHint) = ppr a +pprKinded (CmmKinded a PtrHint) = doubleQuotes (text "address") <+> ppr a +pprKinded (CmmKinded a SignedHint) = doubleQuotes (text "signed") <+> ppr a +pprKinded (CmmKinded a FloatHint) = doubleQuotes (text "float") <+> ppr a pprLast :: Last -> SDoc pprLast stmt = (case stmt of - LastBranch ident -> ptext SLIT("goto") <+> ppr ident <> semi + 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] + 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 ) <> @@ -291,10 +371,10 @@ pprLast stmt = (case stmt of genBareCall :: CmmExpr -> Maybe BlockId -> SDoc genBareCall fn k = - 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 + 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 , semi ] where @@ -304,11 +384,11 @@ pprFun f = parens (ppr f) genFullCondBranch :: Outputable id => CmmExpr -> id -> id -> SDoc genFullCondBranch expr t f = - hsep [ ptext SLIT("if") + hsep [ ptext (sLit "if") , parens(ppr expr) - , ptext SLIT("goto") + , ptext (sLit "goto") , ppr t <> semi - , ptext SLIT("else goto") + , ptext (sLit "else goto") , ppr f <> semi ] @@ -318,3 +398,114 @@ pprConvention (ConventionPrivate {} ) = text "" commafy :: [SDoc] -> SDoc commafy xs = hsep $ punctuate comma xs + + +---------------------------------------------------------------- +-- | The purpose of this function is to print a Cmm zipper graph "as if it were" +-- a Cmm program. The objective is dodgy, so it's unsurprising parts of the +-- code are dodgy as well. + +pprCmmGraphLikeCmm :: CmmGraph -> SDoc +pprCmmGraphLikeCmm g = vcat (swallow blocks) + where blocks = Z.postorder_dfs g + swallow :: [CmmBlock] -> [SDoc] + swallow [] = [] + swallow (Z.Block id t : rest) = tail id [] Nothing t rest + tail id prev' out (Z.ZTail (CopyOut conv args) t) rest = + if isJust out then panic "multiple CopyOut nodes in one basic block" + else + tail id (prev') (Just (conv, args)) t rest + tail id prev' out (Z.ZTail m t) rest = tail id (mid m : prev') out t rest + tail id prev' out (Z.ZLast Z.LastExit) rest = exit id prev' out rest + tail id prev' out (Z.ZLast (Z.LastOther l)) rest = last id prev' out l rest + mid (CopyIn _ [] _) = text "// proc point (no parameters)" + mid m@(CopyIn {}) = ppr m <+> text "(proc point)" + mid m = ppr m + block' id prev' + | id == Z.lg_entry g, entry_has_no_pred = + vcat (text "" : reverse prev') + | otherwise = hang (ppr id <> colon) 4 (vcat (reverse prev')) + last id prev' out l n = + let endblock stmt = block' id (stmt : prev') : swallow n in + case l of + LastBranch tgt -> + case n of + Z.Block id' t : bs + | tgt == id', unique_pred id' + -> tail id prev' out t bs -- optimize out redundant labels + _ -> endblock (ppr $ CmmBranch tgt) + l@(LastCondBranch expr tid fid) -> + let ft id = text "// fall through to " <> ppr id in + case n of + Z.Block id' t : bs + | id' == fid, isNothing out -> + tail id (ft fid : ppr (CmmCondBranch expr tid) : prev') Nothing t bs + | id' == tid, Just e' <- maybeInvertCmmExpr expr, isNothing out-> + tail id (ft tid : ppr (CmmCondBranch e' fid) : prev') Nothing t bs + _ -> endblock $ with_out out l + l@(LastJump {}) -> endblock $ with_out out l + l@(LastReturn {}) -> endblock $ with_out out l + l@(LastSwitch {}) -> endblock $ with_out out l + l@(LastCall _ Nothing) -> endblock $ with_out out l + l@(LastCall tgt (Just k)) + | Z.Block id' (Z.ZTail (CopyIn _ ress srt) t) : bs <- n, + Just (conv, args) <- out, + id' == k -> + let call = CmmCall tgt' ress args (CmmSafe srt) CmmMayReturn + tgt' = CmmCallee tgt (cconv_of_conv conv) + ppcall = ppr call <+> parens (text "ret to" <+> ppr k) + in if unique_pred k then + tail id (ppcall : prev') Nothing t bs + else + endblock (ppcall) + | Z.Block id' t : bs <- n, id' == k, unique_pred k, + Just (conv, args) <- out, + Just (ress, srt) <- findCopyIn t -> + let call = CmmCall tgt' ress args (CmmSafe srt) CmmMayReturn + tgt' = CmmCallee tgt (cconv_of_conv conv) + delayed = + ptext (sLit "// delayed CopyIn follows previous call") + in tail id (delayed : ppr call : prev') Nothing t bs + | otherwise -> endblock $ with_out out l + findCopyIn (Z.ZTail (CopyIn _ ress srt) _) = Just (ress, srt) + findCopyIn (Z.ZTail _ t) = findCopyIn t + findCopyIn (Z.ZLast _) = Nothing + exit id prev' out n = -- highly irregular (assertion violation?) + let endblock stmt = block' id (stmt : prev') : swallow n in + case out of Nothing -> endblock (text "// ") + Just (conv, args) -> endblock (ppr (CopyOut conv args) $$ + text "// ") + preds = zipPreds g + entry_has_no_pred = case lookupBlockEnv preds (Z.lg_entry g) of + Nothing -> True + Just s -> isEmptyUniqSet s + single_preds = + let add b single = + let id = Z.blockId b + in case lookupBlockEnv preds id of + Nothing -> single + Just s -> if sizeUniqSet s == 1 then + extendBlockSet single id + else single + in Z.fold_blocks add emptyBlockSet g + unique_pred id = elemBlockSet id single_preds + cconv_of_conv (ConventionStandard conv _) = conv + cconv_of_conv (ConventionPrivate {}) = CmmCallConv -- XXX totally bogus + +with_out :: Maybe (Convention, CmmActuals) -> Last -> SDoc +with_out Nothing l = ptext (sLit "??no-arguments??") <+> ppr l +with_out (Just (conv, args)) l = last l + where last (LastCall e k) = + hcat [ptext (sLit "... = foreign "), + doubleQuotes(ppr conv), space, + ppr_target e, parens ( commafy $ map ppr args ), + ptext (sLit " \"safe\""), + case k of Nothing -> ptext (sLit " never returns") + Just _ -> empty, + semi ] + last (LastReturn) = ppr (CmmReturn args) + last (LastJump e) = ppr (CmmJump e args) + last l = ppr (CopyOut conv args) $$ ppr l + ppr_target (CmmLit lit) = ppr lit + ppr_target fn' = parens (ppr fn') + commafy xs = hsep $ punctuate comma xs