#2224: -fhpc inteferes/prevents rewrite rules from firing
---------------------------+------------------------------------------------
Reporter: dons | Owner: [EMAIL PROTECTED]
Type: bug | Status: new
Priority: normal | Milestone:
Component: Code Coverage | Version: 6.8.2
Severity: normal | Resolution:
Keywords: rules, hpc | Difficulty: Unknown
Testcase: | Architecture: Unknown
Os: Unknown |
---------------------------+------------------------------------------------
Changes (by simonpj):
* difficulty: => Unknown
Comment:
In general, coverage testing is incompatible with optimisation, although
it seems surprising (to me) robust:
{{{
f x = g (h x)
g x = x
h x = x
}}}
then if we inline busily we'll get
{{{
f x = x
}}}
and in fact this ''does'' happen, but none of the relevant ticks are lost.
In effect, the optimiser knows how to commute stuff with ticks, because
ticks get encoded as `case` expressions. There's a paper in here,
actually, because the code does get shaken around quite a bit, despite the
ticks littering it. (Mind you, we don't yet have an operational semantics
to tell us what ticks ''should'' do, though that would not be hard to
write. That too should be in the paper.)
But this robustness breaks down for rewrite rules, because they inspect
the structure of terms, and that's messed up by the ticks. For a
composition of strict functions, matters are more straightforward, as Andy
says, because all the ticks float to the outside. To take his example, if
we have
{{{
f x = ...(pack (unpack s))...
}}}
after tick decoration it'll look like
{{{
f x = ...(tick <a> (pack (tick <b> (unpack s)))...
}}}
then the tick around the `(unpack s)` will float out (since `pack` is
strict), so we'll end up with something like
{{{
f x = ...(tick <a> (tick <b> (pack (unpack s)))...
}}}
So if we simply did not tick-ify the LHS of a rule you'd think the rule
would work. And it seems to: try this with `-fhpc -O`.
{{{
module Foo where
f g x = g x
{-# NOINLINE g #-}
g x = x
{-# NOINLINE h #-}
h x = x
foo y = f g (h y)
{-# RULES "gh" forall x. g (h x) = g x #-}
}}}
(NB: The rule `gh` doesn't fire until after strictness analysis has told
us that `g` is strict; and that late firing definitely could be a
problem.)
Conclusion: we aren't decorating RULES with ticks anyway, and that must be
the Right Thing for the LHS of the rule. (We almost certainly ''should''
decorate their right-hand sides -- that's a bug.)
The problem, I guess, comes with lazy functions, where the ticks don't
float. And indeed, if `f` is lazy, so does not provably consume its
argument, what would you ''like'' to happen for
{{{
RULE "f" forall x. f (g x) = x
}}}
In an expression `...(f (tick <a> (g x)))...`, what do you want to happen
to the `<a>` tick? Do you want to show `(g x)` as covered? Or not?
The most plausible answer is, I think, that we'd like to show `(g x)` as
covered, so we'd like to do the following rewrite
{{{
...(f (tick <a> (g x)))... ==> ....(tick <a> x)....
}}}
That is, the tick should not get in the way of matching, but should not be
discarded either. Instead it should be saved up and wrapped around the
result.
Interesting. This is '''very like''' what happens for let-expressions.
See Section 4.1 of the [http://research.microsoft.com/%7Esimonpj/papers
/spec-constr/spec-constr.pdf call-pattern specialisation paper], and `Note
[Matching lets]` in `specialise/Rules.lhs`. So I speculate that, if this
is the semantics we want, we could adjust the rule matcher to ignore-but-
accumulate ticks, just as it does lets.
Andy if you want to pursue this, I can guide you to the right place.
Simon
--
Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/2224#comment:2>
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