summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArnaud Spiwack <arnaud.spiwack@tweag.io>2019-04-26 17:58:52 +0200
committerArnaud Spiwack <arnaud.spiwack@tweag.io>2019-07-15 09:23:15 +0200
commit0670f98adafdc863bc51b59b276668cfef60b365 (patch)
treea68e0569c857a295e1a100f3d752e542a9ccf933
parenta39a3cd663273c46cf4e346ddf3bf9fb39195c9d (diff)
downloadhaskell-0670f98adafdc863bc51b59b276668cfef60b365.tar.gz
Add a note in the simplifier about in-scope set as a substitution
See also the discussion at #16592
-rw-r--r--compiler/basicTypes/VarEnv.hs11
-rw-r--r--compiler/simplCore/SimplEnv.hs4
-rw-r--r--compiler/simplCore/Simplify.hs35
3 files changed, 45 insertions, 5 deletions
diff --git a/compiler/basicTypes/VarEnv.hs b/compiler/basicTypes/VarEnv.hs
index b2ab8d8b1a..0daaaea0d1 100644
--- a/compiler/basicTypes/VarEnv.hs
+++ b/compiler/basicTypes/VarEnv.hs
@@ -98,10 +98,13 @@ import Outputable
-- "Secrets of the Glasgow Haskell Compiler inliner" Section 3.2 provides
-- the motivation for this abstraction.
data InScopeSet = InScope VarSet {-# UNPACK #-} !Int
- -- We store a VarSet here, but we use this for lookups rather than
- -- just membership tests. Typically the InScopeSet contains the
- -- canonical version of the variable (e.g. with an informative
- -- unfolding), so this lookup is useful.
+ -- Note [Lookups in in-scope set]
+ -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ -- We store a VarSet here, but we use this for lookups rather than just
+ -- membership tests. Typically the InScopeSet contains the canonical
+ -- version of the variable (e.g. with an informative unfolding), so this
+ -- lookup is useful (see, for instance, Note [In-scope set as a
+ -- substitution]).
--
-- The Int is a kind of hash-value used by uniqAway
-- For example, it might be the size of the set
diff --git a/compiler/simplCore/SimplEnv.hs b/compiler/simplCore/SimplEnv.hs
index 1d55f359fa..a17d6b4bda 100644
--- a/compiler/simplCore/SimplEnv.hs
+++ b/compiler/simplCore/SimplEnv.hs
@@ -667,7 +667,9 @@ substId (SimplEnv { seInScope = in_scope, seIdSubst = ids }) v
-- Get the most up-to-date thing from the in-scope set
-- Even though it isn't in the substitution, it may be in
- -- the in-scope set with better IdInfo
+ -- the in-scope set with better IdInfo.
+ --
+ -- See also Note [In-scope set as a substitution] in Simplify.
refineFromInScope :: InScopeSet -> Var -> Var
refineFromInScope in_scope v
diff --git a/compiler/simplCore/Simplify.hs b/compiler/simplCore/Simplify.hs
index c6bd413c51..6e13ddf59b 100644
--- a/compiler/simplCore/Simplify.hs
+++ b/compiler/simplCore/Simplify.hs
@@ -118,6 +118,40 @@ 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.
+Note [In-scope set as a substitution]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+As per Note [Lookups in in-scope set], an in-scope set can act as
+a substitution. Specifically, it acts as a substitution from variable to
+variables /with the same unique/.
+
+Why do we need this? Well, during the course of the simplifier, we may want to
+adjust inessential properties of a variable. For instance, when performing a
+beta-reduction, we change
+
+ (\x. e) u ==> let x = u in e
+
+We typically want to add an unfolding to `x` so that it inlines to (the
+simplification of) `u`.
+
+We do that by adding the unfolding to the binder `x`, which is added to the
+in-scope set. When simplifying occurrences of `x` (every occurrence!), they are
+replaced by their “updated” version from the in-scope set, hence inherit the
+unfolding. This happens in `SimplEnv.substId`.
+
+Another example. Consider
+
+ case x of y { Node a b -> ...y...
+ ; Leaf v -> ...y... }
+
+In the Node branch want y's unfolding to be (Node a b); in the Leaf branch we
+want y's unfolding to be (Leaf v). We achieve this by adding the appropriate
+unfolding to y, and re-adding it to the in-scope set. See the calls to
+`addBinderUnfolding` in `Simplify.addAltUnfoldings` and elsewhere.
+
+It's quite convenient. This way we don't need to manipulate the substitution all
+the time: every update to a binder is automatically reflected to its bound
+occurrences.
+
************************************************************************
* *
\subsection{Bindings}
@@ -659,6 +693,7 @@ completeBind env top_lvl mb_cont old_bndr new_bndr new_rhs
final_rhs (idType new_bndr) old_unf
; let final_bndr = addLetBndrInfo new_bndr new_arity is_bot new_unfolding
+ -- See Note [In-scope set as a substitution]
; if postInlineUnconditionally env top_lvl final_bndr occ_info final_rhs