Simon Peyton Jones pushed to branch wip/T27737 at Glasgow Haskell Compiler / GHC
Commits:
-
c42c8498
by Simon Peyton Jones at 2026-10-08T16:17:13+01:00
2 changed files:
Changes:
| ... | ... | @@ -45,7 +45,7 @@ module GHC.Core.Opt.Simplify.Env ( |
| 45 | 45 | |
| 46 | 46 | -- * LetFloats
|
| 47 | 47 | LetFloats, FloatEnable(..), letFloatBinds, emptyLetFloats, unitLetFloat,
|
| 48 | - addLetFlts, mapLetFloats,
|
|
| 48 | + unitCaseFloat, addLetFlts, mapLetFloats,
|
|
| 49 | 49 | |
| 50 | 50 | -- * JoinFloats
|
| 51 | 51 | JoinFloat, JoinFloats, emptyJoinFloats,
|
| ... | ... | @@ -65,7 +65,8 @@ import GHC.Core.Subst( substExprSC ) |
| 65 | 65 | import GHC.Core.Unfold
|
| 66 | 66 | import GHC.Core.TyCo.Subst (emptyIdSubstEnv, mkSubst)
|
| 67 | 67 | import GHC.Core.Multiplicity( Scaled(..), mkMultMul )
|
| 68 | -import GHC.Core.Make ( mkWildValBinder, mkCoreLet )
|
|
| 68 | +import GHC.Core.Make ( mkWildValBinder )
|
|
| 69 | +import qualified GHC.Core.Make
|
|
| 69 | 70 | import GHC.Core.Type hiding ( substTy, substTyVar, substTyVarBndr, substCo
|
| 70 | 71 | , extendTvSubst, extendCvSubst )
|
| 71 | 72 | import qualified GHC.Core.Coercion as Coercion
|
| ... | ... | @@ -760,10 +761,46 @@ Examples |
| 760 | 761 | NonRec x* (f y) FltCareful -- Strict binding; might fail or diverge
|
| 761 | 762 | NonRec x# (a /# b) FltCareful -- Might fail; does not satisfy let-can-float invariant
|
| 762 | 763 | NonRec x# (f y) FltCareful -- Might diverge; does not satisfy let-can-float invariant
|
| 764 | + |
|
| 765 | +A binding that does not satisfy the let-can-float invariant (the last two
|
|
| 766 | +examples above) is represented by a FloatCase, not a FloatLet:
|
|
| 767 | + FloatCase (a /# b) x# DEFAULT []
|
|
| 768 | +That is done once and for all by `unitLetFloat`, so a FloatLet in a LetFloats
|
|
| 769 | +is always a valid let-binding, and `wrapFloats` does not need to check.
|
|
| 770 | +Such bindings can arise from `makeTrivial`, because an argument need not
|
|
| 771 | +satisfy the let-can-float invariant. They also arise because
|
|
| 772 | +exprOkForSpeculation is conservative: e.g. it says False for (# s, x #)
|
|
| 773 | +where x is lifted, because it checks the arguments against the
|
|
| 774 | +(representation-polymorphic) type of the unboxed-tuple worker.
|
|
| 775 | + |
|
| 776 | +However, a FloatLet can still be FltCareful: the first FltCareful example
|
|
| 777 | +above, NonRec x* (f y), where x* is lifted but has a strict demand
|
|
| 778 | +(isStrUsedDmd). That is a perfectly valid (lazy) let-binding, but its demand
|
|
| 779 | +info is valid only where it is. If we floated it out of the RHS of a lazy
|
|
| 780 | +binding
|
|
| 781 | + let v = let x* = f y in x*+1 in body
|
|
| 782 | + ==> let x* = f y; v = x*+1 in body
|
|
| 783 | +then x's demand info would be a lie, and CorePrep, which case-binds a let
|
|
| 784 | +whose binder has a strict demand, would evaluate (f y) eagerly. Hence
|
|
| 785 | +FltCareful, which doFloatFromRhs allows to float only out of a strict binding.
|
|
| 786 | + |
|
| 787 | +As well as let-bindings, a LetFloats can contain single-alternative case
|
|
| 788 | +floats (FloatCase), for example
|
|
| 789 | + case e of b { (# a, c #) -> <hole> }
|
|
| 790 | +These are classified just like a strict binding:
|
|
| 791 | + |
|
| 792 | + FloatCase (y +# 3) b DEFAULT [] FltOkSpec -- Scrutinee ok-for-speculation
|
|
| 793 | + FloatCase (f y) b (# a,c #) [a,c] FltCareful -- Might fail or diverge
|
|
| 794 | + |
|
| 795 | +Being strict they are never FltLifted, so they never float to top level or into
|
|
| 796 | +a recursive group.
|
|
| 797 | + |
|
| 798 | +Currently, we never put a FloatTick in a LetFloats.
|
|
| 763 | 799 | -}
|
| 764 | 800 | |
| 765 | -data LetFloats = LetFloats (OrdList OutBind) FloatFlag
|
|
| 801 | +data LetFloats = LetFloats FloatBinds FloatFlag
|
|
| 766 | 802 | -- See Note [LetFloats]
|
| 803 | + -- Contains only FloatLet and FloatCase; never FloatTick
|
|
| 767 | 804 | |
| 768 | 805 | type JoinFloat = OutBind
|
| 769 | 806 | type JoinFloats = OrdList JoinFloat
|
| ... | ... | @@ -864,17 +901,35 @@ isEmptyJoinFloats = isNilOL |
| 864 | 901 | |
| 865 | 902 | unitLetFloat :: OutBind -> LetFloats
|
| 866 | 903 | -- This key function constructs a singleton float with the right form
|
| 904 | +-- If the binding does not satisfy the let-can-float invariant, it
|
|
| 905 | +-- makes a FloatCase. See Note [LetFloats]
|
|
| 867 | 906 | unitLetFloat bind = assert (all (not . isJoinId) (bindersOf bind)) $
|
| 868 | - LetFloats (unitOL bind) (flag bind)
|
|
| 907 | + mk_float bind
|
|
| 869 | 908 | where
|
| 870 | - flag (Rec {}) = FltLifted
|
|
| 871 | - flag (NonRec bndr rhs)
|
|
| 872 | - | not (isStrictId bndr) = FltLifted
|
|
| 873 | - | exprIsTickedString rhs = FltLifted
|
|
| 909 | + mk_float bind@(Rec {}) = let_float FltLifted bind
|
|
| 910 | + mk_float bind@(NonRec bndr rhs)
|
|
| 911 | + | not (isStrictId bndr) = let_float FltLifted bind
|
|
| 912 | + | exprIsTickedString rhs = let_float FltLifted bind
|
|
| 874 | 913 | -- String literals can be floated freely.
|
| 875 | 914 | -- See Note [Core top-level string literals] in GHC.Core.
|
| 876 | - | exprOkForSpeculation rhs = FltOkSpec -- Unlifted, and lifted but ok-for-spec (eg HNF)
|
|
| 877 | - | otherwise = FltCareful
|
|
| 915 | + | exprOkForSpeculation rhs = let_float FltOkSpec bind -- Unlifted, and lifted but ok-for-spec (eg HNF)
|
|
| 916 | + | needsCaseBinding (idType bndr) rhs
|
|
| 917 | + = pprTrace "TMP-unitLetFloat-case" (ppr bind) $
|
|
| 918 | + LetFloats (unitOL (FloatCase rhs bndr DEFAULT [])) FltCareful
|
|
| 919 | + -- Unlifted, and not ok-for-spec: does not satisfy let-can-float invariant
|
|
| 920 | + | otherwise = let_float FltCareful bind
|
|
| 921 | + |
|
| 922 | + let_float flag bind = LetFloats (unitOL (FloatLet bind)) flag
|
|
| 923 | + |
|
| 924 | +unitCaseFloat :: OutExpr -> OutId -> AltCon -> [OutVar] -> LetFloats
|
|
| 925 | +-- Constructs a singleton single-alternative case float
|
|
| 926 | +-- case scrut of bndr { con bndrs -> <hole> }
|
|
| 927 | +-- See Note [LetFloats]
|
|
| 928 | +unitCaseFloat scrut bndr con bndrs
|
|
| 929 | + = LetFloats (unitOL (FloatCase scrut bndr con bndrs)) flag
|
|
| 930 | + where
|
|
| 931 | + flag | exprOkForSpeculation scrut = FltOkSpec
|
|
| 932 | + | otherwise = FltCareful
|
|
| 878 | 933 | |
| 879 | 934 | unitJoinFloat :: OutBind -> JoinFloats
|
| 880 | 935 | unitJoinFloat bind = assert (all isJoinId (bindersOf bind)) $
|
| ... | ... | @@ -929,7 +984,11 @@ addLetFloats floats let_floats |
| 929 | 984 | |
| 930 | 985 | extendInScopeFromLF :: InScopeSet -> LetFloats -> InScopeSet
|
| 931 | 986 | extendInScopeFromLF in_scope (LetFloats binds _)
|
| 932 | - = foldlOL extendInScopeSetBind in_scope binds
|
|
| 987 | + = foldlOL extend in_scope binds
|
|
| 988 | + where
|
|
| 989 | + extend in_scope (FloatLet bind) = in_scope `extendInScopeSetBind` bind
|
|
| 990 | + extend in_scope (FloatCase _ b _ bs) = in_scope `extendInScopeSetList` (b:bs)
|
|
| 991 | + extend in_scope (FloatTick {}) = in_scope
|
|
| 933 | 992 | |
| 934 | 993 | addJoinFloats :: SimplFloats -> JoinFloats -> SimplFloats
|
| 935 | 994 | addJoinFloats floats join_floats
|
| ... | ... | @@ -952,7 +1011,12 @@ addLetFlts (LetFloats bs1 l1) (LetFloats bs2 l2) |
| 952 | 1011 | = LetFloats (bs1 `appOL` bs2) (l1 `andFF` l2)
|
| 953 | 1012 | |
| 954 | 1013 | letFloatBinds :: LetFloats -> [CoreBind]
|
| 955 | -letFloatBinds (LetFloats bs _) = fromOL bs
|
|
| 1014 | +-- Precondition: there are no case-floats
|
|
| 1015 | +-- True, for example, if the FloatFlag is FltLifted
|
|
| 1016 | +letFloatBinds (LetFloats bs _) = map get_bind (fromOL bs)
|
|
| 1017 | + where
|
|
| 1018 | + get_bind (FloatLet bind) = bind
|
|
| 1019 | + get_bind flt = pprPanic "letFloatBinds" (ppr flt)
|
|
| 956 | 1020 | |
| 957 | 1021 | addJoinFlts :: JoinFloats -> JoinFloats -> JoinFloats
|
| 958 | 1022 | addJoinFlts = appOL
|
| ... | ... | @@ -960,7 +1024,7 @@ addJoinFlts = appOL |
| 960 | 1024 | mkRecFloats :: SimplFloats -> SimplFloats
|
| 961 | 1025 | -- Flattens the floats into a single Rec group,
|
| 962 | 1026 | -- They must either all be lifted LetFloats or all JoinFloats
|
| 963 | -mkRecFloats floats@(SimplFloats { sfLetFloats = LetFloats bs _ff
|
|
| 1027 | +mkRecFloats floats@(SimplFloats { sfLetFloats = lfs@(LetFloats bs _ff)
|
|
| 964 | 1028 | , sfJoinFloats = jbs
|
| 965 | 1029 | , sfInScope = in_scope })
|
| 966 | 1030 | = assertPpr (isNilOL bs || isNilOL jbs) (ppr floats) $
|
| ... | ... | @@ -970,20 +1034,19 @@ mkRecFloats floats@(SimplFloats { sfLetFloats = LetFloats bs _ff |
| 970 | 1034 | where
|
| 971 | 1035 | -- See Note [Bangs in the Simplifier]
|
| 972 | 1036 | !floats' | isNilOL bs = emptyLetFloats
|
| 973 | - | otherwise = unitLetFloat (Rec (flattenBinds (fromOL bs)))
|
|
| 1037 | + | otherwise = unitLetFloat (Rec (flattenBinds (letFloatBinds lfs)))
|
|
| 974 | 1038 | !jfloats' | isNilOL jbs = emptyJoinFloats
|
| 975 | 1039 | | otherwise = unitJoinFloat (Rec (flattenBinds (fromOL jbs)))
|
| 976 | 1040 | |
| 977 | 1041 | wrapFloats :: SimplFloats -> OutExpr -> OutExpr
|
| 978 | 1042 | -- Wrap the floats around the expression
|
| 979 | -wrapFloats (SimplFloats { sfLetFloats = LetFloats bs flag
|
|
| 1043 | +wrapFloats (SimplFloats { sfLetFloats = LetFloats bs _
|
|
| 980 | 1044 | , sfJoinFloats = jbs }) body
|
| 981 | - = foldrOL mk_let (wrapJoinFloats jbs body) bs
|
|
| 1045 | + = GHC.Core.Make.wrapFloats bs (wrapJoinFloats jbs body)
|
|
| 982 | 1046 | -- Note: Always safe to put the joins on the inside
|
| 983 | 1047 | -- since the values can't refer to them
|
| 984 | - where
|
|
| 985 | - mk_let | FltCareful <- flag = mkCoreLet -- need to enforce let-can-float-invariant
|
|
| 986 | - | otherwise = Let -- let-can-float invariant hold
|
|
| 1048 | + -- No need to worry about the let-can-float invariant: unitLetFloat
|
|
| 1049 | + -- has made a FloatCase for any binding that does not satisfy it
|
|
| 987 | 1050 | |
| 988 | 1051 | wrapJoinFloatsX :: SimplFloats -> OutExpr -> (SimplFloats, OutExpr)
|
| 989 | 1052 | -- Wrap the sfJoinFloats of the env around the expression,
|
| ... | ... | @@ -1009,8 +1072,10 @@ mapLetFloats :: LetFloats -> ((Id,CoreExpr) -> (Id,CoreExpr)) -> LetFloats |
| 1009 | 1072 | mapLetFloats (LetFloats fs ff) fun
|
| 1010 | 1073 | = LetFloats fs1 ff
|
| 1011 | 1074 | where
|
| 1012 | - app (NonRec b e) = case fun (b,e) of (b',e') -> NonRec b' e'
|
|
| 1013 | - app (Rec bs) = Rec (strictMap fun bs)
|
|
| 1075 | + app (FloatLet (NonRec b e)) = case fun (b,e) of (b',e') -> FloatLet (NonRec b' e')
|
|
| 1076 | + app (FloatLet (Rec bs)) = FloatLet (Rec (strictMap fun bs))
|
|
| 1077 | + app (FloatCase e b con bs) = case fun (b,e) of (b',e') -> FloatCase e' b' con bs
|
|
| 1078 | + app flt@(FloatTick {}) = pprPanic "mapLetFloats" (ppr flt)
|
|
| 1014 | 1079 | !fs1 = (mapOL' app fs) -- See Note [Bangs in the Simplifier]
|
| 1015 | 1080 | |
| 1016 | 1081 | {-
|
| ... | ... | @@ -256,6 +256,8 @@ simplRecBind env0 bind_cxt pairs0 |
| 256 | 256 | ; let new_bndrs = map sndOf3 triples
|
| 257 | 257 | ; (rec_floats, env2) <- enterRecGroupRHSs env1 new_bndrs $ \env ->
|
| 258 | 258 | go env triples
|
| 259 | + |
|
| 260 | + -- In rec_floats, all the `sfLetFloats` bindings are `FltLifted`
|
|
| 259 | 261 | ; return (mkRecFloats rec_floats, env2) }
|
| 260 | 262 | where
|
| 261 | 263 | add_rules :: SimplEnv -> (InBndr,InExpr) -> SimplM (SimplEnv, (InBndr, OutBndr, InExpr))
|
| ... | ... | @@ -284,7 +286,8 @@ simplRecOrTopPair :: SimplEnv |
| 284 | 286 | -> BindContext
|
| 285 | 287 | -> InId -> OutBndr -> InExpr -- Binder and rhs
|
| 286 | 288 | -> SimplM (SimplFloats, SimplEnv)
|
| 287 | - |
|
| 289 | +-- Invariant: in the returned SimplFloats,
|
|
| 290 | +-- all the `sfLetFloats` bindings are `FltLifted`
|
|
| 288 | 291 | simplRecOrTopPair env bind_cxt old_bndr new_bndr rhs
|
| 289 | 292 | | Just env' <- preInlineUnconditionally env (bindContextLevel bind_cxt)
|
| 290 | 293 | old_bndr (UnSimplified env) rhs MRefl
|
| ... | ... | @@ -3399,15 +3402,57 @@ doCaseToLet scrut case_bndr |
| 3399 | 3402 | |
| 3400 | 3403 | reallyRebuildCase (saf,env) scrut case_bndr alts cont
|
| 3401 | 3404 | = do { (floats, env', cont') <- mkDupableCaseCont env alts cont
|
| 3402 | - ; case_expr <- simplAlts (saf,env') scrut
|
|
| 3403 | - (scaleIdBy holeScaling case_bndr)
|
|
| 3404 | - (scaleAltsBy holeScaling alts)
|
|
| 3405 | - cont'
|
|
| 3406 | - ; return (floats, case_expr) }
|
|
| 3405 | + ; traceSmpl "reallyRebuildCase" (vcat [ ppr case_bndr
|
|
| 3406 | + , text "cont':" <+> ppr cont'
|
|
| 3407 | + , text "in_scope" <+> ppr (seInScope env') ])
|
|
| 3408 | + ; (alt_env, scrut', case_bndr', imposs_deflt_cons, in_alts)
|
|
| 3409 | + <- prepareCase (saf,env') scrut (scaleIdBy holeScaling case_bndr)
|
|
| 3410 | + (scaleAltsBy holeScaling alts)
|
|
| 3411 | + ; case in_alts of
|
|
| 3412 | + [in_alt] -> do { (alt_floats, alt') <- simplAlt (saf,alt_env) (Just scrut')
|
|
| 3413 | + imposs_deflt_cons case_bndr'
|
|
| 3414 | + bndr_swap cont' in_alt
|
|
| 3415 | + ; (case_floats, res) <- rebuildSingleAltCase env' scrut' case_bndr'
|
|
| 3416 | + cont' alt_floats alt'
|
|
| 3417 | + ; return (floats `addFloats` case_floats, res) }
|
|
| 3418 | + |
|
| 3419 | + _ -> do { case_expr <- simplAlts (saf,alt_env) scrut' case_bndr'
|
|
| 3420 | + imposs_deflt_cons bndr_swap cont' in_alts
|
|
| 3421 | + ; return (floats, case_expr) } }
|
|
| 3407 | 3422 | where
|
| 3408 | 3423 | holeScaling = contHoleScaling cont
|
| 3409 | 3424 | -- Note [Scaling in case-of-case]
|
| 3410 | 3425 | |
| 3426 | + bndr_swap = scrutOkForBinderSwap scrut
|
|
| 3427 | + |
|
| 3428 | +rebuildSingleAltCase :: SimplEnv -> OutExpr -> OutId -> SimplCont
|
|
| 3429 | + -> SimplFloats -> OutAlt
|
|
| 3430 | + -> SimplM (SimplFloats, OutExpr)
|
|
| 3431 | +-- Build a single-alternative case; but return it as a FloatCase float, so that
|
|
| 3432 | +-- the floats from its RHS are not trapped inside it.
|
|
| 3433 | +-- See Note [Floating single-alternative cases]
|
|
| 3434 | +rebuildSingleAltCase env scrut case_bndr cont alt_floats (Alt con bs rhs)
|
|
| 3435 | + = do { let alts_ty = contResultType cont
|
|
| 3436 | + -- See Note [Avoiding space leaks in OutType]
|
|
| 3437 | + ; case_expr <- seqType alts_ty `seq`
|
|
| 3438 | + mkCase (seMode env) scrut case_bndr alts_ty
|
|
| 3439 | + [Alt con bs (wrapFloats alt_floats rhs)]
|
|
| 3440 | + -- wrapFloats: lazily; see (FSC1)
|
|
| 3441 | + ; case case_expr of
|
|
| 3442 | + Case scrut2 bndr2 _ [Alt con2 bs2 rhs2]
|
|
| 3443 | + | not (noFloats alt_floats)
|
|
| 3444 | + , bndr2 == case_bndr -- mkCase has not changed the case; see (FSC1)
|
|
| 3445 | + -> return (case_float `addFloats` alt_floats, rhs)
|
|
| 3446 | + | otherwise
|
|
| 3447 | + -> return (case_float, rhs2)
|
|
| 3448 | + where
|
|
| 3449 | + case_float = emptyFloats env `addLetFloats`
|
|
| 3450 | + unitCaseFloat scrut2 bndr2 con2 bs2
|
|
| 3451 | + _ -> return (emptyFloats env, case_expr) }
|
|
| 3452 | + where
|
|
| 3453 | + noFloats (SimplFloats { sfLetFloats = lfs, sfJoinFloats = jfs })
|
|
| 3454 | + = isEmptyLetFloats lfs && isEmptyJoinFloats jfs
|
|
| 3455 | + |
|
| 3411 | 3456 | {-
|
| 3412 | 3457 | simplCaseBinder checks whether the scrutinee is a variable, v. If so,
|
| 3413 | 3458 | try to eliminate uses of v in the RHSs in favour of case_bndr; that
|
| ... | ... | @@ -3540,17 +3585,16 @@ scale the entire case we are simplifying, by a scaling factor which can be |
| 3540 | 3585 | computed in the continuation (with function `contHoleScaling`).
|
| 3541 | 3586 | -}
|
| 3542 | 3587 | |
| 3543 | -simplAlts :: (SimplAltFlag, SimplEnv)
|
|
| 3544 | - -> OutExpr -- Scrutinee
|
|
| 3545 | - -> InId -> [InAlt] -- Alts (non-empty)
|
|
| 3546 | - -> SimplCont
|
|
| 3547 | - -> SimplM OutExpr -- Returns the complete simplified case expression
|
|
| 3548 | - |
|
| 3549 | -simplAlts (saf,env0) scrut case_bndr alts cont'
|
|
| 3550 | - = do { traceSmpl "simplAlts" (vcat [ ppr case_bndr
|
|
| 3551 | - , text "cont':" <+> ppr cont'
|
|
| 3552 | - , text "in_scope" <+> ppr (seInScope env0) ])
|
|
| 3553 | - ; (env1, case_bndr1) <- simplAltIdBinder (saf,env0) case_bndr
|
|
| 3588 | +prepareCase :: (SimplAltFlag, SimplEnv)
|
|
| 3589 | + -> OutExpr -- Scrutinee
|
|
| 3590 | + -> InId -> [InAlt] -- Case binder and alts (non-empty)
|
|
| 3591 | + -> SimplM ( SimplEnv -- For the alternatives
|
|
| 3592 | + , OutExpr -- Scrutinee, perhaps improved by improveSeq
|
|
| 3593 | + , OutId -- Case binder
|
|
| 3594 | + , [AltCon] -- Constructors impossible in the DEFAULT alt
|
|
| 3595 | + , [InAlt] ) -- Alternatives, from prepareAlts
|
|
| 3596 | +prepareCase (saf,env0) scrut case_bndr alts
|
|
| 3597 | + = do { (env1, case_bndr1) <- simplAltIdBinder (saf,env0) case_bndr
|
|
| 3554 | 3598 | ; let case_bndr2 = case_bndr1 `setIdUnfolding` evaldUnfolding
|
| 3555 | 3599 | env2 = modifyInScope env1 case_bndr2
|
| 3556 | 3600 | -- See Note [Case binder evaluated-ness]
|
| ... | ... | @@ -3565,16 +3609,61 @@ simplAlts (saf,env0) scrut case_bndr alts cont' |
| 3565 | 3609 | -- NB: pass case_bndr::InId, not case_bndr' :: OutId, to prepareAlts
|
| 3566 | 3610 | -- See Note [Shadowing in prepareAlts] in GHC.Core.Opt.Simplify.Utils
|
| 3567 | 3611 | |
| 3568 | - ; alts' <- forM in_alts $
|
|
| 3569 | - simplAlt (saf,alt_env') (Just scrut') imposs_deflt_cons
|
|
| 3570 | - case_bndr' (scrutOkForBinderSwap scrut) cont'
|
|
| 3612 | + ; return (alt_env', scrut', case_bndr', imposs_deflt_cons, in_alts) }
|
|
| 3613 | + |
|
| 3614 | +simplAlts :: (SimplAltFlag, SimplEnv)
|
|
| 3615 | + -> OutExpr -> OutId -- Scrutinee and case binder
|
|
| 3616 | + -> [AltCon] -- Constructors impossible in the DEFAULT alt
|
|
| 3617 | + -> BinderSwapDecision
|
|
| 3618 | + -> SimplCont
|
|
| 3619 | + -> [InAlt]
|
|
| 3620 | + -> SimplM OutExpr -- Returns the complete simplified case expression
|
|
| 3621 | +-- The arguments are prepared by prepareCase
|
|
| 3622 | +simplAlts (saf,env) scrut' case_bndr' imposs_deflt_cons bndr_swap cont' in_alts
|
|
| 3623 | + = do { alts' <- forM in_alts $
|
|
| 3624 | + simplAltC (saf,env) (Just scrut') imposs_deflt_cons
|
|
| 3625 | + case_bndr' bndr_swap cont'
|
|
| 3571 | 3626 | |
| 3572 | 3627 | ; let alts_ty' = contResultType cont'
|
| 3573 | 3628 | -- See Note [Avoiding space leaks in OutType]
|
| 3574 | 3629 | ; seqType alts_ty' `seq`
|
| 3575 | - mkCase (seMode env0) scrut' case_bndr' alts_ty' alts' }
|
|
| 3630 | + mkCase (seMode env) scrut' case_bndr' alts_ty' alts' }
|
|
| 3576 | 3631 | |
| 3577 | 3632 | |
| 3633 | +{- Note [Floating single-alternative cases]
|
|
| 3634 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 3635 | +When reallyRebuildCase finds a single-alternative case (after prepareAlts)
|
|
| 3636 | + case e of b { (# a, c #) -> let x1 = .. in ... let xn = .. in (# e1, e2 #) }
|
|
| 3637 | +it does not return the case expression; instead it returns
|
|
| 3638 | + * floats: [FloatCase e b (# a,c #) [a,c], x1 = .., ..., xn = ..]
|
|
| 3639 | + * result: (# e1, e2 #)
|
|
| 3640 | +This is done by rebuildSingleAltCase. See Note [LetFloats] in GHC.Core.Opt.Simplify.Env.
|
|
| 3641 | + |
|
| 3642 | +Why? Because a caller (notably rebuildWithFloats, when case-of-case is
|
|
| 3643 | +switched off) may want to do case-of-known-constructor on the result. If we
|
|
| 3644 | +returned the whole case, exprIsConApp_maybe would have to walk all the way
|
|
| 3645 | +down through the case and the lets, which can be quadratic (#27737, T18223).
|
|
| 3646 | + |
|
| 3647 | +This is not restricted to the no-case-of-case path: when case-of-case is on,
|
|
| 3648 | +the continuation has already been pushed into the alternative, and the
|
|
| 3649 | +floats are simply wrapped around the result, or floated further out of a
|
|
| 3650 | +strict let (which a StrictBind continuation would do anyway). The
|
|
| 3651 | +FloatFlag (FltCareful or FltOkSpec) stops a case-float from floating out of
|
|
| 3652 | +a lazy let, or to top level; see doFloatFromRhs.
|
|
| 3653 | + |
|
| 3654 | +Wrinkles:
|
|
| 3655 | + |
|
| 3656 | +(FSC1) mkCase may transform the case, e.g. by case-merging, identity-case
|
|
| 3657 | + elimination, or caseRules (mkCase2), which renames the case binder and
|
|
| 3658 | + wraps (let b = ..) around the RHS. So we call mkCase on the alternative
|
|
| 3659 | + with its floats wrapped (lazily: mkCase inspects only the top of the RHS),
|
|
| 3660 | + and then:
|
|
| 3661 | + - If the alternative has floats, and mkCase has left the case binder
|
|
| 3662 | + unchanged, mkCase cannot have done anything to the RHS (which starts
|
|
| 3663 | + with a let), so we return (case-float + alt-floats, unwrapped RHS).
|
|
| 3664 | + - Otherwise we return the case-float with whatever RHS mkCase produced.
|
|
| 3665 | +-}
|
|
| 3666 | + |
|
| 3578 | 3667 | ------------------------------------
|
| 3579 | 3668 | improveSeq :: (FamInstEnv, FamInstEnv)
|
| 3580 | 3669 | -> (SimplAltFlag, SimplEnv)
|
| ... | ... | @@ -3594,6 +3683,15 @@ improveSeq _ (_,env) scrut _ case_bndr1 _ |
| 3594 | 3683 | |
| 3595 | 3684 | |
| 3596 | 3685 | ------------------------------------
|
| 3686 | +simplAltC :: (SimplAltFlag, SimplEnv) -> Maybe OutExpr -> [AltCon] -> OutId
|
|
| 3687 | + -> BinderSwapDecision -> SimplCont -> InAlt
|
|
| 3688 | + -> SimplM OutAlt
|
|
| 3689 | +-- Like simplAlt, but wraps the floats around the RHS
|
|
| 3690 | +simplAltC env scrut' imposs_deflt_cons case_bndr' bndr_swap' cont' alt
|
|
| 3691 | + = do { (floats, Alt con bs rhs) <- simplAlt env scrut' imposs_deflt_cons
|
|
| 3692 | + case_bndr' bndr_swap' cont' alt
|
|
| 3693 | + ; return (Alt con bs (wrapFloats floats rhs)) }
|
|
| 3694 | + |
|
| 3597 | 3695 | simplAlt :: (SimplAltFlag, SimplEnv)
|
| 3598 | 3696 | -> Maybe OutExpr -- The scrutinee
|
| 3599 | 3697 | -> [AltCon] -- These constructors can't be present when
|
| ... | ... | @@ -3603,19 +3701,21 @@ simplAlt :: (SimplAltFlag, SimplEnv) |
| 3603 | 3701 | -- add unfolding `v :-> bndr |> sym co`
|
| 3604 | 3702 | -> SimplCont
|
| 3605 | 3703 | -> InAlt
|
| 3606 | - -> SimplM OutAlt
|
|
| 3704 | + -> SimplM (SimplFloats, OutAlt)
|
|
| 3705 | + -- The floats scope over the RHS only, and may mention the
|
|
| 3706 | + -- binders of the alternative
|
|
| 3607 | 3707 | |
| 3608 | 3708 | simplAlt (saf,env) _scrut' imposs_deflt_cons case_bndr' bndr_swap' cont' (Alt DEFAULT bndrs rhs)
|
| 3609 | 3709 | = assert (null bndrs) $
|
| 3610 | 3710 | do { let env' = addDefaultUnfoldings env case_bndr' bndr_swap' imposs_deflt_cons
|
| 3611 | - ; rhs' <- simplAltExprC (saf,env') rhs cont'
|
|
| 3612 | - ; return (Alt DEFAULT [] rhs') }
|
|
| 3711 | + ; (floats, rhs') <- simplAltExprF (saf,env') rhs cont'
|
|
| 3712 | + ; return (floats, Alt DEFAULT [] rhs') }
|
|
| 3613 | 3713 | |
| 3614 | 3714 | simplAlt (saf,env) _scrut' _ case_bndr' bndr_swap' cont' (Alt (LitAlt lit) bndrs rhs)
|
| 3615 | 3715 | = assert (null bndrs) $
|
| 3616 | 3716 | do { let env' = addAltUnfoldings env case_bndr' bndr_swap' (Lit lit)
|
| 3617 | - ; rhs' <- simplAltExprC (saf,env') rhs cont'
|
|
| 3618 | - ; return (Alt (LitAlt lit) [] rhs') }
|
|
| 3717 | + ; (floats, rhs') <- simplAltExprF (saf,env') rhs cont'
|
|
| 3718 | + ; return (floats, Alt (LitAlt lit) [] rhs') }
|
|
| 3619 | 3719 | |
| 3620 | 3720 | simplAlt (saf,env) scrut' _ case_bndr' bndr_swap' cont' (Alt (DataAlt con) vs rhs)
|
| 3621 | 3721 | = do { -- See Note [Adding evaluatedness info to pattern-bound variables]
|
| ... | ... | @@ -3633,8 +3733,8 @@ simplAlt (saf,env) scrut' _ case_bndr' bndr_swap' cont' (Alt (DataAlt con) vs rh |
| 3633 | 3733 | con_app = mkConApp2 con inst_tys' vs'
|
| 3634 | 3734 | env'' = addAltUnfoldings env' case_bndr' bndr_swap' con_app
|
| 3635 | 3735 | |
| 3636 | - ; rhs' <- simplAltExprC (saf,env'') rhs cont'
|
|
| 3637 | - ; return (Alt (DataAlt con) vs' rhs') }
|
|
| 3736 | + ; (floats, rhs') <- simplAltExprF (saf,env'') rhs cont'
|
|
| 3737 | + ; return (floats, Alt (DataAlt con) vs' rhs') }
|
|
| 3638 | 3738 | |
| 3639 | 3739 | {- Note [Adding evaluatedness info to pattern-bound variables]
|
| 3640 | 3740 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| ... | ... | @@ -3815,11 +3915,6 @@ simplAltExprF (saf,env) expr cont |
| 3815 | 3915 | SAF_Out -> simplOutExpr env expr cont
|
| 3816 | 3916 | SAF_In -> simplExprF env expr cont
|
| 3817 | 3917 | |
| 3818 | -simplAltExprC :: (SimplAltFlag, SimplEnv) -> CoreExpr -> SimplCont -> SimplM OutExpr
|
|
| 3819 | -simplAltExprC env expr cont
|
|
| 3820 | - = do { (floats, expr') <- simplAltExprF env expr cont
|
|
| 3821 | - ; return (wrapFloats floats expr') }
|
|
| 3822 | - |
|
| 3823 | 3918 | |
| 3824 | 3919 | {- Note [Case binder evaluated-ness]
|
| 3825 | 3920 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| ... | ... | @@ -4338,7 +4433,7 @@ mkDupableContWithDmds env _ |
| 4338 | 4433 | scaleIdBy cont_scaling case_bndr
|
| 4339 | 4434 | |
| 4340 | 4435 | ; alts' <- forM (scaleAltsBy cont_scaling alts) $
|
| 4341 | - simplAlt (saf,alt_env1) Nothing [] case_bndr' NoBinderSwap alt_cont
|
|
| 4436 | + simplAltC (saf,alt_env1) Nothing [] case_bndr' NoBinderSwap alt_cont
|
|
| 4342 | 4437 | -- Safe to say that there are no handled-cons for the DEFAULT case
|
| 4343 | 4438 | -- NB: simplBinder does not zap deadness occ-info, so
|
| 4344 | 4439 | -- a dead case_bndr' will still advertise its deadness
|