2 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
4 % $Id: CgExpr.lhs,v 1.46 2001/10/25 02:13:11 sof 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, getArgAmode, CgIdInfo,
26 nukeDeadBindings, addBindC, addBindsC )
27 import CgCase ( cgCase, saveVolatileVarsAndRegs,
28 restoreCurrentCostCentre )
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, layOutDynConstr )
39 import CostCentre ( sccAbleCostCentre, isSccCountCostCentre )
40 import Id ( idPrimRep, idType, Id )
42 import PrimOp ( primOpOutOfLine, getPrimOpResultInfo, PrimOp(..), PrimOpResultInfo(..) )
43 import PrimRep ( PrimRep(..), isFollowableRep )
44 import TyCon ( maybeTyConSingleCon,
45 isUnboxedTupleTyCon, isEnumerationTyCon )
46 import Type ( Type, typePrimRep, tyConAppArgs, tyConAppTyCon, repType )
47 import Maybes ( maybeToBool )
48 import ListSetOps ( assocMaybe )
49 import Unique ( mkBuiltinUnique )
50 import BasicTypes ( TopLevelFlag(..), RecFlag(..) )
51 import Util ( lengthIs )
55 This module provides the support code for @StgToAbstractC@ to deal
56 with STG {\em expressions}. See also @CgClosure@, which deals
57 with closures, and @CgCon@, which deals with constructors.
60 cgExpr :: StgExpr -- input
64 %********************************************************
68 %********************************************************
70 ``Applications'' mean {\em tail calls}, a service provided by module
71 @CgTailCall@. This includes literals, which show up as
72 @(STGApp (StgLitArg 42) [])@.
75 cgExpr (StgApp fun args) = cgTailCall fun args
78 %********************************************************
80 %* STG ConApps (for inline versions) *
82 %********************************************************
85 cgExpr (StgConApp con args)
86 = getArgAmodes args `thenFC` \ amodes ->
87 cgReturnDataCon con amodes
90 Literals are similar to constructors; they return by putting
91 themselves in an appropriate register and returning to the address on
96 = performPrimReturn (text "literal" <+> ppr lit) (CLit lit)
100 %********************************************************
102 %* STG PrimApps (unboxed primitive ops) *
104 %********************************************************
106 Here is where we insert real live machine instructions.
108 NOTE about _ccall_GC_:
110 A _ccall_GC_ is treated as an out-of-line primop (returns True
111 for primOpOutOfLine) so that when we see the call in case context
112 case (ccall ...) of { ... }
113 we get a proper stack frame on the stack when we perform it. When we
114 get in a tail-call position, however, we need to actually perform the
115 call, so we treat it as an inline primop.
118 cgExpr (StgOpApp op@(StgFCallOp _ _) args res_ty)
119 = primRetUnboxedTuple op args res_ty
121 -- tagToEnum# is special: we need to pull the constructor out of the table,
122 -- and perform an appropriate return.
124 cgExpr (StgOpApp (StgPrimOp TagToEnumOp) [arg] res_ty)
125 = ASSERT(isEnumerationTyCon tycon)
126 getArgAmode arg `thenFC` \amode ->
127 -- save the tag in a temporary in case amode overlaps
129 absC (CAssign dyn_tag amode) `thenC`
133 (CLbl (mkClosureTblLabel tycon) PtrRep)
134 dyn_tag PtrRep) PtrRep))
135 (\ sequel -> mkDynamicAlgReturnCode tycon dyn_tag sequel)
137 dyn_tag = CTemp (mkBuiltinUnique 0) IntRep
139 -- if you're reading this code in the attempt to figure
140 -- out why the compiler panic'ed here, it is probably because
141 -- you used tagToEnum# in a non-monomorphic setting, e.g.,
142 -- intToTg :: Enum a => Int -> a ; intToTg (I# x#) = tagToEnum# x#
146 tycon = tyConAppTyCon res_ty
149 cgExpr x@(StgOpApp op@(StgPrimOp primop) args res_ty)
150 | primOpOutOfLine primop
151 = tailCallPrimOp primop args
154 = ASSERT(primop /= SeqOp) -- can't handle SeqOp
156 getArgAmodes args `thenFC` \ arg_amodes ->
158 case (getPrimOpResultInfo primop) of
161 let result_amode = CReg (dataReturnConvPrim kind) in
163 (COpStmt [result_amode] op arg_amodes [{-no vol_regs-}])
164 (mkPrimReturnCode (text "primapp)" <+> ppr x))
166 -- otherwise, must be returning an enumerated type (eg. Bool).
167 -- we've only got the tag in R2, so we have to load the constructor
171 | isUnboxedTupleTyCon tycon -> primRetUnboxedTuple op args res_ty
173 | isEnumerationTyCon tycon ->
175 (COpStmt [dyn_tag] op arg_amodes [{-no vol_regs-}])
177 absC (CAssign (CReg node) closure_lbl) `thenC`
178 mkDynamicAlgReturnCode tycon dyn_tag sequel)
181 -- Pull a unique out of thin air to put the tag in.
182 -- It shouldn't matter if this overlaps with anything - we're
183 -- about to return anyway.
184 dyn_tag = CTemp (mkBuiltinUnique 0) IntRep
186 closure_lbl = CVal (CIndex
187 (CLbl (mkClosureTblLabel tycon) PtrRep)
188 dyn_tag PtrRep) PtrRep
192 %********************************************************
194 %* Case expressions *
196 %********************************************************
197 Case-expression conversion is complicated enough to have its own
201 cgExpr (StgCase expr live_vars save_vars bndr srt alts)
202 = cgCase expr live_vars save_vars bndr srt alts
206 %********************************************************
210 %********************************************************
211 \subsection[let-and-letrec-codegen]{Converting @StgLet@ and @StgLetrec@}
214 cgExpr (StgLet (StgNonRec srt name rhs) expr)
215 = cgRhs srt name rhs `thenFC` \ (name, info) ->
216 addBindC name info `thenC`
219 cgExpr (StgLet (StgRec srt pairs) expr)
220 = fixC (\ new_bindings -> addBindsC new_bindings `thenC`
221 listFCs [ cgRhs srt b e | (b,e) <- pairs ]
222 ) `thenFC` \ new_bindings ->
224 addBindsC new_bindings `thenC`
229 cgExpr (StgLetNoEscape live_in_whole_let live_in_rhss bindings body)
230 = -- Figure out what volatile variables to save
231 nukeDeadBindings live_in_whole_let `thenC`
232 saveVolatileVarsAndRegs live_in_rhss
233 `thenFC` \ (save_assts, rhs_eob_info, maybe_cc_slot) ->
234 -- ToDo: cost centre???
235 restoreCurrentCostCentre maybe_cc_slot `thenFC` \ restore_cc ->
237 -- Save those variables right now!
238 absC save_assts `thenC`
240 -- Produce code for the rhss
241 -- and add suitable bindings to the environment
242 cgLetNoEscapeBindings live_in_rhss rhs_eob_info maybe_cc_slot bindings `thenC`
245 setEndOfBlockInfo rhs_eob_info (cgExpr body)
249 %********************************************************
253 %********************************************************
255 SCC expressions are treated specially. They set the current cost
258 cgExpr (StgSCC cc expr)
259 = ASSERT(sccAbleCostCentre cc)
262 [mkCCostCentre cc, mkIntCLit (if isSccCountCostCentre cc then 1 else 0)]
267 ToDo: counting of dict sccs ...
269 %********************************************************
271 %* Non-top-level bindings *
273 %********************************************************
274 \subsection[non-top-level-bindings]{Converting non-top-level bindings}
276 We rely on the support code in @CgCon@ (to do constructors) and
277 in @CgClosure@ (to do closures).
280 cgRhs :: SRT -> Id -> StgRhs -> FCode (Id, CgIdInfo)
281 -- the Id is passed along so a binding can be set up
283 cgRhs srt name (StgRhsCon maybe_cc con args)
284 = getArgAmodes args `thenFC` \ amodes ->
285 buildDynCon name maybe_cc con amodes `thenFC` \ idinfo ->
286 returnFC (name, idinfo)
288 cgRhs srt name (StgRhsClosure cc bi fvs upd_flag args body)
289 = mkRhsClosure name cc bi srt fvs upd_flag args body
292 mkRhsClosure looks for two special forms of the right-hand side:
296 If neither happens, it just calls mkClosureLFInfo. You might think
297 that mkClosureLFInfo should do all this, but it seems wrong for the
298 latter to look at the structure of an expression
302 We look at the body of the closure to see if it's a selector---turgid,
303 but nothing deep. We are looking for a closure of {\em exactly} the
306 ... = [the_fv] \ u [] ->
308 con a_1 ... a_n -> a_i
312 mkRhsClosure bndr cc bi srt
313 [the_fv] -- Just one free var
314 upd_flag -- Updatable thunk
316 body@(StgCase (StgApp scrutinee [{-no args-}])
317 _ _ _ _ -- ignore uniq, etc.
318 (StgAlgAlts (Just tycon)
319 [(con, params, use_mask,
320 (StgApp selectee [{-no args-}]))]
322 | the_fv == scrutinee -- Scrutinee is the only free variable
323 && maybeToBool maybe_offset -- Selectee is a component of the tuple
324 && offset_into_int <= mAX_SPEC_SELECTEE_SIZE -- Offset is small enough
325 = -- NOT TRUE: ASSERT(is_single_constructor)
326 -- The simplifier may have statically determined that the single alternative
327 -- is the only possible case and eliminated the others, even if there are
328 -- other constructors in the datatype. It's still ok to make a selector
329 -- thunk in this case, because we *know* which constructor the scrutinee
331 cgStdRhsClosure bndr cc bi [the_fv] [] body lf_info [StgVarArg the_fv]
333 lf_info = mkSelectorLFInfo (idType bndr) offset_into_int
334 (isUpdatable upd_flag)
335 (_, params_w_offsets) = layOutDynConstr bogus_name con idPrimRep params
336 -- Just want the layout
337 maybe_offset = assocMaybe params_w_offsets selectee
338 Just the_offset = maybe_offset
339 offset_into_int = the_offset - fixedHdrSize
340 bogus_name = panic "mkRhsClosure"
346 A more generic AP thunk of the form
348 x = [ x_1...x_n ] \.. [] -> x_1 ... x_n
350 A set of these is compiled statically into the RTS, so we just use
351 those. We could extend the idea to thunks where some of the x_i are
352 global ids (and hence not free variables), but this would entail
353 generating a larger thunk. It might be an option for non-optimising
356 We only generate an Ap thunk if all the free variables are pointers,
357 for semi-obvious reasons.
360 mkRhsClosure bndr cc bi srt
363 [] -- No args; a thunk
364 body@(StgApp fun_id args)
366 | args `lengthIs` (arity-1)
367 && all isFollowableRep (map idPrimRep fvs)
368 && isUpdatable upd_flag
369 && arity <= mAX_SPEC_AP_SIZE
372 = cgStdRhsClosure bndr cc bi fvs [] body lf_info payload
375 lf_info = mkApLFInfo (idType bndr) upd_flag arity
376 -- the payload has to be in the correct order, hence we can't
378 payload = StgVarArg fun_id : args
385 mkRhsClosure bndr cc bi srt fvs upd_flag args body
386 = cgRhsClosure bndr cc bi srt fvs args body lf_info
388 lf_info = mkClosureLFInfo bndr NotTopLevel fvs upd_flag args
392 %********************************************************
394 %* Let-no-escape bindings
396 %********************************************************
398 cgLetNoEscapeBindings live_in_rhss rhs_eob_info maybe_cc_slot
399 (StgNonRec srt binder rhs)
400 = cgLetNoEscapeRhs live_in_rhss rhs_eob_info maybe_cc_slot
401 NonRecursive srt binder rhs
402 `thenFC` \ (binder, info) ->
405 cgLetNoEscapeBindings live_in_rhss rhs_eob_info maybe_cc_slot
407 = fixC (\ new_bindings ->
408 addBindsC new_bindings `thenC`
409 listFCs [ cgLetNoEscapeRhs full_live_in_rhss
410 rhs_eob_info maybe_cc_slot Recursive srt b e
412 ) `thenFC` \ new_bindings ->
414 addBindsC new_bindings
416 -- We add the binders to the live-in-rhss set so that we don't
417 -- delete the bindings for the binder from the environment!
418 full_live_in_rhss = live_in_rhss `unionVarSet` (mkVarSet [b | (b,r) <- pairs])
421 :: StgLiveVars -- Live in rhss
423 -> Maybe VirtualSpOffset
428 -> FCode (Id, CgIdInfo)
430 cgLetNoEscapeRhs full_live_in_rhss rhs_eob_info maybe_cc_slot rec srt binder
431 (StgRhsClosure cc bi _ upd_flag args body)
432 = -- We could check the update flag, but currently we don't switch it off
433 -- for let-no-escaped things, so we omit the check too!
435 -- Updatable -> panic "cgLetNoEscapeRhs" -- Nothing to update!
436 -- other -> cgLetNoEscapeClosure binder cc bi live_in_whole_let live_in_rhss args body
437 cgLetNoEscapeClosure binder cc bi srt full_live_in_rhss rhs_eob_info
438 maybe_cc_slot rec args body
440 -- For a constructor RHS we want to generate a single chunk of code which
441 -- can be jumped to from many places, which will return the constructor.
442 -- It's easy; just behave as if it was an StgRhsClosure with a ConApp inside!
443 cgLetNoEscapeRhs full_live_in_rhss rhs_eob_info maybe_cc_slot rec srt binder
444 (StgRhsCon cc con args)
445 = cgLetNoEscapeClosure binder cc noBinderInfo{-safe-} srt
446 full_live_in_rhss rhs_eob_info maybe_cc_slot rec
447 [] --No args; the binder is data structure, not a function
451 Little helper for primitives that return unboxed tuples.
455 primRetUnboxedTuple :: StgOp -> [StgArg] -> Type -> Code
456 primRetUnboxedTuple op args res_ty
457 = getArgAmodes args `thenFC` \ arg_amodes ->
459 put all the arguments in temporaries so they don't get stomped when
460 we push the return address.
464 arg_uniqs = map mkBuiltinUnique [0 .. n_args-1]
465 arg_reps = map getArgPrimRep args
466 arg_temps = zipWith CTemp arg_uniqs arg_reps
468 absC (mkAbstractCs (zipWith CAssign arg_temps arg_amodes)) `thenC`
470 allocate some temporaries for the return values.
473 ty_args = tyConAppArgs (repType res_ty)
474 prim_reps = map typePrimRep ty_args
475 temp_uniqs = map mkBuiltinUnique [ n_args .. n_args + length ty_args - 1]
476 temp_amodes = zipWith CTemp temp_uniqs prim_reps
478 returnUnboxedTuple temp_amodes (absC (COpStmt temp_amodes op arg_temps []))