diff options
author | Sylvain Henry <sylvain@haskus.fr> | 2021-02-15 13:52:46 +0100 |
---|---|---|
committer | Marge Bot <ben+marge-bot@smart-cactus.org> | 2021-02-28 06:10:42 -0500 |
commit | 72c0e07869a4652399e669e529f1bfd456522ee0 (patch) | |
tree | 9a8eb57953e717e5987e061c70d0b5d06d6a398f | |
parent | d262edad33dfc21e0eee5c7b18d232b93d8922cf (diff) | |
download | haskell-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.hs | 13 | ||||
-rw-r--r-- | compiler/GHC/Types/Name.hs | 60 |
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, |