summaryrefslogtreecommitdiff
path: root/ghc/compiler/NOTES
blob: e5359598475b4953c358dffba42a98d6d030dcf4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
*** unexpected failure for jtod_circint(opt)


	New back end thoughts

-----------------------------------------------------------------------------
Codegen notes

* jumps to ImpossibleBranch should be removed.

* Profiling:
	- when updating a closure with an indirection to a function,
	  we should make a permanent indirection.

	- check that we're bumping the scc count appropriately

* check perf & binary sizes against the HEAD

-----------------------------------------------------------------------------
C backend notes

* use STGCALL macros for foreign calls (doesn't look like volatile regs
  are handled properly at the mo).

-----------------------------------------------------------------------------
Cmm parser notes

* switches

* need to cater for unexported procedures/info tables?

* We should be able to get rid of entry labels, use info labels only.
  - we need a %ENTRY_LBL(info_lbl) macro, so that instead of
     JMP_(foo_entry) we can write jump %ENTRY_LBL(foo_info).

-----------------------------------------------------------------------------

* Move arg-descr from LFInfo to ClosureInfo? 
  But: only needed for functions

* Move all of CgClosure.link_caf into NewCaf, and newDynCaf

* If the case binder is dead, and the constr is nullary,
  do we need to assign to Node?


-------------------------
* Relation between separate type sigs and pattern type sigs
f :: forall a. a->a
f :: b->b = e   -- No: monomorphic

f :: forall a. a->a
f :: forall a. a->a  -- OK

f :: forall a. [a] -> [a]
f :: forall b. b->b = e  ???


-------------------------------
NB: all floats are let-binds, but some non-rec lets
    may be unlifted (with RHS ok-for-speculation)


simplArg:  [use strictness]
	   [used for non-top-lvl non-rec RHS or function arg]
  if strict-type || demanded
	simplStrictExpr
  else
	simplExpr ---> (floats,expr)
	float all the floats if exposes constr app, return expr

simpl (applied lambda)	    ==> simplNonRecBind
simpl (Let (NonRec ...) ..) ==> simplNonRecBind

simpl (Let (Rec ...)    ..) ==> simplRecBind

simplRecBind:
  simplify binders (but not its IdInfo)
  simplify the pairs one at a time
	using simplRecPair

simplNonRecBind:	[was simplBeta]
	[used for non-top-lvl non-rec bindings]
  - check for PreInlineUnconditionally
  - simplify binder, including its IdInfo
  - simplArg
  - if strict-type 
	addCaseBind [which makes a let if ok-for-spec]
    else
	completeLazyBind

simplLazyBind:	[binder already simplified, but not its IdInfo]
	  	[used for both rec and top-lvl non-rec]
		[must not be strict/unboxed; case not allowed]
  - check for PreInlineUnconditionally
  - substituteIdInfo and add result to in-scope 
	[so that rules are available in rec rhs]
  - simplExpr --> (floats,expr)
  - float: lifted floats only
	if exposes constructor or pap (even if non-triv args)
	or if top level
  - completeLazyBind
  

completeLazyBind: 	[given a simplified RHS]
	[used for both rec and non-rec bindings, top level and not]
  - try discarding dead
  - try PostInlineUnconditionally
  - let-bind coerce arg and repeat
  - try rhs tylam (float)
  - try eta expand (float)    [not if any float is unlifted && (non-spec || top_lvl || rec)]
  - let-bind constructor args [not if any float is ..as above..]

  - add unfolding [this is the only place we add an unfolding]
    add arity



Right hand sides and arguments
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In many ways we want to treat 
	(a) the right hand side of a let(rec), and 
	(b) a function argument
in the same way.  But not always!  In particular, we would
like to leave these arguments exactly as they are, so they
will match a RULE more easily.
	
	f (g x, h x)	
	g (+ x)

It's harder to make the rule match if we ANF-ise the constructor,
or eta-expand the PAP:

	f (let { a = g x; b = h x } in (a,b))
	g (\y. + x y)

On the other hand if we see the let-defns

	p = (g x, h x)
	q = + x

then we *do* want to ANF-ise and eta-expand, so that p and q
can be safely inlined.   

Even floating lets out is a bit dubious.  For let RHS's we float lets
out if that exposes a value, so that the value can be inlined more vigorously.
For example

	r = let x = e in (x,x)

Here, if we float the let out we'll expose a nice constructor. We did experiments
that showed this to be a generally good thing.  But it was a bad thing to float
lets out unconditionally, because that meant they got allocated more often.

For function arguments, there's less reason to expose a constructor (it won't
get inlined).  Just possibly it might make a rule match, but I'm pretty skeptical.
So for the moment we don't float lets out of function arguments either.


Eta expansion
~~~~~~~~~~~~~~
For eta expansion, we want to catch things like

	case e of (a,b) -> \x -> case a of (p,q) -> \y -> r

If the \x was on the RHS of a let, we'd eta expand to bring the two
lambdas together.  And in general that's a good thing to do.  Perhaps
we should eta expand wherever we find a (value) lambda?  Then the eta
expansion at a let RHS can concentrate solely on the PAP case.