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