[commit: ghc] wip/nested-cpr: Note [Recursion and nested cpr] and test case (4b2d6b7)

git at git.haskell.org git at git.haskell.org
Tue Jan 21 15:33:41 UTC 2014


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

On branch  : wip/nested-cpr
Link       : http://ghc.haskell.org/trac/ghc/changeset/4b2d6b71502c270701660ae36710e52be06913d2/ghc

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

commit 4b2d6b71502c270701660ae36710e52be06913d2
Author: Joachim Breitner <mail at joachim-breitner.de>
Date:   Tue Jan 21 13:56:14 2014 +0000

    Note [Recursion and nested cpr] and test case
    
    the reason why we remove the converging flag of LoopBreakers is actually
    non-obvious, and has little to do with the termination analysis per se.
    Document that with an extensive note and guard it with two test cases.


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

4b2d6b71502c270701660ae36710e52be06913d2
 compiler/stranal/DmdAnal.lhs                       |   40 ++++++++++++++++++++
 testsuite/tests/stranal/should_run/Stream.hs       |   13 +++++++
 testsuite/tests/stranal/should_run/all.T           |    1 +
 testsuite/tests/stranal/sigs/StreamSig.hs          |   11 ++++++
 .../{InfiniteCPRDepth0.stderr => StreamSig.stderr} |    2 +-
 testsuite/tests/stranal/sigs/all.T                 |    1 +
 6 files changed, 67 insertions(+), 1 deletion(-)

diff --git a/compiler/stranal/DmdAnal.lhs b/compiler/stranal/DmdAnal.lhs
index cf372ca..f302744 100644
--- a/compiler/stranal/DmdAnal.lhs
+++ b/compiler/stranal/DmdAnal.lhs
@@ -1160,6 +1160,7 @@ extendAnalEnv top_lvl env var sig
   = env { ae_sigs = extendSigEnv top_lvl (ae_sigs env) var sig' }
   where
   sig' | isWeakLoopBreaker (idOccInfo var) = sigMayDiverge sig
+             -- ^ Note [Recursion and nested CPR]
        | isUnLiftedType (idType var)       = convergeSig sig
        | otherwise                         = sig
 
@@ -1283,3 +1284,42 @@ of the Id, and start from "bottom".  Nowadays the Id can have a current
 strictness, because interface files record strictness for nested bindings.
 To know when we are in the first iteration, we look at the ae_virgin
 field of the AnalEnv.
+
+Note [Recursion and nested cpr]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In extendAnalEnv, we remove possible definite convergence information from loop
+breakers.
+
+This is *not* required to make termination analysis sound: It would be fine
+without this, since we initialize the fixed point iteration with definite
+divergence, and this is sufficient to make sure that, for example, a
+tail-recursive function is not going to be considered terminating.
+
+But we need to do it to avoid the nested CPR w/w-transformation from going
+horribly wrong. Consider this code (also in tests/stranal/sigs/StreamSig.hs):
+
+    data Stream a = Stream a (Stream a)
+    forever :: a -> Stream a
+    forever x = Stream x (forever x)
+
+This should deserve a CPR information of
+
+   tm(,tm(,))
+
+(or deeper, as you wish) because clearly it terminates arbitrarily deep. But if
+we gave it that signature, we would generate the following worker:
+
+  $wforever x = case $wforever x of
+    (# ww1, ww2, ww3 #) -> (# x, ww1, Stream ww2 ww3 #)
+
+which will obviously diverge. By killing the convergence flag for loop breakers
+we ensure that the CPR information is
+
+   tm(,m(,))
+
+and the worker is
+
+  $wforever x = (# x, case $wforever x of (# a, b#) -> Stream a b #)
+
+which is fine (and will later be further simplified).
diff --git a/testsuite/tests/stranal/should_run/Stream.hs b/testsuite/tests/stranal/should_run/Stream.hs
new file mode 100644
index 0000000..5e3555c
--- /dev/null
+++ b/testsuite/tests/stranal/should_run/Stream.hs
@@ -0,0 +1,13 @@
+-- Adapted from symalg/RealM.hs's treeFrom
+
+data Stream a = Stream a (Stream a)
+
+-- This must not get a CPR signature that allows for nested cpr,
+-- as it would make the worker call itself before producing the
+-- Stream constructor.
+
+forever :: a -> Stream a
+forever x = Stream x (forever x)
+
+main :: IO ()
+main = forever () `seq` return ()
diff --git a/testsuite/tests/stranal/should_run/all.T b/testsuite/tests/stranal/should_run/all.T
index 0c43aac..e8e51de 100644
--- a/testsuite/tests/stranal/should_run/all.T
+++ b/testsuite/tests/stranal/should_run/all.T
@@ -7,3 +7,4 @@ test('strun003', normal, compile_and_run, [''])
 test('strun004', normal, compile_and_run, [''])
 test('T2756b', normal, compile_and_run, [''])
 test('T7649', normal, compile_and_run, [''])
+test('Stream', extra_run_opts('+RTS -M1M -RTS'), compile_and_run, [''])
diff --git a/testsuite/tests/stranal/sigs/StreamSig.hs b/testsuite/tests/stranal/sigs/StreamSig.hs
new file mode 100644
index 0000000..78269d8
--- /dev/null
+++ b/testsuite/tests/stranal/sigs/StreamSig.hs
@@ -0,0 +1,11 @@
+module StreamSig where
+-- Adapted from symalg/RealM.hs's treeFrom
+
+data Stream a = Stream a (Stream a)
+
+-- This must not get a CPR signature that allows for nested cpr,
+-- as it would make the worker call itself before producing the
+-- Stream constructor.
+
+forever :: a -> Stream a
+forever x = Stream x (forever x)
diff --git a/testsuite/tests/stranal/sigs/InfiniteCPRDepth0.stderr b/testsuite/tests/stranal/sigs/StreamSig.stderr
similarity index 63%
copy from testsuite/tests/stranal/sigs/InfiniteCPRDepth0.stderr
copy to testsuite/tests/stranal/sigs/StreamSig.stderr
index 63ca4b6..9d3bf3a 100644
--- a/testsuite/tests/stranal/sigs/InfiniteCPRDepth0.stderr
+++ b/testsuite/tests/stranal/sigs/StreamSig.stderr
@@ -1,5 +1,5 @@
 
 ==================== Strictness signatures ====================
-InfiniteCPR.f: <L,U>
+StreamSig.forever: <L,U>tm(,m(,m(,)))
 
 
diff --git a/testsuite/tests/stranal/sigs/all.T b/testsuite/tests/stranal/sigs/all.T
index e81a2ab..a193e90 100644
--- a/testsuite/tests/stranal/sigs/all.T
+++ b/testsuite/tests/stranal/sigs/all.T
@@ -18,3 +18,4 @@ test('InfiniteCPR', normal, compile, [''])
 test('InfiniteCPRDepth0', normal, compile, [''])
 test('InfiniteCPRDepth1', normal, compile, [''])
 test('AnonLambda', normal, compile, [''])
+test('StreamSig', normal, compile, [''])



More information about the ghc-commits mailing list