Simon Peyton Jones pushed to branch wip/spj-try-opt-coercion at Glasgow Haskell Compiler / GHC

Commits:

6 changed files:

Changes:

  • compiler/GHC/Core/Coercion.hs
    ... ... @@ -709,7 +709,10 @@ isReflCo_maybe _ = Nothing
    709 709
     -- | Slowly checks if the coercion is reflexive. Don't call this in a loop,
    
    710 710
     -- as it walks over the entire coercion.
    
    711 711
     isReflexiveCo :: Coercion -> Bool
    
    712
    -isReflexiveCo = isJust . isReflexiveCo_maybe
    
    712
    +isReflexiveCo (Refl {})       = True
    
    713
    +isReflexiveCo (GRefl _ _ mco) = isReflKindMCo mco
    
    714
    +isReflexiveCo (SymCo co)      = isReflexiveCo co
    
    715
    +isReflexiveCo co              = coercionLKind co `eqType` coercionRKind co
    
    713 716
     
    
    714 717
     isReflexiveMCo :: MCoercion -> Bool
    
    715 718
     isReflexiveMCo MRefl    = True
    

  • compiler/GHC/Core/Opt/OccurAnal.hs
    ... ... @@ -28,7 +28,7 @@ core expression with (hopefully) improved usage information.
    28 28
     module GHC.Core.Opt.OccurAnal (
    
    29 29
         occurAnalysePgm,
    
    30 30
         occurAnalyseExpr,
    
    31
    -    zapLambdaBndrs, BinderSwapDecision(..), scrutOkForBinderSwap
    
    31
    +    zapLambdaBndrs
    
    32 32
       ) where
    
    33 33
     
    
    34 34
     import GHC.Prelude hiding ( head, init, last, tail )
    
    ... ... @@ -36,7 +36,7 @@ import GHC.Prelude hiding ( head, init, last, tail )
    36 36
     import GHC.Core
    
    37 37
     import GHC.Core.FVs
    
    38 38
     import GHC.Core.Utils   ( exprIsTrivial, isDefaultAlt, isExpandableApp,
    
    39
    -                          mkCastMCo, mkTicks )
    
    39
    +                          mkCastMCo, mkTicks, BinderSwapDecision(..), scrutOkForBinderSwap )
    
    40 40
     import GHC.Core.Opt.Arity   ( joinRhsArity, isOneShotBndr )
    
    41 41
     import GHC.Core.Coercion
    
    42 42
     import GHC.Core.Type
    
    ... ... @@ -3535,6 +3535,7 @@ doesn't use it. So this is only to satisfy the perhaps-over-picky Lint.
    3535 3535
     -}
    
    3536 3536
     
    
    3537 3537
     addBndrSwap :: OutExpr -> Id -> OccEnv -> OccEnv
    
    3538
    +-- See Note [Binder swap]
    
    3538 3539
     -- See Note [The binder-swap substitution]
    
    3539 3540
     addBndrSwap scrut case_bndr
    
    3540 3541
                 env@(OccEnv { occ_bs_env = swap_env, occ_bs_rng = rng_vars })
    
    ... ... @@ -3542,7 +3543,7 @@ addBndrSwap scrut case_bndr
    3542 3543
       , scrut_var /= case_bndr
    
    3543 3544
           -- Consider: case x of x { ... }
    
    3544 3545
           -- Do not add [x :-> x] to occ_bs_env, else lookupBndrSwap will loop
    
    3545
    -  = env { occ_bs_env = extendVarEnv swap_env scrut_var (case_bndr', mco)
    
    3546
    +  = env { occ_bs_env = extendVarEnv swap_env scrut_var (case_bndr', mkSymMCo mco)
    
    3546 3547
             , occ_bs_rng = rng_vars `extendVarSet` case_bndr'
    
    3547 3548
                            `unionVarSet` tyCoVarsOfMCo mco }
    
    3548 3549
     
    
    ... ... @@ -3552,27 +3553,6 @@ addBndrSwap scrut case_bndr
    3552 3553
         case_bndr' = zapIdOccInfo case_bndr
    
    3553 3554
                      -- See Note [Zap case binders in proxy bindings]
    
    3554 3555
     
    
    3555
    --- | See bBinderSwaOk.
    
    3556
    -data BinderSwapDecision
    
    3557
    -  = NoBinderSwap
    
    3558
    -  | DoBinderSwap OutVar MCoercion
    
    3559
    -
    
    3560
    -scrutOkForBinderSwap :: OutExpr -> BinderSwapDecision
    
    3561
    --- If (scrutOkForBinderSwap e = DoBinderSwap v mco, then
    
    3562
    ---    v = e |> mco
    
    3563
    --- See Note [Case of cast]
    
    3564
    --- See Historical Note [Care with binder-swap on dictionaries]
    
    3565
    ---
    
    3566
    --- We use this same function in SpecConstr, and Simplify.Iteration,
    
    3567
    --- when something binder-swap-like is happening
    
    3568
    -scrutOkForBinderSwap e
    
    3569
    -  = case e of
    
    3570
    -      Tick _ e        -> scrutOkForBinderSwap e  -- Drop ticks
    
    3571
    -      Var v           -> DoBinderSwap v MRefl
    
    3572
    -      Cast (Var v) co -> DoBinderSwap v (MCo (mkSymCo co))
    
    3573
    -                         -- Cast: see Note [Case of cast]
    
    3574
    -      _               -> NoBinderSwap
    
    3575
    -
    
    3576 3556
     lookupBndrSwap :: OccEnv -> Id -> (CoreExpr, Id)
    
    3577 3557
     -- See Note [The binder-swap substitution]
    
    3578 3558
     -- Returns an expression of the same type as Id
    

  • compiler/GHC/Core/Opt/Simplify/Iteration.hs
    ... ... @@ -22,7 +22,7 @@ import GHC.Core.TyCo.Compare( eqType )
    22 22
     import GHC.Core.Opt.Simplify.Env
    
    23 23
     import GHC.Core.Opt.Simplify.Inline
    
    24 24
     import GHC.Core.Opt.Simplify.Utils
    
    25
    -import GHC.Core.Opt.OccurAnal ( occurAnalyseExpr, zapLambdaBndrs, scrutOkForBinderSwap, BinderSwapDecision (..) )
    
    25
    +import GHC.Core.Opt.OccurAnal ( occurAnalyseExpr, zapLambdaBndrs )
    
    26 26
     import GHC.Core.Make       ( FloatBind, mkImpossibleExpr, castBottomExpr )
    
    27 27
     import qualified GHC.Core.Make
    
    28 28
     import GHC.Core.Coercion hiding ( substCo, substCoVar )
    
    ... ... @@ -1531,7 +1531,8 @@ rebuild_go env expr cont
    1531 1531
           Stop {}          -> return (emptyFloats env, expr)
    
    1532 1532
           TickIt t cont    -> rebuild_go env (mkTick t expr) cont
    
    1533 1533
           CastIt { sc_co = co, sc_opt = opt, sc_cont = cont }
    
    1534
    -        -> rebuild_go env (mkCast expr co') cont
    
    1534
    +        | isReflexiveCo co -> rebuild_go env expr              cont
    
    1535
    +        | otherwise        -> rebuild_go env (mkCast expr co') cont
    
    1535 1536
                -- NB: mkCast implements the (Coercion co |> g) optimisation
    
    1536 1537
             where
    
    1537 1538
               co' = optOutCoercion env co opt
    
    ... ... @@ -3593,11 +3594,13 @@ addAltUnfoldings env case_bndr bndr_swap con_app
    3593 3594
         env1 = addBinderUnfolding env case_bndr con_app_unf
    
    3594 3595
     
    
    3595 3596
         -- See Note [Add unfolding for scrutinee]
    
    3597
    +    -- e.g. case (x |> co) of K a b -> blah
    
    3598
    +    --      We add to `x` the unfolding  (K a b |> sym co)
    
    3596 3599
         env2 | DoBinderSwap v mco <- bndr_swap
    
    3597 3600
              = addBinderUnfolding env1 v $
    
    3598 3601
                   if isReflMCo mco  -- isReflMCo: avoid calling mk_simple_unf
    
    3599 3602
                   then con_app_unf  --            twice in the common case
    
    3600
    -              else mk_simple_unf (mkCastMCo con_app mco)
    
    3603
    +              else mk_simple_unf (mkCastMCo con_app (mkSymMCo mco))
    
    3601 3604
     
    
    3602 3605
              | otherwise = env1
    
    3603 3606
     
    

  • compiler/GHC/Core/Opt/Simplify/Utils.hs
    ... ... @@ -2693,7 +2693,7 @@ mkCase, mkCase1, mkCase2, mkCase3
    2693 2693
     
    
    2694 2694
     mkCase mode scrut outer_bndr alts_ty alts
    
    2695 2695
       | sm_case_merge mode
    
    2696
    -  , Just (joins, alts') <- mergeCaseAlts outer_bndr alts
    
    2696
    +  , Just (joins, alts') <- mergeCaseAlts scrut outer_bndr alts
    
    2697 2697
       = do  { tick (CaseMerge outer_bndr)
    
    2698 2698
             ; case_expr <- mkCase1 mode scrut outer_bndr alts_ty alts'
    
    2699 2699
             ; return (mkLets joins case_expr) }
    

  • compiler/GHC/Core/Opt/SpecConstr.hs
    ... ... @@ -30,7 +30,6 @@ import GHC.Core.Opt.Simplify.Inline
    30 30
     import GHC.Core.FVs     ( exprsFreeVarsList, exprFreeVars )
    
    31 31
     import GHC.Core.Opt.Monad
    
    32 32
     import GHC.Core.Opt.WorkWrap.Utils
    
    33
    -import GHC.Core.Opt.OccurAnal( BinderSwapDecision(..), scrutOkForBinderSwap )
    
    34 33
     import GHC.Core.DataCon
    
    35 34
     import GHC.Core.Class( classTyVars )
    
    36 35
     import GHC.Core.Coercion hiding( substCo )
    
    ... ... @@ -2025,9 +2024,9 @@ spec_one env fn arg_bndrs body (call_pat, rule_number)
    2025 2024
     --               , text "spec_call_args" <+> ppr spec_call_args
    
    2026 2025
     --               , text "rule_rhs" <+> ppr rule_rhs
    
    2027 2026
     --               , text "adds_void_worker_arg" <+> ppr add_void_arg
    
    2028
    -----               , text "body" <+> ppr body
    
    2029
    -----               , text "spec_rhs" <+> ppr spec_rhs
    
    2030
    -----               , text "how_bound" <+> ppr (sc_how_bound env) ]
    
    2027
    +--               , text "body" <+> ppr body
    
    2028
    +--               , text "spec_rhs" <+> ppr spec_rhs
    
    2029
    +--               , text "how_bound" <+> ppr (sc_how_bound env) ]
    
    2031 2030
     --               ]
    
    2032 2031
             ; return (spec_usg, OS { os_pat = call_pat, os_rule = rule
    
    2033 2032
                                    , os_id = spec_id
    

  • compiler/GHC/Core/Utils.hs
    ... ... @@ -19,6 +19,7 @@ module GHC.Core.Utils (
    19 19
             mergeAlts, mergeCaseAlts, trimConArgs,
    
    20 20
             filterAlts, combineIdenticalAlts, refineDefaultAlt,
    
    21 21
             scaleAltsBy,
    
    22
    +        BinderSwapDecision(..), scrutOkForBinderSwap,
    
    22 23
     
    
    23 24
             -- * Properties of expressions
    
    24 25
             exprType, coreAltType, coreAltsType,
    
    ... ... @@ -116,7 +117,6 @@ import Data.ByteString ( ByteString )
    116 117
     import Data.Function       ( on )
    
    117 118
     import Data.List           ( sort, sortBy, partition, zipWith4, mapAccumL )
    
    118 119
     import Data.Ord            ( comparing )
    
    119
    -import Control.Monad       ( guard )
    
    120 120
     import qualified Data.Set as Set
    
    121 121
     
    
    122 122
     {-
    
    ... ... @@ -590,6 +590,28 @@ The default alternative must be first, if it exists at all.
    590 590
     This makes it easy to find, though it makes matching marginally harder.
    
    591 591
     -}
    
    592 592
     
    
    593
    +data BinderSwapDecision
    
    594
    +  = NoBinderSwap
    
    595
    +  | DoBinderSwap OutVar MCoercion
    
    596
    +
    
    597
    +scrutOkForBinderSwap :: OutExpr -> BinderSwapDecision
    
    598
    +-- If (scrutOkForBinderSwap e = DoBinderSwap v mco, then
    
    599
    +--    e = v |> mco
    
    600
    +-- See Note [Case of cast]
    
    601
    +-- See Historical Note [Care with binder-swap on dictionaries]
    
    602
    +--
    
    603
    +-- We use this same function in SpecConstr, and Simplify.Iteration,
    
    604
    +-- when something binder-swap-like is happening
    
    605
    +--
    
    606
    +-- See Note [Binder swap] in GHC.Core.Opt.OccurAnal
    
    607
    +scrutOkForBinderSwap e
    
    608
    +  = case e of
    
    609
    +      Tick _ e        -> scrutOkForBinderSwap e  -- Drop ticks
    
    610
    +      Var v           -> DoBinderSwap v MRefl
    
    611
    +      Cast (Var v) co -> DoBinderSwap v (MCo co)
    
    612
    +                         -- Cast: see Note [Case of cast]
    
    613
    +      _               -> NoBinderSwap
    
    614
    +
    
    593 615
     -- | Extract the default case alternative
    
    594 616
     findDefault :: [Alt b] -> ([Alt b], Maybe (Expr b))
    
    595 617
     findDefault (Alt DEFAULT args rhs : alts) = assert (null args) (alts, Just rhs)
    
    ... ... @@ -651,9 +673,9 @@ filters down the matching alternatives in GHC.Core.Opt.Simplify.rebuildCase.
    651 673
     -}
    
    652 674
     
    
    653 675
     ---------------------------------
    
    654
    -mergeCaseAlts :: Id -> [CoreAlt] -> Maybe ([CoreBind], [CoreAlt])
    
    676
    +mergeCaseAlts :: CoreExpr -> Id -> [CoreAlt] -> Maybe ([CoreBind], [CoreAlt])
    
    655 677
     -- See Note [Merge Nested Cases]
    
    656
    -mergeCaseAlts outer_bndr (Alt DEFAULT _ deflt_rhs : outer_alts)
    
    678
    +mergeCaseAlts scrut outer_bndr (Alt DEFAULT _ deflt_rhs : outer_alts)
    
    657 679
       | Just (joins, inner_alts) <- go deflt_rhs
    
    658 680
       = Just (joins, mergeAlts outer_alts inner_alts)
    
    659 681
                     -- NB: mergeAlts gives priority to the left
    
    ... ... @@ -665,6 +687,9 @@ mergeCaseAlts outer_bndr (Alt DEFAULT _ deflt_rhs : outer_alts)
    665 687
                     -- When we merge, we must ensure that e1 takes
    
    666 688
                     -- precedence over e2 as the value for A!
    
    667 689
       where
    
    690
    +    bndr_swap :: BinderSwapDecision
    
    691
    +    bndr_swap = scrutOkForBinderSwap scrut
    
    692
    +
    
    668 693
         go :: CoreExpr -> Maybe ([CoreBind], [CoreAlt])
    
    669 694
     
    
    670 695
         -- Whizzo: we can merge!
    
    ... ... @@ -702,11 +727,10 @@ mergeCaseAlts outer_bndr (Alt DEFAULT _ deflt_rhs : outer_alts)
    702 727
           = do { (joins, alts) <- go body
    
    703 728
     
    
    704 729
                  -- Check for capture; but only if we could otherwise do a merge
    
    705
    -           ; let capture = outer_bndr `elem` bindersOf bind
    
    706
    -                           || outer_bndr `elemVarSet` bindFreeVars bind
    
    707
    -           ; guard (not capture)
    
    730
    +             --    (i.e. the recursive `go` succeeds)
    
    731
    +           ; fix_up_binds <- okToFloatJoin bndr_swap outer_bndr bind
    
    708 732
     
    
    709
    -           ; return (bind:joins, alts ) }
    
    733
    +           ; return (fix_up_binds ++ (bind : joins), alts ) }
    
    710 734
           | otherwise
    
    711 735
           = Nothing
    
    712 736
     
    
    ... ... @@ -718,7 +742,25 @@ mergeCaseAlts outer_bndr (Alt DEFAULT _ deflt_rhs : outer_alts)
    718 742
     
    
    719 743
         go _ = Nothing
    
    720 744
     
    
    721
    -mergeCaseAlts _ _ = Nothing
    
    745
    +mergeCaseAlts _ _ _ = Nothing
    
    746
    +
    
    747
    +okToFloatJoin :: BinderSwapDecision -> Id -> CoreBind -> Maybe [CoreBind]
    
    748
    +-- Check a join-point binding to see if it can be floated out of
    
    749
    +-- the DEFAULT branch of a `case`.   A Just result means "yes",
    
    750
    +-- and the [CoreBInd] are the extra fix-up bindings to add.
    
    751
    +-- See Note [Floating join points out of DEFAULT alternatives]
    
    752
    +okToFloatJoin bndr_swap outer_bndr bind
    
    753
    +  | outer_bndr `elem` bindersOf bind          -- (a)
    
    754
    +  = Nothing
    
    755
    +  | outer_bndr `elemVarSet` bindFreeVars bind -- (b)
    
    756
    +  = case bndr_swap of
    
    757
    +      DoBinderSwap scrut_var mco
    
    758
    +        | scrut_var /= outer_bndr
    
    759
    +        -> Just [ NonRec outer_bndr (mkCastMCo (Var scrut_var) mco) ]
    
    760
    +      _ -> Nothing
    
    761
    +  | otherwise
    
    762
    +  = Just []
    
    763
    +
    
    722 764
     
    
    723 765
     ---------------------------------
    
    724 766
     mergeAlts :: [Alt a] -> [Alt a] -> [Alt a]
    
    ... ... @@ -927,10 +969,43 @@ Wrinkles
    927 969
           non-join-points unless the /outer/ case has just one alternative; doing
    
    928 970
           so would risk more allocation
    
    929 971
     
    
    972
    +      Floating out join points isn't entirely straightforward.
    
    973
    +      See Note [Floating join points out of DEFAULT alternatives]
    
    974
    +
    
    930 975
     (MC5) See Note [Cascading case merge]
    
    931 976
     
    
    932 977
     See also Note [Example of case-merging and caseRules] in GHC.Core.Opt.Simplify.Utils
    
    933 978
     
    
    979
    +Note [Floating join points out of DEFAULT alternatives]
    
    980
    +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    981
    +Consider this, from (MC4) of Note [Merge Nested Cases]
    
    982
    +   case x of r
    
    983
    +     DEFAULT -> join j = rhs in case r of ...
    
    984
    +     alts
    
    985
    +
    
    986
    +We want to float that join point out to give this
    
    987
    +   join j = rhs
    
    988
    +   case x of r
    
    989
    +     DEFAULT -> case r of ...
    
    990
    +     alts
    
    991
    +
    
    992
    +But doing so is flat-out wrong if the scoping gets messed up:
    
    993
    +    (a) case x of r { DEFAULT -> join r = ... in ...r... }
    
    994
    +    (b) case x of r { DEFAULT -> join j = ...r.. in ... }
    
    995
    +In both cases we can't float the join point out because r changes its meaning.
    
    996
    +
    
    997
    +BUT we can fix up case (b) by adding an extra binding, like this
    
    998
    +    let r = x in
    
    999
    +    join j = rhs[r]
    
    1000
    +    case x of r
    
    1001
    +       DEFAULT -> ...r...
    
    1002
    +       ...other alts...
    
    1003
    +
    
    1004
    +This extra binding is figured out by `okToFloatJoin`.
    
    1005
    +
    
    1006
    +Note that the cases that still don't work (e.g. (a)) will probably work fine the
    
    1007
    +next iteration of the Simplifier, because they involve shadowing, and the Simplifier
    
    1008
    +generally eliminates shadowing.
    
    934 1009
     
    
    935 1010
     Note [Cascading case merge]
    
    936 1011
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~