summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSylvain Henry <sylvain@haskus.fr>2021-02-15 13:52:46 +0100
committerMarge Bot <ben+marge-bot@smart-cactus.org>2021-02-28 06:10:42 -0500
commit72c0e07869a4652399e669e529f1bfd456522ee0 (patch)
tree9a8eb57953e717e5987e061c70d0b5d06d6a398f
parentd262edad33dfc21e0eee5c7b18d232b93d8922cf (diff)
downloadhaskell-72c0e07869a4652399e669e529f1bfd456522ee0.tar.gz
Make known names simple ConApps (#19386)
While fixing #17336 we noticed that code like this: = if | tc == intTyConName -> ... | tc == int8TyConName -> ... | tc == int16TyConName -> ... | tc == int32TyConName -> ... | tc == int64TyConName -> ... | tc == wordTyConName -> ... | tc == word8TyConName -> ... | tc == word16TyConName -> ... | tc == word32TyConName -> ... | tc == word64TyConName -> ... | tc == naturalTyConName -> ... was not transformed into a single case expression on the Name's unique as I would have expected but as a linear search. Bindings for known names are not simple constructor applications because of their strict `n_occ :: !OccName` field that needs to allocate a `FastString`: this field needs to be forced before using the `n_unique` field. This patch partially reverses ccaf7b66fc79e464b4e26f4ae62cb92ef7ba4b0f by making `n_occ` lazy and by ensuring that helper functions used to declare known names are fully inlined. The code above is then optimised as expected. Baseline Test Metric value New value Change --------------------------------------------------------------------------- ManyAlternatives(normal) ghc/alloc 822810880.0 822104032.0 -0.1% ManyConstructors(normal) ghc/alloc 4551734924.0 4480621808.0 -1.6% MultiLayerModules(normal) ghc/alloc 6029108292.0 6016024464.0 -0.2% Naperian(optasm) ghc/alloc 57396600.0 56826184.0 -1.0% PmSeriesG(normal) ghc/alloc 55666656.0 54521840.0 -2.1% PmSeriesS(normal) ghc/alloc 70204344.0 69047328.0 -1.6% PmSeriesT(normal) ghc/alloc 102273172.0 101070016.0 -1.2% PmSeriesV(normal) ghc/alloc 69157156.0 68002176.0 -1.7% T10421(normal) ghc/alloc 129875476.0 128881544.0 -0.8% T10421a(normal) ghc/alloc 92031552.0 90982800.0 -1.1% T10547(normal) ghc/alloc 34399800.0 33016760.0 -4.0% GOOD T10858(normal) ghc/alloc 208316964.0 207318616.0 -0.5% T11195(normal) ghc/alloc 304100548.0 302797040.0 -0.4% T11276(normal) ghc/alloc 140586764.0 139469832.0 -0.8% T11303b(normal) ghc/alloc 52118960.0 51120248.0 -1.9% T11374(normal) ghc/alloc 241325868.0 240692752.0 -0.3% T11822(normal) ghc/alloc 150612036.0 149582736.0 -0.7% T12150(optasm) ghc/alloc 92738452.0 91897224.0 -0.9% T12227(normal) ghc/alloc 494236296.0 493086728.0 -0.2% T12234(optasm) ghc/alloc 66786816.0 65966096.0 -1.2% T12425(optasm) ghc/alloc 112396704.0 111471016.0 -0.8% T12545(normal) ghc/alloc 1832733768.0 1828021072.0 -0.3% T12707(normal) ghc/alloc 1054991144.0 1053359696.0 -0.2% T13035(normal) ghc/alloc 116173180.0 115112072.0 -0.9% T13056(optasm) ghc/alloc 391749192.0 390687864.0 -0.3% T13253(normal) ghc/alloc 382785700.0 381550592.0 -0.3% T13253-spj(normal) ghc/alloc 168806064.0 167987192.0 -0.5% T13379(normal) ghc/alloc 403890296.0 402447920.0 -0.4% T13701(normal) ghc/alloc 2542828108.0 2534392736.0 -0.3% T13719(normal) ghc/alloc 4666717708.0 4659489416.0 -0.2% T14052(ghci) ghc/alloc 2181268580.0 2175320640.0 -0.3% T14683(normal) ghc/alloc 3094166824.0 3094524216.0 +0.0% T14697(normal) ghc/alloc 376323432.0 374024184.0 -0.6% T15164(normal) ghc/alloc 1896324828.0 1893236528.0 -0.2% T15630(normal) ghc/alloc 198932800.0 197783656.0 -0.6% T16190(normal) ghc/alloc 288186840.0 287250024.0 -0.3% T16577(normal) ghc/alloc 8324100940.0 8321580600.0 -0.0% T17096(normal) ghc/alloc 318264420.0 316961792.0 -0.4% T17516(normal) ghc/alloc 1332680768.0 1331635504.0 -0.1% T17836(normal) ghc/alloc 1296308168.0 1291098504.0 -0.4% T17836b(normal) ghc/alloc 62008340.0 60745256.0 -2.0% T17977(normal) ghc/alloc 52954564.0 51890248.0 -2.0% T17977b(normal) ghc/alloc 47824016.0 46683936.0 -2.4% T18140(normal) ghc/alloc 117408932.0 116353672.0 -0.9% T18223(normal) ghc/alloc 5603767896.0 5602037104.0 -0.0% T18282(normal) ghc/alloc 166456808.0 165396320.0 -0.6% T18304(normal) ghc/alloc 103694052.0 103513136.0 -0.2% T18478(normal) ghc/alloc 816819336.0 814459560.0 -0.3% T18698a(normal) ghc/alloc 438652404.0 437041784.0 -0.4% T18698b(normal) ghc/alloc 529448324.0 527666608.0 -0.3% T18923(normal) ghc/alloc 78360824.0 77315560.0 -1.3% T1969(normal) ghc/alloc 854223208.0 851303488.0 -0.3% T3064(normal) ghc/alloc 200655808.0 199368872.0 -0.6% T3294(normal) ghc/alloc 1791121792.0 1790033888.0 -0.1% T4801(normal) ghc/alloc 343749816.0 341760680.0 -0.6% T5030(normal) ghc/alloc 377520872.0 376492360.0 -0.3% T5321FD(normal) ghc/alloc 312680408.0 311618536.0 -0.3% T5321Fun(normal) ghc/alloc 355635656.0 354536264.0 -0.3% T5631(normal) ghc/alloc 629667068.0 629562192.0 -0.0% T5642(normal) ghc/alloc 540913864.0 539569952.0 -0.2% T5837(normal) ghc/alloc 43183652.0 42177928.0 -2.3% T6048(optasm) ghc/alloc 96395616.0 95397032.0 -1.0% T783(normal) ghc/alloc 427778908.0 426307760.0 -0.3% T9020(optasm) ghc/alloc 279523960.0 277010040.0 -0.9% T9233(normal) ghc/alloc 966717488.0 964594096.0 -0.2% T9630(normal) ghc/alloc 1585228636.0 1581428672.0 -0.2% T9675(optasm) ghc/alloc 594817892.0 591703040.0 -0.5% T9872a(normal) ghc/alloc 2216955420.0 2215648024.0 -0.1% T9872b(normal) ghc/alloc 2747814924.0 2746515472.0 -0.0% T9872c(normal) ghc/alloc 2271878772.0 2270554344.0 -0.1% T9872d(normal) ghc/alloc 623661168.0 621434064.0 -0.4% T9961(normal) ghc/alloc 409059124.0 406811120.0 -0.5% WWRec(normal) ghc/alloc 940563924.0 938008112.0 -0.3% hie002(normal) ghc/alloc 9801941116.0 9787675736.0 -0.1% parsing001(normal) ghc/alloc 494756632.0 493828512.0 -0.2% Metric Decrease: T10547 T13035 T12425
-rw-r--r--compiler/GHC/Builtin/Names.hs13
-rw-r--r--compiler/GHC/Types/Name.hs60
2 files changed, 60 insertions, 13 deletions
diff --git a/compiler/GHC/Builtin/Names.hs b/compiler/GHC/Builtin/Names.hs
index 563ccbf57e..40af981264 100644
--- a/compiler/GHC/Builtin/Names.hs
+++ b/compiler/GHC/Builtin/Names.hs
@@ -1701,13 +1701,18 @@ fingerprintDataConName =
All these are original names; hence mkOrig
-}
+{-# INLINE varQual #-}
+{-# INLINE tcQual #-}
+{-# INLINE clsQual #-}
+{-# INLINE dcQual #-}
varQual, tcQual, clsQual, dcQual :: Module -> FastString -> Unique -> Name
-varQual = mk_known_key_name varName
-tcQual = mk_known_key_name tcName
-clsQual = mk_known_key_name clsName
-dcQual = mk_known_key_name dataName
+varQual modu str unique = mk_known_key_name varName modu str unique
+tcQual modu str unique = mk_known_key_name tcName modu str unique
+clsQual modu str unique = mk_known_key_name clsName modu str unique
+dcQual modu str unique = mk_known_key_name dataName modu str unique
mk_known_key_name :: NameSpace -> Module -> FastString -> Unique -> Name
+{-# INLINE mk_known_key_name #-}
mk_known_key_name space modu str unique
= mkExternalName unique modu (mkOccNameFS space str) noSrcSpan
diff --git a/compiler/GHC/Types/Name.hs b/compiler/GHC/Types/Name.hs
index 0b834cbe2b..c2b76b1bfd 100644
--- a/compiler/GHC/Types/Name.hs
+++ b/compiler/GHC/Types/Name.hs
@@ -109,16 +109,26 @@ import Data.Data
-- | A unique, unambiguous name for something, containing information about where
-- that thing originated.
-data Name = Name {
- n_sort :: NameSort, -- What sort of name it is
- n_occ :: !OccName, -- Its occurrence name
- n_uniq :: {-# UNPACK #-} !Unique,
- n_loc :: !SrcSpan -- Definition site
- }
+data Name = Name
+ { n_sort :: NameSort
+ -- ^ What sort of name it is
--- NOTE: we make the n_loc field strict to eliminate some potential
--- (and real!) space leaks, due to the fact that we don't look at
--- the SrcLoc in a Name all that often.
+ , n_occ :: OccName
+ -- ^ Its occurrence name.
+ --
+ -- NOTE: kept lazy to allow known names to be known constructor applications
+ -- and to inline better. See Note [Fast comparison for built-in Names]
+
+ , n_uniq :: {-# UNPACK #-} !Unique
+ -- ^ Its unique.
+
+ , n_loc :: !SrcSpan
+ -- ^ Definition site
+ --
+ -- NOTE: we make the n_loc field strict to eliminate some potential
+ -- (and real!) space leaks, due to the fact that we don't look at
+ -- the SrcLoc in a Name all that often.
+ }
-- See Note [About the NameSorts]
data NameSort
@@ -157,6 +167,36 @@ instance NFData NameSort where
data BuiltInSyntax = BuiltInSyntax | UserSyntax
{-
+Note [Fast comparison for built-in Names]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Consider this wired-in Name in GHC.Builtin.Names:
+
+ int8TyConName = tcQual gHC_INT (fsLit "Int8") int8TyConKey
+
+Ultimately this turns into something like:
+
+ int8TyConName = Name gHC_INT (mkOccName ..."Int8") int8TyConKey
+
+So a comparison like `x == int8TyConName` will turn into `getUnique x ==
+int8TyConKey`, nice and efficient. But if the `n_occ` field is strict, that
+definition will look like:
+
+ int8TyCOnName = case (mkOccName..."Int8") of occ ->
+ Name gHC_INT occ int8TyConKey
+
+and now the comparison will not optimise. This matters even more when there are
+numerous comparisons (see #19386):
+
+if | tc == int8TyCon -> ...
+ | tc == int16TyCon -> ...
+ ...etc...
+
+when we would like to get a single multi-branched case.
+
+TL;DR: we make the `n_occ` field lazy.
+-}
+
+{-
Note [About the NameSorts]
1. Initially, top-level Ids (including locally-defined ones) get External names,
@@ -401,6 +441,7 @@ mkDerivedInternalName derive_occ uniq (Name { n_occ = occ, n_loc = loc })
-- | Create a name which definitely originates in the given module
mkExternalName :: Unique -> Module -> OccName -> SrcSpan -> Name
+{-# INLINE mkExternalName #-}
-- WATCH OUT! External Names should be in the Name Cache
-- (see Note [The Name Cache] in GHC.Iface.Env), so don't just call mkExternalName
-- with some fresh unique without populating the Name Cache
@@ -410,6 +451,7 @@ mkExternalName uniq mod occ loc
-- | Create a name which is actually defined by the compiler itself
mkWiredInName :: Module -> OccName -> Unique -> TyThing -> BuiltInSyntax -> Name
+{-# INLINE mkWiredInName #-}
mkWiredInName mod occ uniq thing built_in
= Name { n_uniq = uniq,
n_sort = WiredIn mod thing built_in,