2 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
4 % $Id: CgCase.lhs,v 1.52 2001/05/22 13:43:15 simonpj Exp $
6 %********************************************************
8 \section[CgCase]{Converting @StgCase@ expressions}
10 %********************************************************
13 module CgCase ( cgCase, saveVolatileVarsAndRegs, restoreCurrentCostCentre
16 #include "HsVersions.h"
18 import {-# SOURCE #-} CgExpr ( cgExpr )
24 import AbsCUtils ( mkAbstractCs, mkAbsCStmts, mkAlgAltsCSwitch,
25 getAmodeRep, nonemptyAbsC
27 import CgUpdate ( reserveSeqFrame )
28 import CgBindery ( getVolatileRegs, getArgAmodes,
29 bindNewToReg, bindNewToTemp,
30 bindNewPrimToAmode, getCAddrModeAndInfo,
31 rebindToStack, getCAddrMode, getCAddrModeIfVolatile,
32 buildContLivenessMask, nukeDeadBindings,
34 import CgCon ( bindConArgs, bindUnboxedTupleComponents )
35 import CgHeapery ( altHeapCheck )
36 import CgRetConv ( dataReturnConvPrim, ctrlReturnConvAlg,
37 CtrlReturnConvention(..)
39 import CgStackery ( allocPrimStack, allocStackTop,
40 deAllocStackTop, freeStackSlots, dataStackSlots
42 import CgTailCall ( tailCallFun )
43 import CgUsages ( getSpRelOffset )
44 import CLabel ( mkVecTblLabel, mkClosureTblLabel,
45 mkDefaultLabel, mkAltLabel, mkReturnInfoLabel
47 import ClosureInfo ( mkLFArgument )
48 import CmdLineOpts ( opt_SccProfilingOn )
49 import Id ( Id, idPrimRep, isDeadBinder )
50 import DataCon ( DataCon, dataConTag, fIRST_TAG, ConTag )
51 import VarSet ( varSetElems )
52 import Literal ( Literal )
53 import PrimOp ( primOpOutOfLine, PrimOp(..) )
54 import PrimRep ( getPrimRepSize, retPrimRepSize, PrimRep(..)
56 import TyCon ( isEnumerationTyCon, isUnboxedTupleTyCon, tyConPrimRep )
57 import Unique ( Unique, Uniquable(..), newTagUnique )
58 import Maybes ( maybeToBool )
65 = GCMayHappen -- The scrutinee may involve GC, so everything must be
66 -- tidy before the code for the scrutinee.
68 | NoGC -- The scrutinee is a primitive value, or a call to a
69 -- primitive op which does no GC. Hence the case can
70 -- be done inline, without tidying up first.
73 It is quite interesting to decide whether to put a heap-check
74 at the start of each alternative. Of course we certainly have
75 to do so if the case forces an evaluation, or if there is a primitive
76 op which can trigger GC.
78 A more interesting situation is this:
85 default -> !C!; ...C...
88 where \tr{!x!} indicates a possible heap-check point. The heap checks
89 in the alternatives {\em can} be omitted, in which case the topmost
90 heapcheck will take their worst case into account.
92 In favour of omitting \tr{!B!}, \tr{!C!}:
94 - {\em May} save a heap overflow test,
95 if ...A... allocates anything. The other advantage
96 of this is that we can use relative addressing
97 from a single Hp to get at all the closures so allocated.
99 - No need to save volatile vars etc across the case
103 - May do more allocation than reqd. This sometimes bites us
104 badly. For example, nfib (ha!) allocates about 30\% more space if the
105 worst-casing is done, because many many calls to nfib are leaf calls
106 which don't need to allocate anything.
108 This never hurts us if there is only one alternative.
120 Special case #1: PrimOps returning enumeration types.
122 For enumeration types, we invent a temporary (builtin-unique 1) to
123 hold the tag, and cross our fingers that this doesn't clash with
124 anything else. Builtin-unique 0 is used for a similar reason when
125 compiling enumerated-type primops in CgExpr.lhs. We can't use the
126 unique from the case binder, because this is used to hold the actual
127 closure (when the case binder is live, that is).
129 There is an extra special case for
134 which generates no code for the primop, unless x is used in the
135 alternatives (in which case we lookup the tag in the relevant closure
136 table to get the closure).
138 Being a bit short of uniques for temporary variables here, we use
139 newTagUnique to generate a new unique from the case binder. The case
140 binder's unique will presumably have the 'c' tag (generated by
141 CoreToStg), so we just change its tag to 'C' (for 'case') to ensure it
142 doesn't clash with anything else.
145 cgCase (StgOpApp op args _)
146 live_in_whole_case live_in_alts bndr srt (StgAlgAlts (Just tycon) alts deflt)
147 | isEnumerationTyCon tycon
148 = getArgAmodes args `thenFC` \ arg_amodes ->
151 StgPrimOp TagToEnumOp -- No code!
152 -> returnFC (only arg_amodes) ;
154 _ -> -- Perform the operation
156 tag_amode = CTemp (newTagUnique (getUnique bndr) 'C') IntRep
158 getVolatileRegs live_in_alts `thenFC` \ vol_regs ->
159 absC (COpStmt [tag_amode] op arg_amodes vol_regs) `thenC`
160 -- NB: no liveness arg
162 } `thenFC` \ tag_amode ->
165 closure = CVal (CIndex (CLbl (mkClosureTblLabel tycon) PtrRep)
170 -- Bind the default binder if necessary
171 -- The deadness info is set by StgVarInfo
172 (if (isDeadBinder bndr)
174 else bindNewToTemp bndr `thenFC` \ bndr_amode ->
175 absC (CAssign bndr_amode closure))
179 cgAlgAlts NoGC (getUnique bndr) Nothing{-cc_slot-} False{-no semi-tagging-}
180 False{-not poly case-} alts deflt
181 False{-don't emit yield-} `thenFC` \ (tagged_alts, deflt_c) ->
184 absC (mkAlgAltsCSwitch tag_amode tagged_alts deflt_c)
187 Special case #2: inline PrimOps.
190 cgCase (StgOpApp op@(StgPrimOp primop) args _)
191 live_in_whole_case live_in_alts bndr srt alts
192 | not (primOpOutOfLine primop)
194 -- Get amodes for the arguments and results
195 getArgAmodes args `thenFC` \ arg_amodes ->
196 getVolatileRegs live_in_alts `thenFC` \ vol_regs ->
199 StgPrimAlts tycon alts deflt -- PRIMITIVE ALTS
200 -> absC (COpStmt [CTemp (getUnique bndr) (tyConPrimRep tycon)]
202 arg_amodes -- note: no liveness arg
204 cgPrimInlineAlts bndr tycon alts deflt
206 StgAlgAlts (Just tycon) [(_, args, _, rhs)] StgNoDefault
207 | isUnboxedTupleTyCon tycon -- UNBOXED TUPLE ALTS
208 -> -- no heap check, no yield, just get in there and do it.
209 absC (COpStmt [ CTemp (getUnique arg) (idPrimRep arg) | arg <- args ]
211 arg_amodes -- note: no liveness arg
213 mapFCs bindNewToTemp args `thenFC` \ _ ->
216 other -> pprPanic "cgCase: case of primop has strange alts" (pprStgAlts alts)
219 TODO: Case-of-case of primop can probably be done inline too (but
220 maybe better to translate it out beforehand). See
221 ghc/lib/misc/PackedString.lhs for examples where this crops up (with
224 Another special case: scrutinising a primitive-typed variable. No
225 evaluation required. We don't save volatile variables, nor do we do a
226 heap-check in the alternatives. Instead, the heap usage of the
227 alternatives is worst-cased and passed upstream. This can result in
228 allocating more heap than strictly necessary, but it will sometimes
229 eliminate a heap check altogether.
232 cgCase (StgApp v []) live_in_whole_case live_in_alts bndr srt
233 (StgPrimAlts tycon alts deflt)
236 getCAddrMode v `thenFC` \amode ->
239 Careful! we can't just bind the default binder to the same thing
240 as the scrutinee, since it might be a stack location, and having
241 two bindings pointing at the same stack locn doesn't work (it
242 confuses nukeDeadBindings). Hence, use a new temp.
244 bindNewToTemp bndr `thenFC` \deflt_amode ->
245 absC (CAssign deflt_amode amode) `thenC`
247 cgPrimAlts NoGC amode alts deflt []
250 Special case: scrutinising a non-primitive variable.
251 This can be done a little better than the general case, because
252 we can reuse/trim the stack slot holding the variable (if it is in one).
255 cgCase (StgApp fun args)
256 live_in_whole_case live_in_alts bndr srt alts
257 = getCAddrModeAndInfo fun `thenFC` \ (fun', fun_amode, lf_info) ->
258 getArgAmodes args `thenFC` \ arg_amodes ->
260 -- Squish the environment
261 nukeDeadBindings live_in_alts `thenC`
262 saveVolatileVarsAndRegs live_in_alts
263 `thenFC` \ (save_assts, alts_eob_info, maybe_cc_slot) ->
265 allocStackTop retPrimRepSize `thenFC` \_ ->
267 forkEval alts_eob_info nopC (
268 deAllocStackTop retPrimRepSize `thenFC` \_ ->
269 cgEvalAlts maybe_cc_slot bndr srt alts)
270 `thenFC` \ scrut_eob_info ->
272 setEndOfBlockInfo (maybeReserveSeqFrame alts scrut_eob_info) $
273 tailCallFun fun' fun_amode lf_info arg_amodes save_assts
276 Note about return addresses: we *always* push a return address, even
277 if because of an optimisation we end up jumping direct to the return
278 code (not through the address itself). The alternatives always assume
279 that the return address is on the stack. The return address is
280 required in case the alternative performs a heap check, since it
281 encodes the liveness of the slots in the activation record.
283 On entry to the case alternative, we can re-use the slot containing
284 the return address immediately after the heap check. That's what the
285 deAllocStackTop call is doing above.
287 Finally, here is the general case.
290 cgCase expr live_in_whole_case live_in_alts bndr srt alts
291 = -- Figure out what volatile variables to save
292 nukeDeadBindings live_in_whole_case `thenC`
294 saveVolatileVarsAndRegs live_in_alts
295 `thenFC` \ (save_assts, alts_eob_info, maybe_cc_slot) ->
297 -- Save those variables right now!
298 absC save_assts `thenC`
300 -- generate code for the alts
301 forkEval alts_eob_info
302 (nukeDeadBindings live_in_alts `thenC`
303 allocStackTop retPrimRepSize -- space for retn address
306 (deAllocStackTop retPrimRepSize `thenFC` \_ ->
307 cgEvalAlts maybe_cc_slot bndr srt alts) `thenFC` \ scrut_eob_info ->
309 setEndOfBlockInfo (maybeReserveSeqFrame alts scrut_eob_info) $
313 There's a lot of machinery going on behind the scenes to manage the
314 stack pointer here. forkEval takes the virtual Sp and free list from
315 the first argument, and turns that into the *real* Sp for the second
316 argument. It also uses this virtual Sp as the args-Sp in the EOB info
317 returned, so that the scrutinee will trim the real Sp back to the
318 right place before doing whatever it does.
319 --SDM (who just spent an hour figuring this out, and didn't want to
322 Why don't we push the return address just before evaluating the
323 scrutinee? Because the slot reserved for the return address might
324 contain something useful, so we wait until performing a tail call or
325 return before pushing the return address (see
326 CgTailCall.pushReturnAddress).
328 This also means that the environment doesn't need to know about the
329 free stack slot for the return address (for generating bitmaps),
330 because we don't reserve it until just before the eval.
332 TODO!! Problem: however, we have to save the current cost centre
333 stack somewhere, because at the eval point the current CCS might be
334 different. So we pick a free stack slot and save CCCS in it. The
335 problem with this is that this slot isn't recorded as free/unboxed in
336 the environment, so a case expression in the scrutinee will have the
337 wrong bitmap attached. Fortunately we don't ever seem to see
338 case-of-case at the back end. One solution might be to shift the
339 saved CCS to the correct place in the activation record just before
343 (one consequence of the above is that activation records on the stack
344 don't follow the layout of closures when we're profiling. The CCS
345 could be anywhere within the record).
348 -- We need to reserve a seq frame for a polymorphic case
349 maybeReserveSeqFrame (StgAlgAlts Nothing _ _) scrut_eob_info = reserveSeqFrame scrut_eob_info
350 maybeReserveSeqFrame other scrut_eob_info = scrut_eob_info
353 %************************************************************************
355 \subsection[CgCase-alts]{Alternatives}
357 %************************************************************************
359 @cgEvalAlts@ returns an addressing mode for a continuation for the
360 alternatives of a @case@, used in a context when there
361 is some evaluation to be done.
364 cgEvalAlts :: Maybe VirtualSpOffset -- Offset of cost-centre to be restored, if any
366 -> SRT -- SRT for the continuation
368 -> FCode Sequel -- Any addr modes inside are guaranteed
369 -- to be a label so that we can duplicate it
370 -- without risk of duplicating code
372 cgEvalAlts cc_slot bndr srt alts
374 let uniq = getUnique bndr in
376 buildContLivenessMask uniq `thenFC` \ liveness_mask ->
380 -- algebraic alts ...
381 StgAlgAlts maybe_tycon alts deflt ->
383 -- bind the default binder (it covers all the alternatives)
384 bindNewToReg bndr node mkLFArgument `thenC`
386 -- Generate sequel info for use downstream
387 -- At the moment, we only do it if the type is vector-returnable.
388 -- Reason: if not, then it costs extra to label the
389 -- alternatives, because we'd get return code like:
391 -- switch TagReg { 0 : JMP(alt_1); 1 : JMP(alt_2) ..etc }
393 -- which is worse than having the alt code in the switch statement
395 let is_alg = maybeToBool maybe_tycon
396 Just spec_tycon = maybe_tycon
399 -- deal with the unboxed tuple case
400 if is_alg && isUnboxedTupleTyCon spec_tycon then
402 [alt] -> let lbl = mkReturnInfoLabel uniq in
403 cgUnboxedTupleAlt uniq cc_slot True alt
405 getSRTLabel `thenFC` \srt_label ->
406 absC (CRetDirect uniq abs_c (srt_label, srt)
407 liveness_mask) `thenC`
408 returnFC (CaseAlts (CLbl lbl RetRep) Nothing)
409 _ -> panic "cgEvalAlts: dodgy case of unboxed tuple type"
411 -- normal algebraic (or polymorphic) case alternatives
413 ret_conv | is_alg = ctrlReturnConvAlg spec_tycon
414 | otherwise = UnvectoredReturn 0
416 use_labelled_alts = case ret_conv of
417 VectoredReturn _ -> True
421 = if use_labelled_alts then
422 cgSemiTaggedAlts bndr alts deflt -- Just <something>
424 Nothing -- no semi-tagging info
427 cgAlgAlts GCMayHappen uniq cc_slot use_labelled_alts (not is_alg)
428 alts deflt True `thenFC` \ (tagged_alt_absCs, deflt_absC) ->
430 mkReturnVector uniq tagged_alt_absCs deflt_absC srt liveness_mask
431 ret_conv `thenFC` \ return_vec ->
433 returnFC (CaseAlts return_vec semi_tagged_stuff)
436 StgPrimAlts tycon alts deflt ->
438 -- Restore the cost centre
439 restoreCurrentCostCentre cc_slot `thenFC` \ cc_restore ->
441 -- Generate the switch
442 getAbsC (cgPrimEvalAlts bndr tycon alts deflt) `thenFC` \ abs_c ->
444 -- Generate the labelled block, starting with restore-cost-centre
445 getSRTLabel `thenFC` \srt_label ->
446 absC (CRetDirect uniq (cc_restore `mkAbsCStmts` abs_c)
447 (srt_label,srt) liveness_mask) `thenC`
449 -- Return an amode for the block
450 returnFC (CaseAlts (CLbl (mkReturnInfoLabel uniq) RetRep) Nothing)
454 HWL comment on {\em GrAnSim\/} (adding GRAN_YIELDs for context switch): If
455 we do an inlining of the case no separate functions for returning are
456 created, so we don't have to generate a GRAN_YIELD in that case. This info
457 must be propagated to cgAlgAltRhs (where the GRAN_YIELD macro might be
458 emitted). Hence, the new Bool arg to cgAlgAltRhs.
460 %************************************************************************
462 \subsection[CgCase-alg-alts]{Algebraic alternatives}
464 %************************************************************************
466 In @cgAlgAlts@, none of the binders in the alternatives are
467 assumed to be yet bound.
469 HWL comment on {\em GrAnSim\/} (adding GRAN_YIELDs for context switch): The
470 last arg of cgAlgAlts indicates if we want a context switch at the
471 beginning of each alternative. Normally we want that. The only exception
472 are inlined alternatives.
477 -> Maybe VirtualSpOffset
478 -> Bool -- True <=> branches must be labelled
479 -> Bool -- True <=> polymorphic case
480 -> [(DataCon, [Id], [Bool], StgExpr)] -- The alternatives
481 -> StgCaseDefault -- The default
482 -> Bool -- Context switch at alts?
483 -> FCode ([(ConTag, AbstractC)], -- The branches
484 AbstractC -- The default case
487 cgAlgAlts gc_flag uniq restore_cc must_label_branches is_fun alts deflt
488 emit_yield{-should a yield macro be emitted?-}
490 = forkAlts (map (cgAlgAlt gc_flag uniq restore_cc must_label_branches emit_yield) alts)
491 (cgAlgDefault gc_flag is_fun uniq restore_cc must_label_branches deflt emit_yield)
495 cgAlgDefault :: GCFlag
496 -> Bool -- could be a function-typed result?
497 -> Unique -> Maybe VirtualSpOffset -> Bool -- turgid state...
498 -> StgCaseDefault -- input
500 -> FCode AbstractC -- output
502 cgAlgDefault gc_flag is_fun uniq cc_slot must_label_branch StgNoDefault _
505 cgAlgDefault gc_flag is_fun uniq cc_slot must_label_branch
507 emit_yield{-should a yield macro be emitted?-}
509 = -- We have arranged that Node points to the thing
510 restoreCurrentCostCentre cc_slot `thenFC` \restore_cc ->
511 getAbsC (absC restore_cc `thenC`
512 -- HWL: maybe need yield here
514 -- then yield [node] True
515 -- else absC AbsCNop) `thenC`
516 possibleHeapCheck gc_flag is_fun [node] [] Nothing (cgExpr rhs)
517 -- Node is live, but doesn't need to point at the thing itself;
518 -- it's ok for Node to point to an indirection or FETCH_ME
519 -- Hence no need to re-enter Node.
520 ) `thenFC` \ abs_c ->
523 final_abs_c | must_label_branch = CCodeBlock lbl abs_c
528 lbl = mkDefaultLabel uniq
530 -- HWL comment on GrAnSim: GRAN_YIELDs needed; emitted in cgAlgAltRhs
533 -> Unique -> Maybe VirtualSpOffset -> Bool -- turgid state
534 -> Bool -- Context switch at alts?
535 -> (DataCon, [Id], [Bool], StgExpr)
536 -> FCode (ConTag, AbstractC)
538 cgAlgAlt gc_flag uniq cc_slot must_label_branch
539 emit_yield{-should a yield macro be emitted?-}
540 (con, args, use_mask, rhs)
542 restoreCurrentCostCentre cc_slot `thenFC` \restore_cc ->
543 getAbsC (absC restore_cc `thenC`
544 -- HWL: maybe need yield here
546 -- then yield [node] True -- XXX live regs wrong
547 -- else absC AbsCNop) `thenC`
549 NoGC -> mapFCs bindNewToTemp args `thenFC` \_ -> nopC
550 GCMayHappen -> bindConArgs con args
552 possibleHeapCheck gc_flag False [node] [] Nothing (
554 ) `thenFC` \ abs_c ->
556 final_abs_c | must_label_branch = CCodeBlock lbl abs_c
559 returnFC (tag, final_abs_c)
562 lbl = mkAltLabel uniq tag
565 :: Unique -- unique for label of the alternative
566 -> Maybe VirtualSpOffset -- Restore cost centre
567 -> Bool -- ctxt switch
568 -> (DataCon, [Id], [Bool], StgExpr) -- alternative
571 cgUnboxedTupleAlt lbl cc_slot emit_yield (con,args,use_mask,rhs)
573 bindUnboxedTupleComponents args
574 `thenFC` \ (live_regs,tags,stack_res) ->
576 restoreCurrentCostCentre cc_slot `thenFC` \restore_cc ->
577 absC restore_cc `thenC`
579 -- HWL: maybe need yield here
581 -- then yield live_regs True -- XXX live regs wrong?
582 -- else absC AbsCNop) `thenC`
584 -- ToDo: could maybe use Nothing here if stack_res is False
585 -- since the heap-check can just return to the top of the
590 -- free up stack slots containing tags,
591 freeStackSlots (map fst tags) `thenC`
593 -- generate a heap check if necessary
594 possibleHeapCheck GCMayHappen False live_regs tags ret_addr (
596 -- and finally the code for the alternative
601 %************************************************************************
603 \subsection[CgCase-semi-tagged-alts]{The code to deal with sem-tagging}
605 %************************************************************************
607 Turgid-but-non-monadic code to conjure up the required info from
608 algebraic case alternatives for semi-tagging.
611 cgSemiTaggedAlts :: Id
612 -> [(DataCon, [Id], [Bool], StgExpr)]
613 -> GenStgCaseDefault Id Id
616 cgSemiTaggedAlts binder alts deflt
617 = Just (map st_alt alts, st_deflt deflt)
619 uniq = getUnique binder
621 st_deflt StgNoDefault = Nothing
623 st_deflt (StgBindDefault _)
625 (CCallProfCtrMacro SLIT("RET_SEMI_BY_DEFAULT") [], -- ToDo: monadise?
629 st_alt (con, args, use_mask, _)
630 = -- Ha! Nothing to do; Node already points to the thing
632 (CCallProfCtrMacro SLIT("RET_SEMI_IN_HEAP") -- ToDo: monadise?
633 [mkIntCLit (length args)], -- how big the thing in the heap is
637 con_tag = dataConTag con
638 join_label = mkAltLabel uniq con_tag
641 %************************************************************************
643 \subsection[CgCase-prim-alts]{Primitive alternatives}
645 %************************************************************************
647 @cgPrimEvalAlts@ and @cgPrimInlineAlts@ generate suitable @CSwitch@es
648 for dealing with the alternatives of a primitive @case@, given an
649 addressing mode for the thing to scrutinise. It also keeps track of
650 the maximum stack depth encountered down any branch.
652 As usual, no binders in the alternatives are yet bound.
655 cgPrimInlineAlts bndr tycon alts deflt
656 = cgPrimAltsWithDefault bndr NoGC (CTemp uniq kind) alts deflt []
658 uniq = getUnique bndr
659 kind = tyConPrimRep tycon
661 cgPrimEvalAlts bndr tycon alts deflt
662 = cgPrimAltsWithDefault bndr GCMayHappen (CReg reg) alts deflt [reg]
664 reg = WARN( case kind of { PtrRep -> True; other -> False },
665 text "cgPrimEE" <+> ppr bndr <+> ppr tycon )
666 dataReturnConvPrim kind
667 kind = tyConPrimRep tycon
669 cgPrimAltsWithDefault bndr gc_flag scrutinee alts deflt regs
670 = -- first bind the default if necessary
671 bindNewPrimToAmode bndr scrutinee `thenC`
672 cgPrimAlts gc_flag scrutinee alts deflt regs
674 cgPrimAlts gc_flag scrutinee alts deflt regs
675 = forkAlts (map (cgPrimAlt gc_flag regs) alts)
676 (cgPrimDefault gc_flag regs deflt)
677 `thenFC` \ (alt_absCs, deflt_absC) ->
679 absC (CSwitch scrutinee alt_absCs deflt_absC)
680 -- CSwitch does sensible things with one or zero alternatives
684 -> [MagicId] -- live registers
685 -> (Literal, StgExpr) -- The alternative
686 -> FCode (Literal, AbstractC) -- Its compiled form
688 cgPrimAlt gc_flag regs (lit, rhs)
689 = getAbsC rhs_code `thenFC` \ absC ->
692 rhs_code = possibleHeapCheck gc_flag False regs [] Nothing (cgExpr rhs)
694 cgPrimDefault :: GCFlag
695 -> [MagicId] -- live registers
699 cgPrimDefault gc_flag regs StgNoDefault
700 = panic "cgPrimDefault: No default in prim case"
702 cgPrimDefault gc_flag regs (StgBindDefault rhs)
703 = getAbsC (possibleHeapCheck gc_flag False regs [] Nothing (cgExpr rhs))
707 %************************************************************************
709 \subsection[CgCase-tidy]{Code for tidying up prior to an eval}
711 %************************************************************************
714 saveVolatileVarsAndRegs
715 :: StgLiveVars -- Vars which should be made safe
716 -> FCode (AbstractC, -- Assignments to do the saves
717 EndOfBlockInfo, -- sequel for the alts
718 Maybe VirtualSpOffset) -- Slot for current cost centre
721 saveVolatileVarsAndRegs vars
722 = saveVolatileVars vars `thenFC` \ var_saves ->
723 saveCurrentCostCentre `thenFC` \ (maybe_cc_slot, cc_save) ->
724 getEndOfBlockInfo `thenFC` \ eob_info ->
725 returnFC (mkAbstractCs [var_saves, cc_save],
730 saveVolatileVars :: StgLiveVars -- Vars which should be made safe
731 -> FCode AbstractC -- Assignments to to the saves
733 saveVolatileVars vars
734 = save_em (varSetElems vars)
736 save_em [] = returnFC AbsCNop
739 = getCAddrModeIfVolatile var `thenFC` \ v ->
741 Nothing -> save_em vars -- Non-volatile, so carry on
744 Just vol_amode -> -- Aha! It's volatile
745 save_var var vol_amode `thenFC` \ abs_c ->
746 save_em vars `thenFC` \ abs_cs ->
747 returnFC (abs_c `mkAbsCStmts` abs_cs)
749 save_var var vol_amode
750 = allocPrimStack (getPrimRepSize kind) `thenFC` \ slot ->
751 rebindToStack var slot `thenC`
752 getSpRelOffset slot `thenFC` \ sp_rel ->
753 returnFC (CAssign (CVal sp_rel kind) vol_amode)
755 kind = getAmodeRep vol_amode
758 ---------------------------------------------------------------------------
760 When we save the current cost centre (which is done for lexical
761 scoping), we allocate a free stack location, and return (a)~the
762 virtual offset of the location, to pass on to the alternatives, and
763 (b)~the assignment to do the save (just as for @saveVolatileVars@).
766 saveCurrentCostCentre ::
767 FCode (Maybe VirtualSpOffset, -- Where we decide to store it
768 AbstractC) -- Assignment to save it
770 saveCurrentCostCentre
771 = if not opt_SccProfilingOn then
772 returnFC (Nothing, AbsCNop)
774 allocPrimStack (getPrimRepSize CostCentreRep) `thenFC` \ slot ->
775 dataStackSlots [slot] `thenC`
776 getSpRelOffset slot `thenFC` \ sp_rel ->
778 CAssign (CVal sp_rel CostCentreRep) (CReg CurCostCentre))
780 restoreCurrentCostCentre :: Maybe VirtualSpOffset -> FCode AbstractC
781 restoreCurrentCostCentre Nothing = returnFC AbsCNop
782 restoreCurrentCostCentre (Just slot)
783 = getSpRelOffset slot `thenFC` \ sp_rel ->
784 freeStackSlots [slot] `thenC`
785 returnFC (CCallProfCCMacro SLIT("RESTORE_CCCS") [CVal sp_rel CostCentreRep])
786 -- we use the RESTORE_CCCS macro, rather than just
787 -- assigning into CurCostCentre, in case RESTORE_CCCS
788 -- has some sanity-checking in it.
791 %************************************************************************
793 \subsection[CgCase-return-vec]{Building a return vector}
795 %************************************************************************
797 Build a return vector, and return a suitable label addressing
801 mkReturnVector :: Unique
802 -> [(ConTag, AbstractC)] -- Branch codes
803 -> AbstractC -- Default case
804 -> SRT -- continuation's SRT
805 -> Liveness -- stack liveness
806 -> CtrlReturnConvention
809 mkReturnVector uniq tagged_alt_absCs deflt_absC srt liveness ret_conv
810 = getSRTLabel `thenFC` \srt_label ->
812 (return_vec_amode, vtbl_body) = case ret_conv of {
814 -- might be a polymorphic case...
815 UnvectoredReturn 0 ->
816 ASSERT(null tagged_alt_absCs)
817 (CLbl ret_label RetRep,
818 absC (CRetDirect uniq deflt_absC (srt_label, srt) liveness));
820 UnvectoredReturn n ->
821 -- find the tag explicitly rather than using tag_reg for now.
822 -- on architectures with lots of regs the tag will be loaded
823 -- into tag_reg by the code doing the returning.
825 tag = CMacroExpr WordRep GET_TAG [CVal (nodeRel 0) DataPtrRep]
827 (CLbl ret_label RetRep,
828 absC (CRetDirect uniq
829 (mkAlgAltsCSwitch tag tagged_alt_absCs deflt_absC)
833 VectoredReturn table_size ->
835 (vector_table, alts_absC) =
836 unzip (map mk_vector_entry [fIRST_TAG .. (table_size+fIRST_TAG-1)])
838 ret_vector = CRetVector vtbl_label
840 (srt_label, srt) liveness
842 (CLbl vtbl_label DataPtrRep,
843 -- alts come first, because we don't want to declare all the symbols
844 absC (mkAbstractCs (mkAbstractCs alts_absC : [deflt_absC,ret_vector]))
849 returnFC return_vec_amode
853 vtbl_label = mkVecTblLabel uniq
854 ret_label = mkReturnInfoLabel uniq
857 case nonemptyAbsC deflt_absC of
858 -- the simplifier might have eliminated a case
859 Nothing -> mkIntCLit 0 -- CLbl mkErrorStdEntryLabel CodePtrRep
860 Just absC@(CCodeBlock lbl _) -> CLbl lbl CodePtrRep
862 mk_vector_entry :: ConTag -> (CAddrMode, AbstractC)
864 = case [ absC | (t, absC) <- tagged_alt_absCs, t == tag ] of
865 [] -> (deflt_lbl, AbsCNop)
866 [absC@(CCodeBlock lbl _)] -> (CLbl lbl CodePtrRep,absC)
867 _ -> panic "mkReturnVector: too many"
870 %************************************************************************
872 \subsection[CgCase-utils]{Utilities for handling case expressions}
874 %************************************************************************
876 @possibleHeapCheck@ tests a flag passed in to decide whether to do a
877 heap check or not. These heap checks are always in a case
878 alternative, so we use altHeapCheck.
883 -> Bool -- True <=> algebraic case
884 -> [MagicId] -- live registers
885 -> [(VirtualSpOffset,Int)] -- stack slots to tag
886 -> Maybe Unique -- return address unique
887 -> Code -- continuation
890 possibleHeapCheck GCMayHappen is_alg regs tags lbl code
891 = altHeapCheck is_alg regs tags AbsCNop lbl code
892 possibleHeapCheck NoGC _ _ tags lbl code