Skip to content

Commit 8547c4e

Browse files
author
doyougnu
committed
lambda lifting: add GHC specific details
1 parent 7d47178 commit 8547c4e

File tree

1 file changed

+48
-2
lines changed

1 file changed

+48
-2
lines changed

src/Optimizations/GHC_opt/lambda_lifting.rst

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,17 +72,63 @@ default method GHC uses for handling local functions and free variables.
7272
Instead, GHC uses an alternative strategy called :term:`Closure Conversion`,
7373
which creates more uniformity at the cost of extra heap allocation.
7474

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.
76109

77110

78111
Observing the Effect of Lambda Lifting
79112
--------------------------------------
80113

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.
81127

82128
When to Manually Apply Lambda Lifting
83129
-------------------------------------
84130

85-
131+
tomorrow: update glossary, start here
86132

87133

88134
Testing Exec

0 commit comments

Comments
 (0)