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 )
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,
48 isUnboxedTupleCon, isNullaryDataCon, dataConId, dataConWrapId
50 import Id ( Id, idName, idType, idPrimRep )
51 import Name ( nameModule, isLocallyDefinedName )
52 import Literal ( Literal(..) )
53 import PrelInfo ( maybeCharLikeCon, maybeIntLikeCon )
54 import PrimRep ( PrimRep(..), isFollowableRep )
55 import Unique ( Uniquable(..) )
57 import Panic ( assertPanic, trace )
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 dynamic_con_or_args) -- checks for litlit args too
75 getArgAmodes args `thenFC` \ amodes ->
78 (closure_info, amodes_w_offsets)
79 = layOutStaticClosure name getAmodeRep amodes lf_info
84 closure_label -- Labelled with the name on lhs of defn
85 closure_info -- Closure is static
87 (map fst amodes_w_offsets)) -- Sorted into ptrs first, then nonptrs
92 returnFC (id, stableAmodeIdInfo id (CLbl closure_label PtrRep) lf_info)
94 con_tycon = dataConTyCon con
95 lf_info = mkConLFInfo con
96 closure_label = mkClosureLabel name
99 top_ccc = mkCCostCentreStack dontCareCCS -- because it's static data
101 -- stuff needed by the assert pred only.
102 dynamic_con_or_args = isDllConApp con args
105 %************************************************************************
107 %* non-top-level constructors *
109 %************************************************************************
110 \subsection[code-for-constructors]{The code for constructors}
113 buildDynCon :: Id -- Name of the thing to which this constr will
115 -> CostCentreStack -- Where to grab cost centre from;
116 -- current CCS if currentOrSubsumedCCS
117 -> DataCon -- The data constructor
118 -> [CAddrMode] -- Its args
119 -> FCode CgIdInfo -- Return details about how to find it
121 -- We used to pass a boolean indicating whether all the
122 -- args were of size zero, so we could use a static
123 -- construtor; but I concluded that it just isn't worth it.
124 -- Now I/O uses unboxed tuples there just aren't any constructors
125 -- with all size-zero args.
127 -- The reason for having a separate argument, rather than looking at
128 -- the addr modes of the args is that we may be in a "knot", and
129 -- premature looking at the args will cause the compiler to black-hole!
132 First we deal with the case of zero-arity constructors. Now, they
133 will probably be unfolded, so we don't expect to see this case much,
134 if at all, but it does no harm, and sets the scene for characters.
136 In the case of zero-arity constructors, or, more accurately, those
137 which have exclusively size-zero (VoidRep) args, we generate no code
141 buildDynCon binder cc con []
142 = returnFC (stableAmodeIdInfo binder
143 (CLbl (mkClosureLabel (idName (dataConWrapId con))) PtrRep)
147 Now for @Char@-like closures. We generate an assignment of the
148 address of the closure to a temporary. It would be possible simply to
149 generate no code, and record the addressing mode in the environment,
150 but we'd have to be careful if the argument wasn't a constant --- so
151 for simplicity we just always asssign to a temporary.
153 Last special case: @Int@-like closures. We only special-case the
154 situation in which the argument is a literal in the range
155 @mIN_INTLIKE@..@mAX_INTLILKE@. NB: for @Char@-like closures we can
156 work with any old argument, but for @Int@-like ones the argument has
157 to be a literal. Reason: @Char@ like closures have an argument type
158 which is guaranteed in range.
160 Because of this, we use can safely return an addressing mode.
163 buildDynCon binder cc con [arg_amode]
165 | maybeCharLikeCon con
166 = absC (CAssign temp_amode (CCharLike arg_amode)) `thenC`
167 returnFC temp_id_info
169 | maybeIntLikeCon con && in_range_int_lit arg_amode
170 = returnFC (stableAmodeIdInfo binder (CIntLike arg_amode) (mkConLFInfo con))
172 (temp_amode, temp_id_info) = newTempAmodeAndIdInfo binder (mkConLFInfo con)
174 in_range_int_lit (CLit (MachInt val)) = val <= mAX_INTLIKE && val >= mIN_INTLIKE
175 in_range_int_lit other_amode = False
177 tycon = dataConTyCon con
180 Now the general case.
183 buildDynCon binder ccs con args
184 = allocDynClosure closure_info use_cc blame_cc amodes_w_offsets `thenFC` \ hp_off ->
185 returnFC (heapIdInfo binder hp_off lf_info)
187 (closure_info, amodes_w_offsets)
188 = layOutDynClosure (idName binder) getAmodeRep args lf_info
189 lf_info = mkConLFInfo con
191 use_cc -- cost-centre to stick in the object
192 = if currentOrSubsumedCCS ccs
193 then CReg CurCostCentre
194 else mkCCostCentreStack ccs
196 blame_cc = use_cc -- cost-centre on which to blame the alloc (same)
200 %************************************************************************
202 %* constructor-related utility function: *
203 %* bindConArgs is called from cgAlt of a case *
205 %************************************************************************
206 \subsection[constructor-utilities]{@bindConArgs@: constructor-related utility}
208 @bindConArgs@ $con args$ augments the environment with bindings for the
209 binders $args$, assuming that we have just returned from a @case@ which
214 :: DataCon -> [Id] -- Constructor and args
218 = ASSERT(not (isUnboxedTupleCon con))
219 mapCs bind_arg args_w_offsets
221 bind_arg (arg, offset) = bindNewToNode arg offset mkLFArgument
222 (_, args_w_offsets) = layOutDynCon con idPrimRep args
225 Unboxed tuples are handled slightly differently - the object is
226 returned in registers and on the stack instead of the heap.
229 bindUnboxedTupleComponents
231 -> FCode ([MagicId], -- regs assigned
232 [(VirtualSpOffset,Int)], -- tag slots
233 Bool) -- any components on stack?
235 bindUnboxedTupleComponents args
236 = -- Assign as many components as possible to registers
237 let (arg_regs, leftovers) = assignRegs [] (map idPrimRep args)
238 (reg_args, stk_args) = splitAt (length arg_regs) args
241 -- Allocate the rest on the stack (ToDo: separate out pointers)
242 getVirtSp `thenFC` \ vsp ->
243 getRealSp `thenFC` \ rsp ->
244 let (top_sp, stk_offsets, tags) =
245 mkTaggedVirtStkOffsets rsp idPrimRep stk_args
248 -- The stack pointer points to the last stack-allocated component
249 setRealAndVirtualSp top_sp `thenC`
251 -- need to explicitly free any empty slots we just jumped over
252 (if vsp < rsp then freeStackSlots [vsp+1 .. rsp] else nopC) `thenC`
254 bindArgsToRegs reg_args arg_regs `thenC`
255 mapCs bindNewToStack stk_offsets `thenC`
256 returnFC (arg_regs,tags, not (null stk_offsets))
259 %************************************************************************
261 \subsubsection[CgRetConv-cgReturnDataCon]{Actually generate code for a constructor return}
263 %************************************************************************
266 Note: it's the responsibility of the @cgReturnDataCon@ caller to be
267 sure the @amodes@ passed don't conflict with each other.
269 cgReturnDataCon :: DataCon -> [CAddrMode] -> Code
271 cgReturnDataCon con amodes
272 = getEndOfBlockInfo `thenFC` \ (EndOfBlockInfo args_sp sequel) ->
276 CaseAlts _ (Just (alts, Just (maybe_deflt, (_,deflt_lbl))))
277 | not (dataConTag con `is_elem` map fst alts)
279 -- Special case! We're returning a constructor to the default case
280 -- of an enclosing case. For example:
282 -- case (case e of (a,b) -> C a b) of
284 -- y -> ...<returning here!>...
287 -- if the default is a non-bind-default (ie does not use y),
288 -- then we should simply jump to the default join point;
291 Nothing -> performReturn AbsCNop {- No reg assts -} jump_to_join_point
292 Just _ -> build_it_then jump_to_join_point
294 is_elem = isIn "cgReturnDataCon"
295 jump_to_join_point sequel = absC (CJump (CLbl deflt_lbl CodePtrRep))
296 -- Ignore the sequel: we've already looked at it above
298 -- If the sequel is an update frame, we might be able to
299 -- do update in place...
301 | not (isNullaryDataCon con) -- no nullary constructors, please
302 && not (maybeCharLikeCon con) -- no chars please (these are all static)
303 && not (any isFollowableRep (map getAmodeRep amodes))
304 -- no ptrs please (generational gc...)
305 && closureSize closure_info <= mIN_UPD_SIZE
306 -- don't know the real size of the
307 -- thunk, so assume mIN_UPD_SIZE
309 -> -- get a new temporary and make it point to the updatee
312 temp = CTemp uniq PtrRep
315 profCtrC SLIT("TICK_UPD_CON_IN_PLACE")
316 [mkIntCLit (length amodes)] `thenC`
318 getSpRelOffset args_sp `thenFC` \ sp_rel ->
320 (CMacroExpr PtrRep UPD_FRAME_UPDATEE [CAddr sp_rel]))
323 -- stomp all over it with the new constructor
324 inPlaceAllocDynClosure closure_info temp (CReg CurCostCentre) stuff
327 -- don't forget to update Su from the update frame
328 absC (CMacroStmt UPDATE_SU_FROM_UPD_FRAME [CAddr sp_rel]) `thenC`
330 -- set Node to point to the closure being returned
331 -- (can't be done earlier: node might conflict with amodes)
332 absC (CAssign (CReg node) temp) `thenC`
334 -- pop the update frame off the stack, and do the proper
336 let new_sp = args_sp - updateFrameSize in
337 setEndOfBlockInfo (EndOfBlockInfo new_sp (OnStack new_sp)) $
338 performReturn (AbsCNop) (mkStaticAlgReturnCode con)
340 where (closure_info, stuff)
341 = layOutDynClosure (dataConName con)
342 getAmodeRep amodes lf_info
344 lf_info = mkConLFInfo con
346 other_sequel -- The usual case
348 | isUnboxedTupleCon con ->
349 -- Return unboxed tuple in registers
350 let (ret_regs, leftovers) =
351 assignRegs [] (map getAmodeRep amodes)
353 profCtrC SLIT("TICK_RET_UNBOXED_TUP")
354 [mkIntCLit (length amodes)] `thenC`
356 doTailCall amodes ret_regs
357 mkUnboxedTupleReturnCode
358 (length leftovers) {- fast args arity -}
359 AbsCNop {-no pending assigments-}
360 Nothing {-not a let-no-escape-}
361 False {-node doesn't point-}
364 build_it_then (mkStaticAlgReturnCode con)
367 con_name = dataConName con
369 move_to_reg :: CAddrMode -> MagicId -> AbstractC
370 move_to_reg src_amode dest_reg = CAssign (CReg dest_reg) src_amode
372 build_it_then return =
373 -- BUILD THE OBJECT IN THE HEAP
374 -- The first "con" says that the name bound to this
375 -- closure is "con", which is a bit of a fudge, but it only
378 -- This Id is also used to get a unique for a
379 -- temporary variable, if the closure is a CHARLIKE.
380 -- funnily enough, this makes the unique always come
382 buildDynCon (dataConId con) currentCCS con amodes `thenFC` \ idinfo ->
383 idInfoToAmode PtrRep idinfo `thenFC` \ amode ->
387 profCtrC SLIT("TICK_RET_NEW") [mkIntCLit (length amodes)] `thenC`
388 -- could use doTailCall here.
389 performReturn (move_to_reg amode node) return