Opened 9 years ago

Closed 9 years ago

#4227 closed bug (fixed)

Allow SPECIALISE pragmas for functions defined in another module

Reported by: simonpj Owned by:
Priority: normal Milestone: 7.4.1
Component: Compiler Version: 6.12.3
Keywords: Cc: sebf@…, michal.terepeta@…
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: None/Unknown Test Case:
Blocked By: Blocking:
Related Tickets: Differential Rev(s):
Wiki Page:



say I have

  module A where
     class C a where ...
     f :: C a => String -> a

  module B where
     import A
     data T = ...
     instance C T where ...
     g :: String -> SomeOtherType
     g s = doSomethingWith (f s)

Is it possible to SPECIALIZE f for the type T? Currently no.

Some care would be needed to support this. Currently GHC's -fexpose-all-unfoldings makes no attempt to ensure that the exposed unfolding for f is exactly what the user originally wrote. For example, other functions might have been inlined into f's RHS that might make it a lot bigger. Maybe you'd want to say

	f = <blah>

to mean "expose f's unfolding, pretty much as-is, rather than optimising it". This is close to what you get with

	{-# INLINE f #-}

(which also exposes the original RHS) but without the "please inline me at every call site" meaning.

Change History (8)

comment:1 Changed 9 years ago by sebf

The motivation for this is Matching.hs. Currently it has SPECIALIZE pragmas for Prelude types but more complex matching policies like Leftmost.hs must use unspecialized matching functions. Ideally, I would just write

 {-# SPECIALIZE partialMatch :: RegExp c -> [(Int,c)] -> Leftmost #-}
 {-# SPECIALIZE matchW :: RegW Leftmost c -> [(Int,c)] -> Leftmost #-}

into Leftmost.hs to specialize partialMatch and its overloaded dependency matchW.

comment:2 Changed 9 years ago by igloo

Milestone: 6.16.1

comment:3 Changed 9 years ago by simonpj

Status: newmerge

Specialisation for imported functions is implemented in GHC 7, provided they are declared INLINABLE. I failed to write the documentation, but I have now done so:

Wed Nov 17 11:15:59 GMT 2010
  * Document SPECIALISE for imported functions
  This is a really useful new facility, but I'd forgotten to document it.
  Pls merge to 7.0 branch

Pls merge.


comment:4 Changed 9 years ago by igloo

Resolution: fixed
Status: mergeclosed


comment:5 Changed 9 years ago by dreixel

Is this working for class methods too? See the following example:

module M1 where

class MyEnum a where
  {-# INLINABLE myEnum #-}
  myEnum :: [a]

instance MyEnum () where myEnum = [()]

{-# INLINABLE myEnum' #-}
myEnum' :: (MyEnum a) => [a]
myEnum' = myEnum
module M2 where

import M1

{-# SPECIALISE myEnum  :: [()] #-}
{-# SPECIALISE myEnum' :: [()] #-}

The first SPECIALISE pragma gives You cannot SPECIALISE `myEnum' because its definition has no INLINE/INLINABLE pragma, whereas the second works fine. I would expect the first to work too.

comment:6 Changed 9 years ago by Blaisorblade

Resolution: fixed
Status: closednew

@dreixel: in the example, myEnum specialized to type [()] would coincide with myEnum as defined in the instance. That is general for all non-polymorphic instances: given an instance MyEnum [a], it would make sense to specialized myEnum :: [Int] (I don't have GHC 7 to test this), assuming that the instance definition myEnum :: [a] is marked as INLINABLE.

OTOH, if the original INLINABLE myEnum annotation is ignored, it should not be ignored silently: an error or warning should be given, and _that is a bug_. Viceversa, INLINABLE on a class method _with_ a definition should be respected. Is it not?

The only reasonable meaning of INLINABLE on an abstract class method could be "make all instance definition inlinable", but in many cases you want to allow specializing only specific instances which have a small size: this might be a good reason against implementing it.

comment:7 Changed 9 years ago by michalt

Cc: michal.terepeta@… added

I can reproduce the problem on 7.0.3, but it seems to be fixed in HEAD. The example compiles just fine and for some simple test like:

test :: [()]
test = myEnum

the rule for specilization fires as expected.

comment:8 Changed 9 years ago by simonpj

Resolution: fixed
Status: newclosed

Great. Sounds as if we're done with this ticket then.

Note: See TracTickets for help on using tickets.