summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsimonpj@microsoft.com <unknown>2008-09-17 16:27:04 +0000
committersimonpj@microsoft.com <unknown>2008-09-17 16:27:04 +0000
commit0ac253aac15a6d5bcfa54be310531203a5456a0a (patch)
tree278918f37f3314cd6b1be1984ed65c62c72cc1c9
parenta211dd24b1149cf3bc5262f775f63e4d1c9b60ce (diff)
downloadhaskell-0ac253aac15a6d5bcfa54be310531203a5456a0a.tar.gz
Avoid arity reduction when doing eta-reduce
We like things with high arity, so when doing eta reduction it's probably a good idea to avoid reducing arity.
-rw-r--r--compiler/simplCore/SimplUtils.lhs31
1 files changed, 22 insertions, 9 deletions
diff --git a/compiler/simplCore/SimplUtils.lhs b/compiler/simplCore/SimplUtils.lhs
index 1fdde7f209..d697fb32dd 100644
--- a/compiler/simplCore/SimplUtils.lhs
+++ b/compiler/simplCore/SimplUtils.lhs
@@ -934,10 +934,16 @@ There are some particularly delicate points here:
So it's important to to the right thing.
-* We need to be careful if we just look at f's arity. Currently (Dec07),
- f's arity is visible in its own RHS (see Note [Arity robustness] in
- SimplEnv) so we must *not* trust the arity when checking that 'f' is
- a value. Instead, look at the unfolding.
+* Note [Arity care]: we need to be careful if we just look at f's
+ arity. Currently (Dec07), f's arity is visible in its own RHS (see
+ Note [Arity robustness] in SimplEnv) so we must *not* trust the
+ arity when checking that 'f' is a value. Otherwise we will
+ eta-reduce
+ f = \x. f x
+ to
+ f = f
+ Which might change a terminiating program (think (f `seq` e)) to a
+ non-terminating one. So we check for being a loop breaker first.
However for GlobalIds we can look at the arity; and for primops we
must, since they have no unfolding.
@@ -950,6 +956,11 @@ There are some particularly delicate points here:
with both type and dictionary lambdas; hence the slightly
ad-hoc isDictId
+* Never *reduce* arity. For example
+ f = \xy. g x y
+ Then if h has arity 1 we don't want to eta-reduce because then
+ f's arity would decrease, and that is bad
+
These delicacies are why we don't use exprIsTrivial and exprIsHNF here.
Alas.
@@ -958,6 +969,8 @@ tryEtaReduce :: [OutBndr] -> OutExpr -> Maybe OutExpr
tryEtaReduce bndrs body
= go (reverse bndrs) body
where
+ incoming_arity = count isId bndrs
+
go (b : bs) (App fun arg) | ok_arg b arg = go bs fun -- Loop round
go [] fun | ok_fun fun = Just fun -- Success!
go _ _ = Nothing -- Failure!
@@ -971,11 +984,11 @@ tryEtaReduce bndrs body
&& (ok_fun_id fun_id || all ok_lam bndrs)
ok_fun _fun = False
- ok_fun_id fun
- | isLocalId fun = isEvaldUnfolding (idUnfolding fun)
- | isDataConWorkId fun = True
- | isGlobalId fun = idArity fun > 0
- | otherwise = panic "tryEtaReduce/ok_fun_id"
+ ok_fun_id fun = fun_arity fun >= incoming_arity
+
+ fun_arity fun -- See Note [Arity care]
+ | isLocalId fun && isLoopBreaker (idOccInfo fun) = 0
+ | otherwise = idArity fun
ok_lam v = isTyVar v || isDictId v