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 :: [Cmm] -> 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 Cmm where
68 instance Outputable CmmTop 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 -----------------------------------------------------------------------------
92 pprCmm (Cmm tops) = vcat $ intersperse (text "") $ map pprTop tops
94 -- --------------------------------------------------------------------------
95 -- Top level `procedure' blocks. The info tables, if not null, are
96 -- printed in the style of C--'s 'stackdata' declaration, just inside
97 -- the proc body, and are labelled with the procedure name ++ "_info".
99 pprTop :: CmmTop -> SDoc
100 pprTop (CmmProc info lbl params blocks )
102 = vcat [ pprCLabel lbl <> parens (commafy $ map ppr params) <+> lbrace
103 , nest 8 $ pprInfo info lbl
104 , nest 4 $ vcat (map ppr blocks)
110 (hang (pprCLabel (entryLblToInfoLbl label) <+> lbrace )
111 4 $ vcat (map pprStatic i))
114 -- --------------------------------------------------------------------------
115 -- We follow [1], 4.5
117 -- section "data" { ... }
119 pprTop (CmmData section ds) =
120 (hang (pprSection section <+> lbrace) 4 (vcat (map pprStatic ds)))
124 -- --------------------------------------------------------------------------
125 -- Basic blocks look like assembly blocks.
126 -- lbl: stmt ; stmt ; ..
127 pprBBlock :: CmmBasicBlock -> SDoc
128 pprBBlock (BasicBlock ident stmts) =
129 hang (pprBlockId ident <> colon) 4 (vcat (map ppr stmts))
131 -- --------------------------------------------------------------------------
132 -- Statements. C-- usually, exceptions to this should be obvious.
134 pprStmt :: CmmStmt -> SDoc
135 pprStmt stmt = case stmt of
141 CmmComment s -> text "//" <+> ftext s
144 CmmAssign reg expr -> ppr reg <+> equals <+> ppr expr <> semi
147 CmmStore lv expr -> rep <> brackets(ppr lv) <+> equals <+> ppr expr <> semi
149 rep = ppr ( cmmExprRep expr )
151 -- call "ccall" foo(x, y)[r1, r2];
153 CmmCall (CmmForeignCall fn cconv) results args srt ->
154 hcat [ ptext SLIT("call"), space,
155 doubleQuotes(ppr cconv), space,
156 target fn, parens ( commafy $ map ppr args ),
159 else brackets( commafy $ map ppr results)),
160 brackets (ppr srt), semi ]
162 target (CmmLit lit) = pprLit lit
163 target fn' = parens (ppr fn')
165 CmmCall (CmmPrim op) results args srt ->
166 pprStmt (CmmCall (CmmForeignCall (CmmLit lbl) CCallConv)
169 lbl = CmmLabel (mkForeignLabel (mkFastString (show op)) Nothing False)
171 CmmBranch ident -> genBranch ident
172 CmmCondBranch expr ident -> genCondBranch expr ident
173 CmmJump expr params -> genJump expr params
174 CmmReturn params -> genReturn params
175 CmmSwitch arg ids -> genSwitch arg ids
177 -- --------------------------------------------------------------------------
178 -- goto local label. [1], section 6.6
182 genBranch :: BlockId -> SDoc
184 ptext SLIT("goto") <+> pprBlockId ident <> semi
186 -- --------------------------------------------------------------------------
187 -- Conditional. [1], section 6.4
189 -- if (expr) { goto lbl; }
191 genCondBranch :: CmmExpr -> BlockId -> SDoc
192 genCondBranch expr ident =
193 hsep [ ptext SLIT("if")
196 , pprBlockId ident <> semi ]
198 -- --------------------------------------------------------------------------
199 -- A tail call. [1], Section 6.9
201 -- jump foo(a, b, c);
203 genJump :: CmmExpr -> [(CmmExpr, MachHint)] -> SDoc
206 hcat [ ptext SLIT("jump")
208 , if isTrivialCmmExpr expr
211 CmmLoad (CmmReg _) _ -> pprExpr expr
212 _ -> parens (pprExpr expr)
214 , parens ( commafy $ map ppr args )
217 -- --------------------------------------------------------------------------
218 -- Return from a function. [1], Section 6.8.2 of version 1.128
222 genReturn :: [(CmmExpr, MachHint)] -> SDoc
225 hcat [ ptext SLIT("return")
227 , parens ( commafy $ map ppr args )
230 -- --------------------------------------------------------------------------
231 -- Tabled jump to local label
233 -- The syntax is from [1], section 6.5
235 -- switch [0 .. n] (expr) { case ... ; }
237 genSwitch :: CmmExpr -> [Maybe BlockId] -> SDoc
238 genSwitch expr maybe_ids
240 = let pairs = groupBy snds (zip [0 .. ] maybe_ids )
242 in hang (hcat [ ptext SLIT("switch [0 .. ")
243 , int (length maybe_ids - 1)
245 , if isTrivialCmmExpr expr
247 else parens (pprExpr expr)
250 4 (vcat ( map caseify pairs )) $$ rbrace
253 snds a b = (snd a) == (snd b)
255 caseify :: [(Int,Maybe BlockId)] -> SDoc
256 caseify ixs@((i,Nothing):_)
257 = ptext SLIT("/* impossible: ") <> hcat (intersperse comma (map (int.fst) ixs))
260 = let (is,ids) = unzip as
261 in hsep [ ptext SLIT("case")
262 , hcat (punctuate comma (map int is))
263 , ptext SLIT(": goto")
264 , pprBlockId (head [ id | Just id <- ids]) <> semi ]
266 -- --------------------------------------------------------------------------
270 pprExpr :: CmmExpr -> SDoc
274 pprExpr (CmmMachOp (MO_Add rep)
275 [CmmReg reg, CmmLit (CmmInt (fromIntegral i) rep)])
276 where rep = cmmRegRep reg
277 CmmLit lit -> pprLit lit
280 -- Here's the precedence table from CmmParse.y:
281 -- %nonassoc '>=' '>' '<=' '<' '!=' '=='
290 -- We just cope with the common operators for now, the rest will get
291 -- a default conservative behaviour.
293 -- %nonassoc '>=' '>' '<=' '<' '!=' '=='
294 pprExpr1 (CmmMachOp op [x,y]) | Just doc <- infixMachOp1 op
295 = pprExpr7 x <+> doc <+> pprExpr7 y
296 pprExpr1 e = pprExpr7 e
298 infixMachOp1 (MO_Eq _) = Just (ptext SLIT("=="))
299 infixMachOp1 (MO_Ne _) = Just (ptext SLIT("!="))
300 infixMachOp1 (MO_Shl _) = Just (ptext SLIT("<<"))
301 infixMachOp1 (MO_U_Shr _) = Just (ptext SLIT(">>"))
302 infixMachOp1 (MO_U_Ge _) = Just (ptext SLIT(">="))
303 infixMachOp1 (MO_U_Le _) = Just (ptext SLIT("<="))
304 infixMachOp1 (MO_U_Gt _) = Just (char '>')
305 infixMachOp1 (MO_U_Lt _) = Just (char '<')
306 infixMachOp1 _ = Nothing
309 pprExpr7 (CmmMachOp (MO_Add rep1) [x, CmmLit (CmmInt i rep2)]) | i < 0
310 = pprExpr7 (CmmMachOp (MO_Sub rep1) [x, CmmLit (CmmInt (negate i) rep2)])
311 pprExpr7 (CmmMachOp op [x,y]) | Just doc <- infixMachOp7 op
312 = pprExpr7 x <+> doc <+> pprExpr8 y
313 pprExpr7 e = pprExpr8 e
315 infixMachOp7 (MO_Add _) = Just (char '+')
316 infixMachOp7 (MO_Sub _) = Just (char '-')
317 infixMachOp7 _ = Nothing
320 pprExpr8 (CmmMachOp op [x,y]) | Just doc <- infixMachOp8 op
321 = pprExpr8 x <+> doc <+> pprExpr9 y
322 pprExpr8 e = pprExpr9 e
324 infixMachOp8 (MO_U_Quot _) = Just (char '/')
325 infixMachOp8 (MO_Mul _) = Just (char '*')
326 infixMachOp8 (MO_U_Rem _) = Just (char '%')
327 infixMachOp8 _ = Nothing
329 pprExpr9 :: CmmExpr -> SDoc
332 CmmLit lit -> pprLit1 lit
333 CmmLoad expr rep -> ppr rep <> brackets( ppr expr )
334 CmmReg reg -> ppr reg
335 CmmRegOff reg off -> parens (ppr reg <+> char '+' <+> int off)
336 CmmMachOp mop args -> genMachOp mop args
338 genMachOp :: MachOp -> [CmmExpr] -> SDoc
340 | Just doc <- infixMachOp mop = case args of
342 [x,y] -> pprExpr9 x <+> doc <+> pprExpr9 y
345 [x] -> doc <> pprExpr9 x
347 _ -> pprTrace "PprCmm.genMachOp: machop with strange number of args"
349 parens (hcat $ punctuate comma (map pprExpr args)))
352 | isJust (infixMachOp1 mop)
353 || isJust (infixMachOp7 mop)
354 || isJust (infixMachOp8 mop) = parens (pprExpr (CmmMachOp mop args))
356 | otherwise = char '%' <> ppr_op <> parens (commafy (map pprExpr args))
357 where ppr_op = text (map (\c -> if c == ' ' then '_' else c)
359 -- replace spaces in (show mop) with underscores,
362 -- Unsigned ops on the word size of the machine get nice symbols.
363 -- All else get dumped in their ugly format.
365 infixMachOp :: MachOp -> Maybe SDoc
368 MO_And _ -> Just $ char '&'
369 MO_Or _ -> Just $ char '|'
370 MO_Xor _ -> Just $ char '^'
371 MO_Not _ -> Just $ char '~'
372 MO_S_Neg _ -> Just $ char '-' -- there is no unsigned neg :)
375 -- --------------------------------------------------------------------------
377 -- To minimise line noise we adopt the convention that if the literal
378 -- has the natural machine word size, we do not append the type
380 pprLit :: CmmLit -> SDoc
381 pprLit lit = case lit of
383 hcat [ (if i < 0 then parens else id)(integer i)
386 else space <> dcolon <+> ppr rep) ]
388 CmmFloat f rep -> hsep [ rational f, dcolon, ppr rep ]
389 CmmLabel clbl -> pprCLabel clbl
390 CmmLabelOff clbl i -> pprCLabel clbl <> ppr_offset i
391 CmmLabelDiffOff clbl1 clbl2 i -> pprCLabel clbl1 <> char '-'
392 <> pprCLabel clbl2 <> ppr_offset i
394 pprLit1 lit@(CmmLabelOff clbl i) = parens (pprLit lit)
395 pprLit1 lit = pprLit lit
397 ppr_offset :: Int -> SDoc
400 | i>=0 = char '+' <> int i
401 | otherwise = char '-' <> int (-i)
403 -- --------------------------------------------------------------------------
405 -- Strings are printed as C strings, and we print them as I8[],
408 pprStatic :: CmmStatic -> SDoc
409 pprStatic s = case s of
410 CmmStaticLit lit -> nest 4 $ ptext SLIT("const") <+> pprLit lit <> semi
411 CmmUninitialised i -> nest 4 $ text "I8" <> brackets (int i)
412 CmmAlign i -> nest 4 $ text "align" <+> int i
413 CmmDataLabel clbl -> pprCLabel clbl <> colon
414 CmmString s' -> nest 4 $ text "I8[]" <+> text (show s')
416 -- --------------------------------------------------------------------------
417 -- Registers, whether local (temps) or global
419 pprReg :: CmmReg -> SDoc
422 CmmLocal local -> pprLocalReg local
423 CmmGlobal global -> pprGlobalReg global
426 -- We only print the type of the local reg if it isn't wordRep
428 pprLocalReg :: LocalReg -> SDoc
429 pprLocalReg (LocalReg uniq rep follow)
430 = hcat [ char '_', ppr uniq, ty ] where
431 ty = if rep == wordRep && follow == KindNonPtr
433 else dcolon <> ptr <> ppr rep
434 ptr = if follow == KindNonPtr
436 else doubleQuotes (text "ptr")
438 -- needs to be kept in syn with Cmm.hs.GlobalReg
440 pprGlobalReg :: GlobalReg -> SDoc
443 VanillaReg n -> char 'R' <> int n
444 FloatReg n -> char 'F' <> int n
445 DoubleReg n -> char 'D' <> int n
446 LongReg n -> char 'L' <> int n
447 Sp -> ptext SLIT("Sp")
448 SpLim -> ptext SLIT("SpLim")
449 Hp -> ptext SLIT("Hp")
450 HpLim -> ptext SLIT("HpLim")
451 CurrentTSO -> ptext SLIT("CurrentTSO")
452 CurrentNursery -> ptext SLIT("CurrentNursery")
453 HpAlloc -> ptext SLIT("HpAlloc")
454 GCEnter1 -> ptext SLIT("stg_gc_enter_1")
455 GCFun -> ptext SLIT("stg_gc_fun")
456 BaseReg -> ptext SLIT("BaseReg")
457 PicBaseReg -> ptext SLIT("PicBaseReg")
459 -- --------------------------------------------------------------------------
462 pprSection :: Section -> SDoc
463 pprSection s = case s of
464 Text -> section <+> doubleQuotes (ptext SLIT("text"))
465 Data -> section <+> doubleQuotes (ptext SLIT("data"))
466 ReadOnlyData -> section <+> doubleQuotes (ptext SLIT("readonly"))
467 RelocatableReadOnlyData
468 -> section <+> doubleQuotes (ptext SLIT("relreadonly"))
469 UninitialisedData -> section <+> doubleQuotes (ptext SLIT("uninitialised"))
470 OtherSection s' -> section <+> doubleQuotes (text s')
472 section = ptext SLIT("section")
474 -- --------------------------------------------------------------------------
477 pprBlockId :: BlockId -> SDoc
478 pprBlockId b = ppr $ getUnique b
480 -----------------------------------------------------------------------------
482 commafy :: [SDoc] -> SDoc
483 commafy xs = hsep $ punctuate comma xs