Opened 8 years ago

Closed 8 years ago

#5779 closed bug (fixed)

SPECIALISE pragma generates wrong activations

Reported by: rl Owned by:
Priority: normal Milestone:
Component: Compiler Version: 7.5
Keywords: Cc:
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: Runtime performance bug Test Case:
Blocked By: Blocking:
Related Tickets: Differential Rev(s):
Wiki Page:


It seems that in the current HEAD, the SPECIALISE pragma generates a rule with the same activation as the function that is being specialised which is utterly wrong. A small example:

foo :: Num a => a -> a
{-# NOINLINE foo #-}
foo x = x+1

{-# SPECIALISE foo :: Int -> Int #-}

The HEAD generates this rule which never fires:

"SPEC" [NEVER] forall $dNum :: GHC.Num.Num GHC.Types.Int @ GHC.Types.Int $dNum = T.foo_foo

If I change the NOINLINE pragma to INLINE [0], the rule will get the activation [0]. 7.2.2 behaves as expected:

"SPEC" [ALWAYS] forall $dNum :: GHC.Num.Num GHC.Types.Int @ GHC.Types.Int $dNum = T.foo_foo

I haven't checked 7.4 but if this happens there, too, then fixing it before the release would be great. I assume it's just a typo somewhere.

Change History (10)

comment:1 Changed 8 years ago by simonpj

difficulty: Unknown
Resolution: invalid
Status: newclosed

On the contrary it's vital that specialisations don't kick in too early. Imagine that foo had a rule

RULE "foo/bar"  forall x. foo (bar x) = x

You put a NOINLINE pragma on foo to make sure it isn't inlined too early, to make sure that the RULE gets to fire. But you'd be annoyed if the SPECIALISE pragma rewrite foo to foo_spec, and thereby stopped the RULE firing!

Happily you can add a phase to the SPECIALISE pragma, thus:

{-# SPECIALISE [1] foo :: Int -> Int #-}

which should let you do as you want. This behaviour, and the override mechanism, are documented: If the documenation is unclear (all too possible) could you suggest better wording? Thanks.


Yell if that doesn't do the job

comment:2 Changed 8 years ago by rl

Hmm, I didn't realise this is intentional. FWIW, I disagree with this design. If I want both rules and SPECIALISE, I'll add explicit phase control to my SPECIALISE pragmas.

I think GHC should at least warn if SPECIALISE generates a rule with a NEVER activation, like in my example. Also, how do I SPECIALISE with an ALWAYS activation if the specialised function has a NOINLINE pragma?

comment:3 Changed 8 years ago by rl

In fact, what guarantees does GHC give about specialisation vs. inlining? If I have:

{-# INLINE [1] f #-}
f = e

{-# SPECIALISE f :: ... #-}

both the INLINE rule and the SPECIALISE rule are now only active in phase 1. Does GHC guarantee to try the SPECIALISE rule before inlining? I suspect not (I vaguely remember you saying that you no longer guarantee that rule matching happens before inlining at some point).

comment:4 Changed 8 years ago by simonpj

  • Yes, we really need a way to say "ALWAYS". And we don't have that at the moment; you'd have to say "[100]" or something. (Which means phase 100 and later.) I'm not sure that's it's worth the pain of adding an ALWAYS case too.
  • There is no guarantee about SPECIALISE vs INLINE. After all, if you are going to inline something that is even better than specialising it. Generally you want specialisation to kick in only if inlining doesn't. So in the case you give, I'd just nuke the SPECIALISE pragma. Unless you specifically want to SPECIALISE first, in which case give a phase.


comment:5 Changed 8 years ago by rl

But if there is no guarantee about SPECIALISE vs INLINE, then how does it make sense that the SPECIALISE rule activates in the same phase as the INLINE rule by default?

comment:6 Changed 8 years ago by simonpj

Because the common case is that you have

f x = e
{-# SPECIALISE f :: Int -> Int #-}

Then you are saying "if f doesn't inline by itself, use the specialised version". That's a perfectly reasonable thing to say.

comment:7 Changed 8 years ago by simonpj

Resolution: invalid
Status: closednew

PS I agree that we should warn if the SPECIALISE rule gets a NEVER activation. Reopening for that reason.

comment:8 Changed 8 years ago by rl

Ah, I see, your point is that it doesn't matter whether we inline or specialise whereas I assume it's always better to specialise than to inline (mostly because of compilation speed and intermediate code size). I still disagree with the current default behaviour but I now see the logic behind it. Thanks for the explanation!

comment:9 Changed 8 years ago by simonpj@…

commit 6acf6cd7a8156b40979321ff94fe836736b46175

Author: Simon Peyton Jones <>
Date:   Tue Jan 17 16:01:16 2012 +0000

    Warn when a SPECIALISE pragma gives rise to a totally inactive rule
    See Trac #5779

 compiler/deSugar/DsBinds.lhs   |   62 ++++++++++++++++++++++++---------------
 compiler/typecheck/TcBinds.lhs |    3 +-
 2 files changed, 40 insertions(+), 25 deletions(-)

comment:10 Changed 8 years ago by simonpj

Resolution: fixed
Status: newclosed

OK I added the warnings

Note: See TracTickets for help on using tickets.