... |
... |
@@ -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
|