[GHC] #4962: Dead code fed to CorePrep because RULEs keep it alive spuriously

GHC cvs-ghc at haskell.org
Thu Mar 21 17:54:35 CET 2013


#4962: Dead code fed to CorePrep because RULEs keep it alive spuriously
--------------------------------------+-------------------------------------
  Reporter:  batterseapower           |          Owner:                  
      Type:  bug                      |         Status:  closed          
  Priority:  normal                   |      Milestone:  7.2.1           
 Component:  Compiler                 |        Version:  7.0.1           
Resolution:  fixed                    |       Keywords:                  
        Os:  Unknown/Multiple         |   Architecture:  Unknown/Multiple
   Failure:  Runtime performance bug  |     Difficulty:  Unknown         
  Testcase:                           |      Blockedby:                  
  Blocking:                           |        Related:                  
--------------------------------------+-------------------------------------
Changes (by simonpj):

  * difficulty:  => Unknown


Old description:

> This ticket is split off from #4941.
>
> I'm seeing output code that looks roughly like this in the final
> simplifier output:
>
> {{{
> let
>       {-# RULES go (Just x) = $sgo_s1lg x #-}
>       go = ... go ... $w$sgo ...
>       $sgo_s1lg = ... $w$sgo_s1mv ...
>       $w$sgo_s1mv = ... big ...
> in ... $w$sgo_s1mv ...
> }}}
>
> This is bad because $sgo is will be dead for the purposes of code
> generation, but currently GHC will allocate a closure for it at runtime
> anyway.
>
> What we should do is drop the dead binding once we have decided that it's
> not reachable via the exported RULES in the interface file.
>
> I've confirmed that this patch achieves this effect (and eliminates the
> main source of increased allocations I was seeing in #4941):
>
> {{{
> hunk ./compiler/main/TidyPgm.lhs 22
> +import OccurAnal        ( occurAnalysePgm )
> hunk ./compiler/main/TidyPgm.lhs 43
> +import qualified ErrUtils as Err
> hunk ./compiler/main/TidyPgm.lhs 47
> +import PprCore
> hunk ./compiler/main/TidyPgm.lhs 322
> +
> +          -- Occurrence analyse the input program, assuming all local
> rules are off,
> +          -- but retaining any bindings referred to by external rules.
> +          -- Occurrence information may have improved since the last run
> of the
> +          -- simplifier because some bindings will become dead once
> RULES are dropped.
> +          --
> +          -- The analysis itself will take care of dropping any newly-
> dead syntax.
> +        ; Err.dumpIfSet_dyn dflags Opt_D_dump_occur_anal "BEFORE TidyPgm
> occurrence analysis" (pprCoreBindings binds)
> +        ; binds <- return $ occurAnalysePgm Nothing ext_rules binds
> +        ; Err.dumpIfSet_dyn dflags Opt_D_dump_occur_anal "TidyPgm
> occurrence analysis" (pprCoreBindings binds)
> +
> hunk ./compiler/simplCore/OccurAnal.lhs 393
> -          rule_fvs   = idRuleVars bndr          -- See Note [Rule
> dependency info]
> +          rule_fvs   = case occ_rule_act env of Nothing -> emptyVarSet;
> Just _ -> idRuleVars bndr          -- See Note [Rule dependency info]
> +          -- FIXME: this is a terrible hack to try to have OccAnal drop
> bindings that are kept alive only due to rules at the CoreTidy stage
> }}}
>
> However the patch is a bit horrible: because attached RULES keep bindings
> alive in a LetRec even if the rules can never be activated (i.e.
> occ_rule_act env == Nothing) the bindings I want to be dropped never get
> dropped. The reason I consider my fix a hack is that just because the
> rules are inactive *now* doesn't mean that they will be inactive *later*.
>
> A better approach would perhaps be to wait until the RULES are stripped
> from the binders entirely (e.g. OccAnal the output of CoreTidy). However,
> this is not straightforward because CoreTidy has globalised Ids, so
> OccAnaling the output says that all top level bindings have no FVs and
> hence turns all LetRecs into Lets!

New description:

 This ticket is split off from #4941.

 I'm seeing output code that looks roughly like this in the final
 simplifier output:

 {{{
 let
       {-# RULES go (Just x) = $sgo_s1lg x #-}
       go = ... go ... $w$sgo ...
       $sgo_s1lg = ... $w$sgo_s1mv ...
       $w$sgo_s1mv = ... big ...
 in ... $w$sgo_s1mv ...
 }}}

 This is bad because $sgo is will be dead for the purposes of code
 generation, but currently GHC will allocate a closure for it at runtime
 anyway.

 What we should do is drop the dead binding once we have decided that it's
 not reachable via the exported RULES in the interface file.

 I've confirmed that this patch achieves this effect (and eliminates the
 main source of increased allocations I was seeing in #4941):

 {{{
 hunk ./compiler/main/TidyPgm.lhs 22
 +import OccurAnal        ( occurAnalysePgm )
 hunk ./compiler/main/TidyPgm.lhs 43
 +import qualified ErrUtils as Err
 hunk ./compiler/main/TidyPgm.lhs 47
 +import PprCore
 hunk ./compiler/main/TidyPgm.lhs 322
 +
 +          -- Occurrence analyse the input program, assuming all local
 rules are off,
 +          -- but retaining any bindings referred to by external rules.
 +          -- Occurrence information may have improved since the last run
 of the
 +          -- simplifier because some bindings will become dead once RULES
 are dropped.
 +          --
 +          -- The analysis itself will take care of dropping any newly-
 dead syntax.
 +        ; Err.dumpIfSet_dyn dflags Opt_D_dump_occur_anal "BEFORE TidyPgm
 occurrence analysis" (pprCoreBindings binds)
 +        ; binds <- return $ occurAnalysePgm Nothing ext_rules binds
 +        ; Err.dumpIfSet_dyn dflags Opt_D_dump_occur_anal "TidyPgm
 occurrence analysis" (pprCoreBindings binds)
 +
 hunk ./compiler/simplCore/OccurAnal.lhs 393
 -          rule_fvs   = idRuleVars bndr          -- See Note [Rule
 dependency info]
 +          rule_fvs   = case occ_rule_act env of Nothing -> emptyVarSet;
 Just _ -> idRuleVars bndr          -- See Note [Rule dependency info]
 +          -- FIXME: this is a terrible hack to try to have OccAnal drop
 bindings that are kept alive only due to rules at the CoreTidy stage
 }}}

 However the patch is a bit horrible: because attached RULES keep bindings
 alive in a !LetRec even if the rules can never be activated (i.e.
 occ_rule_act env == Nothing) the bindings I want to be dropped never get
 dropped. The reason I consider my fix a hack is that just because the
 rules are inactive *now* doesn't mean that they will be inactive *later*.

 A better approach would perhaps be to wait until the RULES are stripped
 from the binders entirely (e.g. !OccAnal the output of !CoreTidy).
 However, this is not straightforward because !CoreTidy has globalised Ids,
 so OccAnaling the output says that all top level bindings have no FVs and
 hence turns all !LetRecs into Lets!

--

-- 
Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/4962#comment:11>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler



More information about the ghc-tickets mailing list