Simon Peyton Jones pushed to branch wip/T23109a at Glasgow Haskell Compiler / GHC

Commits:

2 changed files:

Changes:

  • compiler/GHC/Core/Opt/Simplify/Iteration.hs
    ... ... @@ -2112,8 +2112,8 @@ wrapJoinCont env cont thing_inside
    2112 2112
     
    
    2113 2113
       | otherwise
    
    2114 2114
         -- Normal case; see Note [Join points and case-of-case]
    
    2115
    -  = do { (floats1, cont')  <- mkDupableCont env cont
    
    2116
    -       ; (floats2, result) <- thing_inside (env `setInScopeFromF` floats1) cont'
    
    2115
    +  = do { (floats1, env', cont') <- mkDupableCont env cont
    
    2116
    +       ; (floats2, result) <- thing_inside env' cont'
    
    2117 2117
            ; return (floats1 `addFloats` floats2, result) }
    
    2118 2118
     
    
    2119 2119
     
    
    ... ... @@ -3257,34 +3257,75 @@ doCaseToLet scrut case_bndr
    3257 3257
     --------------------------------------------------
    
    3258 3258
     
    
    3259 3259
     reallyRebuildCase env scrut case_bndr alts cont
    
    3260
    -  | not (seCaseCase env)    -- Only when case-of-case is on.
    
    3261
    -                            -- See GHC.Driver.Config.Core.Opt.Simplify
    
    3262
    -                            --    Note [Case-of-case and full laziness]
    
    3263
    -  = do { case_expr <- simplAlts env scrut case_bndr alts
    
    3264
    -                                (mkBoringStop (contHoleType cont))
    
    3265
    -       ; rebuild (zapSubstEnv env) case_expr cont }
    
    3260
    +  -- ToDo: this code has a lot in common with wrapJoinCont; combine
    
    3261
    +  -- Also (join j = e in body) is very like a case with two alternatives
    
    3262
    +  -- If we aren't going to push StrictArg f into a case, we shouldn't push
    
    3263
    +  -- it into joins either.  More reasons to common-up
    
    3264
    +  | contIsStop cont   -- Shortcut for commmon case
    
    3265
    +  = do { case_expr <- simplAlts env scrut case_bndr alts cont
    
    3266
    +       ; return (emptyFloats env, case_expr) }
    
    3266 3267
     
    
    3267 3268
       | otherwise
    
    3268
    -  = do { (floats, env', cont') <- mkDupableCaseCont env alts cont
    
    3269
    -       ; case_expr <- simplAlts env' scrut
    
    3270
    -                                (scaleIdBy holeScaling case_bndr)
    
    3271
    -                                (scaleAltsBy holeScaling alts)
    
    3272
    -                                cont'
    
    3273
    -       ; return (floats, case_expr) }
    
    3269
    +  = do { let (cont_inner, cont_outer)
    
    3270
    +--                | contIsDupable cont    = all_inner cont -- Do this first, befoe seCaseCase
    
    3271
    +--                                                         -- (ToDo: explain... join points)
    
    3272
    +                | not (seCaseCase env)  = all_outer cont
    
    3273
    +                | not alts_would_dup    = all_inner cont
    
    3274
    +                | otherwise             = split cont     -- See Note [Strict arguments]
    
    3275
    +               -- seCaseCase: see GHC.Driver.Config.Core.Opt.Simplify
    
    3276
    +               --    Note [Case-of-case and full laziness]
    
    3277
    +
    
    3278
    +       ; (floats1, env', cont_inner') <- mkDupableCaseCont env alts_would_dup cont_inner
    
    3279
    +       ; case_expr <- simplAlts env' scrut case_bndr alts cont_inner'
    
    3280
    +       ; let (floats1', case_expr') = wrapJoinFloatsX floats1 case_expr
    
    3281
    +       ; (floats2, res_expr) <- rebuild env' case_expr' cont_outer
    
    3282
    +       ; return (floats1' `addFloats` floats2, res_expr) }
    
    3274 3283
       where
    
    3275
    -    holeScaling = contHoleScaling cont
    
    3276
    -    -- Note [Scaling in case-of-case]
    
    3284
    +    alts_would_dup = altsWouldDup alts
    
    3285
    +
    
    3286
    +    all_outer cont = (mkBoringStop (contHoleType cont), cont)
    
    3287
    +    all_inner cont = (cont, mkBoringStop (contResultType cont))
    
    3288
    +
    
    3289
    +    -- Tricky function!  We must push OkToDup things into cont_inner,
    
    3290
    +    -- to maintain join points
    
    3291
    +    dont_push_inside_multi_case :: SimplCont -> Bool
    
    3292
    +    dont_push_inside_multi_case cont
    
    3293
    +      = case cont of
    
    3294
    +           StrictArg { sc_fun = fun, sc_dup = dup }
    
    3295
    +             -> not (okToDup dup) &&  null (ai_rules fun)
    
    3296
    +           StrictBind { sc_dup = dup }
    
    3297
    +             -> not (okToDup dup)
    
    3298
    +           _ -> False
    
    3299
    +
    
    3300
    +    split cont@(Stop {}) = (cont, cont)
    
    3301
    +    split cont
    
    3302
    +      | dont_push_inside_multi_case cont = all_outer cont
    
    3303
    +      | otherwise                       = (cont { sc_cont = inner }, outer)
    
    3304
    +      where
    
    3305
    +       (inner, outer) = split (sc_cont cont)
    
    3277 3306
     
    
    3278
    -{-
    
    3279
    -simplCaseBinder checks whether the scrutinee is a variable, v.  If so,
    
    3280
    -try to eliminate uses of v in the RHSs in favour of case_bndr; that
    
    3281
    -way, there's a chance that v will now only be used once, and hence
    
    3282
    -inlined.
    
    3307
    +{- Note [Strict arguments]
    
    3308
    +~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    3309
    +Consider
    
    3310
    +   f (case x of I# y -> e1) e2 e3
    
    3311
    +where `f` is strict.  It's always good to push the call into the case, giving
    
    3312
    +   case x of I# y -> f e1 e2 e3
    
    3313
    +But things are much more nuanced when there are /multiple/ alternatives:
    
    3314
    +   f (case x of True -> e1a; False -> e1b) e2 e3
    
    3315
    +We have to be careful about duplicating e1, e2, but `mkDupableCont` deals with that
    
    3316
    +so we /could/ get
    
    3317
    +   let a2 = e2; a3 = e3 in
    
    3318
    +   case x of { True -> f e1a a2 a3; False -> f e1b a2 a3 }
    
    3319
    +This might be good if `f` has rewrite rules, because now it can "see" e1a/e1b.  But
    
    3320
    +but even then not necessarily -- it can't "see" e2 and e3, unless they are epandable.
    
    3321
    +So it is may be better just to leave it as it was, namely
    
    3322
    +   f (case x of True -> e1a; False -> e1b) e2 e3
    
    3323
    +Strightforward!
    
    3324
    +
    
    3325
    +To "leave it as it was" means that in `reallyRebuildCase` instead of pushing the
    
    3326
    +continuation ito the case branches, just build the case and wrapper the outer
    
    3327
    +continuation around it with `rebuild`.
    
    3283 3328
     
    
    3284
    -Historical note: we use to do the "case binder swap" in the Simplifier
    
    3285
    -so there were additional complications if the scrutinee was a variable.
    
    3286
    -Now the binder-swap stuff is done in the occurrence analyser; see
    
    3287
    -"GHC.Core.Opt.OccurAnal" Note [Binder swap].
    
    3288 3329
     
    
    3289 3330
     Note [knownCon occ info]
    
    3290 3331
     ~~~~~~~~~~~~~~~~~~~~~~~~
    
    ... ... @@ -3411,21 +3452,27 @@ simplAlts :: SimplEnv
    3411 3452
               -> OutExpr         -- Scrutinee
    
    3412 3453
               -> InId            -- Case binder
    
    3413 3454
               -> [InAlt]         -- Non-empty
    
    3414
    -          -> SimplCont
    
    3455
    +          -> SimplCont       -- Precondition: this can be duplicated
    
    3415 3456
               -> SimplM OutExpr  -- Returns the complete simplified case expression
    
    3416 3457
     
    
    3417 3458
     simplAlts env0 scrut case_bndr alts cont'
    
    3418 3459
       = do  { traceSmpl "simplAlts" (vcat [ ppr case_bndr
    
    3419 3460
                                           , text "cont':" <+> ppr cont'
    
    3420 3461
                                           , text "in_scope" <+> ppr (seInScope env0) ])
    
    3421
    -        ; (env1, case_bndr1) <- simplBinder env0 case_bndr
    
    3422
    -        ; let case_bndr2 = case_bndr1 `setIdUnfolding` evaldUnfolding
    
    3423
    -              env2       = modifyInScope env1 case_bndr2
    
    3462
    +
    
    3463
    +        -- hole_scaling: see Note [Scaling in case-of-case]
    
    3464
    +        ; let hole_scaling = contHoleScaling cont'
    
    3465
    +              case_bndr1   = scaleIdBy hole_scaling case_bndr
    
    3466
    +              alts1        = scaleAltsBy hole_scaling alts
    
    3467
    +
    
    3468
    +        ; (env1, case_bndr2) <- simplBinder env0 case_bndr1
    
    3469
    +        ; let case_bndr3 = case_bndr2 `setIdUnfolding` evaldUnfolding
    
    3470
    +              env2       = modifyInScope env1 case_bndr3
    
    3424 3471
                   -- See Note [Case binder evaluated-ness]
    
    3425 3472
                   fam_envs   = seFamEnvs env0
    
    3426 3473
     
    
    3427 3474
             ; (alt_env', scrut', case_bndr') <- improveSeq fam_envs env2 scrut
    
    3428
    -                                                       case_bndr case_bndr2 alts
    
    3475
    +                                                       case_bndr case_bndr3 alts1
    
    3429 3476
     
    
    3430 3477
             ; (imposs_deflt_cons, in_alts) <- prepareAlts scrut' case_bndr alts
    
    3431 3478
               -- NB: it's possible that the returned in_alts is empty: this is handled
    
    ... ... @@ -3838,16 +3885,16 @@ join points and inlining them away. See #4930.
    3838 3885
     -}
    
    3839 3886
     
    
    3840 3887
     --------------------
    
    3841
    -mkDupableCaseCont :: SimplEnv -> [InAlt] -> SimplCont
    
    3888
    +mkDupableCaseCont :: SimplEnv
    
    3889
    +                  -> Bool  -- True <=> more than one non-bottom alternative
    
    3890
    +                           -- (result of altsWouldDup)
    
    3891
    +                  -> SimplCont
    
    3842 3892
                       -> SimplM ( SimplFloats  -- Join points (if any)
    
    3843 3893
                                 , SimplEnv     -- Use this for the alts
    
    3844 3894
                                 , SimplCont)
    
    3845
    -mkDupableCaseCont env alts cont
    
    3846
    -  | altsWouldDup alts = do { (floats, cont) <- mkDupableCont env cont
    
    3847
    -                           ; let env' = bumpCaseDepth $
    
    3848
    -                                        env `setInScopeFromF` floats
    
    3849
    -                           ; return (floats, env', cont) }
    
    3850
    -  | otherwise         = return (emptyFloats env, env, cont)
    
    3895
    +mkDupableCaseCont env alts_would_dup cont
    
    3896
    +  | alts_would_dup = mkDupableCont env cont
    
    3897
    +  | otherwise      = return (emptyFloats env, env, cont)
    
    3851 3898
     
    
    3852 3899
     altsWouldDup :: [InAlt] -> Bool -- True iff strictly > 1 non-bottom alternative
    
    3853 3900
     altsWouldDup []  = False        -- See Note [Bottom alternatives]
    
    ... ... @@ -3867,9 +3914,14 @@ mkDupableCont :: SimplEnv
    3867 3914
                   -> SimplCont
    
    3868 3915
                   -> SimplM ( SimplFloats  -- Incoming SimplEnv augmented with
    
    3869 3916
                                            --   extra let/join-floats and in-scope variables
    
    3917
    +                        , SimplEnv
    
    3870 3918
                             , SimplCont)   -- dup_cont: duplicable continuation
    
    3871 3919
     mkDupableCont env cont
    
    3872
    -  = mkDupableContWithDmds (zapSubstEnv env) DupSelectToo (repeat topDmd) cont
    
    3920
    +  = do { (floats, cont') <- mkDupableContWithDmds (zapSubstEnv env)
    
    3921
    +                                  DupSelectToo (repeat topDmd) cont
    
    3922
    +       ; let env' = bumpCaseDepth $
    
    3923
    +                    env `setInScopeFromF` floats
    
    3924
    +       ; return (floats, env', cont') }
    
    3873 3925
     
    
    3874 3926
     mkDupableContWithDmds
    
    3875 3927
        :: SimplEnvIS -> DupContFlag
    
    ... ... @@ -3960,10 +4012,11 @@ mkDupableContWithDmds env _ _
    3960 4012
     
    
    3961 4013
            ; mkDupableStrictBind env bndr' join_body res_ty }
    
    3962 4014
     
    
    3963
    -mkDupableContWithDmds env DupSelectToo _
    
    3964
    -    (StrictArg { sc_fun = fun, sc_cont = cont, sc_fun_ty = fun_ty })
    
    4015
    +mkDupableContWithDmds env df _
    
    4016
    +    sarg_cont@(StrictArg { sc_fun = fun, sc_cont = app_cont, sc_fun_ty = fun_ty })
    
    3965 4017
       -- NB: sc_dup /= OkToDup; that is caught earlier by contIsDupable
    
    3966
    -  | isNothing (isDataConId_maybe (ai_fun fun))
    
    4018
    +  | DupSelectToo <- df
    
    4019
    +  , isNothing (isDataConId_maybe (ai_fun fun))
    
    3967 4020
              -- isDataConId: see point (DJ4) of Note [Duplicating join points]
    
    3968 4021
       = -- Use Plan C of Note [Duplicating StrictArg]
    
    3969 4022
         --   StrictArg (f a b <>) : ApplyTo e1 : ApplyTo e2: K
    
    ... ... @@ -3975,13 +4028,25 @@ mkDupableContWithDmds env DupSelectToo _
    3975 4028
     
    
    3976 4029
            ; (floats_s, args') <- mapAndUnzipM (makeTrivialArg env) (ai_args fun)
    
    3977 4030
     
    
    3978
    -       ; (floats, cont') <- mkDupableContWithDmds env DupAppsOnly dmds cont
    
    4031
    +       ; (floats, app_cont') <- mkDupableContWithDmds env DupAppsOnly dmds app_cont
    
    3979 4032
                      -- Use the demands from the function to add the right
    
    3980 4033
                      -- demand info on any bindings we make for further args
    
    3981 4034
     
    
    3982 4035
            ; return ( foldl' addLetFloats floats floats_s
    
    3983 4036
                     , StrictArg { sc_fun = fun { ai_args = args' }
    
    3984
    -                            , sc_cont = cont', sc_dup = OkToDup, sc_fun_ty = fun_ty }) }
    
    4037
    +                            , sc_cont = app_cont', sc_dup = OkToDup
    
    4038
    +                            , sc_fun_ty = fun_ty }) }
    
    4039
    +
    
    4040
    +  | otherwise
    
    4041
    +  = -- Use Plan B of Note [Duplicating StrictArg]
    
    4042
    +    --   K  -->   join j x = K[ x ]
    
    4043
    +    --            j <>
    
    4044
    +    do { let arg_ty = funArgTy fun_ty
    
    4045
    +             rhs_ty = contResultType app_cont
    
    4046
    +       ; arg_bndr <- newId (fsLit "jarg") ManyTy arg_ty
    
    4047
    +       ; let env' = env `addNewInScopeIds` [arg_bndr]
    
    4048
    +       ; (floats, join_rhs) <- simplOutId env' arg_bndr sarg_cont
    
    4049
    +       ; mkDupableStrictBind env' arg_bndr (wrapFloats floats join_rhs) rhs_ty }
    
    3985 4050
     
    
    3986 4051
     
    
    3987 4052
     {-
    
    ... ... @@ -4037,7 +4102,8 @@ mkDupableContWithDmds env _ _
    4037 4102
             --              in case [...hole...] of { pi -> ji xij }
    
    4038 4103
             -- NB: sc_dup /= OkToDup; that is caught earlier by contIsDupable
    
    4039 4104
         do  { tick (CaseOfCase case_bndr)
    
    4040
    -        ; (floats, alt_env, alt_cont) <- mkDupableCaseCont (se `setInScopeFromE` env) alts cont
    
    4105
    +        ; (floats, alt_env, alt_cont) <- mkDupableCaseCont (se `setInScopeFromE` env)
    
    4106
    +                                                           (altsWouldDup alts) cont
    
    4041 4107
                     -- NB: We call mkDupableCaseCont here to make cont duplicable
    
    4042 4108
                     --     (if necessary, depending on the number of alts)
    
    4043 4109
                     -- And this is important: see Note [Fusing case continuations]
    
    ... ... @@ -4072,17 +4138,6 @@ mkDupableContWithDmds env _ _
    4072 4138
                                           -- See Note [StaticEnv invariant] in GHC.Core.Opt.Simplify.Utils
    
    4073 4139
                               , sc_cont = mkBoringStop (contResultType cont) } ) }
    
    4074 4140
     
    
    4075
    -mkDupableContWithDmds env _ _ cont
    
    4076
    -  = -- Use Plan B of Note [Duplicating StrictArg]
    
    4077
    -    --   K  -->   join j x = K[ x ]
    
    4078
    -    --            j <>
    
    4079
    -    do { let arg_ty = contHoleType cont
    
    4080
    -             rhs_ty = contResultType cont
    
    4081
    -       ; arg_bndr <- newId (fsLit "arg") ManyTy arg_ty
    
    4082
    -       ; let env' = env `addNewInScopeIds` [arg_bndr]
    
    4083
    -       ; (floats, join_rhs) <- simplOutId env' arg_bndr cont
    
    4084
    -       ; mkDupableStrictBind env' arg_bndr (wrapFloats floats join_rhs) rhs_ty }
    
    4085
    -
    
    4086 4141
     mkDupableStrictBind :: SimplEnv -> OutId -> OutExpr -> OutType
    
    4087 4142
                         -> SimplM (SimplFloats, SimplCont)
    
    4088 4143
     -- mkDupableStrictBind env arg body rhs_ty
    

  • compiler/GHC/Core/Opt/Simplify/Utils.hs
    ... ... @@ -27,7 +27,7 @@ module GHC.Core.Opt.Simplify.Utils (
    27 27
             contIsTrivial, contArgs, contIsRhs,
    
    28 28
             countArgs, contOutArgs, dropContArgs,
    
    29 29
             mkBoringStop, mkRhsStop, mkLazyArgStop,
    
    30
    -        interestingCallContext,
    
    30
    +        interestingCallContext, okToDup,
    
    31 31
     
    
    32 32
             -- ArgInfo
    
    33 33
             ArgInfo(..), ArgSpec(..), mkArgInfo,
    
    ... ... @@ -213,8 +213,8 @@ data SimplCont
    213 213
           , sc_cont :: SimplCont }
    
    214 214
     
    
    215 215
       | TickIt              -- (TickIt t K)[e] = K[ tick t e ]
    
    216
    -        CoreTickish     -- Tick tickish <hole>
    
    217
    -        SimplCont
    
    216
    +      { sc_tick :: CoreTickish     -- Tick tickish <hole>
    
    217
    +      , sc_cont ::  SimplCont }
    
    218 218
     
    
    219 219
     data FromWhat = FromLet | FromBeta Levity
    
    220 220
     
    
    ... ... @@ -223,6 +223,10 @@ data DupFlag = NoDup -- Unsimplified, might be big
    223 223
                  | Simplified  -- Simplified
    
    224 224
                  | OkToDup     -- Simplified and small
    
    225 225
     
    
    226
    +okToDup :: DupFlag -> Bool
    
    227
    +okToDup OkToDup = True
    
    228
    +okToDup _       = False
    
    229
    +
    
    226 230
     isSimplified :: DupFlag -> Bool
    
    227 231
     isSimplified NoDup = False
    
    228 232
     isSimplified _     = True       -- Invariant: the subst-env is empty
    
    ... ... @@ -441,13 +445,14 @@ contIsStop (Stop {}) = True
    441 445
     contIsStop _         = False
    
    442 446
     
    
    443 447
     contIsDupable :: SimplCont -> Bool
    
    444
    -contIsDupable (Stop {})                         = True
    
    445
    -contIsDupable (ApplyToTy  { sc_cont = k })      = contIsDupable k
    
    446
    -contIsDupable (ApplyToVal { sc_dup = OkToDup }) = True -- See Note [DupFlag invariants]
    
    447
    -contIsDupable (Select { sc_dup = OkToDup })     = True -- ...ditto...
    
    448
    -contIsDupable (StrictArg { sc_dup = OkToDup })  = True -- ...ditto...
    
    449
    -contIsDupable (CastIt { sc_cont = k })          = contIsDupable k
    
    450
    -contIsDupable _                                 = False
    
    448
    +contIsDupable (Stop {})                     = True
    
    449
    +contIsDupable (ApplyToVal { sc_dup = dup }) = okToDup dup -- See Note [DupFlag invariants]
    
    450
    +contIsDupable (Select     { sc_dup = dup }) = okToDup dup -- ...ditto...
    
    451
    +contIsDupable (StrictArg  { sc_dup = dup }) = okToDup dup -- ...ditto...
    
    452
    +contIsDupable (StrictBind { sc_dup = dup }) = okToDup dup -- ...ditto...
    
    453
    +contIsDupable (ApplyToTy  { sc_cont = k })  = contIsDupable k
    
    454
    +contIsDupable (CastIt { sc_cont = k })      = contIsDupable k
    
    455
    +contIsDupable (TickIt { sc_cont = k })      = contIsDupable k
    
    451 456
     
    
    452 457
     -------------------
    
    453 458
     contIsTrivial :: SimplCont -> Bool