2 % (c) The University of Glasgow 2006
3 % (c) The GRASP/AQUA Project, Glasgow University, 1993-1998
5 %********************************************************
7 \section[CgLetNoEscape]{Handling ``let-no-escapes''}
9 %********************************************************
13 -- The above warning supression flag is a temporary kludge.
14 -- While working on this module you are encouraged to remove it and fix
15 -- any warnings in the module. See
16 -- http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#Warnings
19 module CgLetNoEscape ( cgLetNoEscapeClosure ) where
21 #include "HsVersions.h"
23 import {-# SOURCE #-} CgExpr ( cgExpr )
44 %************************************************************************
46 \subsection[what-is-non-escaping]{What {\em is} a ``non-escaping let''?}
48 %************************************************************************
50 [The {\em code} that detects these things is elsewhere.]
54 let x = fvs \ args -> e
57 if ... then x else ...
59 @x@ is used twice (so we probably can't unfold it), but when it is
60 entered, the stack is deeper than it was when the definition of @x@
61 happened. Specifically, if instead of allocating a closure for @x@,
62 we saved all @x@'s fvs on the stack, and remembered the stack depth at
63 that moment, then whenever we enter @x@ we can simply set the stack
64 pointer(s) to these remembered (compile-time-fixed) values, and jump
67 All of this is provided x is:
72 guaranteed to be entered before the stack retreats -- ie x is not
73 buried in a heap-allocated closure, or passed as an argument to something;
75 all the enters have exactly the right number of arguments,
78 all the enters are tail calls; that is, they return to the
79 caller enclosing the definition of @x@.
82 Under these circumstances we say that @x@ is {\em non-escaping}.
84 An example of when (4) does {\em not} hold:
87 in case x of ...alts...
90 Here, @x@ is certainly entered only when the stack is deeper than when
91 @x@ is defined, but here it must return to \tr{...alts...} So we can't
92 just adjust the stack down to @x@'s recalled points, because that
93 would lost @alts@' context.
95 Things can get a little more complicated. Consider:
98 in let x = fvs \ args -> ...y...
102 Now, if @x@ is used in a non-escaping way in \tr{...x...}, {\em and}
103 @y@ is used in a non-escaping way in \tr{...y...}, {\em then} @y@ is
106 @x@ can even be recursive! Eg:
108 letrec x = [y] \ [v] -> if v then x True else ...
114 %************************************************************************
116 \subsection[codeGen-for-non-escaping]{Generating code for a ``non-escaping let''}
118 %************************************************************************
121 Generating code for this is fun. It is all very very similar to what
122 we do for a case expression. The duality is between
132 That is, the RHS of @x@ (ie @b@) will execute {\em later}, just like
133 the alternative of the case; it needs to be compiled in an environment
134 in which all volatile bindings are forgotten, and the free vars are
135 bound only to stable things like stack locations.. The @e@ part will
136 execute {\em next}, just like the scrutinee of a case.
138 First, we need to save all @x@'s free vars
139 on the stack, if they aren't there already.
144 -> CostCentreStack -- NB: *** NOT USED *** ToDo (WDP 94/06)
145 -> StgBinderInfo -- NB: ditto
146 -> StgLiveVars -- variables live in RHS, including the binders
147 -- themselves in the case of a recursive group
148 -> EndOfBlockInfo -- where are we going to?
149 -> Maybe VirtualSpOffset -- Slot for current cost centre
150 -> RecFlag -- is the binding recursive?
151 -> [Id] -- args (as in \ args -> body)
152 -> StgExpr -- body (as in above)
153 -> FCode (Id, CgIdInfo)
155 -- ToDo: deal with the cost-centre issues
158 bndr cc binder_info full_live_in_rhss
159 rhs_eob_info cc_slot rec args body
162 lf_info = mkLFLetNoEscape arity
164 -- saveVolatileVarsAndRegs done earlier in cgExpr.
166 do { (vSp, _) <- forkEvalHelp rhs_eob_info
168 (do { allocStackTop retAddrSizeW
169 ; nukeDeadBindings full_live_in_rhss })
171 (do { deAllocStackTop retAddrSizeW
172 ; abs_c <- forkProc $ cgLetNoEscapeBody bndr cc
175 -- Ignore the label that comes back from
176 -- mkRetDirectTarget. It must be conjured up elswhere
177 ; emitReturnTarget (idName bndr) abs_c
180 ; returnFC (bndr, letNoEscapeIdInfo bndr vSp lf_info) }
184 cgLetNoEscapeBody :: Id -- Name of the joint point
186 -> Maybe VirtualSpOffset
191 cgLetNoEscapeBody bndr cc cc_slot all_args body = do
192 { (arg_regs, ptrs, nptrs, ret_slot) <- bindUnboxedTupleComponents all_args
194 -- restore the saved cost centre. BUT: we must not free the stack slot
195 -- containing the cost centre, because it might be needed for a
196 -- recursive call to this let-no-escape.
197 ; restoreCurrentCostCentre cc_slot False{-don't free-}
199 -- Enter the closures cc, if required
200 ; -- enterCostCentreCode closure_info cc IsFunction
202 -- The "return address" slot doesn't have a return address in it;
203 -- but the heap-check needs it filled in if the heap-check fails.
204 -- So we pass code to fill it in to the heap-check macro
205 ; sp_rel <- getSpRelOffset ret_slot
207 ; let lbl = mkReturnInfoLabel (idUnique bndr)
208 frame_hdr_asst = oneStmt (CmmStore sp_rel (mkLblExpr lbl))
210 -- Do heap check [ToDo: omit for non-recursive case by recording in
211 -- in envt and absorbing at call site]
212 ; unbxTupleHeapCheck arg_regs ptrs nptrs frame_hdr_asst