[GHC] #16335: Make CPR Analysis more aggressive for inductive cases

GHC ghc-devs at haskell.org
Mon Feb 18 16:47:45 UTC 2019


#16335: Make CPR Analysis more aggressive for inductive cases
-------------------------------------+-------------------------------------
           Reporter:  sgraf          |             Owner:  (none)
               Type:  task           |            Status:  new
           Priority:  normal         |         Milestone:  ⊥
          Component:  Compiler       |           Version:  8.6.3
           Keywords:  CPRAnalysis    |  Operating System:  Unknown/Multiple
       Architecture:                 |   Type of failure:  None/Unknown
  Unknown/Multiple                   |
          Test Case:                 |        Blocked By:
           Blocking:                 |   Related Tickets:
Differential Rev(s):                 |         Wiki Page:
-------------------------------------+-------------------------------------
 While investigating the generated Core for a simple toy benchmark, I came
 up with the following minimal example:

 {{{#!hs

 data Expr
   = Lit Int
   | Plus Expr Expr

 eval :: Expr -> Int
 eval (Lit n) = n
 eval (Plus a b) = eval a + eval b
 }}}

 resulting in the following Core:

 {{{
 eval
   = \ (ds_d112 :: Expr) ->
       case ds_d112 of {
         Lit n_aXf -> n_aXf;
         Plus a_aXg b_aXh ->
           case eval a_aXg of { GHC.Types.I# x_a1bK ->
           case eval b_aXh of { GHC.Types.I# y_a1bO ->
           GHC.Types.I# (GHC.Prim.+# x_a1bK y_a1bO)
           }
           }
       }
 }}}

 Note that this needlessly unboxes and boxes primitive Ints. Lifting this
 is precisely the job of CPR, but `eval` doesn't exactly have the CPR
 property: the `Lit` case doesn't return a product. But we're punishing
 ourselves for the base case when ''even the function itself'' recurses
 multiple times!

 The code resulting from WWing here wouldn't even look bad in the `Lit`
 case:

 {{{
 Foo.$weval
   = \ (w_s1cn :: Expr) ->
       case w_s1cn of {
         Lit dt_d11b -> case dt_d11b { I# ds_abcd -> ds_abcd };
         Plus a_aXf b_aXg ->
           case Foo.$weval a_aXf of ww_s1cq { __DEFAULT ->
           case Foo.$weval b_aXg of ww1_X1dh { __DEFAULT ->
           GHC.Prim.+# ww_s1cq ww1_X1dh
           }
           }
       }

 eval
   = \ (w_s1cn :: Expr) ->
       case Foo.$weval w_s1cn of ww_s1cq { __DEFAULT ->
       GHC.Types.I# ww_s1cq
       }
 }}}

 Granted, this is bad for the case where there is no recursion happening
 and we need the result of `eval` boxed, but that's a small price to pay
 IMO.

 I begin to think of CPR more of as the "dual" to SpecConstr than to
 Strictness Analysis. Return pattern specialisation, so to speak.

-- 
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/16335>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler


More information about the ghc-tickets mailing list