[GHC] #11443: SPECIALIZE pragma does not work + compilation times regression in GHC 8.0-rc1
GHC
ghc-devs at haskell.org
Sun Jan 17 03:22:53 UTC 2016
#11443: SPECIALIZE pragma does not work + compilation times regression in GHC
8.0-rc1
-------------------------------------+-------------------------------------
Reporter: danilo2 | Owner:
Type: bug | Status: new
Priority: highest | Milestone:
Component: Compiler | Version: 8.0.1-rc1
Resolution: | Keywords:
Operating System: Unknown/Multiple | Architecture:
| Unknown/Multiple
Type of failure: None/Unknown | Test Case:
Blocked By: | Blocking:
Related Tickets: | Differential Rev(s):
Wiki Page: |
-------------------------------------+-------------------------------------
Description changed by danilo2:
Old description:
> Hello!
> I've just hit a strange issue. I might missinterpret how the `SPECIALIZE`
> pragma works, but if I understand correctly, then there is a bug in GHC.
> Lets consider this simple code:
>
> module `A`:
>
> {{{
>
> {-# LANGUAGE UndecidableInstances #-}
> {-# LANGUAGE TypeOperators #-}
> {-# LANGUAGE KindSignatures #-}
> {-# LANGUAGE DataKinds #-}
> {-# LANGUAGE TypeFamilies #-}
> {-# LANGUAGE FlexibleInstances #-}
>
> module A where
>
> import Prelude
> import GHC.TypeLits
>
> -- TF utils
>
> type family (a :: Nat) :== (b :: Nat) where
> a :== a = 'True
> a :== b = 'False
>
> type family If cond (a :: Nat) (b :: Nat) where
> If 'True a b = a
> If 'False a b = b
>
> -- Heavy TF computations
>
> type family HeavyTF (n :: Nat) (i :: Nat) :: Nat where HeavyTF n 0 = 0
> HeavyTF n i = If
> (HeavyTF' n :== 0) (HeavyTF n (i - 1)) 1
>
> type family HeavyTF' (n :: Nat) :: Nat where HeavyTF' 0 = 0
> HeavyTF' n = HeavyTF' (n -
> 1)
>
> -- Params for tests (bigger numbers = longer compile times)
>
> type family NatOf a :: Nat
> type instance NatOf Int = 12000
> type instance NatOf String = 12000
>
> -- Type class to check GHC behavior
> class PerfC1 a where perfc1 :: a -> String
> instance CheckOk (HeavyTF 10 (NatOf a)) => PerfC1 a where perfc1 _ = "oh"
> ; {-# INLINABLE perfc1 #-}
>
> class CheckOk (n :: Nat)
> instance CheckOk 0 -- where
>
> main_cache :: IO ()
> main_cache = do
> print $ perfc1 (1 :: Int)
> print $ perfc1 ("a" :: String)
>
> perfc1_Int :: Int -> String
> perfc1_Int = perfc1
>
> perfc1_String :: String -> String
> perfc1_String = perfc1
>
> {-# SPECIALIZE perfc1 :: Int -> String #-}
> {-# SPECIALIZE perfc1 :: String -> String #-}
>
> -----
>
> perfc1' :: PerfC1 a => a -> String
> perfc1' = perfc1
> {-# INLINABLE perfc1' #-}
>
> {-# SPECIALIZE perfc1' :: Int -> String #-}
> {-# SPECIALIZE perfc1' :: String -> String #-}
>
> }}}
>
> module `Test1`:
>
> {{{
> import A
>
> main = do
> print $ perfc1 (1 :: Int)
> print $ perfc1 ("a" :: String)
> }}}
>
> module `Test2`:
>
> {{{
> import A
>
> main = do
> print $ perfc1' (1 :: Int)
> print $ perfc1' ("a" :: String)
> }}}
>
> module `Test3`:
>
> {{{
> import A
>
> main = do
> print $ perfc1_Int (1 :: Int)
> print $ perfc1_String ("a" :: String)
> }}}
>
> Compile with:
> `ghc 7.10.3` : `ghc -O2 -fenable-rewrite-rules Test<n>.hs`
> `ghc 8.0-rc1` : `ghc -O2 -fenable-rewrite-rules -freduction-depth=0
> Test<n>.hs`
>
> (I've used `-fenable-rewrite-rules` explicitly just to be sure it is
> enabled. We can omit it because `-O2` enables it)
>
> If module `A` was already compiled the compilation times for `ghc 7.10.3`
> were as follow:
> - `Test1`: ~ 16s
> - `Test2`: ~ 16s
> - `Test3`: almost instant
>
> And for `ghc 8.0-rc1` were as follow:
> - `Test1`: ~ 28s
> - `Test2`: ~ 28s
> - `Test3`: almost instant
>
> Here are 2 bugs to note:
>
> 1) the compilation times are much longer with new GHC
>
> 2) the specialize pragmas do not work
New description:
Hello!
I've just hit a strange issue. I might missinterpret how the `SPECIALIZE`
pragma works, but if I understand correctly, then there is a bug in GHC.
Lets consider this simple code:
module `A`:
{{{
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleInstances #-}
module A where
import Prelude
import GHC.TypeLits
-- TF utils
type family (a :: Nat) :== (b :: Nat) where
a :== a = 'True
a :== b = 'False
type family If cond (a :: Nat) (b :: Nat) where
If 'True a b = a
If 'False a b = b
-- Heavy TF computations
type family HeavyTF (n :: Nat) (i :: Nat) :: Nat where HeavyTF n 0 = 0
HeavyTF n i = If
(HeavyTF' n :== 0) (HeavyTF n (i - 1)) 1
type family HeavyTF' (n :: Nat) :: Nat where HeavyTF' 0 = 0
HeavyTF' n = HeavyTF' (n - 1)
-- Params for tests (bigger numbers = longer compile times)
type family NatOf a :: Nat
type instance NatOf Int = 12000
type instance NatOf String = 12000
-- Type class to check GHC behavior
class PerfC1 a where perfc1 :: a -> String
instance CheckOk (HeavyTF 10 (NatOf a)) => PerfC1 a where perfc1 _ = "oh"
; {-# INLINABLE perfc1 #-}
class CheckOk (n :: Nat)
instance CheckOk 0 -- where
main_cache :: IO ()
main_cache = do
print $ perfc1 (1 :: Int)
print $ perfc1 ("a" :: String)
perfc1_Int :: Int -> String
perfc1_Int = perfc1
perfc1_String :: String -> String
perfc1_String = perfc1
{-# SPECIALIZE perfc1 :: Int -> String #-}
{-# SPECIALIZE perfc1 :: String -> String #-}
-----
perfc1' :: PerfC1 a => a -> String
perfc1' = perfc1
{-# INLINABLE perfc1' #-}
{-# SPECIALIZE perfc1' :: Int -> String #-}
{-# SPECIALIZE perfc1' :: String -> String #-}
}}}
module `Test1`:
{{{
import A
main = do
print $ perfc1 (1 :: Int)
print $ perfc1 ("a" :: String)
}}}
module `Test2`:
{{{
import A
main = do
print $ perfc1' (1 :: Int)
print $ perfc1' ("a" :: String)
}}}
module `Test3`:
{{{
import A
main = do
print $ perfc1_Int (1 :: Int)
print $ perfc1_String ("a" :: String)
}}}
Compile with:
`ghc 7.10.3` : `ghc -O2 -fenable-rewrite-rules Test<n>.hs`
`ghc 8.0-rc1` : `ghc -O2 -fenable-rewrite-rules -freduction-depth=0
Test<n>.hs`
(I've used `-fenable-rewrite-rules` explicitly just to be sure it is
enabled. We can omit it because `-O2` enables it)
If module `A` was already compiled the compilation times for `ghc 7.10.3`
were as follow:
- `Test1`: ~ 16s
- `Test2`: ~ 16s
- `Test3`: almost instant
And for `ghc 8.0-rc1` were as follow:
- `Test1`: ~ 28s
- `Test2`: ~ 28s
- `Test3`: almost instant
Here are 2 bugs to note:
1) the compilation times are much longer with new GHC
2) the specialize pragmas do not work
**EDIT**
There is yet another funny issue here. If I try to compile the modules
like so: `time ghc -O2 -fenable-rewrite-rules -ddump-spec B.hs` GHC prints
the following lines and hangs forever eating GBs of RAM:
{{{
[1 of 2] Compiling A ( A.hs, A.o )
==================== Specialise ====================
Result size of Specialise
= {terms: 60, types: 80, coercions: 3,048,032}
Rec {
$dShow_a20B :: Show String
[LclId,
Str=DmdType,
Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
WorkFree=True, Expandable=True,
Guidance=ALWAYS_IF(arity=0,unsat_ok=True,boring_ok=True)}]
$dShow_a20B = GHC.Show.$fShow[]_$s$fShow[]1
$dPerfC1_a1Rk :: PerfC1 Int
[LclId,
Arity=1,
Str=DmdType,
Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 20 60}]
}}}
--
--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/11443#comment:5>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
More information about the ghc-tickets
mailing list