[GHC] #7450: Regression in optimisation time of functions with many patterns (6.12 to 7.4)?

GHC cvs-ghc at haskell.org
Mon Dec 24 16:39:28 CET 2012


#7450: Regression in optimisation time of functions with many patterns (6.12 to
7.4)?
-------------------------------------------+--------------------------------
  Reporter:  iustin                        |          Owner:                  
      Type:  bug                           |         Status:  new             
  Priority:  normal                        |      Milestone:                  
 Component:  Compiler                      |        Version:  7.6.1           
Resolution:                                |       Keywords:                  
        Os:  Unknown/Multiple              |   Architecture:  Unknown/Multiple
   Failure:  Compile-time performance bug  |     Difficulty:  Unknown         
  Testcase:                                |      Blockedby:                  
  Blocking:                                |        Related:                  
-------------------------------------------+--------------------------------

Comment(by simonpj):

 One reason that the derived code was big was this. The derived `Read` code
 has lots of this
 {{{
    do { ...
       ; Ident "foo" <- lexP
       ; Punc "=" <- lexP
       ;  ...
 }}}
 Each of these failable pattern matches generates a case expression with a
 call to `error` and an error string.  This is very wasteful.  Better
 instead to define in `GHC.Read`:
 {{{
   expectP :: L.Lexeme -> ReadPrec ()
 }}}
 and use it thus
 {{{
    do { ...
       ; expectP (Ident "foo")
       ; expectP (Punc "=")
       ;  ...
 }}}
 This makes the code significantly shorter.  Without -O, and 200
 constructors, the compiler itself allocates half as much as before.

 This may or may not address the non-linearity, but it certainly improves
 `Read` instances.
 {{{
 commit 52e43004f63276c1342933e40a673ad25cf2113a
 Author: Simon Peyton Jones <simonpj at microsoft.com>
 Date:   Fri Dec 21 17:39:33 2012 +0000

     Use expectP in deriving( Read )

     Note [Use expectP]   in TcGenDeriv
     ~~~~~~~~~~~~~~~~~~
     Note that we use
        expectP (Ident "T1")
     rather than
        Ident "T1" <- lexP
     The latter desugares to inline code for matching the Ident and the
     string, and this can be very voluminous. The former is much more
     compact.  Cf Trac #7258, although that also concerned non-linearity in
     the occurrence analyser, a separate issue.
 }}}
 There is an accompanying patch to `base`:
 {{{
 commit d9b6b25a30bfdaefb69c29dedb30eed06ae71e61
 Author: Simon Peyton Jones <simonpj at microsoft.com>
 Date:   Fri Dec 21 17:40:08 2012 +0000

     Define GHC.Read.expectP and Text.Read.Lex.expect

     They are now used by TcGenDeriv

 >---------------------------------------------------------------

  GHC/Read.lhs     |   29 ++++++++++++++++-------------
  Text/Read/Lex.hs |    7 ++++++-
  2 files changed, 22 insertions(+), 14 deletions(-)

 diff --git a/GHC/Read.lhs b/GHC/Read.lhs index c5024fc..c542274 100644
 --- a/GHC/Read.lhs
 +++ b/GHC/Read.lhs
 @@ -32,7 +32,7 @@ module GHC.Read
    , lexDigits

    -- defining readers
 -  , lexP
 +  , lexP, expectP
    , paren
    , parens
    , list
 @@ -270,12 +270,15 @@ lexP :: ReadPrec L.Lexeme
  -- ^ Parse a single lexeme
  lexP = lift L.lex

 +expectP :: L.Lexeme -> ReadPrec ()
 +expectP lexeme = lift (L.expect lexeme)
 +
  paren :: ReadPrec a -> ReadPrec a
  -- ^ @(paren p)@ parses \"(P0)\"
  --      where @p@ parses \"P0\" in precedence context zero
 -paren p = do L.Punc "(" <- lexP
 -             x          <- reset p
 -             L.Punc ")" <- lexP
 +paren p = do expectP (L.Punc "(")
 +             x <- reset p
 +             expectP (L.Punc ")")
               return x

  parens :: ReadPrec a -> ReadPrec a
 @@ -292,7 +295,7 @@ list :: ReadPrec a -> ReadPrec [a]
  -- using the usual square-bracket syntax.
  list readx =
    parens
 -  ( do L.Punc "[" <- lexP
 +  ( do expectP (L.Punc "[")
         (listRest False +++ listNext)
    )
   where
 @@ -408,12 +411,12 @@ parenthesis-like objects such as (...) and [...] can
 be an argument to  instance Read a => Read (Maybe a) where
    readPrec =
      parens
 -    (do L.Ident "Nothing" <- lexP
 +    (do expectP (L.Ident "Nothing")
          return Nothing
       +++
       prec appPrec (
 -        do L.Ident "Just" <- lexP
 -           x              <- step readPrec
 +        do expectP (L.Ident "Just")
 +           x <- step readPrec
             return (Just x))
      )

 @@ -427,7 +430,7 @@ instance Read a => Read [a] where

  instance  (Ix a, Read a, Read b) => Read (Array a b)  where
      readPrec = parens $ prec appPrec $
 -               do L.Ident "array" <- lexP
 +               do expectP (L.Ident "array")
                    theBounds <- step readPrec
                    vals   <- step readPrec
                    return (array theBounds vals) @@ -504,9 +507,9 @@
 instance (Integral a, Read a) => Read (Ratio a) where
    readPrec =
      parens
      ( prec ratioPrec
 -      ( do x            <- step readPrec
 -           L.Symbol "%" <- lexP
 -           y            <- step readPrec
 +      ( do x <- step readPrec
 +           expectP (L.Symbol "%")
 +           y <- step readPrec
             return (x % y)
        )
      )
 @@ -543,7 +546,7 @@ wrap_tup :: ReadPrec a -> ReadPrec a  wrap_tup p =
 parens (paren p)

  read_comma :: ReadPrec ()
 -read_comma = do { L.Punc "," <- lexP; return () }
 +read_comma = expectP (L.Punc ",")

  read_tup2 :: (Read a, Read b) => ReadPrec (a,b)
  -- Reads "a , b"  no parens!
 diff --git a/Text/Read/Lex.hs b/Text/Read/Lex.hs index f5a07f1..8a64e21
 100644
 --- a/Text/Read/Lex.hs
 +++ b/Text/Read/Lex.hs
 @@ -22,7 +22,7 @@ module Text.Read.Lex
    , numberToInteger, numberToRational, numberToRangedRational

    -- lexer
 -  , lex
 +  , lex, expect
    , hsLex
    , lexChar

 @@ -144,6 +144,11 @@ numberToRational (MkDecimal iPart mFPart mExp)  lex
 :: ReadP Lexeme  lex = skipSpaces >> lexToken

 +expect :: Lexeme -> ReadP ()
 +expect lexeme = do { skipSpaces
 +                   ; thing <- lexToken
 +                   ; if thing == lexeme then return () else pfail }
 +
  hsLex :: ReadP String
  -- ^ Haskell lexer: returns the lexed string, rather than the lexeme
 hsLex = do skipSpaces
 }}}

-- 
Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/7450#comment:5>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler



More information about the Glasgow-haskell-bugs mailing list