2 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1995
4 %********************************************************
6 \section[CgExpr]{Converting @StgExpr@s}
8 %********************************************************
11 #include "HsVersions.h"
13 module CgExpr ( cgExpr, getPrimOpArgAmodes ) where
16 IMPORT_DELOOPER(CgLoop2) -- here for paranoia-checking
18 import Constants ( mAX_SPEC_SELECTEE_SIZE )
23 import AbsCUtils ( mkAbsCStmts, mkAbstractCs )
24 import CgBindery ( getArgAmodes, getCAddrModeAndInfo, CgIdInfo )
25 import CgCase ( cgCase, saveVolatileVarsAndRegs )
26 import CgClosure ( cgRhsClosure )
27 import CgCon ( buildDynCon, cgReturnDataCon )
28 import CgHeapery ( allocHeap )
29 import CgLetNoEscape ( cgLetNoEscapeClosure )
30 import CgRetConv ( dataReturnConvAlg, ctrlReturnConvAlg,
31 DataReturnConvention(..), CtrlReturnConvention(..),
32 assignPrimOpResultRegs, makePrimOpArgsRobust
34 import CgTailCall ( cgTailCall, performReturn,
35 mkDynamicAlgReturnCode, mkPrimReturnCode
37 import CLabel ( mkPhantomInfoTableLabel, mkInfoTableVecTblLabel )
38 import ClosureInfo ( mkClosureLFInfo, mkSelectorLFInfo, mkVapLFInfo,
40 import CostCentre ( sccAbleCostCentre, isDictCC, isSccCountCostCentre )
41 import HeapOffs ( SYN_IE(VirtualSpBOffset), intOffsetIntoGoods )
42 import Id ( dataConTyCon, idPrimRep, getIdArity,
43 mkIdSet, unionIdSets, GenId{-instance Outputable-},
46 import IdInfo ( ArityInfo(..) )
47 import Name ( isLocallyDefined )
48 import PprStyle ( PprStyle(..) )
50 import PrimOp ( primOpCanTriggerGC, primOpHeapReq, HeapRequirement(..),
51 getPrimOpResultInfo, PrimOp(..), PrimOpResultInfo(..)
53 import PrimRep ( getPrimRepSize, PrimRep(..) )
54 import TyCon ( tyConDataCons, maybeTyConSingleCon )
55 import Maybes ( assocMaybe, maybeToBool )
56 import Util ( panic, isIn, pprPanic, assertPanic )
57 #if __GLASGOW_HASKELL__ >= 202
58 import Outputable ( Outputable(..) )
62 This module provides the support code for @StgToAbstractC@ to deal
63 with STG {\em expressions}. See also @CgClosure@, which deals
64 with closures, and @CgCon@, which deals with constructors.
67 cgExpr :: StgExpr -- input
71 %********************************************************
75 %********************************************************
77 ``Applications'' mean {\em tail calls}, a service provided by module
78 @CgTailCall@. This includes literals, which show up as
79 @(STGApp (StgLitArg 42) [])@.
82 cgExpr (StgApp fun args live_vars) = cgTailCall fun args live_vars
85 %********************************************************
87 %* STG ConApps (for inline versions) *
89 %********************************************************
92 cgExpr (StgCon con args live_vars)
93 = getArgAmodes args `thenFC` \ amodes ->
94 cgReturnDataCon con amodes (all zero_size args) live_vars
96 zero_size atom = getPrimRepSize (getArgPrimRep atom) == 0
99 %********************************************************
101 %* STG PrimApps (unboxed primitive ops) *
103 %********************************************************
105 Here is where we insert real live machine instructions.
108 cgExpr x@(StgPrim op args live_vars)
109 = ASSERT(op /= SeqOp) -- can't handle SeqOp
110 getPrimOpArgAmodes op args `thenFC` \ arg_amodes ->
112 result_regs = assignPrimOpResultRegs op
113 result_amodes = map CReg result_regs
114 may_gc = primOpCanTriggerGC op
115 dyn_tag = head result_amodes
116 -- The tag from a primitive op returning an algebraic data type
117 -- is returned in the first result_reg_amode
120 -- Use registers for args, and assign args to the regs
121 -- (Can-trigger-gc primops guarantee to have their args in regs)
123 (arg_robust_amodes, liveness_mask, arg_assts)
124 = makePrimOpArgsRobust op arg_amodes
126 liveness_arg = mkIntCLit liveness_mask
130 COpStmt result_amodes op
131 (pin_liveness op liveness_arg arg_robust_amodes)
136 -- Use args from their current amodes.
138 liveness_mask = panic "cgExpr: liveness of non-GC-ing primop touched\n"
141 COpStmt result_amodes op arg_amodes liveness_mask [{-no vol_regs-}],
144 ) `thenFC` \ (do_before_stack_cleanup,
145 do_just_before_jump) ->
147 case (getPrimOpResultInfo op) of
150 performReturn do_before_stack_cleanup
151 (\ sequel -> robustifySequel may_gc sequel
152 `thenFC` \ (ret_asst, sequel') ->
153 absC (ret_asst `mkAbsCStmts` do_just_before_jump)
155 mkPrimReturnCode sequel')
159 profCtrC SLIT("RET_NEW_IN_REGS") [num_of_fields] `thenC`
161 performReturn do_before_stack_cleanup
162 (\ sequel -> robustifySequel may_gc sequel
163 `thenFC` \ (ret_asst, sequel') ->
164 absC (mkAbstractCs [ret_asst,
167 -- Must load info ptr here, not in do_just_before_stack_cleanup,
168 -- because the info-ptr reg clashes with argument registers
171 mkDynamicAlgReturnCode tycon dyn_tag sequel')
175 -- Here, the destination _can_ be an update frame, so we need to make sure that
176 -- infoptr (R2) is loaded with the constructor's info ptr.
178 info_ptr_assign = CAssign (CReg infoptr) info_lbl
181 = case (ctrlReturnConvAlg tycon) of
182 VectoredReturn _ -> vec_lbl
183 UnvectoredReturn _ -> dir_lbl
185 vec_lbl = CTableEntry (CLbl (mkInfoTableVecTblLabel tycon) DataPtrRep)
188 data_con = head (tyConDataCons tycon)
190 (dir_lbl, num_of_fields)
191 = case (dataReturnConvAlg data_con) of
193 -> (CLbl (mkPhantomInfoTableLabel data_con) DataPtrRep,
194 mkIntCLit (length rs)) -- for ticky-ticky only
197 -> pprPanic "CgExpr: can't return prim in heap:" (ppr PprDebug data_con)
198 -- Never used, and no point in generating
201 -- for all PrimOps except ccalls, we pin the liveness info
202 -- on as the first "argument"
203 -- ToDo: un-duplicate?
205 pin_liveness (CCallOp _ _ _ _ _) _ args = args
206 pin_liveness other_op liveness_arg args
209 -- We only need to worry about the sequel when we may GC and the
210 -- sequel is OnStack. If that's the case, arrange to pull the
211 -- sequel out into RetReg before performing the primOp.
213 robustifySequel True sequel@(OnStack _) =
214 sequelToAmode sequel `thenFC` \ amode ->
215 returnFC (CAssign (CReg RetReg) amode, InRetReg)
216 robustifySequel _ sequel = returnFC (AbsCNop, sequel)
219 %********************************************************
221 %* Case expressions *
223 %********************************************************
224 Case-expression conversion is complicated enough to have its own
228 cgExpr (StgCase expr live_vars save_vars uniq alts)
229 = cgCase expr live_vars save_vars uniq alts
233 %********************************************************
237 %********************************************************
238 \subsection[let-and-letrec-codegen]{Converting @StgLet@ and @StgLetrec@}
241 cgExpr (StgLet (StgNonRec name rhs) expr)
242 = cgRhs name rhs `thenFC` \ (name, info) ->
243 addBindC name info `thenC`
246 cgExpr (StgLet (StgRec pairs) expr)
247 = fixC (\ new_bindings -> addBindsC new_bindings `thenC`
248 listFCs [ cgRhs b e | (b,e) <- pairs ]
249 ) `thenFC` \ new_bindings ->
251 addBindsC new_bindings `thenC`
256 cgExpr (StgLetNoEscape live_in_whole_let live_in_rhss bindings body)
257 = -- Figure out what volatile variables to save
258 nukeDeadBindings live_in_whole_let `thenC`
259 saveVolatileVarsAndRegs live_in_rhss
260 `thenFC` \ (save_assts, rhs_eob_info, maybe_cc_slot) ->
262 -- ToDo: cost centre???
264 -- Save those variables right now!
265 absC save_assts `thenC`
267 -- Produce code for the rhss
268 -- and add suitable bindings to the environment
269 cgLetNoEscapeBindings live_in_rhss rhs_eob_info maybe_cc_slot bindings `thenC`
272 setEndOfBlockInfo rhs_eob_info (cgExpr body)
276 %********************************************************
280 %********************************************************
281 \subsection[scc-codegen]{Converting StgSCC}
283 SCC expressions are treated specially. They set the current cost
286 cgExpr (StgSCC ty cc expr)
287 = ASSERT(sccAbleCostCentre cc)
289 (if isDictCC cc then SLIT("SET_DICT_CCC") else SLIT("SET_CCC"))
290 [mkCCostCentre cc, mkIntCLit (if isSccCountCostCentre cc then 1 else 0)]
295 ToDo: counting of dict sccs ...
297 %********************************************************
299 %* Non-top-level bindings *
301 %********************************************************
302 \subsection[non-top-level-bindings]{Converting non-top-level bindings}
304 We rely on the support code in @CgCon@ (to do constructors) and
305 in @CgClosure@ (to do closures).
308 cgRhs :: Id -> StgRhs -> FCode (Id, CgIdInfo)
309 -- the Id is passed along so a binding can be set up
311 cgRhs name (StgRhsCon maybe_cc con args)
312 = getArgAmodes args `thenFC` \ amodes ->
313 buildDynCon name maybe_cc con amodes (all zero_size args)
315 returnFC (name, idinfo)
317 zero_size atom = getPrimRepSize (getArgPrimRep atom) == 0
319 cgRhs name (StgRhsClosure cc bi fvs upd_flag args body)
320 = cgRhsClosure name cc bi fvs args body lf_info
322 lf_info = mkRhsLFInfo fvs upd_flag args body
326 mkRhsLFInfo looks for two special forms of the right-hand side:
330 If neither happens, it just calls mkClosureLFInfo. You might think
331 that mkClosureLFInfo should do all this, but
333 (a) it seems wrong for the latter to look at the structure
336 [March 97: item (b) is no longer true, but I've left mkRhsLFInfo here
337 anyway because of (a).]
339 (b) mkRhsLFInfo has to be in the monad since it looks up in
340 the environment, and it's very tiresome for mkClosureLFInfo to
341 be. Apart from anything else it would make a loop between
342 CgBindery and ClosureInfo.
346 We look at the body of the closure to see if it's a selector---turgid,
347 but nothing deep. We are looking for a closure of {\em exactly} the
350 ... = [the_fv] \ u [] ->
352 con a_1 ... a_n -> a_i
356 mkRhsLFInfo [the_fv] -- Just one free var
357 Updatable -- Updatable thunk
359 (StgCase (StgApp (StgVarArg scrutinee) [{-no args-}] _)
360 _ _ _ -- ignore live vars and uniq...
362 [(con, params, use_mask,
363 (StgApp (StgVarArg selectee) [{-no args-}] _))]
365 | the_fv == scrutinee -- Scrutinee is the only free variable
366 && maybeToBool maybe_offset -- Selectee is a component of the tuple
367 && maybeToBool offset_into_int_maybe
368 && offset_into_int <= mAX_SPEC_SELECTEE_SIZE -- Offset is small enough
369 = -- ASSERT(is_single_constructor) -- Should be true, but causes error for SpecTyCon
370 mkSelectorLFInfo scrutinee con offset_into_int
372 (_, params_w_offsets) = layOutDynCon con idPrimRep params
373 maybe_offset = assocMaybe params_w_offsets selectee
374 Just the_offset = maybe_offset
375 offset_into_int_maybe = intOffsetIntoGoods the_offset
376 Just offset_into_int = offset_into_int_maybe
377 is_single_constructor = maybeToBool (maybeTyConSingleCon tycon)
378 tycon = dataConTyCon con
384 Same kind of thing, looking for vector-apply thunks, of the form:
386 x = [...] \ .. [] -> f a1 .. an
388 where f has arity n. We rely on the arity info inside the Id being correct.
393 [] -- No args; a thunk
394 (StgApp (StgVarArg fun_id) args _)
395 | isLocallyDefined fun_id -- Must be defined in this module
396 = -- Get the arity of the fun_id. It's guaranteed to be correct (by setStgVarInfo).
398 arity_maybe = case getIdArity fun_id of
399 ArityExactly n -> Just n
404 | arity > 0 && -- It'd better be a function!
405 arity == length args -- Saturated application
406 -> -- Ha! A VAP thunk
407 mkVapLFInfo fvs upd_flag fun_id args store_fun_in_vap
409 other -> mkClosureLFInfo False{-not top level-} fvs upd_flag []
411 -- If the function is a free variable then it must be stored
412 -- in the thunk too; if it isn't a free variable it must be
413 -- because it's constant, so it doesn't need to be stored in the thunk
414 store_fun_in_vap = fun_id `is_elem` fvs
415 is_elem = isIn "mkClosureLFInfo"
421 mkRhsLFInfo fvs upd_flag args body
422 = mkClosureLFInfo False{-not top level-} fvs upd_flag args
426 %********************************************************
428 %* Let-no-escape bindings
430 %********************************************************
432 cgLetNoEscapeBindings live_in_rhss rhs_eob_info maybe_cc_slot (StgNonRec binder rhs)
433 = cgLetNoEscapeRhs live_in_rhss rhs_eob_info maybe_cc_slot binder rhs
434 `thenFC` \ (binder, info) ->
437 cgLetNoEscapeBindings live_in_rhss rhs_eob_info maybe_cc_slot (StgRec pairs)
438 = fixC (\ new_bindings ->
439 addBindsC new_bindings `thenC`
440 listFCs [ cgLetNoEscapeRhs full_live_in_rhss rhs_eob_info
441 maybe_cc_slot b e | (b,e) <- pairs ]
442 ) `thenFC` \ new_bindings ->
444 addBindsC new_bindings
446 -- We add the binders to the live-in-rhss set so that we don't
447 -- delete the bindings for the binder from the environment!
448 full_live_in_rhss = live_in_rhss `unionIdSets` (mkIdSet [b | (b,r) <- pairs])
451 :: StgLiveVars -- Live in rhss
453 -> Maybe VirtualSpBOffset
456 -> FCode (Id, CgIdInfo)
458 cgLetNoEscapeRhs full_live_in_rhss rhs_eob_info maybe_cc_slot binder
459 (StgRhsClosure cc bi _ upd_flag args body)
460 = -- We could check the update flag, but currently we don't switch it off
461 -- for let-no-escaped things, so we omit the check too!
463 -- Updatable -> panic "cgLetNoEscapeRhs" -- Nothing to update!
464 -- other -> cgLetNoEscapeClosure binder cc bi live_in_whole_let live_in_rhss args body
465 cgLetNoEscapeClosure binder cc bi full_live_in_rhss rhs_eob_info maybe_cc_slot args body
467 -- For a constructor RHS we want to generate a single chunk of code which
468 -- can be jumped to from many places, which will return the constructor.
469 -- It's easy; just behave as if it was an StgRhsClosure with a ConApp inside!
470 cgLetNoEscapeRhs full_live_in_rhss rhs_eob_info maybe_cc_slot binder
471 (StgRhsCon cc con args)
472 = cgLetNoEscapeClosure binder cc stgArgOcc{-safe-} full_live_in_rhss rhs_eob_info maybe_cc_slot
473 [] --No args; the binder is data structure, not a function
474 (StgCon con args full_live_in_rhss)
477 Some PrimOps require a {\em fixed} amount of heap allocation. Rather
478 than tidy away ready for GC and do a full heap check, we simply
479 allocate a completely uninitialised block in-line, just like any other
480 thunk/constructor allocation, and pass it to the PrimOp as its first
481 argument. Remember! The PrimOp is entirely responsible for
482 initialising the object. In particular, the PrimOp had better not
483 trigger GC before it has filled it in, and even then it had better
484 make sure that the GC can find the object somehow.
486 Main current use: allocating SynchVars.
489 getPrimOpArgAmodes op args
490 = getArgAmodes args `thenFC` \ arg_amodes ->
492 case primOpHeapReq op of
493 FixedHeapRequired size -> allocHeap size `thenFC` \ amode ->
494 returnFC (amode : arg_amodes)
496 _ -> returnFC arg_amodes