[commit: ghc] master: Allow CaseElim if the case binder is the next thing to be eval'd (35f1fc9)
Simon Peyton Jones
simonpj at microsoft.com
Fri Jan 25 13:50:27 CET 2013
Repository : ssh://darcs.haskell.org//srv/darcs/ghc
On branch : master
http://hackage.haskell.org/trac/ghc/changeset/35f1fc957d152c520c90c6bd2330266e57578eb2
>---------------------------------------------------------------
commit 35f1fc957d152c520c90c6bd2330266e57578eb2
Author: Simon Peyton Jones <simonpj at microsoft.com>
Date: Tue Jan 22 22:46:33 2013 +0000
Allow CaseElim if the case binder is the next thing to be eval'd
This makes CaseElim happen a bit more often.
See Note [Case binder next] in Simplify.
This came up when investigating Trac #7542.
>---------------------------------------------------------------
compiler/simplCore/Simplify.lhs | 32 ++++++++++++++++++++++++++------
1 files changed, 26 insertions(+), 6 deletions(-)
diff --git a/compiler/simplCore/Simplify.lhs b/compiler/simplCore/Simplify.lhs
index 246c5b3..d3688f5 100644
--- a/compiler/simplCore/Simplify.lhs
+++ b/compiler/simplCore/Simplify.lhs
@@ -1677,15 +1677,23 @@ not want to transform to
in blah
because that builds an unnecessary thunk.
-We used also to do case elimination if
- (c) the scrutinee is a variable and 'x' is used strictly
-But that changes
+Note [Case binder next]
+~~~~~~~~~~~~~~~~~~~~~~~
+If we have
+ case e of f { _ -> f e1 e2 }
+then we can safely do CaseElim. The main criterion is that the
+case-binder is evaluated *next*. Previously we just asked that
+the case-binder is used strictly; but that can change
case x of { _ -> error "bad" }
--> error "bad"
which is very puzzling if 'x' is later bound to (error "good").
Where the order of evaluation is specified (via seq or case)
-we should respect it. See also
-Note [Empty case alternatives] in CoreSyn.
+we should respect it.
+See also Note [Empty case alternatives] in CoreSyn.
+
+So instead we use case_bndr_evald_next to see when f is the *next*
+thing to be eval'd. This came up when fixing Trac #7542.
+See also Note [Eta reduction of an eval'd function] in CoreUtils.
For reference, the old code was an extra disjunct in elim_lifted
|| (strict_case_bndr && scrut_is_var scrut)
@@ -1694,6 +1702,8 @@ Note [Empty case alternatives] in CoreSyn.
scrut_is_var (Var _) = True
scrut_is_var _ = False
+ -- True if evaluation of the case_bndr is the next
+ -- thing to be eval'd. Then dropping the case
Note [Case elimination: unlifted case]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1818,12 +1828,13 @@ rebuildCase env scrut case_bndr [(_, bndrs, rhs)] cont
= exprIsHNF scrut
|| (is_plain_seq && ok_for_spec)
-- Note: not the same as exprIsHNF
+ || case_bndr_evald_next rhs
elim_unlifted
| is_plain_seq = exprOkForSideEffects scrut
-- The entire case is dead, so we can drop it,
-- _unless_ the scrutinee has side effects
- | otherwise = exprOkForSpeculation scrut
+ | otherwise = ok_for_spec
-- The case-binder is alive, but we may be able
-- turn the case into a let, if the expression is ok-for-spec
-- See Note [Case elimination: unlifted case]
@@ -1831,6 +1842,15 @@ rebuildCase env scrut case_bndr [(_, bndrs, rhs)] cont
ok_for_spec = exprOkForSpeculation scrut
is_plain_seq = isDeadBinder case_bndr -- Evaluation *only* for effect
+ case_bndr_evald_next :: CoreExpr -> Bool
+ -- See Note [Case binder next]
+ case_bndr_evald_next (Var v) = v == case_bndr
+ case_bndr_evald_next (Cast e _) = case_bndr_evald_next e
+ case_bndr_evald_next (App e _) = case_bndr_evald_next e
+ case_bndr_evald_next (Case e _ _ _) = case_bndr_evald_next e
+ case_bndr_evald_next _ = False
+ -- Could add a case for Let,
+ -- but I'm worried it could become expensive
--------------------------------------------------
-- 3. Try seq rules; see Note [User-defined RULES for seq] in MkId
More information about the ghc-commits
mailing list