1 {-# OPTIONS -Wall -fno-warn-name-shadowing #-}
3 ( mkNop, mkAssign, mkStore, mkCall, mkUnsafeCall, mkFinalCall
4 , mkJump, mkCbranch, mkSwitch, mkReturn, mkComment, mkCmmIfThenElse
7 , CmmZ, CmmTopZ, CmmGraph, CmmBlock, CmmAGraph, Middle(..), Last(..), Convention(..)
11 #include "HsVersions.h"
14 import Cmm ( GenCmm(..), GenCmmTop(..), CmmStatic, CmmInfo
15 , CmmCallTarget(..), CmmActuals, CmmFormalsWithoutKinds, CmmFormals
16 , CmmStmt(CmmJump, CmmSwitch, CmmReturn) -- imported in order to call ppr
25 import Outputable hiding (empty)
26 import qualified Outputable as PP
27 import Prelude hiding (zip, unzip, last)
31 type CmmGraph = LGraph Middle Last
32 type CmmAGraph = AGraph Middle Last
33 type CmmBlock = Block Middle Last
34 type CmmZ = GenCmm CmmStatic CmmInfo CmmGraph
35 type CmmTopZ = GenCmmTop CmmStatic CmmInfo CmmGraph
38 mkAssign :: CmmReg -> CmmExpr -> CmmAGraph
39 mkStore :: CmmExpr -> CmmExpr -> CmmAGraph
40 mkCall :: CmmCallTarget -> CmmFormals -> CmmActuals -> C_SRT -> CmmAGraph
41 mkUnsafeCall :: CmmCallTarget -> CmmFormals -> CmmActuals -> CmmAGraph
42 mkFinalCall :: CmmCallTarget -> CmmActuals -> CmmAGraph -- never returns
43 mkJump :: CmmExpr -> CmmActuals -> CmmAGraph
44 mkCbranch :: CmmExpr -> BlockId -> BlockId -> CmmAGraph
45 mkSwitch :: CmmExpr -> [Maybe BlockId] -> CmmAGraph
46 mkReturn :: CmmActuals -> CmmAGraph
47 mkComment :: FastString -> CmmAGraph
49 -- Not to be forgotten, but exported by MkZipCfg:
50 --mkBranch :: BlockId -> CmmAGraph
51 --mkLabel :: BlockId -> CmmAGraph
52 mkCmmIfThenElse :: CmmExpr -> CmmAGraph -> CmmAGraph -> CmmAGraph
53 mkCmmWhileDo :: CmmExpr -> CmmAGraph -> CmmAGraph
55 --------------------------------------------------------------------------
57 mkCmmIfThenElse e = mkIfThenElse (mkCbranch e)
58 mkCmmWhileDo e = mkWhileDo (mkCbranch e)
60 mkCopyIn :: Convention -> CmmFormals -> C_SRT -> CmmAGraph
61 mkCopyOut :: Convention -> CmmFormals -> CmmAGraph
63 -- ^ XXX: Simon or Simon thinks maybe the hints are being abused and
64 -- we should have CmmFormalsWithoutKinds here, but for now it is CmmFormals
65 -- for consistency with the rest of the back end ---NR
67 mkComment fs = mkMiddle (MidComment fs)
71 | MidComment FastString
73 | MidAssign CmmReg CmmExpr -- Assign to register
75 | MidStore CmmExpr CmmExpr -- Assign to memory location. Size is
76 -- given by cmmExprRep of the rhs.
78 | MidUnsafeCall -- An "unsafe" foreign call;
79 CmmCallTarget -- just a fat machine instructoin
80 CmmFormals -- zero or more results
81 CmmActuals -- zero or more arguments
83 | CopyIn -- Move parameters or results from conventional locations to registers
84 -- Note [CopyIn invariant]
87 C_SRT -- Static things kept alive by this block
88 | CopyOut Convention CmmFormals
91 = LastReturn CmmActuals -- Return from a function,
92 -- with these return values.
94 | LastJump CmmExpr CmmActuals
95 -- Tail call to another procedure
97 | LastBranch BlockId CmmFormalsWithoutKinds
98 -- To another block in the same procedure
99 -- The parameters are unused at present.
101 | LastCall { -- A call (native or safe foreign)
102 cml_target :: CmmCallTarget,
103 cml_actual :: CmmActuals, -- Zero or more arguments
104 cml_next :: Maybe BlockId } -- BlockId of continuation, if call returns
106 | LastCondBranch { -- conditional branch
108 cml_true, cml_false :: BlockId
111 | LastSwitch CmmExpr [Maybe BlockId] -- Table branch
112 -- The scrutinee is zero-based;
113 -- zero -> first block
114 -- one -> second block etc
115 -- Undefined outside range, and when there's a Nothing
118 = Argument CCallConv -- Used for function formal params
119 | Result CCallConv -- Used for function results
121 | Local -- Used for control transfers within a (pre-CPS) procedure
122 -- All jump sites known, never pushed on the stack (hence no SRT)
123 -- You can choose whatever calling convention
124 -- you please (provided you make sure
125 -- all the call sites agree)!
128 -- ^ In a complete LGraph for a procedure, the [[Exit]] node should not
129 -- appear, but it is useful in a subgraph (e.g., replacement for a node).
132 Note [CopyIn invariant]
133 ~~~~~~~~~~~~~~~~~~~~~~~
134 In principle, CopyIn ought to be a First node, but in practice, the
135 possibility raises all sorts of hairy issues with graph splicing,
136 rewriting, and so on. In the end, NR finds it better to make the
137 placement of CopyIn a dynamic invariant. This change will complicate
138 the dataflow fact for the proc-point calculation, but it should make
139 things easier in many other respects.
143 -- ================ IMPLEMENTATION ================--
145 mkNop = mkMiddle $ MidNop
146 mkAssign l r = mkMiddle $ MidAssign l r
147 mkStore l r = mkMiddle $ MidStore l r
148 mkCopyIn conv args srt = mkMiddle $ CopyIn conv args srt
149 mkCopyOut conv args = mkMiddle $ CopyOut conv args
151 mkJump e args = mkLast $ LastJump e args
152 mkCbranch pred ifso ifnot = mkLast $ LastCondBranch pred ifso ifnot
153 mkReturn actuals = mkLast $ LastReturn actuals
154 mkSwitch e tbl = mkLast $ LastSwitch e tbl
156 mkUnsafeCall tgt results actuals = mkMiddle $ MidUnsafeCall tgt results actuals
157 mkFinalCall tgt actuals = mkLast $ LastCall tgt actuals Nothing
159 mkCall tgt results actuals srt =
160 withFreshLabel "call successor" $ \k ->
161 mkLast (LastCall tgt actuals (Just k)) <*>
163 mkCopyIn (Result CmmCallConv) results srt
165 instance HavingSuccessors Last where
167 fold_succs = fold_cmm_succs
169 instance LastNode Last where
170 mkBranchNode id = LastBranch id []
171 isBranchNode (LastBranch _ []) = True
172 isBranchNode _ = False
173 branchNodeTarget (LastBranch id []) = id
174 branchNodeTarget _ = panic "asked for target of non-branch"
176 cmmSuccs :: Last -> [BlockId]
177 cmmSuccs (LastReturn {}) = []
178 cmmSuccs (LastJump {}) = []
179 cmmSuccs (LastBranch id _) = [id]
180 cmmSuccs (LastCall _ _ (Just id)) = [id]
181 cmmSuccs (LastCall _ _ Nothing) = []
182 cmmSuccs (LastCondBranch _ t f) = [f, t] -- meets layout constraint
183 cmmSuccs (LastSwitch _ edges) = catMaybes edges
185 fold_cmm_succs :: (BlockId -> a -> a) -> Last -> a -> a
186 fold_cmm_succs _f (LastReturn {}) z = z
187 fold_cmm_succs _f (LastJump {}) z = z
188 fold_cmm_succs f (LastBranch id _) z = f id z
189 fold_cmm_succs f (LastCall _ _ (Just id)) z = f id z
190 fold_cmm_succs _f (LastCall _ _ Nothing) z = z
191 fold_cmm_succs f (LastCondBranch _ te fe) z = f te (f fe z)
192 fold_cmm_succs f (LastSwitch _ edges) z = foldl (flip f) z $ catMaybes edges
195 ----------------------------------------------------------------
196 -- prettyprinting (avoids recursive imports)
198 instance Outputable Middle where
201 instance Outputable Last where
204 instance Outputable Convention where
207 pprMiddle :: Middle -> SDoc
208 pprMiddle stmt = case stmt of
212 CopyIn conv args _ ->
213 if null args then ptext SLIT("empty CopyIn")
214 else commafy (map ppr args) <+> equals <+>
215 ptext SLIT("foreign") <+> doubleQuotes(ppr conv) <+> ptext SLIT("...")
218 if null args then PP.empty
219 else ptext SLIT("CopyOut") <+> doubleQuotes(ppr conv) <+>
220 parens (commafy (map ppr args))
223 MidComment s -> text "//" <+> ftext s
226 MidAssign reg expr -> ppr reg <+> equals <+> ppr expr <> semi
229 MidStore lv expr -> rep <> brackets(ppr lv) <+> equals <+> ppr expr <> semi
231 rep = ppr ( cmmExprRep expr )
233 -- call "ccall" foo(x, y)[r1, r2];
235 MidUnsafeCall (CmmCallee fn cconv) results args ->
236 hcat [ if null results
238 else parens (commafy $ map ppr results) <>
240 ptext SLIT("call"), space,
241 doubleQuotes(ppr cconv), space,
242 target fn, parens ( commafy $ map ppr args ),
245 target t@(CmmLit _) = ppr t
246 target fn' = parens (ppr fn')
248 MidUnsafeCall (CmmPrim op) results args ->
249 pprMiddle (MidUnsafeCall (CmmCallee (CmmLit lbl) CCallConv) results args)
251 lbl = CmmLabel (mkForeignLabel (mkFastString (show op)) Nothing False)
254 pprLast :: Last -> SDoc
255 pprLast stmt = case stmt of
257 LastBranch ident args -> genBranchWithArgs ident args
258 LastCondBranch expr t f -> genFullCondBranch expr t f
259 LastJump expr params -> ppr $ CmmJump expr params
260 LastReturn params -> ppr $ CmmReturn params
261 LastSwitch arg ids -> ppr $ CmmSwitch arg ids
262 LastCall tgt params k -> genCall tgt params k
264 genCall :: CmmCallTarget -> CmmActuals -> Maybe BlockId -> SDoc
265 genCall (CmmCallee fn cconv) args k =
266 hcat [ ptext SLIT("foreign"), space,
267 doubleQuotes(ppr cconv), space,
268 target fn, parens ( commafy $ map ppr args ),
269 case k of Nothing -> ptext SLIT("never returns")
270 Just k -> ptext SLIT("returns to") <+> ppr k,
273 target t@(CmmLit _) = ppr t
274 target fn' = parens (ppr fn')
276 genCall (CmmPrim op) args k =
277 hcat [ text "%", text (show op), parens ( commafy $ map ppr args ),
278 ptext SLIT("returns to"), space, ppr k,
281 genBranchWithArgs :: (Outputable id, Outputable arg) => id -> [arg] -> SDoc
282 genBranchWithArgs ident [] = ptext SLIT("goto") <+> ppr ident <> semi
283 genBranchWithArgs ident args = ptext SLIT("goto") <+> ppr ident <+>
284 parens (commafy (map ppr args)) <> semi
286 genFullCondBranch :: Outputable id => CmmExpr -> id -> id -> SDoc
287 genFullCondBranch expr t f =
288 hsep [ ptext SLIT("if")
292 , ptext SLIT("else goto")
296 pprConvention :: Convention -> SDoc
297 pprConvention (Argument c) = ppr c
298 pprConvention (Result c) = ppr c
299 pprConvention Local = text "<local>"
301 commafy :: [SDoc] -> SDoc
302 commafy xs = hsep $ punctuate comma xs