2 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1996
4 %********************************************************
6 \section[CgCase]{Converting @StgCase@ expressions}
8 %********************************************************
11 #include "HsVersions.h"
13 module CgCase ( cgCase, saveVolatileVarsAndRegs ) where
16 #if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ <= 201
17 IMPORT_DELOOPER(CgLoop2) ( cgExpr, getPrimOpArgAmodes )
19 import {-# SOURCE #-} CgExpr
26 import AbsCUtils ( mkAbstractCs, mkAbsCStmts, mkAlgAltsCSwitch,
27 magicIdPrimRep, getAmodeRep
29 import CgBindery ( getVolatileRegs, getArgAmode, getArgAmodes,
30 bindNewToReg, bindNewToTemp,
32 rebindToAStack, rebindToBStack,
33 getCAddrModeAndInfo, getCAddrModeIfVolatile,
36 import CgCon ( buildDynCon, bindConArgs )
37 import CgHeapery ( heapCheck, yield )
38 import CgRetConv ( dataReturnConvAlg, dataReturnConvPrim,
40 DataReturnConvention(..), CtrlReturnConvention(..),
41 assignPrimOpResultRegs,
44 import CgStackery ( allocAStack, allocBStack, allocAStackTop, allocBStackTop )
45 import CgTailCall ( tailCallBusiness, performReturn )
46 import CgUsages ( getSpARelOffset, getSpBRelOffset, freeBStkSlot )
47 import CLabel ( mkVecTblLabel, mkReturnPtLabel, mkDefaultLabel,
50 import ClosureInfo ( mkConLFInfo, mkLFArgument, layOutDynCon )
51 import CmdLineOpts ( opt_SccProfilingOn, opt_GranMacros )
52 import CostCentre ( useCurrentCostCentre, CostCentre )
53 import HeapOffs ( SYN_IE(VirtualSpBOffset), SYN_IE(VirtualHeapOffset) )
54 import Id ( idPrimRep, toplevelishId,
55 dataConTag, fIRST_TAG, SYN_IE(ConTag),
56 isDataCon, SYN_IE(DataCon),
57 idSetToList, GenId{-instance Uniquable,Eq-}, SYN_IE(Id)
59 import Literal ( Literal )
60 import Maybes ( catMaybes )
61 import Outputable ( Outputable(..), PprStyle(..) )
62 import PprType ( GenType{-instance Outputable-} )
64 import PrimOp ( primOpCanTriggerGC, PrimOp(..),
65 primOpStackRequired, StackRequirement(..)
67 import PrimRep ( getPrimRepSize, isFollowableRep, retPrimRepSize,
70 import TyCon ( isEnumerationTyCon )
71 import Type ( typePrimRep,
72 getAppSpecDataTyConExpandingDicts,
73 maybeAppSpecDataTyConExpandingDicts,
76 import Unique ( Unique, Uniquable(..) )
77 import Util ( sortLt, isIn, isn'tIn, zipEqual,
78 pprError, panic, assertPanic
85 = GCMayHappen -- The scrutinee may involve GC, so everything must be
86 -- tidy before the code for the scrutinee.
88 | NoGC -- The scrutinee is a primitive value, or a call to a
89 -- primitive op which does no GC. Hence the case can
90 -- be done inline, without tidying up first.
93 It is quite interesting to decide whether to put a heap-check
94 at the start of each alternative. Of course we certainly have
95 to do so if the case forces an evaluation, or if there is a primitive
96 op which can trigger GC.
98 A more interesting situation is this:
105 default -> !C!; ...C...
108 where \tr{!x!} indicates a possible heap-check point. The heap checks
109 in the alternatives {\em can} be omitted, in which case the topmost
110 heapcheck will take their worst case into account.
112 In favour of omitting \tr{!B!}, \tr{!C!}:
116 {\em May} save a heap overflow test,
117 if ...A... allocates anything. The other advantage
118 of this is that we can use relative addressing
119 from a single Hp to get at all the closures so allocated.
121 No need to save volatile vars etc across the case
128 May do more allocation than reqd. This sometimes bites us
129 badly. For example, nfib (ha!) allocates about 30\% more space if the
130 worst-casing is done, because many many calls to nfib are leaf calls
131 which don't need to allocate anything.
133 This never hurts us if there is only one alternative.
137 *** NOT YET DONE *** The difficulty is that \tr{!B!}, \tr{!C!} need
138 to take account of what is live, and that includes all live volatile
139 variables, even if they also have stable analogues. Furthermore, the
140 stack pointers must be lined up properly so that GC sees tidy stacks.
141 If these things are done, then the heap checks can be done at \tr{!B!} and
142 \tr{!C!} without a full save-volatile-vars sequence.
153 Several special cases for primitive operations.
155 ******* TO DO TO DO: fix what follows
159 case (op x1 ... xn) of
162 where the type of the case scrutinee is a multi-constuctor algebraic type.
163 Then we simply compile code for
171 case (op x1 ... xn) of
175 where the type of the case scrutinee is a multi-constuctor algebraic type.
176 we just bomb out at the moment. It never happens in practice.
178 **** END OF TO DO TO DO
181 cgCase scrut@(StgPrim op args _) live_in_whole_case live_in_alts uniq
182 (StgAlgAlts _ alts (StgBindDefault id _ deflt_rhs))
183 = if not (null alts) then
184 panic "cgCase: case on PrimOp with default *and* alts\n"
185 -- For now, die if alts are non-empty
187 cgExpr (StgLet (StgNonRec id scrut_rhs) deflt_rhs)
189 scrut_rhs = StgRhsClosure useCurrentCostCentre stgArgOcc{-safe-} scrut_free_vars
191 scrut_free_vars = [ fv | StgVarArg fv <- args, not (toplevelishId fv) ]
197 cgCase (StgPrim op args _) live_in_whole_case live_in_alts uniq alts
198 | not (primOpCanTriggerGC op)
200 -- Get amodes for the arguments and results
201 getPrimOpArgAmodes op args `thenFC` \ arg_amodes ->
203 result_amodes = getPrimAppResultAmodes uniq alts
204 liveness_mask = panic "cgCase: liveness of non-GC-ing primop touched\n"
206 -- Perform the operation
207 getVolatileRegs live_in_alts `thenFC` \ vol_regs ->
209 -- seq cannot happen here => no additional B Stack alloc
211 absC (COpStmt result_amodes op
212 arg_amodes -- note: no liveness arg
213 liveness_mask vol_regs) `thenC`
215 -- Scrutinise the result
216 cgInlineAlts NoGC uniq alts
218 | otherwise -- *Can* trigger GC
219 = getPrimOpArgAmodes op args `thenFC` \ arg_amodes ->
221 -- Get amodes for the arguments and results, and assign to regs
222 -- (Can-trigger-gc primops guarantee to have their (nonRobust)
225 op_result_regs = assignPrimOpResultRegs op
227 op_result_amodes = map CReg op_result_regs
229 (op_arg_amodes, liveness_mask, arg_assts)
230 = makePrimOpArgsRobust op arg_amodes
232 liveness_arg = mkIntCLit liveness_mask
234 -- Tidy up in case GC happens...
236 -- Nota Bene the use of live_in_whole_case in nukeDeadBindings.
237 -- Reason: the arg_assts computed above may refer to some stack slots
238 -- which are not live in the alts. So we mustn't use those slots
239 -- to save volatile vars in!
240 nukeDeadBindings live_in_whole_case `thenC`
241 saveVolatileVars live_in_alts `thenFC` \ volatile_var_save_assts ->
243 -- Allocate stack words for the prim-op itself,
244 -- these are guaranteed to be ON TOP OF the stack.
245 -- Currently this is used *only* by the seq# primitive op.
247 (a_req,b_req) = case (primOpStackRequired op) of
248 NoStackRequired -> (0, 0)
249 FixedStackRequired a b -> (a, b)
250 VariableStackRequired -> (0, 0) -- i.e. don't care
252 allocAStackTop a_req `thenFC` \ a_slot ->
253 allocBStackTop b_req `thenFC` \ b_slot ->
255 getEndOfBlockInfo `thenFC` \ eob_info@(EndOfBlockInfo args_spa args_spb sequel) ->
256 -- a_req and b_req allocate stack space that is taken care of by the
257 -- macros generated for the primops; thus, we there is no need to adjust
258 -- this part of the stacks later on (=> +a_req in EndOfBlockInfo)
259 -- currently all this is only used for SeqOp
260 forkEval (if True {- a_req==0 && b_req==0 -}
262 else (EndOfBlockInfo (args_spa+a_req)
263 (args_spb+b_req) sequel)) nopC
265 getAbsC (cgInlineAlts GCMayHappen uniq alts) `thenFC` \ abs_c ->
266 absC (CRetUnVector vtbl_label (CLabelledCode return_label abs_c))
268 returnFC (CaseAlts (CUnVecLbl return_label vtbl_label)
269 Nothing{-no semi-tagging-}))
270 `thenFC` \ new_eob_info ->
272 -- Record the continuation info
273 setEndOfBlockInfo new_eob_info (
275 -- Now "return" to the inline alternatives; this will get
276 -- compiled to a fall-through.
278 simultaneous_assts = arg_assts `mkAbsCStmts` volatile_var_save_assts
280 -- do_op_and_continue will be passed an amode for the continuation
281 do_op_and_continue sequel
282 = absC (COpStmt op_result_amodes
284 (pin_liveness op liveness_arg op_arg_amodes)
289 sequelToAmode sequel `thenFC` \ dest_amode ->
290 absC (CReturn dest_amode DirectReturn)
292 -- Note: we CJump even for algebraic data types,
293 -- because cgInlineAlts always generates code, never a
296 performReturn simultaneous_assts do_op_and_continue live_in_alts
299 -- for all PrimOps except ccalls, we pin the liveness info
300 -- on as the first "argument"
301 -- ToDo: un-duplicate?
303 pin_liveness (CCallOp _ _ _ _ _) _ args = args
304 pin_liveness other_op liveness_arg args
307 vtbl_label = mkVecTblLabel uniq
308 return_label = mkReturnPtLabel uniq
312 Another special case: scrutinising a primitive-typed variable. No
313 evaluation required. We don't save volatile variables, nor do we do a
314 heap-check in the alternatives. Instead, the heap usage of the
315 alternatives is worst-cased and passed upstream. This can result in
316 allocating more heap than strictly necessary, but it will sometimes
317 eliminate a heap check altogether.
320 cgCase (StgApp v [] _) live_in_whole_case live_in_alts uniq (StgPrimAlts ty alts deflt)
321 = getArgAmode v `thenFC` \ amode ->
322 cgPrimAltsGivenScrutinee NoGC amode alts deflt
325 Special case: scrutinising a non-primitive variable.
326 This can be done a little better than the general case, because
327 we can reuse/trim the stack slot holding the variable (if it is in one).
330 cgCase (StgApp (StgVarArg fun) args _ {-lvs must be same as live_in_alts-})
331 live_in_whole_case live_in_alts uniq alts@(StgAlgAlts _ _ _)
333 getCAddrModeAndInfo fun `thenFC` \ (fun_amode, lf_info) ->
334 getArgAmodes args `thenFC` \ arg_amodes ->
336 -- Squish the environment
337 nukeDeadBindings live_in_alts `thenC`
338 saveVolatileVarsAndRegs live_in_alts
339 `thenFC` \ (save_assts, alts_eob_info, maybe_cc_slot) ->
341 forkEval alts_eob_info
342 nopC (cgEvalAlts maybe_cc_slot uniq alts) `thenFC` \ scrut_eob_info ->
343 setEndOfBlockInfo scrut_eob_info (
344 tailCallBusiness fun fun_amode lf_info arg_amodes live_in_alts save_assts
349 Finally, here is the general case.
352 cgCase expr live_in_whole_case live_in_alts uniq alts
353 = -- Figure out what volatile variables to save
354 nukeDeadBindings live_in_whole_case `thenC`
355 saveVolatileVarsAndRegs live_in_alts
356 `thenFC` \ (save_assts, alts_eob_info, maybe_cc_slot) ->
358 -- Save those variables right now!
359 absC save_assts `thenC`
361 forkEval alts_eob_info
362 (nukeDeadBindings live_in_alts)
363 (cgEvalAlts maybe_cc_slot uniq alts) `thenFC` \ scrut_eob_info ->
365 setEndOfBlockInfo scrut_eob_info (cgExpr expr)
368 %************************************************************************
370 \subsection[CgCase-primops]{Primitive applications}
372 %************************************************************************
374 Get result amodes for a primitive operation, in the case wher GC can't happen.
375 The amodes are returned in canonical order, ready for the prim-op!
377 Alg case: temporaries named as in the alternatives,
378 plus (CTemp u) for the tag (if needed)
381 This is all disgusting, because these amodes must be consistent with those
382 invented by CgAlgAlts.
385 getPrimAppResultAmodes
392 -- If there's an StgBindDefault which does use the bound
393 -- variable, then we can only handle it if the type involved is
394 -- an enumeration type. That's important in the case
400 -- The only reason for the restriction to *enumeration* types is our
401 -- inability to invent suitable temporaries to hold the results;
402 -- Elaborating the CTemp addr mode to have a second uniq field
403 -- (which would simply count from 1) would solve the problem.
404 -- Anyway, cgInlineAlts is now capable of handling all cases;
405 -- it's only this function which is being wimpish.
407 getPrimAppResultAmodes uniq (StgAlgAlts ty alts (StgBindDefault _ True {- used -} _))
408 | isEnumerationTyCon spec_tycon = [tag_amode]
409 | otherwise = panic "getPrimAppResultAmodes: non-enumeration algebraic alternatives with default"
411 -- A temporary variable to hold the tag; this is unaffected by GC because
412 -- the heap-checks in the branches occur after the switch
413 tag_amode = CTemp uniq IntRep
414 (spec_tycon, _, _) = getAppSpecDataTyConExpandingDicts ty
416 getPrimAppResultAmodes uniq (StgAlgAlts ty alts other_default)
417 -- Default is either StgNoDefault or StgBindDefault with unused binder
419 [_] -> arg_amodes -- No need for a tag
420 other -> tag_amode : arg_amodes
422 -- A temporary variable to hold the tag; this is unaffected by GC because
423 -- the heap-checks in the branches occur after the switch
424 tag_amode = CTemp uniq IntRep
426 -- Sort alternatives into canonical order; there must be a complete
427 -- set because there's no default case.
428 sorted_alts = sortLt lt alts
429 (con1,_,_,_) `lt` (con2,_,_,_) = dataConTag con1 < dataConTag con2
431 arg_amodes :: [CAddrMode]
433 -- Turn them into amodes
434 arg_amodes = concat (map mk_amodes sorted_alts)
435 mk_amodes (con, args, use_mask, rhs)
436 = [ CTemp (uniqueOf arg) (idPrimRep arg) | arg <- args ]
439 The situation is simpler for primitive
440 results, because there is only one!
443 getPrimAppResultAmodes uniq (StgPrimAlts ty _ _)
444 = [CTemp uniq (typePrimRep ty)]
448 %************************************************************************
450 \subsection[CgCase-alts]{Alternatives}
452 %************************************************************************
454 @cgEvalAlts@ returns an addressing mode for a continuation for the
455 alternatives of a @case@, used in a context when there
456 is some evaluation to be done.
459 cgEvalAlts :: Maybe VirtualSpBOffset -- Offset of cost-centre to be restored, if any
462 -> FCode Sequel -- Any addr modes inside are guaranteed to be a label
463 -- so that we can duplicate it without risk of
466 cgEvalAlts cc_slot uniq (StgAlgAlts ty alts deflt)
467 = -- Generate the instruction to restore cost centre, if any
468 restoreCurrentCostCentre cc_slot `thenFC` \ cc_restore ->
470 -- Generate sequel info for use downstream
471 -- At the moment, we only do it if the type is vector-returnable.
472 -- Reason: if not, then it costs extra to label the
473 -- alternatives, because we'd get return code like:
475 -- switch TagReg { 0 : JMP(alt_1); 1 : JMP(alt_2) ..etc }
477 -- which is worse than having the alt code in the switch statement
480 (spec_tycon, _, _) = getAppSpecDataTyConExpandingDicts ty
483 = case ctrlReturnConvAlg spec_tycon of
484 VectoredReturn _ -> True
488 = if not use_labelled_alts then
489 Nothing -- no semi-tagging info
491 cgSemiTaggedAlts uniq alts deflt -- Just <something>
493 cgAlgAlts GCMayHappen uniq cc_restore use_labelled_alts ty alts deflt True
494 `thenFC` \ (tagged_alt_absCs, deflt_absC) ->
496 mkReturnVector uniq ty tagged_alt_absCs deflt_absC `thenFC` \ return_vec ->
498 returnFC (CaseAlts return_vec semi_tagged_stuff)
500 cgEvalAlts cc_slot uniq (StgPrimAlts ty alts deflt)
501 = -- Generate the instruction to restore cost centre, if any
502 restoreCurrentCostCentre cc_slot `thenFC` \ cc_restore ->
504 -- Generate the switch
505 getAbsC (cgPrimAlts GCMayHappen uniq ty alts deflt) `thenFC` \ abs_c ->
507 -- Generate the labelled block, starting with restore-cost-centre
508 absC (CRetUnVector vtbl_label
509 (CLabelledCode return_label (cc_restore `mkAbsCStmts` abs_c)))
511 -- Return an amode for the block
512 returnFC (CaseAlts (CUnVecLbl return_label vtbl_label) Nothing{-no semi-tagging-})
514 vtbl_label = mkVecTblLabel uniq
515 return_label = mkReturnPtLabel uniq
520 cgInlineAlts :: GCFlag -> Unique
525 HWL comment on {\em GrAnSim\/} (adding GRAN_YIELDs for context switch): If
526 we do an inlining of the case no separate functions for returning are
527 created, so we don't have to generate a GRAN_YIELD in that case. This info
528 must be propagated to cgAlgAltRhs (where the GRAN_YIELD macro might be
529 emitted). Hence, the new Bool arg to cgAlgAltRhs.
531 First case: algebraic case, exactly one alternative, no default.
532 In this case the primitive op will not have set a temporary to the
533 tag, so we shouldn't generate a switch statment. Instead we just
537 cgInlineAlts gc_flag uniq (StgAlgAlts ty [alt@(con,args,use_mask,rhs)] StgNoDefault)
538 = cgAlgAltRhs gc_flag con args use_mask rhs False{-no yield macro if alt gets inlined-}
541 Second case: algebraic case, several alternatives.
542 Tag is held in a temporary.
545 cgInlineAlts gc_flag uniq (StgAlgAlts ty alts deflt)
546 = cgAlgAlts gc_flag uniq AbsCNop{-restore_cc-} False{-no semi-tagging-}
548 False{-don't emit yield-} `thenFC` \ (tagged_alts, deflt_c) ->
551 absC (mkAlgAltsCSwitch tag_amode tagged_alts deflt_c)
553 -- A temporary variable to hold the tag; this is unaffected by GC because
554 -- the heap-checks in the branches occur after the switch
555 tag_amode = CTemp uniq IntRep
558 Third (real) case: primitive result type.
561 cgInlineAlts gc_flag uniq (StgPrimAlts ty alts deflt)
562 = cgPrimAlts gc_flag uniq ty alts deflt
566 %************************************************************************
568 \subsection[CgCase-alg-alts]{Algebraic alternatives}
570 %************************************************************************
572 In @cgAlgAlts@, none of the binders in the alternatives are
573 assumed to be yet bound.
575 HWL comment on {\em GrAnSim\/} (adding GRAN_YIELDs for context switch): The
576 last arg of cgAlgAlts indicates if we want a context switch at the
577 beginning of each alternative. Normally we want that. The only exception
578 are inlined alternatives.
583 -> AbstractC -- Restore-cost-centre instruction
584 -> Bool -- True <=> branches must be labelled
585 -> Type -- From the case statement
586 -> [(Id, [Id], [Bool], StgExpr)] -- The alternatives
587 -> StgCaseDefault -- The default
588 -> Bool -- Context switch at alts?
589 -> FCode ([(ConTag, AbstractC)], -- The branches
590 AbstractC -- The default case
594 The case with a default which has a binder is different. We need to
595 pick all the constructors which aren't handled explicitly by an
596 alternative, and which return their results in registers, allocate
597 them explicitly in the heap, and jump to a join point for the default
600 OLD: All of this only works if a heap-check is required anyway, because
601 otherwise it isn't safe to allocate.
603 NEW (July 94): now false! It should work regardless of gc_flag,
604 because of the extra_branches argument now added to forkAlts.
606 We put a heap-check at the join point, for the benefit of constructors
607 which don't need to do allocation. This means that ones which do need
608 to allocate may end up doing two heap-checks; but that's just too bad.
609 (We'd need two join labels otherwise. ToDo.)
611 It's all pretty turgid anyway.
614 cgAlgAlts gc_flag uniq restore_cc semi_tagging
615 ty alts deflt@(StgBindDefault binder True{-used-} _)
616 emit_yield{-should a yield macro be emitted?-}
618 extra_branches :: [FCode (ConTag, AbstractC)]
619 extra_branches = catMaybes (map mk_extra_branch default_cons)
621 must_label_default = semi_tagging || not (null extra_branches)
623 forkAlts (map (cgAlgAlt gc_flag uniq restore_cc semi_tagging emit_yield) alts)
625 (cgAlgDefault gc_flag uniq restore_cc must_label_default deflt emit_yield)
628 default_join_lbl = mkDefaultLabel uniq
629 jump_instruction = CJump (CLbl default_join_lbl CodePtrRep)
631 (spec_tycon, _, spec_cons) = getAppSpecDataTyConExpandingDicts ty
633 alt_cons = [ con | (con,_,_,_) <- alts ]
635 default_cons = [ spec_con | spec_con <- spec_cons, -- In this type
636 spec_con `not_elem` alt_cons ] -- Not handled explicitly
638 not_elem = isn'tIn "cgAlgAlts"
640 -- (mk_extra_branch con) returns the a maybe for the extra branch for con.
641 -- The "maybe" is because con may return in heap, in which case there is
642 -- nothing to do. Otherwise, we have a special case for a nullary constructor,
643 -- but in the general case we do an allocation and heap-check.
645 mk_extra_branch :: DataCon -> (Maybe (FCode (ConTag, AbstractC)))
648 = ASSERT(isDataCon con)
649 case dataReturnConvAlg con of
650 ReturnInHeap -> Nothing
651 ReturnInRegs rs -> Just (getAbsC (alloc_code rs) `thenFC` \ abs_c ->
652 returnFC (tag, abs_c)
655 lf_info = mkConLFInfo con
658 -- alloc_code generates code to allocate constructor con, whose args are
659 -- in the arguments to alloc_code, assigning the result to Node.
660 alloc_code :: [MagicId] -> Code
663 = possibleHeapCheck gc_flag regs False (
664 buildDynCon binder useCurrentCostCentre con
665 (map CReg regs) (all zero_size regs)
667 idInfoToAmode PtrRep idinfo `thenFC` \ amode ->
669 absC (CAssign (CReg node) amode) `thenC`
670 absC jump_instruction
673 zero_size reg = getPrimRepSize (magicIdPrimRep reg) == 0
676 Now comes the general case
679 cgAlgAlts gc_flag uniq restore_cc must_label_branches ty alts deflt
680 {- The deflt is either StgNoDefault or a BindDefault which doesn't use the binder -}
681 emit_yield{-should a yield macro be emitted?-}
683 = forkAlts (map (cgAlgAlt gc_flag uniq restore_cc must_label_branches emit_yield) alts)
684 [{- No "extra branches" -}]
685 (cgAlgDefault gc_flag uniq restore_cc must_label_branches deflt emit_yield)
689 cgAlgDefault :: GCFlag
690 -> Unique -> AbstractC -> Bool -- turgid state...
691 -> StgCaseDefault -- input
693 -> FCode AbstractC -- output
695 cgAlgDefault gc_flag uniq restore_cc must_label_branch
699 cgAlgDefault gc_flag uniq restore_cc must_label_branch
700 (StgBindDefault _ False{-binder not used-} rhs)
701 emit_yield{-should a yield macro be emitted?-}
703 = getAbsC (absC restore_cc `thenC`
705 emit_gran_macros = opt_GranMacros
707 (if emit_gran_macros && emit_yield
709 else absC AbsCNop) `thenC`
710 -- liveness same as in possibleHeapCheck below
711 possibleHeapCheck gc_flag [] False (cgExpr rhs)) `thenFC` \ abs_c ->
713 final_abs_c | must_label_branch = CJump (CLabelledCode lbl abs_c)
718 lbl = mkDefaultLabel uniq
721 cgAlgDefault gc_flag uniq restore_cc must_label_branch
722 (StgBindDefault binder True{-binder used-} rhs)
723 emit_yield{-should a yield macro be emitted?-}
725 = -- We have arranged that Node points to the thing, even
726 -- even if we return in registers
727 bindNewToReg binder node mkLFArgument `thenC`
728 getAbsC (absC restore_cc `thenC`
730 emit_gran_macros = opt_GranMacros
732 (if emit_gran_macros && emit_yield
733 then yield [node] False
734 else absC AbsCNop) `thenC`
735 -- liveness same as in possibleHeapCheck below
736 possibleHeapCheck gc_flag [node] False (cgExpr rhs)
737 -- Node is live, but doesn't need to point at the thing itself;
738 -- it's ok for Node to point to an indirection or FETCH_ME
739 -- Hence no need to re-enter Node.
740 ) `thenFC` \ abs_c ->
743 final_abs_c | must_label_branch = CJump (CLabelledCode lbl abs_c)
748 lbl = mkDefaultLabel uniq
750 -- HWL comment on GrAnSim: GRAN_YIELDs needed; emitted in cgAlgAltRhs
753 -> Unique -> AbstractC -> Bool -- turgid state
754 -> Bool -- Context switch at alts?
755 -> (Id, [Id], [Bool], StgExpr)
756 -> FCode (ConTag, AbstractC)
758 cgAlgAlt gc_flag uniq restore_cc must_label_branch
759 emit_yield{-should a yield macro be emitted?-}
760 (con, args, use_mask, rhs)
761 = getAbsC (absC restore_cc `thenC`
762 cgAlgAltRhs gc_flag con args use_mask rhs
764 ) `thenFC` \ abs_c ->
766 final_abs_c | must_label_branch = CJump (CLabelledCode lbl abs_c)
769 returnFC (tag, final_abs_c)
772 lbl = mkAltLabel uniq tag
774 cgAlgAltRhs :: GCFlag
779 -> Bool -- context switch?
781 cgAlgAltRhs gc_flag con args use_mask rhs emit_yield
783 (live_regs, node_reqd)
784 = case (dataReturnConvAlg con) of
785 ReturnInHeap -> ([], True)
786 ReturnInRegs regs -> ([reg | (reg,True) <- zipEqual "cgAlgAltRhs" regs use_mask], False)
787 -- Pick the live registers using the use_mask
788 -- Doing so is IMPORTANT, because with semi-tagging
789 -- enabled only the live registers will have valid
793 emit_gran_macros = opt_GranMacros
795 (if emit_gran_macros && emit_yield
796 then yield live_regs node_reqd
797 else absC AbsCNop) `thenC`
798 -- liveness same as in possibleHeapCheck below
799 possibleHeapCheck gc_flag live_regs node_reqd (
801 NoGC -> mapFCs bindNewToTemp args `thenFC` \ _ ->
803 GCMayHappen -> bindConArgs con args
809 %************************************************************************
811 \subsection[CgCase-semi-tagged-alts]{The code to deal with sem-tagging}
813 %************************************************************************
815 Turgid-but-non-monadic code to conjure up the required info from
816 algebraic case alternatives for semi-tagging.
819 cgSemiTaggedAlts :: Unique
820 -> [(Id, [Id], [Bool], StgExpr)]
821 -> GenStgCaseDefault Id Id
824 cgSemiTaggedAlts uniq alts deflt
825 = Just (map st_alt alts, st_deflt deflt)
827 st_deflt StgNoDefault = Nothing
829 st_deflt (StgBindDefault binder binder_used _)
830 = Just (if binder_used then Just binder else Nothing,
831 (CCallProfCtrMacro SLIT("RET_SEMI_BY_DEFAULT") [], -- ToDo: monadise?
835 st_alt (con, args, use_mask, _)
836 = case (dataReturnConvAlg con) of
839 -- Ha! Nothing to do; Node already points to the thing
841 (CCallProfCtrMacro SLIT("RET_SEMI_IN_HEAP") -- ToDo: monadise?
842 [mkIntCLit (length args)], -- how big the thing in the heap is
847 -- We have to load the live registers from the constructor
848 -- pointed to by Node.
850 (_, regs_w_offsets) = layOutDynCon con magicIdPrimRep regs
852 used_regs = selectByMask use_mask regs
854 used_regs_w_offsets = [ ro | ro@(reg,offset) <- regs_w_offsets,
855 reg `is_elem` used_regs]
857 is_elem = isIn "cgSemiTaggedAlts"
861 CCallProfCtrMacro SLIT("RET_SEMI_IN_REGS") -- ToDo: macroise?
862 [mkIntCLit (length regs_w_offsets),
863 mkIntCLit (length used_regs_w_offsets)],
864 CSimultaneous (mkAbstractCs (map move_to_reg used_regs_w_offsets))],
867 con_tag = dataConTag con
868 join_label = mkAltLabel uniq con_tag
870 move_to_reg :: (MagicId, VirtualHeapOffset {-from Node-}) -> AbstractC
871 move_to_reg (reg, offset)
872 = CAssign (CReg reg) (CVal (NodeRel offset) (magicIdPrimRep reg))
875 %************************************************************************
877 \subsection[CgCase-prim-alts]{Primitive alternatives}
879 %************************************************************************
881 @cgPrimAlts@ generates a suitable @CSwitch@ for dealing with the
882 alternatives of a primitive @case@, given an addressing mode for the
883 thing to scrutinise. It also keeps track of the maximum stack depth
884 encountered down any branch.
886 As usual, no binders in the alternatives are yet bound.
892 -> [(Literal, StgExpr)] -- Alternatives
893 -> StgCaseDefault -- Default
896 cgPrimAlts gc_flag uniq ty alts deflt
897 = cgPrimAltsGivenScrutinee gc_flag scrutinee alts deflt
899 -- A temporary variable, or standard register, to hold the result
900 scrutinee = case gc_flag of
901 NoGC -> CTemp uniq kind
902 GCMayHappen -> CReg (dataReturnConvPrim kind)
904 kind = typePrimRep ty
907 cgPrimAltsGivenScrutinee gc_flag scrutinee alts deflt
908 = forkAlts (map (cgPrimAlt gc_flag) alts)
909 [{- No "extra branches" -}]
910 (cgPrimDefault gc_flag scrutinee deflt) `thenFC` \ (alt_absCs, deflt_absC) ->
911 absC (CSwitch scrutinee alt_absCs deflt_absC)
912 -- CSwitch does sensible things with one or zero alternatives
916 -> (Literal, StgExpr) -- The alternative
917 -> FCode (Literal, AbstractC) -- Its compiled form
919 cgPrimAlt gc_flag (lit, rhs)
920 = getAbsC rhs_code `thenFC` \ absC ->
923 rhs_code = possibleHeapCheck gc_flag [] False (cgExpr rhs )
925 cgPrimDefault :: GCFlag
926 -> CAddrMode -- Scrutinee
930 cgPrimDefault gc_flag scrutinee StgNoDefault
931 = panic "cgPrimDefault: No default in prim case"
933 cgPrimDefault gc_flag scrutinee (StgBindDefault _ False{-binder not used-} rhs)
934 = getAbsC (possibleHeapCheck gc_flag [] False (cgExpr rhs ))
936 cgPrimDefault gc_flag scrutinee (StgBindDefault binder True{-used-} rhs)
937 = getAbsC (possibleHeapCheck gc_flag regs False rhs_code)
939 regs = if isFollowableRep (getAmodeRep scrutinee) then
942 rhs_code = bindNewPrimToAmode binder scrutinee `thenC`
947 %************************************************************************
949 \subsection[CgCase-tidy]{Code for tidying up prior to an eval}
951 %************************************************************************
954 saveVolatileVarsAndRegs
955 :: StgLiveVars -- Vars which should be made safe
956 -> FCode (AbstractC, -- Assignments to do the saves
957 EndOfBlockInfo, -- New sequel, recording where the return
959 Maybe VirtualSpBOffset) -- Slot for current cost centre
962 saveVolatileVarsAndRegs vars
963 = saveVolatileVars vars `thenFC` \ var_saves ->
964 saveCurrentCostCentre `thenFC` \ (maybe_cc_slot, cc_save) ->
965 saveReturnAddress `thenFC` \ (new_eob_info, ret_save) ->
966 returnFC (mkAbstractCs [var_saves, cc_save, ret_save],
971 saveVolatileVars :: StgLiveVars -- Vars which should be made safe
972 -> FCode AbstractC -- Assignments to to the saves
974 saveVolatileVars vars
975 = save_em (idSetToList vars)
977 save_em [] = returnFC AbsCNop
980 = getCAddrModeIfVolatile var `thenFC` \ v ->
982 Nothing -> save_em vars -- Non-volatile, so carry on
985 Just vol_amode -> -- Aha! It's volatile
986 save_var var vol_amode `thenFC` \ abs_c ->
987 save_em vars `thenFC` \ abs_cs ->
988 returnFC (abs_c `mkAbsCStmts` abs_cs)
990 save_var var vol_amode
991 | isFollowableRep kind
992 = allocAStack `thenFC` \ a_slot ->
993 rebindToAStack var a_slot `thenC`
994 getSpARelOffset a_slot `thenFC` \ spa_rel ->
995 returnFC (CAssign (CVal spa_rel kind) vol_amode)
997 = allocBStack (getPrimRepSize kind) `thenFC` \ b_slot ->
998 rebindToBStack var b_slot `thenC`
999 getSpBRelOffset b_slot `thenFC` \ spb_rel ->
1000 returnFC (CAssign (CVal spb_rel kind) vol_amode)
1002 kind = getAmodeRep vol_amode
1004 saveReturnAddress :: FCode (EndOfBlockInfo, AbstractC)
1006 = getEndOfBlockInfo `thenFC` \ eob_info@(EndOfBlockInfo vA vB sequel) ->
1008 -- See if it is volatile
1010 InRetReg -> -- Yes, it's volatile
1011 allocBStack retPrimRepSize `thenFC` \ b_slot ->
1012 getSpBRelOffset b_slot `thenFC` \ spb_rel ->
1014 returnFC (EndOfBlockInfo vA vB (OnStack b_slot),
1015 CAssign (CVal spb_rel RetRep) (CReg RetReg))
1017 UpdateCode _ -> -- It's non-volatile all right, but we still need
1018 -- to allocate a B-stack slot for it, *solely* to make
1019 -- sure that update frames for different values do not
1020 -- appear adjacent on the B stack. This makes sure
1021 -- that B-stack squeezing works ok.
1023 allocBStack retPrimRepSize `thenFC` \ b_slot ->
1024 returnFC (eob_info, AbsCNop)
1026 other -> -- No, it's non-volatile, so do nothing
1027 returnFC (eob_info, AbsCNop)
1030 Note about B-stack squeezing. Consider the following:`
1032 y = [...] \u [] -> ...
1033 x = [y] \u [] -> case y of (a,b) -> a
1035 The code for x will push an update frame, and then enter y. The code
1036 for y will push another update frame. If the B-stack-squeezer then
1037 wakes up, it will see two update frames right on top of each other,
1038 and will combine them. This is WRONG, of course, because x's value is
1039 not the same as y's.
1041 The fix implemented above makes sure that we allocate an (unused)
1042 B-stack slot before entering y. You can think of this as holding the
1043 saved value of RetAddr, which (after pushing x's update frame will be
1044 some update code ptr). The compiler is clever enough to load the
1045 static update code ptr into RetAddr before entering ~a~, but the slot
1046 is still there to separate the update frames.
1048 When we save the current cost centre (which is done for lexical
1049 scoping), we allocate a free B-stack location, and return (a)~the
1050 virtual offset of the location, to pass on to the alternatives, and
1051 (b)~the assignment to do the save (just as for @saveVolatileVars@).
1054 saveCurrentCostCentre ::
1055 FCode (Maybe VirtualSpBOffset, -- Where we decide to store it
1056 -- Nothing if not lexical CCs
1057 AbstractC) -- Assignment to save it
1058 -- AbsCNop if not lexical CCs
1060 saveCurrentCostCentre
1062 doing_profiling = opt_SccProfilingOn
1064 if not doing_profiling then
1065 returnFC (Nothing, AbsCNop)
1067 allocBStack (getPrimRepSize CostCentreRep) `thenFC` \ b_slot ->
1068 getSpBRelOffset b_slot `thenFC` \ spb_rel ->
1069 returnFC (Just b_slot,
1070 CAssign (CVal spb_rel CostCentreRep) (CReg CurCostCentre))
1072 restoreCurrentCostCentre :: Maybe VirtualSpBOffset -> FCode AbstractC
1074 restoreCurrentCostCentre Nothing
1076 restoreCurrentCostCentre (Just b_slot)
1077 = getSpBRelOffset b_slot `thenFC` \ spb_rel ->
1078 freeBStkSlot b_slot `thenC`
1079 returnFC (CCallProfCCMacro SLIT("RESTORE_CCC") [CVal spb_rel CostCentreRep])
1080 -- we use the RESTORE_CCC macro, rather than just
1081 -- assigning into CurCostCentre, in case RESTORE_CCC
1082 -- has some sanity-checking in it.
1086 %************************************************************************
1088 \subsection[CgCase-return-vec]{Building a return vector}
1090 %************************************************************************
1092 Build a return vector, and return a suitable label addressing
1096 mkReturnVector :: Unique
1098 -> [(ConTag, AbstractC)] -- Branch codes
1099 -> AbstractC -- Default case
1102 mkReturnVector uniq ty tagged_alt_absCs deflt_absC
1104 (return_vec_amode, vtbl_body) = case (ctrlReturnConvAlg spec_tycon) of {
1106 UnvectoredReturn _ ->
1107 (CUnVecLbl ret_label vtbl_label,
1108 absC (CRetUnVector vtbl_label
1109 (CLabelledCode ret_label
1110 (mkAlgAltsCSwitch (CReg TagReg)
1113 VectoredReturn table_size ->
1114 (CLbl vtbl_label DataPtrRep,
1115 absC (CRetVector vtbl_label
1116 -- must restore cc before each alt, if required
1117 (map mk_vector_entry [fIRST_TAG .. (table_size+fIRST_TAG-1)])
1120 -- Leave nops and comments in for now; they are eliminated
1121 -- lazily as it's printed.
1122 -- (case (nonemptyAbsC deflt_absC) of
1123 -- Nothing -> AbsCNop
1128 returnFC return_vec_amode
1132 (spec_tycon,_,_) = case (maybeAppSpecDataTyConExpandingDicts ty) of -- *must* be a real "data" type constructor
1134 Nothing -> pprError "ERROR: can't generate code for polymorphic case;\nprobably a mis-use of `seq' or `par';\nthe User's Guide has more details.\nOffending type: " (ppr PprDebug ty)
1136 vtbl_label = mkVecTblLabel uniq
1137 ret_label = mkReturnPtLabel uniq
1139 mk_vector_entry :: ConTag -> Maybe CAddrMode
1141 = case [ absC | (t, absC) <- tagged_alt_absCs, t == tag ] of
1143 [absC] -> Just (CCode absC)
1144 _ -> panic "mkReturnVector: too many"
1147 %************************************************************************
1149 \subsection[CgCase-utils]{Utilities for handling case expressions}
1151 %************************************************************************
1153 @possibleHeapCheck@ tests a flag passed in to decide whether to
1154 do a heap check or not.
1157 possibleHeapCheck :: GCFlag -> [MagicId] -> Bool -> Code -> Code
1159 possibleHeapCheck GCMayHappen regs node_reqd code = heapCheck regs node_reqd code
1160 possibleHeapCheck NoGC _ _ code = code
1163 Select a restricted set of registers based on a usage mask.
1166 selectByMask [] [] = []
1167 selectByMask (True:ms) (x:xs) = x : selectByMask ms xs
1168 selectByMask (False:ms) (x:xs) = selectByMask ms xs