@@ -72,17 +72,63 @@ default method GHC uses for handling local functions and free variables.
72
72
Instead, GHC uses an alternative strategy called :term: `Closure Conversion `,
73
73
which creates more uniformity at the cost of extra heap allocation.
74
74
75
- Automated Lambda Lifting in GHC is *Selective * and based on several heuristics:
75
+ Automated lambda lifting in GHC occurs *late * in the compiler pipeline at STG,
76
+ right before code generation. GHC lambda lifts at STG instead of Core because
77
+ lambda lifting interferes with other optimizations.
78
+
79
+ Lambda lifting in GHC is also *Selective *. GHC uses a cost model that calculates
80
+ hypothetical heap allocations a function will induce. GHC lists heuristics for
81
+ when *not * to lambda lift in `Note [When to lift]
82
+ <https://gitlab.haskell.org/ghc/ghc/-/blob/master/compiler/GHC/Stg/Lift/Analysis.hs#L46> `_
83
+ , we repeat the basic ideas here. See :cite:t: `selectiveLambdaLifting `, and the
84
+ `lambda lifting wiki
85
+ <https://gitlab.haskell.org/ghc/ghc/-/wikis/late-lam-lift> `_ entry for more
86
+ details.
87
+
88
+ GHC does not lambda lift:
89
+
90
+ #. :term: `Top-level ` bindings. By definition these
91
+ cannot be lifted.
92
+ #. :term: `Thunk ` and Data Constructors. Lifting either of these would destroy
93
+ sharing.
94
+ #. :term: `Join Point ` because there is no lifting possible in a join point.
95
+ Similarly, abstracting over join points destroys the join point by turning it
96
+ into an argument to a lifted function.
97
+ #. Any local :term: `known function `. This would turn a known function call into
98
+ an :term: `unknown function ` call, which is slower. The flag
99
+ ``-fstg-lift-lams-known `` disables this restriction and enables lifting of
100
+ known functions.
101
+ #. Any function whose lifted form would have a higher arity than the available
102
+ number of registers for the function's calling convention. See flags
103
+ ``-fstg-lift-(non)rec-args(-any) ``
104
+ #. Any function whose lifted form will result in *closure grawth *. Closure
105
+ growth occurs when formerly free variables, that are now additional
106
+ arguments, did not previously occur in the closure, thereby increasing
107
+ allocations. This is especially bad for :term: `multi-shot ` lambdas which will
108
+ allocate many times.
76
109
77
110
78
111
Observing the Effect of Lambda Lifting
79
112
--------------------------------------
80
113
114
+ You may directly observe the effect of late lambda lifting by comparing Core to
115
+ STG when late lambda lifting is enabled. You can also directly disable or enable
116
+ late lambda lifting with the flags ``-f-stg-lift-lams `` and
117
+ ``-fno-stg-lift-lams ``. In general, lambda lifting performs the following
118
+ syntactic changes:
119
+
120
+ #. It eliminates a let binding.
121
+ #. It creates a new :term: `Top-level ` binding.
122
+ #. It replaces all occurrences of the lifted function in the let's body with a
123
+ partial application. For example, all occurrences of ``f `` are replaced with
124
+ ``$lf b `` in the let's body.
125
+ #. All non-top-level variables (i.e., free variables) in the let's body become
126
+ occurrences of parameters.
81
127
82
128
When to Manually Apply Lambda Lifting
83
129
-------------------------------------
84
130
85
-
131
+ tomorrow: update glossary, start here
86
132
87
133
88
134
Testing Exec
0 commit comments