------------------------------------
Improve occurrence analysis a little
------------------------------------
Consider
x1 = a0 : []
x2 = a1 : x1
x3 = a2 : x2
g = f x3
First time round, it looks as if x1 and x2 occur as an arg of a
let(rec)-bound constructor, and hence should not be inlined. (If the
RHS of a let is just (C a b) where C is a constructor, then we like to
keep it that way, with atomic a,b, so that it can be inlined easily at
a 'case'.)
But in this case, x3 is inlined in g's RHS... and now x2 is not an arg
of a let-bound constructor, so it can be inlined, and then x1. Result:
g = f (a2 : a1 : a0 : [])
Which is fine. What is *not* fine is that it has been costing us a
whole simplifier iteration for each element!
This commit adds another little hack to get around the problem: don't treat
constructor RHSs specially if the bound variable looks as if it occurs just
once so it'll be inlined. This catches the common case very nicely.
It's a pain that we have the atomic-args-for-constructor-RHSs invariant.
But I can't see how to do without it.
where
(final_body_usage, tagged_binder) = tagBinder body_usage binder
where
(final_body_usage, tagged_binder) = tagBinder body_usage binder
- (rhs_usage, rhs') = occAnalRhs env binder rhs
+ (rhs_usage, rhs') = occAnalRhs env tagged_binder rhs
\end{code}
Dropping dead code for recursive bindings is done in a very simple way:
\end{code}
Dropping dead code for recursive bindings is done in a very simple way:
\begin{code}
occAnalRhs :: OccEnv
-> Id -> CoreExpr -- Binder and rhs
\begin{code}
occAnalRhs :: OccEnv
-> Id -> CoreExpr -- Binder and rhs
+ -- For non-recs the binder is alrady tagged
+ -- with occurrence info
-> (UsageDetails, CoreExpr)
occAnalRhs env id rhs
= (final_usage, rhs')
where
-> (UsageDetails, CoreExpr)
occAnalRhs env id rhs
= (final_usage, rhs')
where
- (rhs_usage, rhs') = occAnal (rhsCtxt env) rhs
- -- Note that we use an rhsCtxt. This tells the occ anal that it's
- -- looking at an RHS, which has an effect in occAnalApp
+ (rhs_usage, rhs') = occAnal ctxt rhs
+ ctxt | certainly_inline id = env
+ | otherwise = rhsCtxt env
+ -- Note that we generally use an rhsCtxt. This tells the occ anal n
+ -- that it's looking at an RHS, which has an effect in occAnalApp
--
-- But there's a problem. Consider
-- x1 = a0 : []
-- x2 = a1 : x1
-- x3 = a2 : x2
--
-- But there's a problem. Consider
-- x1 = a0 : []
-- x2 = a1 : x1
-- x3 = a2 : x2
-- First time round, it looks as if x1 and x2 occur as an arg of a
-- let-bound constructor ==> give them a many-occurrence.
-- But then x3 is inlined (unconditionally as it happens) and
-- next time round, x2 will be, and the next time round x1 will be
-- Result: multiple simplifier iterations. Sigh.
-- First time round, it looks as if x1 and x2 occur as an arg of a
-- let-bound constructor ==> give them a many-occurrence.
-- But then x3 is inlined (unconditionally as it happens) and
-- next time round, x2 will be, and the next time round x1 will be
-- Result: multiple simplifier iterations. Sigh.
- -- Possible solution: use rhsCtxt for things that occur just once...
+ -- Crude solution: use rhsCtxt for things that occur just once...
+
+ certainly_inline id = case idOccInfo id of
+ OneOcc in_lam one_br -> not in_lam && one_br
+ other -> False
-- [March 98] A new wrinkle is that if the binder has specialisations inside
-- it then we count the specialised Ids as "extra rhs's". That way
-- [March 98] A new wrinkle is that if the binder has specialisations inside
-- it then we count the specialised Ids as "extra rhs's". That way
add v u = addOneOcc u v NoOccInfo -- Give a non-committal binder info
-- (i.e manyOcc) because many copies
-- of the specialised thing can appear
add v u = addOneOcc u v NoOccInfo -- Give a non-committal binder info
-- (i.e manyOcc) because many copies
-- of the specialised thing can appear