[commit: ghc] master: Make generated Ord instances smaller (per #10858). (4ff4929)

git at git.haskell.org git at git.haskell.org
Mon Sep 5 19:29:26 UTC 2016


Repository : ssh://git@git.haskell.org/ghc

On branch  : master
Link       : http://ghc.haskell.org/trac/ghc/changeset/4ff4929cbaab21a3ca867abbc1bd24ff3287a16f/ghc

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

commit 4ff4929cbaab21a3ca867abbc1bd24ff3287a16f
Author: Petr Prokhorenkov <prokhorenkov at gmail.com>
Date:   Sun Sep 4 13:23:19 2016 -0400

    Make generated Ord instances smaller (per #10858).
    
    Reviewers: simonpj, bgamari, RyanGlScott, austin
    
    Reviewed By: simonpj
    
    Subscribers: nomeata, simonpj, thomie
    
    Differential Revision: https://phabricator.haskell.org/D2502
    
    GHC Trac Issues: #10858


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

4ff4929cbaab21a3ca867abbc1bd24ff3287a16f
 compiler/typecheck/TcGenDeriv.hs                   | 26 +++++++++++++++++-----
 .../should_compile => deriving/perf}/Makefile      |  0
 testsuite/tests/deriving/perf/T10858.hs            | 10 +++++++++
 .../tests/deriving/perf/T10858.stdout              |  0
 testsuite/tests/deriving/perf/all.T                |  7 ++++++
 5 files changed, 38 insertions(+), 5 deletions(-)

diff --git a/compiler/typecheck/TcGenDeriv.hs b/compiler/typecheck/TcGenDeriv.hs
index f282733..f378172 100644
--- a/compiler/typecheck/TcGenDeriv.hs
+++ b/compiler/typecheck/TcGenDeriv.hs
@@ -329,7 +329,7 @@ Several special cases:
   values we can't call the overloaded functions.
   See function unliftedOrdOp
 
-Note [Do not rely on compare]
+Note [Game plan for deriving Ord]
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 It's a bad idea to define only 'compare', and build the other binary
 comparisons on top of it; see Trac #2130, #4019.  Reason: we don't
@@ -341,8 +341,16 @@ binary result, something like this:
                                        True  -> False
                                        False -> True
 
+This being said, we can get away with generating full code only for
+'compare' and '<' thus saving us generation of other three operators.
+Other operators can be cheaply expressed through '<':
+a <= b = not $ b < a
+a > b = b < a
+a >= b = not $ a < b
+
 So for sufficiently small types (few constructors, or all nullary)
 we generate all methods; for large ones we just use 'compare'.
+
 -}
 
 data OrdOp = OrdCompare | OrdLT | OrdLE | OrdGE | OrdGT
@@ -395,13 +403,21 @@ gen_Ord_binds loc tycon
     aux_binds | single_con_type = emptyBag
               | otherwise       = unitBag $ DerivAuxBind $ DerivCon2Tag tycon
 
-        -- Note [Do not rely on compare]
+        -- Note [Game plan for deriving Ord]
     other_ops | (last_tag - first_tag) <= 2     -- 1-3 constructors
                 || null non_nullary_cons        -- Or it's an enumeration
-              = listToBag (map mkOrdOp [OrdLT,OrdLE,OrdGE,OrdGT])
+              = listToBag [mkOrdOp OrdLT, lE, gT, gE]
               | otherwise
               = emptyBag
 
+    negate_expr = nlHsApp (nlHsVar not_RDR)
+    lE = mk_easy_FunBind loc le_RDR [a_Pat, b_Pat] $
+        negate_expr (nlHsApp (nlHsApp (nlHsVar lt_RDR) b_Expr) a_Expr)
+    gT = mk_easy_FunBind loc gt_RDR [a_Pat, b_Pat] $
+        nlHsApp (nlHsApp (nlHsVar lt_RDR) b_Expr) a_Expr
+    gE = mk_easy_FunBind loc ge_RDR [a_Pat, b_Pat] $
+        negate_expr (nlHsApp (nlHsApp (nlHsVar lt_RDR) a_Expr) b_Expr)
+
     get_tag con = dataConTag con - fIRST_TAG
         -- We want *zero-based* tags, because that's what
         -- con2Tag returns (generated by untag_Expr)!
@@ -2622,11 +2638,11 @@ as_RDRs         = [ mkVarUnqual (mkFastString ("a"++show i)) | i <- [(1::Int) ..
 bs_RDRs         = [ mkVarUnqual (mkFastString ("b"++show i)) | i <- [(1::Int) .. ] ]
 cs_RDRs         = [ mkVarUnqual (mkFastString ("c"++show i)) | i <- [(1::Int) .. ] ]
 
-a_Expr, c_Expr, f_Expr, z_Expr, ltTag_Expr, eqTag_Expr, gtTag_Expr,
+a_Expr, b_Expr, c_Expr, f_Expr, z_Expr, ltTag_Expr, eqTag_Expr, gtTag_Expr,
     false_Expr, true_Expr, fmap_Expr,
     mempty_Expr, foldMap_Expr, traverse_Expr :: LHsExpr RdrName
 a_Expr          = nlHsVar a_RDR
--- b_Expr       = nlHsVar b_RDR
+b_Expr          = nlHsVar b_RDR
 c_Expr          = nlHsVar c_RDR
 f_Expr          = nlHsVar f_RDR
 z_Expr          = nlHsVar z_RDR
diff --git a/testsuite/tests/annotations/should_compile/Makefile b/testsuite/tests/deriving/perf/Makefile
similarity index 100%
copy from testsuite/tests/annotations/should_compile/Makefile
copy to testsuite/tests/deriving/perf/Makefile
diff --git a/testsuite/tests/deriving/perf/T10858.hs b/testsuite/tests/deriving/perf/T10858.hs
new file mode 100644
index 0000000..b4eb7e8
--- /dev/null
+++ b/testsuite/tests/deriving/perf/T10858.hs
@@ -0,0 +1,10 @@
+{-# LANGUAGE MagicHash #-}
+
+import GHC.Prim
+
+data TestData = First Int Double String Int Int Int Int
+              | Second Char# Int# Word# Double#
+              | Third TestData TestData TestData TestData
+              deriving (Eq, Ord)
+
+main = return ()
diff --git a/libraries/base/tests/IO/encoding003.stdout b/testsuite/tests/deriving/perf/T10858.stdout
similarity index 100%
copy from libraries/base/tests/IO/encoding003.stdout
copy to testsuite/tests/deriving/perf/T10858.stdout
diff --git a/testsuite/tests/deriving/perf/all.T b/testsuite/tests/deriving/perf/all.T
new file mode 100644
index 0000000..4d5996b
--- /dev/null
+++ b/testsuite/tests/deriving/perf/all.T
@@ -0,0 +1,7 @@
+test('T10858',
+     [compiler_stats_num_field('bytes allocated',
+          [ (wordsize(64), 241655120, 8) ]),
+      only_ways(['normal'])
+      ],
+     compile,
+     ['-O'])



More information about the ghc-commits mailing list