[project @ 2001-06-11 12:24:51 by simonpj]
[ghc-hetmet.git] / ghc / compiler / NOTES
1 NB: all floats are let-binds, but some non-rec lets
2     may be unlifted (with RHS ok-for-speculation)
3
4
5 simplArg:  [use strictness]
6            [used for non-top-lvl non-rec RHS or function arg]
7   if strict-type || demanded
8         simplStrictExpr
9   else
10         simplExpr ---> (floats,expr)
11         float all the floats if exposes constr app, return expr
12
13 simpl (applied lambda)      ==> simplNonRecBind
14 simpl (Let (NonRec ...) ..) ==> simplNonRecBind
15
16 simpl (Let (Rec ...)    ..) ==> simplRecBind
17
18 simplRecBind:
19   simplify binders (but not its IdInfo)
20   simplify the pairs one at a time
21         using simplRecPair
22
23 simplNonRecBind:        [was simplBeta]
24         [used for non-top-lvl non-rec bindings]
25   - check for PreInlineUnconditionally
26   - simplify binder, including its IdInfo
27   - simplArg
28   - if strict-type 
29         addCaseBind [which makes a let if ok-for-spec]
30     else
31         completeLazyBind
32
33 simplRecPair:   [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)
42         or if top level
43   - completeLazyBind
44   
45
46 completeLazyBind:       [given a simplified RHS]
47         [used for both rec and non-rec bindings, top level and not]
48   - try discarding dead
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..]
54
55   - add unfolding [this is the only place we add an unfolding]
56     add arity
57
58
59
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.
68         
69         f (g x, h x)    
70         g (+ x)
71
72 It's harder to make the rule match if we ANF-ise the constructor,
73 or eta-expand the PAP:
74
75         f (let { a = g x; b = h x } in (a,b))
76         g (\y. + x y)
77
78 On the other hand if we see the let-defns
79
80         p = (g x, h x)
81         q = + x
82
83 then we *do* want to ANF-ise and eta-expand, so that p and q
84 can be safely inlined.   
85
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.
88 For example
89
90         r = let x = e in (x,x)
91
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.
95
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.
99
100
101 Eta expansion
102 ~~~~~~~~~~~~~~
103 For eta expansion, we want to catch things like
104
105         case e of (a,b) -> \x -> case a of (p,q) -> \y -> r
106
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.