X-Git-Url: http://git.megacz.com/?p=ghc-hetmet.git;a=blobdiff_plain;f=compiler%2FsimplCore%2FOccurAnal.lhs;h=77c586158bbe13b8d17b7a2069d4ade849f4dfd9;hp=4dfd3bfd2927d8fbf78efba92fec6f591b125c48;hb=ad94d40948668032189ad22a0ad741ac1f645f50;hpb=3887012695f2ee71f1f55e72eb215fed3450bb1d diff --git a/compiler/simplCore/OccurAnal.lhs b/compiler/simplCore/OccurAnal.lhs index 4dfd3bf..77c5861 100644 --- a/compiler/simplCore/OccurAnal.lhs +++ b/compiler/simplCore/OccurAnal.lhs @@ -11,6 +11,13 @@ The occurrence analyser re-typechecks a core expression, returning a new core expression with (hopefully) improved usage information. \begin{code} +{-# OPTIONS -w #-} +-- The above warning supression flag is a temporary kludge. +-- While working on this module you are encouraged to remove it and fix +-- any warnings in the module. See +-- http://hackage.haskell.org/trac/ghc/wiki/CodingStyle#Warnings +-- for details + module OccurAnal ( occurAnalysePgm, occurAnalyseExpr ) where @@ -35,8 +42,10 @@ import Digraph ( stronglyConnCompR, SCC(..) ) import PrelNames ( buildIdKey, foldrIdKey, runSTRepIdKey, augmentIdKey ) import Unique ( Unique ) import UniqFM ( keysUFM, intersectsUFM ) -import Util ( mapAndUnzip, mapAccumL ) +import Util ( mapAndUnzip ) import Outputable + +import Data.List \end{code} @@ -133,7 +142,7 @@ It isn't easy to do a perfect job in one blow. Consider \begin{code} occAnalBind env (Rec pairs) body_usage - = foldr (_scc_ "occAnalBind.dofinal" do_final_bind) (body_usage, []) sccs + = foldr ({-# SCC "occAnalBind.dofinal" #-} do_final_bind) (body_usage, []) sccs where analysed_pairs :: [Details] analysed_pairs = [ (bndr, rhs_usage, rhs') @@ -142,12 +151,12 @@ occAnalBind env (Rec pairs) body_usage ] sccs :: [SCC (Node Details)] - sccs = _scc_ "occAnalBind.scc" stronglyConnCompR edges + sccs = {-# SCC "occAnalBind.scc" #-} stronglyConnCompR edges ---- stuff for dependency analysis of binds ------------------------------- edges :: [Node Details] - edges = _scc_ "occAnalBind.assoc" + edges = {-# SCC "occAnalBind.assoc" #-} [ (details, idUnique id, edges_from id rhs_usage) | details@(id, rhs_usage, rhs) <- analysed_pairs ] @@ -162,7 +171,7 @@ occAnalBind env (Rec pairs) body_usage -- which has n**2 cost, and this meant that edges_from alone -- consumed 10% of total runtime! edges_from :: Id -> UsageDetails -> [Unique] - edges_from bndr rhs_usage = _scc_ "occAnalBind.edges_from" + edges_from bndr rhs_usage = {-# SCC "occAnalBind.edges_from" #-} keysUFM (addRuleUsage rhs_usage bndr) ---- Stuff to "re-constitute" bindings from dependency-analysis info ------ @@ -300,16 +309,16 @@ reOrderCycle bndrs (bind : binds) -- where df is the exported dictionary. Then df makes a really -- bad choice for loop breaker - | is_con_app rhs = 3 -- Data types help with cases - -- This used to have a lower score than inlineCandidate, but - -- it's *really* helpful if dictionaries get inlined fast, - -- so I'm experimenting with giving higher priority to data-typed things + | idHasRules bndr = 3 + -- Avoid things with specialisations; we'd like + -- to take advantage of them in the subsequent bindings + -- Also vital to avoid risk of divergence: + -- Note [Recursive rules] | inlineCandidate bndr rhs = 2 -- Likely to be inlined + -- Note [Inline candidates] - | idHasRules bndr = 1 - -- Avoid things with specialisations; we'd like - -- to take advantage of them in the subsequent bindings + | is_con_app rhs = 1 -- Data types help with cases | otherwise = 0 @@ -352,6 +361,44 @@ makeLoopBreaker bndrs rhs_usg bndr rules_only = bndrs `intersectsUFM` rhs_usg \end{code} +Note [Inline candidates] +~~~~~~~~~~~~~~~~~~~~~~~~ +At one point I gave is_con_app a higher score than inline-candidate, +on the grounds that "it's *really* helpful if dictionaries get inlined fast". +However a nofib run revealed no change if they were swapped so that +inline-candidate has the higher score. And it's important that it does, +else you can get a bad worker-wrapper split thus: + rec { + $wfoo x = ....foo x.... + + {-loop brk-} foo x = ...$wfoo x... + } +But we *want* the wrapper to be inlined! If it isn't, the interface +file sees the unfolding for $wfoo, and sees that foo is strict (and +hence it gets an auto-generated wrapper. Result: an infinite inlining +in the importing scope. So be a bit careful if you change this. A +good example is Tree.repTree in nofib/spectral/minimax. If is_con_app +has the higher score, then compiling Game.hs goes into an infinite loop. + +Note [Recursive rules] +~~~~~~~~~~~~~~~~~~~~~~ +Consider this group, which is typical of what SpecConstr builds: + + fs a = ....f (C a).... + f x = ....f (C a).... + {-# RULE f (C a) = fs a #-} + +So 'f' and 'fs' are mutually recursive. If we choose 'fs' as the loop breaker, +all is well; the RULE is applied, and 'fs' becomes self-recursive. + +But if we choose 'f' as the loop breaker, we may get an infinite loop: + - the RULE is applied in f's RHS (see Note [Self-recursive rules] in Simplify + - fs is inlined (say it's small) + - now there's another opportunity to apply the RULE + +So it's very important to choose the RULE-variable as the loop breaker. +This showed up when compiling Control.Concurrent.Chan.getChanContents. + Note [Closure conversion] ~~~~~~~~~~~~~~~~~~~~~~~~~ We treat (\x. C p q) as a high-score candidate in the letrec scoring algorithm.