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