[project @ 2004-08-13 13:04:50 by simonmar]
[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 -- N.B. we remove 'Nothing's from the list of branches, as they don't
223 -- seem to make sense currently. This may change, if they are defined in
224 -- some way.
225 --
226 genSwitch :: CmmExpr -> [Maybe BlockId] -> SDoc
227 genSwitch expr maybe_ids 
228
229     = let ids   = [ i | Just i <- maybe_ids ]
230           pairs = groupBy snds (zip [0 .. ] ids )
231
232       in hang (hcat [ ptext SLIT("switch [0 .. ") 
233                     , int (length ids - 1)
234                     , ptext SLIT("] ")
235                     , if isTrivialCmmExpr expr
236                         then pprExpr expr
237                         else parens (pprExpr expr)
238                     , ptext SLIT(" {") 
239                     ]) 
240             4 (vcat ( map caseify pairs )) $$ rbrace
241
242     where
243       snds a b = (snd a) == (snd b)
244
245       caseify :: [(Int,BlockId)] -> SDoc
246       caseify as 
247         = let (is,ids) = unzip as 
248           in hsep [ ptext SLIT("case")
249                   , hcat (punctuate comma (map int is))
250                   , ptext SLIT(": goto")
251                   , pprBlockId (head ids) <> semi ]
252
253 -- --------------------------------------------------------------------------
254 -- Expressions
255 --
256
257 pprExpr :: CmmExpr -> SDoc
258 pprExpr e 
259     = case e of
260         CmmRegOff reg i -> 
261                 pprExpr (CmmMachOp (MO_Add rep)
262                            [CmmReg reg, CmmLit (CmmInt (fromIntegral i) rep)])
263                 where rep = cmmRegRep reg       
264         CmmLit lit -> pprLit lit
265         _other     -> pprExpr1 e
266
267 -- Here's the precedence table from CmmParse.y:
268 -- %nonassoc '>=' '>' '<=' '<' '!=' '=='
269 -- %left '|'
270 -- %left '^'
271 -- %left '&'
272 -- %left '>>' '<<'
273 -- %left '-' '+'
274 -- %left '/' '*' '%'
275 -- %right '~'
276
277 -- We just cope with the common operators for now, the rest will get
278 -- a default conservative behaviour.
279
280 -- %nonassoc '>=' '>' '<=' '<' '!=' '=='
281 pprExpr1 (CmmMachOp op [x,y]) | Just doc <- infixMachOp1 op
282    = pprExpr7 x <+> doc <+> pprExpr7 y
283 pprExpr1 e = pprExpr7 e
284
285 infixMachOp1 (MO_Eq     _) = Just (ptext SLIT("=="))
286 infixMachOp1 (MO_Ne     _) = Just (ptext SLIT("!="))
287 infixMachOp1 (MO_Shl    _) = Just (ptext SLIT("<<"))
288 infixMachOp1 (MO_U_Shr  _) = Just (ptext SLIT(">>"))
289 infixMachOp1 (MO_U_Ge   _) = Just (ptext SLIT(">="))
290 infixMachOp1 (MO_U_Le   _) = Just (ptext SLIT("<="))
291 infixMachOp1 (MO_U_Gt   _) = Just (char '>')
292 infixMachOp1 (MO_U_Lt   _) = Just (char '<')
293 infixMachOp1 _             = Nothing
294
295 -- %left '-' '+'
296 pprExpr7 (CmmMachOp op [x,y]) | Just doc <- infixMachOp7 op
297    = pprExpr7 x <+> doc <+> pprExpr8 y
298 pprExpr7 e = pprExpr8 e
299
300 infixMachOp7 (MO_Add _)  = Just (char '+')
301 infixMachOp7 (MO_Sub _)  = Just (char '-')
302 infixMachOp7 _           = Nothing
303
304 -- %left '/' '*' '%'
305 pprExpr8 (CmmMachOp op [x,y]) | Just doc <- infixMachOp8 op
306    = pprExpr8 x <+> doc <+> pprExpr9 y
307 pprExpr8 e = pprExpr9 e
308
309 infixMachOp8 (MO_U_Quot _) = Just (char '/')
310 infixMachOp8 (MO_Mul _)    = Just (char '*')
311 infixMachOp8 (MO_U_Rem _)  = Just (char '%')
312 infixMachOp8 _             = Nothing
313
314 pprExpr9 :: CmmExpr -> SDoc
315 pprExpr9 e = 
316    case e of
317         CmmLit    lit       -> pprLit1 lit
318         CmmLoad   expr rep  -> ppr rep <> brackets( ppr expr )
319         CmmReg    reg       -> ppr reg
320         CmmMachOp mop args  -> genMachOp mop args
321         e                   -> parens (pprExpr e)
322
323 genMachOp :: MachOp -> [CmmExpr] -> SDoc
324 genMachOp mop args
325    | Just doc <- infixMachOp mop = case args of
326         -- dyadic
327         [x,y] -> pprExpr9 x <+> doc <+> pprExpr9 y
328
329         -- unary
330         [x]   -> doc <> pprExpr9 x
331
332         _     -> pprTrace "PprCmm.genMachOp: machop with strange number of args"
333                           (pprMachOp mop <+>
334                             parens (hcat $ punctuate comma (map pprExpr args)))
335                           empty
336
337    | isJust (infixMachOp1 mop)
338    || isJust (infixMachOp7 mop)
339    || isJust (infixMachOp8 mop)  = parens (pprExpr (CmmMachOp mop args))
340
341    | otherwise = char '%' <> pprMachOp mop <> parens (commafy (map pprExpr args))
342
343 --
344 -- Unsigned ops on the word size of the machine get nice symbols.
345 -- All else get dumped in their ugly format.
346 --
347 infixMachOp :: MachOp -> Maybe SDoc
348 infixMachOp mop
349         = case mop of
350             MO_And    _ -> Just $ char '&'
351             MO_Or     _ -> Just $ char '|'
352             MO_Xor    _ -> Just $ char '^'
353             MO_Not    _ -> Just $ char '~'
354             MO_S_Neg  _ -> Just $ char '-' -- there is no unsigned neg :)
355             MO_Not    _ -> Just $ char '~'
356             _ -> Nothing
357
358 -- --------------------------------------------------------------------------
359 -- Literals.
360 --  To minimise line noise we adopt the convention that if the literal
361 --  has the natural machine word size, we do not append the type
362 --
363 pprLit :: CmmLit -> SDoc
364 pprLit lit = case lit of
365     CmmInt i rep ->
366         hcat [ (if i < 0 then parens else id)(integer i)
367              , (if rep == wordRep 
368                     then empty 
369                     else space <> dcolon <+> ppr rep) ]
370
371     CmmFloat f rep     -> hsep [ rational f, dcolon, ppr rep ]
372     CmmLabel clbl      -> pprCLabel clbl
373     CmmLabelOff clbl i -> pprCLabel clbl <> ppr_offset i
374
375 pprLit1 lit@(CmmLabelOff clbl i) = parens (pprLit lit)
376 pprLit1 lit                      = pprLit lit
377
378 ppr_offset :: Int -> SDoc
379 ppr_offset i
380     | i==0      = empty
381     | i>=0      = char '+' <> int i
382     | otherwise = char '-' <> int (-i)
383
384 -- --------------------------------------------------------------------------
385 -- Static data.
386 --      Strings are printed as C strings, and we print them as I8[],
387 --      following C--
388 --
389 pprStatic :: CmmStatic -> SDoc
390 pprStatic s = case s of
391     CmmStaticLit lit   -> nest 4 $ ptext SLIT("const") <+> pprLit lit <> semi
392     CmmUninitialised i -> nest 4 $ text "I8" <> brackets (int i)
393     CmmAlign i         -> nest 4 $ text "align" <+> int i
394     CmmDataLabel clbl  -> pprCLabel clbl <> colon
395     CmmString s'       -> nest 4 $ text "I8[]" <+> doubleQuotes (text s')
396
397 -- --------------------------------------------------------------------------
398 -- Registers, whether local (temps) or global
399 --
400 pprReg :: CmmReg -> SDoc
401 pprReg r 
402     = case r of
403         CmmLocal  local  -> pprLocalReg local
404         CmmGlobal global -> pprGlobalReg global
405
406 --
407 -- We only print the type of the local reg if it isn't wordRep
408 --
409 pprLocalReg :: LocalReg -> SDoc
410 pprLocalReg (LocalReg uniq rep) 
411     = hcat [ char '_', ppr uniq, 
412             (if rep == wordRep 
413                 then empty else dcolon <> ppr rep) ]
414
415 -- needs to be kept in syn with Cmm.hs.GlobalReg
416 --
417 pprGlobalReg :: GlobalReg -> SDoc
418 pprGlobalReg gr 
419     = case gr of
420         VanillaReg n   -> char 'R' <> int n
421         FloatReg   n   -> char 'F' <> int n
422         DoubleReg  n   -> char 'D' <> int n
423         LongReg    n   -> char 'L' <> int n
424         Sp             -> ptext SLIT("Sp")
425         SpLim          -> ptext SLIT("SpLim")
426         Hp             -> ptext SLIT("Hp")
427         HpLim          -> ptext SLIT("HpLim")
428         CurrentTSO     -> ptext SLIT("CurrentTSO")
429         CurrentNursery -> ptext SLIT("CurrentNursery")
430         HpAlloc        -> ptext SLIT("HpAlloc")
431         GCEnter1       -> ptext SLIT("stg_gc_enter_1")
432         GCFun          -> ptext SLIT("stg_gc_fun")
433         BaseReg        -> ptext SLIT("BaseReg")
434
435         _ -> panic $ "PprCmm.pprGlobalReg: unknown global reg"
436
437 -- --------------------------------------------------------------------------
438 -- data sections
439 --
440 pprSection :: Section -> SDoc
441 pprSection s = case s of
442     Text              -> section <+> doubleQuotes (ptext SLIT("text"))
443     Data              -> section <+> doubleQuotes (ptext SLIT("data"))
444     ReadOnlyData      -> section <+> doubleQuotes (ptext SLIT("readonly"))
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