Skip to content
GitLab
Projects Groups Snippets
  • /
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
  • Sign in / Register
  • GHC GHC
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
    • Locked Files
  • Issues 5,359
    • Issues 5,359
    • List
    • Boards
    • Service Desk
    • Milestones
    • Iterations
  • Merge requests 571
    • Merge requests 571
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
    • Test Cases
  • Deployments
    • Deployments
    • Releases
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Code review
    • Insights
    • Issue
    • Repository
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • Glasgow Haskell CompilerGlasgow Haskell Compiler
  • GHCGHC
  • Issues
  • #7360
Closed
Open
Issue created Oct 22, 2012 by Simon Peyton Jones@simonpjDeveloper

Case-of-identical-alts optimisation fails abjectly

Herbert Valerio Riedel writes: I've been trying to improve/fix a minor optimization sub-optimality w.r.t to the following code (code like that results from the generics-based NFData deriver[1]):

    data Foo = Foo1 | Foo2 | Foo3 !Int
    
    rnf1 :: Foo -> ()
    rnf1 x = case x of
               Foo1 -> ()
               Foo2 -> ()
               Foo3 {} -> ()

which the current GHC 7.6.1 translates to the following core expression:

    NFDataTest2.rnf1 =
      \ x_aeG ->
        case x_aeG of _ {
          __DEFAULT -> GHC.Tuple.();
          NFDataTest2.Foo3 ds_deT -> GHC.Tuple.()
        }
  1. ..whereas I'd have expected it to to compile it to a collapsed __DEFAULT-only case, i.e.
    NFDataTest2.rnf1 =
      \ x_aeG -> case x_aeG of _ { __DEFAULT -> GHC.Tuple.() }

Now I've been hunting it down to the function SimplUtils.mkCase1 [2], which according to the source-code comments, is supposed to merge identical alternatives, i.e.:

| 3.  Merge identical alternatives.
|     If several alternatives are identical, merge them into
|     a single DEFAULT alternative.  I've occasionally seen this
|     making a big difference:
| 
|         case e of               =====>     case e of
|           C _ -> f x                         D v -> ....v....
|           D v -> ....v....                   DEFAULT -> f x
|           DEFAULT -> f x
  1. ..and the mkCase1 function itself reads as follows:
    mkCase1 dflags scrut case_bndr alts_ty ((_con1,bndrs1,rhs1) : con_alts)
      | all isDeadBinder bndrs1                     -- Remember the default
      , length filtered_alts < length con_alts      -- alternative comes first
            -- Also Note [Dead binders]
      = do  { tick (AltMerge case_bndr)
            ; mkCase2 dflags scrut case_bndr alts_ty alts' }
      where
        alts' = (DEFAULT, [], rhs1) : filtered_alts
        filtered_alts         = filter keep con_alts
        keep (_con,bndrs,rhs) = not (all isDeadBinder bndrs && rhs `cheapEqExpr` rhs1)

Now the problem seems to be, that isDeadBinder returns False; so I hacked up mkCase1 and inserted a occurAnalyseExpr on artificially constructed single-alternative 'Case' values before applying isDeadBinder, and then it would return True and simplify the case expression as expected.

So now my question is, why isn't the occurrence information available for the case-alternative's binders (the occInfo is set to NoOccInfo) at mkCase1-time? When is occurence analysis performed relative to the simplifier?

  • [1]: http://hackage.haskell.org/package/deepseq-generics
  • [2]: http://www.haskell.org/ghc/docs/7.6.1/html/libraries/ghc-7.6.1/src/SimplUtils.html#mkCase1
Trac metadata
Trac field Value
Version 7.6.1
Type Bug
TypeOfFailure OtherFailure
Priority normal
Resolution Unresolved
Component Compiler
Test case
Differential revisions
BlockedBy
Related
Blocking
CC hvr@gnu.org
Operating system
Architecture
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information
Assignee
Assign to
Time tracking