[project @ 1999-03-11 11:32:22 by simonm]
[ghc-hetmet.git] / ghc / compiler / absCSyn / PprAbsC.lhs
1 %
2 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
3 %
4 %************************************************************************
5 %*                                                                      *
6 \section[PprAbsC]{Pretty-printing Abstract~C}
7 %*                                                                      *
8 %************************************************************************
9
10 \begin{code}
11 module PprAbsC (
12         writeRealC,
13         dumpRealC,
14         pprAmode,
15         pprMagicId
16     ) where
17
18 #include "HsVersions.h"
19
20 import IO       ( Handle )
21
22 import AbsCSyn
23 import ClosureInfo
24 import AbsCUtils        ( getAmodeRep, nonemptyAbsC,
25                           mixedPtrLocn, mixedTypeLocn
26                         )
27
28 import Constants        ( mIN_UPD_SIZE )
29 import CallConv         ( CallConv, callConvAttribute, cCallConv )
30 import CLabel           ( externallyVisibleCLabel, mkErrorStdEntryLabel,
31                           isReadOnly, needsCDecl, pprCLabel,
32                           mkReturnInfoLabel, mkReturnPtLabel,
33                           CLabel, CLabelType(..), labelType, labelDynamic
34                         )
35
36 import CmdLineOpts      ( opt_SccProfilingOn, opt_EmitCExternDecls, opt_GranMacros )
37 import CostCentre       ( pprCostCentreDecl, pprCostCentreStackDecl )
38
39 import Costs            ( costs, addrModeCosts, CostRes(..), Side(..) )
40 import CStrings         ( stringToC )
41 import FiniteMap        ( addToFM, emptyFM, lookupFM, FiniteMap )
42 import Const            ( Literal(..) )
43 import Maybes           ( maybeToBool, catMaybes )
44 import PrimOp           ( primOpNeedsWrapper, pprPrimOp, PrimOp(..) )
45 import PrimRep          ( isFloatingRep, PrimRep(..), getPrimRepSize, showPrimRep )
46 import SMRep            ( pprSMRep )
47 import Unique           ( pprUnique, Unique{-instance NamedThing-} )
48 import UniqSet          ( emptyUniqSet, elementOfUniqSet,
49                           addOneToUniqSet, UniqSet
50                         )
51 import StgSyn           ( SRT(..) )
52 import BitSet           ( intBS )
53 import Outputable
54 import Util             ( nOfThem )
55 import Addr             ( Addr )
56
57 import ST
58 import MutableArray
59
60 infixr 9 `thenTE`
61 \end{code}
62
63 For spitting out the costs of an abstract~C expression, @writeRealC@
64 now not only prints the C~code of the @absC@ arg but also adds a macro
65 call to a cost evaluation function @GRAN_EXEC@. For that,
66 @pprAbsC@ has a new ``costs'' argument.  %% HWL
67
68 \begin{code}
69 {-
70 writeRealC :: Handle -> AbstractC -> IO ()
71 writeRealC handle absC
72      -- avoid holding on to the whole of absC in the !Gransim case.
73      if opt_GranMacros
74         then printForCFast fp (pprAbsC absC (costs absC))
75         else printForCFast fp (pprAbsC absC (panic "costs"))
76              --printForC handle (pprAbsC absC (panic "costs"))
77 dumpRealC :: AbstractC -> SDoc
78 dumpRealC absC = pprAbsC absC (costs absC)
79 -}
80
81 writeRealC :: Handle -> AbstractC -> IO ()
82 --writeRealC handle absC = 
83 -- _scc_ "writeRealC" 
84 -- printDoc LeftMode handle (pprAbsC absC (costs absC))
85
86 writeRealC handle absC
87  | opt_GranMacros = _scc_ "writeRealC" printForC handle $ 
88                                        pprCode CStyle (pprAbsC absC (costs absC))
89  | otherwise      = _scc_ "writeRealC" printForC handle $
90                                        pprCode CStyle (pprAbsC absC (panic "costs"))
91
92 dumpRealC :: AbstractC -> SDoc
93 dumpRealC absC
94  | opt_GranMacros = pprCode CStyle (pprAbsC absC (costs absC))
95  | otherwise      = pprCode CStyle (pprAbsC absC (panic "costs"))
96
97 \end{code}
98
99 This emits the macro,  which is used in GrAnSim  to compute the total costs
100 from a cost 5 tuple. %%  HWL
101
102 \begin{code}
103 emitMacro :: CostRes -> SDoc
104
105 emitMacro _ | not opt_GranMacros = empty
106
107 emitMacro (Cost (i,b,l,s,f))
108   = hcat [ ptext SLIT("GRAN_EXEC"), char '(',
109                           int i, comma, int b, comma, int l, comma,
110                           int s, comma, int f, pp_paren_semi ]
111
112 pp_paren_semi = text ");"
113 \end{code}
114
115 New type: Now pprAbsC also takes the costs for evaluating the Abstract C
116 code as an argument (that's needed when spitting out the GRAN_EXEC macro
117 which must be done before the return i.e. inside absC code)   HWL
118
119 \begin{code}
120 pprAbsC :: AbstractC -> CostRes -> SDoc
121 pprAbsC AbsCNop _ = empty
122 pprAbsC (AbsCStmts s1 s2) c = ($$) (pprAbsC s1 c) (pprAbsC s2 c)
123
124 pprAbsC (CAssign dest src) _ = pprAssign (getAmodeRep dest) dest src
125
126 pprAbsC (CJump target) c
127   = ($$) (hcat [emitMacro c {-WDP:, text "/* <--++  CJump */"-} ])
128              (hcat [ text jmp_lit, pprAmode target, pp_paren_semi ])
129
130 pprAbsC (CFallThrough target) c
131   = ($$) (hcat [emitMacro c {-WDP:, text "/* <--++  CFallThrough */"-} ])
132              (hcat [ text jmp_lit, pprAmode target, pp_paren_semi ])
133
134 -- --------------------------------------------------------------------------
135 -- Spit out GRAN_EXEC macro immediately before the return                 HWL
136
137 pprAbsC (CReturn am return_info)  c
138   = ($$) (hcat [emitMacro c {-WDP:, text "/* <----  CReturn */"-} ])
139              (hcat [text jmp_lit, target, pp_paren_semi ])
140   where
141    target = case return_info of
142         DirectReturn -> hcat [char '(', pprAmode am, rparen]
143         DynamicVectoredReturn am' -> mk_vector (pprAmode am')
144         StaticVectoredReturn n -> mk_vector (int n)     -- Always positive
145    mk_vector x = hcat [text "RET_VEC", char '(', pprAmode am, comma,
146                        x, rparen ]
147
148 pprAbsC (CSplitMarker) _ = ptext SLIT("/* SPLIT */")
149
150 -- we optimise various degenerate cases of CSwitches.
151
152 -- --------------------------------------------------------------------------
153 -- Assume: CSwitch is also end of basic block
154 --         costs function yields nullCosts for whole switch
155 --         ==> inherited costs c are those of basic block up to switch
156 --         ==> inherit c + costs for the corresponding branch
157 --                                                                       HWL
158 -- --------------------------------------------------------------------------
159
160 pprAbsC (CSwitch discrim [] deflt) c
161   = pprAbsC deflt (c + costs deflt)
162     -- Empty alternative list => no costs for discrim as nothing cond. here HWL
163
164 pprAbsC (CSwitch discrim [(tag,alt_code)] deflt) c -- only one alt
165   = case (nonemptyAbsC deflt) of
166       Nothing ->                -- one alt and no default
167                  pprAbsC alt_code (c + costs alt_code)
168                  -- Nothing conditional in here either  HWL
169
170       Just dc ->                -- make it an "if"
171                  do_if_stmt discrim tag alt_code dc c
172
173 -- What problem is the re-ordering trying to solve ?
174 pprAbsC (CSwitch discrim [(tag1@(MachInt i1 _), alt_code1),
175                               (tag2@(MachInt i2 _), alt_code2)] deflt) c
176   | empty_deflt && ((i1 == 0 && i2 == 1) || (i1 == 1 && i2 == 0))
177   = if (i1 == 0) then
178         do_if_stmt discrim tag1 alt_code1 alt_code2 c
179     else
180         do_if_stmt discrim tag2 alt_code2 alt_code1 c
181   where
182     empty_deflt = not (maybeToBool (nonemptyAbsC deflt))
183
184 pprAbsC (CSwitch discrim alts deflt) c -- general case
185   | isFloatingRep (getAmodeRep discrim)
186     = pprAbsC (foldr ( \ a -> CSwitch discrim [a]) deflt alts) c
187   | otherwise
188     = vcat [
189         hcat [text "switch (", pp_discrim, text ") {"],
190         nest 2 (vcat (map ppr_alt alts)),
191         (case (nonemptyAbsC deflt) of
192            Nothing -> empty
193            Just dc ->
194             nest 2 (vcat [ptext SLIT("default:"),
195                                   pprAbsC dc (c + switch_head_cost
196                                                     + costs dc),
197                                   ptext SLIT("break;")])),
198         char '}' ]
199   where
200     pp_discrim
201       = pprAmode discrim
202
203     ppr_alt (lit, absC)
204       = vcat [ hcat [ptext SLIT("case "), pprBasicLit lit, char ':'],
205                    nest 2 (($$) (pprAbsC absC (c + switch_head_cost + costs absC))
206                                        (ptext SLIT("break;"))) ]
207
208     -- Costs for addressing header of switch and cond. branching        -- HWL
209     switch_head_cost = addrModeCosts discrim Rhs + (Cost (0, 1, 0, 0, 0))
210
211 pprAbsC stmt@(COpStmt results op@(CCallOp _ _ _ _) args vol_regs) _
212   = pprCCall op args results vol_regs
213
214 pprAbsC stmt@(COpStmt results op args vol_regs) _
215   = let
216         non_void_args = grab_non_void_amodes args
217         non_void_results = grab_non_void_amodes results
218         -- if just one result, we print in the obvious "assignment" style;
219         -- if 0 or many results, we emit a macro call, w/ the results
220         -- followed by the arguments.  The macro presumably knows which
221         -- are which :-)
222
223         the_op = ppr_op_call non_void_results non_void_args
224                 -- liveness mask is *in* the non_void_args
225     in
226     case (ppr_vol_regs vol_regs) of { (pp_saves, pp_restores) ->
227     if primOpNeedsWrapper op then
228         vcat [  pp_saves,
229                 the_op,
230                 pp_restores
231              ]
232     else
233         the_op
234     }
235   where
236     ppr_op_call results args
237       = hcat [ pprPrimOp op, lparen,
238         hcat (punctuate comma (map ppr_op_result results)),
239         if null results || null args then empty else comma,
240         hcat (punctuate comma (map pprAmode args)),
241         pp_paren_semi ]
242
243     ppr_op_result r = ppr_amode r
244       -- primop macros do their own casting of result;
245       -- hence we can toss the provided cast...
246
247 pprAbsC stmt@(CSRT lbl closures) c
248   = case (pprTempAndExternDecls stmt) of { (_, pp_exts) ->
249          pp_exts
250       $$ ptext SLIT("SRT") <> lparen <> pprCLabel lbl <> rparen
251       $$ nest 2 (hcat (punctuate comma (map pp_closure_lbl closures)))
252          <> ptext SLIT("};")
253   }
254   where 
255     pp_closure_lbl lbl
256       | labelDynamic lbl = text "DLL_SRT_ENTRY" <> parens (pprCLabel lbl)
257       | otherwise        = char '&' <> pprCLabel lbl
258
259 pprAbsC stmt@(CBitmap lbl mask) c
260   = vcat [
261         hcat [ ptext SLIT("BITMAP"), lparen, 
262                         pprCLabel lbl, comma,
263                         int (length mask), 
264                rparen ],
265         hcat (punctuate comma (map (int.intBS) mask)),
266         ptext SLIT("}};")
267     ]
268
269 pprAbsC (CSimultaneous abs_c) c
270   = hcat [ptext SLIT("{{"), pprAbsC abs_c c, ptext SLIT("}}")]
271
272 pprAbsC (CCheck macro as code) c
273   = hcat [text (show macro), lparen,
274        hcat (punctuate comma (map ppr_amode as)), comma,
275        pprAbsC code c, pp_paren_semi
276     ]
277 pprAbsC (CMacroStmt macro as) _
278   = hcat [text (show macro), lparen,
279         hcat (punctuate comma (map ppr_amode as)),pp_paren_semi] -- no casting
280 pprAbsC (CCallProfCtrMacro op as) _
281   = hcat [ptext op, lparen,
282         hcat (punctuate comma (map ppr_amode as)),pp_paren_semi]
283 pprAbsC (CCallProfCCMacro op as) _
284   = hcat [ptext op, lparen,
285         hcat (punctuate comma (map ppr_amode as)),pp_paren_semi]
286 pprAbsC stmt@(CCallTypedef op@(CCallOp op_str is_asm may_gc cconv) results args) _
287   =  hsep [ ptext SLIT("typedef")
288           , ccall_res_ty
289           , fun_nm
290           , parens (hsep (punctuate comma ccall_decl_ty_args))
291           ] <> semi
292     where
293      fun_nm       = parens (text (callConvAttribute cconv) <+> char '*' <> ccall_fun_ty)
294
295      ccall_fun_ty = 
296         case op_str of
297           Right u -> ptext SLIT("_ccall_fun_ty") <> ppr u
298
299      ccall_res_ty = 
300        case non_void_results of
301           []       -> ptext SLIT("void")
302           [amode]  -> text (showPrimRep (getAmodeRep amode))
303           _        -> panic "pprAbsC{CCallTypedef}: ccall_res_ty"
304
305      ccall_decl_ty_args = tail ccall_arg_tys
306      ccall_arg_tys      = map (text.showPrimRep.getAmodeRep) non_void_args
307
308       -- the first argument will be the "I/O world" token (a VoidRep)
309       -- all others should be non-void
310      non_void_args =
311         let nvas = tail args
312         in ASSERT (all non_void nvas) nvas
313
314       -- there will usually be two results: a (void) state which we
315       -- should ignore and a (possibly void) result.
316      non_void_results =
317         let nvrs = grab_non_void_amodes results
318         in ASSERT (length nvrs <= 1) nvrs
319
320 pprAbsC (CCodeBlock label abs_C) _
321   = if not (maybeToBool(nonemptyAbsC abs_C)) then
322         pprTrace "pprAbsC: curious empty code block for" (pprCLabel label) empty
323     else
324     case (pprTempAndExternDecls abs_C) of { (pp_temps, pp_exts) ->
325     vcat [
326         hcat [text (if (externallyVisibleCLabel label)
327                           then "FN_("   -- abbreviations to save on output
328                           else "IFN_("),
329                    pprCLabel label, text ") {"],
330
331         pp_exts, pp_temps,
332
333         nest 8 (ptext SLIT("FB_")),
334         nest 8 (pprAbsC abs_C (costs abs_C)),
335         nest 8 (ptext SLIT("FE_")),
336         char '}' ]
337     }
338
339
340 pprAbsC (CInitHdr cl_info reg_rel cost_centre) _
341   = hcat [ ptext SLIT("SET_HDR_"), char '(',
342                 ppr_amode (CAddr reg_rel), comma,
343                 pprCLabelAddr info_lbl, comma,
344                 if_profiling (pprAmode cost_centre),
345                 pp_paren_semi ]
346   where
347     info_lbl    = infoTableLabelFromCI cl_info
348
349 pprAbsC stmt@(CStaticClosure closure_lbl cl_info cost_centre amodes) _
350   = case (pprTempAndExternDecls stmt) of { (_, pp_exts) ->
351     vcat [
352         pp_exts,
353         hcat [
354                 ptext SLIT("SET_STATIC_HDR"), char '(',
355                 pprCLabel closure_lbl,                          comma,
356                 pprCLabel info_lbl,                             comma,
357                 if_profiling (pprAmode cost_centre),            comma,
358                 ppLocalness closure_lbl,                        comma,
359                 ppLocalnessMacro True{-include dyn-} info_lbl,
360                 char ')'
361                 ],
362         nest 2 (ppr_payload (amodes ++ padding_wds ++ static_link_field)),
363         ptext SLIT("};") ]
364     }
365   where
366     info_lbl = infoTableLabelFromCI cl_info
367
368     ppr_payload [] = empty
369     ppr_payload ls = comma <+> 
370                      braces (hsep (punctuate comma (map ((text "(L_)" <>).ppr_item) ls)))
371
372     ppr_item item
373       | rep == VoidRep   = text "0" -- might not even need this...
374       | rep == FloatRep  = ppr_amode (floatToWord item)
375       | rep == DoubleRep = hcat (punctuate (text ", (L_)")
376                                  (map ppr_amode (doubleToWords item)))
377       | otherwise        = ppr_amode item
378       where 
379         rep = getAmodeRep item
380
381     padding_wds =
382         if not (closureUpdReqd cl_info) then
383             []
384         else
385             case max 0 (mIN_UPD_SIZE - length amodes) of { still_needed ->
386             nOfThem still_needed (mkIntCLit 0) } -- a bunch of 0s
387
388     static_link_field
389         | staticClosureNeedsLink cl_info = [mkIntCLit 0]
390         | otherwise                      = []
391
392 pprAbsC stmt@(CClosureInfoAndCode cl_info slow maybe_fast cl_descr) _
393   = vcat [
394         hcat [
395              ptext SLIT("INFO_TABLE"),
396              ( if is_selector then
397                  ptext SLIT("_SELECTOR")
398                else if is_constr then
399                  ptext SLIT("_CONSTR")
400                else if needs_srt then
401                  ptext SLIT("_SRT")
402                else empty ), char '(',
403
404             pprCLabel info_lbl,                         comma,
405             pprCLabel slow_lbl,                         comma,
406             pp_rest, {- ptrs,nptrs,[srt,]type,-}        comma,
407
408             ppLocalness info_lbl,                          comma,
409             ppLocalnessMacro True{-include dyn-} slow_lbl, comma,
410
411             if_profiling pp_descr, comma,
412             if_profiling pp_type,
413             text ");"
414              ],
415         pp_slow,
416         case maybe_fast of
417             Nothing -> empty
418             Just fast -> let stuff = CCodeBlock fast_lbl fast in
419                          pprAbsC stuff (costs stuff)
420     ]
421   where
422     info_lbl    = infoTableLabelFromCI cl_info
423     fast_lbl    = fastLabelFromCI cl_info
424
425     (slow_lbl, pp_slow)
426       = case (nonemptyAbsC slow) of
427           Nothing -> (mkErrorStdEntryLabel, empty)
428           Just xx -> (entryLabelFromCI cl_info,
429                        let stuff = CCodeBlock slow_lbl xx in
430                        pprAbsC stuff (costs stuff))
431
432     maybe_selector = maybeSelectorInfo cl_info
433     is_selector = maybeToBool maybe_selector
434     (Just select_word_i) = maybe_selector
435
436     maybe_tag = closureSemiTag cl_info
437     is_constr = maybeToBool maybe_tag
438     (Just tag) = maybe_tag
439
440     needs_srt = infoTblNeedsSRT cl_info
441     srt = getSRTInfo cl_info
442
443     size = closureNonHdrSize cl_info
444
445     ptrs        = closurePtrsSize cl_info
446     nptrs       = size - ptrs
447
448     pp_rest | is_selector      = int select_word_i
449             | otherwise        = hcat [
450                   int ptrs,             comma,
451                   int nptrs,            comma,
452                   if is_constr then
453                         hcat [ int tag, comma ]
454                   else if needs_srt then
455                         pp_srt_info srt
456                   else empty,
457                   type_str ]
458
459     type_str = pprSMRep (closureSMRep cl_info)
460
461     pp_descr = hcat [char '"', text (stringToC cl_descr), char '"']
462     pp_type  = hcat [char '"', text (stringToC (closureTypeDescr cl_info)), char '"']
463
464 pprAbsC stmt@(CRetDirect uniq code srt liveness) _
465   = vcat [
466       hcat [
467           ptext SLIT("INFO_TABLE_SRT_BITMAP"), lparen, 
468           pprCLabel info_lbl,           comma,
469           pprCLabel entry_lbl,          comma,
470           pp_liveness liveness,         comma,    -- bitmap
471           pp_srt_info srt,                        -- SRT
472           ptext type_str,               comma,    -- closure type
473           ppLocalness info_lbl,         comma,    -- info table storage class
474           ppLocalnessMacro True{-include dyn-} entry_lbl,       comma,    -- entry pt storage class
475           int 0, comma,
476           int 0, text ");"
477       ],
478       pp_code
479     ]
480   where
481      info_lbl  = mkReturnInfoLabel uniq
482      entry_lbl = mkReturnPtLabel uniq
483
484      pp_code   = let stuff = CCodeBlock entry_lbl code in
485                  pprAbsC stuff (costs stuff)
486
487      type_str = case liveness of
488                    LvSmall _ -> SLIT("RET_SMALL")
489                    LvLarge _ -> SLIT("RET_BIG")
490
491 pprAbsC stmt@(CRetVector label amodes srt liveness) _
492   = vcat [
493         pp_vector,
494         hcat [
495         ptext SLIT("  }"), comma, ptext SLIT("\n  VEC_INFO_TABLE"),
496         lparen, 
497         pp_liveness liveness, comma,    -- bitmap liveness mask
498         pp_srt_info srt,                -- SRT
499         ptext type_str,                 -- or big, depending on the size
500                                         -- of the liveness mask.
501         rparen 
502        ],
503        text "};"
504     ]
505
506   where
507     pp_vector = 
508         case (pprTempAndExternDecls stmt) of { (_, pp_exts) ->
509          vcat [
510             pp_exts,
511             hcat [ppLocalness label,
512                   ptext SLIT(" vec_info_"), int size, space,
513                   pprCLabel label, text "= { {"
514                   ],
515             nest 2 (sep (punctuate comma (map ppr_item (reverse amodes))))
516             ] }
517
518     ppr_item item = (<>) (text "(F_) ") (ppr_amode item)
519     size = length amodes
520
521     type_str = case liveness of
522                    LvSmall _ -> SLIT("RET_VEC_SMALL")
523                    LvLarge _ -> SLIT("RET_VEC_BIG")
524
525
526 pprAbsC (CCostCentreDecl is_local cc) _ = pprCostCentreDecl is_local cc
527 pprAbsC (CCostCentreStackDecl ccs)    _ = pprCostCentreStackDecl ccs
528 \end{code}
529
530 \begin{code}
531 ppLocalness label
532   = (<>) static const
533   where
534     static = if (externallyVisibleCLabel label) 
535                 then empty 
536                 else ptext SLIT("static ")
537     const  = if not (isReadOnly label)          
538                 then empty 
539                 else ptext SLIT("const")
540
541 -- Horrible macros for declaring the types and locality of labels (see
542 -- StgMacros.h).
543
544 ppLocalnessMacro include_dyn_prefix clabel =
545      hcat [
546         visiblity_prefix,
547         dyn_prefix,
548         case label_type of
549           ClosureType -> ptext SLIT("C_")
550           CodeType    -> ptext SLIT("F_")
551           InfoTblType -> ptext SLIT("I_")
552           DataType    -> ptext SLIT("D_") <>
553                                    if isReadOnly clabel 
554                                       then ptext SLIT("RO_") 
555                                       else empty 
556      ]
557   where
558    is_visible = externallyVisibleCLabel clabel
559    label_type = labelType clabel
560    is_dynamic = labelDynamic clabel
561
562    visiblity_prefix
563      | is_visible = char 'E'
564      | otherwise  = char 'I'
565
566    dyn_prefix
567      | not include_dyn_prefix = empty
568      | is_dynamic             = char 'D'
569      | otherwise              = empty
570
571 \end{code}
572
573 \begin{code}
574 jmp_lit = "JMP_("
575
576 grab_non_void_amodes amodes
577   = filter non_void amodes
578
579 non_void amode
580   = case (getAmodeRep amode) of
581       VoidRep -> False
582       k -> True
583 \end{code}
584
585 \begin{code}
586 ppr_vol_regs :: [MagicId] -> (SDoc, SDoc)
587
588 ppr_vol_regs [] = (empty, empty)
589 ppr_vol_regs (VoidReg:rs) = ppr_vol_regs rs
590 ppr_vol_regs (r:rs)
591   = let pp_reg = case r of
592                     VanillaReg pk n -> pprVanillaReg n
593                     _ -> pprMagicId r
594         (more_saves, more_restores) = ppr_vol_regs rs
595     in
596     (($$) ((<>) (ptext SLIT("CALLER_SAVE_"))    pp_reg) more_saves,
597      ($$) ((<>) (ptext SLIT("CALLER_RESTORE_")) pp_reg) more_restores)
598
599 -- pp_basic_{saves,restores}: The BaseReg, SpA, SuA, SpB, SuB, Hp and
600 -- HpLim (see StgRegs.lh) may need to be saved/restored around CCalls,
601 -- depending on the platform.  (The "volatile regs" stuff handles all
602 -- other registers.)  Just be *sure* BaseReg is OK before trying to do
603 -- anything else. The correct sequence of saves&restores are
604 -- encoded by the CALLER_*_SYSTEM macros.
605 pp_basic_saves
606   = vcat
607        [ ptext SLIT("CALLER_SAVE_Base")
608        , ptext SLIT("CALLER_SAVE_SYSTEM")
609        ]
610
611 pp_basic_restores = ptext SLIT("CALLER_RESTORE_SYSTEM")
612 \end{code}
613
614 \begin{code}
615 has_srt (_, NoSRT) = False
616 has_srt _ = True
617
618 pp_srt_info srt = 
619     case srt of
620         (lbl, NoSRT) -> 
621                 hcat [  int 0, comma, 
622                         int 0, comma, 
623                         int 0, comma ]
624         (lbl, SRT off len) -> 
625                 hcat [  pprCLabel lbl, comma,
626                         int off, comma,
627                         int len, comma ]
628 \end{code}
629
630 \begin{code}
631 if_profiling pretty
632   = if  opt_SccProfilingOn
633     then pretty
634     else char '0' -- leave it out!
635 -- ---------------------------------------------------------------------------
636 -- Changes for GrAnSim:
637 --  draw costs for computation in head of if into both branches;
638 --  as no abstractC data structure is given for the head, one is constructed
639 --  guessing unknown values and fed into the costs function
640 -- ---------------------------------------------------------------------------
641
642 do_if_stmt discrim tag alt_code deflt c
643   = case tag of
644       -- This special case happens when testing the result of a comparison.
645       -- We can just avoid some redundant clutter in the output.
646       MachInt n _ | n==0 -> ppr_if_stmt (pprAmode discrim)
647                                       deflt alt_code
648                                       (addrModeCosts discrim Rhs) c
649       other              -> let
650                                cond = hcat [ pprAmode discrim
651                                            , ptext SLIT(" == ")
652                                            , tcast
653                                            , pprAmode (CLit tag)
654                                            ]
655                                 -- to be absolutely sure that none of the 
656                                 -- conversion rules hit, e.g.,
657                                 --
658                                 --     minInt is different to (int)minInt
659                                 --
660                                 -- in C (when minInt is a number not a constant
661                                 --  expression which evaluates to it.)
662                                 -- 
663                                tcast =
664                                  case other of
665                                    MachInt _ signed | signed    -> ptext SLIT("(I_)")
666                                    _ -> empty
667                             in
668                             ppr_if_stmt cond
669                                          alt_code deflt
670                                          (addrModeCosts discrim Rhs) c
671
672 ppr_if_stmt pp_pred then_part else_part discrim_costs c
673   = vcat [
674       hcat [text "if (", pp_pred, text ") {"],
675       nest 8 (pprAbsC then_part         (c + discrim_costs +
676                                         (Cost (0, 2, 0, 0, 0)) +
677                                         costs then_part)),
678       (case nonemptyAbsC else_part of Nothing -> empty; Just _ -> text "} else {"),
679       nest 8 (pprAbsC else_part  (c + discrim_costs +
680                                         (Cost (0, 1, 0, 0, 0)) +
681                                         costs else_part)),
682       char '}' ]
683     {- Total costs = inherited costs (before if) + costs for accessing discrim
684                      + costs for cond branch ( = (0, 1, 0, 0, 0) )
685                      + costs for that alternative
686     -}
687 \end{code}
688
689 Historical note: this used to be two separate cases -- one for `ccall'
690 and one for `casm'.  To get round a potential limitation to only 10
691 arguments, the numbering of arguments in @process_casm@ was beefed up a
692 bit. ADR
693
694 Some rough notes on generating code for @CCallOp@:
695
696 1) Evaluate all arguments and stuff them into registers. (done elsewhere)
697 2) Save any essential registers (heap, stack, etc).
698
699    ToDo: If stable pointers are in use, these must be saved in a place
700    where the runtime system can get at them so that the Stg world can
701    be restarted during the call.
702
703 3) Save any temporary registers that are currently in use.
704 4) Do the call, putting result into a local variable
705 5) Restore essential registers
706 6) Restore temporaries
707
708    (This happens after restoration of essential registers because we
709    might need the @Base@ register to access all the others correctly.)
710
711    Otherwise, copy local variable into result register.
712
713 8) If ccall (not casm), declare the function being called as extern so
714    that C knows if it returns anything other than an int.
715
716 \begin{pseudocode}
717 { ResultType _ccall_result;
718   basic_saves;
719   saves;
720   _ccall_result = f( args );
721   basic_restores;
722   restores;
723
724   return_reg = _ccall_result;
725 }
726 \end{pseudocode}
727
728 Amendment to the above: if we can GC, we have to:
729
730 * make sure we save all our registers away where the garbage collector
731   can get at them.
732 * be sure that there are no live registers or we're in trouble.
733   (This can cause problems if you try something foolish like passing
734    an array or a foreign obj to a _ccall_GC_ thing.)
735 * increment/decrement the @inCCallGC@ counter before/after the call so
736   that the runtime check that PerformGC is being used sensibly will work.
737
738 \begin{code}
739 pprCCall op@(CCallOp op_str is_asm may_gc cconv) args results vol_regs
740   = vcat [
741       char '{',
742       declare_local_vars,   -- local var for *result*
743       vcat local_arg_decls,
744       pp_save_context,
745         declare_fun_extern,   -- declare expected function type.
746         process_casm local_vars pp_non_void_args casm_str,
747       pp_restore_context,
748       assign_results,
749       char '}'
750     ]
751   where
752     (pp_saves, pp_restores) = ppr_vol_regs vol_regs
753     (pp_save_context, pp_restore_context)
754         | may_gc  = ( text "do { SaveThreadState();"
755                     , text "LoadThreadState();} while(0);"
756                     )
757         | otherwise = ( pp_basic_saves $$ pp_saves,
758                         pp_basic_restores $$ pp_restores)
759
760     non_void_args =
761         let nvas = tail args
762         in ASSERT (all non_void nvas) nvas
763     -- the first argument will be the "I/O world" token (a VoidRep)
764     -- all others should be non-void
765
766     non_void_results =
767         let nvrs = grab_non_void_amodes results
768         in ASSERT (length nvrs <= 1) nvrs
769     -- there will usually be two results: a (void) state which we
770     -- should ignore and a (possibly void) result.
771
772     (local_arg_decls, pp_non_void_args)
773       = unzip [ ppr_casm_arg a i | (a,i) <- non_void_args `zip` [1..] ]
774
775
776     {-
777       In the non-casm case, to ensure that we're entering the given external
778       entry point using the correct calling convention, we have to do the following:
779
780         - When entering via a function pointer (the `dynamic' case) using the specified
781           calling convention, we emit a typedefn declaration attributed with the
782           calling convention to use together with the result and parameter types we're
783           assuming. Coerce the function pointer to this type and go.
784
785         - to enter the function at a given code label, we emit an extern declaration
786           for the label here, stating the calling convention together with result and
787           argument types we're assuming. 
788
789           The C compiler will hopefully use this extern declaration to good effect,
790           reporting any discrepancies between our extern decl and any other that
791           may be in scope.
792     
793           Re: calling convention, notice that gcc (2.8.1 and egcs-1.0.2) will for
794           the external function `foo' use the calling convention of the first `foo'
795           prototype it encounters (nor does it complain about conflicting attribute
796           declarations). The consequence of this is that you cannot override the
797           calling convention of `foo' using an extern declaration (you'd have to use
798           a typedef), but why you would want to do such a thing in the first place
799           is totally beyond me.
800           
801           ToDo: petition the gcc folks to add code to warn about conflicting attribute
802           declarations.
803
804     -}
805     declare_fun_extern
806       | is_dynamic || is_asm || not opt_EmitCExternDecls = empty
807       | otherwise                           =
808          hsep [ typedef_or_extern
809               , ccall_res_ty
810               , fun_nm
811               , parens (hsep (punctuate comma ccall_decl_ty_args))
812               ] <> semi
813        where
814         typedef_or_extern
815           | is_dynamic     = ptext SLIT("typedef")
816           | otherwise      = ptext SLIT("extern")
817
818         fun_nm 
819           | is_dynamic     = parens (text (callConvAttribute cconv) <+> char '*' <> ccall_fun_ty)
820           | otherwise      = text (callConvAttribute cconv) <+> ptext asm_str
821
822           -- leave out function pointer
823         ccall_decl_ty_args
824           | is_dynamic     = tail ccall_arg_tys
825           | otherwise      = ccall_arg_tys
826
827     ccall_arg_tys = map (text.showPrimRep.getAmodeRep) non_void_args
828
829     ccall_res_ty = 
830        case non_void_results of
831           []       -> ptext SLIT("void")
832           [amode]  -> text (showPrimRep (getAmodeRep amode))
833           _        -> panic "pprCCall: ccall_res_ty"
834
835     ccall_fun_ty = 
836        ptext SLIT("_ccall_fun_ty") <>
837        case op_str of
838          Right u -> ppr u
839          _       -> empty
840
841     (declare_local_vars, local_vars, assign_results)
842       = ppr_casm_results non_void_results
843
844     (Left asm_str) = op_str
845     is_dynamic = 
846        case op_str of
847          Left _ -> False
848          _      -> True
849
850     casm_str = if is_asm then _UNPK_ asm_str else ccall_str
851
852     -- Remainder only used for ccall
853
854     fun_name 
855       | is_dynamic = parens (parens (ccall_fun_ty) <> text "%0")
856       | otherwise  = ptext asm_str
857
858     ccall_str = showSDoc
859         (hcat [
860                 if null non_void_results
861                   then empty
862                   else text "%r = ",
863                 lparen, fun_name, lparen,
864                   hcat (punctuate comma ccall_fun_args),
865                 text "));"
866         ])
867
868     ccall_fun_args
869      | is_dynamic = tail ccall_args
870      | otherwise  = ccall_args
871
872     ccall_args    = zipWith (\ _ i -> char '%' <> int i) non_void_args [0..]
873
874 \end{code}
875
876 If the argument is a heap object, we need to reach inside and pull out
877 the bit the C world wants to see.  The only heap objects which can be
878 passed are @Array@s and @ByteArray@s.
879
880 \begin{code}
881 ppr_casm_arg :: CAddrMode -> Int -> (SDoc, SDoc)
882     -- (a) decl and assignment, (b) local var to be used later
883
884 ppr_casm_arg amode a_num
885   = let
886         a_kind   = getAmodeRep amode
887         pp_amode = pprAmode amode
888         pp_kind  = pprPrimKind a_kind
889
890         local_var  = (<>) (ptext SLIT("_ccall_arg")) (int a_num)
891
892         (arg_type, pp_amode2)
893           = case a_kind of
894
895               -- for array arguments, pass a pointer to the body of the array
896               -- (PTRS_ARR_CTS skips over all the header nonsense)
897               ArrayRep      -> (pp_kind,
898                                 hcat [ptext SLIT("PTRS_ARR_CTS"),char '(', pp_amode, rparen])
899               ByteArrayRep -> (pp_kind,
900                                 hcat [ptext SLIT("BYTE_ARR_CTS"),char '(', pp_amode, rparen])
901
902               -- for ForeignObj, use FOREIGN_OBJ_DATA to fish out the contents.
903               ForeignObjRep -> (pp_kind,
904                                 hcat [ptext SLIT("ForeignObj_CLOSURE_DATA"),
905                                       char '(', pp_amode, char ')'])
906
907               other         -> (pp_kind, pp_amode)
908
909         declare_local_var
910           = hcat [ arg_type, space, local_var, equals, pp_amode2, semi ]
911     in
912     (declare_local_var, local_var)
913 \end{code}
914
915 For l-values, the critical questions are:
916
917 1) Are there any results at all?
918
919    We only allow zero or one results.
920
921 \begin{code}
922 ppr_casm_results
923         :: [CAddrMode]  -- list of results (length <= 1)
924         ->
925         ( SDoc,         -- declaration of any local vars
926           [SDoc],       -- list of result vars (same length as results)
927           SDoc )        -- assignment (if any) of results in local var to registers
928
929 ppr_casm_results []
930   = (empty, [], empty)  -- no results
931
932 ppr_casm_results [r]
933   = let
934         result_reg = ppr_amode r
935         r_kind     = getAmodeRep r
936
937         local_var  = ptext SLIT("_ccall_result")
938
939         (result_type, assign_result)
940           = (pprPrimKind r_kind,
941              hcat [ result_reg, equals, local_var, semi ])
942
943         declare_local_var = hcat [ result_type, space, local_var, semi ]
944     in
945     (declare_local_var, [local_var], assign_result)
946
947 ppr_casm_results rs
948   = panic "ppr_casm_results: ccall/casm with many results"
949 \end{code}
950
951
952 Note the sneaky way _the_ result is represented by a list so that we
953 can complain if it's used twice.
954
955 ToDo: Any chance of giving line numbers when process-casm fails?
956       Or maybe we should do a check _much earlier_ in compiler. ADR
957
958 \begin{code}
959 process_casm :: [SDoc]          -- results (length <= 1)
960              -> [SDoc]          -- arguments
961              -> String          -- format string (with embedded %'s)
962              -> SDoc            -- code being generated
963
964 process_casm results args string = process results args string
965  where
966   process []    _ "" = empty
967   process (_:_) _ "" = error ("process_casm: non-void result not assigned while processing _casm_ \"" ++ 
968                               string ++ 
969                               "\"\n(Try changing result type to PrimIO ()\n")
970
971   process ress args ('%':cs)
972     = case cs of
973         [] ->
974             error ("process_casm: lonely % while processing _casm_ \"" ++ string ++ "\".\n")
975
976         ('%':css) ->
977             char '%' <> process ress args css
978
979         ('r':css)  ->
980           case ress of
981             []  -> error ("process_casm: no result to match %r while processing _casm_ \"" ++ string ++ "\".\nTry deleting %r or changing result type from PrimIO ()\n")
982             [r] -> r <> (process [] args css)
983             _   -> panic ("process_casm: casm with many results while processing _casm_ \"" ++ string ++ "\".\n")
984
985         other ->
986           let
987                 read_int :: ReadS Int
988                 read_int = reads
989           in
990           case (read_int other) of
991             [(num,css)] ->
992                   if 0 <= num && num < length args
993                   then parens (args !! num) <> process ress args css
994                   else error ("process_casm: no such arg #:"++(show num)++" while processing \"" ++ string ++ "\".\n")
995             _ -> error ("process_casm: not %<num> while processing _casm_ \"" ++ string ++ "\".\n")
996
997   process ress args (other_c:cs)
998     = char other_c <> process ress args cs
999 \end{code}
1000
1001 %************************************************************************
1002 %*                                                                      *
1003 \subsection[a2r-assignments]{Assignments}
1004 %*                                                                      *
1005 %************************************************************************
1006
1007 Printing assignments is a little tricky because of type coercion.
1008
1009 First of all, the kind of the thing being assigned can be gotten from
1010 the destination addressing mode.  (It should be the same as the kind
1011 of the source addressing mode.)  If the kind of the assignment is of
1012 @VoidRep@, then don't generate any code at all.
1013
1014 \begin{code}
1015 pprAssign :: PrimRep -> CAddrMode -> CAddrMode -> SDoc
1016
1017 pprAssign VoidRep dest src = empty
1018 \end{code}
1019
1020 Special treatment for floats and doubles, to avoid unwanted conversions.
1021
1022 \begin{code}
1023 pprAssign FloatRep dest@(CVal reg_rel _) src
1024   = hcat [ ptext SLIT("ASSIGN_FLT"),char '(', ppr_amode (CAddr reg_rel), comma, pprAmode src, pp_paren_semi ]
1025
1026 pprAssign DoubleRep dest@(CVal reg_rel _) src
1027   = hcat [ ptext SLIT("ASSIGN_DBL"),char '(', ppr_amode (CAddr reg_rel), comma, pprAmode src, pp_paren_semi ]
1028
1029 pprAssign Int64Rep dest@(CVal reg_rel _) src
1030   = hcat [ ptext SLIT("ASSIGN_Int64"),char '(', ppr_amode (CAddr reg_rel), comma, pprAmode src, pp_paren_semi ]
1031 pprAssign Word64Rep dest@(CVal reg_rel _) src
1032   = hcat [ ptext SLIT("ASSIGN_Word64"),char '(', ppr_amode (CAddr reg_rel), comma, pprAmode src, pp_paren_semi ]
1033 \end{code}
1034
1035 Lastly, the question is: will the C compiler think the types of the
1036 two sides of the assignment match?
1037
1038         We assume that the types will match
1039         if neither side is a @CVal@ addressing mode for any register
1040         which can point into the heap or B stack.
1041
1042 Why?  Because the heap and B stack are used to store miscellaneous things,
1043 whereas the A stack, temporaries, registers, etc., are only used for things
1044 of fixed type.
1045
1046 \begin{code}
1047 pprAssign kind (CReg (VanillaReg _ dest)) (CReg (VanillaReg _ src))
1048   = hcat [ pprVanillaReg dest, equals,
1049                 pprVanillaReg src, semi ]
1050
1051 pprAssign kind dest src
1052   | mixedTypeLocn dest
1053     -- Add in a cast to StgWord (a.k.a. W_) iff the destination is mixed
1054   = hcat [ ppr_amode dest, equals,
1055                 text "(W_)(",   -- Here is the cast
1056                 ppr_amode src, pp_paren_semi ]
1057
1058 pprAssign kind dest src
1059   | mixedPtrLocn dest && getAmodeRep src /= PtrRep
1060     -- Add in a cast to StgPtr (a.k.a. P_) iff the destination is mixed
1061   = hcat [ ppr_amode dest, equals,
1062                 text "(P_)(",   -- Here is the cast
1063                 ppr_amode src, pp_paren_semi ]
1064
1065 pprAssign ByteArrayRep dest src
1066   | mixedPtrLocn src
1067     -- Add in a cast iff the source is mixed
1068   = hcat [ ppr_amode dest, equals,
1069                 text "(StgByteArray)(", -- Here is the cast
1070                 ppr_amode src, pp_paren_semi ]
1071
1072 pprAssign kind other_dest src
1073   = hcat [ ppr_amode other_dest, equals,
1074                 pprAmode  src, semi ]
1075 \end{code}
1076
1077
1078 %************************************************************************
1079 %*                                                                      *
1080 \subsection[a2r-CAddrModes]{Addressing modes}
1081 %*                                                                      *
1082 %************************************************************************
1083
1084 @pprAmode@ is used to print r-values (which may need casts), whereas
1085 @ppr_amode@ is used for l-values {\em and} as a help function for
1086 @pprAmode@.
1087
1088 \begin{code}
1089 pprAmode, ppr_amode :: CAddrMode -> SDoc
1090 \end{code}
1091
1092 For reasons discussed above under assignments, @CVal@ modes need
1093 to be treated carefully.  First come special cases for floats and doubles,
1094 similar to those in @pprAssign@:
1095
1096 (NB: @PK_FLT@ and @PK_DBL@ require the {\em address} of the value in
1097 question.)
1098
1099 \begin{code}
1100 pprAmode (CVal reg_rel FloatRep)
1101   = hcat [ text "PK_FLT(", ppr_amode (CAddr reg_rel), rparen ]
1102 pprAmode (CVal reg_rel DoubleRep)
1103   = hcat [ text "PK_DBL(", ppr_amode (CAddr reg_rel), rparen ]
1104 pprAmode (CVal reg_rel Int64Rep)
1105   = hcat [ text "PK_Int64(", ppr_amode (CAddr reg_rel), rparen ]
1106 pprAmode (CVal reg_rel Word64Rep)
1107   = hcat [ text "PK_Word64(", ppr_amode (CAddr reg_rel), rparen ]
1108 \end{code}
1109
1110 Next comes the case where there is some other cast need, and the
1111 no-cast case:
1112
1113 \begin{code}
1114 pprAmode amode
1115   | mixedTypeLocn amode
1116   = parens (hcat [ pprPrimKind (getAmodeRep amode), ptext SLIT(")("),
1117                 ppr_amode amode ])
1118   | otherwise   -- No cast needed
1119   = ppr_amode amode
1120 \end{code}
1121
1122 Now the rest of the cases for ``workhorse'' @ppr_amode@:
1123
1124 \begin{code}
1125 ppr_amode (CVal reg_rel _)
1126   = case (pprRegRelative False{-no sign wanted-} reg_rel) of
1127         (pp_reg, Nothing)     -> (<>)  (char '*') pp_reg
1128         (pp_reg, Just offset) -> hcat [ pp_reg, brackets offset ]
1129
1130 ppr_amode (CAddr reg_rel)
1131   = case (pprRegRelative True{-sign wanted-} reg_rel) of
1132         (pp_reg, Nothing)     -> pp_reg
1133         (pp_reg, Just offset) -> (<>) pp_reg offset
1134
1135 ppr_amode (CReg magic_id) = pprMagicId magic_id
1136
1137 ppr_amode (CTemp uniq kind) = char '_' <> pprUnique uniq <> char '_'
1138
1139 ppr_amode (CLbl label kind) = pprCLabelAddr label 
1140
1141 ppr_amode (CCharLike ch)
1142   = hcat [ptext SLIT("CHARLIKE_CLOSURE"), char '(', pprAmode ch, rparen ]
1143 ppr_amode (CIntLike int)
1144   = hcat [ptext SLIT("INTLIKE_CLOSURE"), char '(', pprAmode int, rparen ]
1145
1146 ppr_amode (CString str) = hcat [char '"', text (stringToC (_UNPK_ str)), char '"']
1147   -- ToDo: are these *used* for anything?
1148
1149 ppr_amode (CLit lit) = pprBasicLit lit
1150
1151 ppr_amode (CLitLit str _) = ptext str
1152
1153 ppr_amode (CJoinPoint _)
1154   = panic "ppr_amode: CJoinPoint"
1155
1156 ppr_amode (CTableEntry base index kind)
1157   = hcat [text "((", pprPrimKind kind, text " *)(",
1158                ppr_amode base, text "))[(I_)(", ppr_amode index,
1159                ptext SLIT(")]")]
1160
1161 ppr_amode (CMacroExpr pk macro as)
1162   = parens (pprPrimKind pk) <+> 
1163     parens (text (show macro) <> 
1164             parens (hcat (punctuate comma (map pprAmode as))))
1165 \end{code}
1166
1167 %************************************************************************
1168 %*                                                                      *
1169 \subsection[ppr-liveness-masks]{Liveness Masks}
1170 %*                                                                      *
1171 %************************************************************************
1172
1173 \begin{code}
1174 pp_liveness :: Liveness -> SDoc
1175 pp_liveness lv = 
1176    case lv of
1177         LvSmall mask -> int (intBS mask)
1178         LvLarge lbl  -> char '&' <> pprCLabel lbl
1179 \end{code}
1180
1181 %************************************************************************
1182 %*                                                                      *
1183 \subsection[a2r-MagicIds]{Magic ids}
1184 %*                                                                      *
1185 %************************************************************************
1186
1187 @pprRegRelative@ returns a pair of the @Doc@ for the register
1188 (some casting may be required), and a @Maybe Doc@ for the offset
1189 (zero offset gives a @Nothing@).
1190
1191 \begin{code}
1192 addPlusSign :: Bool -> SDoc -> SDoc
1193 addPlusSign False p = p
1194 addPlusSign True  p = (<>) (char '+') p
1195
1196 pprSignedInt :: Bool -> Int -> Maybe SDoc       -- Nothing => 0
1197 pprSignedInt sign_wanted n
1198  = if n == 0 then Nothing else
1199    if n > 0  then Just (addPlusSign sign_wanted (int n))
1200    else           Just (int n)
1201
1202 pprRegRelative :: Bool          -- True <=> Print leading plus sign (if +ve)
1203                -> RegRelative
1204                -> (SDoc, Maybe SDoc)
1205
1206 pprRegRelative sign_wanted (SpRel off)
1207   = (pprMagicId Sp, pprSignedInt sign_wanted (I# off))
1208
1209 pprRegRelative sign_wanted r@(HpRel o)
1210   = let pp_Hp    = pprMagicId Hp; off = I# o
1211     in
1212     if off == 0 then
1213         (pp_Hp, Nothing)
1214     else
1215         (pp_Hp, Just ((<>) (char '-') (int off)))
1216
1217 pprRegRelative sign_wanted (NodeRel o)
1218   = let pp_Node = pprMagicId node; off = I# o
1219     in
1220     if off == 0 then
1221         (pp_Node, Nothing)
1222     else
1223         (pp_Node, Just (addPlusSign sign_wanted (int off)))
1224
1225 \end{code}
1226
1227 @pprMagicId@ just prints the register name.  @VanillaReg@ registers are
1228 represented by a discriminated union (@StgUnion@), so we use the @PrimRep@
1229 to select the union tag.
1230
1231 \begin{code}
1232 pprMagicId :: MagicId -> SDoc
1233
1234 pprMagicId BaseReg                  = ptext SLIT("BaseReg")
1235 pprMagicId (VanillaReg pk n)
1236                                     = hcat [ pprVanillaReg n, char '.',
1237                                                   pprUnionTag pk ]
1238 pprMagicId (FloatReg  n)            = (<>) (ptext SLIT("F")) (int IBOX(n))
1239 pprMagicId (DoubleReg n)            = (<>) (ptext SLIT("D")) (int IBOX(n))
1240 pprMagicId (LongReg _ n)            = (<>) (ptext SLIT("L")) (int IBOX(n))
1241 pprMagicId Sp                       = ptext SLIT("Sp")
1242 pprMagicId Su                       = ptext SLIT("Su")
1243 pprMagicId SpLim                    = ptext SLIT("SpLim")
1244 pprMagicId Hp                       = ptext SLIT("Hp")
1245 pprMagicId HpLim                    = ptext SLIT("HpLim")
1246 pprMagicId CurCostCentre            = ptext SLIT("CCCS")
1247 pprMagicId VoidReg                  = panic "pprMagicId:VoidReg!"
1248
1249 pprVanillaReg :: FAST_INT -> SDoc
1250 pprVanillaReg n = (<>) (char 'R') (int IBOX(n))
1251
1252 pprUnionTag :: PrimRep -> SDoc
1253
1254 pprUnionTag PtrRep              = char 'p'
1255 pprUnionTag CodePtrRep          = ptext SLIT("fp")
1256 pprUnionTag DataPtrRep          = char 'd'
1257 pprUnionTag RetRep              = char 'p'
1258 pprUnionTag CostCentreRep       = panic "pprUnionTag:CostCentre?"
1259
1260 pprUnionTag CharRep             = char 'c'
1261 pprUnionTag IntRep              = char 'i'
1262 pprUnionTag WordRep             = char 'w'
1263 pprUnionTag AddrRep             = char 'a'
1264 pprUnionTag FloatRep            = char 'f'
1265 pprUnionTag DoubleRep           = panic "pprUnionTag:Double?"
1266
1267 pprUnionTag StablePtrRep        = char 'i'
1268 pprUnionTag StableNameRep       = char 'p'
1269 pprUnionTag WeakPtrRep          = char 'p'
1270 pprUnionTag ForeignObjRep       = char 'p'
1271
1272 pprUnionTag ThreadIdRep         = char 't'
1273
1274 pprUnionTag ArrayRep            = char 'p'
1275 pprUnionTag ByteArrayRep        = char 'b'
1276
1277 pprUnionTag _                   = panic "pprUnionTag:Odd kind"
1278 \end{code}
1279
1280
1281 Find and print local and external declarations for a list of
1282 Abstract~C statements.
1283 \begin{code}
1284 pprTempAndExternDecls :: AbstractC -> (SDoc{-temps-}, SDoc{-externs-})
1285 pprTempAndExternDecls AbsCNop = (empty, empty)
1286
1287 pprTempAndExternDecls (AbsCStmts stmt1 stmt2)
1288   = initTE (ppr_decls_AbsC stmt1        `thenTE` \ (t_p1, e_p1) ->
1289             ppr_decls_AbsC stmt2        `thenTE` \ (t_p2, e_p2) ->
1290             case (catMaybes [t_p1, t_p2])        of { real_temps ->
1291             case (catMaybes [e_p1, e_p2])        of { real_exts ->
1292             returnTE (vcat real_temps, vcat real_exts) }}
1293            )
1294
1295 pprTempAndExternDecls other_stmt
1296   = initTE (ppr_decls_AbsC other_stmt `thenTE` \ (maybe_t, maybe_e) ->
1297             returnTE (
1298                 case maybe_t of
1299                   Nothing -> empty
1300                   Just pp -> pp,
1301
1302                 case maybe_e of
1303                   Nothing -> empty
1304                   Just pp -> pp )
1305            )
1306
1307 pprBasicLit :: Literal -> SDoc
1308 pprPrimKind :: PrimRep -> SDoc
1309
1310 pprBasicLit  lit = ppr lit
1311 pprPrimKind  k   = ppr k
1312 \end{code}
1313
1314
1315 %************************************************************************
1316 %*                                                                      *
1317 \subsection[a2r-monad]{Monadery}
1318 %*                                                                      *
1319 %************************************************************************
1320
1321 We need some monadery to keep track of temps and externs we have already
1322 printed.  This info must be threaded right through the Abstract~C, so
1323 it's most convenient to hide it in this monad.
1324
1325 WDP 95/02: Switched from \tr{([Unique], [CLabel])} to
1326 \tr{(UniqSet, CLabelSet)}.  Allegedly for efficiency.
1327
1328 \begin{code}
1329 type CLabelSet = FiniteMap CLabel (){-any type will do-}
1330 emptyCLabelSet = emptyFM
1331 x `elementOfCLabelSet` labs
1332   = case (lookupFM labs x) of { Just _ -> True; Nothing -> False }
1333
1334 addToCLabelSet set x = addToFM set x ()
1335
1336 type TEenv = (UniqSet Unique, CLabelSet)
1337
1338 type TeM result =  TEenv -> (TEenv, result)
1339
1340 initTE :: TeM a -> a
1341 initTE sa
1342   = case sa (emptyUniqSet, emptyCLabelSet) of { (_, result) ->
1343     result }
1344
1345 {-# INLINE thenTE #-}
1346 {-# INLINE returnTE #-}
1347
1348 thenTE :: TeM a -> (a -> TeM b) -> TeM b
1349 thenTE a b u
1350   = case a u        of { (u_1, result_of_a) ->
1351     b result_of_a u_1 }
1352
1353 mapTE :: (a -> TeM b) -> [a] -> TeM [b]
1354 mapTE f []     = returnTE []
1355 mapTE f (x:xs)
1356   = f x         `thenTE` \ r  ->
1357     mapTE f xs  `thenTE` \ rs ->
1358     returnTE (r : rs)
1359
1360 returnTE :: a -> TeM a
1361 returnTE result env = (env, result)
1362
1363 -- these next two check whether the thing is already
1364 -- recorded, and THEN THEY RECORD IT
1365 -- (subsequent calls will return False for the same uniq/label)
1366
1367 tempSeenTE :: Unique -> TeM Bool
1368 tempSeenTE uniq env@(seen_uniqs, seen_labels)
1369   = if (uniq `elementOfUniqSet` seen_uniqs)
1370     then (env, True)
1371     else ((addOneToUniqSet seen_uniqs uniq,
1372           seen_labels),
1373           False)
1374
1375 labelSeenTE :: CLabel -> TeM Bool
1376 labelSeenTE label env@(seen_uniqs, seen_labels)
1377   = if (label `elementOfCLabelSet` seen_labels)
1378     then (env, True)
1379     else ((seen_uniqs,
1380           addToCLabelSet seen_labels label),
1381           False)
1382 \end{code}
1383
1384 \begin{code}
1385 pprTempDecl :: Unique -> PrimRep -> SDoc
1386 pprTempDecl uniq kind
1387   = hcat [ pprPrimKind kind, space, char '_', pprUnique uniq, ptext SLIT("_;") ]
1388
1389 pprExternDecl :: Bool -> CLabel -> SDoc
1390 pprExternDecl in_srt clabel
1391   | not (needsCDecl clabel) = empty -- do not print anything for "known external" things
1392   | otherwise               = 
1393         hcat [ ppLocalnessMacro (not in_srt) clabel, 
1394                lparen, dyn_wrapper (pprCLabel clabel), pp_paren_semi ]
1395  where
1396   dyn_wrapper d
1397     | in_srt && labelDynamic clabel = text "DLL_IMPORT_DATA_VAR" <> parens d
1398     | otherwise                     = d
1399
1400 \end{code}
1401
1402 \begin{code}
1403 ppr_decls_AbsC :: AbstractC -> TeM (Maybe SDoc{-temps-}, Maybe SDoc{-externs-})
1404
1405 ppr_decls_AbsC AbsCNop          = returnTE (Nothing, Nothing)
1406
1407 ppr_decls_AbsC (AbsCStmts stmts_1 stmts_2)
1408   = ppr_decls_AbsC stmts_1  `thenTE` \ p1 ->
1409     ppr_decls_AbsC stmts_2  `thenTE` \ p2 ->
1410     returnTE (maybe_vcat [p1, p2])
1411
1412 ppr_decls_AbsC (CSplitMarker) = returnTE (Nothing, Nothing)
1413
1414 ppr_decls_AbsC (CAssign dest source)
1415   = ppr_decls_Amode dest    `thenTE` \ p1 ->
1416     ppr_decls_Amode source  `thenTE` \ p2 ->
1417     returnTE (maybe_vcat [p1, p2])
1418
1419 ppr_decls_AbsC (CJump target) = ppr_decls_Amode target
1420
1421 ppr_decls_AbsC (CFallThrough target) = ppr_decls_Amode target
1422
1423 ppr_decls_AbsC (CReturn target _) = ppr_decls_Amode target
1424
1425 ppr_decls_AbsC (CSwitch discrim alts deflt)
1426   = ppr_decls_Amode discrim     `thenTE` \ pdisc ->
1427     mapTE ppr_alt_stuff alts    `thenTE` \ palts  ->
1428     ppr_decls_AbsC deflt        `thenTE` \ pdeflt ->
1429     returnTE (maybe_vcat (pdisc:pdeflt:palts))
1430   where
1431     ppr_alt_stuff (_, absC) = ppr_decls_AbsC absC
1432
1433 ppr_decls_AbsC (CCodeBlock label absC)
1434   = ppr_decls_AbsC absC
1435
1436 ppr_decls_AbsC (CInitHdr cl_info reg_rel cost_centre)
1437         -- ToDo: strictly speaking, should chk "cost_centre" amode
1438   = labelSeenTE info_lbl     `thenTE` \  label_seen ->
1439     returnTE (Nothing,
1440               if label_seen then
1441                   Nothing
1442               else
1443                   Just (pprExternDecl False{-not in an SRT decl-} info_lbl))
1444   where
1445     info_lbl = infoTableLabelFromCI cl_info
1446
1447 ppr_decls_AbsC (COpStmt results _ args _) = ppr_decls_Amodes (results ++ args)
1448 ppr_decls_AbsC (CSimultaneous abc)          = ppr_decls_AbsC abc
1449
1450 ppr_decls_AbsC (CCheck              _ amodes code) = 
1451      ppr_decls_Amodes amodes `thenTE` \p1 ->
1452      ppr_decls_AbsC code     `thenTE` \p2 ->
1453      returnTE (maybe_vcat [p1,p2])
1454
1455 ppr_decls_AbsC (CMacroStmt          _ amodes)   = ppr_decls_Amodes amodes
1456
1457 ppr_decls_AbsC (CCallProfCtrMacro   _ amodes)   = ppr_decls_Amodes [] -- *****!!!
1458   -- you get some nasty re-decls of stdio.h if you compile
1459   -- the prelude while looking inside those amodes;
1460   -- no real reason to, anyway.
1461 ppr_decls_AbsC (CCallProfCCMacro    _ amodes)   = ppr_decls_Amodes amodes
1462
1463 ppr_decls_AbsC (CStaticClosure closure_lbl closure_info cost_centre amodes)
1464         -- ToDo: strictly speaking, should chk "cost_centre" amode
1465   = ppr_decls_Amodes amodes
1466
1467 ppr_decls_AbsC (CClosureInfoAndCode cl_info slow maybe_fast _)
1468   = ppr_decls_Amodes [entry_lbl]                `thenTE` \ p1 ->
1469     ppr_decls_AbsC slow                         `thenTE` \ p2 ->
1470     (case maybe_fast of
1471         Nothing   -> returnTE (Nothing, Nothing)
1472         Just fast -> ppr_decls_AbsC fast)       `thenTE` \ p3 ->
1473     returnTE (maybe_vcat [p1, p2, p3])
1474   where
1475     entry_lbl = CLbl slow_lbl CodePtrRep
1476     slow_lbl    = case (nonemptyAbsC slow) of
1477                     Nothing -> mkErrorStdEntryLabel
1478                     Just _  -> entryLabelFromCI cl_info
1479
1480 ppr_decls_AbsC (CSRT lbl closure_lbls)
1481   = mapTE labelSeenTE closure_lbls              `thenTE` \ seen ->
1482     returnTE (Nothing, 
1483               if and seen then Nothing
1484                 else Just (vcat [ pprExternDecl True{-in SRT decl-} l
1485                                 | (l,False) <- zip closure_lbls seen ]))
1486
1487 ppr_decls_AbsC (CRetDirect     _ code _ _)   = ppr_decls_AbsC code
1488 ppr_decls_AbsC (CRetVector _ amodes _ _)     = ppr_decls_Amodes amodes
1489 \end{code}
1490
1491 \begin{code}
1492 ppr_decls_Amode :: CAddrMode -> TeM (Maybe SDoc, Maybe SDoc)
1493 ppr_decls_Amode (CVal _ _)      = returnTE (Nothing, Nothing)
1494 ppr_decls_Amode (CAddr _)       = returnTE (Nothing, Nothing)
1495 ppr_decls_Amode (CReg _)        = returnTE (Nothing, Nothing)
1496 ppr_decls_Amode (CString _)     = returnTE (Nothing, Nothing)
1497 ppr_decls_Amode (CLit _)        = returnTE (Nothing, Nothing)
1498 ppr_decls_Amode (CLitLit _ _)   = returnTE (Nothing, Nothing)
1499
1500 -- CIntLike must be a literal -- no decls
1501 ppr_decls_Amode (CIntLike int)  = returnTE (Nothing, Nothing)
1502
1503 -- CCharLike may have be arbitrary value -- may have decls
1504 ppr_decls_Amode (CCharLike char)
1505   = ppr_decls_Amode char
1506
1507 -- now, the only place where we actually print temps/externs...
1508 ppr_decls_Amode (CTemp uniq kind)
1509   = case kind of
1510       VoidRep -> returnTE (Nothing, Nothing)
1511       other ->
1512         tempSeenTE uniq `thenTE` \ temp_seen ->
1513         returnTE
1514           (if temp_seen then Nothing else Just (pprTempDecl uniq kind), Nothing)
1515
1516 ppr_decls_Amode (CLbl label VoidRep)
1517   = returnTE (Nothing, Nothing)
1518
1519 ppr_decls_Amode (CLbl label kind)
1520   = labelSeenTE label `thenTE` \ label_seen ->
1521     returnTE (Nothing,
1522               if label_seen then Nothing else Just (pprExternDecl False{-not in an SRT decl-} label))
1523
1524 ppr_decls_Amode (CTableEntry base index _)
1525   = ppr_decls_Amode base    `thenTE` \ p1 ->
1526     ppr_decls_Amode index   `thenTE` \ p2 ->
1527     returnTE (maybe_vcat [p1, p2])
1528
1529 ppr_decls_Amode (CMacroExpr _ _ amodes)
1530   = ppr_decls_Amodes amodes
1531
1532 ppr_decls_Amode other = returnTE (Nothing, Nothing)
1533
1534
1535 maybe_vcat :: [(Maybe SDoc, Maybe SDoc)] -> (Maybe SDoc, Maybe SDoc)
1536 maybe_vcat ps
1537   = case (unzip ps)     of { (ts, es) ->
1538     case (catMaybes ts) of { real_ts  ->
1539     case (catMaybes es) of { real_es  ->
1540     (if (null real_ts) then Nothing else Just (vcat real_ts),
1541      if (null real_es) then Nothing else Just (vcat real_es))
1542     } } }
1543 \end{code}
1544
1545 \begin{code}
1546 ppr_decls_Amodes :: [CAddrMode] -> TeM (Maybe SDoc, Maybe SDoc)
1547 ppr_decls_Amodes amodes
1548   = mapTE ppr_decls_Amode amodes `thenTE` \ ps ->
1549     returnTE ( maybe_vcat ps )
1550 \end{code}
1551
1552 Print out a C Label where you want the *address* of the label, not the
1553 object it refers to.  The distinction is important when the label may
1554 refer to a C structure (info tables and closures, for instance).
1555
1556 When just generating a declaration for the label, use pprCLabel.
1557
1558 \begin{code}
1559 pprCLabelAddr :: CLabel -> SDoc
1560 pprCLabelAddr clabel =
1561   case labelType clabel of
1562      InfoTblType -> addr_of_label
1563      ClosureType -> addr_of_label
1564      VecTblType  -> addr_of_label
1565      _           -> pp_label
1566   where
1567     addr_of_label = ptext SLIT("(P_)&") <> pp_label
1568     pp_label = pprCLabel clabel
1569
1570 \end{code}
1571
1572 -----------------------------------------------------------------------------
1573 Initialising static objects with floating-point numbers.  We can't
1574 just emit the floating point number, because C will cast it to an int
1575 by rounding it.  We want the actual bit-representation of the float.
1576
1577 This is a hack to turn the floating point numbers into ints that we
1578 can safely initialise to static locations.
1579
1580 \begin{code}
1581 big_doubles = (getPrimRepSize DoubleRep) /= 1
1582
1583 -- floatss are always 1 word
1584 floatToWord :: CAddrMode -> CAddrMode
1585 floatToWord (CLit (MachFloat r))
1586   = runST (do
1587         arr <- newFloatArray ((0::Int),0)
1588         writeFloatArray arr 0 (fromRational r)
1589         i <- readIntArray arr 0
1590         return (CLit (MachInt (toInteger i) True))
1591     )
1592
1593 doubleToWords :: CAddrMode -> [CAddrMode]
1594 doubleToWords (CLit (MachDouble r))
1595   | big_doubles                         -- doubles are 2 words
1596   = runST (do
1597         arr <- newDoubleArray ((0::Int),1)
1598         writeDoubleArray arr 0 (fromRational r)
1599         i1 <- readIntArray arr 0
1600         i2 <- readIntArray arr 1
1601         return [ CLit (MachInt (toInteger i1) True)
1602                , CLit (MachInt (toInteger i2) True)
1603                ]
1604     )
1605   | otherwise                           -- doubles are 1 word
1606   = runST (do
1607         arr <- newDoubleArray ((0::Int),0)
1608         writeDoubleArray arr 0 (fromRational r)
1609         i <- readIntArray arr 0
1610         return [ CLit (MachInt (toInteger i) True) ]
1611     )
1612 \end{code}