#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