diff --git a/compiler/GHC/Core/Opt/ConstantFold.hs b/compiler/GHC/Core/Opt/ConstantFold.hs index 21e8a5eabd5a757660d0bdd66c20ff230072e296..b295a70b0a67341e0bd417f944f4dfc8822434b8 100644 --- a/compiler/GHC/Core/Opt/ConstantFold.hs +++ b/compiler/GHC/Core/Opt/ConstantFold.hs @@ -2067,21 +2067,18 @@ unsafeEqualityProofRule {- ********************************************************************* * * - Rules for seq# and spark# + Rules for spark# * * ********************************************************************* -} -seqRule :: RuleM CoreExpr -seqRule = do +-- spark# :: forall a s . a -> State# s -> (# State# s, a #) +sparkRule :: RuleM CoreExpr +sparkRule = do -- reduce on HNF [Type _ty_a, Type _ty_s, a, s] <- getArgs guard $ exprIsHNF a return $ mkCoreUnboxedTuple [s, a] - --- spark# :: forall a s . a -> State# s -> (# State# s, a #) -sparkRule :: RuleM CoreExpr -sparkRule = seqRule -- reduce on HNF, just the same - -- XXX perhaps we shouldn't do this, because a spark eliminated by - -- this rule won't be counted as a dud at runtime? + -- XXX perhaps we shouldn't do this, because a spark eliminated by + -- this rule won't be counted as a dud at runtime? {- ************************************************************************ @@ -2158,9 +2155,7 @@ builtinRules platform <- getPlatform return $ Var (primOpId IntAndOp) `App` arg `App` mkIntVal platform (d - 1) - ], - - mkBasicRule seqHashName 4 seqRule + ] ] ++ builtinBignumRules {-# NOINLINE builtinRules #-} diff --git a/compiler/GHC/CoreToStg/Prep.hs b/compiler/GHC/CoreToStg/Prep.hs index 7add9fd9bfb4d08276f767e44a99c6250ba3ee77..564c199316c41cc35e0a8039df61e3bec08b30c0 100644 --- a/compiler/GHC/CoreToStg/Prep.hs +++ b/compiler/GHC/CoreToStg/Prep.hs @@ -890,6 +890,29 @@ cpeRhsE env (Case scrut bndr _ alts@[Alt con [covar] _]) floats = snocFloat floats_scrut case_float `appFloats` floats_rhs ; return (floats, rhs) } +cpeRhsE env (Case scrut bndr _ [Alt (DataAlt dc) [token_out, res] rhs]) + -- See item (SEQ4) of Note [seq# magic]. We want to match + -- case seq# @a @RealWorld <ok-to-discard> s of (# s', _ #) -> rhs[s'] + -- and simplify to rhs[s]. Triggers in T15226. + | isUnboxedTupleDataCon dc + , (Var f,[_ty1, _ty2, arg, Var token_in]) <- collectArgs scrut + , f `hasKey` seqHashKey + , exprOkToDiscard arg + -- ok-to-discard, because we want to discard the evaluation of `arg`. + -- ok-to-discard includes ok-for-spec, but *also* CanFail primops such as + -- `quotInt# 1# 0#`, but not ThrowsException primops. + -- See Note [Classifying primop effects] + -- and Note [Transformations affected by primop effects] for why this is + -- the correct choice. + , Var token_in' <- lookupCorePrepEnv env token_in + , isDeadBinder res, isDeadBinder bndr + -- Check that bndr and res are dead + -- We can rely on `isDeadBinder res`, despite the fact that the Simplifier + -- often zaps the OccInfo on case-alternative binders (see Note [DataAlt occ info] + -- in GHC.Core.Opt.Simplify.Iteration) because the scrutinee is not a + -- variable, and in that case the zapping doesn't happen; see that Note. + = cpeRhsE (extendCorePrepEnv env token_out token_in') rhs + cpeRhsE env (Case scrut bndr ty alts) = do { (floats, scrut') <- cpeBody env scrut ; (env', bndr2) <- cpCloneBndr env bndr diff --git a/compiler/GHC/Types/Id/Make.hs b/compiler/GHC/Types/Id/Make.hs index 35c774f8f49982347ac25dfaba1920c7780d1630..36ecd0ab9a3902f8dd5efa2e156e31d9e05995a0 100644 --- a/compiler/GHC/Types/Id/Make.hs +++ b/compiler/GHC/Types/Id/Make.hs @@ -2295,9 +2295,16 @@ Things to note also we can attach an evaldUnfolding to x' to discard any subsequent evals such as the `case x' of __DEFAULT`. +(SEQ4) + T15226 demonstrates that we want to discard ok-for-discard seq#s. That is, + simplify `case seq# <ok-to-discard> s of (# s', _ #) -> rhs[s']` to `rhs[s]`. + You might wonder whether the Simplifier could do this. But see the excellent + example in #24334 (immortalised as test T24334) for why it should be done in + CorePrep. + Implementing seq#. The compiler has magic for `seq#` in -- GHC.Core.Opt.ConstantFold.seqRule: eliminate (seq# <whnf> s) +- GHC.CoreToStg.Prep.cpeRhsE: Implement (SEQ4). - Simplify.addEvals records evaluated-ness for the result (cf. (SEQ3)); see Note [Adding evaluatedness info to pattern-bound variables] diff --git a/testsuite/tests/codeGen/should_compile/T24264.hs b/testsuite/tests/codeGen/should_compile/T24264.hs index a52ca4dc747b854c5ed86685432676e5ea2037bb..9c790e1477c2f8e80af0a8d75cc1f9c17971abcd 100644 --- a/testsuite/tests/codeGen/should_compile/T24264.hs +++ b/testsuite/tests/codeGen/should_compile/T24264.hs @@ -24,12 +24,8 @@ fun3 :: a -> IO a {-# OPAQUE fun3 #-} fun3 x = do pure () - -- "evaluate $! x" - case x of !x' -> IO (noinline seq# x') - -- noinline to work around the bogus seqRule - -- This ideally also should not push a continuation to the stack - -- before entering 'x'. It currently does, but let's wait for - -- !11515 to land before worrying about that. + evaluate $! x + -- This should not push a continuation to the stack before entering 'x' funPair :: a -> IO (a, a) {-# OPAQUE funPair #-} diff --git a/testsuite/tests/core-to-stg/T24334.hs b/testsuite/tests/core-to-stg/T24334.hs new file mode 100644 index 0000000000000000000000000000000000000000..59256874c17dca129155a4ca1cab8dffbc75aa31 --- /dev/null +++ b/testsuite/tests/core-to-stg/T24334.hs @@ -0,0 +1,20 @@ +import Control.Exception +import Data.IORef + +strictPrint :: Show a => a -> IO () +{-# OPAQUE strictPrint #-} +strictPrint x = print $! x + +f :: Show a => a -> IORef a -> IO () +{-# OPAQUE f #-} +f x r = do + x' <- evaluate $! x + writeIORef r x' + strictPrint x' + +main :: IO () +main = do + r <- newIORef (42 :: Int) + f (error "foo") r `catch` \(e :: SomeException) -> return () + n <- readIORef r + print n diff --git a/testsuite/tests/core-to-stg/T24334.stdout b/testsuite/tests/core-to-stg/T24334.stdout new file mode 100644 index 0000000000000000000000000000000000000000..d81cc0710eb6cf9efd5b920a8453e1e07157b6cd --- /dev/null +++ b/testsuite/tests/core-to-stg/T24334.stdout @@ -0,0 +1 @@ +42 diff --git a/testsuite/tests/core-to-stg/all.T b/testsuite/tests/core-to-stg/all.T index 51465e5e9805da1e4fda3057b8acb6d0a5d9e636..858c70afb02b032220ea5adf646cfe0410ed0f05 100644 --- a/testsuite/tests/core-to-stg/all.T +++ b/testsuite/tests/core-to-stg/all.T @@ -5,4 +5,5 @@ test('T23270', [grep_errmsg(r'patError')], compile, ['-O0 -dsuppress-uniques -dd test('T23914', normal, compile, ['-O']) test('T14895', normal, compile, ['-O -ddump-stg-final -dno-typeable-binds -dsuppress-uniques']) test('T24124', normal, compile, ['-O -ddump-stg-final -dno-typeable-binds -dsuppress-uniques']) +test('T24334', normal, compile_and_run, ['-O']) test('T24463', normal, compile, ['-O'])