-
- -- Right hand sides that are constructors
- -- let v = C args
- -- in
- --- ...(let w = C same-args in ...)...
- -- Then use v instead of w. This may save
- -- re-constructing an existing constructor.
-completeNonRec env binder new_id rhs@(Con con con_args)
- | switchIsSet env SimplReuseCon &&
- maybeToBool maybe_existing_con &&
- not (isExported new_id) -- Don't bother for exported things
- -- because we won't be able to drop
- -- its binding.
- = tick ConReused `thenSmpl_`
- returnSmpl (extendIdEnvWithAtom env binder (VarArg it), [NonRec new_id rhs])
+\end{pseudocode}
+----------------------------------------------------------------------------
+
+
+
+%************************************************************************
+%* *
+\subsection[Simplify-letrec]{Letrec-expressions}
+%* *
+%************************************************************************
+
+Letrec expressions
+~~~~~~~~~~~~~~~~~~
+Here's the game plan
+
+1. Float any let(rec)s out of the RHSs
+2. Clone all the Ids and extend the envt with these clones
+3. Simplify one binding at a time, adding each binding to the
+ environment once it's done.
+
+This relies on the occurrence analyser to
+ a) break all cycles with an Id marked MustNotBeInlined
+ b) sort the decls into topological order
+The former prevents infinite inlinings, and the latter means
+that we get maximum benefit from working top to bottom.
+
+
+\begin{code}
+simplRec env pairs body_c body_ty
+ = -- Do floating, if necessary
+ floatBind env False (Rec pairs) `thenSmpl` \ [Rec pairs'] ->
+ let
+ binders = map fst pairs'
+ in
+ cloneIds env binders `thenSmpl` \ ids' ->
+ let
+ env_w_clones = extendIdEnvWithClones env binders ids'
+ in
+ simplRecursiveGroup env_w_clones ids' pairs' `thenSmpl` \ (pairs', new_env) ->
+
+ body_c new_env `thenSmpl` \ body' ->
+
+ returnSmpl (Let (Rec pairs') body')
+\end{code}
+
+\begin{code}
+-- The env passed to simplRecursiveGroup already has
+-- bindings that clone the variables of the group.
+simplRecursiveGroup env new_ids []
+ = returnSmpl ([], env)
+
+simplRecursiveGroup env (new_id : new_ids) ((binder@(id, occ_info), rhs) : pairs)
+ | inlineUnconditionally ok_to_dup id occ_info
+ = -- Single occurrence, so drop binding and extend env with the inlining
+ -- This is a little delicate, because what if the unique occurrence
+ -- is *before* this binding? This'll never happen, because
+ -- either it'll be marked "never inline" or else its occurrence will
+ -- occur after its binding in the group.
+ --
+ -- If these claims aren't right Core Lint will spot an unbound
+ -- variable. A quick fix is to delete this clause for simplRecursiveGroup
+ let
+ new_env = extendEnvGivenInlining env new_id occ_info rhs
+ in
+ simplRecursiveGroup new_env new_ids pairs
+
+ | otherwise
+ = simplRhsExpr env binder rhs new_id `thenSmpl` \ (new_rhs, arity) ->
+ let
+ new_id' = new_id `withArity` arity
+
+ -- ToDo: this next bit could usefully share code with completeNonRec
+
+ new_env
+ | idMustNotBeINLINEd new_id -- Occurrence analyser says "don't inline"
+ = env
+
+ | is_atomic eta'd_rhs -- If rhs (after eta reduction) is atomic
+ = extendIdEnvWithAtom env binder the_arg
+
+ | otherwise -- Non-atomic
+ = extendEnvGivenBinding env occ_info new_id new_rhs
+ -- Don't eta if it doesn't eliminate the binding
+
+ eta'd_rhs = etaCoreExpr new_rhs
+ the_arg = case eta'd_rhs of
+ Var v -> VarArg v
+ Lit l -> LitArg l
+ in
+ simplRecursiveGroup new_env new_ids pairs `thenSmpl` \ (new_pairs, final_env) ->
+ returnSmpl ((new_id', new_rhs) : new_pairs, final_env)