[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