[GHC] #13025: Type family reduction irregularity (change from 7.10.3 to 8.0.1)

GHC ghc-devs at haskell.org
Wed Dec 21 17:39:03 UTC 2016


#13025: Type family reduction irregularity (change from 7.10.3 to 8.0.1)
-------------------------------------+-------------------------------------
           Reporter:  acowley        |             Owner:
               Type:  bug            |            Status:  new
           Priority:  normal         |         Milestone:
          Component:  Compiler       |           Version:  8.0.1
           Keywords:  TypeFamilies   |  Operating System:  Unknown/Multiple
       Architecture:                 |   Type of failure:  Runtime
  Unknown/Multiple                   |  performance bug
          Test Case:                 |        Blocked By:
           Blocking:                 |   Related Tickets:
Differential Rev(s):                 |         Wiki Page:
-------------------------------------+-------------------------------------
 I was recently made aware that [http://hackage.haskell.org/package/vinyl
 vinyl]'s performance dramatically deteriorated with GHC 8.0.1 when
 compared to GHC 7.x. Vinyl is an extensible records library that's been
 around for about four years; the aspect of its design relevant here is the
 basic HList-style indexed GADT. Care was taken in the past so that working
 with, say, a `Storable` `Vector` of records would suffer no overhead from
 `vinyl` when compared with standard records, and we have a benchmark suite
 to spot check this.

 In the move to GHC-8.0.1, it turns out that we do introduce overhead.
 Inspecting the Core reveals that the benchmark inner loop includes a
 `case` match on an `HEq_sc` value whose presence I would not expect, and
 that is not present when compiling with GHC-7.10.3:


 {{{
 case HEq_sc
          @ Nat
          @ Nat
          @ ('S 'Z)
          @ (RIndex
               '("normal", V3 Float)
               '['("tex", V2 Float), '("normal", V3 Float)])
          ($s$fRElemar:S_$s$fRElemar:S_$cp1RElem
           `cast` (N:~[0] <Nat>_N <'S 'Z>_N <RIndex
                                               '("normal",
                                                 V3 Float)
                                               '['("tex",
                                                   V2 Float),
                                                 '("normal",
                                                   V3 Float)]>_N
                   :: (('S 'Z :: Nat)
                       ~
                       (RIndex
                          '("normal", V3 Float)
                          '['("tex", V2 Float),
                            '("normal",
                              V3 Float)] :: Nat) :: Constraint)
                      ~R#
                      (('S 'Z :: Nat)
                       ~~
                       (RIndex
                          '("normal", V3 Float)
                          '['("tex", V2 Float),
                            '("normal",
                              V3 Float)] :: Nat) :: Constraint)))
   of cobox0 { __DEFAULT ->
 }}}

 I have since made an effort to reproduce the issue, and discovered more
 fragility than I expected. I am attaching two modules: `Rec.hs` defines a
 kind of record type, `Main.hs` is a test program that I will reproduce
 here,

 {{{
 {-# LANGUAGE DataKinds #-}
 module Main where
 import Rec

 type MyRec = Rec '[ '("A",Int), '("B",Int), '("C",Int) ]

 getC :: MyRec -> Int
 getC = getField (Proxy::Proxy '("C",Int))

 doubleC :: MyRec -> MyRec
 doubleC r = setC (2 * (getC r)) r
   where setC = set . (Field :: Int -> Field '("C",Int))

 main :: IO ()
 main = print (getC (Field 1 :& Field 2 :& Field 3 :& Nil :: MyRec))
 }}}

 If the `doubleC` definition is present, the Core emitted (with `-O2`)
 includes an `HEq_sc` case in the RHS of `getC`. If `doubleC` is commented
 out, that `case HEq_sc ...` is no longer present. In this example, the
 offending piece of Core is,

 {{{
 case HEq_sc
        @ Nat
        @ Nat
        @ (Index '("C", Int) '['("B", Int), '("C", Int)])
        @ ('S 'Z)
        ($s$fHasFieldkr:S_$s$fHasFieldkr:S_$cp1HasField
         `cast` (N:~[0] <Nat>_N <Index
                                   '("C", Int) '['("B", Int), '("C",
 Int)]>_N <'S 'Z>_N
                 :: ((Index '("C", Int) '['("B", Int), '("C", Int)] :: Nat)
                     ~
                     ('S 'Z :: Nat) :: Constraint)
                    ~R#
                    ((Index '("C", Int) '['("B", Int), '("C", Int)] :: Nat)
                     ~~
                     ('S 'Z :: Nat) :: Constraint)))
 of cobox1 { __DEFAULT ->
 }}}

 If the contents of `Rec.hs` are included in `Main.hs`, the `case HEq_sc
 ...` is not present in the resulting Core.

 The result of what looks like a failure to normalize the `Index` type
 family (or `RIndex` in `vinyl`) manifests as a 2x slowdown in the
 benchmark available in the `vinyl` repository.

--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/13025>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler


More information about the ghc-tickets mailing list