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 #if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ <= 201
17 IMPORT_DELOOPER(CgLoop2) -- here for paranoia-checking
20 import Constants ( mAX_SPEC_SELECTEE_SIZE )
25 import AbsCUtils ( mkAbsCStmts, mkAbstractCs )
26 import CgBindery ( getArgAmodes, getCAddrModeAndInfo, CgIdInfo )
27 import CgCase ( cgCase, saveVolatileVarsAndRegs )
28 import CgClosure ( cgRhsClosure )
29 import CgCon ( buildDynCon, cgReturnDataCon )
30 import CgHeapery ( allocHeap )
31 import CgLetNoEscape ( cgLetNoEscapeClosure )
32 import CgRetConv ( dataReturnConvAlg, ctrlReturnConvAlg,
33 DataReturnConvention(..), CtrlReturnConvention(..),
34 assignPrimOpResultRegs, makePrimOpArgsRobust
36 import CgTailCall ( cgTailCall, performReturn,
37 mkDynamicAlgReturnCode, mkPrimReturnCode
39 import CLabel ( mkPhantomInfoTableLabel, mkInfoTableVecTblLabel )
40 import ClosureInfo ( mkClosureLFInfo, mkSelectorLFInfo, mkVapLFInfo,
42 import CostCentre ( sccAbleCostCentre, isDictCC, isSccCountCostCentre )
43 import HeapOffs ( SYN_IE(VirtualSpBOffset), intOffsetIntoGoods )
44 import Id ( dataConTyCon, idPrimRep, getIdArity,
45 mkIdSet, unionIdSets, GenId{-instance Outputable-},
48 import IdInfo ( ArityInfo(..) )
49 import Name ( isLocallyDefined )
50 import Outputable ( PprStyle(..), Outputable(..) )
52 import PrimOp ( primOpCanTriggerGC, primOpHeapReq, HeapRequirement(..),
53 getPrimOpResultInfo, PrimOp(..), PrimOpResultInfo(..)
55 import PrimRep ( getPrimRepSize, PrimRep(..) )
56 import TyCon ( tyConDataCons, maybeTyConSingleCon )
57 import Maybes ( assocMaybe, maybeToBool )
58 import Util ( panic, isIn, pprPanic, assertPanic )
61 This module provides the support code for @StgToAbstractC@ to deal
62 with STG {\em expressions}. See also @CgClosure@, which deals
63 with closures, and @CgCon@, which deals with constructors.
66 cgExpr :: StgExpr -- input
70 %********************************************************
74 %********************************************************
76 ``Applications'' mean {\em tail calls}, a service provided by module
77 @CgTailCall@. This includes literals, which show up as
78 @(STGApp (StgLitArg 42) [])@.
81 cgExpr (StgApp fun args live_vars) = cgTailCall fun args live_vars
84 %********************************************************
86 %* STG ConApps (for inline versions) *
88 %********************************************************
91 cgExpr (StgCon con args live_vars)
92 = getArgAmodes args `thenFC` \ amodes ->
93 cgReturnDataCon con amodes (all zero_size args) live_vars
95 zero_size atom = getPrimRepSize (getArgPrimRep atom) == 0
98 %********************************************************
100 %* STG PrimApps (unboxed primitive ops) *
102 %********************************************************
104 Here is where we insert real live machine instructions.
107 cgExpr x@(StgPrim op args live_vars)
108 = ASSERT(op /= SeqOp) -- can't handle SeqOp
109 getPrimOpArgAmodes op args `thenFC` \ arg_amodes ->
111 result_regs = assignPrimOpResultRegs op
112 result_amodes = map CReg result_regs
113 may_gc = primOpCanTriggerGC op
114 dyn_tag = head result_amodes
115 -- The tag from a primitive op returning an algebraic data type
116 -- is returned in the first result_reg_amode
119 -- Use registers for args, and assign args to the regs
120 -- (Can-trigger-gc primops guarantee to have their args in regs)
122 (arg_robust_amodes, liveness_mask, arg_assts)
123 = makePrimOpArgsRobust op arg_amodes
125 liveness_arg = mkIntCLit liveness_mask
129 COpStmt result_amodes op
130 (pin_liveness op liveness_arg arg_robust_amodes)
135 -- Use args from their current amodes.
137 liveness_mask = panic "cgExpr: liveness of non-GC-ing primop touched\n"
140 COpStmt result_amodes op arg_amodes liveness_mask [{-no vol_regs-}],
143 ) `thenFC` \ (do_before_stack_cleanup,
144 do_just_before_jump) ->
146 case (getPrimOpResultInfo op) of
149 performReturn do_before_stack_cleanup
150 (\ sequel -> robustifySequel may_gc sequel
151 `thenFC` \ (ret_asst, sequel') ->
152 absC (ret_asst `mkAbsCStmts` do_just_before_jump)
154 mkPrimReturnCode sequel')
158 profCtrC SLIT("RET_NEW_IN_REGS") [num_of_fields] `thenC`
160 performReturn do_before_stack_cleanup
161 (\ sequel -> robustifySequel may_gc sequel
162 `thenFC` \ (ret_asst, sequel') ->
163 absC (mkAbstractCs [ret_asst,
166 -- Must load info ptr here, not in do_just_before_stack_cleanup,
167 -- because the info-ptr reg clashes with argument registers
170 mkDynamicAlgReturnCode tycon dyn_tag sequel')
174 -- Here, the destination _can_ be an update frame, so we need to make sure that
175 -- infoptr (R2) is loaded with the constructor's info ptr.
177 info_ptr_assign = CAssign (CReg infoptr) info_lbl
180 = case (ctrlReturnConvAlg tycon) of
181 VectoredReturn _ -> vec_lbl
182 UnvectoredReturn _ -> dir_lbl
184 vec_lbl = CTableEntry (CLbl (mkInfoTableVecTblLabel tycon) DataPtrRep)
187 data_con = head (tyConDataCons tycon)
189 (dir_lbl, num_of_fields)
190 = case (dataReturnConvAlg data_con) of
192 -> (CLbl (mkPhantomInfoTableLabel data_con) DataPtrRep,
193 mkIntCLit (length rs)) -- for ticky-ticky only
196 -> pprPanic "CgExpr: can't return prim in heap:" (ppr PprDebug data_con)
197 -- Never used, and no point in generating
200 -- for all PrimOps except ccalls, we pin the liveness info
201 -- on as the first "argument"
202 -- ToDo: un-duplicate?
204 pin_liveness (CCallOp _ _ _ _ _) _ args = args
205 pin_liveness other_op liveness_arg args
208 -- We only need to worry about the sequel when we may GC and the
209 -- sequel is OnStack. If that's the case, arrange to pull the
210 -- sequel out into RetReg before performing the primOp.
212 robustifySequel True sequel@(OnStack _) =
213 sequelToAmode sequel `thenFC` \ amode ->
214 returnFC (CAssign (CReg RetReg) amode, InRetReg)
215 robustifySequel _ sequel = returnFC (AbsCNop, sequel)
218 %********************************************************
220 %* Case expressions *
222 %********************************************************
223 Case-expression conversion is complicated enough to have its own
227 cgExpr (StgCase expr live_vars save_vars uniq alts)
228 = cgCase expr live_vars save_vars uniq alts
232 %********************************************************
236 %********************************************************
237 \subsection[let-and-letrec-codegen]{Converting @StgLet@ and @StgLetrec@}
240 cgExpr (StgLet (StgNonRec name rhs) expr)
241 = cgRhs name rhs `thenFC` \ (name, info) ->
242 addBindC name info `thenC`
245 cgExpr (StgLet (StgRec pairs) expr)
246 = fixC (\ new_bindings -> addBindsC new_bindings `thenC`
247 listFCs [ cgRhs b e | (b,e) <- pairs ]
248 ) `thenFC` \ new_bindings ->
250 addBindsC new_bindings `thenC`
255 cgExpr (StgLetNoEscape live_in_whole_let live_in_rhss bindings body)
256 = -- Figure out what volatile variables to save
257 nukeDeadBindings live_in_whole_let `thenC`
258 saveVolatileVarsAndRegs live_in_rhss
259 `thenFC` \ (save_assts, rhs_eob_info, maybe_cc_slot) ->
261 -- ToDo: cost centre???
263 -- Save those variables right now!
264 absC save_assts `thenC`
266 -- Produce code for the rhss
267 -- and add suitable bindings to the environment
268 cgLetNoEscapeBindings live_in_rhss rhs_eob_info maybe_cc_slot bindings `thenC`
271 setEndOfBlockInfo rhs_eob_info (cgExpr body)
275 %********************************************************
279 %********************************************************
280 \subsection[scc-codegen]{Converting StgSCC}
282 SCC expressions are treated specially. They set the current cost
285 cgExpr (StgSCC ty cc expr)
286 = ASSERT(sccAbleCostCentre cc)
288 (if isDictCC cc then SLIT("SET_DICT_CCC") else SLIT("SET_CCC"))
289 [mkCCostCentre cc, mkIntCLit (if isSccCountCostCentre cc then 1 else 0)]
294 ToDo: counting of dict sccs ...
296 %********************************************************
298 %* Non-top-level bindings *
300 %********************************************************
301 \subsection[non-top-level-bindings]{Converting non-top-level bindings}
303 We rely on the support code in @CgCon@ (to do constructors) and
304 in @CgClosure@ (to do closures).
307 cgRhs :: Id -> StgRhs -> FCode (Id, CgIdInfo)
308 -- the Id is passed along so a binding can be set up
310 cgRhs name (StgRhsCon maybe_cc con args)
311 = getArgAmodes args `thenFC` \ amodes ->
312 buildDynCon name maybe_cc con amodes (all zero_size args)
314 returnFC (name, idinfo)
316 zero_size atom = getPrimRepSize (getArgPrimRep atom) == 0
318 cgRhs name (StgRhsClosure cc bi fvs upd_flag args body)
319 = cgRhsClosure name cc bi fvs args body lf_info
321 lf_info = mkRhsLFInfo fvs upd_flag args body
325 mkRhsLFInfo looks for two special forms of the right-hand side:
329 If neither happens, it just calls mkClosureLFInfo. You might think
330 that mkClosureLFInfo should do all this, but
332 (a) it seems wrong for the latter to look at the structure
335 [March 97: item (b) is no longer true, but I've left mkRhsLFInfo here
336 anyway because of (a).]
338 (b) mkRhsLFInfo has to be in the monad since it looks up in
339 the environment, and it's very tiresome for mkClosureLFInfo to
340 be. Apart from anything else it would make a loop between
341 CgBindery and ClosureInfo.
345 We look at the body of the closure to see if it's a selector---turgid,
346 but nothing deep. We are looking for a closure of {\em exactly} the
349 ... = [the_fv] \ u [] ->
351 con a_1 ... a_n -> a_i
355 mkRhsLFInfo [the_fv] -- Just one free var
356 Updatable -- Updatable thunk
358 (StgCase (StgApp (StgVarArg scrutinee) [{-no args-}] _)
359 _ _ _ -- ignore live vars and uniq...
361 [(con, params, use_mask,
362 (StgApp (StgVarArg selectee) [{-no args-}] _))]
364 | the_fv == scrutinee -- Scrutinee is the only free variable
365 && maybeToBool maybe_offset -- Selectee is a component of the tuple
366 && maybeToBool offset_into_int_maybe
367 && offset_into_int <= mAX_SPEC_SELECTEE_SIZE -- Offset is small enough
368 = -- ASSERT(is_single_constructor) -- Should be true, but causes error for SpecTyCon
369 mkSelectorLFInfo scrutinee con offset_into_int
371 (_, params_w_offsets) = layOutDynCon con idPrimRep params
372 maybe_offset = assocMaybe params_w_offsets selectee
373 Just the_offset = maybe_offset
374 offset_into_int_maybe = intOffsetIntoGoods the_offset
375 Just offset_into_int = offset_into_int_maybe
376 is_single_constructor = maybeToBool (maybeTyConSingleCon tycon)
377 tycon = dataConTyCon con
383 Same kind of thing, looking for vector-apply thunks, of the form:
385 x = [...] \ .. [] -> f a1 .. an
387 where f has arity n. We rely on the arity info inside the Id being correct.
392 [] -- No args; a thunk
393 (StgApp (StgVarArg fun_id) args _)
394 | isLocallyDefined fun_id -- Must be defined in this module
395 = -- Get the arity of the fun_id. It's guaranteed to be correct (by setStgVarInfo).
397 arity_maybe = case getIdArity fun_id of
398 ArityExactly n -> Just n
403 | arity > 0 && -- It'd better be a function!
404 arity == length args -- Saturated application
405 -> -- Ha! A VAP thunk
406 mkVapLFInfo fvs upd_flag fun_id args store_fun_in_vap
408 other -> mkClosureLFInfo False{-not top level-} fvs upd_flag []
410 -- If the function is a free variable then it must be stored
411 -- in the thunk too; if it isn't a free variable it must be
412 -- because it's constant, so it doesn't need to be stored in the thunk
413 store_fun_in_vap = fun_id `is_elem` fvs
414 is_elem = isIn "mkClosureLFInfo"
420 mkRhsLFInfo fvs upd_flag args body
421 = mkClosureLFInfo False{-not top level-} fvs upd_flag args
425 %********************************************************
427 %* Let-no-escape bindings
429 %********************************************************
431 cgLetNoEscapeBindings live_in_rhss rhs_eob_info maybe_cc_slot (StgNonRec binder rhs)
432 = cgLetNoEscapeRhs live_in_rhss rhs_eob_info maybe_cc_slot binder rhs
433 `thenFC` \ (binder, info) ->
436 cgLetNoEscapeBindings live_in_rhss rhs_eob_info maybe_cc_slot (StgRec pairs)
437 = fixC (\ new_bindings ->
438 addBindsC new_bindings `thenC`
439 listFCs [ cgLetNoEscapeRhs full_live_in_rhss rhs_eob_info
440 maybe_cc_slot b e | (b,e) <- pairs ]
441 ) `thenFC` \ new_bindings ->
443 addBindsC new_bindings
445 -- We add the binders to the live-in-rhss set so that we don't
446 -- delete the bindings for the binder from the environment!
447 full_live_in_rhss = live_in_rhss `unionIdSets` (mkIdSet [b | (b,r) <- pairs])
450 :: StgLiveVars -- Live in rhss
452 -> Maybe VirtualSpBOffset
455 -> FCode (Id, CgIdInfo)
457 cgLetNoEscapeRhs full_live_in_rhss rhs_eob_info maybe_cc_slot binder
458 (StgRhsClosure cc bi _ upd_flag args body)
459 = -- We could check the update flag, but currently we don't switch it off
460 -- for let-no-escaped things, so we omit the check too!
462 -- Updatable -> panic "cgLetNoEscapeRhs" -- Nothing to update!
463 -- other -> cgLetNoEscapeClosure binder cc bi live_in_whole_let live_in_rhss args body
464 cgLetNoEscapeClosure binder cc bi full_live_in_rhss rhs_eob_info maybe_cc_slot args body
466 -- For a constructor RHS we want to generate a single chunk of code which
467 -- can be jumped to from many places, which will return the constructor.
468 -- It's easy; just behave as if it was an StgRhsClosure with a ConApp inside!
469 cgLetNoEscapeRhs full_live_in_rhss rhs_eob_info maybe_cc_slot binder
470 (StgRhsCon cc con args)
471 = cgLetNoEscapeClosure binder cc stgArgOcc{-safe-} full_live_in_rhss rhs_eob_info maybe_cc_slot
472 [] --No args; the binder is data structure, not a function
473 (StgCon con args full_live_in_rhss)
476 Some PrimOps require a {\em fixed} amount of heap allocation. Rather
477 than tidy away ready for GC and do a full heap check, we simply
478 allocate a completely uninitialised block in-line, just like any other
479 thunk/constructor allocation, and pass it to the PrimOp as its first
480 argument. Remember! The PrimOp is entirely responsible for
481 initialising the object. In particular, the PrimOp had better not
482 trigger GC before it has filled it in, and even then it had better
483 make sure that the GC can find the object somehow.
485 Main current use: allocating SynchVars.
488 getPrimOpArgAmodes op args
489 = getArgAmodes args `thenFC` \ arg_amodes ->
491 case primOpHeapReq op of
492 FixedHeapRequired size -> allocHeap size `thenFC` \ amode ->
493 returnFC (amode : arg_amodes)
495 _ -> returnFC arg_amodes