1 NB: all floats are let-binds, but some non-rec lets
2 may be unlifted (with RHS ok-for-speculation)
5 simplArg: [use strictness]
6 [used for non-top-lvl non-rec RHS or function arg]
7 if strict-type || demanded
10 simplExpr ---> (floats,expr)
11 float all the floats if exposes constr app, return expr
13 simpl (applied lambda) ==> simplNonRecBind
14 simpl (Let (NonRec ...) ..) ==> simplNonRecBind
16 simpl (Let (Rec ...) ..) ==> simplRecBind
19 simplify binders (but not its IdInfo)
20 simplify the pairs one at a time
23 simplNonRecBind: [was simplBeta]
24 [used for non-top-lvl non-rec bindings]
25 - check for PreInlineUnconditionally
26 - simplify binder, including its IdInfo
29 addCaseBind [which makes a let if ok-for-spec]
33 simplLazyBind: [binder already simplified, but not its IdInfo]
34 [used for both rec and top-lvl non-rec]
35 [must not be strict/unboxed; case not allowed]
36 - check for PreInlineUnconditionally
37 - substituteIdInfo and add result to in-scope
38 [so that rules are available in rec rhs]
39 - simplExpr --> (floats,expr)
40 - float: lifted floats only
41 if exposes constructor or pap (even if non-triv args)
46 completeLazyBind: [given a simplified RHS]
47 [used for both rec and non-rec bindings, top level and not]
49 - try PostInlineUnconditionally
50 - let-bind coerce arg and repeat
51 - try rhs tylam (float)
52 - try eta expand (float) [not if any float is unlifted && (non-spec || top_lvl || rec)]
53 - let-bind constructor args [not if any float is ..as above..]
55 - add unfolding [this is the only place we add an unfolding]
60 Right hand sides and arguments
61 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
62 In many ways we want to treat
63 (a) the right hand side of a let(rec), and
64 (b) a function argument
65 in the same way. But not always! In particular, we would
66 like to leave these arguments exactly as they are, so they
67 will match a RULE more easily.
72 It's harder to make the rule match if we ANF-ise the constructor,
73 or eta-expand the PAP:
75 f (let { a = g x; b = h x } in (a,b))
78 On the other hand if we see the let-defns
83 then we *do* want to ANF-ise and eta-expand, so that p and q
84 can be safely inlined.
86 Even floating lets out is a bit dubious. For let RHS's we float lets
87 out if that exposes a value, so that the value can be inlined more vigorously.
90 r = let x = e in (x,x)
92 Here, if we float the let out we'll expose a nice constructor. We did experiments
93 that showed this to be a generally good thing. But it was a bad thing to float
94 lets out unconditionally, because that meant they got allocated more often.
96 For function arguments, there's less reason to expose a constructor (it won't
97 get inlined). Just possibly it might make a rule match, but I'm pretty skeptical.
98 So for the moment we don't float lets out of function arguments either.
103 For eta expansion, we want to catch things like
105 case e of (a,b) -> \x -> case a of (p,q) -> \y -> r
107 If the \x was on the RHS of a let, we'd eta expand to bring the two
108 lambdas together. And in general that's a good thing to do. Perhaps
109 we should eta expand wherever we find a (value) lambda? Then the eta
110 expansion at a let RHS can concentrate solely on the PAP case.