[commit: ghc] master: Be a bit more aggressive about let-to-case (0e6d42f)

git at git.haskell.org git at git.haskell.org
Wed Sep 12 14:08:44 UTC 2018


Repository : ssh://git@git.haskell.org/ghc

On branch  : master
Link       : http://ghc.haskell.org/trac/ghc/changeset/0e6d42fe76958648243f99c49e648769c1ea658c/ghc

>---------------------------------------------------------------

commit 0e6d42fe76958648243f99c49e648769c1ea658c
Author: Simon Peyton Jones <simonpj at microsoft.com>
Date:   Wed Sep 12 13:06:53 2018 +0100

    Be a bit more aggressive about let-to-case
    
    This patch takes up the missed opportunity described in
    Trac #15631, by convering a case into a let slightly
    more agressively. See Simplify.hs
    Note [Case-to-let for strictly-used binders]
    
    There is no measurable perf impact for good or ill. But
    the code is simpler and easier to explain.


>---------------------------------------------------------------

0e6d42fe76958648243f99c49e648769c1ea658c
 compiler/simplCore/Simplify.hs                     | 52 +++++++++++++++-------
 testsuite/tests/simplCore/should_compile/Makefile  |  5 +++
 testsuite/tests/simplCore/should_compile/T15631.hs | 11 +++++
 .../tests/simplCore/should_compile/T15631.stdout   |  7 +++
 testsuite/tests/simplCore/should_compile/all.T     |  5 ++-
 5 files changed, 62 insertions(+), 18 deletions(-)

diff --git a/compiler/simplCore/Simplify.hs b/compiler/simplCore/Simplify.hs
index c8870c9..e359c43 100644
--- a/compiler/simplCore/Simplify.hs
+++ b/compiler/simplCore/Simplify.hs
@@ -2247,7 +2247,7 @@ We treat the unlifted and lifted cases separately:
   However, we can turn the case into a /strict/ let if the 'r' is
   used strictly in the body.  Then we won't lose divergence; and
   we won't build a thunk because the let is strict.
-  See also Note [Eliminating redundant seqs]
+  See also Note [Case-to-let for strictly-used binders]
 
   NB: absentError satisfies exprIsHNF: see Note [aBSENT_ERROR_ID] in MkCore.
   We want to turn
@@ -2256,13 +2256,18 @@ We treat the unlifted and lifted cases separately:
      let r = absentError "foo" in ...MkT r...
 
 
-Note [Eliminating redundant seqs]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Note [Case-to-let for strictly-used binders]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 If we have this:
-   case x of r { _ -> ..r.. }
-where 'r' is used strictly in (..r..), the case is effectively a 'seq'
-on 'x', but since 'r' is used strictly anyway, we can safely transform to
-   (...x...)
+   case <scrut> of r { _ -> ..r.. }
+
+where 'r' is used strictly in (..r..), we can safely transform to
+   let r = <scrut> in ...r...
+
+This is a Good Thing, because 'r' might be dead (if the body just
+calls error), or might be used just once (in which case it can be
+inlined); or we might be able to float the let-binding up or down.
+E.g. Trac #15631 has an example.
 
 Note that this can change the error behaviour.  For example, we might
 transform
@@ -2278,7 +2283,24 @@ transformation bit us in practice.
 
 See also Note [Empty case alternatives] in CoreSyn.
 
-Just for reference, the original code (added Jan 13) looked like this:
+Historical notes
+
+There have been various earlier versions of this patch:
+
+* By Sept 18 the code looked like this:
+     || scrut_is_demanded_var scrut
+
+    scrut_is_demanded_var :: CoreExpr -> Bool
+    scrut_is_demanded_var (Cast s _) = scrut_is_demanded_var s
+    scrut_is_demanded_var (Var _)    = isStrictDmd (idDemandInfo case_bndr)
+    scrut_is_demanded_var _          = False
+
+  This only fired if the scrutinee was a /variable/, which seems
+  an unnecessary restriction. So in Trac #15631 I relaxed it to allow
+  arbitrary scrutinees.  Less code, less to explain -- but the change
+  had 0.00% effect on nofib.
+
+* Previously, in Jan 13 the code looked like this:
      || case_bndr_evald_next rhs
 
     case_bndr_evald_next :: CoreExpr -> Bool
@@ -2289,8 +2311,8 @@ Just for reference, the original code (added Jan 13) looked like this:
     case_bndr_evald_next (Case e _ _ _)  = case_bndr_evald_next e
     case_bndr_evald_next _               = False
 
-(This came up when fixing Trac #7542. See also Note [Eta reduction of
-an eval'd function] in CoreUtils.)
+  This patch was part of fixing Trac #7542. See also
+  Note [Eta reduction of an eval'd function] in CoreUtils.)
 
 
 Further notes about case elimination
@@ -2405,7 +2427,7 @@ rebuildCase env scrut case_bndr alts@[(_, bndrs, rhs)] cont
   | all_dead_bndrs
   , if isUnliftedType (idType case_bndr)
     then exprOkForSpeculation scrut
-    else exprIsHNF scrut || scrut_is_demanded_var scrut
+    else exprIsHNF scrut || case_bndr_is_demanded
   = do { tick (CaseElim case_bndr)
        ; (floats1, env') <- simplNonRecX env case_bndr scrut
        ; (floats2, expr') <- simplExprF env' rhs cont
@@ -2424,12 +2446,8 @@ rebuildCase env scrut case_bndr alts@[(_, bndrs, rhs)] cont
     all_dead_bndrs = all isDeadBinder bndrs       -- bndrs are [InId]
     is_plain_seq   = all_dead_bndrs && isDeadBinder case_bndr -- Evaluation *only* for effect
 
-    scrut_is_demanded_var :: CoreExpr -> Bool
-            -- See Note [Eliminating redundant seqs]
-    scrut_is_demanded_var (Cast s _) = scrut_is_demanded_var s
-    scrut_is_demanded_var (Var _)    = isStrictDmd (idDemandInfo case_bndr)
-    scrut_is_demanded_var _          = False
-
+    case_bndr_is_demanded = isStrictDmd (idDemandInfo case_bndr)
+    -- See Note [Case-to-let for strictly-used binders]
 
 rebuildCase env scrut case_bndr alts cont
   = reallyRebuildCase env scrut case_bndr alts cont
diff --git a/testsuite/tests/simplCore/should_compile/Makefile b/testsuite/tests/simplCore/should_compile/Makefile
index 1233b8c..277a5a6 100644
--- a/testsuite/tests/simplCore/should_compile/Makefile
+++ b/testsuite/tests/simplCore/should_compile/Makefile
@@ -246,3 +246,8 @@ T14140:
 	$(RM) -f T14140.o T14140.hi
 	-'$(TEST_HC)' $(TEST_HC_OPTS) -O -c -ddump-simpl T14140.hs | grep '[2-9]# *->'
 # Expecting no output from the grep, hence "-"
+
+T15631:
+	$(RM) -f T15631.o T15631.hi
+	'$(TEST_HC)' $(TEST_HC_OPTS) -O -c -ddump-simpl -dsuppress-uniques T15631.hs | grep 'case'
+# Expecting one fewwer case expressions after fixing Trac #15631
diff --git a/testsuite/tests/simplCore/should_compile/T15631.hs b/testsuite/tests/simplCore/should_compile/T15631.hs
new file mode 100644
index 0000000..55f6758
--- /dev/null
+++ b/testsuite/tests/simplCore/should_compile/T15631.hs
@@ -0,0 +1,11 @@
+{-# Language PartialTypeSignatures, RankNTypes #-}
+
+module Foo where
+
+f xs = let ys = reverse xs
+       in ys `seq`
+          let w = length xs
+          in w + length (reverse (case ys of { a:as -> as; [] -> [] }))
+
+
+
diff --git a/testsuite/tests/simplCore/should_compile/T15631.stdout b/testsuite/tests/simplCore/should_compile/T15631.stdout
new file mode 100644
index 0000000..5a096f2
--- /dev/null
+++ b/testsuite/tests/simplCore/should_compile/T15631.stdout
@@ -0,0 +1,7 @@
+      case GHC.List.$wlenAcc
+      case GHC.List.$wlenAcc @ a w 0# of ww2 { __DEFAULT ->
+      case GHC.List.reverse1 @ a w (GHC.Types.[] @ a) of {
+        [] -> case Foo.f1 @ a of { GHC.Types.I# v1 -> GHC.Prim.+# ww2 v1 };
+          case GHC.List.$wlenAcc
+                 case Foo.$wf @ a w of ww [Occ=Once] { __DEFAULT ->
+      case Foo.$wf @ a w of ww { __DEFAULT -> GHC.Types.I# ww }
diff --git a/testsuite/tests/simplCore/should_compile/all.T b/testsuite/tests/simplCore/should_compile/all.T
index 1284b7c..d572d04 100644
--- a/testsuite/tests/simplCore/should_compile/all.T
+++ b/testsuite/tests/simplCore/should_compile/all.T
@@ -322,4 +322,7 @@ test('T15517', normal, compile, ['-O0'])
 test('T15517a', normal, compile, ['-O0'])
 test('T15453', normal, compile, ['-dcore-lint -O1'])
 test('T15445', normal, multimod_compile, ['T15445', '-v0 -O -ddump-rule-firings'])
-
+test('T15631',
+     normal,
+     run_command,
+     ['$MAKE -s --no-print-directory T15631'])



More information about the ghc-commits mailing list