2 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
4 %************************************************************************
6 \section[PprAbsC]{Pretty-printing Abstract~C}
8 %************************************************************************
18 #include "HsVersions.h"
25 import AbsCUtils ( getAmodeRep, nonemptyAbsC,
26 mixedPtrLocn, mixedTypeLocn
29 import ForeignCall ( CCallSpec(..), CCallTarget(..), playSafe,
30 playThreadSafe, ccallConvAttribute )
31 import CLabel ( externallyVisibleCLabel,
32 needsCDecl, pprCLabel, mkClosureLabel,
33 mkReturnInfoLabel, mkReturnPtLabel, mkClosureTblLabel,
34 CLabel, CLabelType(..), labelType, labelDynamic
37 import CmdLineOpts ( opt_SccProfilingOn, opt_GranMacros )
38 import CostCentre ( pprCostCentreDecl, pprCostCentreStackDecl )
40 import Costs ( costs, addrModeCosts, CostRes(..), Side(..) )
41 import CStrings ( pprCLabelString )
42 import FiniteMap ( addToFM, emptyFM, lookupFM, FiniteMap )
43 import Literal ( Literal(..) )
44 import TyCon ( tyConDataCons )
45 import Name ( NamedThing(..) )
46 import DataCon ( dataConWrapId )
47 import Maybes ( catMaybes )
48 import PrimOp ( primOpNeedsWrapper )
49 import MachOp ( MachOp(..) )
50 import ForeignCall ( ForeignCall(..) )
51 import PrimRep ( isFloatingRep, PrimRep(..), getPrimRepSize )
52 import Unique ( pprUnique, Unique{-instance NamedThing-} )
53 import UniqSet ( emptyUniqSet, elementOfUniqSet,
54 addOneToUniqSet, UniqSet
56 import StgSyn ( StgOp(..) )
57 import BitSet ( BitSet, intBS )
60 import Util ( lengthExceeds )
61 import Constants ( wORD_SIZE )
63 #if __GLASGOW_HASKELL__ >= 504
68 import Util ( listLengthCmp )
71 import Maybe ( isJust )
78 For spitting out the costs of an abstract~C expression, @writeRealC@
79 now not only prints the C~code of the @absC@ arg but also adds a macro
80 call to a cost evaluation function @GRAN_EXEC@. For that,
81 @pprAbsC@ has a new ``costs'' argument. %% HWL
85 writeRealC :: Handle -> AbstractC -> IO ()
86 writeRealC handle absC
87 -- avoid holding on to the whole of absC in the !Gransim case.
89 then printForCFast fp (pprAbsC absC (costs absC))
90 else printForCFast fp (pprAbsC absC (panic "costs"))
91 --printForC handle (pprAbsC absC (panic "costs"))
92 dumpRealC :: AbstractC -> SDoc
93 dumpRealC absC = pprAbsC absC (costs absC)
96 writeRealC :: Handle -> AbstractC -> IO ()
97 --writeRealC handle absC =
99 -- printDoc LeftMode handle (pprAbsC absC (costs absC))
101 writeRealC handle absC
102 | opt_GranMacros = _scc_ "writeRealC" printForC handle $
103 pprCode CStyle (pprAbsC absC (costs absC))
104 | otherwise = _scc_ "writeRealC" printForC handle $
105 pprCode CStyle (pprAbsC absC (panic "costs"))
107 dumpRealC :: AbstractC -> SDoc
109 | opt_GranMacros = pprCode CStyle (pprAbsC absC (costs absC))
110 | otherwise = pprCode CStyle (pprAbsC absC (panic "costs"))
114 This emits the macro, which is used in GrAnSim to compute the total costs
115 from a cost 5 tuple. %% HWL
118 emitMacro :: CostRes -> SDoc
120 emitMacro _ | not opt_GranMacros = empty
122 emitMacro (Cost (i,b,l,s,f))
123 = hcat [ ptext SLIT("GRAN_EXEC"), char '(',
124 int i, comma, int b, comma, int l, comma,
125 int s, comma, int f, pp_paren_semi ]
127 pp_paren_semi = text ");"
130 New type: Now pprAbsC also takes the costs for evaluating the Abstract C
131 code as an argument (that's needed when spitting out the GRAN_EXEC macro
132 which must be done before the return i.e. inside absC code) HWL
135 pprAbsC :: AbstractC -> CostRes -> SDoc
136 pprAbsC AbsCNop _ = empty
137 pprAbsC (AbsCStmts s1 s2) c = ($$) (pprAbsC s1 c) (pprAbsC s2 c)
139 pprAbsC (CAssign dest src) _ = pprAssign (getAmodeRep dest) dest src
141 pprAbsC (CJump target) c
142 = ($$) (hcat [emitMacro c {-WDP:, text "/* <--++ CJump */"-} ])
143 (hcat [ text jmp_lit, pprAmode target, pp_paren_semi ])
145 pprAbsC (CFallThrough target) c
146 = ($$) (hcat [emitMacro c {-WDP:, text "/* <--++ CFallThrough */"-} ])
147 (hcat [ text jmp_lit, pprAmode target, pp_paren_semi ])
149 -- --------------------------------------------------------------------------
150 -- Spit out GRAN_EXEC macro immediately before the return HWL
152 pprAbsC (CReturn am return_info) c
153 = ($$) (hcat [emitMacro c {-WDP:, text "/* <---- CReturn */"-} ])
154 (hcat [text jmp_lit, target, pp_paren_semi ])
156 target = case return_info of
157 DirectReturn -> hcat [ptext SLIT("ENTRY_CODE"), lparen,
159 DynamicVectoredReturn am' -> mk_vector (pprAmode am')
160 StaticVectoredReturn n -> mk_vector (int n) -- Always positive
161 mk_vector x = hcat [ptext SLIT("RET_VEC"), char '(', pprAmode am, comma,
164 pprAbsC (CSplitMarker) _ = ptext SLIT("__STG_SPLIT_MARKER")
166 -- we optimise various degenerate cases of CSwitches.
168 -- --------------------------------------------------------------------------
169 -- Assume: CSwitch is also end of basic block
170 -- costs function yields nullCosts for whole switch
171 -- ==> inherited costs c are those of basic block up to switch
172 -- ==> inherit c + costs for the corresponding branch
174 -- --------------------------------------------------------------------------
176 pprAbsC (CSwitch discrim [] deflt) c
177 = pprAbsC deflt (c + costs deflt)
178 -- Empty alternative list => no costs for discrim as nothing cond. here HWL
180 pprAbsC (CSwitch discrim [(tag,alt_code)] deflt) c -- only one alt
181 = case (nonemptyAbsC deflt) of
182 Nothing -> -- one alt and no default
183 pprAbsC alt_code (c + costs alt_code)
184 -- Nothing conditional in here either HWL
186 Just dc -> -- make it an "if"
187 do_if_stmt discrim tag alt_code dc c
189 -- What problem is the re-ordering trying to solve ?
190 pprAbsC (CSwitch discrim [(tag1@(MachInt i1), alt_code1),
191 (tag2@(MachInt i2), alt_code2)] deflt) c
192 | empty_deflt && ((i1 == 0 && i2 == 1) || (i1 == 1 && i2 == 0))
194 do_if_stmt discrim tag1 alt_code1 alt_code2 c
196 do_if_stmt discrim tag2 alt_code2 alt_code1 c
198 empty_deflt = not (isJust (nonemptyAbsC deflt))
200 pprAbsC (CSwitch discrim alts deflt) c -- general case
201 | isFloatingRep (getAmodeRep discrim)
202 = pprAbsC (foldr ( \ a -> CSwitch discrim [a]) deflt alts) c
205 hcat [text "switch (", pp_discrim, text ") {"],
206 nest 2 (vcat (map ppr_alt alts)),
207 (case (nonemptyAbsC deflt) of
210 nest 2 (vcat [ptext SLIT("default:"),
211 pprAbsC dc (c + switch_head_cost
213 ptext SLIT("break;")])),
220 = vcat [ hcat [ptext SLIT("case "), pprBasicLit lit, char ':'],
221 nest 2 (($$) (pprAbsC absC (c + switch_head_cost + costs absC))
222 (ptext SLIT("break;"))) ]
224 -- Costs for addressing header of switch and cond. branching -- HWL
225 switch_head_cost = addrModeCosts discrim Rhs + (Cost (0, 1, 0, 0, 0))
227 pprAbsC stmt@(COpStmt results (StgFCallOp fcall uniq) args vol_regs) _
228 = pprFCall fcall uniq args results vol_regs
230 pprAbsC stmt@(COpStmt results (StgPrimOp op) args vol_regs) _
232 non_void_args = grab_non_void_amodes args
233 non_void_results = grab_non_void_amodes results
234 -- if just one result, we print in the obvious "assignment" style;
235 -- if 0 or many results, we emit a macro call, w/ the results
236 -- followed by the arguments. The macro presumably knows which
239 the_op = ppr_op_call non_void_results non_void_args
240 -- liveness mask is *in* the non_void_args
242 if primOpNeedsWrapper op then
243 case (ppr_vol_regs vol_regs) of { (pp_saves, pp_restores) ->
252 ppr_op_call results args
253 = hcat [ ppr op, lparen,
254 hcat (punctuate comma (map ppr_op_result results)),
255 if null results || null args then empty else comma,
256 hcat (punctuate comma (map pprAmode args)),
259 ppr_op_result r = ppr_amode r
260 -- primop macros do their own casting of result;
261 -- hence we can toss the provided cast...
263 -- NEW CASES FOR EXPANDED PRIMOPS
265 pprAbsC stmt@(CMachOpStmt res mop [arg1,arg2] maybe_vols) _
266 = let prefix_fn = mop `elem` [MO_Dbl_Pwr, MO_Flt_Pwr, MO_NatS_MulMayOflo]
268 case ppr_maybe_vol_regs maybe_vols of {(saves,restores) ->
271 [ppr_amode res, equals]
273 then [pprMachOp_for_C mop, parens (pprAmode arg1 <> comma <> pprAmode arg2)]
274 else [pprAmode arg1, pprMachOp_for_C mop, pprAmode arg2])
280 pprAbsC stmt@(CMachOpStmt res mop [arg1] maybe_vols) _
281 = case ppr_maybe_vol_regs maybe_vols of {(saves,restores) ->
283 hcat [ppr_amode res, equals,
284 pprMachOp_for_C mop, parens (pprAmode arg1),
289 pprAbsC stmt@(CSequential stuff) c
290 = vcat (map (flip pprAbsC c) stuff)
292 -- end of NEW CASES FOR EXPANDED PRIMOPS
294 pprAbsC stmt@(CSRT lbl closures) c
295 = case (pprTempAndExternDecls stmt) of { (_, pp_exts) ->
297 $$ ptext SLIT("SRT") <> lparen <> pprCLabel lbl <> rparen
298 $$ nest 2 (hcat (punctuate comma (map pp_closure_lbl closures)))
302 pprAbsC stmt@(CBitmap liveness@(Liveness lbl size mask)) c
303 = pp_liveness_switch liveness semi $
304 hcat [ ptext SLIT("BITMAP"), lparen,
305 pprCLabel lbl, comma,
307 pp_bitmap mask, rparen ]
309 pprAbsC (CSimultaneous abs_c) c
310 = hcat [ptext SLIT("{{"), pprAbsC abs_c c, ptext SLIT("}}")]
312 pprAbsC (CCheck macro as code) c
313 = hcat [ptext (cCheckMacroText macro), lparen,
314 hcat (punctuate comma (map ppr_amode as)), comma,
315 pprAbsC code c, pp_paren_semi
317 pprAbsC (CMacroStmt macro as) _
318 = hcat [ptext (cStmtMacroText macro), lparen,
319 hcat (punctuate comma (map ppr_amode as)),pp_paren_semi] -- no casting
320 pprAbsC (CCallProfCtrMacro op as) _
321 = hcat [ftext op, lparen,
322 hcat (punctuate comma (map ppr_amode as)),pp_paren_semi]
323 pprAbsC (CCallProfCCMacro op as) _
324 = hcat [ftext op, lparen,
325 hcat (punctuate comma (map ppr_amode as)),pp_paren_semi]
326 pprAbsC stmt@(CCallTypedef is_tdef (CCallSpec op_str cconv _) uniq results args) _
327 = hsep [ ptext (if is_tdef then SLIT("typedef") else SLIT("extern"))
330 , parens (hsep (punctuate comma ccall_decl_ty_args))
334 In the non-casm case, to ensure that we're entering the given external
335 entry point using the correct calling convention, we have to do the following:
337 - When entering via a function pointer (the `dynamic' case) using the specified
338 calling convention, we emit a typedefn declaration attributed with the
339 calling convention to use together with the result and parameter types we're
340 assuming. Coerce the function pointer to this type and go.
342 - to enter the function at a given code label, we emit an extern declaration
343 for the label here, stating the calling convention together with result and
344 argument types we're assuming.
346 The C compiler will hopefully use this extern declaration to good effect,
347 reporting any discrepancies between our extern decl and any other that
350 Re: calling convention, notice that gcc (2.8.1 and egcs-1.0.2) will for
351 the external function `foo' use the calling convention of the first `foo'
352 prototype it encounters (nor does it complain about conflicting attribute
353 declarations). The consequence of this is that you cannot override the
354 calling convention of `foo' using an extern declaration (you'd have to use
355 a typedef), but why you would want to do such a thing in the first place
356 is totally beyond me.
358 ToDo: petition the gcc folks to add code to warn about conflicting attribute
364 | is_tdef = parens (text (ccallConvAttribute cconv) <+> char '*' <> ccall_fun_ty)
365 | otherwise = text (ccallConvAttribute cconv) <+> ccall_fun_ty
369 DynamicTarget -> ptext SLIT("_ccall_fun_ty") <> ppr uniq
370 StaticTarget x -> pprCLabelString x
373 case non_void_results of
374 [] -> ptext SLIT("void")
375 [amode] -> ppr (getAmodeRep amode)
376 _ -> panic "pprAbsC{CCallTypedef}: ccall_res_ty"
379 | is_tdef = tail ccall_arg_tys
380 | otherwise = ccall_arg_tys
382 ccall_arg_tys = map (ppr . getAmodeRep) non_void_args
384 -- the first argument will be the "I/O world" token (a VoidRep)
385 -- all others should be non-void
388 in ASSERT (all non_void nvas) nvas
390 -- there will usually be two results: a (void) state which we
391 -- should ignore and a (possibly void) result.
393 let nvrs = grab_non_void_amodes results
394 in ASSERT (listLengthCmp nvrs 1 /= GT) nvrs
396 pprAbsC (CCodeBlock lbl abs_C) _
397 = if not (isJust(nonemptyAbsC abs_C)) then
398 pprTrace "pprAbsC: curious empty code block for" (pprCLabel lbl) empty
400 case (pprTempAndExternDecls abs_C) of { (pp_temps, pp_exts) ->
404 hcat [text (if (externallyVisibleCLabel lbl)
405 then "FN_(" -- abbreviations to save on output
407 pprCLabel lbl, text ") {"],
411 nest 8 (ptext SLIT("FB_")),
412 nest 8 (pprAbsC abs_C (costs abs_C)),
413 nest 8 (ptext SLIT("FE_")),
419 pprAbsC (CInitHdr cl_info amode cost_centre size) _
420 = hcat [ ptext SLIT("SET_HDR_"), char '(',
421 ppr_amode amode, comma,
422 pprCLabelAddr info_lbl, comma,
423 if_profiling (pprAmode cost_centre), comma,
424 if_profiling (int size),
427 info_lbl = infoTableLabelFromCI cl_info
430 pprAbsC stmt@(CStaticClosure closure_lbl cl_info cost_centre amodes) _
431 = case (pprTempAndExternDecls stmt) of { (_, pp_exts) ->
435 ptext SLIT("SET_STATIC_HDR"), char '(',
436 pprCLabel closure_lbl, comma,
437 pprCLabel info_lbl, comma,
438 if_profiling (pprAmode cost_centre), comma,
439 ppLocalness closure_lbl, comma,
440 ppLocalnessMacro True{-include dyn-} info_lbl,
443 nest 2 (ppr_payload amodes),
447 info_lbl = infoTableLabelFromCI cl_info
449 ppr_payload [] = empty
452 (braces $ hsep $ punctuate comma $
453 map (text "(L_)" <>) (foldr ppr_item [] ls))
456 | rep == VoidRep = rest
457 | rep == FloatRep = ppr_amode (floatToWord item) : rest
458 | rep == DoubleRep = map ppr_amode (doubleToWords item) ++ rest
459 | otherwise = ppr_amode item : rest
461 rep = getAmodeRep item
463 pprAbsC stmt@(CClosureInfoAndCode cl_info entry) _
464 = pprInfoTable info_lbl (mkInfoTable cl_info)
465 $$ let stuff = CCodeBlock entry_lbl entry in
466 pprAbsC stuff (costs stuff)
468 entry_lbl = entryLabelFromCI cl_info
469 info_lbl = infoTableLabelFromCI cl_info
471 pprAbsC stmt@(CClosureTbl tycon) _
473 ptext SLIT("CLOSURE_TBL") <>
474 lparen <> pprCLabel (mkClosureTblLabel tycon) <> rparen :
476 map (pp_closure_lbl . mkClosureLabel . getName . dataConWrapId) (tyConDataCons tycon)
478 ) $$ ptext SLIT("};")
480 pprAbsC stmt@(CRetDirect uniq code srt liveness) _
481 = pprInfoTable info_lbl (mkRetInfoTable entry_lbl srt liveness)
482 $$ let stuff = CCodeBlock entry_lbl code in
483 pprAbsC stuff (costs stuff)
485 info_lbl = mkReturnInfoLabel uniq
486 entry_lbl = mkReturnPtLabel uniq
488 pprAbsC stmt@(CRetVector lbl amodes srt liveness) _
489 = pprInfoTable lbl (mkVecInfoTable amodes srt liveness)
491 pprAbsC stmt@(CModuleInitBlock plain_lbl lbl code) _
493 ptext SLIT("START_MOD_INIT") <>
494 parens (pprCLabel plain_lbl <> comma <> pprCLabel lbl),
495 case (pprTempAndExternDecls stmt) of { (_, pp_exts) -> pp_exts },
496 pprAbsC code (costs code),
497 hcat [ptext SLIT("END_MOD_INIT"), lparen, rparen]
500 pprAbsC (CCostCentreDecl is_local cc) _ = pprCostCentreDecl is_local cc
501 pprAbsC (CCostCentreStackDecl ccs) _ = pprCostCentreStackDecl ccs
504 Info tables... just arrays of words (the translation is done in
508 pprInfoTable info_lbl amodes
509 = (case snd (initTE (ppr_decls_Amodes amodes)) of
512 $$ hcat [ ppLocalness info_lbl, ptext SLIT("StgWord "),
513 pprCLabel info_lbl, ptext SLIT("[] = {") ]
514 $$ hcat (punctuate comma (map (castToWord.pprAmode) amodes))
517 castToWord s = text "(W_)(" <> s <> char ')'
521 -- Print a CMachOp in a way suitable for emitting via C.
522 pprMachOp_for_C MO_Nat_Add = char '+'
523 pprMachOp_for_C MO_Nat_Sub = char '-'
524 pprMachOp_for_C MO_Nat_Eq = text "=="
525 pprMachOp_for_C MO_Nat_Ne = text "!="
527 pprMachOp_for_C MO_NatS_Ge = text ">="
528 pprMachOp_for_C MO_NatS_Le = text "<="
529 pprMachOp_for_C MO_NatS_Gt = text ">"
530 pprMachOp_for_C MO_NatS_Lt = text "<"
532 pprMachOp_for_C MO_NatU_Ge = text ">="
533 pprMachOp_for_C MO_NatU_Le = text "<="
534 pprMachOp_for_C MO_NatU_Gt = text ">"
535 pprMachOp_for_C MO_NatU_Lt = text "<"
537 pprMachOp_for_C MO_NatS_Mul = char '*'
538 pprMachOp_for_C MO_NatS_MulMayOflo = text "mulIntMayOflo"
539 pprMachOp_for_C MO_NatS_Quot = char '/'
540 pprMachOp_for_C MO_NatS_Rem = char '%'
541 pprMachOp_for_C MO_NatS_Neg = char '-'
543 pprMachOp_for_C MO_NatU_Mul = char '*'
544 pprMachOp_for_C MO_NatU_Quot = char '/'
545 pprMachOp_for_C MO_NatU_Rem = char '%'
547 pprMachOp_for_C MO_Nat_And = text "&"
548 pprMachOp_for_C MO_Nat_Or = text "|"
549 pprMachOp_for_C MO_Nat_Xor = text "^"
550 pprMachOp_for_C MO_Nat_Not = text "~"
551 pprMachOp_for_C MO_Nat_Shl = text "<<"
552 pprMachOp_for_C MO_Nat_Shr = text ">>"
553 pprMachOp_for_C MO_Nat_Sar = text ">>"
555 pprMachOp_for_C MO_32U_Eq = text "=="
556 pprMachOp_for_C MO_32U_Ne = text "!="
557 pprMachOp_for_C MO_32U_Ge = text ">="
558 pprMachOp_for_C MO_32U_Le = text "<="
559 pprMachOp_for_C MO_32U_Gt = text ">"
560 pprMachOp_for_C MO_32U_Lt = text "<"
562 pprMachOp_for_C MO_Dbl_Eq = text "=="
563 pprMachOp_for_C MO_Dbl_Ne = text "!="
564 pprMachOp_for_C MO_Dbl_Ge = text ">="
565 pprMachOp_for_C MO_Dbl_Le = text "<="
566 pprMachOp_for_C MO_Dbl_Gt = text ">"
567 pprMachOp_for_C MO_Dbl_Lt = text "<"
569 pprMachOp_for_C MO_Dbl_Add = text "+"
570 pprMachOp_for_C MO_Dbl_Sub = text "-"
571 pprMachOp_for_C MO_Dbl_Mul = text "*"
572 pprMachOp_for_C MO_Dbl_Div = text "/"
573 pprMachOp_for_C MO_Dbl_Pwr = text "pow"
575 pprMachOp_for_C MO_Dbl_Sin = text "sin"
576 pprMachOp_for_C MO_Dbl_Cos = text "cos"
577 pprMachOp_for_C MO_Dbl_Tan = text "tan"
578 pprMachOp_for_C MO_Dbl_Sinh = text "sinh"
579 pprMachOp_for_C MO_Dbl_Cosh = text "cosh"
580 pprMachOp_for_C MO_Dbl_Tanh = text "tanh"
581 pprMachOp_for_C MO_Dbl_Asin = text "asin"
582 pprMachOp_for_C MO_Dbl_Acos = text "acos"
583 pprMachOp_for_C MO_Dbl_Atan = text "atan"
584 pprMachOp_for_C MO_Dbl_Log = text "log"
585 pprMachOp_for_C MO_Dbl_Exp = text "exp"
586 pprMachOp_for_C MO_Dbl_Sqrt = text "sqrt"
587 pprMachOp_for_C MO_Dbl_Neg = text "-"
589 pprMachOp_for_C MO_Flt_Add = text "+"
590 pprMachOp_for_C MO_Flt_Sub = text "-"
591 pprMachOp_for_C MO_Flt_Mul = text "*"
592 pprMachOp_for_C MO_Flt_Div = text "/"
593 pprMachOp_for_C MO_Flt_Pwr = text "pow"
595 pprMachOp_for_C MO_Flt_Eq = text "=="
596 pprMachOp_for_C MO_Flt_Ne = text "!="
597 pprMachOp_for_C MO_Flt_Ge = text ">="
598 pprMachOp_for_C MO_Flt_Le = text "<="
599 pprMachOp_for_C MO_Flt_Gt = text ">"
600 pprMachOp_for_C MO_Flt_Lt = text "<"
602 pprMachOp_for_C MO_Flt_Sin = text "sin"
603 pprMachOp_for_C MO_Flt_Cos = text "cos"
604 pprMachOp_for_C MO_Flt_Tan = text "tan"
605 pprMachOp_for_C MO_Flt_Sinh = text "sinh"
606 pprMachOp_for_C MO_Flt_Cosh = text "cosh"
607 pprMachOp_for_C MO_Flt_Tanh = text "tanh"
608 pprMachOp_for_C MO_Flt_Asin = text "asin"
609 pprMachOp_for_C MO_Flt_Acos = text "acos"
610 pprMachOp_for_C MO_Flt_Atan = text "atan"
611 pprMachOp_for_C MO_Flt_Log = text "log"
612 pprMachOp_for_C MO_Flt_Exp = text "exp"
613 pprMachOp_for_C MO_Flt_Sqrt = text "sqrt"
614 pprMachOp_for_C MO_Flt_Neg = text "-"
616 pprMachOp_for_C MO_32U_to_NatS = text "(StgInt)"
617 pprMachOp_for_C MO_NatS_to_32U = text "(StgWord32)"
619 pprMachOp_for_C MO_NatS_to_Dbl = text "(StgDouble)"
620 pprMachOp_for_C MO_Dbl_to_NatS = text "(StgInt)"
622 pprMachOp_for_C MO_NatS_to_Flt = text "(StgFloat)"
623 pprMachOp_for_C MO_Flt_to_NatS = text "(StgInt)"
625 pprMachOp_for_C MO_NatS_to_NatU = text "(StgWord)"
626 pprMachOp_for_C MO_NatU_to_NatS = text "(StgInt)"
628 pprMachOp_for_C MO_NatS_to_NatP = text "(void*)"
629 pprMachOp_for_C MO_NatP_to_NatS = text "(StgInt)"
630 pprMachOp_for_C MO_NatU_to_NatP = text "(void*)"
631 pprMachOp_for_C MO_NatP_to_NatU = text "(StgWord)"
633 pprMachOp_for_C MO_Dbl_to_Flt = text "(StgFloat)"
634 pprMachOp_for_C MO_Flt_to_Dbl = text "(StgDouble)"
636 pprMachOp_for_C MO_8S_to_NatS = text "(StgInt8)(StgInt)"
637 pprMachOp_for_C MO_16S_to_NatS = text "(StgInt16)(StgInt)"
638 pprMachOp_for_C MO_32S_to_NatS = text "(StgInt32)(StgInt)"
640 pprMachOp_for_C MO_8U_to_NatU = text "(StgWord8)(StgWord)"
641 pprMachOp_for_C MO_16U_to_NatU = text "(StgWord16)(StgWord)"
642 pprMachOp_for_C MO_32U_to_NatU = text "(StgWord32)(StgWord)"
644 pprMachOp_for_C MO_8U_to_32U = text "(StgWord32)"
645 pprMachOp_for_C MO_32U_to_8U = text "(StgWord8)"
649 = if (externallyVisibleCLabel lbl)
651 else ptext SLIT("static ")
653 -- Horrible macros for declaring the types and locality of labels (see
656 ppLocalnessMacro include_dyn_prefix clabel =
661 ClosureType -> ptext SLIT("C_")
662 CodeType -> ptext SLIT("F_")
663 InfoTblType -> ptext SLIT("I_")
664 RetInfoTblType -> ptext SLIT("RI_")
665 ClosureTblType -> ptext SLIT("CP_")
666 DataType -> ptext SLIT("D_")
669 is_visible = externallyVisibleCLabel clabel
670 label_type = labelType clabel
673 | is_visible = char 'E'
674 | otherwise = char 'I'
677 | include_dyn_prefix && labelDynamic clabel = char 'D'
685 grab_non_void_amodes amodes
686 = filter non_void amodes
689 = case (getAmodeRep amode) of
695 ppr_maybe_vol_regs :: Maybe [MagicId] -> (SDoc, SDoc)
696 ppr_maybe_vol_regs Nothing
698 ppr_maybe_vol_regs (Just vrs)
699 = case ppr_vol_regs vrs of
701 -> (pp_basic_saves $$ saves,
702 pp_basic_restores $$ restores)
704 ppr_vol_regs :: [MagicId] -> (SDoc, SDoc)
706 ppr_vol_regs [] = (empty, empty)
707 ppr_vol_regs (VoidReg:rs) = ppr_vol_regs rs
709 = let pp_reg = case r of
710 VanillaReg pk n -> pprVanillaReg n
712 (more_saves, more_restores) = ppr_vol_regs rs
714 (($$) ((<>) (ptext SLIT("CALLER_SAVE_")) pp_reg) more_saves,
715 ($$) ((<>) (ptext SLIT("CALLER_RESTORE_")) pp_reg) more_restores)
717 -- pp_basic_{saves,restores}: The BaseReg, Sp, Hp and
718 -- HpLim (see StgRegs.lh) may need to be saved/restored around CCalls,
719 -- depending on the platform. (The "volatile regs" stuff handles all
720 -- other registers.) Just be *sure* BaseReg is OK before trying to do
721 -- anything else. The correct sequence of saves&restores are
722 -- encoded by the CALLER_*_SYSTEM macros.
723 pp_basic_saves = ptext SLIT("CALLER_SAVE_SYSTEM")
724 pp_basic_restores = ptext SLIT("CALLER_RESTORE_SYSTEM")
729 | labelDynamic lbl = text "DLL_SRT_ENTRY" <> parens (pprCLabel lbl)
730 | otherwise = char '&' <> pprCLabel lbl
735 = if opt_SccProfilingOn
737 else char '0' -- leave it out!
738 -- ---------------------------------------------------------------------------
739 -- Changes for GrAnSim:
740 -- draw costs for computation in head of if into both branches;
741 -- as no abstractC data structure is given for the head, one is constructed
742 -- guessing unknown values and fed into the costs function
743 -- ---------------------------------------------------------------------------
745 do_if_stmt discrim tag alt_code deflt c
747 cond = hcat [ pprAmode discrim
750 , pprAmode (CLit tag)
752 -- to be absolutely sure that none of the
753 -- conversion rules hit, e.g.,
755 -- minInt is different to (int)minInt
757 -- in C (when minInt is a number not a constant
758 -- expression which evaluates to it.)
761 MachInt _ -> ptext SLIT("(I_)")
766 (addrModeCosts discrim Rhs) c
768 ppr_if_stmt pp_pred then_part else_part discrim_costs c
770 hcat [text "if (", pp_pred, text ") {"],
771 nest 8 (pprAbsC then_part (c + discrim_costs +
772 (Cost (0, 2, 0, 0, 0)) +
774 (case nonemptyAbsC else_part of Nothing -> empty; Just _ -> text "} else {"),
775 nest 8 (pprAbsC else_part (c + discrim_costs +
776 (Cost (0, 1, 0, 0, 0)) +
779 {- Total costs = inherited costs (before if) + costs for accessing discrim
780 + costs for cond branch ( = (0, 1, 0, 0, 0) )
781 + costs for that alternative
785 Historical note: this used to be two separate cases -- one for `ccall'
786 and one for `casm'. To get round a potential limitation to only 10
787 arguments, the numbering of arguments in @process_casm@ was beefed up a
790 Some rough notes on generating code for @CCallOp@:
792 1) Evaluate all arguments and stuff them into registers. (done elsewhere)
793 2) Save any essential registers (heap, stack, etc).
795 ToDo: If stable pointers are in use, these must be saved in a place
796 where the runtime system can get at them so that the Stg world can
797 be restarted during the call.
799 3) Save any temporary registers that are currently in use.
800 4) Do the call, putting result into a local variable
801 5) Restore essential registers
802 6) Restore temporaries
804 (This happens after restoration of essential registers because we
805 might need the @Base@ register to access all the others correctly.)
807 Otherwise, copy local variable into result register.
809 8) If ccall (not casm), declare the function being called as extern so
810 that C knows if it returns anything other than an int.
813 { ResultType _ccall_result;
816 _ccall_result = f( args );
820 return_reg = _ccall_result;
824 Amendment to the above: if we can GC, we have to:
826 * make sure we save all our registers away where the garbage collector
828 * be sure that there are no live registers or we're in trouble.
829 (This can cause problems if you try something foolish like passing
830 an array or a foreign obj to a _ccall_GC_ thing.)
831 * increment/decrement the @inCCallGC@ counter before/after the call so
832 that the runtime check that PerformGC is being used sensibly will work.
835 pprFCall call@(CCall (CCallSpec target cconv safety)) uniq args results vol_regs
838 declare_local_vars, -- local var for *result*
839 vcat local_arg_decls,
841 process_casm local_vars pp_non_void_args call_str,
847 (pp_saves, pp_restores) = ppr_vol_regs vol_regs
849 thread_macro_args = ppr_uniq_token <> comma <+>
850 text "rts" <> ppr (playThreadSafe safety)
851 ppr_uniq_token = text "tok_" <> ppr uniq
852 (pp_save_context, pp_restore_context)
853 | playSafe safety = ( text "{ I_" <+> ppr_uniq_token <>
854 text "; SUSPEND_THREAD" <> parens thread_macro_args <> semi
855 , text "RESUME_THREAD" <> parens thread_macro_args <> text ";}"
857 | otherwise = ( pp_basic_saves $$ pp_saves,
858 pp_basic_restores $$ pp_restores)
862 in ASSERT2 ( all non_void nvas, ppr call <+> hsep (map pprAmode args) )
864 -- the last argument will be the "I/O world" token (a VoidRep)
865 -- all others should be non-void
868 let nvrs = grab_non_void_amodes results
869 in ASSERT (listLengthCmp nvrs 1 /= GT) nvrs
870 -- there will usually be two results: a (void) state which we
871 -- should ignore and a (possibly void) result.
873 (local_arg_decls, pp_non_void_args)
874 = unzip [ ppr_casm_arg a i | (a,i) <- non_void_args `zip` [1..] ]
876 (declare_local_vars, local_vars, assign_results)
877 = ppr_casm_results non_void_results
879 call_str = case target of
880 CasmTarget str -> unpackFS str
881 StaticTarget fn -> mk_ccall_str (pprCLabelString fn) ccall_args
882 DynamicTarget -> mk_ccall_str dyn_fun (tail ccall_args)
884 ccall_args = zipWith (\ _ i -> char '%' <> int i) non_void_args [0..]
885 dyn_fun = parens (parens (ptext SLIT("_ccall_fun_ty") <> ppr uniq) <> text "%0")
888 -- Remainder only used for ccall
889 mk_ccall_str fun_name ccall_fun_args = showSDoc
891 if null non_void_results
894 lparen, fun_name, lparen,
895 hcat (punctuate comma ccall_fun_args),
900 ppr_casm_arg :: CAddrMode -> Int -> (SDoc, SDoc)
901 -- (a) decl and assignment, (b) local var to be used later
903 ppr_casm_arg amode a_num
905 a_kind = getAmodeRep amode
906 pp_amode = pprAmode amode
907 pp_kind = pprPrimKind a_kind
909 local_var = (<>) (ptext SLIT("_ccall_arg")) (int a_num)
912 = hcat [ pp_kind, space, local_var, equals, pp_amode, semi ]
914 (declare_local_var, local_var)
917 For l-values, the critical questions are:
919 1) Are there any results at all?
921 We only allow zero or one results.
925 :: [CAddrMode] -- list of results (length <= 1)
927 ( SDoc, -- declaration of any local vars
928 [SDoc], -- list of result vars (same length as results)
929 SDoc ) -- assignment (if any) of results in local var to registers
932 = (empty, [], empty) -- no results
936 result_reg = ppr_amode r
937 r_kind = getAmodeRep r
939 local_var = ptext SLIT("_ccall_result")
941 (result_type, assign_result)
942 = (pprPrimKind r_kind,
943 hcat [ result_reg, equals, local_var, semi ])
945 declare_local_var = hcat [ result_type, space, local_var, semi ]
947 (declare_local_var, [local_var], assign_result)
950 = panic "ppr_casm_results: ccall/casm with many results"
954 Note the sneaky way _the_ result is represented by a list so that we
955 can complain if it's used twice.
957 ToDo: Any chance of giving line numbers when process-casm fails?
958 Or maybe we should do a check _much earlier_ in compiler. ADR
961 process_casm :: [SDoc] -- results (length <= 1)
962 -> [SDoc] -- arguments
963 -> String -- format string (with embedded %'s)
964 -> SDoc -- code being generated
966 process_casm results args string = process results args string
968 process [] _ "" = empty
969 process (_:_) _ "" = error ("process_casm: non-void result not assigned while processing _casm_ \"" ++
971 "\"\n(Try changing result type to IO ()\n")
973 process ress args ('%':cs)
976 error ("process_casm: lonely % while processing _casm_ \"" ++ string ++ "\".\n")
979 char '%' <> process ress args css
983 [] -> error ("process_casm: no result to match %r while processing _casm_ \"" ++ string ++ "\".\nTry deleting %r or changing result type from PrimIO ()\n")
984 [r] -> r <> (process [] args css)
985 _ -> panic ("process_casm: casm with many results while processing _casm_ \"" ++ string ++ "\".\n")
989 read_int :: ReadS Int
992 case (read_int other) of
994 if num >= 0 && args `lengthExceeds` num
995 then parens (args !! num) <> process ress args css
996 else error ("process_casm: no such arg #:"++(show num)++" while processing \"" ++ string ++ "\".\n")
997 _ -> error ("process_casm: not %<num> while processing _casm_ \"" ++ string ++ "\".\n")
999 process ress args (other_c:cs)
1000 = char other_c <> process ress args cs
1003 %************************************************************************
1005 \subsection[a2r-assignments]{Assignments}
1007 %************************************************************************
1009 Printing assignments is a little tricky because of type coercion.
1011 First of all, the kind of the thing being assigned can be gotten from
1012 the destination addressing mode. (It should be the same as the kind
1013 of the source addressing mode.) If the kind of the assignment is of
1014 @VoidRep@, then don't generate any code at all.
1017 pprAssign :: PrimRep -> CAddrMode -> CAddrMode -> SDoc
1019 pprAssign VoidRep dest src = empty
1022 Special treatment for floats and doubles, to avoid unwanted conversions.
1025 pprAssign FloatRep dest@(CVal reg_rel _) src
1026 = hcat [ ptext SLIT("ASSIGN_FLT((W_*)"), parens (ppr_amode (CAddr reg_rel)), comma, pprAmode src, pp_paren_semi ]
1028 pprAssign DoubleRep dest@(CVal reg_rel _) src
1029 = hcat [ ptext SLIT("ASSIGN_DBL((W_*)"), parens (ppr_amode (CAddr reg_rel)), comma, pprAmode src, pp_paren_semi ]
1031 pprAssign Int64Rep dest@(CVal reg_rel _) src
1032 = hcat [ ptext SLIT("ASSIGN_Int64((W_*)"), parens (ppr_amode (CAddr reg_rel)), comma, pprAmode src, pp_paren_semi ]
1033 pprAssign Word64Rep dest@(CVal reg_rel _) src
1034 = hcat [ ptext SLIT("ASSIGN_Word64((W_*)"), parens (ppr_amode (CAddr reg_rel)), comma, pprAmode src, pp_paren_semi ]
1037 Lastly, the question is: will the C compiler think the types of the
1038 two sides of the assignment match?
1040 We assume that the types will match if neither side is a
1041 @CVal@ addressing mode for any register which can point into
1044 Why? Because the heap and stack are used to store miscellaneous
1045 things, whereas the temporaries, registers, etc., are only used for
1046 things of fixed type.
1049 pprAssign kind (CReg (VanillaReg _ dest)) (CReg (VanillaReg _ src))
1050 = hcat [ pprVanillaReg dest, equals,
1051 pprVanillaReg src, semi ]
1053 pprAssign kind dest src
1054 | mixedTypeLocn dest
1055 -- Add in a cast to StgWord (a.k.a. W_) iff the destination is mixed
1056 = hcat [ ppr_amode dest, equals,
1057 text "(W_)(", -- Here is the cast
1058 ppr_amode src, pp_paren_semi ]
1060 pprAssign kind dest src
1061 | mixedPtrLocn dest && getAmodeRep src /= PtrRep
1062 -- Add in a cast to StgPtr (a.k.a. P_) iff the destination is mixed
1063 = hcat [ ppr_amode dest, equals,
1064 text "(P_)(", -- Here is the cast
1065 ppr_amode src, pp_paren_semi ]
1067 pprAssign kind other_dest src
1068 = hcat [ ppr_amode other_dest, equals,
1069 pprAmode src, semi ]
1073 %************************************************************************
1075 \subsection[a2r-CAddrModes]{Addressing modes}
1077 %************************************************************************
1079 @pprAmode@ is used to print r-values (which may need casts), whereas
1080 @ppr_amode@ is used for l-values {\em and} as a help function for
1084 pprAmode, ppr_amode :: CAddrMode -> SDoc
1087 For reasons discussed above under assignments, @CVal@ modes need
1088 to be treated carefully. First come special cases for floats and doubles,
1089 similar to those in @pprAssign@:
1091 (NB: @PK_FLT@ and @PK_DBL@ require the {\em address} of the value in
1095 pprAmode (CVal reg_rel FloatRep)
1096 = hcat [ text "PK_FLT((W_*)", parens (ppr_amode (CAddr reg_rel)), rparen ]
1097 pprAmode (CVal reg_rel DoubleRep)
1098 = hcat [ text "PK_DBL((W_*)", parens (ppr_amode (CAddr reg_rel)), rparen ]
1099 pprAmode (CVal reg_rel Int64Rep)
1100 = hcat [ text "PK_Int64((W_*)", parens (ppr_amode (CAddr reg_rel)), rparen ]
1101 pprAmode (CVal reg_rel Word64Rep)
1102 = hcat [ text "PK_Word64((W_*)", parens (ppr_amode (CAddr reg_rel)), rparen ]
1105 Next comes the case where there is some other cast need, and the
1110 | mixedTypeLocn amode
1111 = parens (hcat [ pprPrimKind (getAmodeRep amode), ptext SLIT(")("),
1113 | otherwise -- No cast needed
1117 When we have an indirection through a CIndex, we have to be careful to
1118 get the type casts right.
1122 CVal (CIndex kind1 base offset) kind2
1126 *(kind2 *)((kind1 *)base + offset)
1128 That is, the indexing is done in units of kind1, but the resulting
1132 ppr_amode CBytesPerWord
1133 = text "(sizeof(void*))"
1135 ppr_amode (CVal reg_rel@(CIndex _ _ _) kind)
1136 = case (pprRegRelative False{-no sign wanted-} reg_rel) of
1137 (pp_reg, Nothing) -> panic "ppr_amode: CIndex"
1138 (pp_reg, Just offset) ->
1139 hcat [ char '*', parens (pprPrimKind kind <> char '*'),
1140 parens (pp_reg <> char '+' <> offset) ]
1143 Now the rest of the cases for ``workhorse'' @ppr_amode@:
1146 ppr_amode (CVal reg_rel _)
1147 = case (pprRegRelative False{-no sign wanted-} reg_rel) of
1148 (pp_reg, Nothing) -> (<>) (char '*') pp_reg
1149 (pp_reg, Just offset) -> hcat [ pp_reg, brackets offset ]
1151 ppr_amode (CAddr reg_rel)
1152 = case (pprRegRelative True{-sign wanted-} reg_rel) of
1153 (pp_reg, Nothing) -> pp_reg
1154 (pp_reg, Just offset) -> pp_reg <> offset
1156 ppr_amode (CReg magic_id) = pprMagicId magic_id
1158 ppr_amode (CTemp uniq kind) = char '_' <> pprUnique uniq <> char '_'
1160 ppr_amode (CLbl lbl kind) = pprCLabelAddr lbl
1162 ppr_amode (CCharLike ch)
1163 = hcat [ptext SLIT("CHARLIKE_CLOSURE"), char '(', pprAmode ch, rparen ]
1164 ppr_amode (CIntLike int)
1165 = hcat [ptext SLIT("INTLIKE_CLOSURE"), char '(', pprAmode int, rparen ]
1167 ppr_amode (CLit lit) = pprBasicLit lit
1169 ppr_amode (CJoinPoint _)
1170 = panic "ppr_amode: CJoinPoint"
1172 ppr_amode (CMacroExpr pk macro as)
1173 = parens (ptext (cExprMacroText macro) <>
1174 parens (hcat (punctuate comma (map pprAmode as))))
1178 cExprMacroText ENTRY_CODE = SLIT("ENTRY_CODE")
1179 cExprMacroText ARG_TAG = SLIT("ARG_TAG")
1180 cExprMacroText GET_TAG = SLIT("GET_TAG")
1181 cExprMacroText UPD_FRAME_UPDATEE = SLIT("UPD_FRAME_UPDATEE")
1182 cExprMacroText CCS_HDR = SLIT("CCS_HDR")
1183 cExprMacroText BYTE_ARR_CTS = SLIT("BYTE_ARR_CTS")
1184 cExprMacroText PTRS_ARR_CTS = SLIT("PTRS_ARR_CTS")
1185 cExprMacroText ForeignObj_CLOSURE_DATA = SLIT("ForeignObj_CLOSURE_DATA")
1187 cStmtMacroText UPD_CAF = SLIT("UPD_CAF")
1188 cStmtMacroText UPD_BH_UPDATABLE = SLIT("UPD_BH_UPDATABLE")
1189 cStmtMacroText UPD_BH_SINGLE_ENTRY = SLIT("UPD_BH_SINGLE_ENTRY")
1190 cStmtMacroText PUSH_UPD_FRAME = SLIT("PUSH_UPD_FRAME")
1191 cStmtMacroText SET_TAG = SLIT("SET_TAG")
1192 cStmtMacroText DATA_TO_TAGZH = SLIT("dataToTagzh")
1193 cStmtMacroText REGISTER_FOREIGN_EXPORT = SLIT("REGISTER_FOREIGN_EXPORT")
1194 cStmtMacroText REGISTER_IMPORT = SLIT("REGISTER_IMPORT")
1195 cStmtMacroText REGISTER_DIMPORT = SLIT("REGISTER_DIMPORT")
1196 cStmtMacroText GRAN_FETCH = SLIT("GRAN_FETCH")
1197 cStmtMacroText GRAN_RESCHEDULE = SLIT("GRAN_RESCHEDULE")
1198 cStmtMacroText GRAN_FETCH_AND_RESCHEDULE= SLIT("GRAN_FETCH_AND_RESCHEDULE")
1199 cStmtMacroText THREAD_CONTEXT_SWITCH = SLIT("THREAD_CONTEXT_SWITCH")
1200 cStmtMacroText GRAN_YIELD = SLIT("GRAN_YIELD")
1202 cCheckMacroText HP_CHK_NP = SLIT("HP_CHK_NP")
1203 cCheckMacroText STK_CHK_NP = SLIT("STK_CHK_NP")
1204 cCheckMacroText HP_STK_CHK_NP = SLIT("HP_STK_CHK_NP")
1205 cCheckMacroText HP_CHK_FUN = SLIT("HP_CHK_FUN")
1206 cCheckMacroText STK_CHK_FUN = SLIT("STK_CHK_FUN")
1207 cCheckMacroText HP_STK_CHK_FUN = SLIT("HP_STK_CHK_FUN")
1208 cCheckMacroText HP_CHK_NOREGS = SLIT("HP_CHK_NOREGS")
1209 cCheckMacroText HP_CHK_UNPT_R1 = SLIT("HP_CHK_UNPT_R1")
1210 cCheckMacroText HP_CHK_UNBX_R1 = SLIT("HP_CHK_UNBX_R1")
1211 cCheckMacroText HP_CHK_F1 = SLIT("HP_CHK_F1")
1212 cCheckMacroText HP_CHK_D1 = SLIT("HP_CHK_D1")
1213 cCheckMacroText HP_CHK_L1 = SLIT("HP_CHK_L1")
1214 cCheckMacroText HP_CHK_UNBX_TUPLE = SLIT("HP_CHK_UNBX_TUPLE")
1220 %************************************************************************
1222 \subsection[ppr-liveness-masks]{Liveness Masks}
1224 %************************************************************************
1227 pp_bitmap_switch :: Int -> SDoc -> SDoc -> SDoc
1228 pp_bitmap_switch size small large
1229 | size <= mAX_SMALL_BITMAP_SIZE = small
1232 -- magic numbers, must agree with BITMAP_BITS_SHIFT in InfoTables.h
1233 mAX_SMALL_BITMAP_SIZE | wORD_SIZE == 4 = 27
1236 pp_liveness_switch :: Liveness -> SDoc -> SDoc -> SDoc
1237 pp_liveness_switch (Liveness _ size _) = pp_bitmap_switch size
1239 pp_bitset :: BitSet -> SDoc
1241 | i < -1 = int (i + 1) <> text "-1"
1245 pp_bitmap :: [BitSet] -> SDoc
1246 pp_bitmap [] = int 0
1247 pp_bitmap ss = hcat (punctuate (ptext SLIT(" COMMA ")) (bundle ss)) where
1249 bundle [s] = [hcat bitmap32]
1250 where bitmap32 = [ptext SLIT("BITMAP32"), lparen,
1251 pp_bitset s, rparen]
1252 bundle (s1:s2:ss) = hcat bitmap64 : bundle ss
1253 where bitmap64 = [ptext SLIT("BITMAP64"), lparen,
1254 pp_bitset s1, comma, pp_bitset s2, rparen]
1257 %************************************************************************
1259 \subsection[a2r-MagicIds]{Magic ids}
1261 %************************************************************************
1263 @pprRegRelative@ returns a pair of the @Doc@ for the register
1264 (some casting may be required), and a @Maybe Doc@ for the offset
1265 (zero offset gives a @Nothing@).
1268 addPlusSign :: Bool -> SDoc -> SDoc
1269 addPlusSign False p = p
1270 addPlusSign True p = (<>) (char '+') p
1272 pprSignedInt :: Bool -> Int -> Maybe SDoc -- Nothing => 0
1273 pprSignedInt sign_wanted n
1274 = if n == 0 then Nothing else
1275 if n > 0 then Just (addPlusSign sign_wanted (int n))
1278 pprRegRelative :: Bool -- True <=> Print leading plus sign (if +ve)
1280 -> (SDoc, Maybe SDoc)
1282 pprRegRelative sign_wanted (SpRel off)
1283 = (pprMagicId Sp, pprSignedInt sign_wanted (I# off))
1285 pprRegRelative sign_wanted r@(HpRel o)
1286 = let pp_Hp = pprMagicId Hp; off = I# o
1291 (pp_Hp, Just ((<>) (char '-') (int off)))
1293 pprRegRelative sign_wanted (NodeRel o)
1294 = let pp_Node = pprMagicId node; off = I# o
1299 (pp_Node, Just (addPlusSign sign_wanted (int off)))
1301 pprRegRelative sign_wanted (CIndex base offset kind)
1302 = ( hcat [text "((", pprPrimKind kind, text " *)(", ppr_amode base, text "))"]
1303 , Just (hcat [if sign_wanted then char '+' else empty,
1304 text "(I_)(", ppr_amode offset, ptext SLIT(")")])
1308 @pprMagicId@ just prints the register name. @VanillaReg@ registers are
1309 represented by a discriminated union (@StgUnion@), so we use the @PrimRep@
1310 to select the union tag.
1313 pprMagicId :: MagicId -> SDoc
1315 pprMagicId BaseReg = ptext SLIT("BaseReg")
1316 pprMagicId (VanillaReg pk n)
1317 = hcat [ pprVanillaReg n, char '.',
1319 pprMagicId (FloatReg n) = ptext SLIT("F") <> int (I# n)
1320 pprMagicId (DoubleReg n) = ptext SLIT("D") <> int (I# n)
1321 pprMagicId (LongReg _ n) = ptext SLIT("L") <> int (I# n)
1322 pprMagicId Sp = ptext SLIT("Sp")
1323 pprMagicId SpLim = ptext SLIT("SpLim")
1324 pprMagicId Hp = ptext SLIT("Hp")
1325 pprMagicId HpLim = ptext SLIT("HpLim")
1326 pprMagicId CurCostCentre = ptext SLIT("CCCS")
1327 pprMagicId VoidReg = panic "pprMagicId:VoidReg!"
1329 pprVanillaReg :: Int# -> SDoc
1330 pprVanillaReg n = char 'R' <> int (I# n)
1332 pprUnionTag :: PrimRep -> SDoc
1334 pprUnionTag PtrRep = char 'p'
1335 pprUnionTag CodePtrRep = ptext SLIT("fp")
1336 pprUnionTag DataPtrRep = char 'd'
1337 pprUnionTag RetRep = char 'p'
1338 pprUnionTag CostCentreRep = panic "pprUnionTag:CostCentre?"
1340 pprUnionTag CharRep = char 'c'
1341 pprUnionTag Int8Rep = ptext SLIT("i8")
1342 pprUnionTag IntRep = char 'i'
1343 pprUnionTag WordRep = char 'w'
1344 pprUnionTag Int32Rep = char 'i'
1345 pprUnionTag Word32Rep = char 'w'
1346 pprUnionTag AddrRep = char 'a'
1347 pprUnionTag FloatRep = char 'f'
1348 pprUnionTag DoubleRep = panic "pprUnionTag:Double?"
1350 pprUnionTag StablePtrRep = char 'p'
1352 pprUnionTag _ = panic "pprUnionTag:Odd kind"
1356 Find and print local and external declarations for a list of
1357 Abstract~C statements.
1359 pprTempAndExternDecls :: AbstractC -> (SDoc{-temps-}, SDoc{-externs-})
1360 pprTempAndExternDecls AbsCNop = (empty, empty)
1362 pprTempAndExternDecls (AbsCStmts stmt1 stmt2)
1363 = initTE (ppr_decls_AbsC stmt1 `thenTE` \ (t_p1, e_p1) ->
1364 ppr_decls_AbsC stmt2 `thenTE` \ (t_p2, e_p2) ->
1365 case (catMaybes [t_p1, t_p2]) of { real_temps ->
1366 case (catMaybes [e_p1, e_p2]) of { real_exts ->
1367 returnTE (vcat real_temps, vcat real_exts) }}
1370 pprTempAndExternDecls other_stmt
1371 = initTE (ppr_decls_AbsC other_stmt `thenTE` \ (maybe_t, maybe_e) ->
1382 pprBasicLit :: Literal -> SDoc
1383 pprPrimKind :: PrimRep -> SDoc
1385 pprBasicLit lit = ppr lit
1386 pprPrimKind k = ppr k
1390 %************************************************************************
1392 \subsection[a2r-monad]{Monadery}
1394 %************************************************************************
1396 We need some monadery to keep track of temps and externs we have already
1397 printed. This info must be threaded right through the Abstract~C, so
1398 it's most convenient to hide it in this monad.
1400 WDP 95/02: Switched from \tr{([Unique], [CLabel])} to
1401 \tr{(UniqSet, CLabelSet)}. Allegedly for efficiency.
1404 type CLabelSet = FiniteMap CLabel (){-any type will do-}
1405 emptyCLabelSet = emptyFM
1406 x `elementOfCLabelSet` labs
1407 = case (lookupFM labs x) of { Just _ -> True; Nothing -> False }
1409 addToCLabelSet set x = addToFM set x ()
1411 type TEenv = (UniqSet Unique, CLabelSet)
1413 type TeM result = TEenv -> (TEenv, result)
1415 initTE :: TeM a -> a
1417 = case sa (emptyUniqSet, emptyCLabelSet) of { (_, result) ->
1420 {-# INLINE thenTE #-}
1421 {-# INLINE returnTE #-}
1423 thenTE :: TeM a -> (a -> TeM b) -> TeM b
1425 = case a u of { (u_1, result_of_a) ->
1428 mapTE :: (a -> TeM b) -> [a] -> TeM [b]
1429 mapTE f [] = returnTE []
1431 = f x `thenTE` \ r ->
1432 mapTE f xs `thenTE` \ rs ->
1435 returnTE :: a -> TeM a
1436 returnTE result env = (env, result)
1438 -- these next two check whether the thing is already
1439 -- recorded, and THEN THEY RECORD IT
1440 -- (subsequent calls will return False for the same uniq/label)
1442 tempSeenTE :: Unique -> TeM Bool
1443 tempSeenTE uniq env@(seen_uniqs, seen_labels)
1444 = if (uniq `elementOfUniqSet` seen_uniqs)
1446 else ((addOneToUniqSet seen_uniqs uniq,
1450 labelSeenTE :: CLabel -> TeM Bool
1451 labelSeenTE lbl env@(seen_uniqs, seen_labels)
1452 = if (lbl `elementOfCLabelSet` seen_labels)
1455 addToCLabelSet seen_labels lbl),
1460 pprTempDecl :: Unique -> PrimRep -> SDoc
1461 pprTempDecl uniq kind
1462 = hcat [ pprPrimKind kind, space, char '_', pprUnique uniq, ptext SLIT("_;") ]
1464 pprExternDecl :: Bool -> CLabel -> SDoc
1465 pprExternDecl in_srt clabel
1466 | not (needsCDecl clabel) = empty -- do not print anything for "known external" things
1468 hcat [ ppLocalnessMacro (not in_srt) clabel,
1469 lparen, dyn_wrapper (pprCLabel clabel), pp_paren_semi ]
1472 | in_srt && labelDynamic clabel = text "DLL_IMPORT_DATA_VAR" <> parens d
1478 ppr_decls_AbsC :: AbstractC -> TeM (Maybe SDoc{-temps-}, Maybe SDoc{-externs-})
1480 ppr_decls_AbsC AbsCNop = returnTE (Nothing, Nothing)
1482 ppr_decls_AbsC (AbsCStmts stmts_1 stmts_2)
1483 = ppr_decls_AbsC stmts_1 `thenTE` \ p1 ->
1484 ppr_decls_AbsC stmts_2 `thenTE` \ p2 ->
1485 returnTE (maybe_vcat [p1, p2])
1487 ppr_decls_AbsC (CSplitMarker) = returnTE (Nothing, Nothing)
1489 ppr_decls_AbsC (CAssign dest source)
1490 = ppr_decls_Amode dest `thenTE` \ p1 ->
1491 ppr_decls_Amode source `thenTE` \ p2 ->
1492 returnTE (maybe_vcat [p1, p2])
1494 ppr_decls_AbsC (CJump target) = ppr_decls_Amode target
1496 ppr_decls_AbsC (CFallThrough target) = ppr_decls_Amode target
1498 ppr_decls_AbsC (CReturn target _) = ppr_decls_Amode target
1500 ppr_decls_AbsC (CSwitch discrim alts deflt)
1501 = ppr_decls_Amode discrim `thenTE` \ pdisc ->
1502 mapTE ppr_alt_stuff alts `thenTE` \ palts ->
1503 ppr_decls_AbsC deflt `thenTE` \ pdeflt ->
1504 returnTE (maybe_vcat (pdisc:pdeflt:palts))
1506 ppr_alt_stuff (_, absC) = ppr_decls_AbsC absC
1508 ppr_decls_AbsC (CCodeBlock lbl absC)
1509 = ppr_decls_AbsC absC
1511 ppr_decls_AbsC (CInitHdr cl_info reg_rel cost_centre _)
1512 -- ToDo: strictly speaking, should chk "cost_centre" amode
1513 = labelSeenTE info_lbl `thenTE` \ label_seen ->
1518 Just (pprExternDecl False{-not in an SRT decl-} info_lbl))
1520 info_lbl = infoTableLabelFromCI cl_info
1522 ppr_decls_AbsC (CMachOpStmt res _ args _) = ppr_decls_Amodes (res : args)
1523 ppr_decls_AbsC (COpStmt results _ args _) = ppr_decls_Amodes (results ++ args)
1525 ppr_decls_AbsC (CSimultaneous abc) = ppr_decls_AbsC abc
1527 ppr_decls_AbsC (CSequential abcs)
1528 = mapTE ppr_decls_AbsC abcs `thenTE` \ t_and_e_s ->
1529 returnTE (maybe_vcat t_and_e_s)
1531 ppr_decls_AbsC (CCheck _ amodes code) =
1532 ppr_decls_Amodes amodes `thenTE` \p1 ->
1533 ppr_decls_AbsC code `thenTE` \p2 ->
1534 returnTE (maybe_vcat [p1,p2])
1536 ppr_decls_AbsC (CMacroStmt _ amodes) = ppr_decls_Amodes amodes
1538 ppr_decls_AbsC (CCallProfCtrMacro _ amodes) = ppr_decls_Amodes [] -- *****!!!
1539 -- you get some nasty re-decls of stdio.h if you compile
1540 -- the prelude while looking inside those amodes;
1541 -- no real reason to, anyway.
1542 ppr_decls_AbsC (CCallProfCCMacro _ amodes) = ppr_decls_Amodes amodes
1544 ppr_decls_AbsC (CStaticClosure _ closure_info cost_centre amodes)
1545 -- ToDo: strictly speaking, should chk "cost_centre" amode
1546 = ppr_decls_Amodes amodes
1548 ppr_decls_AbsC (CClosureInfoAndCode cl_info entry)
1549 = ppr_decls_Amodes [entry_lbl] `thenTE` \ p1 ->
1550 ppr_decls_AbsC entry `thenTE` \ p2 ->
1551 returnTE (maybe_vcat [p1, p2])
1553 entry_lbl = CLbl (entryLabelFromCI cl_info) CodePtrRep
1555 ppr_decls_AbsC (CSRT _ closure_lbls)
1556 = mapTE labelSeenTE closure_lbls `thenTE` \ seen ->
1558 if and seen then Nothing
1559 else Just (vcat [ pprExternDecl True{-in SRT decl-} l
1560 | (l,False) <- zip closure_lbls seen ]))
1562 ppr_decls_AbsC (CRetDirect _ code _ _) = ppr_decls_AbsC code
1563 ppr_decls_AbsC (CRetVector _ amodes _ _) = ppr_decls_Amodes amodes
1564 ppr_decls_AbsC (CModuleInitBlock _ _ code) = ppr_decls_AbsC code
1566 ppr_decls_AbsC (_) = returnTE (Nothing, Nothing)
1570 ppr_decls_Amode :: CAddrMode -> TeM (Maybe SDoc, Maybe SDoc)
1571 ppr_decls_Amode (CVal (CIndex base offset _) _) = ppr_decls_Amodes [base,offset]
1572 ppr_decls_Amode (CAddr (CIndex base offset _)) = ppr_decls_Amodes [base,offset]
1573 ppr_decls_Amode (CVal _ _) = returnTE (Nothing, Nothing)
1574 ppr_decls_Amode (CAddr _) = returnTE (Nothing, Nothing)
1575 ppr_decls_Amode (CReg _) = returnTE (Nothing, Nothing)
1576 ppr_decls_Amode (CLit _) = returnTE (Nothing, Nothing)
1578 -- CIntLike must be a literal -- no decls
1579 ppr_decls_Amode (CIntLike int) = returnTE (Nothing, Nothing)
1582 ppr_decls_Amode (CCharLike char) = returnTE (Nothing, Nothing)
1584 -- now, the only place where we actually print temps/externs...
1585 ppr_decls_Amode (CTemp uniq kind)
1587 VoidRep -> returnTE (Nothing, Nothing)
1589 tempSeenTE uniq `thenTE` \ temp_seen ->
1591 (if temp_seen then Nothing else Just (pprTempDecl uniq kind), Nothing)
1593 ppr_decls_Amode (CLbl lbl VoidRep)
1594 = returnTE (Nothing, Nothing)
1596 ppr_decls_Amode (CLbl lbl kind)
1597 = labelSeenTE lbl `thenTE` \ label_seen ->
1599 if label_seen then Nothing else Just (pprExternDecl False{-not in an SRT decl-} lbl))
1601 ppr_decls_Amode (CMacroExpr _ _ amodes)
1602 = ppr_decls_Amodes amodes
1604 ppr_decls_Amode other = returnTE (Nothing, Nothing)
1607 maybe_vcat :: [(Maybe SDoc, Maybe SDoc)] -> (Maybe SDoc, Maybe SDoc)
1609 = case (unzip ps) of { (ts, es) ->
1610 case (catMaybes ts) of { real_ts ->
1611 case (catMaybes es) of { real_es ->
1612 (if (null real_ts) then Nothing else Just (vcat real_ts),
1613 if (null real_es) then Nothing else Just (vcat real_es))
1618 ppr_decls_Amodes :: [CAddrMode] -> TeM (Maybe SDoc, Maybe SDoc)
1619 ppr_decls_Amodes amodes
1620 = mapTE ppr_decls_Amode amodes `thenTE` \ ps ->
1621 returnTE ( maybe_vcat ps )
1624 Print out a C Label where you want the *address* of the label, not the
1625 object it refers to. The distinction is important when the label may
1626 refer to a C structure (info tables and closures, for instance).
1628 When just generating a declaration for the label, use pprCLabel.
1631 pprCLabelAddr :: CLabel -> SDoc
1632 pprCLabelAddr clabel =
1633 case labelType clabel of
1634 InfoTblType -> addr_of_label
1635 RetInfoTblType -> addr_of_label
1636 ClosureType -> addr_of_label
1637 VecTblType -> addr_of_label
1638 DataType -> addr_of_label
1642 addr_of_label = ptext SLIT("(P_)&") <> pp_label
1643 pp_label = pprCLabel clabel
1646 -----------------------------------------------------------------------------
1647 Initialising static objects with floating-point numbers. We can't
1648 just emit the floating point number, because C will cast it to an int
1649 by rounding it. We want the actual bit-representation of the float.
1651 This is a hack to turn the floating point numbers into ints that we
1652 can safely initialise to static locations.
1655 big_doubles = (getPrimRepSize DoubleRep) /= 1
1657 #if __GLASGOW_HASKELL__ >= 504
1658 newFloatArray :: (Int,Int) -> ST s (STUArray s Int Float)
1659 newFloatArray = newArray_
1661 newDoubleArray :: (Int,Int) -> ST s (STUArray s Int Double)
1662 newDoubleArray = newArray_
1664 castFloatToIntArray :: STUArray s Int Float -> ST s (STUArray s Int Int)
1665 castFloatToIntArray = castSTUArray
1667 castDoubleToIntArray :: STUArray s Int Double -> ST s (STUArray s Int Int)
1668 castDoubleToIntArray = castSTUArray
1670 writeFloatArray :: STUArray s Int Float -> Int -> Float -> ST s ()
1671 writeFloatArray = writeArray
1673 writeDoubleArray :: STUArray s Int Double -> Int -> Double -> ST s ()
1674 writeDoubleArray = writeArray
1676 readIntArray :: STUArray s Int Int -> Int -> ST s Int
1677 readIntArray = readArray
1681 castFloatToIntArray :: MutableByteArray s t -> ST s (MutableByteArray s t)
1682 castFloatToIntArray = return
1684 castDoubleToIntArray :: MutableByteArray s t -> ST s (MutableByteArray s t)
1685 castDoubleToIntArray = return
1689 -- floats are always 1 word
1690 floatToWord :: CAddrMode -> CAddrMode
1691 floatToWord (CLit (MachFloat r))
1693 arr <- newFloatArray ((0::Int),0)
1694 writeFloatArray arr 0 (fromRational r)
1695 arr' <- castFloatToIntArray arr
1696 i <- readIntArray arr' 0
1697 return (CLit (MachInt (toInteger i)))
1700 doubleToWords :: CAddrMode -> [CAddrMode]
1701 doubleToWords (CLit (MachDouble r))
1702 | big_doubles -- doubles are 2 words
1704 arr <- newDoubleArray ((0::Int),1)
1705 writeDoubleArray arr 0 (fromRational r)
1706 arr' <- castDoubleToIntArray arr
1707 i1 <- readIntArray arr' 0
1708 i2 <- readIntArray arr' 1
1709 return [ CLit (MachInt (toInteger i1))
1710 , CLit (MachInt (toInteger i2))
1713 | otherwise -- doubles are 1 word
1715 arr <- newDoubleArray ((0::Int),0)
1716 writeDoubleArray arr 0 (fromRational r)
1717 arr' <- castDoubleToIntArray arr
1718 i <- readIntArray arr' 0
1719 return [ CLit (MachInt (toInteger i)) ]