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,
26 idInfoToAmode, stableAmodeIdInfo,
27 heapIdInfo, CgIdInfo, bindNewToStack
29 import CgStackery ( mkTaggedVirtStkOffsets, freeStackSlots,
32 import CgUsages ( getRealSp, getVirtSp, setRealAndVirtualSp,
34 import CgRetConv ( assignRegs )
35 import Constants ( mAX_INTLIKE, mIN_INTLIKE, mAX_CHARLIKE, mIN_CHARLIKE,
37 import CgHeapery ( allocDynClosure, inPlaceAllocDynClosure )
38 import CgTailCall ( performReturn, mkStaticAlgReturnCode, doTailCall,
39 mkUnboxedTupleReturnCode )
40 import CLabel ( mkClosureLabel )
41 import ClosureInfo ( mkConLFInfo, mkLFArgument,
42 layOutDynCon, layOutDynClosure,
43 layOutStaticClosure, closureSize
45 import CostCentre ( currentOrSubsumedCCS, dontCareCCS, CostCentreStack,
47 import DataCon ( DataCon, dataConName, dataConTag,
48 isUnboxedTupleCon, isNullaryDataCon, dataConId,
49 dataConWrapId, dataConRepArity
51 import Id ( Id, idName, idPrimRep )
52 import Literal ( Literal(..) )
53 import PrelInfo ( maybeCharLikeCon, maybeIntLikeCon )
54 import PrimRep ( PrimRep(..), isFollowableRep )
55 import Unique ( Uniquable(..) )
60 %************************************************************************
62 \subsection[toplevel-constructors]{Top-level constructors}
64 %************************************************************************
67 cgTopRhsCon :: Id -- Name of thing bound to this RHS
70 -> FCode (Id, CgIdInfo)
71 cgTopRhsCon id con args
72 = ASSERT(not (isDllConApp con args)) -- checks for litlit args too
73 ASSERT(length args == dataConRepArity con)
76 closure_label = mkClosureLabel name
77 lf_info = mkConLFInfo con
82 getArgAmodes args `thenFC` \ amodes ->
85 (closure_info, amodes_w_offsets)
86 = layOutStaticClosure name getAmodeRep amodes lf_info
91 closure_label -- Labelled with the name on lhs of defn
92 closure_info -- Closure is static
93 (mkCCostCentreStack dontCareCCS) -- because it's static data
94 (map fst amodes_w_offsets)) -- Sorted into ptrs first, then nonptrs
99 returnFC (id, stableAmodeIdInfo id (CLbl closure_label PtrRep) lf_info)
102 %************************************************************************
104 %* non-top-level constructors *
106 %************************************************************************
107 \subsection[code-for-constructors]{The code for constructors}
110 buildDynCon :: Id -- Name of the thing to which this constr will
112 -> CostCentreStack -- Where to grab cost centre from;
113 -- current CCS if currentOrSubsumedCCS
114 -> DataCon -- The data constructor
115 -> [CAddrMode] -- Its args
116 -> FCode CgIdInfo -- Return details about how to find it
118 -- We used to pass a boolean indicating whether all the
119 -- args were of size zero, so we could use a static
120 -- construtor; but I concluded that it just isn't worth it.
121 -- Now I/O uses unboxed tuples there just aren't any constructors
122 -- with all size-zero args.
124 -- The reason for having a separate argument, rather than looking at
125 -- the addr modes of the args is that we may be in a "knot", and
126 -- premature looking at the args will cause the compiler to black-hole!
129 First we deal with the case of zero-arity constructors. Now, they
130 will probably be unfolded, so we don't expect to see this case much,
131 if at all, but it does no harm, and sets the scene for characters.
133 In the case of zero-arity constructors, or, more accurately, those
134 which have exclusively size-zero (VoidRep) args, we generate no code
138 buildDynCon binder cc con []
139 = returnFC (stableAmodeIdInfo binder
140 (CLbl (mkClosureLabel (idName (dataConWrapId con))) PtrRep)
144 The following three paragraphs about @Char@-like and @Int@-like
145 closures are obsolete, but I don't understand the details well enough
146 to properly word them, sorry. I've changed the treatment of @Char@s to
147 be analogous to @Int@s: only a subset is preallocated, because @Char@
148 has now 31 bits. Only literals are handled here. -- Qrczak
150 Now for @Char@-like closures. We generate an assignment of the
151 address of the closure to a temporary. It would be possible simply to
152 generate no code, and record the addressing mode in the environment,
153 but we'd have to be careful if the argument wasn't a constant --- so
154 for simplicity we just always asssign to a temporary.
156 Last special case: @Int@-like closures. We only special-case the
157 situation in which the argument is a literal in the range
158 @mIN_INTLIKE@..@mAX_INTLILKE@. NB: for @Char@-like closures we can
159 work with any old argument, but for @Int@-like ones the argument has
160 to be a literal. Reason: @Char@ like closures have an argument type
161 which is guaranteed in range.
163 Because of this, we use can safely return an addressing mode.
166 buildDynCon binder cc con [arg_amode]
167 | maybeIntLikeCon con && in_range_int_lit arg_amode
168 = returnFC (stableAmodeIdInfo binder (CIntLike arg_amode) (mkConLFInfo con))
170 in_range_int_lit (CLit (MachInt val)) = val <= mAX_INTLIKE && val >= mIN_INTLIKE
171 in_range_int_lit _other_amode = False
173 buildDynCon binder cc con [arg_amode]
174 | maybeCharLikeCon con && in_range_char_lit arg_amode
175 = returnFC (stableAmodeIdInfo binder (CCharLike arg_amode) (mkConLFInfo con))
177 in_range_char_lit (CLit (MachChar val)) = val <= mAX_CHARLIKE && val >= mIN_CHARLIKE
178 in_range_char_lit _other_amode = False
181 Now the general case.
184 buildDynCon binder ccs con args
185 = allocDynClosure closure_info use_cc blame_cc amodes_w_offsets `thenFC` \ hp_off ->
186 returnFC (heapIdInfo binder hp_off lf_info)
188 (closure_info, amodes_w_offsets)
189 = layOutDynClosure (idName binder) getAmodeRep args lf_info
190 lf_info = mkConLFInfo con
192 use_cc -- cost-centre to stick in the object
193 = if currentOrSubsumedCCS ccs
194 then CReg CurCostCentre
195 else mkCCostCentreStack ccs
197 blame_cc = use_cc -- cost-centre on which to blame the alloc (same)
201 %************************************************************************
203 %* constructor-related utility function: *
204 %* bindConArgs is called from cgAlt of a case *
206 %************************************************************************
207 \subsection[constructor-utilities]{@bindConArgs@: constructor-related utility}
209 @bindConArgs@ $con args$ augments the environment with bindings for the
210 binders $args$, assuming that we have just returned from a @case@ which
215 :: DataCon -> [Id] -- Constructor and args
219 = ASSERT(not (isUnboxedTupleCon con))
220 mapCs bind_arg args_w_offsets
222 bind_arg (arg, offset) = bindNewToNode arg offset mkLFArgument
223 (_, args_w_offsets) = layOutDynCon con idPrimRep args
226 Unboxed tuples are handled slightly differently - the object is
227 returned in registers and on the stack instead of the heap.
230 bindUnboxedTupleComponents
232 -> FCode ([MagicId], -- regs assigned
233 [(VirtualSpOffset,Int)], -- tag slots
234 Bool) -- any components on stack?
236 bindUnboxedTupleComponents args
237 = -- Assign as many components as possible to registers
238 let (arg_regs, leftovers) = assignRegs [] (map idPrimRep args)
239 (reg_args, stk_args) = splitAt (length arg_regs) args
242 -- Allocate the rest on the stack (ToDo: separate out pointers)
243 getVirtSp `thenFC` \ vsp ->
244 getRealSp `thenFC` \ rsp ->
245 let (top_sp, stk_offsets, tags) =
246 mkTaggedVirtStkOffsets rsp idPrimRep stk_args
249 -- The stack pointer points to the last stack-allocated component
250 setRealAndVirtualSp top_sp `thenC`
252 -- need to explicitly free any empty slots we just jumped over
253 (if vsp < rsp then freeStackSlots [vsp+1 .. rsp] else nopC) `thenC`
255 bindArgsToRegs reg_args arg_regs `thenC`
256 mapCs bindNewToStack stk_offsets `thenC`
257 returnFC (arg_regs,tags, not (null stk_offsets))
260 %************************************************************************
262 \subsubsection[CgRetConv-cgReturnDataCon]{Actually generate code for a constructor return}
264 %************************************************************************
267 Note: it's the responsibility of the @cgReturnDataCon@ caller to be
268 sure the @amodes@ passed don't conflict with each other.
270 cgReturnDataCon :: DataCon -> [CAddrMode] -> Code
272 cgReturnDataCon con amodes
273 = ASSERT(length amodes == dataConRepArity con)
274 getEndOfBlockInfo `thenFC` \ (EndOfBlockInfo args_sp sequel) ->
278 CaseAlts _ (Just (alts, Just (maybe_deflt, (_,deflt_lbl))))
279 | not (dataConTag con `is_elem` map fst alts)
281 -- Special case! We're returning a constructor to the default case
282 -- of an enclosing case. For example:
284 -- case (case e of (a,b) -> C a b) of
286 -- y -> ...<returning here!>...
289 -- if the default is a non-bind-default (ie does not use y),
290 -- then we should simply jump to the default join point;
293 Nothing -> performReturn AbsCNop {- No reg assts -} jump_to_join_point
294 Just _ -> build_it_then jump_to_join_point
296 is_elem = isIn "cgReturnDataCon"
297 jump_to_join_point sequel = absC (CJump (CLbl deflt_lbl CodePtrRep))
298 -- Ignore the sequel: we've already looked at it above
300 -- If the sequel is an update frame, we might be able to
301 -- do update in place...
303 | not (isNullaryDataCon con) -- no nullary constructors, please
304 && not (any isFollowableRep (map getAmodeRep amodes))
305 -- no ptrs please (generational gc...)
306 && closureSize closure_info <= mIN_UPD_SIZE
307 -- don't know the real size of the
308 -- thunk, so assume mIN_UPD_SIZE
310 -> -- get a new temporary and make it point to the updatee
313 temp = CTemp uniq PtrRep
316 profCtrC SLIT("TICK_UPD_CON_IN_PLACE")
317 [mkIntCLit (length amodes)] `thenC`
319 getSpRelOffset args_sp `thenFC` \ sp_rel ->
321 (CMacroExpr PtrRep UPD_FRAME_UPDATEE [CAddr sp_rel]))
324 -- stomp all over it with the new constructor
325 inPlaceAllocDynClosure closure_info temp (CReg CurCostCentre) stuff
328 -- don't forget to update Su from the update frame
329 absC (CMacroStmt UPDATE_SU_FROM_UPD_FRAME [CAddr sp_rel]) `thenC`
331 -- set Node to point to the closure being returned
332 -- (can't be done earlier: node might conflict with amodes)
333 absC (CAssign (CReg node) temp) `thenC`
335 -- pop the update frame off the stack, and do the proper
337 let new_sp = args_sp - updateFrameSize in
338 setEndOfBlockInfo (EndOfBlockInfo new_sp (OnStack new_sp)) $
339 performReturn (AbsCNop) (mkStaticAlgReturnCode con)
341 where (closure_info, stuff)
342 = layOutDynClosure (dataConName con)
343 getAmodeRep amodes lf_info
345 lf_info = mkConLFInfo con
347 other_sequel -- The usual case
349 | isUnboxedTupleCon con ->
350 -- Return unboxed tuple in registers
351 let (ret_regs, leftovers) =
352 assignRegs [] (map getAmodeRep amodes)
354 profCtrC SLIT("TICK_RET_UNBOXED_TUP")
355 [mkIntCLit (length amodes)] `thenC`
357 doTailCall amodes ret_regs
358 mkUnboxedTupleReturnCode
359 (length leftovers) {- fast args arity -}
360 AbsCNop {-no pending assigments-}
361 Nothing {-not a let-no-escape-}
362 False {-node doesn't point-}
365 build_it_then (mkStaticAlgReturnCode con)
368 move_to_reg :: CAddrMode -> MagicId -> AbstractC
369 move_to_reg src_amode dest_reg = CAssign (CReg dest_reg) src_amode
371 build_it_then return =
372 -- BUILD THE OBJECT IN THE HEAP
373 -- The first "con" says that the name bound to this
374 -- closure is "con", which is a bit of a fudge, but it only
377 -- This Id is also used to get a unique for a
378 -- temporary variable, if the closure is a CHARLIKE.
379 -- funnily enough, this makes the unique always come
381 buildDynCon (dataConId con) currentCCS con amodes `thenFC` \ idinfo ->
382 idInfoToAmode PtrRep idinfo `thenFC` \ amode ->
386 profCtrC SLIT("TICK_RET_NEW") [mkIntCLit (length amodes)] `thenC`
387 -- could use doTailCall here.
388 performReturn (move_to_reg amode node) return