2 % (c) The GRASP Project, Glasgow University, 1992-1998
4 \section[CgCon]{Code generation for constructors}
6 This module provides the support code for @StgToAbstractC@ to deal
7 with {\em constructors} on the RHSs of let(rec)s. See also
8 @CgClosure@, which deals with closures.
12 cgTopRhsCon, buildDynCon,
13 bindConArgs, bindUnboxedTupleComponents,
17 #include "HsVersions.h"
23 import AbsCUtils ( getAmodeRep )
24 import CgBindery ( getArgAmodes, bindNewToNode,
25 bindArgsToRegs, newTempAmodeAndIdInfo,
26 idInfoToAmode, stableAmodeIdInfo,
27 heapIdInfo, CgIdInfo, bindNewToStack
29 import CgStackery ( mkTaggedVirtStkOffsets, freeStackSlots,
32 import CgUsages ( getRealSp, getVirtSp, setRealAndVirtualSp,
34 import CgClosure ( cgTopRhsClosure )
35 import CgRetConv ( assignRegs )
36 import Constants ( mAX_INTLIKE, mIN_INTLIKE, mIN_UPD_SIZE )
37 import CgHeapery ( allocDynClosure, inPlaceAllocDynClosure )
38 import CgTailCall ( performReturn, mkStaticAlgReturnCode, doTailCall,
39 mkUnboxedTupleReturnCode )
40 import CLabel ( mkClosureLabel, mkStaticClosureLabel )
41 import ClosureInfo ( mkClosureLFInfo, mkConLFInfo, mkLFArgument,
42 layOutDynCon, layOutDynClosure,
43 layOutStaticClosure, closureSize
45 import CostCentre ( currentOrSubsumedCCS, dontCareCCS, CostCentreStack,
47 import DataCon ( DataCon, dataConName, dataConTag, dataConTyCon,
49 import MkId ( mkDataConId )
50 import Id ( Id, idName, idType, idPrimRep )
51 import Name ( nameModule, isLocallyDefinedName )
52 import Module ( isDynamicModule )
53 import Const ( Con(..), Literal(..), isLitLitLit )
54 import PrelInfo ( maybeCharLikeCon, maybeIntLikeCon )
55 import PrimRep ( PrimRep(..), isFollowableRep )
56 import Unique ( Uniquable(..) )
58 import Panic ( assertPanic, trace )
61 %************************************************************************
63 \subsection[toplevel-constructors]{Top-level constructors}
65 %************************************************************************
68 cgTopRhsCon :: Id -- Name of thing bound to this RHS
71 -> Bool -- All zero-size args (see buildDynCon)
72 -> FCode (Id, CgIdInfo)
73 cgTopRhsCon id con args all_zero_size_args
74 = ASSERT(not (any_litlit_args || dynamic_con_or_args))
77 getArgAmodes args `thenFC` \ amodes ->
80 (closure_info, amodes_w_offsets)
81 = layOutStaticClosure name getAmodeRep amodes lf_info
86 closure_label -- Labelled with the name on lhs of defn
87 closure_info -- Closure is static
89 (map fst amodes_w_offsets)) -- Sorted into ptrs first, then nonptrs
94 returnFC (id, stableAmodeIdInfo id (CLbl closure_label PtrRep) lf_info)
96 con_tycon = dataConTyCon con
97 lf_info = mkConLFInfo con
98 closure_label = mkClosureLabel name
101 top_ccc = mkCCostCentreStack dontCareCCS -- because it's static data
103 -- stuff needed by the assert pred only.
104 any_litlit_args = any isLitLitArg args
105 dynamic_con_or_args = dynamic_con || any (isDynamic) args
107 dynamic_con = isDynName (dataConName con)
110 not (isLocallyDefinedName nm) &&
111 isDynamicModule (nameModule nm)
114 Do any of the arguments refer to something in a DLL?
116 isDynamic (StgVarArg v) = isDynName (idName v)
117 isDynamic (StgConArg c) =
119 DataCon dc -> isDynName (dataConName dc)
120 Literal l -> isLitLitLit l -- all bets are off if it is.
126 %************************************************************************
128 %* non-top-level constructors *
130 %************************************************************************
131 \subsection[code-for-constructors]{The code for constructors}
134 buildDynCon :: Id -- Name of the thing to which this constr will
136 -> CostCentreStack -- Where to grab cost centre from;
137 -- current CCS if currentOrSubsumedCCS
138 -> DataCon -- The data constructor
139 -> [CAddrMode] -- Its args
140 -> Bool -- True <=> all args (if any) are
141 -- of "zero size" (i.e., VoidRep);
142 -- The reason we don't just look at the
143 -- args is that we may be in a "knot", and
144 -- premature looking at the args will cause
145 -- the compiler to black-hole!
146 -> FCode CgIdInfo -- Return details about how to find it
149 First we deal with the case of zero-arity constructors. Now, they
150 will probably be unfolded, so we don't expect to see this case much,
151 if at all, but it does no harm, and sets the scene for characters.
153 In the case of zero-arity constructors, or, more accurately, those
154 which have exclusively size-zero (VoidRep) args, we generate no code
158 buildDynCon binder cc con args all_zero_size_args@True
159 = returnFC (stableAmodeIdInfo binder
160 (CLbl (mkStaticClosureLabel (dataConName con)) PtrRep)
164 Now for @Char@-like closures. We generate an assignment of the
165 address of the closure to a temporary. It would be possible simply to
166 generate no code, and record the addressing mode in the environment,
167 but we'd have to be careful if the argument wasn't a constant --- so
168 for simplicity we just always asssign to a temporary.
170 Last special case: @Int@-like closures. We only special-case the
171 situation in which the argument is a literal in the range
172 @mIN_INTLIKE@..@mAX_INTLILKE@. NB: for @Char@-like closures we can
173 work with any old argument, but for @Int@-like ones the argument has
174 to be a literal. Reason: @Char@ like closures have an argument type
175 which is guaranteed in range.
177 Because of this, we use can safely return an addressing mode.
180 buildDynCon binder cc con [arg_amode] all_zero_size_args@False
182 | maybeCharLikeCon con
183 = absC (CAssign temp_amode (CCharLike arg_amode)) `thenC`
184 returnFC temp_id_info
186 | maybeIntLikeCon con && in_range_int_lit arg_amode
187 = returnFC (stableAmodeIdInfo binder (CIntLike arg_amode) (mkConLFInfo con))
189 (temp_amode, temp_id_info) = newTempAmodeAndIdInfo binder (mkConLFInfo con)
191 in_range_int_lit (CLit (MachInt val _)) = val <= mAX_INTLIKE && val >= mIN_INTLIKE
192 in_range_int_lit other_amode = False
194 tycon = dataConTyCon con
197 Now the general case.
200 buildDynCon binder ccs con args all_zero_size_args@False
201 = allocDynClosure closure_info use_cc blame_cc amodes_w_offsets `thenFC` \ hp_off ->
202 returnFC (heapIdInfo binder hp_off lf_info)
204 (closure_info, amodes_w_offsets)
205 = layOutDynClosure (idName binder) getAmodeRep args lf_info
206 lf_info = mkConLFInfo con
208 use_cc -- cost-centre to stick in the object
209 = if currentOrSubsumedCCS ccs
210 then CReg CurCostCentre
211 else mkCCostCentreStack ccs
213 blame_cc = use_cc -- cost-centre on which to blame the alloc (same)
217 %************************************************************************
219 %* constructor-related utility function: *
220 %* bindConArgs is called from cgAlt of a case *
222 %************************************************************************
223 \subsection[constructor-utilities]{@bindConArgs@: constructor-related utility}
225 @bindConArgs@ $con args$ augments the environment with bindings for the
226 binders $args$, assuming that we have just returned from a @case@ which
231 :: DataCon -> [Id] -- Constructor and args
235 = ASSERT(not (isUnboxedTupleCon con))
236 mapCs bind_arg args_w_offsets
238 bind_arg (arg, offset) = bindNewToNode arg offset mkLFArgument
239 (_, args_w_offsets) = layOutDynCon con idPrimRep args
242 Unboxed tuples are handled slightly differently - the object is
243 returned in registers and on the stack instead of the heap.
246 bindUnboxedTupleComponents
248 -> FCode ([MagicId], -- regs assigned
249 [(VirtualSpOffset,Int)], -- tag slots
250 Bool) -- any components on stack?
252 bindUnboxedTupleComponents args
253 = -- Assign as many components as possible to registers
254 let (arg_regs, leftovers) = assignRegs [] (map idPrimRep args)
255 (reg_args, stk_args) = splitAt (length arg_regs) args
258 -- Allocate the rest on the stack (ToDo: separate out pointers)
259 getVirtSp `thenFC` \ vsp ->
260 getRealSp `thenFC` \ rsp ->
261 let (top_sp, stk_offsets, tags) =
262 mkTaggedVirtStkOffsets rsp idPrimRep stk_args
265 -- The stack pointer points to the last stack-allocated component
266 setRealAndVirtualSp top_sp `thenC`
268 -- need to explicitly free any empty slots we just jumped over
269 (if vsp < rsp then freeStackSlots [vsp+1 .. rsp] else nopC) `thenC`
271 bindArgsToRegs reg_args arg_regs `thenC`
272 mapCs bindNewToStack stk_offsets `thenC`
273 returnFC (arg_regs,tags, not (null stk_offsets))
276 %************************************************************************
278 \subsubsection[CgRetConv-cgReturnDataCon]{Actually generate code for a constructor return}
280 %************************************************************************
283 Note: it's the responsibility of the @cgReturnDataCon@ caller to be
284 sure the @amodes@ passed don't conflict with each other.
286 cgReturnDataCon :: DataCon -> [CAddrMode] -> Bool -> Code
288 cgReturnDataCon con amodes all_zero_size_args
289 = getEndOfBlockInfo `thenFC` \ (EndOfBlockInfo args_sp sequel) ->
293 CaseAlts _ (Just (alts, Just (Nothing, (_,deflt_lbl))))
294 | not (dataConTag con `is_elem` map fst alts)
296 -- Special case! We're returning a constructor to the default case
297 -- of an enclosing case. For example:
299 -- case (case e of (a,b) -> C a b) of
301 -- y -> ...<returning here!>...
304 -- if the default is a non-bind-default (ie does not use y),
305 -- then we should simply jump to the default join point;
307 performReturn AbsCNop {- No reg assts -} jump_to_join_point
309 is_elem = isIn "cgReturnDataCon"
310 jump_to_join_point sequel = absC (CJump (CLbl deflt_lbl CodePtrRep))
311 -- Ignore the sequel: we've already looked at it above
313 -- If the sequel is an update frame, we might be able to
314 -- do update in place...
316 | not all_zero_size_args -- no nullary constructors, please
317 && not (maybeCharLikeCon con) -- no chars please (these are all static)
318 && not (any isFollowableRep (map getAmodeRep amodes))
319 -- no ptrs please (generational gc...)
320 && closureSize closure_info <= mIN_UPD_SIZE
321 -- don't know the real size of the
322 -- thunk, so assume mIN_UPD_SIZE
324 -> -- get a new temporary and make it point to the updatee
327 temp = CTemp uniq PtrRep
329 getSpRelOffset args_sp `thenFC` \ sp_rel ->
331 (CMacroExpr PtrRep UPD_FRAME_UPDATEE [CAddr sp_rel]))
334 -- stomp all over it with the new constructor
335 inPlaceAllocDynClosure closure_info temp (CReg CurCostCentre) stuff
338 -- don't forget to update Su from the update frame
339 absC (CMacroStmt UPDATE_SU_FROM_UPD_FRAME [CAddr sp_rel]) `thenC`
341 -- set Node to point to the closure being returned
342 -- (can't be done earlier: node might conflict with amodes)
343 absC (CAssign (CReg node) temp) `thenC`
345 -- pop the update frame off the stack, and do the proper
347 let new_sp = args_sp - updateFrameSize in
348 setEndOfBlockInfo (EndOfBlockInfo new_sp (OnStack new_sp)) $
349 performReturn (AbsCNop) (mkStaticAlgReturnCode con)
351 where (closure_info, stuff)
352 = layOutDynClosure (dataConName con)
353 getAmodeRep amodes lf_info
355 lf_info = mkConLFInfo con
357 other_sequel -- The usual case
359 | isUnboxedTupleCon con ->
360 -- Return unboxed tuple in registers
361 let (ret_regs, leftovers) =
362 assignRegs [] (map getAmodeRep amodes)
364 profCtrC SLIT("TICK_RET_UNBOXED_TUP")
365 [mkIntCLit (length amodes)] `thenC`
367 doTailCall amodes ret_regs
368 mkUnboxedTupleReturnCode
369 (length leftovers) {- fast args arity -}
370 AbsCNop {-no pending assigments-}
371 Nothing {-not a let-no-escape-}
372 False {-node doesn't point-}
375 -- BUILD THE OBJECT IN THE HEAP
376 -- The first "con" says that the name bound to this
377 -- closure is "con", which is a bit of a fudge, but it only
380 -- This Id is also used to get a unique for a
381 -- temporary variable, if the closure is a CHARLIKE.
382 -- funilly enough, this makes the unique always come
384 buildDynCon (mkDataConId con) currentCCS
385 con amodes all_zero_size_args
387 idInfoToAmode PtrRep idinfo `thenFC` \ amode ->
391 profCtrC SLIT("TICK_RET_NEW") [mkIntCLit (length amodes)] `thenC`
392 -- could use doTailCall here.
393 performReturn (move_to_reg amode node)
394 (mkStaticAlgReturnCode con)
397 con_name = dataConName con
399 move_to_reg :: CAddrMode -> MagicId -> AbstractC
400 move_to_reg src_amode dest_reg = CAssign (CReg dest_reg) src_amode