[GHC] #11770: Demand analysis: Wrong one-shot annotation due to fixed-point iteration
GHC
ghc-devs at haskell.org
Tue Mar 29 15:44:00 UTC 2016
#11770: Demand analysis: Wrong one-shot annotation due to fixed-point iteration
-------------------------------------+-------------------------------------
Reporter: nomeata | Owner:
Type: bug | Status: new
Priority: normal | Milestone:
Component: Compiler | Version: 8.1
Keywords: | Operating System: Unknown/Multiple
Architecture: | Type of failure: None/Unknown
Unknown/Multiple |
Test Case: | Blocked By:
Blocking: | Related Tickets:
Differential Rev(s): | Wiki Page:
-------------------------------------+-------------------------------------
After quite a while of staring at the core of nofib’s `fft2` benchmark,
where my dynamic entry counting code (#10613), I found the problem. Here
is a small example:
{{{
foo :: Int -> Int -> Int
foo 10 c = 0
foo n c =
let bar :: Int -> Int
bar n = n + c
{-# NOINLINE bar #-}
in bar n + foo (bar (n+1)) c
}}}
Clearly, `bar` is not single-entry. But the demand analyzer believes it
is:
{{{
Rec {
-- RHS size: {terms: 32, types: 12, coercions: 0}
foo [Occ=LoopBreaker] :: Int -> Int -> Int
[LclIdX,
Arity=2,
Str=<S(S),1*U(U)><L,U(U)>m,
Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
WorkFree=True, Expandable=True, Guidance=IF_ARGS [20 0] 192 20}]
foo =
\ (ds [Dmd=<S(S),1*U(U)>] :: Int) (c [Dmd=<L,U(U)>] :: Int) ->
case ds of wild [Dmd=<L,1*U(U)>] { I# ds [Dmd=<S,U>] ->
case ds of ds {
__DEFAULT ->
let {
bar [InlPrag=NOINLINE, Dmd=<C(S(S)),C(U(U))>] :: Int -> Int
[LclId,
Arity=1,
CallArity=1,
Str=<S(S),1*U(U)>m {axl-><S(S),1*U(U)>},
Unf=Unf{Src=<vanilla>, TopLvl=False, Value=True, ConLike=True,
WorkFree=True, Expandable=True, Guidance=IF_ARGS [0] 30
0}]
bar =
\ (n [Dmd=<S(S),1*U(U)>, OS=OneShot] :: Int) ->
$fNumInt_$c+ n c } in
case bar wild of _ [Occ=Dead, Dmd=<L,A>] { I# x [Dmd=<S,U>] ->
case foo (bar (I# (+# ds 1#))) c
of _ [Occ=Dead, Dmd=<L,A>] { I# y [Dmd=<S,U>] ->
I# (+# x y)
}
};
10# -> lvl
}
}
end Rec }
}}}
The reason is that during the first fixed-point iteration for `foo`, `foo`
itself is assumed to not put any demand on its arguments. Under this
assumption, it is correct to find that `bar` is called at most once. This
is then noted in the lambda binder. The second iteration corrects the
demand, but not the one-shot annotation, because that is only added by the
demand analyzer, never dropped:
{{{#!hs
setOneShotness :: Count -> Id -> Id
setOneShotness One bndr = setOneShotLambda bndr
setOneShotness Many bndr = bndr
}}}
This can be fixed by changing that code (from `DmdAnal.hs`) to
{{{#!hs
setOneShotness :: Count -> Id -> Id
setOneShotness One bndr = setOneShotLambda bndr
setOneShotness Many bndr = clearOneShotLambda bndr
}}}
But this would have other consequences, e.g. erasing any possible manual
one-shot annotations using `oneShot`.
Or maybe `setOneShotness` should not be set by the demand analyzer during
its work, but once at the end, or maybe even the next simplifier pass
should take care of that.
--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/11770>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
More information about the ghc-tickets
mailing list