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

Commits:

10 changed files:

Changes:

  • compiler/GHC/Core/Coercion.hs
    ... ... @@ -69,7 +69,8 @@ module GHC.Core.Coercion (
    69 69
     
    
    70 70
             isReflKindCo,isReflKindMCo,
    
    71 71
             isReflCo, isReflCo_maybe,
    
    72
    -        isReflexiveMCo, isReflexiveCo, isReflexiveCo_maybe,
    
    72
    +        isReflexiveMCo, isReflexiveCo,
    
    73
    +        isReflexiveCoIgnoringMultiplicity,
    
    73 74
             isReflCoVar_maybe, mkGReflLeftMCo, mkGReflRightMCo,
    
    74 75
             mkCoherenceRightMCo,
    
    75 76
     
    
    ... ... @@ -665,7 +666,9 @@ isReflCoVar_maybe cv
    665 666
     -- See Note [KindCoercion] in GHC.Core.TyCo.Rep
    
    666 667
     isKindCo :: Coercion -> Bool
    
    667 668
     isKindCo co
    
    668
    -  = role == Nominal && isLiftedTypeKind kk1 && isLiftedTypeKind kk2
    
    669
    +  = role == Nominal
    
    670
    +    && definitelyLiftedType kk1
    
    671
    +    && definitelyLiftedType kk2
    
    669 672
       where
    
    670 673
         (Pair kk1 kk2, role) = coercionKindRole co
    
    671 674
     
    
    ... ... @@ -679,8 +682,14 @@ isKindCo co
    679 682
     --    so we return True
    
    680 683
     -- See Note [KindCoercion] in GHC.Core.TyCo.Rep
    
    681 684
     isReflKindCo :: HasDebugCallStack => KindCoercion -> Bool
    
    682
    -isReflKindCo co@(GRefl {}) = assertPpr (isKindCo co) (ppr co) $
    
    685
    +isReflKindCo co@(GRefl {}) = assertPpr (isKindCo co) (ppr co $$ ppr kk1 $$ ppr kk2
    
    686
    +                                                   $$ ppr (isLiftedTypeKind kk1)
    
    687
    +                                                   $$ ppr (isLiftedTypeKind kk2)
    
    688
    +                                                   $$ ppr (role == Nominal)
    
    689
    +                                                   $$ ppr (isKindCo  co))
    
    683 690
                                  True
    
    691
    +  where
    
    692
    +    (Pair kk1 kk2, role) = coercionKindRole co
    
    684 693
     isReflKindCo (Refl{})      = True -- Refl ty == GRefl N ty MRefl
    
    685 694
     isReflKindCo _             = False
    
    686 695
     
    
    ... ... @@ -700,7 +709,7 @@ isReflCo _ = False
    700 709
     
    
    701 710
     -- | Returns the type coerced if this coercion is reflexive. Guaranteed
    
    702 711
     -- to work very quickly. Sometimes a coercion can be reflexive, but not
    
    703
    --- obviously so. c.f. 'isReflexiveCo_maybe'
    
    712
    +-- obviously so.
    
    704 713
     isReflCo_maybe :: Coercion -> Maybe (Type, Role)
    
    705 714
     isReflCo_maybe (Refl ty) = Just (ty, Nominal)
    
    706 715
     isReflCo_maybe (GRefl r ty mco) | isReflKindMCo mco = Just (ty, r)
    
    ... ... @@ -709,27 +718,26 @@ isReflCo_maybe _ = Nothing
    709 718
     -- | Slowly checks if the coercion is reflexive. Don't call this in a loop,
    
    710 719
     -- as it walks over the entire coercion.
    
    711 720
     isReflexiveCo :: Coercion -> Bool
    
    712
    -isReflexiveCo (Refl {})       = True
    
    713
    -isReflexiveCo (GRefl _ _ mco) = isReflKindMCo mco
    
    714
    -isReflexiveCo (SymCo co)      = isReflexiveCo co
    
    715
    -isReflexiveCo co              = coercionLKind co `eqType` coercionRKind co
    
    721
    +isReflexiveCo co
    
    722
    +  = case co of
    
    723
    +      Refl {}       -> True
    
    724
    +      GRefl _ _ mco -> isReflKindMCo mco
    
    725
    +      SymCo co      -> isReflexiveCo co
    
    726
    +      _             -> coercionLKind co `eqType` coercionRKind co
    
    727
    +
    
    728
    +-- | Just like isReflexiveCo but ignores multiplicity
    
    729
    +isReflexiveCoIgnoringMultiplicity :: Coercion -> Bool
    
    730
    +isReflexiveCoIgnoringMultiplicity co
    
    731
    +  = case co of
    
    732
    +      Refl {}       -> True
    
    733
    +      GRefl _ _ mco -> isReflKindMCo mco
    
    734
    +      SymCo co      -> isReflexiveCoIgnoringMultiplicity co
    
    735
    +      _             -> coercionLKind co `eqTypeIgnoringMultiplicity` coercionRKind co
    
    716 736
     
    
    717 737
     isReflexiveMCo :: MCoercion -> Bool
    
    718 738
     isReflexiveMCo MRefl    = True
    
    719 739
     isReflexiveMCo (MCo co) = isReflexiveCo co
    
    720 740
     
    
    721
    --- | Extracts the coerced type from a reflexive coercion. This potentially
    
    722
    --- walks over the entire coercion, so avoid doing this in a loop.
    
    723
    -isReflexiveCo_maybe :: Coercion -> Maybe (Type, Role)
    
    724
    -isReflexiveCo_maybe (Refl ty) = Just (ty, Nominal)
    
    725
    -isReflexiveCo_maybe (GRefl r ty mco) | isReflKindMCo mco = Just (ty, r)
    
    726
    -isReflexiveCo_maybe co
    
    727
    -  | ty1 `eqType` ty2
    
    728
    -  = Just (ty1, r)
    
    729
    -  | otherwise
    
    730
    -  = Nothing
    
    731
    -  where (Pair ty1 ty2, r) = coercionKindRole co
    
    732
    -
    
    733 741
     forAllCoKindCo :: TyCoVar -> KindMCoercion -> KindCoercion
    
    734 742
     -- Get the kind coercion from a ForAllCo
    
    735 743
     forAllCoKindCo _   (MCo co) = co
    

  • compiler/GHC/Core/Coercion/Opt.hs
    1 1
     -- (c) The University of Glasgow 2006
    
    2
    -
    
    3 2
     {-# LANGUAGE CPP #-}
    
    4 3
     
    
    5 4
     module GHC.Core.Coercion.Opt
    
    6
    -   ( optCoercion
    
    5
    +   ( optCoProgram, optCoercion
    
    7 6
        , OptCoercionOpts (..)
    
    8 7
        )
    
    9 8
     where
    
    ... ... @@ -12,6 +11,7 @@ import GHC.Prelude
    12 11
     
    
    13 12
     import GHC.Tc.Utils.TcType   ( exactTyCoVarsOfType )
    
    14 13
     
    
    14
    +import GHC.Core
    
    15 15
     import GHC.Core.TyCo.Rep
    
    16 16
     import GHC.Core.TyCo.Subst
    
    17 17
     import GHC.Core.TyCo.Compare( eqForAllVis, eqTypeIgnoringMultiplicity )
    
    ... ... @@ -164,6 +164,54 @@ We use the following invariants:
    164 164
            to the little bits being substituted.
    
    165 165
     -}
    
    166 166
     
    
    167
    +{- **********************************************************************
    
    168
    +%*                                                                      *
    
    169
    +                    optCoercionPgm
    
    170
    +%*                                                                      *
    
    171
    +%********************************************************************* -}
    
    172
    +
    
    173
    +optCoProgram :: CoreProgram -> CoreProgram
    
    174
    +optCoProgram binds
    
    175
    +  = map go binds
    
    176
    +  where
    
    177
    +    go (NonRec b r) = NonRec b (optCoExpr in_scope r)
    
    178
    +    go (Rec prs)    = Rec (mapSnd (optCoExpr in_scope) prs)
    
    179
    +    in_scope = mkInScopeSetList (bindersOfBinds binds)
    
    180
    +       -- Put all top-level binders into scope; it is possible to have
    
    181
    +       -- forward references.  See Note [Glomming] in GHC.Core.Opt.OccurAnal
    
    182
    +
    
    183
    +optCoExpr :: InScopeSet -> CoreExpr -> CoreExpr
    
    184
    +optCoExpr _ e@(Var {})     = e
    
    185
    +optCoExpr _ e@(Lit {})     = e
    
    186
    +optCoExpr _ e@(Type {})    = e
    
    187
    +optCoExpr is (App e1 e2)   = App (optCoExpr is e1) (optCoExpr is e2)
    
    188
    +optCoExpr is (Lam b e)     = Lam b (optCoExpr (is `extendInScopeSet` b) e)
    
    189
    +optCoExpr is (Coercion co) = Coercion (optCo is co)
    
    190
    +optCoExpr is (Cast e co)   = Cast (optCoExpr is e) (optCo is co)
    
    191
    +optCoExpr is (Tick t e)    = Tick t (optCoExpr is e)
    
    192
    +optCoExpr is (Let (NonRec b r) e)  = Let (NonRec b (optCoExpr is r))
    
    193
    +                                         (optCoExpr (is `extendInScopeSet` b) e)
    
    194
    +optCoExpr is (Let (Rec prs)    e)  = Let (Rec (mapSnd (optCoExpr is') prs))
    
    195
    +                                         (optCoExpr is' e)
    
    196
    +                                   where
    
    197
    +                                     is' = is `extendInScopeSetList` map fst prs
    
    198
    +optCoExpr is (Case e b ty alts) = Case (optCoExpr is e) b ty
    
    199
    +                                       (map (optCoAlt (is `extendInScopeSet` b)) alts)
    
    200
    +
    
    201
    +optCo :: InScopeSet -> Coercion -> Coercion
    
    202
    +optCo is co = optCoercion' (mkEmptySubst is) co
    
    203
    +
    
    204
    +optCoAlt :: InScopeSet -> CoreAlt -> CoreAlt
    
    205
    +optCoAlt is (Alt k bs e)
    
    206
    +  = Alt k bs (optCoExpr (is `extendInScopeSetList` bs) e)
    
    207
    +
    
    208
    +
    
    209
    +{- **********************************************************************
    
    210
    +%*                                                                      *
    
    211
    +                    optCoercion
    
    212
    +%*                                                                      *
    
    213
    +%********************************************************************* -}
    
    214
    +
    
    167 215
     -- | Coercion optimisation options
    
    168 216
     newtype OptCoercionOpts = OptCoercionOpts
    
    169 217
        { optCoercionEnabled :: Bool  -- ^ Enable coercion optimisation (reduce its size)
    
    ... ... @@ -624,7 +672,7 @@ opt_univ env sym prov deps role ty1 ty2
    624 672
         in
    
    625 673
           -- We only Lint multiplicities in the output of the typechecker, as
    
    626 674
           -- described in Note [Linting linearity] in GHC.Core.Lint. This means
    
    627
    -      -- we can use 'eqTypeIgnoringMultiplicity' instea of 'eqType' below.
    
    675
    +      -- we can use 'eqTypeIgnoringMultiplicity' instead of 'eqType' below.
    
    628 676
           --
    
    629 677
           -- In particular, this gets rid of 'SubMultProv' coercions that were
    
    630 678
           -- introduced for typechecking multiplicities of data constructors, as
    

  • compiler/GHC/Core/Opt/Pipeline.hs
    ... ... @@ -24,6 +24,7 @@ import GHC.Platform.Ways ( hasWay, Way(WayProf) )
    24 24
     import GHC.Core
    
    25 25
     import GHC.Core.SimpleOpt (simpleOptPgm)
    
    26 26
     import GHC.Core.Opt.CSE  ( cseProgram )
    
    27
    +import GHC.Core.Coercion.Opt  ( optCoProgram )
    
    27 28
     import GHC.Core.Rules   ( RuleBase, ruleCheckProgram, getRules )
    
    28 29
     import GHC.Core.Ppr     ( pprCoreBindings, pprRules )
    
    29 30
     import GHC.Core.Utils   ( dumpIdInfoOfProgram )
    
    ... ... @@ -134,6 +135,7 @@ getCoreToDo dflags hpt_rule_base extra_vars
    134 135
         strictness    = gopt Opt_Strictness                   dflags
    
    135 136
         full_laziness = gopt Opt_FullLaziness                 dflags
    
    136 137
         do_specialise = gopt Opt_Specialise                   dflags
    
    138
    +    do_co_opt     = gopt Opt_OptCoercion                 dflags
    
    137 139
         do_float_in   = gopt Opt_FloatIn                      dflags
    
    138 140
         cse           = gopt Opt_CSE                          dflags
    
    139 141
         spec_constr   = gopt Opt_SpecConstr                   dflags
    
    ... ... @@ -146,7 +148,6 @@ getCoreToDo dflags hpt_rule_base extra_vars
    146 148
         static_ptrs   = xopt LangExt.StaticPointers           dflags
    
    147 149
         profiling     = ways dflags `hasWay` WayProf
    
    148 150
     
    
    149
    -    do_presimplify = do_specialise -- TODO: any other optimizations benefit from pre-simplification?
    
    150 151
         do_simpl3      = const_fold || rules_on -- TODO: any other optimizations benefit from three-phase simplification?
    
    151 152
     
    
    152 153
         maybe_rule_check phase = runMaybe rule_check (CoreDoRuleCheck phase)
    
    ... ... @@ -215,12 +216,14 @@ getCoreToDo dflags hpt_rule_base extra_vars
    215 216
             -- after this before anything else
    
    216 217
             runWhen static_args (CoreDoPasses [ simpl_gently, CoreDoStaticArgs ]),
    
    217 218
     
    
    218
    -        -- initial simplify: mk specialiser happy: minimum effort please
    
    219
    -        runWhen do_presimplify simpl_gently,
    
    220
    -
    
    219
    +        -- Initial simplify: make specialiser happy and/or optimise coercions:
    
    220
    +        --                   minimum effort please
    
    221 221
             -- Specialisation is best done before full laziness
    
    222 222
             -- so that overloaded functions have all their dictionary lambdas manifest
    
    223
    -        runWhen do_specialise CoreDoSpecialising,
    
    223
    +        runWhen (do_specialise || do_co_opt) $
    
    224
    +        CoreDoPasses [ simpl_gently
    
    225
    +                     , runWhen do_co_opt     CoreOptCoercion
    
    226
    +                     , runWhen do_specialise CoreDoSpecialising ],
    
    224 227
     
    
    225 228
             if full_laziness then
    
    226 229
                CoreDoFloatOutwards $ FloatOutSwitches
    
    ... ... @@ -496,6 +499,9 @@ doCorePass pass guts = do
    496 499
         CoreCSE                   -> {-# SCC "CommonSubExpr" #-}
    
    497 500
                                      updateBinds cseProgram
    
    498 501
     
    
    502
    +    CoreOptCoercion           -> {-# SCC "OptCoercion" #-}
    
    503
    +                                 updateBinds optCoProgram
    
    504
    +
    
    499 505
         CoreLiberateCase          -> {-# SCC "LiberateCase" #-}
    
    500 506
                                      updateBinds (liberateCase (initLiberateCaseOpts dflags))
    
    501 507
     
    

  • compiler/GHC/Core/Opt/Pipeline/Types.hs
    ... ... @@ -52,6 +52,7 @@ data CoreToDo -- These are diff core-to-core passes,
    52 52
       | CoreDoSpecialising
    
    53 53
       | CoreDoSpecConstr
    
    54 54
       | CoreCSE
    
    55
    +  | CoreOptCoercion  -- Run the coercion optimiser
    
    55 56
       | CoreDoRuleCheck CompilerPhase String  -- Check for non-application of rules
    
    56 57
                                            -- matching this string
    
    57 58
       | CoreDoNothing                -- Useful when building up
    
    ... ... @@ -81,6 +82,7 @@ instance Outputable CoreToDo where
    81 82
       ppr CoreDoSpecialising       = text "Specialise"
    
    82 83
       ppr CoreDoSpecConstr         = text "SpecConstr"
    
    83 84
       ppr CoreCSE                  = text "Common sub-expression"
    
    85
    +  ppr CoreOptCoercion          = text "Optimise coercions"
    
    84 86
       ppr CoreDesugar              = text "Desugar (before optimization)"
    
    85 87
       ppr CoreDesugarOpt           = text "Desugar (after optimization)"
    
    86 88
       ppr CoreTidy                 = text "Tidy Core"
    

  • compiler/GHC/Core/Opt/Simplify/Iteration.hs
    ... ... @@ -1531,8 +1531,11 @@ 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
    -        | isReflexiveCo co -> rebuild_go env expr              cont
    
    1535
    -        | otherwise        -> rebuild_go env (mkCast expr co') cont
    
    1534
    +        | isReflexiveCoIgnoringMultiplicity co
    
    1535
    +              -- ignoring multiplicity: c.f. GHC.Core.Coercion.Opt.opt_univ
    
    1536
    +        -> rebuild_go env expr cont
    
    1537
    +        | otherwise
    
    1538
    +        -> rebuild_go env (mkCast expr co') cont
    
    1536 1539
                -- NB: mkCast implements the (Coercion co |> g) optimisation
    
    1537 1540
             where
    
    1538 1541
               co' = optOutCoercion env co opt
    

  • compiler/GHC/Driver/Config.hs
    ... ... @@ -17,7 +17,7 @@ import GHCi.Message (EvalOpts(..))
    17 17
     -- | Initialise coercion optimiser configuration from DynFlags
    
    18 18
     initOptCoercionOpts :: DynFlags -> OptCoercionOpts
    
    19 19
     initOptCoercionOpts dflags = OptCoercionOpts
    
    20
    -   { optCoercionEnabled = not (hasNoOptCoercion dflags)
    
    20
    +   { optCoercionEnabled = gopt Opt_OptCoercion dflags
    
    21 21
        }
    
    22 22
     
    
    23 23
     -- | Initialise Simple optimiser configuration from DynFlags
    

  • compiler/GHC/Driver/Config/Core/Lint.hs
    ... ... @@ -77,6 +77,7 @@ initEndPassConfig dflags extra_vars name_ppr_ctx pass = EndPassConfig
    77 77
     coreDumpFlag :: CoreToDo -> Maybe DumpFlag
    
    78 78
     coreDumpFlag (CoreDoSimplify {})      = Just Opt_D_verbose_core2core
    
    79 79
     coreDumpFlag (CoreDoPluginPass {})    = Just Opt_D_verbose_core2core
    
    80
    +coreDumpFlag (CoreOptCoercion {})     = Just Opt_D_verbose_core2core
    
    80 81
     coreDumpFlag CoreDoFloatInwards       = Just Opt_D_dump_float_in
    
    81 82
     coreDumpFlag (CoreDoFloatOutwards {}) = Just Opt_D_dump_float_out
    
    82 83
     coreDumpFlag CoreLiberateCase         = Just Opt_D_dump_liberate_case
    

  • compiler/GHC/Driver/DynFlags.hs
    ... ... @@ -996,7 +996,7 @@ hasNoStateHack :: DynFlags -> Bool
    996 996
     hasNoStateHack = gopt Opt_G_NoStateHack
    
    997 997
     
    
    998 998
     hasNoOptCoercion :: DynFlags -> Bool
    
    999
    -hasNoOptCoercion = gopt Opt_G_NoOptCoercion
    
    999
    +hasNoOptCoercion flags = not (gopt Opt_OptCoercion flags)
    
    1000 1000
     
    
    1001 1001
     -- | Test whether a 'DumpFlag' is set
    
    1002 1002
     dopt :: DumpFlag -> DynFlags -> Bool
    
    ... ... @@ -1237,6 +1237,7 @@ optLevelFlags -- see Note [Documenting optimisation flags]
    1237 1237
         , ([1,2],   Opt_DoCleverArgEtaExpansion) -- See Note [Eta expansion of arguments in CorePrep]
    
    1238 1238
         , ([0,1,2], Opt_DoEtaReduction)          -- See Note [Eta-reduction in -O0]
    
    1239 1239
         , ([0,1,2], Opt_ProfManualCcs )
    
    1240
    +    , ([0,1,2], Opt_OptCoercion )
    
    1240 1241
         , ([2], Opt_DictsStrict)
    
    1241 1242
     
    
    1242 1243
         , ([0],     Opt_IgnoreInterfacePragmas)
    

  • compiler/GHC/Driver/Flags.hs
    ... ... @@ -641,6 +641,7 @@ data GeneralFlag
    641 641
        | Opt_InlineGenerics
    
    642 642
        | Opt_InlineGenericsAggressively
    
    643 643
        | Opt_StaticArgumentTransformation
    
    644
    +   | Opt_OptCoercion
    
    644 645
        | Opt_CSE
    
    645 646
        | Opt_StgCSE
    
    646 647
        | Opt_StgLiftLams
    
    ... ... @@ -887,7 +888,6 @@ data GeneralFlag
    887 888
        | Opt_PluginTrustworthy
    
    888 889
     
    
    889 890
        | Opt_G_NoStateHack
    
    890
    -   | Opt_G_NoOptCoercion
    
    891 891
        deriving (Eq, Show, Enum)
    
    892 892
     
    
    893 893
     -- | The set of flags which affect optimisation for the purposes of
    
    ... ... @@ -910,6 +910,7 @@ optimisationFlags = EnumSet.fromList
    910 910
        , Opt_CrossModuleSpecialise
    
    911 911
        , Opt_StaticArgumentTransformation
    
    912 912
        , Opt_PolymorphicSpecialisation
    
    913
    +   , Opt_OptCoercion
    
    913 914
        , Opt_CSE
    
    914 915
        , Opt_StgCSE
    
    915 916
        , Opt_StgLiftLams
    

  • compiler/GHC/Driver/Session.hs
    ... ... @@ -1328,8 +1328,6 @@ dynamic_flags_deps = [
    1328 1328
             (NoArg (setGeneralFlag Opt_NoHsMain))
    
    1329 1329
       , make_ord_flag defGhcFlag "fno-state-hack"
    
    1330 1330
             (NoArg (setGeneralFlag Opt_G_NoStateHack))
    
    1331
    -  , make_ord_flag defGhcFlag "fno-opt-coercion"
    
    1332
    -        (NoArg (setGeneralFlag Opt_G_NoOptCoercion))
    
    1333 1331
       , make_ord_flag defGhcFlag "with-rtsopts"
    
    1334 1332
             (HasArg setRtsOpts)
    
    1335 1333
       , make_ord_flag defGhcFlag "rtsopts"
    
    ... ... @@ -2477,6 +2475,7 @@ fFlagsDeps = [
    2477 2475
       flagSpec "cmm-elim-common-blocks"           Opt_CmmElimCommonBlocks,
    
    2478 2476
       flagSpec "cmm-sink"                         Opt_CmmSink,
    
    2479 2477
       flagSpec "cmm-static-pred"                  Opt_CmmStaticPred,
    
    2478
    +  flagSpec "opt-coercion"                     Opt_OptCoercion,
    
    2480 2479
       flagSpec "cse"                              Opt_CSE,
    
    2481 2480
       flagSpec "stg-cse"                          Opt_StgCSE,
    
    2482 2481
       flagSpec "stg-lift-lams"                    Opt_StgLiftLams,