2 % (c) The University of Glasgow 2006
3 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
7 module CgExpr ( cgExpr ) where
9 #include "HsVersions.h"
47 This module provides the support code for @StgToAbstractC@ to deal
48 with STG {\em expressions}. See also @CgClosure@, which deals
49 with closures, and @CgCon@, which deals with constructors.
52 cgExpr :: StgExpr -- input
56 %********************************************************
60 %********************************************************
62 ``Applications'' mean {\em tail calls}, a service provided by module
63 @CgTailCall@. This includes literals, which show up as
64 @(STGApp (StgLitArg 42) [])@.
67 cgExpr (StgApp fun args) = cgTailCall fun args
70 %********************************************************
72 %* STG ConApps (for inline versions) *
74 %********************************************************
77 cgExpr (StgConApp con args)
78 = do { amodes <- getArgAmodes args
79 ; cgReturnDataCon con amodes }
82 Literals are similar to constructors; they return by putting
83 themselves in an appropriate register and returning to the address on
88 = do { cmm_lit <- cgLit lit
89 ; performPrimReturn rep (CmmLit cmm_lit) }
91 rep = (typeCgRep) (literalType lit)
95 %********************************************************
97 %* PrimOps and foreign calls.
99 %********************************************************
101 NOTE about "safe" foreign calls: a safe foreign call is never compiled
102 inline in a case expression. When we see
104 case (ccall ...) of { ... }
106 We generate a proper return address for the alternatives and push the
107 stack frame before doing the call, so that in the event that the call
108 re-enters the RTS the stack is in a sane state.
111 cgExpr (StgOpApp (StgFCallOp fcall _) stg_args res_ty) = do
113 First, copy the args into temporaries. We're going to push
114 a return address right before doing the call, so the args
115 must be out of the way.
117 reps_n_amodes <- getArgAmodes stg_args
119 -- Get the *non-void* args, and jiggle them with shimForeignCall
120 arg_exprs = [ (shimForeignCallArg stg_arg expr, stg_arg)
121 | (stg_arg, (rep,expr)) <- stg_args `zip` reps_n_amodes,
124 arg_tmps <- sequence [ assignTemp arg
125 | (arg, _) <- arg_exprs]
126 let arg_hints = zipWith CmmHinted arg_tmps (map (typeForeignHint.stgArgType) stg_args)
128 Now, allocate some result regs.
130 (res_reps,res_regs,res_hints) <- newUnboxedTupleRegs res_ty
131 ccallReturnUnboxedTuple (zip res_reps (map (CmmReg . CmmLocal) res_regs)) $
132 emitForeignCall (zipWith CmmHinted res_regs res_hints) fcall
133 arg_hints emptyVarSet{-no live vars-}
135 -- tagToEnum# is special: we need to pull the constructor out of the table,
136 -- and perform an appropriate return.
138 cgExpr (StgOpApp (StgPrimOp TagToEnumOp) [arg] res_ty)
139 = ASSERT(isEnumerationTyCon tycon)
140 do { (_rep,amode) <- getArgAmode arg
141 ; amode' <- assignTemp amode -- We're going to use it twice,
142 -- so save in a temp if non-trivial
143 ; stmtC (CmmAssign nodeReg (tagToClosure tycon amode'))
144 ; performReturn emitReturnInstr }
146 -- If you're reading this code in the attempt to figure
147 -- out why the compiler panic'ed here, it is probably because
148 -- you used tagToEnum# in a non-monomorphic setting, e.g.,
149 -- intToTg :: Enum a => Int -> a ; intToTg (I# x#) = tagToEnum# x#
151 tycon = tyConAppTyCon res_ty
154 cgExpr (StgOpApp (StgPrimOp primop) args res_ty)
155 | primOpOutOfLine primop
156 = tailCallPrimOp primop args
158 | ReturnsPrim VoidRep <- result_info
159 = do cgPrimOp [] primop args emptyVarSet
160 performReturn emitReturnInstr
162 | ReturnsPrim rep <- result_info
163 = do res <- newTemp (typeCmmType res_ty)
164 cgPrimOp [res] primop args emptyVarSet
165 performPrimReturn (primRepToCgRep rep) (CmmReg (CmmLocal res))
167 | ReturnsAlg tycon <- result_info, isUnboxedTupleTyCon tycon
168 = do (reps, regs, _hints) <- newUnboxedTupleRegs res_ty
169 cgPrimOp regs primop args emptyVarSet{-no live vars-}
170 returnUnboxedTuple (zip reps (map (CmmReg . CmmLocal) regs))
172 | ReturnsAlg tycon <- result_info, isEnumerationTyCon tycon
173 -- c.f. cgExpr (...TagToEnumOp...)
174 = do tag_reg <- newTemp bWord -- The tag is a word
175 cgPrimOp [tag_reg] primop args emptyVarSet
176 stmtC (CmmAssign nodeReg
178 (CmmReg (CmmLocal tag_reg))))
179 performReturn emitReturnInstr
181 result_info = getPrimOpResultInfo primop
183 cgExpr (StgOpApp (StgPrimCallOp primcall) args _res_ty)
184 = tailCallPrimCall primcall args
187 %********************************************************
189 %* Case expressions *
191 %********************************************************
192 Case-expression conversion is complicated enough to have its own
196 cgExpr (StgCase expr live_vars save_vars bndr srt alt_type alts)
197 = setSRT srt $ cgCase expr live_vars save_vars bndr alt_type alts
201 %********************************************************
205 %********************************************************
206 \subsection[let-and-letrec-codegen]{Converting @StgLet@ and @StgLetrec@}
209 cgExpr (StgLet (StgNonRec name rhs) expr)
210 = cgRhs name rhs `thenFC` \ (name, info) ->
211 addBindC name info `thenC`
214 cgExpr (StgLet (StgRec pairs) expr)
215 = fixC (\ new_bindings -> addBindsC new_bindings `thenC`
216 listFCs [ cgRhs b e | (b,e) <- pairs ]
217 ) `thenFC` \ new_bindings ->
219 addBindsC new_bindings `thenC`
224 cgExpr (StgLetNoEscape live_in_whole_let live_in_rhss bindings body)
225 = do { -- Figure out what volatile variables to save
226 ; nukeDeadBindings live_in_whole_let
227 ; (save_assts, rhs_eob_info, maybe_cc_slot)
228 <- saveVolatileVarsAndRegs live_in_rhss
230 -- Save those variables right now!
231 ; emitStmts save_assts
233 -- Produce code for the rhss
234 -- and add suitable bindings to the environment
235 ; cgLetNoEscapeBindings live_in_rhss rhs_eob_info
236 maybe_cc_slot bindings
239 ; setEndOfBlockInfo rhs_eob_info (cgExpr body) }
243 %********************************************************
247 %********************************************************
249 SCC expressions are treated specially. They set the current cost
253 cgExpr (StgSCC cc expr) = do emitSetCCC cc; cgExpr expr
256 %********************************************************
260 %********************************************************
263 cgExpr (StgTick m n expr) = do cgTickBox m n; cgExpr expr
266 %********************************************************
270 %********************************************************
273 cgExpr _ = panic "cgExpr"
276 %********************************************************
278 %* Non-top-level bindings *
280 %********************************************************
281 \subsection[non-top-level-bindings]{Converting non-top-level bindings}
283 We rely on the support code in @CgCon@ (to do constructors) and
284 in @CgClosure@ (to do closures).
287 cgRhs :: Id -> StgRhs -> FCode (Id, CgIdInfo)
288 -- the Id is passed along so a binding can be set up
290 cgRhs name (StgRhsCon maybe_cc con args)
291 = do { amodes <- getArgAmodes args
292 ; idinfo <- buildDynCon name maybe_cc con amodes
293 ; returnFC (name, idinfo) }
295 cgRhs name (StgRhsClosure cc bi fvs upd_flag srt args body)
296 = setSRT srt $ mkRhsClosure name cc bi fvs upd_flag args body
299 mkRhsClosure looks for two special forms of the right-hand side:
303 If neither happens, it just calls mkClosureLFInfo. You might think
304 that mkClosureLFInfo should do all this, but it seems wrong for the
305 latter to look at the structure of an expression
309 We look at the body of the closure to see if it's a selector---turgid,
310 but nothing deep. We are looking for a closure of {\em exactly} the
313 ... = [the_fv] \ u [] ->
315 con a_1 ... a_n -> a_i
319 mkRhsClosure :: Id -> CostCentreStack -> StgBinderInfo
320 -> [Id] -> UpdateFlag -> [Id] -> GenStgExpr Id Id
321 -> FCode (Id, CgIdInfo)
322 mkRhsClosure bndr cc bi
323 [the_fv] -- Just one free var
324 upd_flag -- Updatable thunk
326 body@(StgCase (StgApp scrutinee [{-no args-}])
327 _ _ _ srt -- ignore uniq, etc.
329 [(DataAlt con, params, _use_mask,
330 (StgApp selectee [{-no args-}]))])
331 | the_fv == scrutinee -- Scrutinee is the only free variable
332 && maybeToBool maybe_offset -- Selectee is a component of the tuple
333 && offset_into_int <= mAX_SPEC_SELECTEE_SIZE -- Offset is small enough
334 = -- NOT TRUE: ASSERT(is_single_constructor)
335 -- The simplifier may have statically determined that the single alternative
336 -- is the only possible case and eliminated the others, even if there are
337 -- other constructors in the datatype. It's still ok to make a selector
338 -- thunk in this case, because we *know* which constructor the scrutinee
340 setSRT srt $ cgStdRhsClosure bndr cc bi [the_fv] [] body lf_info [StgVarArg the_fv]
342 lf_info = mkSelectorLFInfo bndr offset_into_int
343 (isUpdatable upd_flag)
344 (_, params_w_offsets) = layOutDynConstr con (addIdReps params)
345 -- Just want the layout
346 maybe_offset = assocMaybe params_w_offsets selectee
347 Just the_offset = maybe_offset
348 offset_into_int = the_offset - fixedHdrSize
354 A more generic AP thunk of the form
356 x = [ x_1...x_n ] \.. [] -> x_1 ... x_n
358 A set of these is compiled statically into the RTS, so we just use
359 those. We could extend the idea to thunks where some of the x_i are
360 global ids (and hence not free variables), but this would entail
361 generating a larger thunk. It might be an option for non-optimising
364 We only generate an Ap thunk if all the free variables are pointers,
365 for semi-obvious reasons.
368 mkRhsClosure bndr cc bi
371 [] -- No args; a thunk
372 body@(StgApp fun_id args)
374 | args `lengthIs` (arity-1)
375 && all isFollowableArg (map idCgRep fvs)
376 && isUpdatable upd_flag
377 && arity <= mAX_SPEC_AP_SIZE
380 = cgStdRhsClosure bndr cc bi fvs [] body lf_info payload
383 lf_info = mkApLFInfo bndr upd_flag arity
384 -- the payload has to be in the correct order, hence we can't
386 payload = StgVarArg fun_id : args
393 mkRhsClosure bndr cc bi fvs upd_flag args body
394 = cgRhsClosure bndr cc bi fvs upd_flag args body
398 %********************************************************
400 %* Let-no-escape bindings
402 %********************************************************
404 cgLetNoEscapeBindings :: StgLiveVars -> EndOfBlockInfo
405 -> Maybe VirtualSpOffset -> GenStgBinding Id Id
407 cgLetNoEscapeBindings live_in_rhss rhs_eob_info maybe_cc_slot
408 (StgNonRec binder rhs)
409 = do { (binder,info) <- cgLetNoEscapeRhs live_in_rhss rhs_eob_info
411 NonRecursive binder rhs
412 ; addBindC binder info }
414 cgLetNoEscapeBindings live_in_rhss rhs_eob_info maybe_cc_slot (StgRec pairs)
415 = do { new_bindings <- fixC (\ new_bindings -> do
416 { addBindsC new_bindings
417 ; listFCs [ cgLetNoEscapeRhs full_live_in_rhss
418 rhs_eob_info maybe_cc_slot Recursive b e
419 | (b,e) <- pairs ] })
421 ; addBindsC new_bindings }
423 -- We add the binders to the live-in-rhss set so that we don't
424 -- delete the bindings for the binder from the environment!
425 full_live_in_rhss = live_in_rhss `unionVarSet` (mkVarSet [b | (b,_) <- pairs])
428 :: StgLiveVars -- Live in rhss
430 -> Maybe VirtualSpOffset
434 -> FCode (Id, CgIdInfo)
436 cgLetNoEscapeRhs full_live_in_rhss rhs_eob_info maybe_cc_slot rec binder
437 (StgRhsClosure cc bi _ _upd_flag srt args body)
438 = -- We could check the update flag, but currently we don't switch it off
439 -- for let-no-escaped things, so we omit the check too!
441 -- Updatable -> panic "cgLetNoEscapeRhs" -- Nothing to update!
442 -- other -> cgLetNoEscapeClosure binder cc bi live_in_whole_let live_in_rhss args body
443 setSRT srt $ cgLetNoEscapeClosure binder cc bi full_live_in_rhss rhs_eob_info
444 maybe_cc_slot rec args body
446 -- For a constructor RHS we want to generate a single chunk of code which
447 -- can be jumped to from many places, which will return the constructor.
448 -- It's easy; just behave as if it was an StgRhsClosure with a ConApp inside!
449 cgLetNoEscapeRhs full_live_in_rhss rhs_eob_info maybe_cc_slot rec binder
450 (StgRhsCon cc con args)
451 = setSRT NoSRT $ cgLetNoEscapeClosure binder cc noBinderInfo{-safe-}
452 full_live_in_rhss rhs_eob_info maybe_cc_slot rec
453 [] --No args; the binder is data structure, not a function
457 Little helper for primitives that return unboxed tuples.
460 newUnboxedTupleRegs :: Type -> FCode ([CgRep], [LocalReg], [ForeignHint])
461 newUnboxedTupleRegs res_ty =
463 ty_args = tyConAppArgs (repType res_ty)
464 (reps,hints) = unzip [ (rep, typeForeignHint ty) | ty <- ty_args,
465 let rep = typeCgRep ty,
467 make_new_temp rep = newTemp (argMachRep rep)
469 regs <- mapM make_new_temp reps
470 return (reps,regs,hints)