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 )
45 %************************************************************************
47 \subsection[what-is-non-escaping]{What {\em is} a ``non-escaping let''?}
49 %************************************************************************
51 [The {\em code} that detects these things is elsewhere.]
55 let x = fvs \ args -> e
58 if ... then x else ...
60 @x@ is used twice (so we probably can't unfold it), but when it is
61 entered, the stack is deeper than it was when the definition of @x@
62 happened. Specifically, if instead of allocating a closure for @x@,
63 we saved all @x@'s fvs on the stack, and remembered the stack depth at
64 that moment, then whenever we enter @x@ we can simply set the stack
65 pointer(s) to these remembered (compile-time-fixed) values, and jump
68 All of this is provided x is:
73 guaranteed to be entered before the stack retreats -- ie x is not
74 buried in a heap-allocated closure, or passed as an argument to something;
76 all the enters have exactly the right number of arguments,
79 all the enters are tail calls; that is, they return to the
80 caller enclosing the definition of @x@.
83 Under these circumstances we say that @x@ is {\em non-escaping}.
85 An example of when (4) does {\em not} hold:
88 in case x of ...alts...
91 Here, @x@ is certainly entered only when the stack is deeper than when
92 @x@ is defined, but here it must return to \tr{...alts...} So we can't
93 just adjust the stack down to @x@'s recalled points, because that
94 would lost @alts@' context.
96 Things can get a little more complicated. Consider:
99 in let x = fvs \ args -> ...y...
103 Now, if @x@ is used in a non-escaping way in \tr{...x...}, {\em and}
104 @y@ is used in a non-escaping way in \tr{...y...}, {\em then} @y@ is
107 @x@ can even be recursive! Eg:
109 letrec x = [y] \ [v] -> if v then x True else ...
115 %************************************************************************
117 \subsection[codeGen-for-non-escaping]{Generating code for a ``non-escaping let''}
119 %************************************************************************
122 Generating code for this is fun. It is all very very similar to what
123 we do for a case expression. The duality is between
133 That is, the RHS of @x@ (ie @b@) will execute {\em later}, just like
134 the alternative of the case; it needs to be compiled in an environment
135 in which all volatile bindings are forgotten, and the free vars are
136 bound only to stable things like stack locations.. The @e@ part will
137 execute {\em next}, just like the scrutinee of a case.
139 First, we need to save all @x@'s free vars
140 on the stack, if they aren't there already.
145 -> CostCentreStack -- NB: *** NOT USED *** ToDo (WDP 94/06)
146 -> StgBinderInfo -- NB: ditto
147 -> StgLiveVars -- variables live in RHS, including the binders
148 -- themselves in the case of a recursive group
149 -> EndOfBlockInfo -- where are we going to?
150 -> Maybe VirtualSpOffset -- Slot for current cost centre
151 -> RecFlag -- is the binding recursive?
152 -> [Id] -- args (as in \ args -> body)
153 -> StgExpr -- body (as in above)
154 -> FCode (Id, CgIdInfo)
156 -- ToDo: deal with the cost-centre issues
159 bndr cc binder_info full_live_in_rhss
160 rhs_eob_info cc_slot rec args body
163 lf_info = mkLFLetNoEscape arity
165 -- saveVolatileVarsAndRegs done earlier in cgExpr.
167 do { (vSp, _) <- forkEvalHelp rhs_eob_info
169 (do { allocStackTop retAddrSizeW
170 ; nukeDeadBindings full_live_in_rhss })
172 (do { deAllocStackTop retAddrSizeW
173 ; abs_c <- forkProc $ cgLetNoEscapeBody bndr cc
176 -- Ignore the label that comes back from
177 -- mkRetDirectTarget. It must be conjured up elswhere
178 ; emitReturnTarget (idName bndr) abs_c
181 ; returnFC (bndr, letNoEscapeIdInfo bndr vSp lf_info) }
185 cgLetNoEscapeBody :: Id -- Name of the joint point
187 -> Maybe VirtualSpOffset
192 cgLetNoEscapeBody bndr cc cc_slot all_args body = do
193 { (arg_regs, ptrs, nptrs, ret_slot) <- bindUnboxedTupleComponents all_args
195 -- restore the saved cost centre. BUT: we must not free the stack slot
196 -- containing the cost centre, because it might be needed for a
197 -- recursive call to this let-no-escape.
198 ; restoreCurrentCostCentre cc_slot False{-don't free-}
200 -- Enter the closures cc, if required
201 ; -- enterCostCentreCode closure_info cc IsFunction
203 -- The "return address" slot doesn't have a return address in it;
204 -- but the heap-check needs it filled in if the heap-check fails.
205 -- So we pass code to fill it in to the heap-check macro
206 ; sp_rel <- getSpRelOffset ret_slot
208 ; let lbl = mkReturnInfoLabel (idUnique bndr)
209 frame_hdr_asst = oneStmt (CmmStore sp_rel (mkLblExpr lbl))
211 -- Do heap check [ToDo: omit for non-recursive case by recording in
212 -- in envt and absorbing at call site]
213 ; unbxTupleHeapCheck arg_regs ptrs nptrs frame_hdr_asst