Add graph coloring register allocator.
[ghc-hetmet.git] / compiler / cmm / PprCmm.hs
1 ----------------------------------------------------------------------------
2 --
3 -- Pretty-printing of Cmm as (a superset of) C--
4 --
5 -- (c) The University of Glasgow 2004-2006
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, pprSection, pprStatic
37   ) where
38
39 #include "HsVersions.h"
40
41 import Cmm
42 import CmmUtils
43 import MachOp
44 import CLabel
45
46 import ForeignCall
47 import Unique
48 import Outputable
49 import FastString
50
51 import Data.List
52 import System.IO
53 import Data.Maybe
54
55 pprCmms :: (Outputable info) => [GenCmm CmmStatic info CmmStmt] -> 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 info) => Outputable (GenCmm CmmStatic info CmmStmt) where
66     ppr c = pprCmm c
67
68 instance (Outputable d, Outputable info, Outputable i)
69         => Outputable (GenCmmTop d info i) where
70     ppr t = pprTop t
71
72 instance (Outputable instr) => Outputable (GenBasicBlock instr) where
73     ppr b = pprBBlock b
74
75 instance Outputable BlockId where
76     ppr id = pprBlockId id
77
78 instance Outputable CmmStmt where
79     ppr s = pprStmt s
80
81 instance Outputable CmmExpr where
82     ppr e = pprExpr e
83
84 instance Outputable CmmReg where
85     ppr e = pprReg e
86
87 instance Outputable LocalReg where
88     ppr e = pprLocalReg e
89
90 instance Outputable GlobalReg where
91     ppr e = pprGlobalReg e
92
93 instance Outputable CmmStatic where
94     ppr e = pprStatic e
95
96 instance Outputable CmmInfo where
97     ppr e = pprInfo e
98
99
100
101 -----------------------------------------------------------------------------
102
103 pprCmm :: (Outputable info) => GenCmm CmmStatic info CmmStmt -> SDoc
104 pprCmm (Cmm tops) = vcat $ intersperse (text "") $ map pprTop tops
105
106 -- --------------------------------------------------------------------------
107 -- Top level `procedure' blocks.
108 --
109 pprTop  :: (Outputable d, Outputable info, Outputable i)
110         => GenCmmTop d info i -> SDoc
111
112 pprTop (CmmProc info lbl params blocks )
113
114   = vcat [ pprCLabel lbl <> parens (commafy $ map ppr params) <+> lbrace
115          , nest 8 $ lbrace <+> ppr info $$ rbrace
116          , nest 4 $ vcat (map ppr blocks)
117          , rbrace ]
118
119 -- --------------------------------------------------------------------------
120 -- We follow [1], 4.5
121 --
122 --      section "data" { ... }
123 --
124 pprTop (CmmData section ds) = 
125     (hang (pprSection section <+> lbrace) 4 (vcat (map ppr ds)))
126     $$ rbrace
127
128 -- --------------------------------------------------------------------------
129 instance Outputable CmmSafety where
130   ppr CmmUnsafe = ptext SLIT("_unsafe_call_")
131   ppr (CmmSafe srt) = ppr srt
132
133 -- --------------------------------------------------------------------------
134 -- Info tables. The current pretty printer needs refinement
135 -- but will work for now.
136 --
137 -- For ideas on how to refine it, they used to be printed in the
138 -- style of C--'s 'stackdata' declaration, just inside the proc body,
139 -- and were labelled with the procedure name ++ "_info".
140 pprInfo (CmmInfo gc_target update_frame CmmNonInfoTable) =
141     vcat [{-ptext SLIT("gc_target: ") <>
142                 maybe (ptext SLIT("<none>")) pprBlockId gc_target,-}
143           ptext SLIT("update_frame: ") <>
144                 maybe (ptext SLIT("<none>")) pprUpdateFrame update_frame]
145 pprInfo (CmmInfo gc_target update_frame
146          (CmmInfoTable (ProfilingInfo closure_type closure_desc) tag info)) =
147     vcat [{-ptext SLIT("gc_target: ") <>
148                 maybe (ptext SLIT("<none>")) pprBlockId gc_target,-}
149           ptext SLIT("update_frame: ") <>
150                 maybe (ptext SLIT("<none>")) pprUpdateFrame update_frame,
151           ptext SLIT("type: ") <> pprLit closure_type,
152           ptext SLIT("desc: ") <> pprLit closure_desc,
153           ptext SLIT("tag: ") <> integer (toInteger tag),
154           pprTypeInfo info]
155
156 pprTypeInfo (ConstrInfo layout constr descr) =
157     vcat [ptext SLIT("ptrs: ") <> integer (toInteger (fst layout)),
158           ptext SLIT("nptrs: ") <> integer (toInteger (snd layout)),
159           ptext SLIT("constructor: ") <> integer (toInteger constr),
160           pprLit descr]
161 pprTypeInfo (FunInfo layout srt fun_type arity args slow_entry) =
162     vcat [ptext SLIT("ptrs: ") <> integer (toInteger (fst layout)),
163           ptext SLIT("nptrs: ") <> integer (toInteger (snd layout)),
164           ptext SLIT("srt: ") <> ppr srt,
165           ptext SLIT("fun_type: ") <> integer (toInteger fun_type),
166           ptext SLIT("arity: ") <> integer (toInteger arity),
167           --ptext SLIT("args: ") <> ppr args, -- TODO: needs to be printed
168           ptext SLIT("slow: ") <> pprLit slow_entry
169          ]
170 pprTypeInfo (ThunkInfo layout srt) =
171     vcat [ptext SLIT("ptrs: ") <> integer (toInteger (fst layout)),
172           ptext SLIT("nptrs: ") <> integer (toInteger (snd layout)),
173           ptext SLIT("srt: ") <> ppr srt]
174 pprTypeInfo (ThunkSelectorInfo offset srt) =
175     vcat [ptext SLIT("ptrs: ") <> integer (toInteger offset),
176           ptext SLIT("srt: ") <> ppr srt]
177 pprTypeInfo (ContInfo stack srt) =
178     vcat [ptext SLIT("stack: ") <> ppr stack,
179           ptext SLIT("srt: ") <> ppr srt]
180
181 pprUpdateFrame :: UpdateFrame -> SDoc
182 pprUpdateFrame (UpdateFrame expr args) = 
183     hcat [ ptext SLIT("jump")
184          , space
185          , if isTrivialCmmExpr expr
186                 then pprExpr expr
187                 else case expr of
188                     CmmLoad (CmmReg _) _ -> pprExpr expr 
189                     _ -> parens (pprExpr expr)
190          , space
191          , parens  ( commafy $ map ppr args ) ]
192
193
194 -- --------------------------------------------------------------------------
195 -- Basic blocks look like assembly blocks.
196 --      lbl: stmt ; stmt ; .. 
197 pprBBlock :: Outputable stmt => GenBasicBlock stmt -> SDoc
198 pprBBlock (BasicBlock ident stmts) =
199     hang (pprBlockId ident <> colon) 4 (vcat (map ppr stmts))
200
201 -- --------------------------------------------------------------------------
202 -- Statements. C-- usually, exceptions to this should be obvious.
203 --
204 pprStmt :: CmmStmt -> SDoc    
205 pprStmt stmt = case stmt of
206
207     -- ;
208     CmmNop -> semi
209
210     --  // text
211     CmmComment s -> text "//" <+> ftext s
212
213     -- reg = expr;
214     CmmAssign reg expr -> ppr reg <+> equals <+> ppr expr <> semi
215
216     -- rep[lv] = expr;
217     CmmStore lv expr -> rep <> brackets(ppr lv) <+> equals <+> ppr expr <> semi
218         where
219           rep = ppr ( cmmExprRep expr )
220
221     -- call "ccall" foo(x, y)[r1, r2];
222     -- ToDo ppr volatile
223     CmmCall (CmmCallee fn cconv) results args safety ret ->
224         hcat [ if null results
225                   then empty
226                   else parens (commafy $ map ppr results) <>
227                        ptext SLIT(" = "),
228                ptext SLIT("call"), space, 
229                doubleQuotes(ppr cconv), space,
230                target fn, parens  ( commafy $ map ppr args ),
231                brackets (ppr safety), 
232                case ret of CmmMayReturn -> empty
233                            CmmNeverReturns -> ptext SLIT(" never returns"),
234                semi ]
235         where
236             target (CmmLit lit) = pprLit lit
237             target fn'          = parens (ppr fn')
238
239     CmmCall (CmmPrim op) results args safety ret ->
240         pprStmt (CmmCall (CmmCallee (CmmLit lbl) CCallConv)
241                         results args safety ret)
242         where
243           lbl = CmmLabel (mkForeignLabel (mkFastString (show op)) Nothing False)
244
245     CmmBranch ident          -> genBranch ident
246     CmmCondBranch expr ident -> genCondBranch expr ident
247     CmmJump expr params      -> genJump expr params
248     CmmReturn params         -> genReturn params
249     CmmSwitch arg ids        -> genSwitch arg ids
250
251 -- --------------------------------------------------------------------------
252 -- goto local label. [1], section 6.6
253 --
254 --     goto lbl;
255 --
256 genBranch :: BlockId -> SDoc
257 genBranch ident = 
258     ptext SLIT("goto") <+> pprBlockId ident <> semi
259
260 -- --------------------------------------------------------------------------
261 -- Conditional. [1], section 6.4
262 --
263 --     if (expr) { goto lbl; } 
264 --
265 genCondBranch :: CmmExpr -> BlockId -> SDoc
266 genCondBranch expr ident =
267     hsep [ ptext SLIT("if")
268          , parens(ppr expr)
269          , ptext SLIT("goto")
270          , pprBlockId ident <> semi ]
271
272 -- --------------------------------------------------------------------------
273 -- A tail call. [1], Section 6.9
274 --
275 --     jump foo(a, b, c);
276 --
277 genJump :: CmmExpr -> [(CmmExpr, MachHint)] -> SDoc
278 genJump expr args = 
279
280     hcat [ ptext SLIT("jump")
281          , space
282          , if isTrivialCmmExpr expr
283                 then pprExpr expr
284                 else case expr of
285                     CmmLoad (CmmReg _) _ -> pprExpr expr 
286                     _ -> parens (pprExpr expr)
287          , space
288          , parens  ( commafy $ map ppr args )
289          , semi ]
290
291 -- --------------------------------------------------------------------------
292 -- Return from a function. [1], Section 6.8.2 of version 1.128
293 --
294 --     return (a, b, c);
295 --
296 genReturn :: [(CmmExpr, MachHint)] -> SDoc
297 genReturn args = 
298
299     hcat [ ptext SLIT("return")
300          , space
301          , parens  ( commafy $ map ppr args )
302          , semi ]
303
304 -- --------------------------------------------------------------------------
305 -- Tabled jump to local label
306 --
307 -- The syntax is from [1], section 6.5
308 --
309 --      switch [0 .. n] (expr) { case ... ; }
310 --
311 genSwitch :: CmmExpr -> [Maybe BlockId] -> SDoc
312 genSwitch expr maybe_ids 
313
314     = let pairs = groupBy snds (zip [0 .. ] maybe_ids )
315
316       in hang (hcat [ ptext SLIT("switch [0 .. ") 
317                     , int (length maybe_ids - 1)
318                     , ptext SLIT("] ")
319                     , if isTrivialCmmExpr expr
320                         then pprExpr expr
321                         else parens (pprExpr expr)
322                     , ptext SLIT(" {") 
323                     ]) 
324             4 (vcat ( map caseify pairs )) $$ rbrace
325
326     where
327       snds a b = (snd a) == (snd b)
328
329       caseify :: [(Int,Maybe BlockId)] -> SDoc
330       caseify ixs@((i,Nothing):_)
331         = ptext SLIT("/* impossible: ") <> hcat (intersperse comma (map (int.fst) ixs))
332                 <> ptext SLIT(" */")
333       caseify as 
334         = let (is,ids) = unzip as 
335           in hsep [ ptext SLIT("case")
336                   , hcat (punctuate comma (map int is))
337                   , ptext SLIT(": goto")
338                   , pprBlockId (head [ id | Just id <- ids]) <> semi ]
339
340 -- --------------------------------------------------------------------------
341 -- Expressions
342 --
343
344 pprExpr :: CmmExpr -> SDoc
345 pprExpr e 
346     = case e of
347         CmmRegOff reg i -> 
348                 pprExpr (CmmMachOp (MO_Add rep)
349                            [CmmReg reg, CmmLit (CmmInt (fromIntegral i) rep)])
350                 where rep = cmmRegRep reg       
351         CmmLit lit -> pprLit lit
352         _other     -> pprExpr1 e
353
354 -- Here's the precedence table from CmmParse.y:
355 -- %nonassoc '>=' '>' '<=' '<' '!=' '=='
356 -- %left '|'
357 -- %left '^'
358 -- %left '&'
359 -- %left '>>' '<<'
360 -- %left '-' '+'
361 -- %left '/' '*' '%'
362 -- %right '~'
363
364 -- We just cope with the common operators for now, the rest will get
365 -- a default conservative behaviour.
366
367 -- %nonassoc '>=' '>' '<=' '<' '!=' '=='
368 pprExpr1 (CmmMachOp op [x,y]) | Just doc <- infixMachOp1 op
369    = pprExpr7 x <+> doc <+> pprExpr7 y
370 pprExpr1 e = pprExpr7 e
371
372 infixMachOp1 (MO_Eq     _) = Just (ptext SLIT("=="))
373 infixMachOp1 (MO_Ne     _) = Just (ptext SLIT("!="))
374 infixMachOp1 (MO_Shl    _) = Just (ptext SLIT("<<"))
375 infixMachOp1 (MO_U_Shr  _) = Just (ptext SLIT(">>"))
376 infixMachOp1 (MO_U_Ge   _) = Just (ptext SLIT(">="))
377 infixMachOp1 (MO_U_Le   _) = Just (ptext SLIT("<="))
378 infixMachOp1 (MO_U_Gt   _) = Just (char '>')
379 infixMachOp1 (MO_U_Lt   _) = Just (char '<')
380 infixMachOp1 _             = Nothing
381
382 -- %left '-' '+'
383 pprExpr7 (CmmMachOp (MO_Add rep1) [x, CmmLit (CmmInt i rep2)]) | i < 0
384    = pprExpr7 (CmmMachOp (MO_Sub rep1) [x, CmmLit (CmmInt (negate i) rep2)])
385 pprExpr7 (CmmMachOp op [x,y]) | Just doc <- infixMachOp7 op
386    = pprExpr7 x <+> doc <+> pprExpr8 y
387 pprExpr7 e = pprExpr8 e
388
389 infixMachOp7 (MO_Add _)  = Just (char '+')
390 infixMachOp7 (MO_Sub _)  = Just (char '-')
391 infixMachOp7 _           = Nothing
392
393 -- %left '/' '*' '%'
394 pprExpr8 (CmmMachOp op [x,y]) | Just doc <- infixMachOp8 op
395    = pprExpr8 x <+> doc <+> pprExpr9 y
396 pprExpr8 e = pprExpr9 e
397
398 infixMachOp8 (MO_U_Quot _) = Just (char '/')
399 infixMachOp8 (MO_Mul _)    = Just (char '*')
400 infixMachOp8 (MO_U_Rem _)  = Just (char '%')
401 infixMachOp8 _             = Nothing
402
403 pprExpr9 :: CmmExpr -> SDoc
404 pprExpr9 e = 
405    case e of
406         CmmLit    lit       -> pprLit1 lit
407         CmmLoad   expr rep  -> ppr rep <> brackets( ppr expr )
408         CmmReg    reg       -> ppr reg
409         CmmRegOff reg off   -> parens (ppr reg <+> char '+' <+> int off)
410         CmmMachOp mop args  -> genMachOp mop args
411
412 genMachOp :: MachOp -> [CmmExpr] -> SDoc
413 genMachOp mop args
414    | Just doc <- infixMachOp mop = case args of
415         -- dyadic
416         [x,y] -> pprExpr9 x <+> doc <+> pprExpr9 y
417
418         -- unary
419         [x]   -> doc <> pprExpr9 x
420
421         _     -> pprTrace "PprCmm.genMachOp: machop with strange number of args"
422                           (pprMachOp mop <+>
423                             parens (hcat $ punctuate comma (map pprExpr args)))
424                           empty
425
426    | isJust (infixMachOp1 mop)
427    || isJust (infixMachOp7 mop)
428    || isJust (infixMachOp8 mop)  = parens (pprExpr (CmmMachOp mop args))
429
430    | otherwise = char '%' <> ppr_op <> parens (commafy (map pprExpr args))
431         where ppr_op = text (map (\c -> if c == ' ' then '_' else c)
432                                  (show mop))
433                 -- replace spaces in (show mop) with underscores,
434
435 --
436 -- Unsigned ops on the word size of the machine get nice symbols.
437 -- All else get dumped in their ugly format.
438 --
439 infixMachOp :: MachOp -> Maybe SDoc
440 infixMachOp mop
441         = case mop of
442             MO_And    _ -> Just $ char '&'
443             MO_Or     _ -> Just $ char '|'
444             MO_Xor    _ -> Just $ char '^'
445             MO_Not    _ -> Just $ char '~'
446             MO_S_Neg  _ -> Just $ char '-' -- there is no unsigned neg :)
447             _ -> Nothing
448
449 -- --------------------------------------------------------------------------
450 -- Literals.
451 --  To minimise line noise we adopt the convention that if the literal
452 --  has the natural machine word size, we do not append the type
453 --
454 pprLit :: CmmLit -> SDoc
455 pprLit lit = case lit of
456     CmmInt i rep ->
457         hcat [ (if i < 0 then parens else id)(integer i)
458              , (if rep == wordRep 
459                     then empty 
460                     else space <> dcolon <+> ppr rep) ]
461
462     CmmFloat f rep     -> hsep [ rational f, dcolon, ppr rep ]
463     CmmLabel clbl      -> pprCLabel clbl
464     CmmLabelOff clbl i -> pprCLabel clbl <> ppr_offset i
465     CmmLabelDiffOff clbl1 clbl2 i -> pprCLabel clbl1 <> char '-'  
466                                   <> pprCLabel clbl2 <> ppr_offset i
467
468 pprLit1 lit@(CmmLabelOff clbl i) = parens (pprLit lit)
469 pprLit1 lit                      = pprLit lit
470
471 ppr_offset :: Int -> SDoc
472 ppr_offset i
473     | i==0      = empty
474     | i>=0      = char '+' <> int i
475     | otherwise = char '-' <> int (-i)
476
477 -- --------------------------------------------------------------------------
478 -- Static data.
479 --      Strings are printed as C strings, and we print them as I8[],
480 --      following C--
481 --
482 pprStatic :: CmmStatic -> SDoc
483 pprStatic s = case s of
484     CmmStaticLit lit   -> nest 4 $ ptext SLIT("const") <+> pprLit lit <> semi
485     CmmUninitialised i -> nest 4 $ text "I8" <> brackets (int i)
486     CmmAlign i         -> nest 4 $ text "align" <+> int i
487     CmmDataLabel clbl  -> pprCLabel clbl <> colon
488     CmmString s'       -> nest 4 $ text "I8[]" <+> text (show s')
489
490 -- --------------------------------------------------------------------------
491 -- Registers, whether local (temps) or global
492 --
493 pprReg :: CmmReg -> SDoc
494 pprReg r 
495     = case r of
496         CmmLocal  local  -> pprLocalReg local
497         CmmGlobal global -> pprGlobalReg global
498
499 --
500 -- We only print the type of the local reg if it isn't wordRep
501 --
502 pprLocalReg :: LocalReg -> SDoc
503 pprLocalReg (LocalReg uniq rep follow) 
504     = hcat [ char '_', ppr uniq, ty ] where
505   ty = if rep == wordRep && follow == KindNonPtr
506                 then empty
507                 else dcolon <> ptr <> ppr rep
508   ptr = if follow == KindNonPtr
509                 then empty
510                 else doubleQuotes (text "ptr")
511
512 -- needs to be kept in syn with Cmm.hs.GlobalReg
513 --
514 pprGlobalReg :: GlobalReg -> SDoc
515 pprGlobalReg gr 
516     = case gr of
517         VanillaReg n   -> char 'R' <> int n
518         FloatReg   n   -> char 'F' <> int n
519         DoubleReg  n   -> char 'D' <> int n
520         LongReg    n   -> char 'L' <> int n
521         Sp             -> ptext SLIT("Sp")
522         SpLim          -> ptext SLIT("SpLim")
523         Hp             -> ptext SLIT("Hp")
524         HpLim          -> ptext SLIT("HpLim")
525         CurrentTSO     -> ptext SLIT("CurrentTSO")
526         CurrentNursery -> ptext SLIT("CurrentNursery")
527         HpAlloc        -> ptext SLIT("HpAlloc")
528         GCEnter1       -> ptext SLIT("stg_gc_enter_1")
529         GCFun          -> ptext SLIT("stg_gc_fun")
530         BaseReg        -> ptext SLIT("BaseReg")
531         PicBaseReg     -> ptext SLIT("PicBaseReg")
532
533 -- --------------------------------------------------------------------------
534 -- data sections
535 --
536 pprSection :: Section -> SDoc
537 pprSection s = case s of
538     Text              -> section <+> doubleQuotes (ptext SLIT("text"))
539     Data              -> section <+> doubleQuotes (ptext SLIT("data"))
540     ReadOnlyData      -> section <+> doubleQuotes (ptext SLIT("readonly"))
541     RelocatableReadOnlyData
542                       -> section <+> doubleQuotes (ptext SLIT("relreadonly"))
543     UninitialisedData -> section <+> doubleQuotes (ptext SLIT("uninitialised"))
544     OtherSection s'   -> section <+> doubleQuotes (text s')
545  where
546     section = ptext SLIT("section")
547        
548 -- --------------------------------------------------------------------------
549 -- Basic block ids
550 --
551 pprBlockId :: BlockId -> SDoc
552 pprBlockId b = ppr $ getUnique b
553
554 -----------------------------------------------------------------------------
555
556 commafy :: [SDoc] -> SDoc
557 commafy xs = hsep $ punctuate comma xs
558