#1592: Unexpected boxing in generated code
-------------------------+--------------------------------------------------
    Reporter:  neil      |        Owner:         
        Type:  bug       |       Status:  new    
    Priority:  normal    |    Milestone:         
   Component:  Compiler  |      Version:  6.6.1  
    Severity:  minor     |   Resolution:         
    Keywords:            |   Difficulty:  Unknown
          Os:  Unknown   |     Testcase:         
Architecture:  Unknown   |  
-------------------------+--------------------------------------------------
Old description:

> argument being passed around, but that GHC 6.6.1 isn't unboxing. In
> the following example both functions take a GHC.Base.Int, which I
> think should be an Int#.
>
> {{{
> Rec {
> f60_rS5 :: GHC.Prim.State# GHC.Prim.RealWorld -> GHC.Base.Int ->
> GHC.Base.Int
> [GlobalId]
> [Arity 2
>  NoCafRefs
>  Str: DmdType LL]
> f60_rS5 =
>  \ (v1_aWH :: GHC.Prim.State# GHC.Prim.RealWorld) (v2_aWI ::
> GHC.Base.Int) ->
>    case $wccall_r2kv v1_aWH of wild_X2j { (# ds_d1V4, ds1_d1V3 #) ->
>    case ds1_d1V3 of wild1_X2L {
>      __DEFAULT -> f60_rS5 ds_d1V4 v2_aWI;
>      (-1) -> v2_aWI;
>      10 -> f561_r2kx ds_d1V4 v2_aWI
>    }
>    }
> f561_r2kx :: GHC.Prim.State# GHC.Prim.RealWorld -> GHC.Base.Int ->
> GHC.Base.Int
> [GlobalId]
> [Arity 2
>  NoCafRefs
>  Str: DmdType LL]
> f561_r2kx =
>  \ (v1_aWm :: GHC.Prim.State# GHC.Prim.RealWorld) (v2_aWn ::
> GHC.Base.Int) ->
>    case $wccall_r2kv v1_aWm of wild_X2j { (# ds_d1V4, ds1_d1V3 #) ->
>    case ds1_d1V3 of wild1_X2P {
>      __DEFAULT ->
>        case v2_aWn of wild2_a2du { GHC.Base.I# x_a2dw ->
>        case wild1_X2P of wild3_X35 {
>          __DEFAULT -> f60_rS5 ds_d1V4 (GHC.Base.I# (GHC.Prim.+# x_a2dw
> 1));
>          10 -> f561_r2kx ds_d1V4 (GHC.Base.I# (GHC.Prim.+# x_a2dw 1))
>        }
>        };
>      (-1) -> v2_aWn
>    }
>    }
> end Rec }
> }}}
>
> This code comes from a line counting program, I have attached the
> entire source. My character counting program does infer the correct
> strictness, although that is based on a single self-recursive
> function. The largest obvious difference is that the strictness
> depends on the two functions which call each other - does this impeed
> GHC's strictness analysis?

New description:

 I've got an inner loop that I think I can see is strict in the Int
 argument being passed around, but that GHC 6.6.1 isn't unboxing. In
 the following example both functions take a GHC.Base.Int, which I
 think should be an Int#.

 {{{
 Rec {
 f60_rS5 :: GHC.Prim.State# GHC.Prim.RealWorld -> GHC.Base.Int ->
 GHC.Base.Int
 [GlobalId]
 [Arity 2
  NoCafRefs
  Str: DmdType LL]
 f60_rS5 =
  \ (v1_aWH :: GHC.Prim.State# GHC.Prim.RealWorld) (v2_aWI :: GHC.Base.Int)
 ->
    case $wccall_r2kv v1_aWH of wild_X2j { (# ds_d1V4, ds1_d1V3 #) ->
    case ds1_d1V3 of wild1_X2L {
      __DEFAULT -> f60_rS5 ds_d1V4 v2_aWI;
      (-1) -> v2_aWI;
      10 -> f561_r2kx ds_d1V4 v2_aWI
    }
    }
 f561_r2kx :: GHC.Prim.State# GHC.Prim.RealWorld -> GHC.Base.Int ->
 GHC.Base.Int
 [GlobalId]
 [Arity 2
  NoCafRefs
  Str: DmdType LL]
 f561_r2kx =
  \ (v1_aWm :: GHC.Prim.State# GHC.Prim.RealWorld) (v2_aWn :: GHC.Base.Int)
 ->
    case $wccall_r2kv v1_aWm of wild_X2j { (# ds_d1V4, ds1_d1V3 #) ->
    case ds1_d1V3 of wild1_X2P {
      __DEFAULT ->
        case v2_aWn of wild2_a2du { GHC.Base.I# x_a2dw ->
        case wild1_X2P of wild3_X35 {
          __DEFAULT -> f60_rS5 ds_d1V4 (GHC.Base.I# (GHC.Prim.+# x_a2dw
 1));
          10 -> f561_r2kx ds_d1V4 (GHC.Base.I# (GHC.Prim.+# x_a2dw 1))
        }
        };
      (-1) -> v2_aWn
    }
    }
 end Rec }
 }}}

 This code comes from a line counting program, I have attached the
 entire source. My character counting program does infer the correct
 strictness, although that is based on a single self-recursive
 function. The largest obvious difference is that the strictness
 depends on the two functions which call each other - does this impeed
 GHC's strictness analysis?

Comment (by simonpj):

 (Written before I'd seen Tim's correct remarks.)  OK this is an
 interesting one. Here's the smallest program that demonstrates the
 problem.
 {{{
 foreign import ccall unsafe "stdio.h getchar" getchar :: IO CInt

 f56 :: State# RealWorld -> Int -> Int
 f56 s v2 = case (unIO getchar s) of
            (# s' , v6  #) ->
               case v2 of I# _ -> f56 s' v2
 }}}
 GHC says this is lazy in v2, which it obviously isn't.  Why?  Because
 there's a special hack (introduced after an earlier bug report) in the
 strictness analyser to account for the fact that a ccall might exit the
 program.  Suppose instead of calling 'getchar' we called 'exit'!  Then f56
 is not strict in v2 any more.

 Here was a larger program that demonstrated the problem:
 {{{
         do { let len = <expensive> ;
            ; when (...) (exitWith ExitSuccess)
            ; print len }
 }}}
 Suppose exitWith doesn't exit; it loops or returns. Then 'len' is sure to
 be evaluated, and GHC will evaluate it before the 'when'.

 The hack is in the demand analyser, to make it believe that any I/O
 operation (including getchar!) might exit instead of returning.


 OK, so that's the reason you aren't getting proper strictness in your
 inner loop.  What to do about it? It would be easy to revert to the non-
 hack situation, in which case 'len' might well be evaluated in the program
 above, even in the program above.  To make the program sufficiently lazy
 you could write
 {{{
         do { let len = <expensive> ;
            ; when (...) (exitWith ExitSuccess)
            ; lazy (print len) }
 }}}
 Here 'lazy' is a (documented) function that makes its argument appear to
 be evaluated lazily, so far as the demand analyser is concerned.  But this
 is horribly non-compositional.  ANYWHERE you say
 {{{
         do { a; b; c }
 }}}
 and b might exit, then you should really say 'lazy c'.


 One could imagine an analysis for "definitely does not exit".  But it only
 really makes sense for IO-ish things.

 In short, it's hard to see a beautiful solution.  Does anyone else have
 ideas?

 Simon

-- 
Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/1592>
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