3c3e9764a496f6b0e79c878ee2345441ddc439fa
[ghc-hetmet.git] / ghc / compiler / cmm / PprCmm.hs
1 ----------------------------------------------------------------------------
2 --
3 -- Pretty-printing of Cmm as (a superset of) C--
4 --
5 -- (c) The University of Glasgow 2004
6 --
7 -----------------------------------------------------------------------------
8
9 --
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.
13 --
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.
19 --
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
24 -- cases:
25 --      1) if a value has wordRep type, the type is not appended in the
26 --      output.
27 --      2) MachOps that operate over wordRep type are printed in a
28 --      C-style, rather than as their internal MachRep name.
29 --
30 -- These conventions produce much more readable Cmm output.
31 --
32 -- A useful example pass over Cmm is in nativeGen/MachCodeGen.hs
33 --
34
35 module PprCmm (         
36         writeCmms, pprCmms, pprCmm, pprStmt, pprExpr
37   ) where
38
39 #include "HsVersions.h"
40
41 import Cmm
42 import CmmUtils     ( isTrivialCmmExpr )
43 import MachOp       ( MachOp(..), pprMachOp, MachRep(..), wordRep )
44 import CLabel       ( pprCLabel, mkForeignLabel, entryLblToInfoLbl )
45
46 import ForeignCall  ( CCallConv(..) )
47 import Unique       ( getUnique )
48 import Outputable
49 import FastString   ( mkFastString )
50
51 import Data.List    ( intersperse, groupBy )
52 import IO           ( Handle )
53 import Maybe        ( isJust )
54
55 pprCmms :: [Cmm] -> SDoc
56 pprCmms cmms = pprCode CStyle (vcat (intersperse separator $ map ppr cmms))
57         where
58           separator = space $$ ptext SLIT("-------------------") $$ space
59
60 writeCmms :: Handle -> [Cmm] -> IO ()
61 writeCmms handle cmms = printForC handle (pprCmms cmms)
62
63 -----------------------------------------------------------------------------
64
65 instance Outputable Cmm where
66     ppr c = pprCmm c
67
68 instance Outputable CmmTop where
69     ppr t = pprTop t
70
71 instance Outputable CmmBasicBlock where
72     ppr b = pprBBlock b
73
74 instance Outputable CmmStmt where
75     ppr s = pprStmt s
76
77 instance Outputable CmmExpr where
78     ppr e = pprExpr e
79
80 instance Outputable CmmReg where
81     ppr e = pprReg e
82
83 instance Outputable GlobalReg where
84     ppr e = pprGlobalReg e
85
86 -----------------------------------------------------------------------------
87
88 pprCmm :: Cmm -> SDoc
89 pprCmm (Cmm tops) = vcat $ intersperse (text "") $ map pprTop tops
90
91 -- --------------------------------------------------------------------------
92 -- Top level `procedure' blocks. The info tables, if not null, are
93 -- printed in the style of C--'s 'stackdata' declaration, just inside
94 -- the proc body, and are labelled with the procedure name ++ "_info".
95 --
96 pprTop :: CmmTop -> SDoc
97 pprTop (CmmProc info lbl params blocks )
98
99   = vcat [ pprCLabel lbl <> parens (commafy $ map pprLocalReg params) <+> lbrace
100          , nest 8 $ pprInfo info lbl
101          , nest 4 $ vcat (map ppr blocks)
102          , rbrace ]
103
104   where
105     pprInfo [] _  = empty
106     pprInfo i label = 
107         (hang (pprCLabel (entryLblToInfoLbl label) <+> lbrace )
108             4 $ vcat (map pprStatic i))
109         $$ rbrace
110
111 -- --------------------------------------------------------------------------
112 -- We follow [1], 4.5
113 --
114 --      section "data" { ... }
115 --
116 pprTop (CmmData section ds) = 
117     (hang (pprSection section <+> lbrace) 4 (vcat (map pprStatic ds)))
118     $$ rbrace
119
120
121 -- --------------------------------------------------------------------------
122 -- Basic blocks look like assembly blocks.
123 --      lbl: stmt ; stmt ; .. 
124 pprBBlock :: CmmBasicBlock -> SDoc
125 pprBBlock (BasicBlock ident stmts) =
126     hang (pprBlockId ident <> colon) 4 (vcat (map ppr stmts))
127
128 -- --------------------------------------------------------------------------
129 -- Statements. C-- usually, exceptions to this should be obvious.
130 --
131 pprStmt :: CmmStmt -> SDoc    
132 pprStmt stmt = case stmt of
133
134     -- ;
135     CmmNop -> semi
136
137     --  // text
138     CmmComment s -> text "//" <+> ftext s
139
140     -- reg = expr;
141     CmmAssign reg expr -> ppr reg <+> equals <+> ppr expr <> semi
142
143     -- rep[lv] = expr;
144     CmmStore lv expr -> rep <> brackets(ppr lv) <+> equals <+> ppr expr <> semi
145         where
146           rep = ppr ( cmmExprRep expr )
147
148     -- call "ccall" foo(x, y)[r1, r2];
149     -- ToDo ppr volatile
150     CmmCall (CmmForeignCall fn cconv) results args _volatile ->
151         hcat [ ptext SLIT("call"), space, 
152                doubleQuotes(ppr cconv), space,
153                target fn, parens  ( commafy $ map ppr args ),
154                (if null results
155                     then empty
156                     else brackets( commafy $ map ppr results)), semi ]
157         where
158             target (CmmLit lit) = pprLit lit
159             target fn'          = parens (ppr fn')
160
161     CmmCall (CmmPrim op) results args volatile ->
162         pprStmt (CmmCall (CmmForeignCall (CmmLit lbl) CCallConv)
163                         results args volatile)
164         where
165           lbl = CmmLabel (mkForeignLabel (mkFastString (show op)) Nothing False)
166
167     CmmBranch ident          -> genBranch ident
168     CmmCondBranch expr ident -> genCondBranch expr ident
169     CmmJump expr params      -> genJump expr params
170     CmmSwitch arg ids        -> genSwitch arg ids
171
172 -- --------------------------------------------------------------------------
173 -- goto local label. [1], section 6.6
174 --
175 --     goto lbl;
176 --
177 genBranch :: BlockId -> SDoc
178 genBranch ident = 
179     ptext SLIT("goto") <+> pprBlockId ident <> semi
180
181 -- --------------------------------------------------------------------------
182 -- Conditional. [1], section 6.4
183 --
184 --     if (expr) { goto lbl; } 
185 --
186 genCondBranch :: CmmExpr -> BlockId -> SDoc
187 genCondBranch expr ident =
188     hsep [ ptext SLIT("if")
189          , parens(ppr expr)
190          , ptext SLIT("goto")
191          , pprBlockId ident <> semi ]
192
193 -- --------------------------------------------------------------------------
194 -- A tail call. [1], Section 6.9
195 --
196 --     jump foo(a, b, c);
197 --
198 genJump :: CmmExpr -> [LocalReg] -> SDoc
199 genJump expr actuals = 
200
201     hcat [ ptext SLIT("jump")
202          , space
203          , if isTrivialCmmExpr expr
204                 then pprExpr expr
205                 else case expr of
206                     CmmLoad (CmmReg _) _ -> pprExpr expr 
207                     _ -> parens (pprExpr expr)
208          , pprActuals actuals
209          , semi ]
210
211   where
212     pprActuals [] = empty
213     pprActuals as = parens ( commafy $ map pprLocalReg as ) 
214
215 -- --------------------------------------------------------------------------
216 -- Tabled jump to local label
217 --
218 -- The syntax is from [1], section 6.5
219 --
220 --      switch [0 .. n] (expr) { case ... ; }
221 --
222 genSwitch :: CmmExpr -> [Maybe BlockId] -> SDoc
223 genSwitch expr maybe_ids 
224
225     = let pairs = groupBy snds (zip [0 .. ] maybe_ids )
226
227       in hang (hcat [ ptext SLIT("switch [0 .. ") 
228                     , int (length maybe_ids - 1)
229                     , ptext SLIT("] ")
230                     , if isTrivialCmmExpr expr
231                         then pprExpr expr
232                         else parens (pprExpr expr)
233                     , ptext SLIT(" {") 
234                     ]) 
235             4 (vcat ( map caseify pairs )) $$ rbrace
236
237     where
238       snds a b = (snd a) == (snd b)
239
240       caseify :: [(Int,Maybe BlockId)] -> SDoc
241       caseify ixs@((i,Nothing):_)
242         = ptext SLIT("/* impossible: ") <> hcat (intersperse comma (map (int.fst) ixs))
243                 <> ptext SLIT(" */")
244       caseify as 
245         = let (is,ids) = unzip as 
246           in hsep [ ptext SLIT("case")
247                   , hcat (punctuate comma (map int is))
248                   , ptext SLIT(": goto")
249                   , pprBlockId (head [ id | Just id <- ids]) <> semi ]
250
251 -- --------------------------------------------------------------------------
252 -- Expressions
253 --
254
255 pprExpr :: CmmExpr -> SDoc
256 pprExpr e 
257     = case e of
258         CmmRegOff reg i -> 
259                 pprExpr (CmmMachOp (MO_Add rep)
260                            [CmmReg reg, CmmLit (CmmInt (fromIntegral i) rep)])
261                 where rep = cmmRegRep reg       
262         CmmLit lit -> pprLit lit
263         _other     -> pprExpr1 e
264
265 -- Here's the precedence table from CmmParse.y:
266 -- %nonassoc '>=' '>' '<=' '<' '!=' '=='
267 -- %left '|'
268 -- %left '^'
269 -- %left '&'
270 -- %left '>>' '<<'
271 -- %left '-' '+'
272 -- %left '/' '*' '%'
273 -- %right '~'
274
275 -- We just cope with the common operators for now, the rest will get
276 -- a default conservative behaviour.
277
278 -- %nonassoc '>=' '>' '<=' '<' '!=' '=='
279 pprExpr1 (CmmMachOp op [x,y]) | Just doc <- infixMachOp1 op
280    = pprExpr7 x <+> doc <+> pprExpr7 y
281 pprExpr1 e = pprExpr7 e
282
283 infixMachOp1 (MO_Eq     _) = Just (ptext SLIT("=="))
284 infixMachOp1 (MO_Ne     _) = Just (ptext SLIT("!="))
285 infixMachOp1 (MO_Shl    _) = Just (ptext SLIT("<<"))
286 infixMachOp1 (MO_U_Shr  _) = Just (ptext SLIT(">>"))
287 infixMachOp1 (MO_U_Ge   _) = Just (ptext SLIT(">="))
288 infixMachOp1 (MO_U_Le   _) = Just (ptext SLIT("<="))
289 infixMachOp1 (MO_U_Gt   _) = Just (char '>')
290 infixMachOp1 (MO_U_Lt   _) = Just (char '<')
291 infixMachOp1 _             = Nothing
292
293 -- %left '-' '+'
294 pprExpr7 (CmmMachOp op [x,y]) | Just doc <- infixMachOp7 op
295    = pprExpr7 x <+> doc <+> pprExpr8 y
296 pprExpr7 e = pprExpr8 e
297
298 infixMachOp7 (MO_Add _)  = Just (char '+')
299 infixMachOp7 (MO_Sub _)  = Just (char '-')
300 infixMachOp7 _           = Nothing
301
302 -- %left '/' '*' '%'
303 pprExpr8 (CmmMachOp op [x,y]) | Just doc <- infixMachOp8 op
304    = pprExpr8 x <+> doc <+> pprExpr9 y
305 pprExpr8 e = pprExpr9 e
306
307 infixMachOp8 (MO_U_Quot _) = Just (char '/')
308 infixMachOp8 (MO_Mul _)    = Just (char '*')
309 infixMachOp8 (MO_U_Rem _)  = Just (char '%')
310 infixMachOp8 _             = Nothing
311
312 pprExpr9 :: CmmExpr -> SDoc
313 pprExpr9 e = 
314    case e of
315         CmmLit    lit       -> pprLit1 lit
316         CmmLoad   expr rep  -> ppr rep <> brackets( ppr expr )
317         CmmReg    reg       -> ppr reg
318         CmmRegOff reg off   -> parens (ppr reg <+> char '+' <+> int off)
319         CmmMachOp mop args  -> genMachOp mop args
320
321 genMachOp :: MachOp -> [CmmExpr] -> SDoc
322 genMachOp mop args
323    | Just doc <- infixMachOp mop = case args of
324         -- dyadic
325         [x,y] -> pprExpr9 x <+> doc <+> pprExpr9 y
326
327         -- unary
328         [x]   -> doc <> pprExpr9 x
329
330         _     -> pprTrace "PprCmm.genMachOp: machop with strange number of args"
331                           (pprMachOp mop <+>
332                             parens (hcat $ punctuate comma (map pprExpr args)))
333                           empty
334
335    | isJust (infixMachOp1 mop)
336    || isJust (infixMachOp7 mop)
337    || isJust (infixMachOp8 mop)  = parens (pprExpr (CmmMachOp mop args))
338
339    | otherwise = char '%' <> pprMachOp mop <> parens (commafy (map pprExpr args))
340
341 --
342 -- Unsigned ops on the word size of the machine get nice symbols.
343 -- All else get dumped in their ugly format.
344 --
345 infixMachOp :: MachOp -> Maybe SDoc
346 infixMachOp mop
347         = case mop of
348             MO_And    _ -> Just $ char '&'
349             MO_Or     _ -> Just $ char '|'
350             MO_Xor    _ -> Just $ char '^'
351             MO_Not    _ -> Just $ char '~'
352             MO_S_Neg  _ -> Just $ char '-' -- there is no unsigned neg :)
353             _ -> Nothing
354
355 -- --------------------------------------------------------------------------
356 -- Literals.
357 --  To minimise line noise we adopt the convention that if the literal
358 --  has the natural machine word size, we do not append the type
359 --
360 pprLit :: CmmLit -> SDoc
361 pprLit lit = case lit of
362     CmmInt i rep ->
363         hcat [ (if i < 0 then parens else id)(integer i)
364              , (if rep == wordRep 
365                     then empty 
366                     else space <> dcolon <+> ppr rep) ]
367
368     CmmFloat f rep     -> hsep [ rational f, dcolon, ppr rep ]
369     CmmLabel clbl      -> pprCLabel clbl
370     CmmLabelOff clbl i -> pprCLabel clbl <> ppr_offset i
371     CmmLabelDiffOff clbl1 clbl2 i -> pprCLabel clbl1 <> char '-'  
372                                   <> pprCLabel clbl2 <> ppr_offset i
373
374 pprLit1 lit@(CmmLabelOff clbl i) = parens (pprLit lit)
375 pprLit1 lit                      = pprLit lit
376
377 ppr_offset :: Int -> SDoc
378 ppr_offset i
379     | i==0      = empty
380     | i>=0      = char '+' <> int i
381     | otherwise = char '-' <> int (-i)
382
383 -- --------------------------------------------------------------------------
384 -- Static data.
385 --      Strings are printed as C strings, and we print them as I8[],
386 --      following C--
387 --
388 pprStatic :: CmmStatic -> SDoc
389 pprStatic s = case s of
390     CmmStaticLit lit   -> nest 4 $ ptext SLIT("const") <+> pprLit lit <> semi
391     CmmUninitialised i -> nest 4 $ text "I8" <> brackets (int i)
392     CmmAlign i         -> nest 4 $ text "align" <+> int i
393     CmmDataLabel clbl  -> pprCLabel clbl <> colon
394     CmmString s'       -> nest 4 $ text "I8[]" <+> doubleQuotes (text s')
395
396 -- --------------------------------------------------------------------------
397 -- Registers, whether local (temps) or global
398 --
399 pprReg :: CmmReg -> SDoc
400 pprReg r 
401     = case r of
402         CmmLocal  local  -> pprLocalReg local
403         CmmGlobal global -> pprGlobalReg global
404
405 --
406 -- We only print the type of the local reg if it isn't wordRep
407 --
408 pprLocalReg :: LocalReg -> SDoc
409 pprLocalReg (LocalReg uniq rep) 
410     = hcat [ char '_', ppr uniq, 
411             (if rep == wordRep 
412                 then empty else dcolon <> ppr rep) ]
413
414 -- needs to be kept in syn with Cmm.hs.GlobalReg
415 --
416 pprGlobalReg :: GlobalReg -> SDoc
417 pprGlobalReg gr 
418     = case gr of
419         VanillaReg n   -> char 'R' <> int n
420         FloatReg   n   -> char 'F' <> int n
421         DoubleReg  n   -> char 'D' <> int n
422         LongReg    n   -> char 'L' <> int n
423         Sp             -> ptext SLIT("Sp")
424         SpLim          -> ptext SLIT("SpLim")
425         Hp             -> ptext SLIT("Hp")
426         HpLim          -> ptext SLIT("HpLim")
427         CurrentTSO     -> ptext SLIT("CurrentTSO")
428         CurrentNursery -> ptext SLIT("CurrentNursery")
429         HpAlloc        -> ptext SLIT("HpAlloc")
430         GCEnter1       -> ptext SLIT("stg_gc_enter_1")
431         GCFun          -> ptext SLIT("stg_gc_fun")
432         BaseReg        -> ptext SLIT("BaseReg")
433         PicBaseReg     -> ptext SLIT("PicBaseReg")
434
435 -- --------------------------------------------------------------------------
436 -- data sections
437 --
438 pprSection :: Section -> SDoc
439 pprSection s = case s of
440     Text              -> section <+> doubleQuotes (ptext SLIT("text"))
441     Data              -> section <+> doubleQuotes (ptext SLIT("data"))
442     ReadOnlyData      -> section <+> doubleQuotes (ptext SLIT("readonly"))
443     RelocatableReadOnlyData
444                       -> section <+> doubleQuotes (ptext SLIT("relreadonly"))
445     UninitialisedData -> section <+> doubleQuotes (ptext SLIT("uninitialised"))
446     OtherSection s'   -> section <+> doubleQuotes (text s')
447  where
448     section = ptext SLIT("section")
449        
450 -- --------------------------------------------------------------------------
451 -- Basic block ids
452 --
453 pprBlockId :: BlockId -> SDoc
454 pprBlockId b = ppr $ getUnique b
455
456 -----------------------------------------------------------------------------
457
458 commafy :: [SDoc] -> SDoc
459 commafy xs = hsep $ punctuate comma xs
460