Andreas Klebinger pushed to branch wip/andreask/ghc_par at Glasgow Haskell Compiler / GHC

Commits:

12 changed files:

Changes:

  • compiler/GHC/Core/Opt/CSE.hs
    ... ... @@ -380,18 +380,18 @@ body/rest of the module.
    380 380
     -}
    
    381 381
     
    
    382 382
     cseProgram :: CoreProgram -> CoreProgram
    
    383
    -cseProgram comp_units
    
    384
    -  = snd (mapAccumL cse_comp_unit init_env comp_units)
    
    383
    +cseProgram = map cseCoreCompUnit
    
    384
    +
    
    385
    +cseCoreCompUnit :: CoreCompUnit -> CoreCompUnit
    
    386
    +cseCoreCompUnit (CoreCompUnit unit_binds unit_rules)
    
    387
    +  = CoreCompUnit binds' unit_rules
    
    385 388
       where
    
    386
    -    init_env  = emptyCSEnv $
    
    387
    -                mkInScopeSetList (bindersOfBinds (concatMap coreCompUnitBinds comp_units))
    
    388
    -                -- Put all top-level binders into scope; it is possible to have
    
    389
    -                -- forward references.  See Note [Glomming] in GHC.Core.Opt.OccurAnal
    
    390
    -                -- Missing this caused #25468
    
    391
    -
    
    392
    -    cse_comp_unit env (CoreCompUnit binds unit_rules)
    
    393
    -      = let (env', binds') = mapAccumL (cseBind TopLevel) env binds
    
    394
    -        in (env', CoreCompUnit binds' unit_rules)
    
    389
    +    init_env = emptyCSEnv $
    
    390
    +               mkInScopeSetList (bindersOfBinds unit_binds)
    
    391
    +               -- Put all top-level binders in this compilation unit into
    
    392
    +               -- scope; it is possible to have forward references.
    
    393
    +               -- See Note [Glomming] in GHC.Core.Opt.OccurAnal.
    
    394
    +    (_env', binds') = mapAccumL (cseBind TopLevel) init_env unit_binds
    
    395 395
     
    
    396 396
     cseBind :: TopLevelFlag -> CSEnv -> CoreBind -> (CSEnv, CoreBind)
    
    397 397
     cseBind toplevel env (NonRec b e)
    

  • compiler/GHC/Core/Opt/Monad.hs
    ... ... @@ -16,7 +16,7 @@ module GHC.Core.Opt.Monad (
    16 16
     
    
    17 17
         -- ** Reading from the monad
    
    18 18
         getModule,
    
    19
    -    initRuleEnv, getExternalRuleBase,
    
    19
    +    initRuleEnv, getHomeRuleBase, getExternalRuleBase,
    
    20 20
         getDynFlags, getPackageFamInstEnv,
    
    21 21
         getInteractiveContext,
    
    22 22
         getUniqTag,
    

  • compiler/GHC/Core/Opt/OccurAnal.hs
    ... ... @@ -28,7 +28,6 @@ core expression with (hopefully) improved usage information.
    28 28
     module GHC.Core.Opt.OccurAnal (
    
    29 29
         occurAnalysePgm,
    
    30 30
         occurAnalyseCompUnit,
    
    31
    -    occurSplitPgm,
    
    32 31
         occurAnalyseExpr, occurAnalyseExpr_Prep,
    
    33 32
         zapLambdaBndrs
    
    34 33
       ) where
    
    ... ... @@ -57,7 +56,6 @@ import GHC.Types.Id.Info
    57 56
     import GHC.Types.InlinePragma ( ActivationGhc, isAlwaysActive )
    
    58 57
     import GHC.Types.Basic
    
    59 58
     import GHC.Types.Tickish
    
    60
    -import GHC.Types.Name (isExternalName, nameModule)
    
    61 59
     import GHC.Types.Var.Set
    
    62 60
     import GHC.Types.Var.Env
    
    63 61
     import GHC.Types.Var
    
    ... ... @@ -70,14 +68,12 @@ import GHC.Utils.Misc
    70 68
     import GHC.Builtin.Names( runRWKey )
    
    71 69
     import GHC.Unit.Module( Module )
    
    72 70
     
    
    73
    -import qualified Data.IntMap.Strict as IntMap
    
    74
    -import qualified Data.IntSet as IntSet
    
    75 71
     import Data.List (mapAccumL)
    
    76 72
     
    
    77 73
     {-
    
    78 74
     ************************************************************************
    
    79 75
     *                                                                      *
    
    80
    -    occurAnalysePgm, occurAnalyseExpr, occurSplitPgm
    
    76
    +    occurAnalysePgm, occurAnalyseExpr
    
    81 77
     *                                                                      *
    
    82 78
     ************************************************************************
    
    83 79
     
    
    ... ... @@ -99,140 +95,6 @@ occurAnalyseExpr_Prep expr = expr'
    99 95
       where
    
    100 96
         WUD _ expr' = occAnal (initOccEnv { occ_allow_weak_joins = True }) expr
    
    101 97
     
    
    102
    --- After optimizations a rule might no longer reference binders from this module.
    
    103
    --- In these cases we return them here and then add them to mg_rules.
    
    104
    -occurSplitPgm :: Module -> [CoreRule] -> CoreCompUnit -> ([CoreCompUnit], [CoreRule])
    
    105
    -occurSplitPgm mod imp_rules (CoreCompUnit unit_binds unit_rules)
    
    106
    -  =
    
    107
    -    -- pprTrace "occurSplitPgm"
    
    108
    -    -- ( vcat [
    
    109
    -    --     text "imp",
    
    110
    -    --     ppr imp_rules,
    
    111
    -    --     text "unit",
    
    112
    -    --     ppr (unit_rules, unit_binds)
    
    113
    -    --   ]
    
    114
    -    -- )
    
    115
    -    (zipWith mk_comp_unit comp_pairs [0..], rules_for_imps)
    
    116
    -  where
    
    117
    -    CoreCompUnit occ_binds _ =
    
    118
    -      occurAnalyseCompUnit mod (const True) (const True) imp_rules
    
    119
    -        (CoreCompUnit unit_binds unit_rules)
    
    120
    -
    
    121
    -    pairs = flattenBinds occ_binds
    
    122
    -    bndrs    = map fst pairs
    
    123
    -    bndr_set = mkVarSet bndrs
    
    124
    -
    
    125
    -    imp_rule_edges :: ImpRuleEdges
    
    126
    -    imp_rule_edges = mkImpRuleEdges imp_rules
    
    127
    -
    
    128
    -    -- If a unit rule mentions multiple local binders, they must end up in
    
    129
    -    -- the same component; otherwise the rule cannot be attached to any one
    
    130
    -    -- split unit without creating cross-unit references.
    
    131
    -    rule_fv_edges :: IdEnv VarSet
    
    132
    -    rule_fv_edges
    
    133
    -      = foldr (plusVarEnv_C unionVarSet) emptyVarEnv
    
    134
    -          [ mapVarEnv (const local_rule_fvs) (getUniqSet local_rule_fvs)
    
    135
    -          | rule <- unit_rules
    
    136
    -          , let local_rule_fvs = ruleFreeVars rule `intersectVarSet` bndr_set
    
    137
    -          ]
    
    138
    -
    
    139
    -    dir_nodes :: [Node Unique (Id, CoreExpr)]
    
    140
    -    dir_nodes = map mk_dir_node pairs
    
    141
    -
    
    142
    -    mk_dir_node (bndr, rhs)
    
    143
    -      = DigraphNode { node_payload = (bndr, rhs)
    
    144
    -                    , node_key = varUnique bndr
    
    145
    -                    , node_dependencies = nonDetKeysUniqSet deps
    
    146
    -                    }
    
    147
    -      where
    
    148
    -        deps = traced_fvs `intersectVarSet` bndr_set
    
    149
    -
    
    150
    -        traced_fvs = -- pprTrace "occurSplitPgm: binder fvs before unit assignment"
    
    151
    -                     -- (ppr bndr $$ text "fvs:" <+> ppr dep_fvs)
    
    152
    -                      dep_fvs
    
    153
    -
    
    154
    -        dep_fvs = exprFreeIds rhs
    
    155
    -                  `unionVarSet` bndrRuleAndUnfoldingIds bndr
    
    156
    -                  `unionVarSet` localRuleDeps bndr
    
    157
    -                  `unionVarSet` impRuleDeps bndr
    
    158
    -
    
    159
    -        impRuleDeps b = foldr unionVarSet emptyVarSet [ vs | (_, vs) <- lookupImpRules imp_rule_edges b ]
    
    160
    -
    
    161
    -        localRuleDeps b = lookupVarEnv rule_fv_edges b `orElse` emptyVarSet
    
    162
    -
    
    163
    -    incoming_edges :: UniqFM Unique [Unique]
    
    164
    -    incoming_edges = foldr add_incoming emptyUFM dir_nodes
    
    165
    -      where
    
    166
    -        add_incoming DigraphNode { node_key = src, node_dependencies = dests } incoming
    
    167
    -          = foldr (\dest acc -> addToUFM_C (++) acc dest [src]) incoming dests
    
    168
    -    -- TODO: AI Garbage? -
    
    169
    -    -- We probably really should just do this on a undirected graph instead.
    
    170
    -    undir_nodes :: [Node Unique (Id, CoreExpr)]
    
    171
    -    undir_nodes =
    
    172
    -      [ node { node_dependencies = node_dependencies node ++ lookupWithDefaultUFM incoming_edges [] (node_key node) }
    
    173
    -      | node <- dir_nodes
    
    174
    -      ]
    
    175
    -
    
    176
    -    comp_pairs :: [[(Id, CoreExpr)]]
    
    177
    -    comp_pairs = map scc_payloads (stronglyConnCompFromEdgedVerticesUniq undir_nodes)
    
    178
    -
    
    179
    -    component_bndrs :: [[Id]]
    
    180
    -    component_bndrs = map (map fst) comp_pairs
    
    181
    -
    
    182
    -    mk_comp_unit prs i = CoreCompUnit (mk_comp_binds prs) (component_rules i)
    
    183
    -
    
    184
    -    mk_comp_binds [pr] = [NonRec (fst pr) (snd pr)]
    
    185
    -    mk_comp_binds prs  = [Rec prs]
    
    186
    -
    
    187
    -    (component_rule_map, rules_for_imps) = foldr assign_rule (IntMap.empty, []) unit_rules
    
    188
    -
    
    189
    -    assign_rule rule (rule_map, imp_rules_acc)
    
    190
    -      = case rule_comp_index rule of
    
    191
    -          Just i  -> (IntMap.insertWith (++) i [rule] rule_map, imp_rules_acc)
    
    192
    -          Nothing -> (rule_map, rule : imp_rules_acc)
    
    193
    -
    
    194
    -    component_rules i = IntMap.findWithDefault [] i component_rule_map
    
    195
    -
    
    196
    -    rule_comp_index rule
    
    197
    -      = case rule_component_indices of
    
    198
    -          [i] -> Just i
    
    199
    -          []  -> Nothing
    
    200
    -          is  -> pprPanic "occurSplitPgm"
    
    201
    -                 (text "Rule free vars span multiple components"
    
    202
    -                  $$ text "rule:" <+> ppr rule
    
    203
    -                  $$ text "components:" <+> ppr is
    
    204
    -                  $$ text "rule_fvs:" <+> pprVarsWithModule (nonDetEltsUniqSet rule_fvs)
    
    205
    -                  $$ vcat [ text "component" <+> int i <> colon <+> ppr hits
    
    206
    -                          | (i, hits) <- component_hits ])
    
    207
    -      where
    
    208
    -        rule_component_indices :: [Int]
    
    209
    -        rule_component_indices = IntSet.toList $ IntSet.fromList
    
    210
    -          [ i
    
    211
    -          | (ids, i) <- zip component_bndrs [0..]
    
    212
    -          , not (isEmptyVarSet (local_rule_fvs `intersectVarSet` mkVarSet ids))
    
    213
    -          ]
    
    214
    -
    
    215
    -        rule_fvs = ruleFreeVars rule
    
    216
    -        local_rule_fvs = rule_fvs `intersectVarSet` bndr_set
    
    217
    -        component_hits =
    
    218
    -          [ (i, local_rule_fvs `intersectVarSet` mkVarSet ids)
    
    219
    -          | (ids, i) <- zip component_bndrs [0..]
    
    220
    -          , not (isEmptyVarSet (local_rule_fvs `intersectVarSet` mkVarSet ids))
    
    221
    -          ]
    
    222
    -
    
    223
    -    scc_payloads (AcyclicSCC p) = [p]
    
    224
    -    scc_payloads (CyclicSCC ps) = ps
    
    225
    -
    
    226
    -    pprVarsWithModule :: [Var] -> SDoc
    
    227
    -    pprVarsWithModule vars = braces (fsep (punctuate comma (map pprVarWithModule vars)))
    
    228
    -
    
    229
    -    pprVarWithModule :: Var -> SDoc
    
    230
    -    pprVarWithModule v
    
    231
    -      | isExternalName n = ppr v <+> parens (ppr (nameModule n))
    
    232
    -      | otherwise        = ppr v
    
    233
    -      where
    
    234
    -        n = varName v
    
    235
    -
    
    236 98
     occurAnalyseCompUnit
    
    237 99
       :: Module
    
    238 100
       -> (Id -> Bool)
    

  • compiler/GHC/Core/Opt/Pipeline.hs
    ... ... @@ -14,7 +14,7 @@ import GHC.Driver.DynFlags
    14 14
     import GHC.Driver.Plugins ( withPlugins, installCoreToDos )
    
    15 15
     import GHC.Driver.Env
    
    16 16
     import GHC.Driver.Config (initSimpleOpts)
    
    17
    -import GHC.Driver.Config.Core.Lint ( endPass )
    
    17
    +import GHC.Driver.Config.Core.Lint ( endPass, initLintConfig )
    
    18 18
     import GHC.Driver.Config.Core.Opt.LiberateCase ( initLiberateCaseOpts )
    
    19 19
     import GHC.Driver.Config.Core.Opt.Simplify ( initSimplifyOpts, initSimplMode, initGentleSimplMode )
    
    20 20
     import GHC.Driver.Config.Core.Opt.WorkWrap ( initWorkWrapOpts )
    
    ... ... @@ -22,12 +22,12 @@ import GHC.Driver.Config.Core.Rules ( initRuleOpts )
    22 22
     import GHC.Platform.Ways  ( hasWay, Way(WayProf) )
    
    23 23
     
    
    24 24
     import GHC.Core
    
    25
    -import GHC.Core.SimpleOpt (simpleOptPgm)
    
    25
    +import GHC.Core.SimpleOpt (simpleOptPgm, defaultSimpleOpts, so_inline, so_uf_opts)
    
    26 26
     import GHC.Core.Opt.CSE  ( cseProgram )
    
    27 27
     import GHC.Core.Rules   ( RuleBase, ruleCheckProgram, getRules )
    
    28 28
     import GHC.Core.Ppr     ( pprCoreProgram, pprRules )
    
    29 29
     import GHC.Core.Utils   ( dumpIdInfoOfProgram )
    
    30
    -import GHC.Core.Lint    ( lintAnnots )
    
    30
    +import GHC.Core.Lint    ( lintAnnots, lintCoreProgram', displayLintResults )
    
    31 31
     import GHC.Core.Lint.Interactive ( interactiveInScope )
    
    32 32
     import GHC.Core.Opt.Simplify ( simplifyExpr, simplifyPgm )
    
    33 33
     import GHC.Core.Opt.Simplify.Monad
    
    ... ... @@ -43,7 +43,7 @@ import GHC.Core.Opt.DmdAnal
    43 43
     import GHC.Core.Opt.CprAnal      ( cprAnalProgram )
    
    44 44
     import GHC.Core.Opt.CallArity    ( callArityAnalProgram )
    
    45 45
     import GHC.Core.Opt.Exitify      ( exitifyProgram )
    
    46
    -import GHC.Core.Opt.OccurAnal    ( occurSplitPgm )
    
    46
    +import GHC.Core.Opt.Split        ( splitCompUnit, checkNameClashes )
    
    47 47
     import GHC.Core.Opt.WorkWrap     ( wwTopBinds )
    
    48 48
     import GHC.Core.Opt.CallerCC     ( addCallerCostCentres )
    
    49 49
     import GHC.Core.LateCC.TopLevelBinds (topLevelBindsCCMG)
    
    ... ... @@ -320,7 +320,11 @@ getCoreToDo dflags hpt_rule_base extra_vars
    320 320
             -- in wheel-sieve1), and I'm guessing that SpecConstr can too
    
    321 321
             -- And CSE is a very cheap pass. So it seems worth doing here.
    
    322 322
             runWhen ((liberate_case || spec_constr) && cse) $ CoreDoPasses
    
    323
    -           [ CoreCSE, simplify "post-final-cse" ],
    
    323
    +           [ runWhen split_core CoreMerge
    
    324
    +           , CoreCSE
    
    325
    +           , runWhen split_core CoreSplit
    
    326
    +           , simplify "post-final-cse"
    
    327
    +           ],
    
    324 328
     
    
    325 329
             ---------  End of -O2 passes --------------
    
    326 330
     
    
    ... ... @@ -457,6 +461,7 @@ doCorePass pass guts = do
    457 461
       dflags    <- getDynFlags
    
    458 462
       us        <- getUniqueSupplyM
    
    459 463
       p_fam_env <- getPackageFamInstEnv
    
    464
    +  let extra_vars = interactiveInScope (hsc_IC hsc_env)
    
    460 465
       let platform = targetPlatform dflags
    
    461 466
       let fam_envs = (p_fam_env, mg_fam_inst_env guts)
    
    462 467
       let updateBinds  f = return $ guts { mg_binds = f (mg_binds guts) }
    
    ... ... @@ -478,14 +483,16 @@ doCorePass pass guts = do
    478 483
                                      updateBindsAndRulesM (desugarOpt dflags logger (mg_module guts))
    
    479 484
     
    
    480 485
         CoreSplit                 -> {-# SCC "CoreSplit" #-}
    
    481
    -                                 do { let split_res = map (occurSplitPgm (mg_module guts) (mg_rules guts)) (mg_binds guts)
    
    486
    +                                 do { let split_res = map (splitCompUnit (mg_module guts) (mg_rules guts)) (mg_binds guts)
    
    482 487
                                               binds' = concatMap fst split_res
    
    483 488
                                               rules' = mg_rules guts ++ concatMap snd split_res
    
    484 489
                                         ; return guts { mg_binds = binds', mg_rules = rules' } }
    
    485 490
     
    
    486 491
         CoreMerge                 -> {-# SCC "CoreMerge" #-}
    
    487 492
                                      do { let binds_before = mg_binds guts
    
    493
    +                                          _ = checkNameClashes binds_before
    
    488 494
                                               binds_after  = flattenCoreProgram binds_before
    
    495
    +                                          _ = checkNameClashes binds_after
    
    489 496
                                         ; liftIO $
    
    490 497
                                             Logger.putDumpFileMaybe logger Opt_D_dump_split_core
    
    491 498
                                               "Core before merge"
    
    ... ... @@ -497,7 +504,33 @@ doCorePass pass guts = do
    497 504
                                               "Core after merge"
    
    498 505
                                               FormatCore
    
    499 506
                                               (pprCoreProgram binds_after)
    
    500
    -                                    ; return $ guts { mg_binds = binds_after } }
    
    507
    +                                    ; liftIO $ do
    
    508
    +                                        let warns_and_errs = lintCoreProgram'
    
    509
    +                                              (initLintConfig dflags extra_vars)
    
    510
    +                                              binds_after
    
    511
    +                                              (mg_rules guts)
    
    512
    +                                              True
    
    513
    +                                        displayLintResults logger
    
    514
    +                                          (text "CoreMerge after flattenCoreProgram")
    
    515
    +                                          (pprCoreProgram binds_after)
    
    516
    +                                          warns_and_errs
    
    517
    +                                    ; let minimal_things = defaultSimpleOpts
    
    518
    +                                              { so_inline = False
    
    519
    +                                              , so_uf_opts = unfoldingOpts dflags }
    
    520
    +                                          (binds_w_unfolds, rules_for_imps, occ_anald_binds) = simpleOptPgm
    
    521
    +                                              minimal_things
    
    522
    +                                              (mg_module guts)
    
    523
    +                                              binds_after
    
    524
    +                                              (mg_rules guts)
    
    525
    +                                          _ = checkNameClashes binds_w_unfolds
    
    526
    +                                    ; liftIO $
    
    527
    +                                        Logger.putDumpFileMaybe logger Opt_D_dump_split_core
    
    528
    +                                          "Core after re-attaching unfolds"
    
    529
    +                                          FormatCore
    
    530
    +                                          (pprCoreProgram occ_anald_binds)
    
    531
    +
    
    532
    +                                    ; return $ guts { mg_binds = binds_w_unfolds
    
    533
    +                                                    , mg_rules = rules_for_imps } }
    
    501 534
     
    
    502 535
         CoreDoSimplify opts       -> {-# SCC "Simplify" #-}
    
    503 536
                                      liftIOWithCount $ simplifyPgm logger (hsc_unit_env hsc_env) name_ppr_ctx opts guts
    

  • compiler/GHC/Core/Opt/Simplify.hs
    ... ... @@ -10,6 +10,7 @@ import GHC.Prelude
    10 10
     import GHC.Driver.Flags
    
    11 11
     
    
    12 12
     import GHC.Core
    
    13
    +import GHC.Core.FVs (ruleFreeVars)
    
    13 14
     import GHC.Core.Rules
    
    14 15
     import GHC.Core.Ppr     ( pprCoreBindings, pprCoreExpr )
    
    15 16
     import GHC.Core.Opt.OccurAnal ( occurAnalysePgm, occurAnalyseExpr )
    
    ... ... @@ -38,10 +39,10 @@ import GHC.Unit.Module.ModGuts
    38 39
     import GHC.Types.Id
    
    39 40
     import GHC.Types.Id.Info
    
    40 41
     import GHC.Types.InlinePragma
    
    41
    -import GHC.Types.Var.Set
    
    42 42
     import GHC.Types.Var.Env
    
    43 43
     import GHC.Types.Tickish
    
    44 44
     import GHC.Types.Unique.FM
    
    45
    +import GHC.Types.Var.Set
    
    45 46
     
    
    46 47
     import Control.Monad
    
    47 48
     import Data.Foldable ( for_ )
    
    ... ... @@ -240,7 +241,7 @@ simplifyPgm' logger unit_env name_ppr_ctx opts
    240 241
                     -- number of iterations we actually completed
    
    241 242
             return ( "Simplifier bailed out", iteration_no - 1
    
    242 243
                    , totalise counts_so_far
    
    243
    -               , dyn_no_binds { dsd_binds = [CoreCompUnit bind_list unit_rules], dsd_rules = local_rules } )
    
    244
    +               , dyn_no_binds { dsd_binds = binds, dsd_rules = local_rules } )
    
    244 245
     
    
    245 246
           -- Try and force thunks off the binds; significantly reduces
    
    246 247
           -- space usage, especially with -O.  JRS, 000620.
    
    ... ... @@ -271,38 +272,19 @@ simplifyPgm' logger unit_env name_ppr_ctx opts
    271 272
                       --    (b) local rules (substituted), including unit rules from `binds`
    
    272 273
                       -- Forcing base_rule_env to avoid unnecessary allocations.
    
    273 274
                       -- Not doing so results in +25.6% allocations of LargeRecord.
    
    274
    -                ; !base_rule_env = updLocalRules hpt_rule_env (local_rules ++ unit_rules)
    
    275
    -
    
    276
    -                ; read_eps_rules :: IO PackageRuleBase
    
    277
    -                ; read_eps_rules = eps_rule_base <$> ueEPS unit_env
    
    278
    -
    
    279
    -                ; read_rule_env :: IO RuleEnv
    
    280
    -                ; read_rule_env = updExternalPackageRules base_rule_env <$> read_eps_rules
    
    281
    -
    
    282 275
                     ; fam_envs = (eps_fam_inst_env eps, fam_inst_env)
    
    283 276
                     ; simpl_env = mkSimplEnv mode fam_envs } ;
    
    284 277
     
    
    285
    -                -- Simplify the program
    
    286
    -           ((binds1, rules1, unit_rules1), counts1) <-
    
    287
    -             initSmpl logger read_rule_env top_env_cfg sz $
    
    288
    -               do { (floats, env1) <- {-# SCC "SimplTopBinds" #-}
    
    289
    -                                      simplTopBinds simpl_env tagged_bind_list
    
    290
    -
    
    291
    -                      -- Apply the substitution to rules defined in this module
    
    292
    -                      -- for imported Ids.  Eg  RULE map my_f = blah
    
    293
    -                      -- If we have a substitution my_f :-> other_f, we'd better
    
    294
    -                      -- apply it to the rule to, or it'll never match
    
    295
    -                  ; rules1 <- simplImpRules env1 local_rules
    
    296
    -                  ; unit_rules1 <- simplImpRules env1 unit_rules
    
    297
    -
    
    298
    -                  ; return (getTopFloatBinds floats, rules1, unit_rules1) } ;
    
    278
    +                -- Simplify each compilation unit independently
    
    279
    +           ((binds1, rules1), counts1) <-
    
    280
    +             simpl_comp_units simpl_env local_rules tagged_binds sz ;
    
    299 281
     
    
    300 282
                     -- Stop if nothing happened; don't dump output
    
    301 283
                     -- See Note [Which transformations are innocuous] in GHC.Core.Opt.Stats
    
    302 284
                if isZeroSimplCount counts1 then
    
    303 285
                     return ( "Simplifier reached fixed point", iteration_no
    
    304 286
                            , totalise (counts1 : counts_so_far)  -- Include "free" ticks
    
    305
    -                       , dyn_no_binds { dsd_binds = [CoreCompUnit binds1 unit_rules1], dsd_rules = rules1 } )
    
    287
    +                       , dyn_no_binds { dsd_binds = binds1, dsd_rules = rules1 } )
    
    306 288
                else do {
    
    307 289
                     -- Short out indirections
    
    308 290
                     -- We do this *after* at least one run of the simplifier
    
    ... ... @@ -312,26 +294,77 @@ simplifyPgm' logger unit_env name_ppr_ctx opts
    312 294
                     --
    
    313 295
                     -- ToDo: alas, this means that indirection-shorting does not happen at all
    
    314 296
                     --       if the simplifier does nothing (not common, I know, but unsavoury)
    
    315
    -           let { binds2 = {-# SCC "ZapInd" #-} shortOutIndirections binds1 } ;
    
    297
    +           let { binds2 = {-# SCC "ZapInd" #-}
    
    298
    +                          [ CoreCompUnit (shortOutIndirections unit_binds) unit_rules'
    
    299
    +                          | CoreCompUnit unit_binds unit_rules' <- binds1 ] } ;
    
    316 300
     
    
    317 301
                     -- Dump the result of this iteration
    
    318 302
                dump_end_iteration logger dump_core_sizes name_ppr_ctx iteration_no counts1
    
    319
    -             [CoreCompUnit binds2 unit_rules1] rules1 ;
    
    303
    +             binds2 rules1 ;
    
    320 304
     
    
    321 305
                for_ (so_pass_result_cfg opts) $ \pass_result_cfg ->
    
    322
    -             lintPassResult logger pass_result_cfg [CoreCompUnit binds2 unit_rules1] rules1 ;
    
    306
    +             lintPassResult logger pass_result_cfg binds2 rules1 ;
    
    323 307
     
    
    324 308
                     -- Loop
    
    325
    -           do_iteration (iteration_no + 1) (counts1:counts_so_far) [CoreCompUnit binds2 unit_rules1] rules1
    
    309
    +           do_iteration (iteration_no + 1) (counts1:counts_so_far) binds2 rules1
    
    326 310
                } }
    
    327 311
           where
    
    328 312
             bind_list = concatMap coreCompUnitBinds binds
    
    329
    -        unit_rules = concatMap cu_rules binds
    
    330 313
             -- Remember the counts_so_far are reversed
    
    331 314
             totalise :: [SimplCount] -> SimplCount
    
    332 315
             totalise = foldr (\c acc -> acc `plusSimplCount` c)
    
    333 316
                              (zeroSimplCount $ logHasDumpFlag logger Opt_D_dump_simpl_stats)
    
    334 317
     
    
    318
    +    -- Keep top-level in-scope sets per-unit until CoreMerge.
    
    319
    +    simpl_comp_units
    
    320
    +      :: SimplEnv
    
    321
    +      -> [CoreRule]
    
    322
    +      -> CoreProgram
    
    323
    +      -> Int
    
    324
    +      -> IO ((CoreProgram, [CoreRule]), SimplCount)
    
    325
    +    simpl_comp_units simpl_env rules0 units0 sz = go rules0 [] zero_counts units0
    
    326
    +      where
    
    327
    +        zero_counts = zeroSimplCount $ logHasDumpFlag logger Opt_D_dump_simpl_stats
    
    328
    +
    
    329
    +        go !rules acc !counts [] = return ((reverse acc, rules), counts)
    
    330
    +        go !rules acc !counts (CoreCompUnit unit_binds unit_rules' : rest) = do
    
    331
    +          let unit_bndrs = mkVarSet (bindersOfBinds unit_binds)
    
    332
    +              (visible_rules, hidden_rules) = partitionVisibleImpRules unit_bndrs rules
    
    333
    +              !base_rule_env = updLocalRules hpt_rule_env (visible_rules ++ unit_rules')
    
    334
    +              read_eps_rules = eps_rule_base <$> ueEPS unit_env
    
    335
    +              read_rule_env = updExternalPackageRules base_rule_env <$> read_eps_rules
    
    336
    +
    
    337
    +          ((unit1, visible_rules1), counts1) <-
    
    338
    +            initSmpl logger read_rule_env top_env_cfg sz $ do
    
    339
    +              (floats, env1) <- {-# SCC "SimplTopBindsUnit" #-}
    
    340
    +                                simplTopBinds simpl_env unit_binds
    
    341
    +
    
    342
    +              -- Apply substitutions from this unit to imported-head rules and
    
    343
    +              -- the unit's own rules. Keep each unit's local rules separate.
    
    344
    +              visible_rules1 <- simplImpRules env1 visible_rules
    
    345
    +              unit_rules1 <- simplImpRules env1 unit_rules'
    
    346
    +
    
    347
    +              let unit_binds1 = getTopFloatBinds floats
    
    348
    +              pure (CoreCompUnit unit_binds1 unit_rules1, visible_rules1)
    
    349
    +
    
    350
    +          let rules1 = visible_rules1 ++ hidden_rules
    
    351
    +          go rules1 (unit1 : acc) (counts `plusSimplCount` counts1) rest
    
    352
    +
    
    353
    +    partitionVisibleImpRules :: VarSet -> [CoreRule] -> ([CoreRule], [CoreRule])
    
    354
    +    partitionVisibleImpRules unit_bndrs = foldr go_rule ([], [])
    
    355
    +      where
    
    356
    +        go_rule rule (visible, hidden)
    
    357
    +          | rule_mentions_unit = (rule : visible, hidden)
    
    358
    +          | rule_has_local_fvs = (visible, rule : hidden)
    
    359
    +          | otherwise          = (rule : visible, hidden)
    
    360
    +          where
    
    361
    +            local_fvs = ruleFreeVars rule `intersectVarSet` all_local_bndrs
    
    362
    +            rule_has_local_fvs = not (isEmptyVarSet local_fvs)
    
    363
    +            rule_mentions_unit = not (isEmptyVarSet (local_fvs `intersectVarSet` unit_bndrs))
    
    364
    +
    
    365
    +    all_local_bndrs :: VarSet
    
    366
    +    all_local_bndrs = mkVarSet (bindersOfBinds (concatMap coreCompUnitBinds (dsd_binds dyn)))
    
    367
    +
    
    335 368
     dump_end_iteration :: Logger -> Bool -> NamePprCtx -> Int
    
    336 369
                        -> SimplCount -> CoreProgram -> [CoreRule] -> IO ()
    
    337 370
     dump_end_iteration logger dump_core_sizes name_ppr_ctx iteration_no counts binds rules
    

  • compiler/GHC/Core/Opt/SpecConstr.hs
    ... ... @@ -794,9 +794,12 @@ specConstrProgram guts
    794 794
     scTopCompUnits :: ScEnv -> CoreProgram -> UniqSM (ScUsage, CoreProgram, [SpecFailWarning])
    
    795 795
     scTopCompUnits _env [] = return (nullUsage, [], [])
    
    796 796
     scTopCompUnits env (CoreCompUnit unit_binds unit_rules:units) = do
    
    797
    -  (unit_usg, unit_binds', unit_warnings) <- scTopBinds env unit_binds
    
    798
    -  (units_usg, units', units_warnings) <- scTopCompUnits env units
    
    799
    -  return (unit_usg `combineUsage` units_usg, CoreCompUnit unit_binds' unit_rules : units', unit_warnings ++ units_warnings)
    
    797
    +  let unit_env = initScCompUnitEnv env unit_binds
    
    798
    +  (_unit_usg, unit_binds', unit_warnings) <- scTopBinds unit_env unit_binds
    
    799
    +  (_units_usg, units', units_warnings) <- scTopCompUnits env units
    
    800
    +  -- Before CoreMerge, different compilation units may legitimately reuse the
    
    801
    +  -- same top-level Id/Unique, so we must not combine ScUsage across units.
    
    802
    +  return (nullUsage, CoreCompUnit unit_binds' unit_rules : units', unit_warnings ++ units_warnings)
    
    800 803
     
    
    801 804
     scTopBinds :: ScEnv -> [InBind] -> UniqSM (ScUsage, [OutBind], [SpecFailWarning])
    
    802 805
     scTopBinds _env []     = return (nullUsage, [], [])
    
    ... ... @@ -1009,18 +1012,19 @@ initScEnv guts
    1009 1012
            ; this_mod  <- getModule
    
    1010 1013
            ; return (SCE { sc_opts        = initScOpts dflags this_mod,
    
    1011 1014
                            sc_force       = False,
    
    1012
    -                       sc_subst       = init_subst,
    
    1015
    +                       sc_subst       = mkEmptySubst emptyInScopeSet,
    
    1013 1016
                            sc_how_bound   = emptyVarEnv,
    
    1014 1017
                            sc_vals        = emptyVarEnv,
    
    1015 1018
                            sc_annotations = anns }) }
    
    1019
    +
    
    1020
    +initScCompUnitEnv :: ScEnv -> [InBind] -> ScEnv
    
    1021
    +initScCompUnitEnv env unit_binds
    
    1022
    +  = env { sc_subst = mkEmptySubst in_scope }
    
    1016 1023
       where
    
    1017
    -    init_subst = mkEmptySubst $ foldl' addCompUnitBndrs emptyInScopeSet (mg_binds guts)
    
    1018
    -        -- Acccount for top-level bindings that are not in dependency order;
    
    1019
    -        -- see Note [Glomming] in GHC.Core.Opt.OccurAnal
    
    1020
    -        -- Easiest thing is to bring all the top level binders into scope at once,
    
    1021
    -        -- as if  at once, as if all the top-level decls were mutually recursive.
    
    1022
    -    addCompUnitBndrs scope (CoreCompUnit unit_binds _) =
    
    1023
    -      scope `extendInScopeSetBndrs` unit_binds
    
    1024
    +    in_scope = emptyInScopeSet `extendInScopeSetBndrs` unit_binds
    
    1025
    +      -- Account for top-level bindings that are not in dependency order;
    
    1026
    +      -- see Note [Glomming] in GHC.Core.Opt.OccurAnal.
    
    1027
    +      -- Crucially, only add binders from the current compilation unit.
    
    1024 1028
     
    
    1025 1029
     data HowBound = RecFun  -- These are the recursive functions for which
    
    1026 1030
                             -- we seek interesting call patterns
    
    ... ... @@ -1443,7 +1447,8 @@ scBind top_lvl env (NonRec bndr rhs) do_body
    1443 1447
         -- but found some regressions (see !8135).  So I backed off.
    
    1444 1448
       = do { (rhs_usage, rhs', ws_rhs)   <- scExpr env rhs
    
    1445 1449
     
    
    1446
    -       -- At top level, we've already put all binders into scope; see initScEnv
    
    1450
    +       -- At top level, we've already put the current compilation unit's
    
    1451
    +       -- binders into scope; see initScCompUnitEnv.
    
    1447 1452
            -- Hence no need to call `extendBndr`. But we still want to
    
    1448 1453
            -- extend the `ValueEnv` to record the value of this binder.
    
    1449 1454
            ; let body_env = extendValEnv env bndr (isValue (sc_vals env) rhs')
    
    ... ... @@ -1491,7 +1496,8 @@ scBind top_lvl env (Rec prs) do_body
    1491 1496
     
    
    1492 1497
         (rhs_env1,bndrs') | isTopLevel top_lvl = (env, bndrs)
    
    1493 1498
                           | otherwise          = extendRecBndrs env bndrs
    
    1494
    -       -- At top level, we've already put all binders into scope; see initScEnv
    
    1499
    +       -- At top level, we've already put the current compilation unit's
    
    1500
    +       -- binders into scope; see initScCompUnitEnv.
    
    1495 1501
     
    
    1496 1502
         rhs_env2 = extendHowBound rhs_env1 bndrs' RecFun
    
    1497 1503
     
    

  • compiler/GHC/Core/Opt/Specialise.hs
    ... ... @@ -65,6 +65,7 @@ import GHC.Utils.Outputable
    65 65
     import GHC.Utils.Panic
    
    66 66
     
    
    67 67
     import GHC.Unit.Module( Module )
    
    68
    +import GHC.Unit.Module.Deps ( Dependencies )
    
    68 69
     import GHC.Unit.Module.ModGuts
    
    69 70
     import GHC.Core.Unfold
    
    70 71
     
    
    ... ... @@ -641,10 +642,9 @@ Hence, the invariant is this:
    641 642
     -- | Specialise calls to type-class overloaded functions occurring in a program.
    
    642 643
     specProgram :: ModGuts -> CoreM ModGuts
    
    643 644
     specProgram guts = do
    
    644
    -  rule_env <- initRuleEnv guts
    
    645 645
       let static = StaticSpecInput
    
    646 646
             { ssi_module = mg_module guts
    
    647
    -        , ssi_rule_env = rule_env
    
    647
    +        , ssi_deps   = mg_deps guts
    
    648 648
             }
    
    649 649
           dyn = DynamicSpecData
    
    650 650
             { dsd_binds = mg_binds guts
    
    ... ... @@ -655,7 +655,7 @@ specProgram guts = do
    655 655
     
    
    656 656
     data StaticSpecInput = StaticSpecInput
    
    657 657
       { ssi_module   :: !Module
    
    658
    -  , ssi_rule_env :: !RuleEnv
    
    658
    +  , ssi_deps     :: !Dependencies
    
    659 659
       }
    
    660 660
     
    
    661 661
     data DynamicSpecData = DynamicSpecData
    
    ... ... @@ -680,20 +680,26 @@ specProgram' static dyn
    680 680
     -- | Specialise calls to type-class overloaded functions occurring in a program.
    
    681 681
     specCompUnit :: StaticSpecInput -> DynFlags -> CoreCompUnit -> CoreM CoreCompUnit
    
    682 682
     specCompUnit static dflags (CoreCompUnit unit_binds unit_rules)
    
    683
    -  = do { (unit_binds', uds) <- runSpecM (go unit_binds)
    
    683
    +  = do { hpt_rules <- getHomeRuleBase
    
    684
    +       ; eps_rules <- getExternalRuleBase
    
    685
    +       ; let rule_env = mkRuleEnv (ssi_module static) (ssi_deps static) [] [unit]
    
    686
    +                                  eps_rules hpt_rules
    
    687
    +             top_env = SE { se_subst = Core.mkEmptySubst in_scope
    
    688
    +                          , se_module = ssi_module static
    
    689
    +                          , se_rules  = rule_env
    
    690
    +                          , se_dflags = dflags }
    
    691
    +       ; (unit_binds', uds) <- runSpecM (go top_env unit_binds)
    
    684 692
            ; (spec_rules, spec_binds) <- specImports top_env uds
    
    685 693
            ; return (CoreCompUnit (spec_binds ++ unit_binds') (spec_rules ++ unit_rules)) }
    
    686 694
       where
    
    687
    -    top_env = SE { se_subst = Core.mkEmptySubst in_scope
    
    688
    -                 , se_module = ssi_module static
    
    689
    -                 , se_rules  = ssi_rule_env static
    
    690
    -                 , se_dflags = dflags }
    
    695
    +    unit = CoreCompUnit unit_binds unit_rules
    
    691 696
         in_scope = mkInScopeSetBndrs unit_binds
    
    692 697
     
    
    693
    -    go []           = return ([], emptyUDs)
    
    694
    -    go (bind:binds) = do (bind', binds', uds') <- specBind TopLevel top_env bind $ \_ ->
    
    695
    -                                                  go binds
    
    696
    -                         return (bind' ++ binds', uds')
    
    698
    +    go _ []           = return ([], emptyUDs)
    
    699
    +    go env (bind:binds)
    
    700
    +      = do (bind', binds', uds') <- specBind TopLevel env bind $ \_ ->
    
    701
    +                                     go env binds
    
    702
    +           return (bind' ++ binds', uds')
    
    697 703
     
    
    698 704
     {-
    
    699 705
     Note [Wrap bindings returned by specImports]
    

  • compiler/GHC/Core/Opt/Split.hs
    1
    +{-# LANGUAGE ViewPatterns #-}
    
    2
    +
    
    3
    +module GHC.Core.Opt.Split
    
    4
    +  ( splitCompUnit
    
    5
    +  , checkNameClashes
    
    6
    +  ) where
    
    7
    +
    
    8
    +import GHC.Prelude hiding ( head, init, last )
    
    9
    +
    
    10
    +import GHC.Core
    
    11
    +import GHC.Core.FVs
    
    12
    +import GHC.Core.Opt.OccurAnal (occurAnalyseCompUnit)
    
    13
    +
    
    14
    +import GHC.Data.Graph.Directed (SCC(..), Node(..), stronglyConnCompFromEdgedVerticesUniq)
    
    15
    +import GHC.Data.Maybe (orElse)
    
    16
    +
    
    17
    +import GHC.Types.Unique.Set
    
    18
    +import GHC.Types.Name (isExternalName, nameModule)
    
    19
    +import GHC.Types.Id (realIdUnfolding)
    
    20
    +import GHC.Types.Var.Set
    
    21
    +import GHC.Types.Var.Env
    
    22
    +import GHC.Types.Var
    
    23
    +
    
    24
    +import GHC.Utils.Outputable
    
    25
    +import GHC.Utils.Panic
    
    26
    +
    
    27
    +import GHC.Unit.Module (Module)
    
    28
    +
    
    29
    +import qualified Data.IntMap.Strict as IntMap
    
    30
    +import qualified Data.IntSet as IntSet
    
    31
    +import Data.List (find)
    
    32
    +
    
    33
    +{- Note [Splitting core programs]
    
    34
    +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    35
    +splitCompUnit splits a single compilation unit into multiple.
    
    36
    +To do so we:
    
    37
    +
    
    38
    +Initially we run OccAnal on the compilation unit. I don't think it's strictly neccessary
    
    39
    +but it zaps fragile unfoldings which speeds up and gets rid of glomming.
    
    40
    +We will try getting rid of this later.
    
    41
    +
    
    42
    +We split imported rules into those which only concern imported rules and those mentioning
    
    43
    +local binders (called unit_rules).
    
    44
    +
    
    45
    +Rules mentioning local binders introduce edges between any local binders they mention.
    
    46
    +
    
    47
    +Next we build the graph nodes from binders:
    
    48
    +* Fully nodes have one key, the first Id the binder defines. Their node data is the binder itself.
    
    49
    +* Pseudo nodes for every id the binder defines (tail $ bindersOf bind) with no data.
    
    50
    +
    
    51
    +Now we introduce edges:
    
    52
    +  * For binders from the first id to all other defined ids and those it mentions as fv
    
    53
    +      let key = (head bindersOf bind)
    
    54
    +      let edges = map (\x -> (key, x)) bindersOf bind ++ map (\x -> (key, x)) (bindFreeVars bind)
    
    55
    +  * For rules if they mention local binders introduce edges between any local binders they mention.
    
    56
    +
    
    57
    +* All edges computed so far are directional. So we take all edges and also add their reversed version.
    
    58
    +
    
    59
    +* After this we split the graph into independent components.
    
    60
    +
    
    61
    +* As the last step we assign each unit rule to a unit from which it mentions variables
    
    62
    +-}
    
    63
    +
    
    64
    +data DepGraphNode
    
    65
    +  = BindNode
    
    66
    +  { depNodeKey  :: !Var
    
    67
    +  , depNodeBind :: CoreBind
    
    68
    +  }
    
    69
    +  | PseudoNode
    
    70
    +  { depNodeKey :: !Var }
    
    71
    +
    
    72
    +type Edge = (Var, Var)
    
    73
    +
    
    74
    +-- | Is the given variable defined in the given module.
    
    75
    +varFromModule :: Module -> Var -> Bool
    
    76
    +varFromModule _ var = isLocalId var
    
    77
    +
    
    78
    +maybeRuleEdges :: Module -> CoreRule -> Maybe [Edge]
    
    79
    +maybeRuleEdges this_module rule =
    
    80
    +  case local_fvs of
    
    81
    +    []  -> Nothing
    
    82
    +    [_] -> Just []
    
    83
    +    _   -> Just (zip local_fvs (drop 1 local_fvs))
    
    84
    +  where
    
    85
    +    local_fvs = filter (varFromModule this_module) (nonDetEltsUniqSet (ruleFreeVars rule))
    
    86
    +
    
    87
    +bindNode :: VarSet -> CoreBind -> ([DepGraphNode], [Edge])
    
    88
    +bindNode local_top_bndrs bind =
    
    89
    +  case bindersOf bind of
    
    90
    +    []       -> ([], [])
    
    91
    +    key:rest ->
    
    92
    +      let split_fvs = bindSplitFreeVars local_top_bndrs bind
    
    93
    +          intern_edges = map (\v -> (key, v)) rest
    
    94
    +          ext_edges = map (\v -> (key, v)) (nonDetEltsUniqSet split_fvs)
    
    95
    +          node = BindNode key bind
    
    96
    +          pseudo_nodes = map PseudoNode rest
    
    97
    +      in (node : pseudo_nodes, intern_edges ++ ext_edges)
    
    98
    +
    
    99
    +bindSplitFreeVars :: VarSet -> CoreBind -> VarSet
    
    100
    +bindSplitFreeVars local_top_bndrs bind =
    
    101
    +  close_over_imported_unfoldings (bindMentionedVars bind `unionVarSet` bindBndrInfoVars bind)
    
    102
    +  where
    
    103
    +    close_over_imported_unfoldings fvs = go emptyVarSet fvs
    
    104
    +
    
    105
    +    go !seen !fvs =
    
    106
    +      case pick_new_import (fvs `minusVarSet` seen) of
    
    107
    +        Nothing -> fvs
    
    108
    +        Just v  ->
    
    109
    +          let unfolding_fvs = unfoldingRefs v
    
    110
    +              local_unfolding_fvs = unfolding_fvs `intersectVarSet` local_top_bndrs
    
    111
    +          in go (extendVarSet seen v) (fvs `unionVarSet` local_unfolding_fvs `unionVarSet` unfolding_fvs)
    
    112
    +
    
    113
    +    pick_new_import vars =
    
    114
    +      find pickable (nonDetEltsUniqSet vars)
    
    115
    +
    
    116
    +    pickable v = isId v && not (v `elemVarSet` local_top_bndrs)
    
    117
    +
    
    118
    +    unfoldingRefs v =
    
    119
    +      case maybeUnfoldingTemplate (realIdUnfolding v) of
    
    120
    +        Just rhs -> exprSomeFreeVars (const True) rhs
    
    121
    +        Nothing  -> emptyVarSet
    
    122
    +
    
    123
    +bindMentionedVars :: CoreBind -> VarSet
    
    124
    +bindMentionedVars (NonRec _ rhs) = exprSomeFreeVars (const True) rhs
    
    125
    +bindMentionedVars (Rec prs)      = exprsSomeFreeVars (const True) (map snd prs)
    
    126
    +
    
    127
    +bindBndrInfoVars :: CoreBind -> VarSet
    
    128
    +bindBndrInfoVars bind =
    
    129
    +  mkVarSet $
    
    130
    +    concatMap (dVarSetElems . bndrRuleAndUnfoldingVarsDSet) (bindersOf bind)
    
    131
    +
    
    132
    +type Edges = IdEnv [Var]
    
    133
    +
    
    134
    +-- Split core binders takes directed edges treating them as undirected by adding the reverse edge internally.
    
    135
    +splitCoreBinders :: [DepGraphNode] -> [Edge] -> [(VarSet, [CoreBind])]
    
    136
    +splitCoreBinders nodes edges =
    
    137
    +  [ (mkVarSet (concatMap bindersOf binds), binds)
    
    138
    +  | comp_nodes <- map scc_payloads (stronglyConnCompFromEdgedVerticesUniq (map mk_graph_node nodes))
    
    139
    +  , let binds = [ b | BindNode { depNodeBind = b } <- comp_nodes ]
    
    140
    +  ]
    
    141
    +  where
    
    142
    +    key_set = mkVarSet (map depNodeKey nodes)
    
    143
    +    undirected_edges = foldr add_edge emptyVarEnv (edges ++ map reverse_edge edges)
    
    144
    +
    
    145
    +    add_edge :: Edge -> Edges -> Edges
    
    146
    +    add_edge (src, dst) env = extendVarEnv_C (++) env src [dst]
    
    147
    +
    
    148
    +    reverse_edge :: Edge -> Edge
    
    149
    +    reverse_edge (src, dst) = (dst, src)
    
    150
    +
    
    151
    +    mk_graph_node node
    
    152
    +      = DigraphNode
    
    153
    +          { node_payload = node
    
    154
    +          , node_key = varUnique key
    
    155
    +          , node_dependencies =
    
    156
    +              [ varUnique dst
    
    157
    +              | dst <- lookupVarEnv undirected_edges key `orElse` []
    
    158
    +              , elemVarSet dst key_set
    
    159
    +              ]
    
    160
    +          }
    
    161
    +      where
    
    162
    +        key = depNodeKey node
    
    163
    +
    
    164
    +    scc_payloads (AcyclicSCC p) = [p]
    
    165
    +    scc_payloads (CyclicSCC ps) = ps
    
    166
    +
    
    167
    +assignLocalRules
    
    168
    +  :: [CoreRule]
    
    169
    +  -> [(VarSet, [CoreBind])]
    
    170
    +  -> ([(VarSet, [CoreBind], [CoreRule])], [CoreRule])
    
    171
    +assignLocalRules unit_rules binder_components =
    
    172
    +  (components_with_rules, rules_without_component)
    
    173
    +  where
    
    174
    +    (component_rule_map, rules_without_component)
    
    175
    +      = foldr assign_rule (IntMap.empty, []) unit_rules
    
    176
    +
    
    177
    +    assign_rule rule (rule_map, no_comp_rules)
    
    178
    +      = case rule_comp_indices rule of
    
    179
    +          [i] -> (IntMap.insertWith (++) i [rule] rule_map, no_comp_rules)
    
    180
    +          []  -> (rule_map, rule : no_comp_rules)
    
    181
    +          is  -> pprPanic "splitCompUnit"
    
    182
    +                 ( text "Rule free vars span multiple components"
    
    183
    +                $$ text "rule:" <+> ppr rule
    
    184
    +                $$ text "components:" <+> ppr is
    
    185
    +                $$ text "rule_fvs:" <+> pprVarsWithModule (nonDetEltsUniqSet (ruleFreeVars rule))
    
    186
    +                $$ vcat [ text "component" <+> int i <> colon <+> ppr hits
    
    187
    +                        | (i, hits) <- comp_hits rule ] )
    
    188
    +
    
    189
    +    rule_comp_indices rule
    
    190
    +      = IntSet.toList $ IntSet.fromList
    
    191
    +          [ i
    
    192
    +          | ((bndrs, _), i) <- zip binder_components [0..]
    
    193
    +          , not (isEmptyVarSet (ruleFreeVars rule `intersectVarSet` bndrs))
    
    194
    +          ]
    
    195
    +
    
    196
    +    comp_hits rule =
    
    197
    +      [ (i, ruleFreeVars rule `intersectVarSet` bndrs)
    
    198
    +      | ((bndrs, _), i) <- zip binder_components [0..]
    
    199
    +      , not (isEmptyVarSet (ruleFreeVars rule `intersectVarSet` bndrs))
    
    200
    +      ]
    
    201
    +
    
    202
    +    components_with_rules =
    
    203
    +      [ (bndrs, binds, IntMap.findWithDefault [] i component_rule_map)
    
    204
    +      | ((bndrs, binds), i) <- zip binder_components [0..]
    
    205
    +      ]
    
    206
    +
    
    207
    +pprVarsWithModule :: [Var] -> SDoc
    
    208
    +pprVarsWithModule vars = braces (fsep (punctuate comma (map pprVarWithModule vars)))
    
    209
    +
    
    210
    +pprVarWithModule :: Var -> SDoc
    
    211
    +pprVarWithModule v
    
    212
    +  | isExternalName n = ppr v <+> parens (ppr (nameModule n))
    
    213
    +  | otherwise        = ppr v
    
    214
    +  where
    
    215
    +    n = varName v
    
    216
    +
    
    217
    +-- After optimizations a rule might no longer reference binders from this module.
    
    218
    +-- In these cases we return them here and then add them to mg_rules.
    
    219
    +splitCompUnit :: Module -> [CoreRule] -> CoreCompUnit -> ([CoreCompUnit], [CoreRule])
    
    220
    +splitCompUnit this_module imp_rules unit
    
    221
    +  = let comp_units = map mk_comp_unit components_with_rules
    
    222
    +    in checkNameClashes comp_units `seq`
    
    223
    +       (comp_units, rules_for_imps ++ rules_without_component)
    
    224
    +  where
    
    225
    +    CoreCompUnit occ_binds unit_rules =
    
    226
    +      occurAnalyseCompUnit this_module (const True) (const True) imp_rules unit
    
    227
    +
    
    228
    +    top_level_bndrs = bindersOfBinds occ_binds
    
    229
    +    checked_bndrs =
    
    230
    +      assertPpr (all isLocalVar top_level_bndrs)
    
    231
    +        ( text "splitCompUnit: non-local top-level binder(s)"
    
    232
    +       $$ ppr top_level_bndrs )
    
    233
    +      top_level_bndrs
    
    234
    +
    
    235
    +    local_top_bndrs = mkVarSet checked_bndrs
    
    236
    +
    
    237
    +    (bind_nodes, bind_edges)
    
    238
    +      = checked_bndrs `seq`
    
    239
    +        foldr (\b (ns, es) -> let (ns', es') = bindNode local_top_bndrs b in (ns' ++ ns, es' ++ es))
    
    240
    +              ([], [])
    
    241
    +              occ_binds
    
    242
    +
    
    243
    +    rule_edge_pairs = [ (r, maybeRuleEdges this_module r) | r <- unit_rules ]
    
    244
    +    rule_edges = concat [ es | (_, Just es) <- rule_edge_pairs ]
    
    245
    +    rules_for_imps = [ r | (r, Nothing) <- rule_edge_pairs ]
    
    246
    +    unit_rules_local = [ r | (r, Just _) <- rule_edge_pairs ]
    
    247
    +
    
    248
    +    all_edges = bind_edges ++ rule_edges
    
    249
    +    binder_components = splitCoreBinders bind_nodes all_edges
    
    250
    +    (components_with_rules, rules_without_component) =
    
    251
    +      assignLocalRules unit_rules_local binder_components
    
    252
    +
    
    253
    +    mk_comp_unit (_, binds, rules) = CoreCompUnit binds rules
    
    254
    +
    
    255
    +checkNameClashes :: [CoreCompUnit] -> ()
    
    256
    +checkNameClashes comp_units
    
    257
    +  | null dup_bndrs = ()
    
    258
    +  | otherwise
    
    259
    +  = pprPanic "checkNameClashes"
    
    260
    +      ( text "Duplicate top-level binders across split compilation units"
    
    261
    +     $$ ppr dup_bndrs )
    
    262
    +  where
    
    263
    +    all_bndrs = concatMap (bindersOfBinds . coreCompUnitBinds) comp_units
    
    264
    +
    
    265
    +    dup_bndrs :: [Var]
    
    266
    +    dup_bndrs = go emptyVarSet all_bndrs
    
    267
    +
    
    268
    +    go _    [] = []
    
    269
    +    go seen (b:bs)
    
    270
    +      | b `elemVarSet` seen = b : go seen bs
    
    271
    +      | otherwise           = go (extendVarSet seen b) bs

  • compiler/GHC/Core/SimpleOpt.hs
    ... ... @@ -205,7 +205,8 @@ simpleOptPgm opts this_mod binds rules =
    205 205
     
    
    206 206
         do_unit (env, comp_units') (CoreCompUnit unit_binds unit_rules)
    
    207 207
           = let (env', unit_binds') = foldl' do_one (env, []) unit_binds
    
    208
    -        in (env', CoreCompUnit (reverse unit_binds') unit_rules : comp_units')
    
    208
    +            unit_rules' = map (substRule (soe_subst env') id) unit_rules
    
    209
    +        in (env', CoreCompUnit (reverse unit_binds') unit_rules' : comp_units')
    
    209 210
     
    
    210 211
         do_one (env, binds') bind
    
    211 212
           = case simple_opt_bind env bind TopLevel of
    

  • compiler/GHC/Core/Subst.hs
    ... ... @@ -13,7 +13,7 @@ module GHC.Core.Subst (
    13 13
     
    
    14 14
             -- ** Substituting into expressions and related types
    
    15 15
             deShadowBinds, deShadowCompUnits,
    
    16
    -        substRuleInfo, substRulesForImportedIds,
    
    16
    +        substRule, substRuleInfo, substRulesForImportedIds,
    
    17 17
             substTyUnchecked, substCo, substExpr, substExprSC, substBind, substBindSC,
    
    18 18
             substUnfolding, substUnfoldingSC,
    
    19 19
             lookupIdSubst, lookupIdSubst_maybe, substIdType, substIdOcc,
    

  • compiler/ghc.cabal.in
    ... ... @@ -393,6 +393,7 @@ Library
    393 393
             GHC.Core.Opt.Simplify.Utils
    
    394 394
             GHC.Core.Opt.SpecConstr
    
    395 395
             GHC.Core.Opt.Specialise
    
    396
    +        GHC.Core.Opt.Split
    
    396 397
             GHC.Core.Opt.StaticArgs
    
    397 398
             GHC.Core.Opt.Stats
    
    398 399
             GHC.Core.Opt.WorkWrap
    

  • testsuite/driver/testlib.py
    ... ... @@ -2842,7 +2842,21 @@ def _normalised_outputs(expected_file: Path,
    2842 2842
         return expected, actual
    
    2843 2843
     
    
    2844 2844
     def _sorted_lines(s: str) -> str:
    
    2845
    -    return '\n'.join(sorted(s.splitlines()))
    
    2845
    +    return '\n'.join(sorted(_drop_split_comp_unit_headers(s.splitlines())))
    
    2846
    +
    
    2847
    +def _drop_split_comp_unit_headers(lines: List[str]) -> List[str]:
    
    2848
    +    kept: List[str] = []
    
    2849
    +    i = 0
    
    2850
    +    while i < len(lines):
    
    2851
    +        # Ignore an empty line immediately followed by the split-core unit header.
    
    2852
    +        if i + 1 < len(lines) \
    
    2853
    +           and lines[i] == '' \
    
    2854
    +           and lines[i + 1].startswith('=== Start of new compilation unit'):
    
    2855
    +            i += 2
    
    2856
    +            continue
    
    2857
    +        kept.append(lines[i])
    
    2858
    +        i += 1
    
    2859
    +    return kept
    
    2846 2860
     
    
    2847 2861
     def _is_reordered_output_mismatch(expected_file: Path,
    
    2848 2862
                                       actual_file: Path,