2 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
4 % $Id: CgExpr.lhs,v 1.20 1999/03/11 11:32:26 simonm Exp $
6 %********************************************************
8 \section[CgExpr]{Converting @StgExpr@s}
10 %********************************************************
13 module CgExpr ( cgExpr ) where
15 #include "HsVersions.h"
17 import Constants ( mAX_SPEC_SELECTEE_SIZE, mAX_SPEC_AP_SIZE )
21 import AbsCUtils ( mkAbstractCs )
22 import CLabel ( mkClosureTblLabel )
24 import SMRep ( fixedHdrSize )
25 import CgBindery ( getArgAmodes, CgIdInfo, nukeDeadBindings )
26 import CgCase ( cgCase, saveVolatileVarsAndRegs,
27 restoreCurrentCostCentre,
28 splitTyConAppThroughNewTypes )
29 import CgClosure ( cgRhsClosure, cgStdRhsClosure )
30 import CgCon ( buildDynCon, cgReturnDataCon )
31 import CgLetNoEscape ( cgLetNoEscapeClosure )
32 import CgRetConv ( dataReturnConvPrim )
33 import CgTailCall ( cgTailCall, performReturn, performPrimReturn,
34 mkDynamicAlgReturnCode, mkPrimReturnCode,
35 tailCallPrimOp, returnUnboxedTuple
37 import ClosureInfo ( mkClosureLFInfo, mkSelectorLFInfo,
38 mkApLFInfo, layOutDynCon )
39 import CostCentre ( sccAbleCostCentre, isDictCC, isSccCountCostCentre )
40 import Id ( idPrimRep, idType, Id )
42 import DataCon ( DataCon, dataConTyCon )
43 import Const ( Con(..) )
44 import IdInfo ( ArityInfo(..) )
45 import PrimOp ( primOpOutOfLine,
46 getPrimOpResultInfo, PrimOp(..), PrimOpResultInfo(..)
48 import PrimRep ( getPrimRepSize, PrimRep(..), isFollowableRep )
49 import TyCon ( maybeTyConSingleCon,
50 isUnboxedTupleTyCon, isEnumerationTyCon )
51 import Type ( Type, typePrimRep )
52 import Maybes ( assocMaybe, maybeToBool )
53 import Unique ( mkBuiltinUnique )
54 import BasicTypes ( TopLevelFlag(..), RecFlag(..) )
58 This module provides the support code for @StgToAbstractC@ to deal
59 with STG {\em expressions}. See also @CgClosure@, which deals
60 with closures, and @CgCon@, which deals with constructors.
63 cgExpr :: StgExpr -- input
67 %********************************************************
71 %********************************************************
73 ``Applications'' mean {\em tail calls}, a service provided by module
74 @CgTailCall@. This includes literals, which show up as
75 @(STGApp (StgLitArg 42) [])@.
78 cgExpr (StgApp fun args) = cgTailCall fun args
81 %********************************************************
83 %* STG ConApps (for inline versions) *
85 %********************************************************
88 cgExpr (StgCon (DataCon con) args res_ty)
89 = getArgAmodes args `thenFC` \ amodes ->
90 cgReturnDataCon con amodes (all zero_size args)
92 zero_size atom = getPrimRepSize (getArgPrimRep atom) == 0
95 Literals are similar to constructors; they return by putting
96 themselves in an appropriate register and returning to the address on
100 cgExpr (StgCon (Literal lit) args res_ty)
101 = ASSERT( null args )
102 performPrimReturn (text "literal" <+> ppr lit) (CLit lit)
106 %********************************************************
108 %* STG PrimApps (unboxed primitive ops) *
110 %********************************************************
112 Here is where we insert real live machine instructions.
114 NOTE about _ccall_GC_:
116 A _ccall_GC_ is treated as an out-of-line primop for the case
117 expression code, because we want a proper stack frame on the stack
118 when we perform it. When we get here, however, we need to actually
119 perform the call, so we treat it an an inline primop.
122 cgExpr (StgCon (PrimOp op@(CCallOp _ _ may_gc@True _)) args res_ty)
123 = primRetUnboxedTuple op args res_ty
125 cgExpr x@(StgCon (PrimOp op) args res_ty)
126 | primOpOutOfLine op = tailCallPrimOp op args
128 = ASSERT(op /= SeqOp) -- can't handle SeqOp
130 getArgAmodes args `thenFC` \ arg_amodes ->
132 case (getPrimOpResultInfo op) of
135 let result_amode = CReg (dataReturnConvPrim kind) in
137 (COpStmt [result_amode] op arg_amodes [{-no vol_regs-}])
138 (mkPrimReturnCode (text "primapp)" <+> ppr x))
140 -- otherwise, must be returning an enumerated type (eg. Bool).
141 -- we've only got the tag in R2, so we have to load the constructor
145 | isUnboxedTupleTyCon tycon -> primRetUnboxedTuple op args res_ty
148 | isEnumerationTyCon tycon ->
150 (COpStmt [dyn_tag] op arg_amodes [{-no vol_regs-}])
152 absC (CAssign (CReg node) closure_lbl) `thenC`
153 mkDynamicAlgReturnCode tycon dyn_tag sequel)
156 -- Pull a unique out of thin air to put the tag in.
157 -- It shouldn't matter if this overlaps with anything - we're
158 -- about to return anyway.
159 dyn_tag = CTemp (mkBuiltinUnique 0) IntRep
161 closure_lbl = CTableEntry
162 (CLbl (mkClosureTblLabel tycon) PtrRep)
167 %********************************************************
169 %* Case expressions *
171 %********************************************************
172 Case-expression conversion is complicated enough to have its own
176 cgExpr (StgCase expr live_vars save_vars bndr srt alts)
177 = cgCase expr live_vars save_vars bndr srt alts
181 %********************************************************
185 %********************************************************
186 \subsection[let-and-letrec-codegen]{Converting @StgLet@ and @StgLetrec@}
189 cgExpr (StgLet (StgNonRec name rhs) expr)
190 = cgRhs name rhs `thenFC` \ (name, info) ->
191 addBindC name info `thenC`
194 cgExpr (StgLet (StgRec pairs) expr)
195 = fixC (\ new_bindings -> addBindsC new_bindings `thenC`
196 listFCs [ cgRhs b e | (b,e) <- pairs ]
197 ) `thenFC` \ new_bindings ->
199 addBindsC new_bindings `thenC`
204 cgExpr (StgLetNoEscape live_in_whole_let live_in_rhss bindings body)
205 = -- Figure out what volatile variables to save
206 nukeDeadBindings live_in_whole_let `thenC`
207 saveVolatileVarsAndRegs live_in_rhss
208 `thenFC` \ (save_assts, rhs_eob_info, maybe_cc_slot) ->
209 -- ToDo: cost centre???
210 restoreCurrentCostCentre maybe_cc_slot `thenFC` \ restore_cc ->
212 -- Save those variables right now!
213 absC save_assts `thenC`
215 -- Produce code for the rhss
216 -- and add suitable bindings to the environment
217 cgLetNoEscapeBindings live_in_rhss rhs_eob_info maybe_cc_slot bindings `thenC`
220 setEndOfBlockInfo rhs_eob_info (cgExpr body)
224 %********************************************************
228 %********************************************************
230 SCC expressions are treated specially. They set the current cost
233 cgExpr (StgSCC cc expr)
234 = ASSERT(sccAbleCostCentre cc)
236 (if isDictCC cc then SLIT("SET_DICT_CCC") else SLIT("SET_CCC"))
237 [mkCCostCentre cc, mkIntCLit (if isSccCountCostCentre cc then 1 else 0)]
242 ToDo: counting of dict sccs ...
244 %********************************************************
246 %* Non-top-level bindings *
248 %********************************************************
249 \subsection[non-top-level-bindings]{Converting non-top-level bindings}
251 We rely on the support code in @CgCon@ (to do constructors) and
252 in @CgClosure@ (to do closures).
255 cgRhs :: Id -> StgRhs -> FCode (Id, CgIdInfo)
256 -- the Id is passed along so a binding can be set up
258 cgRhs name (StgRhsCon maybe_cc con args)
259 = getArgAmodes args `thenFC` \ amodes ->
260 buildDynCon name maybe_cc con amodes (all zero_size args)
262 returnFC (name, idinfo)
264 zero_size atom = getPrimRepSize (getArgPrimRep atom) == 0
266 cgRhs name (StgRhsClosure cc bi srt@(NoSRT) fvs upd_flag args body)
267 = mkRhsClosure name cc bi srt fvs upd_flag args body
268 cgRhs name (StgRhsClosure cc bi srt@(SRT _ _) fvs upd_flag args body)
269 = mkRhsClosure name cc bi srt fvs upd_flag args body
272 mkRhsClosure looks for two special forms of the right-hand side:
276 If neither happens, it just calls mkClosureLFInfo. You might think
277 that mkClosureLFInfo should do all this, but it seems wrong for the
278 latter to look at the structure of an expression
282 We look at the body of the closure to see if it's a selector---turgid,
283 but nothing deep. We are looking for a closure of {\em exactly} the
286 ... = [the_fv] \ u [] ->
288 con a_1 ... a_n -> a_i
292 mkRhsClosure bndr cc bi srt
293 [the_fv] -- Just one free var
294 upd_flag -- Updatable thunk
296 body@(StgCase (StgApp scrutinee [{-no args-}])
297 _ _ _ _ -- ignore uniq, etc.
299 [(con, params, use_mask,
300 (StgApp selectee [{-no args-}]))]
302 | the_fv == scrutinee -- Scrutinee is the only free variable
303 && maybeToBool maybe_offset -- Selectee is a component of the tuple
304 && offset_into_int <= mAX_SPEC_SELECTEE_SIZE -- Offset is small enough
305 = ASSERT(is_single_constructor)
306 cgStdRhsClosure bndr cc bi [the_fv] [] body lf_info [StgVarArg the_fv]
308 lf_info = mkSelectorLFInfo (idType bndr) offset_into_int
309 (isUpdatable upd_flag)
310 (_, params_w_offsets) = layOutDynCon con idPrimRep params
311 maybe_offset = assocMaybe params_w_offsets selectee
312 Just the_offset = maybe_offset
313 offset_into_int = the_offset - fixedHdrSize
314 is_single_constructor = maybeToBool (maybeTyConSingleCon tycon)
315 tycon = dataConTyCon con
322 A more generic AP thunk of the form
324 x = [ x_1...x_n ] \.. [] -> x_1 ... x_n
326 A set of these is compiled statically into the RTS, so we just use
327 those. We could extend the idea to thunks where some of the x_i are
328 global ids (and hence not free variables), but this would entail
329 generating a larger thunk. It might be an option for non-optimising
332 We only generate an Ap thunk if all the free variables are pointers,
333 for semi-obvious reasons.
336 mkRhsClosure bndr cc bi srt
339 [] -- No args; a thunk
340 body@(StgApp fun_id args)
342 | length args + 1 == arity
343 && all isFollowableRep (map idPrimRep fvs)
344 && isUpdatable upd_flag
345 && arity <= mAX_SPEC_AP_SIZE
348 = cgStdRhsClosure bndr cc bi fvs [] body lf_info payload
351 lf_info = mkApLFInfo (idType bndr) upd_flag arity
352 -- the payload has to be in the correct order, hence we can't
354 payload = StgVarArg fun_id : args
361 mkRhsClosure bndr cc bi srt fvs upd_flag args body
362 = getSRTLabel `thenFC` \ srt_label ->
364 mkClosureLFInfo bndr NotTopLevel fvs upd_flag args srt_label srt
366 cgRhsClosure bndr cc bi fvs args body lf_info
370 %********************************************************
372 %* Let-no-escape bindings
374 %********************************************************
376 cgLetNoEscapeBindings live_in_rhss rhs_eob_info maybe_cc_slot (StgNonRec binder rhs)
377 = cgLetNoEscapeRhs live_in_rhss rhs_eob_info maybe_cc_slot
378 NonRecursive binder rhs
379 `thenFC` \ (binder, info) ->
382 cgLetNoEscapeBindings live_in_rhss rhs_eob_info maybe_cc_slot (StgRec pairs)
383 = fixC (\ new_bindings ->
384 addBindsC new_bindings `thenC`
385 listFCs [ cgLetNoEscapeRhs full_live_in_rhss
386 rhs_eob_info maybe_cc_slot Recursive b e
388 ) `thenFC` \ new_bindings ->
390 addBindsC new_bindings
392 -- We add the binders to the live-in-rhss set so that we don't
393 -- delete the bindings for the binder from the environment!
394 full_live_in_rhss = live_in_rhss `unionVarSet` (mkVarSet [b | (b,r) <- pairs])
397 :: StgLiveVars -- Live in rhss
399 -> Maybe VirtualSpOffset
403 -> FCode (Id, CgIdInfo)
405 cgLetNoEscapeRhs full_live_in_rhss rhs_eob_info maybe_cc_slot rec binder
406 (StgRhsClosure cc bi srt _ upd_flag args body)
407 = -- We could check the update flag, but currently we don't switch it off
408 -- for let-no-escaped things, so we omit the check too!
410 -- Updatable -> panic "cgLetNoEscapeRhs" -- Nothing to update!
411 -- other -> cgLetNoEscapeClosure binder cc bi live_in_whole_let live_in_rhss args body
412 cgLetNoEscapeClosure binder cc bi srt full_live_in_rhss rhs_eob_info maybe_cc_slot rec args body
414 -- For a constructor RHS we want to generate a single chunk of code which
415 -- can be jumped to from many places, which will return the constructor.
416 -- It's easy; just behave as if it was an StgRhsClosure with a ConApp inside!
417 cgLetNoEscapeRhs full_live_in_rhss rhs_eob_info maybe_cc_slot rec binder
418 (StgRhsCon cc con args)
419 = cgLetNoEscapeClosure binder cc stgArgOcc{-safe-} NoSRT full_live_in_rhss rhs_eob_info maybe_cc_slot rec
420 [] --No args; the binder is data structure, not a function
421 (StgCon (DataCon con) args (idType binder))
424 Little helper for primitives that return unboxed tuples.
428 primRetUnboxedTuple :: PrimOp -> [StgArg] -> Type -> Code
429 primRetUnboxedTuple op args res_ty
430 = getArgAmodes args `thenFC` \ arg_amodes ->
432 put all the arguments in temporaries so they don't get stomped when
433 we push the return address.
437 arg_uniqs = map mkBuiltinUnique [0 .. n_args-1]
438 arg_reps = map getArgPrimRep args
439 arg_temps = zipWith CTemp arg_uniqs arg_reps
441 absC (mkAbstractCs (zipWith CAssign arg_temps arg_amodes)) `thenC`
443 allocate some temporaries for the return values.
446 (tc,ty_args) = case splitTyConAppThroughNewTypes res_ty of
447 Nothing -> pprPanic "primRetUnboxedTuple" (ppr res_ty)
449 prim_reps = map typePrimRep ty_args
450 temp_uniqs = map mkBuiltinUnique [ n_args .. n_args + length ty_args - 1]
451 temp_amodes = zipWith CTemp temp_uniqs prim_reps
453 returnUnboxedTuple temp_amodes (absC (COpStmt temp_amodes op arg_temps []))