1 ----------------------------------------------------------------------------
3 -- Pretty-printing of Cmm as (a superset of) C--
5 -- (c) The University of Glasgow 2004-2006
7 -----------------------------------------------------------------------------
10 -- This is where we walk over Cmm emitting an external representation,
11 -- suitable for parsing, in a syntax strongly reminiscent of C--. This
12 -- is the "External Core" for the Cmm layer.
14 -- As such, this should be a well-defined syntax: we want it to look nice.
15 -- Thus, we try wherever possible to use syntax defined in [1],
16 -- "The C-- Reference Manual", http://www.cminusminus.org/. We differ
17 -- slightly, in some cases. For one, we use I8 .. I64 for types, rather
18 -- than C--'s bits8 .. bits64.
20 -- We try to ensure that all information available in the abstract
21 -- syntax is reproduced, or reproducible, in the concrete syntax.
22 -- Data that is not in printed out can be reconstructed according to
23 -- conventions used in the pretty printer. There are at least two such
25 -- 1) if a value has wordRep type, the type is not appended in the
27 -- 2) MachOps that operate over wordRep type are printed in a
28 -- C-style, rather than as their internal MachRep name.
30 -- These conventions produce much more readable Cmm output.
32 -- A useful example pass over Cmm is in nativeGen/MachCodeGen.hs
36 writeCmms, pprCmms, pprCmm, pprStmt, pprExpr
39 #include "HsVersions.h"
55 pprCmms :: (Outputable info) => [GenCmm CmmStatic info CmmStmt] -> SDoc
56 pprCmms cmms = pprCode CStyle (vcat (intersperse separator $ map ppr cmms))
58 separator = space $$ ptext SLIT("-------------------") $$ space
60 writeCmms :: Handle -> [Cmm] -> IO ()
61 writeCmms handle cmms = printForC handle (pprCmms cmms)
63 -----------------------------------------------------------------------------
65 instance (Outputable info) => Outputable (GenCmm CmmStatic info CmmStmt) where
68 instance (Outputable info) => Outputable (GenCmmTop CmmStatic info CmmStmt) where
71 instance Outputable CmmBasicBlock where
74 instance Outputable CmmStmt where
77 instance Outputable CmmExpr where
80 instance Outputable CmmReg where
83 instance Outputable LocalReg where
86 instance Outputable GlobalReg where
87 ppr e = pprGlobalReg e
89 instance Outputable CmmStatic where
92 instance Outputable CmmInfo where
95 -----------------------------------------------------------------------------
97 pprCmm :: (Outputable info) => GenCmm CmmStatic info CmmStmt -> SDoc
98 pprCmm (Cmm tops) = vcat $ intersperse (text "") $ map pprTop tops
100 -- --------------------------------------------------------------------------
101 -- Top level `procedure' blocks.
103 pprTop :: (Outputable info) => GenCmmTop CmmStatic info CmmStmt -> SDoc
104 pprTop (CmmProc info lbl params blocks )
106 = vcat [ pprCLabel lbl <> parens (commafy $ map ppr params) <+> lbrace
107 , nest 8 $ lbrace <+> ppr info $$ rbrace
108 , nest 4 $ vcat (map ppr blocks)
111 -- --------------------------------------------------------------------------
112 -- We follow [1], 4.5
114 -- section "data" { ... }
116 pprTop (CmmData section ds) =
117 (hang (pprSection section <+> lbrace) 4 (vcat (map pprStatic ds)))
122 -- --------------------------------------------------------------------------
123 -- Info tables. The current pretty printer needs refinement
124 -- but will work for now.
126 -- For ideas on how to refine it, they used to be printed in the
127 -- style of C--'s 'stackdata' declaration, just inside the proc body,
128 -- and were labelled with the procedure name ++ "_info".
129 pprInfo (CmmNonInfo gc_target) =
130 ptext SLIT("gc_target: ") <>
131 maybe (ptext SLIT("<none>")) pprBlockId gc_target
132 pprInfo (CmmInfo (ProfilingInfo closure_type closure_desc)
133 gc_target tag info) =
134 vcat [ptext SLIT("type: ") <> pprLit closure_type,
135 ptext SLIT("desc: ") <> pprLit closure_desc,
136 ptext SLIT("gc_target: ") <>
137 maybe (ptext SLIT("<none>")) pprBlockId gc_target,
138 ptext SLIT("tag: ") <> integer (toInteger tag),
141 pprTypeInfo (ConstrInfo layout constr descr) =
142 vcat [ptext SLIT("ptrs: ") <> integer (toInteger (fst layout)),
143 ptext SLIT("nptrs: ") <> integer (toInteger (snd layout)),
144 ptext SLIT("constructor: ") <> integer (toInteger constr),
146 pprTypeInfo (FunInfo layout srt fun_type arity args slow_entry) =
147 vcat [ptext SLIT("ptrs: ") <> integer (toInteger (fst layout)),
148 ptext SLIT("nptrs: ") <> integer (toInteger (snd layout)),
149 ptext SLIT("srt: ") <> ppr srt,
150 ptext SLIT("fun_type: ") <> integer (toInteger fun_type),
151 ptext SLIT("arity: ") <> integer (toInteger arity)
152 --ppr args, -- TODO: needs to be printed
153 --ppr slow_entry -- TODO: needs to be printed
155 pprTypeInfo (ThunkInfo layout srt) =
156 vcat [ptext SLIT("ptrs: ") <> integer (toInteger (fst layout)),
157 ptext SLIT("nptrs: ") <> integer (toInteger (snd layout)),
158 ptext SLIT("srt: ") <> ppr srt]
159 pprTypeInfo (ThunkSelectorInfo offset srt) =
160 vcat [ptext SLIT("ptrs: ") <> integer (toInteger offset),
161 ptext SLIT("srt: ") <> ppr srt]
162 pprTypeInfo (ContInfo stack srt) =
163 vcat [ptext SLIT("stack: ") <> ppr stack,
164 ptext SLIT("srt: ") <> ppr srt]
166 -- --------------------------------------------------------------------------
167 -- Basic blocks look like assembly blocks.
168 -- lbl: stmt ; stmt ; ..
169 pprBBlock :: CmmBasicBlock -> SDoc
170 pprBBlock (BasicBlock ident stmts) =
171 hang (pprBlockId ident <> colon) 4 (vcat (map ppr stmts))
173 -- --------------------------------------------------------------------------
174 -- Statements. C-- usually, exceptions to this should be obvious.
176 pprStmt :: CmmStmt -> SDoc
177 pprStmt stmt = case stmt of
183 CmmComment s -> text "//" <+> ftext s
186 CmmAssign reg expr -> ppr reg <+> equals <+> ppr expr <> semi
189 CmmStore lv expr -> rep <> brackets(ppr lv) <+> equals <+> ppr expr <> semi
191 rep = ppr ( cmmExprRep expr )
193 -- call "ccall" foo(x, y)[r1, r2];
195 CmmCall (CmmForeignCall fn cconv) results args srt ->
196 hcat [ if null results
198 else parens (commafy $ map ppr results) <>
200 ptext SLIT("call"), space,
201 doubleQuotes(ppr cconv), space,
202 target fn, parens ( commafy $ map ppr args ),
203 brackets (ppr srt), semi ]
205 target (CmmLit lit) = pprLit lit
206 target fn' = parens (ppr fn')
208 CmmCall (CmmPrim op) results args srt ->
209 pprStmt (CmmCall (CmmForeignCall (CmmLit lbl) CCallConv)
212 lbl = CmmLabel (mkForeignLabel (mkFastString (show op)) Nothing False)
214 CmmBranch ident -> genBranch ident
215 CmmCondBranch expr ident -> genCondBranch expr ident
216 CmmJump expr params -> genJump expr params
217 CmmReturn params -> genReturn params
218 CmmSwitch arg ids -> genSwitch arg ids
220 -- --------------------------------------------------------------------------
221 -- goto local label. [1], section 6.6
225 genBranch :: BlockId -> SDoc
227 ptext SLIT("goto") <+> pprBlockId ident <> semi
229 -- --------------------------------------------------------------------------
230 -- Conditional. [1], section 6.4
232 -- if (expr) { goto lbl; }
234 genCondBranch :: CmmExpr -> BlockId -> SDoc
235 genCondBranch expr ident =
236 hsep [ ptext SLIT("if")
239 , pprBlockId ident <> semi ]
241 -- --------------------------------------------------------------------------
242 -- A tail call. [1], Section 6.9
244 -- jump foo(a, b, c);
246 genJump :: CmmExpr -> [(CmmExpr, MachHint)] -> SDoc
249 hcat [ ptext SLIT("jump")
251 , if isTrivialCmmExpr expr
254 CmmLoad (CmmReg _) _ -> pprExpr expr
255 _ -> parens (pprExpr expr)
257 , parens ( commafy $ map ppr args )
260 -- --------------------------------------------------------------------------
261 -- Return from a function. [1], Section 6.8.2 of version 1.128
265 genReturn :: [(CmmExpr, MachHint)] -> SDoc
268 hcat [ ptext SLIT("return")
270 , parens ( commafy $ map ppr args )
273 -- --------------------------------------------------------------------------
274 -- Tabled jump to local label
276 -- The syntax is from [1], section 6.5
278 -- switch [0 .. n] (expr) { case ... ; }
280 genSwitch :: CmmExpr -> [Maybe BlockId] -> SDoc
281 genSwitch expr maybe_ids
283 = let pairs = groupBy snds (zip [0 .. ] maybe_ids )
285 in hang (hcat [ ptext SLIT("switch [0 .. ")
286 , int (length maybe_ids - 1)
288 , if isTrivialCmmExpr expr
290 else parens (pprExpr expr)
293 4 (vcat ( map caseify pairs )) $$ rbrace
296 snds a b = (snd a) == (snd b)
298 caseify :: [(Int,Maybe BlockId)] -> SDoc
299 caseify ixs@((i,Nothing):_)
300 = ptext SLIT("/* impossible: ") <> hcat (intersperse comma (map (int.fst) ixs))
303 = let (is,ids) = unzip as
304 in hsep [ ptext SLIT("case")
305 , hcat (punctuate comma (map int is))
306 , ptext SLIT(": goto")
307 , pprBlockId (head [ id | Just id <- ids]) <> semi ]
309 -- --------------------------------------------------------------------------
313 pprExpr :: CmmExpr -> SDoc
317 pprExpr (CmmMachOp (MO_Add rep)
318 [CmmReg reg, CmmLit (CmmInt (fromIntegral i) rep)])
319 where rep = cmmRegRep reg
320 CmmLit lit -> pprLit lit
323 -- Here's the precedence table from CmmParse.y:
324 -- %nonassoc '>=' '>' '<=' '<' '!=' '=='
333 -- We just cope with the common operators for now, the rest will get
334 -- a default conservative behaviour.
336 -- %nonassoc '>=' '>' '<=' '<' '!=' '=='
337 pprExpr1 (CmmMachOp op [x,y]) | Just doc <- infixMachOp1 op
338 = pprExpr7 x <+> doc <+> pprExpr7 y
339 pprExpr1 e = pprExpr7 e
341 infixMachOp1 (MO_Eq _) = Just (ptext SLIT("=="))
342 infixMachOp1 (MO_Ne _) = Just (ptext SLIT("!="))
343 infixMachOp1 (MO_Shl _) = Just (ptext SLIT("<<"))
344 infixMachOp1 (MO_U_Shr _) = Just (ptext SLIT(">>"))
345 infixMachOp1 (MO_U_Ge _) = Just (ptext SLIT(">="))
346 infixMachOp1 (MO_U_Le _) = Just (ptext SLIT("<="))
347 infixMachOp1 (MO_U_Gt _) = Just (char '>')
348 infixMachOp1 (MO_U_Lt _) = Just (char '<')
349 infixMachOp1 _ = Nothing
352 pprExpr7 (CmmMachOp (MO_Add rep1) [x, CmmLit (CmmInt i rep2)]) | i < 0
353 = pprExpr7 (CmmMachOp (MO_Sub rep1) [x, CmmLit (CmmInt (negate i) rep2)])
354 pprExpr7 (CmmMachOp op [x,y]) | Just doc <- infixMachOp7 op
355 = pprExpr7 x <+> doc <+> pprExpr8 y
356 pprExpr7 e = pprExpr8 e
358 infixMachOp7 (MO_Add _) = Just (char '+')
359 infixMachOp7 (MO_Sub _) = Just (char '-')
360 infixMachOp7 _ = Nothing
363 pprExpr8 (CmmMachOp op [x,y]) | Just doc <- infixMachOp8 op
364 = pprExpr8 x <+> doc <+> pprExpr9 y
365 pprExpr8 e = pprExpr9 e
367 infixMachOp8 (MO_U_Quot _) = Just (char '/')
368 infixMachOp8 (MO_Mul _) = Just (char '*')
369 infixMachOp8 (MO_U_Rem _) = Just (char '%')
370 infixMachOp8 _ = Nothing
372 pprExpr9 :: CmmExpr -> SDoc
375 CmmLit lit -> pprLit1 lit
376 CmmLoad expr rep -> ppr rep <> brackets( ppr expr )
377 CmmReg reg -> ppr reg
378 CmmRegOff reg off -> parens (ppr reg <+> char '+' <+> int off)
379 CmmMachOp mop args -> genMachOp mop args
381 genMachOp :: MachOp -> [CmmExpr] -> SDoc
383 | Just doc <- infixMachOp mop = case args of
385 [x,y] -> pprExpr9 x <+> doc <+> pprExpr9 y
388 [x] -> doc <> pprExpr9 x
390 _ -> pprTrace "PprCmm.genMachOp: machop with strange number of args"
392 parens (hcat $ punctuate comma (map pprExpr args)))
395 | isJust (infixMachOp1 mop)
396 || isJust (infixMachOp7 mop)
397 || isJust (infixMachOp8 mop) = parens (pprExpr (CmmMachOp mop args))
399 | otherwise = char '%' <> ppr_op <> parens (commafy (map pprExpr args))
400 where ppr_op = text (map (\c -> if c == ' ' then '_' else c)
402 -- replace spaces in (show mop) with underscores,
405 -- Unsigned ops on the word size of the machine get nice symbols.
406 -- All else get dumped in their ugly format.
408 infixMachOp :: MachOp -> Maybe SDoc
411 MO_And _ -> Just $ char '&'
412 MO_Or _ -> Just $ char '|'
413 MO_Xor _ -> Just $ char '^'
414 MO_Not _ -> Just $ char '~'
415 MO_S_Neg _ -> Just $ char '-' -- there is no unsigned neg :)
418 -- --------------------------------------------------------------------------
420 -- To minimise line noise we adopt the convention that if the literal
421 -- has the natural machine word size, we do not append the type
423 pprLit :: CmmLit -> SDoc
424 pprLit lit = case lit of
426 hcat [ (if i < 0 then parens else id)(integer i)
429 else space <> dcolon <+> ppr rep) ]
431 CmmFloat f rep -> hsep [ rational f, dcolon, ppr rep ]
432 CmmLabel clbl -> pprCLabel clbl
433 CmmLabelOff clbl i -> pprCLabel clbl <> ppr_offset i
434 CmmLabelDiffOff clbl1 clbl2 i -> pprCLabel clbl1 <> char '-'
435 <> pprCLabel clbl2 <> ppr_offset i
437 pprLit1 lit@(CmmLabelOff clbl i) = parens (pprLit lit)
438 pprLit1 lit = pprLit lit
440 ppr_offset :: Int -> SDoc
443 | i>=0 = char '+' <> int i
444 | otherwise = char '-' <> int (-i)
446 -- --------------------------------------------------------------------------
448 -- Strings are printed as C strings, and we print them as I8[],
451 pprStatic :: CmmStatic -> SDoc
452 pprStatic s = case s of
453 CmmStaticLit lit -> nest 4 $ ptext SLIT("const") <+> pprLit lit <> semi
454 CmmUninitialised i -> nest 4 $ text "I8" <> brackets (int i)
455 CmmAlign i -> nest 4 $ text "align" <+> int i
456 CmmDataLabel clbl -> pprCLabel clbl <> colon
457 CmmString s' -> nest 4 $ text "I8[]" <+> text (show s')
459 -- --------------------------------------------------------------------------
460 -- Registers, whether local (temps) or global
462 pprReg :: CmmReg -> SDoc
465 CmmLocal local -> pprLocalReg local
466 CmmGlobal global -> pprGlobalReg global
469 -- We only print the type of the local reg if it isn't wordRep
471 pprLocalReg :: LocalReg -> SDoc
472 pprLocalReg (LocalReg uniq rep follow)
473 = hcat [ char '_', ppr uniq, ty ] where
474 ty = if rep == wordRep && follow == KindNonPtr
476 else dcolon <> ptr <> ppr rep
477 ptr = if follow == KindNonPtr
479 else doubleQuotes (text "ptr")
481 -- needs to be kept in syn with Cmm.hs.GlobalReg
483 pprGlobalReg :: GlobalReg -> SDoc
486 VanillaReg n -> char 'R' <> int n
487 FloatReg n -> char 'F' <> int n
488 DoubleReg n -> char 'D' <> int n
489 LongReg n -> char 'L' <> int n
490 Sp -> ptext SLIT("Sp")
491 SpLim -> ptext SLIT("SpLim")
492 Hp -> ptext SLIT("Hp")
493 HpLim -> ptext SLIT("HpLim")
494 CurrentTSO -> ptext SLIT("CurrentTSO")
495 CurrentNursery -> ptext SLIT("CurrentNursery")
496 HpAlloc -> ptext SLIT("HpAlloc")
497 GCEnter1 -> ptext SLIT("stg_gc_enter_1")
498 GCFun -> ptext SLIT("stg_gc_fun")
499 BaseReg -> ptext SLIT("BaseReg")
500 PicBaseReg -> ptext SLIT("PicBaseReg")
502 -- --------------------------------------------------------------------------
505 pprSection :: Section -> SDoc
506 pprSection s = case s of
507 Text -> section <+> doubleQuotes (ptext SLIT("text"))
508 Data -> section <+> doubleQuotes (ptext SLIT("data"))
509 ReadOnlyData -> section <+> doubleQuotes (ptext SLIT("readonly"))
510 RelocatableReadOnlyData
511 -> section <+> doubleQuotes (ptext SLIT("relreadonly"))
512 UninitialisedData -> section <+> doubleQuotes (ptext SLIT("uninitialised"))
513 OtherSection s' -> section <+> doubleQuotes (text s')
515 section = ptext SLIT("section")
517 -- --------------------------------------------------------------------------
520 pprBlockId :: BlockId -> SDoc
521 pprBlockId b = ppr $ getUnique b
523 -----------------------------------------------------------------------------
525 commafy :: [SDoc] -> SDoc
526 commafy xs = hsep $ punctuate comma xs