#6056: INLINABLE pragma prevents worker-wrapper to happen.
-------------------------------------+--------------------------------------
 Reporter:  milan                    |          Owner:                  
     Type:  bug                      |         Status:  new             
 Priority:  normal                   |      Component:  Compiler        
  Version:  7.4.1                    |       Keywords:                  
       Os:  Unknown/Multiple         |   Architecture:  Unknown/Multiple
  Failure:  Runtime performance bug  |       Testcase:                  
Blockedby:                           |       Blocking:                  
  Related:                           |  
-------------------------------------+--------------------------------------
 When working on containers I found out that a method returning a pair
 marked as INLINABLE does not go through a worker/wrapper transformation to
 get a worker that would return unboxed pair.

 For example:

 {{{
 module Test where

 smallerAndRest :: Ord a => a -> [a] -> (Maybe a, [a])
 smallerAndRest x [] = (Nothing, [])
 smallerAndRest x (y:ys) | y < x = (Just y, ys)
                         | otherwise = smallerAndRest x ys

 {-# INLINABLE smallerAndRest #-}
 }}}

 With the `INLINABLE` pragma, `-ddump-prep` prints
 {{{
 ==================== CorePrep ====================
 Result size = 42

 lvl_rkg :: forall a_ajz. (Data.Maybe.Maybe a_ajz, [a_ajz])
 [GblId, Caf=NoCafRefs, Str=DmdType m, Unf=OtherCon []]
 lvl_rkg =
   \ (@ a_ajz) -> (Data.Maybe.Nothing @ a_ajz, GHC.Types.[] @ a_ajz)

 Rec {
 Test.smallerAndRest [InlPrag=INLINABLE[ALWAYS], Occ=LoopBreaker]
   :: forall a_a9I.
      GHC.Classes.Ord a_a9I =>
      a_a9I -> [a_a9I] -> (Data.Maybe.Maybe a_a9I, [a_a9I])
 [GblId, Arity=3, Caf=NoCafRefs, Str=DmdType LLSm, Unf=OtherCon []]
 Test.smallerAndRest =
   \ (@ a_ajz)
     ($dOrd_sko :: GHC.Classes.Ord a_ajz)
     (x_skq :: a_ajz)
     (ds_skk :: [a_ajz]) ->
     case ds_skk of _ {
       [] -> lvl_rkg @ a_ajz;
       : y_skp ys_sks ->
         case GHC.Classes.< @ a_ajz $dOrd_sko y_skp x_skq of _ {
           GHC.Types.False ->
             Test.smallerAndRest @ a_ajz $dOrd_sko x_skq ys_sks;
           GHC.Types.True ->
             let {
               sat_skw :: Data.Maybe.Maybe a_ajz
               [LclId]
               sat_skw = Data.Maybe.Just @ a_ajz y_skp } in
             (sat_skw, ys_sks)
         }
     }
 end Rec }
 }}}

 but without the `INLINABLE` pragma, we get
 {{{
 ==================== CorePrep ====================
 Result size = 57

 Rec {
 Test.$wsmallerAndRest [Occ=LoopBreaker]
   :: forall a_a9I.
      GHC.Classes.Ord a_a9I =>
      a_a9I -> [a_a9I] -> (# Data.Maybe.Maybe a_a9I, [a_a9I] #)
 [GblId, Arity=3, Caf=NoCafRefs, Str=DmdType LLS, Unf=OtherCon []]
 Test.$wsmallerAndRest =
   \ (@ a_a9I)
     (w_skC :: GHC.Classes.Ord a_a9I)
     (w1_skE :: a_a9I)
     (w2_sky :: [a_a9I]) ->
     case w2_sky of _ {
       [] -> (# Data.Maybe.Nothing @ a_a9I, GHC.Types.[] @ a_a9I #);
       : y_skD ys_skG ->
         case GHC.Classes.< @ a_a9I w_skC y_skD w1_skE of _ {
           GHC.Types.False ->
             Test.$wsmallerAndRest @ a_a9I w_skC w1_skE ys_skG;
           GHC.Types.True ->
             let {
               sat_skV :: Data.Maybe.Maybe a_a9I
               [LclId]
               sat_skV = Data.Maybe.Just @ a_a9I y_skD } in
             (# sat_skV, ys_skG #)
         }
     }
 end Rec }

 Test.smallerAndRest [InlPrag=INLINE[0]]
   :: forall a_a9I.
      GHC.Classes.Ord a_a9I =>
      a_a9I -> [a_a9I] -> (Data.Maybe.Maybe a_a9I, [a_a9I])
 [GblId, Arity=3, Caf=NoCafRefs, Str=DmdType LLSm, Unf=OtherCon []]
 Test.smallerAndRest =
   \ (@ a_a9I)
     (w_skL :: GHC.Classes.Ord a_a9I)
     (w1_skM :: a_a9I)
     (w2_skN :: [a_a9I]) ->
     case Test.$wsmallerAndRest @ a_a9I w_skL w1_skM w2_skN
     of _ { (# ww1_skR, ww2_skS #) ->
     (ww1_skR, ww2_skS)
     }
 }}}
 Here the worker-wrapper creates a variant, which returns unboxed pair.


 I assume that there is no simple solution to this, because the
 worker/wrapper changes the INLINABLE on `smallerAndRest` to INLINE. The
 INLINABLE could be added to `$wsmallerAndRest`, but then #5928 causes the
 specialization to fail.

 Maybe at least both `smallerAndRest` and `$wsmallerAndRest` could be
 marked `INLINABLE`? Then it is not sure that `smallerAndRest` gets INLINED
 and `$wsmallerAndRest` exposed, but it is not worse than current
 situation.

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

_______________________________________________
Glasgow-haskell-bugs mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs

Reply via email to