[commit: ghc] wip/T11731: Used-once variables are not trivial (7ac5610)

git at git.haskell.org git at git.haskell.org
Wed Mar 30 10:54:53 UTC 2016


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

On branch  : wip/T11731
Link       : http://ghc.haskell.org/trac/ghc/changeset/7ac5610606e8f338cd2eb92eb5d711e054d9d55a/ghc

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

commit 7ac5610606e8f338cd2eb92eb5d711e054d9d55a
Author: Joachim Breitner <mail at joachim-breitner.de>
Date:   Wed Mar 30 12:55:10 2016 +0200

    Used-once variables are not trivial
    
    The specification for exprIsTrivial demands that we are unconditionally
    happy to duplicate the expression. This is not true for variables where
    we would like to exploit (or already have exploited) that they are used
    at most once. In order to preserve this property, they must not be
    duplicated nilly-willy. This fixes #11731 and comes with a test case.


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

7ac5610606e8f338cd2eb92eb5d711e054d9d55a
 compiler/coreSyn/CoreUtils.hs                      | 12 +++++++-
 testsuite/.gitignore                               |  1 +
 testsuite/tests/simplCore/should_run/T11731.hs     | 36 ++++++++++++++++++++++
 testsuite/tests/simplCore/should_run/T11731.stderr |  1 +
 testsuite/tests/simplCore/should_run/all.T         |  1 +
 5 files changed, 50 insertions(+), 1 deletion(-)

diff --git a/compiler/coreSyn/CoreUtils.hs b/compiler/coreSyn/CoreUtils.hs
index 1d9b83b..d02b934 100644
--- a/compiler/coreSyn/CoreUtils.hs
+++ b/compiler/coreSyn/CoreUtils.hs
@@ -62,6 +62,7 @@ import DataCon
 import PrimOp
 import Id
 import IdInfo
+import Demand ( isUsedOnce )
 import Type
 import Coercion
 import TyCon
@@ -755,6 +756,13 @@ Note [exprIsTrivial]
 
 Note [Variables are trivial]
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Variables are usually trivial.
+
+Except if 'isUsedOnce (idDemandInfo v) == True':
+In this case we have previously determined that a variable is used at most
+once, and we likely rely on this information, e.g. during code generation. In
+this case, we are not unconditionally happy to duplicate, so we don’t.  See #11731.
+
 There used to be a gruesome test for (hasNoBinding v) in the
 Var case:
         exprIsTrivial (Var v) | hasNoBinding v = idArity v == 0
@@ -793,7 +801,9 @@ it off at source.
 -}
 
 exprIsTrivial :: CoreExpr -> Bool
-exprIsTrivial (Var _)          = True        -- See Note [Variables are trivial]
+exprIsTrivial (Var v) -- See Note [Variables are trivial]
+  | isUsedOnce (idDemandInfo v) = False
+  | otherwise                  = True
 exprIsTrivial (Type _)         = True
 exprIsTrivial (Coercion _)     = True
 exprIsTrivial (Lit lit)        = litIsTrivial lit
diff --git a/testsuite/.gitignore b/testsuite/.gitignore
index 8926e4e..b578602 100644
--- a/testsuite/.gitignore
+++ b/testsuite/.gitignore
@@ -1474,6 +1474,7 @@ mk/ghcconfig*_test___spaces_ghc*.exe.mk
 /tests/simplCore/should_run/T5997
 /tests/simplCore/should_run/T7101
 /tests/simplCore/should_run/T7924
+/tests/simplCore/should_run/T11731
 /tests/simplCore/should_run/T9128
 /tests/simplCore/should_run/T9390
 /tests/simplCore/should_run/runST
diff --git a/testsuite/tests/simplCore/should_run/T11731.hs b/testsuite/tests/simplCore/should_run/T11731.hs
new file mode 100644
index 0000000..e148507
--- /dev/null
+++ b/testsuite/tests/simplCore/should_run/T11731.hs
@@ -0,0 +1,36 @@
+module Main (main ) where
+
+import Debug.Trace
+
+foo :: (a,b) -> a
+foo (x,y) = x
+{-# NOINLINE foo #-}
+
+wwMe :: Int -> (Int,Int) -> (Int, Int)
+wwMe 0 p =
+    let a = fst p
+        b = snd p
+        -- This ensure sharing of b, as seen by the demand analyzer
+
+    in foo p `seq`
+       -- This ensures that wwMe is strict in the tuple, but that the tuple
+       -- is preserved.
+       (b + a, a + b)
+
+wwMe n p = wwMe (n-1) (0,0)
+    -- ^ Make it recursive, so that it is attractive to worker-wrapper
+
+go :: Int -> IO ()
+go seed = do
+    let shareMeThunk = trace "Evaluated (should only happen once)" (seed + 1)
+        {-# NOINLINE shareMeThunk #-}
+        -- ^ This is the thunk that is wrongly evaluated twice.
+
+    let (x,y) = wwMe 0 (seed,shareMeThunk)
+
+    (x + y) `seq` return ()
+    -- ^ Use both components
+{-# NOINLINE go #-}
+
+main :: IO ()
+main = go 42
diff --git a/testsuite/tests/simplCore/should_run/T11731.stderr b/testsuite/tests/simplCore/should_run/T11731.stderr
new file mode 100644
index 0000000..8d1fc60
--- /dev/null
+++ b/testsuite/tests/simplCore/should_run/T11731.stderr
@@ -0,0 +1 @@
+Evaluated (should only happen once)
diff --git a/testsuite/tests/simplCore/should_run/all.T b/testsuite/tests/simplCore/should_run/all.T
index 9c15b0f..7fd1812 100644
--- a/testsuite/tests/simplCore/should_run/all.T
+++ b/testsuite/tests/simplCore/should_run/all.T
@@ -71,3 +71,4 @@ test('T9128', normal, compile_and_run, [''])
 test('T9390', normal, compile_and_run, [''])
 test('T10830', extra_run_opts('+RTS -K100k -RTS'), compile_and_run, [''])
 test('T11172', normal, compile_and_run, [''])
+test('T11731', normal, compile_and_run, ['-fspec-constr'])



More information about the ghc-commits mailing list