Re: [GHC] #5129: "evaluate" optimized away

#5129: "evaluate" optimized away -------------------------------------+------------------------------------- Reporter: dons | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 7.0.3 Resolution: | Keywords: seq, evaluate Operating System: Unknown/Multiple | Architecture: Type of failure: Incorrect result | Unknown/Multiple at runtime | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Phab:D615 Wiki Page: | -------------------------------------+------------------------------------- Comment (by osa1): Started looking into this, With -O1 evaluate (and `seq#`, and the `throwIfNegative` call) vanishes, and the whole program is transformed into an assertFailure: {{{ Main.main1 = \ (eta2_a3iv :: GHC.Prim.State# GHC.Prim.RealWorld) -> GHC.Prim.catch# @ () @ SomeException Main.main3 Main.main2 eta2_a3iv Main.main3 = \ _ [Occ=Dead, OS=OneShot] -> case Main.main4 of wild_00 { } Main.main4 = assertFailure_rCn @ (IO ()) lvl1_r4kE Main.main2 = \ (e1_a3iI [OS=OneShot] :: SomeException) (eta_B1 [OS=OneShot] :: GHC.Prim.State# GHC.Prim.RealWorld) -> case e1_a3iI of wild_a3jJ }}} With some debug prints I was able to find the simplifier call that eliminates seq#: {{{ rebuildCase is_plain_seq expr ok for side effects: seq# @ String @ RealWorld (throwIfNegative (I# -1#)) s_a3jI alts: [((#,#), [ipv_a3jL, ipv1_a3jM], case assertFailure @ (IO ()) (build @ Char (\ (@ b_a3eo) -> unpackFoldrCString# @ b_a3eo "must throw when given a negative number"#)) of { })] cont: Stop[BoringCtxt] (# State# RealWorld, () #) ret: (SimplFloats {lets: FltLifted [] joins: [] in_scope: InScope {...}}, case assertFailure @ (IO ()) (build @ Char (\ (@ b_a3eo) -> unpackFoldrCString# @ b_a3eo "must throw when given a negative number"#)) of wild_00 { }) }}} This basically says `rebuildCase` sees the `seq#` call in the scrutinee position, thinks that it's side-effect-free (because the primop is not marked as effectful), also thinks that it's a "plain seq", and eliminates the case expression. "Plain seq" in this context is defined like this: {{{ is_plain_seq = all_dead_bndrs && isDeadBinder case_bndr -- Evaluation *only* for effect }}} So the code looks correct to me; primops is not marked as effectful, and this case expression is only for the (non-existent) effects, so it can be eliminated. Looking at the discussion above, I think not marking `seq#` as effectful was deliberate (otherwise `seq#` becomes `spark#`). I guess the idea was to force sequencing via a dependency of `State# RealWorld` return value of `seq#` and the next IO action, but I'm not sure how is that supposed to work in pure code. Can anyone say a few words about how do we expect to keep `seq#` when it's not effectful, and its return value is not used? -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/5129#comment:24 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
participants (1)
-
GHC