2 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
4 % $Id: CgCase.lhs,v 1.68 2004/08/10 09:02:38 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,
26 getAmodeRep, shimFCallArg )
27 import CgBindery ( getVolatileRegs, getArgAmodes,
28 bindNewToReg, bindNewToTemp,
30 rebindToStack, getCAddrMode, getCAddrModeIfVolatile,
31 buildContLivenessMask, nukeDeadBindings,
33 import CgCon ( bindConArgs, bindUnboxedTupleComponents )
34 import CgHeapery ( altHeapCheck, unbxTupleHeapCheck )
35 import CgRetConv ( dataReturnConvPrim, ctrlReturnConvAlg,
36 CtrlReturnConvention(..)
38 import CgStackery ( allocPrimStack, allocStackTop,
39 deAllocStackTop, freeStackSlots, dataStackSlots
41 import CgTailCall ( performTailCall )
42 import CgUsages ( getSpRelOffset )
43 import CLabel ( mkVecTblLabel, mkClosureTblLabel,
44 mkDefaultLabel, mkAltLabel, mkReturnInfoLabel
46 import ClosureInfo ( mkLFArgument )
47 import CmdLineOpts ( opt_SccProfilingOn )
48 import Id ( Id, idName, isDeadBinder )
49 import DataCon ( dataConTag, fIRST_TAG, ConTag )
50 import VarSet ( varSetElems )
51 import CoreSyn ( AltCon(..) )
52 import PrimOp ( primOpOutOfLine, PrimOp(..) )
53 import PrimRep ( getPrimRepSize, retPrimRepSize, PrimRep(..)
55 import TyCon ( TyCon, isEnumerationTyCon, tyConPrimRep )
56 import Unique ( Unique, Uniquable(..), newTagUnique )
59 import List ( sortBy )
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.
121 Special case #1: case of literal.
124 cgCase (StgLit lit) live_in_whole_case live_in_alts bndr srt
125 alt_type@(PrimAlt tycon) alts
126 = bindNewToTemp bndr `thenFC` \ tmp_amode ->
127 absC (CAssign tmp_amode (CLit lit)) `thenC`
128 cgPrimAlts NoGC tmp_amode alts alt_type
131 Special case #2: scrutinising a primitive-typed variable. No
132 evaluation required. We don't save volatile variables, nor do we do a
133 heap-check in the alternatives. Instead, the heap usage of the
134 alternatives is worst-cased and passed upstream. This can result in
135 allocating more heap than strictly necessary, but it will sometimes
136 eliminate a heap check altogether.
139 cgCase (StgApp v []) live_in_whole_case live_in_alts bndr srt
140 alt_type@(PrimAlt tycon) alts
142 = -- Careful! we can't just bind the default binder to the same thing
143 -- as the scrutinee, since it might be a stack location, and having
144 -- two bindings pointing at the same stack locn doesn't work (it
145 -- confuses nukeDeadBindings). Hence, use a new temp.
146 getCAddrMode v `thenFC` \ amode ->
147 bindNewToTemp bndr `thenFC` \ tmp_amode ->
148 absC (CAssign tmp_amode amode) `thenC`
149 cgPrimAlts NoGC tmp_amode alts alt_type
152 Special case #3: inline PrimOps and foreign calls.
155 cgCase (StgOpApp op args _)
156 live_in_whole_case live_in_alts bndr srt alt_type alts
158 = -- Get amodes for the arguments and results
159 getArgAmodes args `thenFC` \ arg_amodes1 ->
162 | StgFCallOp{} <- op = zipWith shimFCallArg args arg_amodes1
163 | otherwise = arg_amodes1
165 getVolatileRegs live_in_alts `thenFC` \ vol_regs ->
168 PrimAlt tycon -- PRIMITIVE ALTS
169 -> bindNewToTemp bndr `thenFC` \ tmp_amode ->
170 absC (COpStmt [tmp_amode] op arg_amodes vol_regs) `thenC`
171 -- Note: no liveness arg
172 cgPrimAlts NoGC tmp_amode alts alt_type
174 UbxTupAlt tycon -- UNBOXED TUPLE ALTS
175 -> -- No heap check, no yield, just get in there and do it.
176 -- NB: the case binder isn't bound to anything;
177 -- it has a unboxed tuple type
178 mapFCs bindNewToTemp res_ids `thenFC` \ res_tmps ->
179 absC (COpStmt res_tmps op arg_amodes vol_regs) `thenC`
182 [(_, res_ids, _, rhs)] = alts
184 AlgAlt tycon -- ENUMERATION TYPE RETURN
185 | StgPrimOp primop <- op
186 -> ASSERT( isEnumerationTyCon tycon )
188 do_enum_primop :: PrimOp -> FCode CAddrMode -- Returns amode for result
189 do_enum_primop TagToEnumOp -- No code!
190 = returnFC (only arg_amodes)
192 do_enum_primop primop
193 = absC (COpStmt [tag_amode] op arg_amodes vol_regs) `thenC`
196 tag_amode = CTemp (newTagUnique (getUnique bndr) 'C') IntRep
197 -- Being a bit short of uniques for temporary
198 -- variables here, we use newTagUnique to
199 -- generate a new unique from the case binder.
200 -- The case binder's unique will presumably
201 -- have the 'c' tag (generated by CoreToStg),
202 -- so we just change its tag to 'C' (for
203 -- 'case') to ensure it doesn't clash with
204 -- anything else. We can't use the unique
205 -- from the case binder, becaus e this is used
206 -- to hold the actual result closure (via the
207 -- call to bindNewToTemp)
209 do_enum_primop primop `thenFC` \ tag_amode ->
211 -- Bind the default binder if necessary
212 -- (avoiding it avoids the assignment)
213 -- The deadness info is set by StgVarInfo
214 (if (isDeadBinder bndr)
216 else bindNewToTemp bndr `thenFC` \ tmp_amode ->
217 absC (CAssign tmp_amode (tagToClosure tycon tag_amode))
221 cgAlgAlts NoGC (getUnique bndr)
222 Nothing{-cc_slot-} False{-no semi-tagging-}
223 (AlgAlt tycon) alts `thenFC` \ tagged_alts ->
226 absC (mkAlgAltsCSwitch tag_amode tagged_alts)
228 other -> pprPanic "cgCase: case of primop has strange alt type" (ppr alt_type)
230 inline_primop = case op of
231 StgPrimOp primop -> not (primOpOutOfLine primop)
232 --StgFCallOp (CCall (CCallSpec _ _ PlayRisky)) _ -> True
233 -- unsafe foreign calls are "inline"
238 TODO: Case-of-case of primop can probably be done inline too (but
239 maybe better to translate it out beforehand). See
240 ghc/lib/misc/PackedString.lhs for examples where this crops up (with
243 Special case: scrutinising a non-primitive variable.
244 This can be done a little better than the general case, because
245 we can reuse/trim the stack slot holding the variable (if it is in one).
248 cgCase (StgApp fun args)
249 live_in_whole_case live_in_alts bndr srt alt_type alts
250 = getCAddrModeAndInfo fun `thenFC` \ (fun', fun_amode, lf_info) ->
251 getArgAmodes args `thenFC` \ arg_amodes ->
253 -- Nuking dead bindings *before* calculating the saves is the
254 -- value-add here. We might end up freeing up some slots currently
255 -- occupied by variables only required for the call.
256 -- NOTE: we need to look up the variables used in the call before
257 -- doing this, because some of them may not be in the environment
259 nukeDeadBindings live_in_alts `thenC`
260 saveVolatileVarsAndRegs live_in_alts
261 `thenFC` \ (save_assts, alts_eob_info, maybe_cc_slot) ->
263 forkEval alts_eob_info
264 ( allocStackTop retPrimRepSize
265 `thenFC` \_ -> nopC )
266 ( deAllocStackTop retPrimRepSize `thenFC` \_ ->
267 cgEvalAlts maybe_cc_slot bndr srt alt_type alts )
268 `thenFC` \ scrut_eob_info ->
270 setEndOfBlockInfo (maybeReserveSeqFrame alt_type scrut_eob_info) $
271 performTailCall fun' fun_amode lf_info arg_amodes save_assts
274 Note about return addresses: we *always* push a return address, even
275 if because of an optimisation we end up jumping direct to the return
276 code (not through the address itself). The alternatives always assume
277 that the return address is on the stack. The return address is
278 required in case the alternative performs a heap check, since it
279 encodes the liveness of the slots in the activation record.
281 On entry to the case alternative, we can re-use the slot containing
282 the return address immediately after the heap check. That's what the
283 deAllocStackTop call is doing above.
285 Finally, here is the general case.
288 cgCase expr live_in_whole_case live_in_alts bndr srt alt_type alts
289 = -- Figure out what volatile variables to save
290 nukeDeadBindings live_in_whole_case `thenC`
292 saveVolatileVarsAndRegs live_in_alts
293 `thenFC` \ (save_assts, alts_eob_info, maybe_cc_slot) ->
295 -- Save those variables right now!
296 absC save_assts `thenC`
298 -- generate code for the alts
299 forkEval alts_eob_info
300 (nukeDeadBindings live_in_alts `thenC`
301 allocStackTop retPrimRepSize -- space for retn address
304 (deAllocStackTop retPrimRepSize `thenFC` \_ ->
305 cgEvalAlts maybe_cc_slot bndr srt alt_type alts) `thenFC` \ scrut_eob_info ->
307 setEndOfBlockInfo (maybeReserveSeqFrame alt_type scrut_eob_info) $
311 There's a lot of machinery going on behind the scenes to manage the
312 stack pointer here. forkEval takes the virtual Sp and free list from
313 the first argument, and turns that into the *real* Sp for the second
314 argument. It also uses this virtual Sp as the args-Sp in the EOB info
315 returned, so that the scrutinee will trim the real Sp back to the
316 right place before doing whatever it does.
317 --SDM (who just spent an hour figuring this out, and didn't want to
320 Why don't we push the return address just before evaluating the
321 scrutinee? Because the slot reserved for the return address might
322 contain something useful, so we wait until performing a tail call or
323 return before pushing the return address (see
324 CgTailCall.pushReturnAddress).
326 This also means that the environment doesn't need to know about the
327 free stack slot for the return address (for generating bitmaps),
328 because we don't reserve it until just before the eval.
330 TODO!! Problem: however, we have to save the current cost centre
331 stack somewhere, because at the eval point the current CCS might be
332 different. So we pick a free stack slot and save CCCS in it. The
333 problem with this is that this slot isn't recorded as free/unboxed in
334 the environment, so a case expression in the scrutinee will have the
335 wrong bitmap attached. Fortunately we don't ever seem to see
336 case-of-case at the back end. One solution might be to shift the
337 saved CCS to the correct place in the activation record just before
341 (one consequence of the above is that activation records on the stack
342 don't follow the layout of closures when we're profiling. The CCS
343 could be anywhere within the record).
346 maybeReserveSeqFrame PolyAlt (EndOfBlockInfo args_sp (CaseAlts amode stuff _))
347 = EndOfBlockInfo (args_sp + retPrimRepSize) (CaseAlts amode stuff True)
348 maybeReserveSeqFrame other scrut_eob_info = scrut_eob_info
351 %************************************************************************
353 \subsection[CgCase-alts]{Alternatives}
355 %************************************************************************
357 @cgEvalAlts@ returns an addressing mode for a continuation for the
358 alternatives of a @case@, used in a context when there
359 is some evaluation to be done.
362 cgEvalAlts :: Maybe VirtualSpOffset -- Offset of cost-centre to be restored, if any
364 -> SRT -- SRT for the continuation
367 -> FCode Sequel -- Any addr modes inside are guaranteed
368 -- to be a label so that we can duplicate it
369 -- without risk of duplicating code
371 cgEvalAlts cc_slot bndr srt (UbxTupAlt _) [(con,args,_,rhs)]
372 = -- Unboxed tuple case
373 -- By now, the simplifier should have have turned it
374 -- into case e of (# a,b #) -> e
375 -- There shouldn't be a
376 -- case e of DEFAULT -> e
377 ASSERT2( case con of { DataAlt _ -> True; other -> False },
378 text "cgEvalAlts: dodgy case of unboxed tuple type" )
380 forkAbsC ( -- forkAbsC for the RHS, so that the envt is
381 -- not changed for the mkRetDirect call
382 bindUnboxedTupleComponents args `thenFC` \ (live_regs, ptrs, nptrs, _) ->
383 -- restore the CC *after* binding the tuple components, so that we
384 -- get the stack offset of the saved CC right.
385 restoreCurrentCostCentre cc_slot True `thenC`
386 -- Generate a heap check if necessary
387 unbxTupleHeapCheck live_regs ptrs nptrs AbsCNop (
388 -- And finally the code for the alternative
390 )) `thenFC` \ abs_c ->
391 mkRetDirectTarget bndr abs_c srt `thenFC` \ lbl ->
392 returnFC (CaseAlts lbl Nothing False)
394 cgEvalAlts cc_slot bndr srt alt_type@(PrimAlt tycon) alts
395 = forkAbsC ( -- forkAbsC for the RHS, so that the envt is
396 -- not changed for the mkRetDirect call
397 restoreCurrentCostCentre cc_slot True `thenC`
398 bindNewToReg bndr reg (mkLFArgument bndr) `thenC`
399 cgPrimAlts GCMayHappen (CReg reg) alts alt_type
400 ) `thenFC` \ abs_c ->
401 mkRetDirectTarget bndr abs_c srt `thenFC` \ lbl ->
402 returnFC (CaseAlts lbl Nothing False)
404 reg = dataReturnConvPrim kind
405 kind = tyConPrimRep tycon
407 cgEvalAlts cc_slot bndr srt alt_type alts
408 = -- Algebraic and polymorphic case
409 -- Bind the default binder
410 bindNewToReg bndr node (mkLFArgument bndr) `thenC`
412 -- Generate sequel info for use downstream
413 -- At the moment, we only do it if the type is vector-returnable.
414 -- Reason: if not, then it costs extra to label the
415 -- alternatives, because we'd get return code like:
417 -- switch TagReg { 0 : JMP(alt_1); 1 : JMP(alt_2) ..etc }
419 -- which is worse than having the alt code in the switch statement
421 let ret_conv = case alt_type of
422 AlgAlt tc -> ctrlReturnConvAlg tc
423 PolyAlt -> UnvectoredReturn 0
425 use_labelled_alts = case ret_conv of
426 VectoredReturn _ -> True
429 semi_tagged_stuff = cgSemiTaggedAlts use_labelled_alts bndr alts
432 cgAlgAlts GCMayHappen (getUnique bndr)
433 cc_slot use_labelled_alts
434 alt_type alts `thenFC` \ tagged_alt_absCs ->
436 mkRetVecTarget bndr tagged_alt_absCs
437 srt ret_conv `thenFC` \ return_vec ->
439 returnFC (CaseAlts return_vec semi_tagged_stuff False)
443 HWL comment on {\em GrAnSim\/} (adding GRAN_YIELDs for context switch): If
444 we do an inlining of the case no separate functions for returning are
445 created, so we don't have to generate a GRAN_YIELD in that case. This info
446 must be propagated to cgAlgAltRhs (where the GRAN_YIELD macro might be
447 emitted). Hence, the new Bool arg to cgAlgAltRhs.
449 %************************************************************************
451 \subsection[CgCase-alg-alts]{Algebraic alternatives}
453 %************************************************************************
455 In @cgAlgAlts@, none of the binders in the alternatives are
456 assumed to be yet bound.
458 HWL comment on {\em GrAnSim\/} (adding GRAN_YIELDs for context switch): The
459 last arg of cgAlgAlts indicates if we want a context switch at the
460 beginning of each alternative. Normally we want that. The only exception
461 are inlined alternatives.
466 -> Maybe VirtualSpOffset
467 -> Bool -- True <=> branches must be labelled
468 -- (used for semi-tagging)
469 -> AltType -- ** AlgAlt or PolyAlt only **
470 -> [StgAlt] -- The alternatives
471 -> FCode [(AltCon, AbstractC)] -- The branches
473 cgAlgAlts gc_flag uniq restore_cc must_label_branches alt_type alts
474 = forkAlts [ cgAlgAlt gc_flag uniq restore_cc must_label_branches alt_type alt
478 -> Unique -> Maybe VirtualSpOffset -> Bool -- turgid state
479 -> AltType -- ** AlgAlt or PolyAlt only **
481 -> FCode (AltCon, AbstractC)
483 cgAlgAlt gc_flag uniq cc_slot must_label_branch
484 alt_type (con, args, use_mask, rhs)
485 = getAbsC (bind_con_args con args `thenFC` \ _ ->
486 restoreCurrentCostCentre cc_slot True `thenC`
487 maybeAltHeapCheck gc_flag alt_type (cgExpr rhs)
488 ) `thenFC` \ abs_c ->
490 final_abs_c | must_label_branch = CCodeBlock lbl abs_c
493 returnFC (con, final_abs_c)
496 DataAlt dc -> mkAltLabel uniq (dataConTag dc)
497 DEFAULT -> mkDefaultLabel uniq
498 other -> pprPanic "cgAlgAlt" (ppr con)
500 bind_con_args DEFAULT args = nopC
501 bind_con_args (DataAlt dc) args = bindConArgs dc args
504 %************************************************************************
506 \subsection[CgCase-semi-tagged-alts]{The code to deal with sem-tagging}
508 %************************************************************************
510 Turgid-but-non-monadic code to conjure up the required info from
511 algebraic case alternatives for semi-tagging.
514 cgSemiTaggedAlts :: Bool -- True <=> use semitagging: each alt will be labelled
519 cgSemiTaggedAlts False binder alts
521 cgSemiTaggedAlts True binder alts
522 = Just ([st_alt con args | (DataAlt con, args, _, _) <- alts],
524 (DEFAULT, _, _, _) -> Just st_deflt
527 uniq = getUnique binder
530 (CCallProfCtrMacro FSLIT("RET_SEMI_BY_DEFAULT") [], -- ToDo: monadise?
531 mkDefaultLabel uniq))
533 st_alt con args -- Ha! Nothing to do; Node already points to the thing
535 (CCallProfCtrMacro FSLIT("RET_SEMI_IN_HEAP") -- ToDo: monadise?
536 [mkIntCLit (length args)], -- how big the thing in the heap is
540 con_tag = dataConTag con
541 join_label = mkAltLabel uniq con_tag
544 tagToClosure :: TyCon -> CAddrMode -> CAddrMode
545 -- Primops returning an enumeration type (notably Bool)
546 -- actually return an index into
547 -- the table of closures for the enumeration type
548 tagToClosure tycon tag_amode
549 = CVal (CIndex closure_tbl tag_amode PtrRep) PtrRep
551 closure_tbl = CLbl (mkClosureTblLabel tycon) PtrRep
554 %************************************************************************
556 \subsection[CgCase-prim-alts]{Primitive alternatives}
558 %************************************************************************
560 @cgPrimAlts@ generates suitable a @CSwitch@
561 for dealing with the alternatives of a primitive @case@, given an
562 addressing mode for the thing to scrutinise. It also keeps track of
563 the maximum stack depth encountered down any branch.
565 As usual, no binders in the alternatives are yet bound.
569 -> CAddrMode -- Scrutinee
570 -> [StgAlt] -- Alternatives
573 -- INVARIANT: the default binder is already bound
574 cgPrimAlts gc_flag scrutinee alts alt_type
575 = forkAlts (map (cgPrimAlt gc_flag alt_type) alts) `thenFC` \ tagged_absCs ->
577 ((DEFAULT, deflt_absC) : others) = tagged_absCs -- There is always a default
578 alt_absCs = [(lit,rhs) | (LitAlt lit, rhs) <- others]
580 absC (CSwitch scrutinee alt_absCs deflt_absC)
581 -- CSwitch does sensible things with one or zero alternatives
585 -> StgAlt -- The alternative
586 -> FCode (AltCon, AbstractC) -- Its compiled form
588 cgPrimAlt gc_flag alt_type (con, [], [], rhs)
589 = ASSERT( case con of { DEFAULT -> True; LitAlt _ -> True; other -> False } )
590 getAbsC (maybeAltHeapCheck gc_flag alt_type (cgExpr rhs)) `thenFC` \ abs_c ->
591 returnFC (con, abs_c)
595 %************************************************************************
597 \subsection[CgCase-tidy]{Code for tidying up prior to an eval}
599 %************************************************************************
604 -> AltType -- PolyAlt, PrimAlt, AlgAlt, but *not* UbxTupAlt
605 -> Code -- Continuation
607 maybeAltHeapCheck NoGC _ code = code
608 maybeAltHeapCheck GCMayHappen alt_type code
609 = -- HWL: maybe need yield here
610 -- yield [node] True -- XXX live regs wrong
611 altHeapCheck alt_type code
613 saveVolatileVarsAndRegs
614 :: StgLiveVars -- Vars which should be made safe
615 -> FCode (AbstractC, -- Assignments to do the saves
616 EndOfBlockInfo, -- sequel for the alts
617 Maybe VirtualSpOffset) -- Slot for current cost centre
619 saveVolatileVarsAndRegs vars
620 = saveVolatileVars vars `thenFC` \ var_saves ->
621 saveCurrentCostCentre `thenFC` \ (maybe_cc_slot, cc_save) ->
622 getEndOfBlockInfo `thenFC` \ eob_info ->
623 returnFC (mkAbstractCs [var_saves, cc_save],
628 saveVolatileVars :: StgLiveVars -- Vars which should be made safe
629 -> FCode AbstractC -- Assignments to to the saves
631 saveVolatileVars vars
632 = save_em (varSetElems vars)
634 save_em [] = returnFC AbsCNop
637 = getCAddrModeIfVolatile var `thenFC` \ v ->
639 Nothing -> save_em vars -- Non-volatile, so carry on
642 Just vol_amode -> -- Aha! It's volatile
643 save_var var vol_amode `thenFC` \ abs_c ->
644 save_em vars `thenFC` \ abs_cs ->
645 returnFC (abs_c `mkAbsCStmts` abs_cs)
647 save_var var vol_amode
648 = allocPrimStack (getPrimRepSize kind) `thenFC` \ slot ->
649 rebindToStack var slot `thenC`
650 getSpRelOffset slot `thenFC` \ sp_rel ->
651 returnFC (CAssign (CVal sp_rel kind) vol_amode)
653 kind = getAmodeRep vol_amode
656 ---------------------------------------------------------------------------
658 When we save the current cost centre (which is done for lexical
659 scoping), we allocate a free stack location, and return (a)~the
660 virtual offset of the location, to pass on to the alternatives, and
661 (b)~the assignment to do the save (just as for @saveVolatileVars@).
664 saveCurrentCostCentre ::
665 FCode (Maybe VirtualSpOffset, -- Where we decide to store it
666 AbstractC) -- Assignment to save it
668 saveCurrentCostCentre
669 = if not opt_SccProfilingOn then
670 returnFC (Nothing, AbsCNop)
672 allocPrimStack (getPrimRepSize CostCentreRep) `thenFC` \ slot ->
673 dataStackSlots [slot] `thenC`
674 getSpRelOffset slot `thenFC` \ sp_rel ->
676 CAssign (CVal sp_rel CostCentreRep) (CReg CurCostCentre))
678 -- Sometimes we don't free the slot containing the cost centre after restoring it
679 -- (see CgLetNoEscape.cgLetNoEscapeBody).
680 restoreCurrentCostCentre :: Maybe VirtualSpOffset -> Bool -> Code
681 restoreCurrentCostCentre Nothing _freeit = nopC
682 restoreCurrentCostCentre (Just slot) freeit
683 = getSpRelOffset slot `thenFC` \ sp_rel ->
684 (if freeit then freeStackSlots [slot] else nopC) `thenC`
685 absC (CCallProfCCMacro FSLIT("RESTORE_CCCS") [CVal sp_rel CostCentreRep])
686 -- we use the RESTORE_CCCS macro, rather than just
687 -- assigning into CurCostCentre, in case RESTORE_CCCS
688 -- has some sanity-checking in it.
691 %************************************************************************
693 \subsection[CgCase-return-vec]{Building a return vector}
695 %************************************************************************
697 Build a return vector, and return a suitable label addressing
701 mkRetDirectTarget :: Id -- Used for labelling only
702 -> AbstractC -- Return code
703 -> SRT -- Live CAFs in return code
704 -> FCode CAddrMode -- Emit the labelled return block,
705 -- and return its label
706 mkRetDirectTarget bndr abs_c srt
707 = buildContLivenessMask bndr `thenFC` \ liveness ->
708 getSRTInfo name srt `thenFC` \ srt_info ->
709 absC (CRetDirect uniq abs_c srt_info liveness) `thenC`
713 uniq = getUnique name
714 lbl = CLbl (mkReturnInfoLabel uniq) RetRep
718 mkRetVecTarget :: Id -- Just for its unique
719 -> [(AltCon, AbstractC)] -- Branch codes
720 -> SRT -- Continuation's SRT
721 -> CtrlReturnConvention
724 mkRetVecTarget bndr tagged_alt_absCs srt (UnvectoredReturn 0)
725 = ASSERT( null other_alts )
726 mkRetDirectTarget bndr deflt_absC srt
728 ((DEFAULT, deflt_absC) : other_alts) = tagged_alt_absCs
730 mkRetVecTarget bndr tagged_alt_absCs srt (UnvectoredReturn n)
731 = mkRetDirectTarget bndr switch_absC srt
733 -- Find the tag explicitly rather than using tag_reg for now.
734 -- on architectures with lots of regs the tag will be loaded
735 -- into tag_reg by the code doing the returning.
736 tag = CMacroExpr WordRep GET_TAG [CVal (nodeRel 0) DataPtrRep]
737 switch_absC = mkAlgAltsCSwitch tag tagged_alt_absCs
740 mkRetVecTarget bndr tagged_alt_absCs srt (VectoredReturn table_size)
741 = buildContLivenessMask bndr `thenFC` \ liveness ->
742 getSRTInfo name srt `thenFC` \ srt_info ->
744 ret_vector = CRetVector vtbl_lbl vector_table srt_info liveness
746 absC (mkAbstractCs alts_absCs `mkAbsCStmts` ret_vector) `thenC`
747 -- Alts come first, because we don't want to declare all the symbols
749 return (CLbl vtbl_lbl DataPtrRep)
751 tags = [fIRST_TAG .. (table_size+fIRST_TAG-1)]
752 vector_table = map mk_vector_entry tags
753 alts_absCs = map snd (sortBy cmp tagged_alt_absCs)
754 -- The sort is unnecessary; just there for now
755 -- to make the new order the same as the old
756 (DEFAULT,_) `cmp` (DEFAULT,_) = EQ
757 (DEFAULT,_) `cmp` _ = GT
758 (DataAlt d1,_) `cmp` (DataAlt d2,_) = dataConTag d1 `compare` dataConTag d2
759 (DataAlt d1,_) `cmp` (DEFAULT, _) = LT
763 uniq = getUnique name
764 vtbl_lbl = mkVecTblLabel uniq
766 deflt_lbl :: CAddrMode
767 deflt_lbl = case tagged_alt_absCs of
768 (DEFAULT, abs_c) : _ -> get_block_label abs_c
770 -- 'other' case: the simplifier might have eliminated a case
771 -- so we may have e.g. case xs of
773 -- In that situation the default should never be taken,
774 -- so we just use '0' (=> seg fault if used)
776 mk_vector_entry :: ConTag -> CAddrMode
778 = case [ absC | (DataAlt d, absC) <- tagged_alt_absCs, dataConTag d == tag ] of
779 -- The comprehension neatly, and correctly, ignores the DEFAULT
781 [abs_c] -> get_block_label abs_c
782 _ -> panic "mkReturnVector: too many"
784 get_block_label (CCodeBlock lbl _) = CLbl lbl CodePtrRep