summaryrefslogtreecommitdiff
path: root/ghc/compiler/codeGen/CgLetNoEscape.lhs
diff options
context:
space:
mode:
Diffstat (limited to 'ghc/compiler/codeGen/CgLetNoEscape.lhs')
-rw-r--r--ghc/compiler/codeGen/CgLetNoEscape.lhs202
1 files changed, 202 insertions, 0 deletions
diff --git a/ghc/compiler/codeGen/CgLetNoEscape.lhs b/ghc/compiler/codeGen/CgLetNoEscape.lhs
new file mode 100644
index 0000000000..abc1e115c9
--- /dev/null
+++ b/ghc/compiler/codeGen/CgLetNoEscape.lhs
@@ -0,0 +1,202 @@
+%
+% (c) The GRASP/AQUA Project, Glasgow University, 1993-1994
+%
+%********************************************************
+%* *
+\section[CgLetNoEscape]{Handling ``let-no-escapes''}
+%* *
+%********************************************************
+
+\begin{code}
+#include "HsVersions.h"
+
+module CgLetNoEscape ( cgLetNoEscapeClosure ) where
+
+import StgSyn
+import CgMonad
+import AbsCSyn
+
+import CgBindery -- various things
+import CgExpr ( cgExpr )
+import CgHeapery ( heapCheck )
+import CgRetConv ( assignRegs )
+import CgStackery ( mkVirtStkOffsets )
+import CgUsages ( setRealAndVirtualSps, getVirtSps )
+import CLabelInfo ( mkFastEntryLabel )
+import ClosureInfo ( mkLFLetNoEscape )
+import Id ( getIdKind )
+import Util
+\end{code}
+
+%************************************************************************
+%* *
+\subsection[what-is-non-escaping]{What {\em is} a ``non-escaping let''?}
+%* *
+%************************************************************************
+
+[The {\em code} that detects these things is elsewhere.]
+
+Consider:
+\begin{verbatim}
+ let x = fvs \ args -> e
+ in
+ if ... then x else
+ if ... then x else ...
+\end{verbatim}
+@x@ is used twice (so we probably can't unfold it), but when it is
+entered, the stack is deeper than it was then the definition of @x@
+happened. Specifically, if instead of allocating a closure for @x@,
+we saved all @x@'s fvs on the stack, and remembered the stack depth at
+that moment, then whenever we enter @x@ we can simply set the stack
+pointer(s) to these remembered (compile-time-fixed) values, and jump
+to the code for @x@.
+
+All of this is provided x is:
+\begin{enumerate}
+\item
+non-updatable;
+\item
+guaranteed to be entered before the stack retreats -- ie x is not
+buried in a heap-allocated closure, or passed as an argument to something;
+\item
+all the enters have exactly the right number of arguments,
+no more no less;
+\item
+all the enters are tail calls; that is, they return to the
+caller enclosing the definition of @x@.
+\end{enumerate}
+
+Under these circumstances we say that @x@ is {\em non-escaping}.
+
+An example of when (4) does {\em not} hold:
+\begin{verbatim}
+ let x = ...
+ in case x of ...alts...
+\end{verbatim}
+
+Here, @x@ is certainly entered only when the stack is deeper than when
+@x@ is defined, but here it must return to \tr{...alts...} So we can't
+just adjust the stack down to @x@'s recalled points, because that
+would lost @alts@' context.
+
+Things can get a little more complicated. Consider:
+\begin{verbatim}
+ let y = ...
+ in let x = fvs \ args -> ...y...
+ in ...x...
+\end{verbatim}
+
+Now, if @x@ is used in a non-escaping way in \tr{...x...}, {\em and}
+@y@ is used in a non-escaping way in \tr{...y...}, {\em then} @y@ is
+non-escaping.
+
+@x@ can even be recursive! Eg:
+\begin{verbatim}
+ letrec x = [y] \ [v] -> if v then x True else ...
+ in
+ ...(x b)...
+\end{verbatim}
+
+
+%************************************************************************
+%* *
+\subsection[codeGen-for-non-escaping]{Generating code for a ``non-escaping let''}
+%* *
+%************************************************************************
+
+
+Generating code for this is fun. It is all very very similar to what
+we do for a case expression. The duality is between
+\begin{verbatim}
+ let-no-escape x = b
+ in e
+\end{verbatim}
+and
+\begin{verbatim}
+ case e of ... -> b
+\end{verbatim}
+
+That is, the RHS of @x@ (ie @b@) will execute {\em later}, just like
+the alternative of the case; it needs to be compiled in an environment
+in which all volatile bindings are forgotten, and the free vars are
+bound only to stable things like stack locations.. The @e@ part will
+execute {\em next}, just like the scrutinee of a case.
+
+First, we need to save all @x@'s free vars
+on the stack, if they aren't there already.
+
+\begin{code}
+cgLetNoEscapeClosure
+ :: Id -- binder
+ -> CostCentre -- NB: *** NOT USED *** ToDo (WDP 94/06)
+ -> StgBinderInfo -- NB: ditto
+ -> PlainStgLiveVars -- variables live in RHS, including the binders
+ -- themselves in the case of a recursive group
+ -> EndOfBlockInfo -- where are we going to?
+ -> Maybe VirtualSpBOffset -- Slot for current cost centre
+ -> [Id] -- args (as in \ args -> body)
+ -> PlainStgExpr -- body (as in above)
+ -> FCode (Id, CgIdInfo)
+
+-- ToDo: deal with the cost-centre issues
+
+cgLetNoEscapeClosure binder cc bi full_live_in_rhss rhs_eob_info maybe_cc_slot args body
+ = let
+ arity = length args
+ lf_info = mkLFLetNoEscape arity full_live_in_rhss{-used???-}
+ in
+ forkEvalHelp
+ rhs_eob_info
+ (nukeDeadBindings full_live_in_rhss)
+ (forkAbsC (cgLetNoEscapeBody args body))
+ `thenFC` \ (vA, vB, code) ->
+ let
+ label = mkFastEntryLabel binder arity
+ in
+ absC (CCodeBlock label code) `thenC`
+ returnFC (binder, letNoEscapeIdInfo binder vA vB lf_info)
+\end{code}
+
+\begin{code}
+cgLetNoEscapeBody :: [Id] -- Args
+ -> PlainStgExpr -- Body
+ -> Code
+
+cgLetNoEscapeBody all_args rhs
+ = getVirtSps `thenFC` \ (vA, vB) ->
+ let
+ arg_kinds = map getIdKind all_args
+ (arg_regs, _) = assignRegs [{-nothing live-}] arg_kinds
+ stk_args = drop (length arg_regs) all_args
+
+ -- stk_args is the args which are passed on the stack at the fast-entry point
+ -- Using them, we define the stack layout
+ (spA_stk_args, spB_stk_args, stk_bxd_w_offsets, stk_ubxd_w_offsets)
+ = mkVirtStkOffsets
+ vA vB -- Initial virtual SpA, SpB
+ getIdKind
+ stk_args
+ in
+
+ -- Bind args to appropriate regs/stk locns
+ bindArgsToRegs all_args arg_regs `thenC`
+ mapCs bindNewToAStack stk_bxd_w_offsets `thenC`
+ mapCs bindNewToBStack stk_ubxd_w_offsets `thenC`
+ setRealAndVirtualSps spA_stk_args spB_stk_args `thenC`
+
+{- ToDo: NOT SURE ABOUT COST CENTRES!
+ -- Enter the closures cc, if required
+ lexEnterCCcode closure_info maybe_cc `thenC`
+-}
+
+ -- [No need for stack check; forkEvalHelp dealt with that]
+
+ -- Do heap check [ToDo: omit for non-recursive case by recording in
+ -- in envt and absorbing at call site]
+ heapCheck arg_regs False {- Node doesn't point to it -} (
+ -- heapCheck *encloses* the rest
+
+ -- Compile the body
+ cgExpr rhs
+ )
+\end{code}