[GHC] #8091: retry# lacks strictness information
#8091: retry# lacks strictness information ------------------------------------+------------------------------------- Reporter: parcs | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 7.6.3 Keywords: | Operating System: Unknown/Multiple Architecture: Unknown/Multiple | Type of failure: None/Unknown Difficulty: Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | ------------------------------------+------------------------------------- The `retry#` primop should be marked as returning bottom since it never actually returns anything as far as the simplifier is concerned. This change would help the simplifier eliminate unreachable code inside STM transactions. -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/8091> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#8091: retry# lacks strictness information -------------------------------------+------------------------------------ Reporter: parcs | Owner: Type: bug | Status: patch Priority: normal | Milestone: Component: Compiler | Version: 7.6.3 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Unknown/Multiple Type of failure: None/Unknown | Difficulty: Unknown Test Case: | Blocked By: Blocking: | Related Tickets: -------------------------------------+------------------------------------ Changes (by parcs): * status: new => patch Comment: The patch (validated): {{{ #!diff diff --git a/compiler/prelude/primops.txt.pp b/compiler/prelude/primops.txt.pp index 3d3518b..e12c1a5 100644 --- a/compiler/prelude/primops.txt.pp +++ b/compiler/prelude/primops.txt.pp @@ -1614,6 +1614,7 @@ primop AtomicallyOp "atomically#" GenPrimOp primop RetryOp "retry#" GenPrimOp State# RealWorld -> (# State# RealWorld, a #) with + strictness = { \ _arity -> mkStrictSig (mkTopDmdType [topDmd] botRes) } out_of_line = True has_side_effects = True }}} The unfoldings in Control.Concurrent.STM.TSem and .TQueue are improved as a result of this change due to the aforementioned dead code elimination. -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/8091#comment:1> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#8091: retry# lacks strictness information -------------------------------------+------------------------------------ Reporter: parcs | Owner: Type: bug | Status: patch Priority: normal | Milestone: Component: Compiler | Version: 7.6.3 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Unknown/Multiple Type of failure: None/Unknown | Difficulty: Unknown Test Case: | Blocked By: Blocking: | Related Tickets: -------------------------------------+------------------------------------ Comment (by simonpj): I like the idea, but it does have strictness consequences too. For example: {{{ f :: TVar Int -> Int -> STM Int f r y = do { v <- readTVar r ; if v>0 then retry else if y>0 then return 0 else return y } }}} I have not checked but I think this will not be strict in y because the `then` branch doesn't evaluate y. With your change it'll become strict in y, just as it would if you replace `retry` with `throw exn`. I think that's probably fine, and no one will even notice; just saying. Simon -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/8091#comment:2> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#8091: retry# lacks strictness information -------------------------------------+------------------------------------ Reporter: parcs | Owner: Type: bug | Status: patch Priority: normal | Milestone: Component: Compiler | Version: 7.6.3 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Unknown/Multiple Type of failure: None/Unknown | Difficulty: Unknown Test Case: | Blocked By: Blocking: | Related Tickets: -------------------------------------+------------------------------------ Comment (by parcs): Ah, subtle.. But in this particular example , `f` seems to be lazy in `y` even when `retry` is replaced with `throw Overflow`: its strictness signature is `<S,1*U(U)><L,1*U(U)><L,U>` either way.. (It would be incorrect, I think, to have `f` strict in `y` since that could potentially elide the side-effect-having call to `readTVar`.) I found an example of a function whose strictness does change due to this patch (courtesy of the comments for `RaiseIOOp` in primops.txt.pp): {{{ #!haskell g :: Int -> Int -> STM Int g x y | x>0 = retry | y>0 = return 1 | otherwise = return 2 }}} This function is now strict in `y`, where it originally wasn't. It looks like this change will only have strictness implications in fairly contrived functions where `retry` is used in such a way that the transaction could not possibly make any progress; and in that case behaving as if `retry` returns bottom makes a good amount of sense. -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/8091#comment:3> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#8091: retry# lacks strictness information -------------------------------------+------------------------------------ Reporter: parcs | Owner: Type: bug | Status: patch Priority: normal | Milestone: Component: Compiler | Version: 7.6.3 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Unknown/Multiple Type of failure: None/Unknown | Difficulty: Unknown Test Case: | Blocked By: Blocking: | Related Tickets: -------------------------------------+------------------------------------ Comment (by parcs): To be clear, the form of dead code elimination that this change enables is replacing {{{ #!haskell case retry# s1 of (# s2, a #) -> ...inaccessible.. }}} with simply {{{ #!haskell retry# s1 }}} Such Core can appear after performing case-of-case on code like {{{ #!haskell s <- readTVar v when (s > 0) retry ... }}} where everything after the `when` statement might get inlined under the scrutinization of `retry`. -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/8091#comment:4> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#8091: retry# lacks strictness information -------------------------------------+------------------------------------ Reporter: parcs | Owner: Type: bug | Status: closed Priority: normal | Milestone: Component: Compiler | Version: 7.6.3 Resolution: fixed | Keywords: Operating System: Unknown/Multiple | Architecture: Unknown/Multiple Type of failure: None/Unknown | Difficulty: Unknown Test Case: | Blocked By: Blocking: | Related Tickets: -------------------------------------+------------------------------------ Changes (by thoughtpolice): * status: patch => closed * resolution: => fixed Comment: Thanks Patrick. Committed in {{{ commit e2b72cadce3ae799a74981f9957b40bb201f1ba1 Author: Austin Seipp <aseipp@pobox.com> Date: Sat Aug 10 22:39:15 2013 -0500 Mark retry# as returning bottom. This change helps the simplifier eliminate unreachable code, since retry# technically doesn't return. This closes ticket #8091. Authored-by: Patrick Palka <patrick@parcs.ath.cx> Signed-off-by: Austin Seipp <aseipp@pobox.com> }}} -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/8091#comment:5> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#8091: retry# lacks strictness information -------------------------------------+------------------------------------ Reporter: parcs | Owner: Type: bug | Status: closed Priority: normal | Milestone: Component: Compiler | Version: 7.6.3 Resolution: fixed | Keywords: Operating System: Unknown/Multiple | Architecture: Unknown/Multiple Type of failure: None/Unknown | Difficulty: Unknown Test Case: | Blocked By: Blocking: | Related Tickets: -------------------------------------+------------------------------------ Comment (by simonpj): I wonder if we might have a regression test here... Perhaps a `-ddump- simpl` and check that a function in the `...inaccessible...` part no longer appears? Simon -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/8091#comment:6> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#8091: retry# lacks strictness information -------------------------------------+------------------------------------- Reporter: parcs | Owner: (none) Type: bug | Status: closed Priority: normal | Milestone: Component: Compiler | Version: 7.6.3 Resolution: fixed | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by bgamari): #13916 leads me to believe this is strictness signature is too strong. Consider this program, {{{#!hs loop :: [TMVar a] -> STM a -> STM a loop [] m = m loop (x:xs) m = loop xs (m `orElse` takeTMVar x) doIt :: [TMVar Int] -> STM Int doIt xs = atomically $ loop xs retry }}} GHC will currently give `loop` a strictness signature of `<S,1*U><C(S),1*C1(U(U,U))>`. So this means that if we give `retry#` a divergent result demand GHC incorrectly assume that `loop xs retry` will itself diverge, which is clearly not true. -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/8091#comment:7> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#8091: retry# lacks strictness information -------------------------------------+------------------------------------- Reporter: parcs | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 7.6.3 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Changes (by bgamari): * status: closed => new * resolution: fixed => -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/8091#comment:8> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#8091: retry# lacks strictness information -------------------------------------+------------------------------------- Reporter: parcs | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 7.6.3 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by bgamari): Actually, comment:7 isn't quite right: The fact that `loop` doesn't diverge should be accounted for by the `ExnStr` of the first argument of `orElse`. I would have thought that the `ExnStr` should propagate to the second argument of `loop` during demand analysis but it doesn't. That seems to be the issue. -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/8091#comment:9> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#8091: retry# lacks strictness information -------------------------------------+------------------------------------- Reporter: parcs | Owner: (none) Type: bug | Status: closed Priority: normal | Milestone: Component: Compiler | Version: 7.6.3 Resolution: fixed | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Changes (by bgamari): * status: new => closed * resolution: => fixed Comment: It turns out that the root cause was #13977, which was fixed by Phab:D3756. Closing. -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/8091#comment:10> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#8091: retry# lacks strictness information -------------------------------------+------------------------------------- Reporter: parcs | Owner: (none) Type: bug | Status: closed Priority: normal | Milestone: Component: Compiler | Version: 7.6.3 Resolution: fixed | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by simonpj): Do we have a regression test? -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/8091#comment:11> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#8091: retry# lacks strictness information -------------------------------------+------------------------------------- Reporter: parcs | Owner: (none) Type: bug | Status: closed Priority: normal | Milestone: Component: Compiler | Version: 7.6.3 Resolution: fixed | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by bgamari): Do you mean for #13977? I intend on adding the case from #13916 to the testsuite. It's imperfect but better than nothing. -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/8091#comment:12> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#8091: retry# lacks strictness information -------------------------------------+------------------------------------- Reporter: parcs | Owner: (none) Type: bug | Status: closed Priority: normal | Milestone: Component: Compiler | Version: 7.6.3 Resolution: fixed | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by Ben Gamari <ben@…>): In [changeset:"10a1a4781c646f81ca9e2ef7a2585df2cbe3a014/ghc" 10a1a47/ghc]: {{{ #!CommitTicketReference repository="ghc" revision="10a1a4781c646f81ca9e2ef7a2585df2cbe3a014" Model divergence of retry# as ThrowsExn, not Diverges The demand signature of the retry# primop previously had a Diverges result. However, this caused the demand analyser to conclude that a program of the shape, catchRetry# (... >> retry#) would diverge. Of course, this is plainly wrong; catchRetry#'s sole reason to exist is to "catch" the "exception" thrown by retry#. While catchRetry#'s demand signature correctly had the ExnStr flag set on its first argument, indicating that it should catch divergence, the logic associated with this flag doesn't apply to Diverges results. This resulted in #14171. The solution here is to treat the divergence of retry# as an exception. Namely, give it a result type of ThrowsExn rather than Diverges. Updates stm submodule for tests. Test Plan: Validate with T14171 Reviewers: simonpj, austin Subscribers: rwbarton, thomie GHC Trac Issues: #14171, #8091 Differential Revision: https://phabricator.haskell.org/D3919 }}} -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/8091#comment:13> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
participants (1)
-
GHC