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
22 import AbsCUtils ( mkAbsCStmts, mkAbstractCs )
23 import CgBindery ( getArgAmodes )
24 import CgCase ( cgCase, saveVolatileVarsAndRegs )
25 import CgClosure ( cgRhsClosure )
26 import CgCon ( buildDynCon, cgReturnDataCon )
27 import CgHeapery ( allocHeap )
28 import CgLetNoEscape ( cgLetNoEscapeClosure )
29 import CgRetConv ( dataReturnConvAlg, ctrlReturnConvAlg,
30 DataReturnConvention(..), CtrlReturnConvention(..),
31 assignPrimOpResultRegs, makePrimOpArgsRobust
33 import CgTailCall ( cgTailCall, performReturn,
34 mkDynamicAlgReturnCode, mkPrimReturnCode
36 import CLabel ( mkPhantomInfoTableLabel, mkInfoTableVecTblLabel )
37 import ClosureInfo ( mkClosureLFInfo )
38 import CostCentre ( sccAbleCostCentre, isDictCC, isSccCountCostCentre )
39 import HeapOffs ( SYN_IE(VirtualSpBOffset) )
40 import Id ( mkIdSet, unionIdSets, GenId{-instance Outputable-} )
41 import PprStyle ( PprStyle(..) )
42 import PrimOp ( primOpCanTriggerGC, primOpHeapReq, HeapRequirement(..),
43 getPrimOpResultInfo, PrimOp(..), PrimOpResultInfo(..)
45 import PrimRep ( getPrimRepSize, PrimRep(..) )
46 import TyCon ( tyConDataCons )
47 import Util ( panic, pprPanic, assertPanic )
50 This module provides the support code for @StgToAbstractC@ to deal
51 with STG {\em expressions}. See also @CgClosure@, which deals
52 with closures, and @CgCon@, which deals with constructors.
55 cgExpr :: StgExpr -- input
59 %********************************************************
63 %********************************************************
65 ``Applications'' mean {\em tail calls}, a service provided by module
66 @CgTailCall@. This includes literals, which show up as
67 @(STGApp (StgLitArg 42) [])@.
70 cgExpr (StgApp fun args live_vars) = cgTailCall fun args live_vars
73 %********************************************************
75 %* STG ConApps (for inline versions) *
77 %********************************************************
80 cgExpr (StgCon con args live_vars)
81 = getArgAmodes args `thenFC` \ amodes ->
82 cgReturnDataCon con amodes (all zero_size args) live_vars
84 zero_size atom = getPrimRepSize (getArgPrimRep atom) == 0
87 %********************************************************
89 %* STG PrimApps (unboxed primitive ops) *
91 %********************************************************
93 Here is where we insert real live machine instructions.
96 cgExpr x@(StgPrim op args live_vars)
97 = ASSERT(op /= SeqOp) -- can't handle SeqOp
98 getPrimOpArgAmodes op args `thenFC` \ arg_amodes ->
100 result_regs = assignPrimOpResultRegs op
101 result_amodes = map CReg result_regs
102 may_gc = primOpCanTriggerGC op
103 dyn_tag = head result_amodes
104 -- The tag from a primitive op returning an algebraic data type
105 -- is returned in the first result_reg_amode
108 -- Use registers for args, and assign args to the regs
109 -- (Can-trigger-gc primops guarantee to have their args in regs)
111 (arg_robust_amodes, liveness_mask, arg_assts)
112 = makePrimOpArgsRobust op arg_amodes
114 liveness_arg = mkIntCLit liveness_mask
118 COpStmt result_amodes op
119 (pin_liveness op liveness_arg arg_robust_amodes)
124 -- Use args from their current amodes.
126 liveness_mask = panic "cgExpr: liveness of non-GC-ing primop touched\n"
129 COpStmt result_amodes op arg_amodes liveness_mask [{-no vol_regs-}],
132 ) `thenFC` \ (do_before_stack_cleanup,
133 do_just_before_jump) ->
135 case (getPrimOpResultInfo op) of
138 performReturn do_before_stack_cleanup
139 (\ sequel -> robustifySequel may_gc sequel
140 `thenFC` \ (ret_asst, sequel') ->
141 absC (ret_asst `mkAbsCStmts` do_just_before_jump)
143 mkPrimReturnCode sequel')
147 profCtrC SLIT("RET_NEW_IN_REGS") [num_of_fields] `thenC`
149 performReturn do_before_stack_cleanup
150 (\ sequel -> robustifySequel may_gc sequel
151 `thenFC` \ (ret_asst, sequel') ->
152 absC (mkAbstractCs [ret_asst,
155 -- Must load info ptr here, not in do_just_before_stack_cleanup,
156 -- because the info-ptr reg clashes with argument registers
159 mkDynamicAlgReturnCode tycon dyn_tag sequel')
163 -- Here, the destination _can_ be an update frame, so we need to make sure that
164 -- infoptr (R2) is loaded with the constructor's info ptr.
166 info_ptr_assign = CAssign (CReg infoptr) info_lbl
169 = case (ctrlReturnConvAlg tycon) of
170 VectoredReturn _ -> vec_lbl
171 UnvectoredReturn _ -> dir_lbl
173 vec_lbl = CTableEntry (CLbl (mkInfoTableVecTblLabel tycon) DataPtrRep)
176 data_con = head (tyConDataCons tycon)
178 (dir_lbl, num_of_fields)
179 = case (dataReturnConvAlg data_con) of
181 -> (CLbl (mkPhantomInfoTableLabel data_con) DataPtrRep,
182 mkIntCLit (length rs)) -- for ticky-ticky only
185 -> pprPanic "CgExpr: can't return prim in heap:" (ppr PprDebug data_con)
186 -- Never used, and no point in generating
189 -- for all PrimOps except ccalls, we pin the liveness info
190 -- on as the first "argument"
191 -- ToDo: un-duplicate?
193 pin_liveness (CCallOp _ _ _ _ _) _ args = args
194 pin_liveness other_op liveness_arg args
197 -- We only need to worry about the sequel when we may GC and the
198 -- sequel is OnStack. If that's the case, arrange to pull the
199 -- sequel out into RetReg before performing the primOp.
201 robustifySequel True sequel@(OnStack _) =
202 sequelToAmode sequel `thenFC` \ amode ->
203 returnFC (CAssign (CReg RetReg) amode, InRetReg)
204 robustifySequel _ sequel = returnFC (AbsCNop, sequel)
207 %********************************************************
209 %* Case expressions *
211 %********************************************************
212 Case-expression conversion is complicated enough to have its own
216 cgExpr (StgCase expr live_vars save_vars uniq alts)
217 = cgCase expr live_vars save_vars uniq alts
221 %********************************************************
225 %********************************************************
226 \subsection[let-and-letrec-codegen]{Converting @StgLet@ and @StgLetrec@}
229 cgExpr (StgLet (StgNonRec name rhs) expr)
230 = cgRhs name rhs `thenFC` \ (name, info) ->
231 addBindC name info `thenC`
234 cgExpr (StgLet (StgRec pairs) expr)
235 = fixC (\ new_bindings -> addBindsC new_bindings `thenC`
236 listFCs [ cgRhs b e | (b,e) <- pairs ]
237 ) `thenFC` \ new_bindings ->
239 addBindsC new_bindings `thenC`
244 cgExpr (StgLetNoEscape live_in_whole_let live_in_rhss bindings body)
245 = -- Figure out what volatile variables to save
246 nukeDeadBindings live_in_whole_let `thenC`
247 saveVolatileVarsAndRegs live_in_rhss
248 `thenFC` \ (save_assts, rhs_eob_info, maybe_cc_slot) ->
250 -- ToDo: cost centre???
252 -- Save those variables right now!
253 absC save_assts `thenC`
255 -- Produce code for the rhss
256 -- and add suitable bindings to the environment
257 cgLetNoEscapeBindings live_in_rhss rhs_eob_info maybe_cc_slot bindings `thenC`
260 setEndOfBlockInfo rhs_eob_info (cgExpr body)
264 %********************************************************
268 %********************************************************
269 \subsection[scc-codegen]{Converting StgSCC}
271 SCC expressions are treated specially. They set the current cost
274 cgExpr (StgSCC ty cc expr)
275 = ASSERT(sccAbleCostCentre cc)
277 (if isDictCC cc then SLIT("SET_DICT_CCC") else SLIT("SET_CCC"))
278 [mkCCostCentre cc, mkIntCLit (if isSccCountCostCentre cc then 1 else 0)]
283 ToDo: counting of dict sccs ...
285 %********************************************************
287 %* Non-top-level bindings *
289 %********************************************************
290 \subsection[non-top-level-bindings]{Converting non-top-level bindings}
292 @cgBinding@ is only used for let/letrec, not for unboxed bindings.
293 So the kind should always be @PtrRep@.
295 We rely on the support code in @CgCon@ (to do constructors) and
296 in @CgClosure@ (to do closures).
299 cgRhs :: Id -> StgRhs -> FCode (Id, CgIdInfo)
300 -- the Id is passed along so a binding can be set up
302 cgRhs name (StgRhsCon maybe_cc con args)
303 = getArgAmodes args `thenFC` \ amodes ->
304 buildDynCon name maybe_cc con amodes (all zero_size args)
306 returnFC (name, idinfo)
308 zero_size atom = getPrimRepSize (getArgPrimRep atom) == 0
310 cgRhs name (StgRhsClosure cc bi fvs upd_flag args body)
311 = cgRhsClosure name cc bi fvs args body lf_info
313 lf_info = mkClosureLFInfo False{-not top level-} fvs upd_flag args body
317 cgLetNoEscapeBindings live_in_rhss rhs_eob_info maybe_cc_slot (StgNonRec binder rhs)
318 = cgLetNoEscapeRhs live_in_rhss rhs_eob_info maybe_cc_slot binder rhs
319 `thenFC` \ (binder, info) ->
322 cgLetNoEscapeBindings live_in_rhss rhs_eob_info maybe_cc_slot (StgRec pairs)
323 = fixC (\ new_bindings ->
324 addBindsC new_bindings `thenC`
325 listFCs [ cgLetNoEscapeRhs full_live_in_rhss rhs_eob_info
326 maybe_cc_slot b e | (b,e) <- pairs ]
327 ) `thenFC` \ new_bindings ->
329 addBindsC new_bindings
331 -- We add the binders to the live-in-rhss set so that we don't
332 -- delete the bindings for the binder from the environment!
333 full_live_in_rhss = live_in_rhss `unionIdSets` (mkIdSet [b | (b,r) <- pairs])
336 :: StgLiveVars -- Live in rhss
338 -> Maybe VirtualSpBOffset
341 -> FCode (Id, CgIdInfo)
343 cgLetNoEscapeRhs full_live_in_rhss rhs_eob_info maybe_cc_slot binder
344 (StgRhsClosure cc bi _ upd_flag args body)
345 = -- We could check the update flag, but currently we don't switch it off
346 -- for let-no-escaped things, so we omit the check too!
348 -- Updatable -> panic "cgLetNoEscapeRhs" -- Nothing to update!
349 -- other -> cgLetNoEscapeClosure binder cc bi live_in_whole_let live_in_rhss args body
350 cgLetNoEscapeClosure binder cc bi full_live_in_rhss rhs_eob_info maybe_cc_slot args body
352 -- For a constructor RHS we want to generate a single chunk of code which
353 -- can be jumped to from many places, which will return the constructor.
354 -- It's easy; just behave as if it was an StgRhsClosure with a ConApp inside!
355 cgLetNoEscapeRhs full_live_in_rhss rhs_eob_info maybe_cc_slot binder
356 (StgRhsCon cc con args)
357 = cgLetNoEscapeClosure binder cc stgArgOcc{-safe-} full_live_in_rhss rhs_eob_info maybe_cc_slot
358 [] --No args; the binder is data structure, not a function
359 (StgCon con args full_live_in_rhss)
362 Some PrimOps require a {\em fixed} amount of heap allocation. Rather
363 than tidy away ready for GC and do a full heap check, we simply
364 allocate a completely uninitialised block in-line, just like any other
365 thunk/constructor allocation, and pass it to the PrimOp as its first
366 argument. Remember! The PrimOp is entirely responsible for
367 initialising the object. In particular, the PrimOp had better not
368 trigger GC before it has filled it in, and even then it had better
369 make sure that the GC can find the object somehow.
371 Main current use: allocating SynchVars.
374 getPrimOpArgAmodes op args
375 = getArgAmodes args `thenFC` \ arg_amodes ->
377 case primOpHeapReq op of
378 FixedHeapRequired size -> allocHeap size `thenFC` \ amode ->
379 returnFC (amode : arg_amodes)
381 _ -> returnFC arg_amodes