2 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
4 % $Id: CgCase.lhs,v 1.66 2003/07/22 16:11:26 simonmar Exp $
6 %********************************************************
8 \section[CgCase]{Converting @StgCase@ expressions}
10 %********************************************************
13 module CgCase ( cgCase, saveVolatileVarsAndRegs,
14 mkRetDirectTarget, restoreCurrentCostCentre
17 #include "HsVersions.h"
19 import {-# SOURCE #-} CgExpr ( cgExpr )
25 import AbsCUtils ( mkAbstractCs, mkAbsCStmts, mkAlgAltsCSwitch, getAmodeRep )
26 import CgBindery ( getVolatileRegs, getArgAmodes,
27 bindNewToReg, bindNewToTemp,
29 rebindToStack, getCAddrMode, getCAddrModeIfVolatile,
30 buildContLivenessMask, nukeDeadBindings,
32 import CgCon ( bindConArgs, bindUnboxedTupleComponents )
33 import CgHeapery ( altHeapCheck, unbxTupleHeapCheck )
34 import CgRetConv ( dataReturnConvPrim, ctrlReturnConvAlg,
35 CtrlReturnConvention(..)
37 import CgStackery ( allocPrimStack, allocStackTop,
38 deAllocStackTop, freeStackSlots, dataStackSlots
40 import CgTailCall ( performTailCall )
41 import CgUsages ( getSpRelOffset )
42 import CLabel ( mkVecTblLabel, mkClosureTblLabel,
43 mkDefaultLabel, mkAltLabel, mkReturnInfoLabel
45 import ClosureInfo ( mkLFArgument )
46 import CmdLineOpts ( opt_SccProfilingOn )
47 import Id ( Id, idName, isDeadBinder )
48 import DataCon ( dataConTag, fIRST_TAG, ConTag )
49 import VarSet ( varSetElems )
50 import CoreSyn ( AltCon(..) )
51 import PrimOp ( primOpOutOfLine, PrimOp(..) )
52 import PrimRep ( getPrimRepSize, retPrimRepSize, PrimRep(..)
54 import TyCon ( TyCon, isEnumerationTyCon, tyConPrimRep )
55 import Unique ( Unique, Uniquable(..), newTagUnique )
57 import List ( sortBy )
63 = GCMayHappen -- The scrutinee may involve GC, so everything must be
64 -- tidy before the code for the scrutinee.
66 | NoGC -- The scrutinee is a primitive value, or a call to a
67 -- primitive op which does no GC. Hence the case can
68 -- be done inline, without tidying up first.
71 It is quite interesting to decide whether to put a heap-check
72 at the start of each alternative. Of course we certainly have
73 to do so if the case forces an evaluation, or if there is a primitive
74 op which can trigger GC.
76 A more interesting situation is this:
83 default -> !C!; ...C...
86 where \tr{!x!} indicates a possible heap-check point. The heap checks
87 in the alternatives {\em can} be omitted, in which case the topmost
88 heapcheck will take their worst case into account.
90 In favour of omitting \tr{!B!}, \tr{!C!}:
92 - {\em May} save a heap overflow test,
93 if ...A... allocates anything. The other advantage
94 of this is that we can use relative addressing
95 from a single Hp to get at all the closures so allocated.
97 - No need to save volatile vars etc across the case
101 - May do more allocation than reqd. This sometimes bites us
102 badly. For example, nfib (ha!) allocates about 30\% more space if the
103 worst-casing is done, because many many calls to nfib are leaf calls
104 which don't need to allocate anything.
106 This never hurts us if there is only one alternative.
119 Special case #1: case of literal.
122 cgCase (StgLit lit) live_in_whole_case live_in_alts bndr srt
123 alt_type@(PrimAlt tycon) alts
124 = bindNewToTemp bndr `thenFC` \ tmp_amode ->
125 absC (CAssign tmp_amode (CLit lit)) `thenC`
126 cgPrimAlts NoGC tmp_amode alts alt_type
129 Special case #2: scrutinising a primitive-typed variable. No
130 evaluation required. We don't save volatile variables, nor do we do a
131 heap-check in the alternatives. Instead, the heap usage of the
132 alternatives is worst-cased and passed upstream. This can result in
133 allocating more heap than strictly necessary, but it will sometimes
134 eliminate a heap check altogether.
137 cgCase (StgApp v []) live_in_whole_case live_in_alts bndr srt
138 alt_type@(PrimAlt tycon) alts
140 = -- Careful! we can't just bind the default binder to the same thing
141 -- as the scrutinee, since it might be a stack location, and having
142 -- two bindings pointing at the same stack locn doesn't work (it
143 -- confuses nukeDeadBindings). Hence, use a new temp.
144 getCAddrMode v `thenFC` \ amode ->
145 bindNewToTemp bndr `thenFC` \ tmp_amode ->
146 absC (CAssign tmp_amode amode) `thenC`
147 cgPrimAlts NoGC tmp_amode alts alt_type
150 Special case #3: inline PrimOps.
153 cgCase (StgOpApp op@(StgPrimOp primop) args _)
154 live_in_whole_case live_in_alts bndr srt alt_type alts
155 | not (primOpOutOfLine primop)
156 = -- Get amodes for the arguments and results
157 getArgAmodes args `thenFC` \ arg_amodes ->
158 getVolatileRegs live_in_alts `thenFC` \ vol_regs ->
161 PrimAlt tycon -- PRIMITIVE ALTS
162 -> bindNewToTemp bndr `thenFC` \ tmp_amode ->
163 absC (COpStmt [tmp_amode] op arg_amodes vol_regs) `thenC`
164 -- Note: no liveness arg
165 cgPrimAlts NoGC tmp_amode alts alt_type
167 UbxTupAlt tycon -- UNBOXED TUPLE ALTS
168 -> -- No heap check, no yield, just get in there and do it.
169 -- NB: the case binder isn't bound to anything;
170 -- it has a unboxed tuple type
171 mapFCs bindNewToTemp res_ids `thenFC` \ res_tmps ->
172 absC (COpStmt res_tmps op arg_amodes vol_regs) `thenC`
175 [(_, res_ids, _, rhs)] = alts
177 AlgAlt tycon -- ENUMERATION TYPE RETURN
178 -> ASSERT( isEnumerationTyCon tycon )
179 do_enum_primop primop `thenFC` \ tag_amode ->
181 -- Bind the default binder if necessary
182 -- (avoiding it avoids the assignment)
183 -- The deadness info is set by StgVarInfo
184 (if (isDeadBinder bndr)
186 else bindNewToTemp bndr `thenFC` \ tmp_amode ->
187 absC (CAssign tmp_amode (tagToClosure tycon tag_amode))
191 cgAlgAlts NoGC (getUnique bndr)
192 Nothing{-cc_slot-} False{-no semi-tagging-}
193 (AlgAlt tycon) alts `thenFC` \ tagged_alts ->
196 absC (mkAlgAltsCSwitch tag_amode tagged_alts)
198 do_enum_primop :: PrimOp -> FCode CAddrMode -- Returns amode for result
199 do_enum_primop TagToEnumOp -- No code!
200 = returnFC (only arg_amodes)
202 do_enum_primop primop
203 = absC (COpStmt [tag_amode] op arg_amodes vol_regs) `thenC`
206 tag_amode = CTemp (newTagUnique (getUnique bndr) 'C') IntRep
207 -- Being a bit short of uniques for temporary variables here,
208 -- we use newTagUnique to generate a new unique from the case
209 -- binder. The case binder's unique will presumably have
210 -- the 'c' tag (generated by CoreToStg), so we just change
211 -- its tag to 'C' (for 'case') to ensure it doesn't clash with
213 -- We can't use the unique from the case binder, becaus e
214 -- this is used to hold the actual result closure
215 -- (via the call to bindNewToTemp)
217 other -> pprPanic "cgCase: case of primop has strange alt type" (ppr alt_type)
220 TODO: Case-of-case of primop can probably be done inline too (but
221 maybe better to translate it out beforehand). See
222 ghc/lib/misc/PackedString.lhs for examples where this crops up (with
225 Special case: scrutinising a non-primitive variable.
226 This can be done a little better than the general case, because
227 we can reuse/trim the stack slot holding the variable (if it is in one).
230 cgCase (StgApp fun args)
231 live_in_whole_case live_in_alts bndr srt alt_type alts
232 = getCAddrModeAndInfo fun `thenFC` \ (fun', fun_amode, lf_info) ->
233 getArgAmodes args `thenFC` \ arg_amodes ->
235 -- Nuking dead bindings *before* calculating the saves is the
236 -- value-add here. We might end up freeing up some slots currently
237 -- occupied by variables only required for the call.
238 -- NOTE: we need to look up the variables used in the call before
239 -- doing this, because some of them may not be in the environment
241 nukeDeadBindings live_in_alts `thenC`
242 saveVolatileVarsAndRegs live_in_alts
243 `thenFC` \ (save_assts, alts_eob_info, maybe_cc_slot) ->
245 forkEval alts_eob_info
246 ( allocStackTop retPrimRepSize
247 `thenFC` \_ -> nopC )
248 ( deAllocStackTop retPrimRepSize `thenFC` \_ ->
249 cgEvalAlts maybe_cc_slot bndr srt alt_type alts )
250 `thenFC` \ scrut_eob_info ->
252 setEndOfBlockInfo (maybeReserveSeqFrame alt_type scrut_eob_info) $
253 performTailCall fun' fun_amode lf_info arg_amodes save_assts
256 Note about return addresses: we *always* push a return address, even
257 if because of an optimisation we end up jumping direct to the return
258 code (not through the address itself). The alternatives always assume
259 that the return address is on the stack. The return address is
260 required in case the alternative performs a heap check, since it
261 encodes the liveness of the slots in the activation record.
263 On entry to the case alternative, we can re-use the slot containing
264 the return address immediately after the heap check. That's what the
265 deAllocStackTop call is doing above.
267 Finally, here is the general case.
270 cgCase expr live_in_whole_case live_in_alts bndr srt alt_type alts
271 = -- Figure out what volatile variables to save
272 nukeDeadBindings live_in_whole_case `thenC`
274 saveVolatileVarsAndRegs live_in_alts
275 `thenFC` \ (save_assts, alts_eob_info, maybe_cc_slot) ->
277 -- Save those variables right now!
278 absC save_assts `thenC`
280 -- generate code for the alts
281 forkEval alts_eob_info
282 (nukeDeadBindings live_in_alts `thenC`
283 allocStackTop retPrimRepSize -- space for retn address
286 (deAllocStackTop retPrimRepSize `thenFC` \_ ->
287 cgEvalAlts maybe_cc_slot bndr srt alt_type alts) `thenFC` \ scrut_eob_info ->
289 setEndOfBlockInfo (maybeReserveSeqFrame alt_type scrut_eob_info) $
293 There's a lot of machinery going on behind the scenes to manage the
294 stack pointer here. forkEval takes the virtual Sp and free list from
295 the first argument, and turns that into the *real* Sp for the second
296 argument. It also uses this virtual Sp as the args-Sp in the EOB info
297 returned, so that the scrutinee will trim the real Sp back to the
298 right place before doing whatever it does.
299 --SDM (who just spent an hour figuring this out, and didn't want to
302 Why don't we push the return address just before evaluating the
303 scrutinee? Because the slot reserved for the return address might
304 contain something useful, so we wait until performing a tail call or
305 return before pushing the return address (see
306 CgTailCall.pushReturnAddress).
308 This also means that the environment doesn't need to know about the
309 free stack slot for the return address (for generating bitmaps),
310 because we don't reserve it until just before the eval.
312 TODO!! Problem: however, we have to save the current cost centre
313 stack somewhere, because at the eval point the current CCS might be
314 different. So we pick a free stack slot and save CCCS in it. The
315 problem with this is that this slot isn't recorded as free/unboxed in
316 the environment, so a case expression in the scrutinee will have the
317 wrong bitmap attached. Fortunately we don't ever seem to see
318 case-of-case at the back end. One solution might be to shift the
319 saved CCS to the correct place in the activation record just before
323 (one consequence of the above is that activation records on the stack
324 don't follow the layout of closures when we're profiling. The CCS
325 could be anywhere within the record).
328 maybeReserveSeqFrame PolyAlt (EndOfBlockInfo args_sp (CaseAlts amode stuff _))
329 = EndOfBlockInfo (args_sp + retPrimRepSize) (CaseAlts amode stuff True)
330 maybeReserveSeqFrame other scrut_eob_info = scrut_eob_info
333 %************************************************************************
335 \subsection[CgCase-alts]{Alternatives}
337 %************************************************************************
339 @cgEvalAlts@ returns an addressing mode for a continuation for the
340 alternatives of a @case@, used in a context when there
341 is some evaluation to be done.
344 cgEvalAlts :: Maybe VirtualSpOffset -- Offset of cost-centre to be restored, if any
346 -> SRT -- SRT for the continuation
349 -> FCode Sequel -- Any addr modes inside are guaranteed
350 -- to be a label so that we can duplicate it
351 -- without risk of duplicating code
353 cgEvalAlts cc_slot bndr srt (UbxTupAlt _) [(con,args,_,rhs)]
354 = -- Unboxed tuple case
355 -- By now, the simplifier should have have turned it
356 -- into case e of (# a,b #) -> e
357 -- There shouldn't be a
358 -- case e of DEFAULT -> e
359 ASSERT2( case con of { DataAlt _ -> True; other -> False },
360 text "cgEvalAlts: dodgy case of unboxed tuple type" )
362 forkAbsC ( -- forkAbsC for the RHS, so that the envt is
363 -- not changed for the mkRetDirect call
364 bindUnboxedTupleComponents args `thenFC` \ (live_regs, ptrs, nptrs, _) ->
365 -- restore the CC *after* binding the tuple components, so that we
366 -- get the stack offset of the saved CC right.
367 restoreCurrentCostCentre cc_slot True `thenC`
368 -- Generate a heap check if necessary
369 unbxTupleHeapCheck live_regs ptrs nptrs AbsCNop (
370 -- And finally the code for the alternative
372 )) `thenFC` \ abs_c ->
373 mkRetDirectTarget bndr abs_c srt `thenFC` \ lbl ->
374 returnFC (CaseAlts lbl Nothing False)
376 cgEvalAlts cc_slot bndr srt alt_type@(PrimAlt tycon) alts
377 = forkAbsC ( -- forkAbsC for the RHS, so that the envt is
378 -- not changed for the mkRetDirect call
379 restoreCurrentCostCentre cc_slot True `thenC`
380 bindNewToReg bndr reg (mkLFArgument bndr) `thenC`
381 cgPrimAlts GCMayHappen (CReg reg) alts alt_type
382 ) `thenFC` \ abs_c ->
383 mkRetDirectTarget bndr abs_c srt `thenFC` \ lbl ->
384 returnFC (CaseAlts lbl Nothing False)
386 reg = dataReturnConvPrim kind
387 kind = tyConPrimRep tycon
389 cgEvalAlts cc_slot bndr srt alt_type alts
390 = -- Algebraic and polymorphic case
391 -- Bind the default binder
392 bindNewToReg bndr node (mkLFArgument bndr) `thenC`
394 -- Generate sequel info for use downstream
395 -- At the moment, we only do it if the type is vector-returnable.
396 -- Reason: if not, then it costs extra to label the
397 -- alternatives, because we'd get return code like:
399 -- switch TagReg { 0 : JMP(alt_1); 1 : JMP(alt_2) ..etc }
401 -- which is worse than having the alt code in the switch statement
403 let ret_conv = case alt_type of
404 AlgAlt tc -> ctrlReturnConvAlg tc
405 PolyAlt -> UnvectoredReturn 0
407 use_labelled_alts = case ret_conv of
408 VectoredReturn _ -> True
411 semi_tagged_stuff = cgSemiTaggedAlts use_labelled_alts bndr alts
414 cgAlgAlts GCMayHappen (getUnique bndr)
415 cc_slot use_labelled_alts
416 alt_type alts `thenFC` \ tagged_alt_absCs ->
418 mkRetVecTarget bndr tagged_alt_absCs
419 srt ret_conv `thenFC` \ return_vec ->
421 returnFC (CaseAlts return_vec semi_tagged_stuff False)
425 HWL comment on {\em GrAnSim\/} (adding GRAN_YIELDs for context switch): If
426 we do an inlining of the case no separate functions for returning are
427 created, so we don't have to generate a GRAN_YIELD in that case. This info
428 must be propagated to cgAlgAltRhs (where the GRAN_YIELD macro might be
429 emitted). Hence, the new Bool arg to cgAlgAltRhs.
431 %************************************************************************
433 \subsection[CgCase-alg-alts]{Algebraic alternatives}
435 %************************************************************************
437 In @cgAlgAlts@, none of the binders in the alternatives are
438 assumed to be yet bound.
440 HWL comment on {\em GrAnSim\/} (adding GRAN_YIELDs for context switch): The
441 last arg of cgAlgAlts indicates if we want a context switch at the
442 beginning of each alternative. Normally we want that. The only exception
443 are inlined alternatives.
448 -> Maybe VirtualSpOffset
449 -> Bool -- True <=> branches must be labelled
450 -- (used for semi-tagging)
451 -> AltType -- ** AlgAlt or PolyAlt only **
452 -> [StgAlt] -- The alternatives
453 -> FCode [(AltCon, AbstractC)] -- The branches
455 cgAlgAlts gc_flag uniq restore_cc must_label_branches alt_type alts
456 = forkAlts [ cgAlgAlt gc_flag uniq restore_cc must_label_branches alt_type alt
460 -> Unique -> Maybe VirtualSpOffset -> Bool -- turgid state
461 -> AltType -- ** AlgAlt or PolyAlt only **
463 -> FCode (AltCon, AbstractC)
465 cgAlgAlt gc_flag uniq cc_slot must_label_branch
466 alt_type (con, args, use_mask, rhs)
467 = getAbsC (bind_con_args con args `thenFC` \ _ ->
468 restoreCurrentCostCentre cc_slot True `thenC`
469 maybeAltHeapCheck gc_flag alt_type (cgExpr rhs)
470 ) `thenFC` \ abs_c ->
472 final_abs_c | must_label_branch = CCodeBlock lbl abs_c
475 returnFC (con, final_abs_c)
478 DataAlt dc -> mkAltLabel uniq (dataConTag dc)
479 DEFAULT -> mkDefaultLabel uniq
480 other -> pprPanic "cgAlgAlt" (ppr con)
482 bind_con_args DEFAULT args = nopC
483 bind_con_args (DataAlt dc) args = bindConArgs dc args
486 %************************************************************************
488 \subsection[CgCase-semi-tagged-alts]{The code to deal with sem-tagging}
490 %************************************************************************
492 Turgid-but-non-monadic code to conjure up the required info from
493 algebraic case alternatives for semi-tagging.
496 cgSemiTaggedAlts :: Bool -- True <=> use semitagging: each alt will be labelled
501 cgSemiTaggedAlts False binder alts
503 cgSemiTaggedAlts True binder alts
504 = Just ([st_alt con args | (DataAlt con, args, _, _) <- alts],
506 (DEFAULT, _, _, _) -> Just st_deflt
509 uniq = getUnique binder
512 (CCallProfCtrMacro FSLIT("RET_SEMI_BY_DEFAULT") [], -- ToDo: monadise?
513 mkDefaultLabel uniq))
515 st_alt con args -- Ha! Nothing to do; Node already points to the thing
517 (CCallProfCtrMacro FSLIT("RET_SEMI_IN_HEAP") -- ToDo: monadise?
518 [mkIntCLit (length args)], -- how big the thing in the heap is
522 con_tag = dataConTag con
523 join_label = mkAltLabel uniq con_tag
526 tagToClosure :: TyCon -> CAddrMode -> CAddrMode
527 -- Primops returning an enumeration type (notably Bool)
528 -- actually return an index into
529 -- the table of closures for the enumeration type
530 tagToClosure tycon tag_amode
531 = CVal (CIndex closure_tbl tag_amode PtrRep) PtrRep
533 closure_tbl = CLbl (mkClosureTblLabel tycon) PtrRep
536 %************************************************************************
538 \subsection[CgCase-prim-alts]{Primitive alternatives}
540 %************************************************************************
542 @cgPrimAlts@ generates suitable a @CSwitch@
543 for dealing with the alternatives of a primitive @case@, given an
544 addressing mode for the thing to scrutinise. It also keeps track of
545 the maximum stack depth encountered down any branch.
547 As usual, no binders in the alternatives are yet bound.
551 -> CAddrMode -- Scrutinee
552 -> [StgAlt] -- Alternatives
555 -- INVARIANT: the default binder is already bound
556 cgPrimAlts gc_flag scrutinee alts alt_type
557 = forkAlts (map (cgPrimAlt gc_flag alt_type) alts) `thenFC` \ tagged_absCs ->
559 ((DEFAULT, deflt_absC) : others) = tagged_absCs -- There is always a default
560 alt_absCs = [(lit,rhs) | (LitAlt lit, rhs) <- others]
562 absC (CSwitch scrutinee alt_absCs deflt_absC)
563 -- CSwitch does sensible things with one or zero alternatives
567 -> StgAlt -- The alternative
568 -> FCode (AltCon, AbstractC) -- Its compiled form
570 cgPrimAlt gc_flag alt_type (con, [], [], rhs)
571 = ASSERT( case con of { DEFAULT -> True; LitAlt _ -> True; other -> False } )
572 getAbsC (maybeAltHeapCheck gc_flag alt_type (cgExpr rhs)) `thenFC` \ abs_c ->
573 returnFC (con, abs_c)
577 %************************************************************************
579 \subsection[CgCase-tidy]{Code for tidying up prior to an eval}
581 %************************************************************************
586 -> AltType -- PolyAlt, PrimAlt, AlgAlt, but *not* UbxTupAlt
587 -> Code -- Continuation
589 maybeAltHeapCheck NoGC _ code = code
590 maybeAltHeapCheck GCMayHappen alt_type code
591 = -- HWL: maybe need yield here
592 -- yield [node] True -- XXX live regs wrong
593 altHeapCheck alt_type code
595 saveVolatileVarsAndRegs
596 :: StgLiveVars -- Vars which should be made safe
597 -> FCode (AbstractC, -- Assignments to do the saves
598 EndOfBlockInfo, -- sequel for the alts
599 Maybe VirtualSpOffset) -- Slot for current cost centre
601 saveVolatileVarsAndRegs vars
602 = saveVolatileVars vars `thenFC` \ var_saves ->
603 saveCurrentCostCentre `thenFC` \ (maybe_cc_slot, cc_save) ->
604 getEndOfBlockInfo `thenFC` \ eob_info ->
605 returnFC (mkAbstractCs [var_saves, cc_save],
610 saveVolatileVars :: StgLiveVars -- Vars which should be made safe
611 -> FCode AbstractC -- Assignments to to the saves
613 saveVolatileVars vars
614 = save_em (varSetElems vars)
616 save_em [] = returnFC AbsCNop
619 = getCAddrModeIfVolatile var `thenFC` \ v ->
621 Nothing -> save_em vars -- Non-volatile, so carry on
624 Just vol_amode -> -- Aha! It's volatile
625 save_var var vol_amode `thenFC` \ abs_c ->
626 save_em vars `thenFC` \ abs_cs ->
627 returnFC (abs_c `mkAbsCStmts` abs_cs)
629 save_var var vol_amode
630 = allocPrimStack (getPrimRepSize kind) `thenFC` \ slot ->
631 rebindToStack var slot `thenC`
632 getSpRelOffset slot `thenFC` \ sp_rel ->
633 returnFC (CAssign (CVal sp_rel kind) vol_amode)
635 kind = getAmodeRep vol_amode
638 ---------------------------------------------------------------------------
640 When we save the current cost centre (which is done for lexical
641 scoping), we allocate a free stack location, and return (a)~the
642 virtual offset of the location, to pass on to the alternatives, and
643 (b)~the assignment to do the save (just as for @saveVolatileVars@).
646 saveCurrentCostCentre ::
647 FCode (Maybe VirtualSpOffset, -- Where we decide to store it
648 AbstractC) -- Assignment to save it
650 saveCurrentCostCentre
651 = if not opt_SccProfilingOn then
652 returnFC (Nothing, AbsCNop)
654 allocPrimStack (getPrimRepSize CostCentreRep) `thenFC` \ slot ->
655 dataStackSlots [slot] `thenC`
656 getSpRelOffset slot `thenFC` \ sp_rel ->
658 CAssign (CVal sp_rel CostCentreRep) (CReg CurCostCentre))
660 -- Sometimes we don't free the slot containing the cost centre after restoring it
661 -- (see CgLetNoEscape.cgLetNoEscapeBody).
662 restoreCurrentCostCentre :: Maybe VirtualSpOffset -> Bool -> Code
663 restoreCurrentCostCentre Nothing _freeit = nopC
664 restoreCurrentCostCentre (Just slot) freeit
665 = getSpRelOffset slot `thenFC` \ sp_rel ->
666 (if freeit then freeStackSlots [slot] else nopC) `thenC`
667 absC (CCallProfCCMacro FSLIT("RESTORE_CCCS") [CVal sp_rel CostCentreRep])
668 -- we use the RESTORE_CCCS macro, rather than just
669 -- assigning into CurCostCentre, in case RESTORE_CCCS
670 -- has some sanity-checking in it.
673 %************************************************************************
675 \subsection[CgCase-return-vec]{Building a return vector}
677 %************************************************************************
679 Build a return vector, and return a suitable label addressing
683 mkRetDirectTarget :: Id -- Used for labelling only
684 -> AbstractC -- Return code
685 -> SRT -- Live CAFs in return code
686 -> FCode CAddrMode -- Emit the labelled return block,
687 -- and return its label
688 mkRetDirectTarget bndr abs_c srt
689 = buildContLivenessMask bndr `thenFC` \ liveness ->
690 getSRTInfo name srt `thenFC` \ srt_info ->
691 absC (CRetDirect uniq abs_c srt_info liveness) `thenC`
695 uniq = getUnique name
696 lbl = CLbl (mkReturnInfoLabel uniq) RetRep
700 mkRetVecTarget :: Id -- Just for its unique
701 -> [(AltCon, AbstractC)] -- Branch codes
702 -> SRT -- Continuation's SRT
703 -> CtrlReturnConvention
706 mkRetVecTarget bndr tagged_alt_absCs srt (UnvectoredReturn 0)
707 = ASSERT( null other_alts )
708 mkRetDirectTarget bndr deflt_absC srt
710 ((DEFAULT, deflt_absC) : other_alts) = tagged_alt_absCs
712 mkRetVecTarget bndr tagged_alt_absCs srt (UnvectoredReturn n)
713 = mkRetDirectTarget bndr switch_absC srt
715 -- Find the tag explicitly rather than using tag_reg for now.
716 -- on architectures with lots of regs the tag will be loaded
717 -- into tag_reg by the code doing the returning.
718 tag = CMacroExpr WordRep GET_TAG [CVal (nodeRel 0) DataPtrRep]
719 switch_absC = mkAlgAltsCSwitch tag tagged_alt_absCs
722 mkRetVecTarget bndr tagged_alt_absCs srt (VectoredReturn table_size)
723 = buildContLivenessMask bndr `thenFC` \ liveness ->
724 getSRTInfo name srt `thenFC` \ srt_info ->
726 ret_vector = CRetVector vtbl_lbl vector_table srt_info liveness
728 absC (mkAbstractCs alts_absCs `mkAbsCStmts` ret_vector) `thenC`
729 -- Alts come first, because we don't want to declare all the symbols
731 return (CLbl vtbl_lbl DataPtrRep)
733 tags = [fIRST_TAG .. (table_size+fIRST_TAG-1)]
734 vector_table = map mk_vector_entry tags
735 alts_absCs = map snd (sortBy cmp tagged_alt_absCs)
736 -- The sort is unnecessary; just there for now
737 -- to make the new order the same as the old
738 (DEFAULT,_) `cmp` (DEFAULT,_) = EQ
739 (DEFAULT,_) `cmp` _ = GT
740 (DataAlt d1,_) `cmp` (DataAlt d2,_) = dataConTag d1 `compare` dataConTag d2
741 (DataAlt d1,_) `cmp` (DEFAULT, _) = LT
745 uniq = getUnique name
746 vtbl_lbl = mkVecTblLabel uniq
748 deflt_lbl :: CAddrMode
749 deflt_lbl = case tagged_alt_absCs of
750 (DEFAULT, abs_c) : _ -> get_block_label abs_c
752 -- 'other' case: the simplifier might have eliminated a case
753 -- so we may have e.g. case xs of
755 -- In that situation the default should never be taken,
756 -- so we just use '0' (=> seg fault if used)
758 mk_vector_entry :: ConTag -> CAddrMode
760 = case [ absC | (DataAlt d, absC) <- tagged_alt_absCs, dataConTag d == tag ] of
761 -- The comprehension neatly, and correctly, ignores the DEFAULT
763 [abs_c] -> get_block_label abs_c
764 _ -> panic "mkReturnVector: too many"
766 get_block_label (CCodeBlock lbl _) = CLbl lbl CodePtrRep