diff options
author | Krzysztof Gogolewski <krzysztof.gogolewski@tweag.io> | 2020-06-15 19:59:46 +0200 |
---|---|---|
committer | Ben Gamari <ben@smart-cactus.org> | 2020-06-17 16:22:03 -0400 |
commit | 6cb84c469bf1ab6b03e099f5d100e78800ca09e0 (patch) | |
tree | 5dd883d7fd637093b60b7a62ecdb58389873bb0f /compiler/GHC/Core/TyCo | |
parent | 40fa237e1daab7a76b9871bb6c50b953a1addf23 (diff) | |
download | haskell-6cb84c469bf1ab6b03e099f5d100e78800ca09e0.tar.gz |
Various performance improvements
This implements several general performance improvements to GHC,
to offset the effect of the linear types change.
General optimisations:
- Add a `coreFullView` function which iterates `coreView` on the
head. This avoids making function recursive solely because the
iterate `coreView` themselves. As a consequence, this functions can
be inlined, and trigger case-of-known constructor (_e.g._
`kindRep_maybe`, `isLiftedRuntimeRep`, `isMultiplicityTy`,
`getTyVar_maybe`, `splitAppTy_maybe`, `splitFunType_maybe`,
`tyConAppTyCon_maybe`). The common pattern about all these functions
is that they are almost always used as views, and immediately
consumed by a case expression. This commit also mark them asx `INLINE`.
- In `subst_ty` add a special case for nullary `TyConApp`, which avoid
allocations altogether.
- Use `mkTyConApp` in `subst_ty` for the general `TyConApp`. This
required quite a bit of module shuffling.
case. `myTyConApp` enforces crucial sharing, which was lost during
substitution. See also !2952 .
- Make `subst_ty` stricter.
- In `eqType` (specifically, in `nonDetCmpType`), add a special case,
tested first, for the very common case of nullary `TyConApp`.
`nonDetCmpType` has been made `INLINE` otherwise it is actually a
regression. This is similar to the optimisations in !2952.
Linear-type specific optimisations:
- Use `tyConAppTyCon_maybe` instead of the more complex `eqType` in
the definition of the pattern synonyms `One` and `Many`.
- Break the `hs-boot` cycles between `Multiplicity.hs` and `Type.hs`:
`Multiplicity` now import `Type` normally, rather than from the
`hs-boot`. This way `tyConAppTyCon_maybe` can inline properly in the
`One` and `Many` pattern synonyms.
- Make `updateIdTypeAndMult` strict in its type and multiplicity
- The `scaleIdBy` gets a specialised definition rather than being an
alias to `scaleVarBy`
- `splitFunTy_maybe` is given the type `Type -> Maybe (Mult, Type,
Type)` instead of `Type -> Maybe (Scaled Type, Type)`
- Remove the `MultMul` pattern synonym in favour of a view `isMultMul`
because pattern synonyms appear not to inline well.
- in `eqType`, in a `FunTy`, compare multiplicities last: they are
almost always both `Many`, so it helps failing faster.
- Cache `manyDataConTy` in `mkTyConApp`, to make sure that all the
instances of `TyConApp ManyDataConTy []` are physically the same.
This commit has been authored by
* Richard Eisenberg
* Krzysztof Gogolewski
* Arnaud Spiwack
Metric Decrease:
haddock.base
T12227
T12545
T12990
T1969
T3064
T5030
T9872b
Metric Increase:
haddock.base
haddock.Cabal
haddock.compiler
T12150
T12234
T12425
T12707
T13035
T13056
T15164
T16190
T18304
T1969
T3064
T3294
T5631
T5642
T5837
T6048
T9020
T9233
T9675
T9872a
T9961
WWRec
Diffstat (limited to 'compiler/GHC/Core/TyCo')
-rw-r--r-- | compiler/GHC/Core/TyCo/Ppr.hs | 6 | ||||
-rw-r--r-- | compiler/GHC/Core/TyCo/Ppr.hs-boot | 5 | ||||
-rw-r--r-- | compiler/GHC/Core/TyCo/Rep.hs | 120 | ||||
-rw-r--r-- | compiler/GHC/Core/TyCo/Rep.hs-boot | 3 | ||||
-rw-r--r-- | compiler/GHC/Core/TyCo/Subst.hs | 14 | ||||
-rw-r--r-- | compiler/GHC/Core/TyCo/Tidy.hs | 4 |
6 files changed, 130 insertions, 22 deletions
diff --git a/compiler/GHC/Core/TyCo/Ppr.hs b/compiler/GHC/Core/TyCo/Ppr.hs index c6bf57e6d2..44899be2ac 100644 --- a/compiler/GHC/Core/TyCo/Ppr.hs +++ b/compiler/GHC/Core/TyCo/Ppr.hs @@ -1,3 +1,5 @@ +{-# LANGUAGE PatternSynonyms #-} + -- | Pretty-printing types and coercions. module GHC.Core.TyCo.Ppr ( @@ -34,10 +36,8 @@ import {-# SOURCE #-} GHC.CoreToIface import {-# SOURCE #-} GHC.Core.DataCon ( dataConFullSig , dataConUserTyVarBinders , DataCon ) -import GHC.Core.Multiplicity -import {-# SOURCE #-} GHC.Core.Type - ( isLiftedTypeKind ) +import GHC.Core.Type ( isLiftedTypeKind, pattern One, pattern Many ) import GHC.Core.TyCon import GHC.Core.TyCo.Rep diff --git a/compiler/GHC/Core/TyCo/Ppr.hs-boot b/compiler/GHC/Core/TyCo/Ppr.hs-boot index 8e89c334ea..2b1a787f1f 100644 --- a/compiler/GHC/Core/TyCo/Ppr.hs-boot +++ b/compiler/GHC/Core/TyCo/Ppr.hs-boot @@ -1,10 +1,11 @@ module GHC.Core.TyCo.Ppr where +import {-# SOURCE #-} GHC.Types.Var ( TyVar ) import {-# SOURCE #-} GHC.Core.TyCo.Rep (Type, Kind, Coercion, TyLit) -import GHC.Utils.Outputable +import GHC.Utils.Outputable ( SDoc ) pprType :: Type -> SDoc pprKind :: Kind -> SDoc pprCo :: Coercion -> SDoc pprTyLit :: TyLit -> SDoc - +pprTyVar :: TyVar -> SDoc diff --git a/compiler/GHC/Core/TyCo/Rep.hs b/compiler/GHC/Core/TyCo/Rep.hs index e201dcfea3..e72284477a 100644 --- a/compiler/GHC/Core/TyCo/Rep.hs +++ b/compiler/GHC/Core/TyCo/Rep.hs @@ -25,10 +25,7 @@ module GHC.Core.TyCo.Rep ( TyThing(..), tyThingCategory, pprTyThingCategory, pprShortTyThing, -- * Types - Type( TyVarTy, AppTy, TyConApp, ForAllTy - , LitTy, CastTy, CoercionTy - , FunTy, ft_mult, ft_arg, ft_res, ft_af - ), -- Export the type synonym FunTy too + Type(..), TyLit(..), KindOrType, Kind, @@ -53,6 +50,7 @@ module GHC.Core.TyCo.Rep ( mkScaledFunTy, mkVisFunTyMany, mkVisFunTysMany, mkInvisFunTyMany, mkInvisFunTysMany, + mkTyConApp, -- * Functions over binders TyCoBinder(..), TyCoVarBinder, TyBinder, @@ -69,7 +67,10 @@ module GHC.Core.TyCo.Rep ( TyCoFolder(..), foldTyCo, -- * Sizes - typeSize, coercionSize, provSize + typeSize, coercionSize, provSize, + + -- * Multiplicities + Scaled(..), scaledMult, scaledThing, mapScaledType, Mult ) where #include "HsVersions.h" @@ -87,12 +88,14 @@ import GHC.Iface.Type import GHC.Types.Var import GHC.Types.Var.Set import GHC.Types.Name hiding ( varName ) -import GHC.Core.Multiplicity import GHC.Core.TyCon import GHC.Core.Coercion.Axiom -- others +import GHC.Builtin.Names ( liftedTypeKindTyConKey, manyDataConKey ) +import {-# SOURCE #-} GHC.Builtin.Types ( liftedTypeKindTyCon, manyDataConTy ) import GHC.Types.Basic ( LeftOrRight(..), pickLR ) +import GHC.Types.Unique ( hasKey ) import GHC.Utils.Outputable import GHC.Data.FastString import GHC.Utils.Misc @@ -1003,14 +1006,14 @@ mkVisFunTy = mkFunTy VisArg mkInvisFunTy = mkFunTy InvisArg mkFunTyMany :: AnonArgFlag -> Type -> Type -> Type -mkFunTyMany af = mkFunTy af Many +mkFunTyMany af = mkFunTy af manyDataConTy -- | Special, common, case: Arrow type with mult Many mkVisFunTyMany :: Type -> Type -> Type -mkVisFunTyMany = mkVisFunTy Many +mkVisFunTyMany = mkVisFunTy manyDataConTy mkInvisFunTyMany :: Type -> Type -> Type -mkInvisFunTyMany = mkInvisFunTy Many +mkInvisFunTyMany = mkInvisFunTy manyDataConTy -- | Make nested arrow types mkVisFunTys :: [Scaled Type] -> Type -> Type @@ -1046,6 +1049,58 @@ mkPiTys tbs ty = foldr mkPiTy ty tbs mkTyConTy :: TyCon -> Type mkTyConTy tycon = TyConApp tycon [] +-- | A key function: builds a 'TyConApp' or 'FunTy' as appropriate to +-- its arguments. Applies its arguments to the constructor from left to right. +mkTyConApp :: TyCon -> [Type] -> Type +mkTyConApp tycon tys + | isFunTyCon tycon + , [w, _rep1,_rep2,ty1,ty2] <- tys + -- The FunTyCon (->) is always a visible one + = FunTy { ft_af = VisArg, ft_mult = w, ft_arg = ty1, ft_res = ty2 } + + -- Note [mkTyConApp and Type] + | tycon `hasKey` liftedTypeKindTyConKey + = ASSERT2( null tys, ppr tycon $$ ppr tys ) + liftedTypeKindTyConApp + | tycon `hasKey` manyDataConKey + -- There are a lot of occurrences of 'Many' so it's a small optimisation to + -- avoid reboxing every time `mkTyConApp` is called. + = ASSERT2( null tys, ppr tycon $$ ppr tys ) + manyDataConTy + | otherwise + = TyConApp tycon tys + +-- This is a single, global definition of the type `Type` +-- Defined here so it is only allocated once. +-- See Note [mkTyConApp and Type] +liftedTypeKindTyConApp :: Type +liftedTypeKindTyConApp = TyConApp liftedTypeKindTyCon [] + +{- +Note [mkTyConApp and Type] +~~~~~~~~~~~~~~~~~~~~~~~~~~ +Whilst benchmarking it was observed in #17292 that GHC allocated a lot +of `TyConApp` constructors. Upon further inspection a large number of these +TyConApp constructors were all duplicates of `Type` applied to no arguments. + +``` +(From a sample of 100000 TyConApp closures) +0x45f3523 - 28732 - `Type` +0x420b840702 - 9629 - generic type constructors +0x42055b7e46 - 9596 +0x420559b582 - 9511 +0x420bb15a1e - 9509 +0x420b86c6ba - 9501 +0x42055bac1e - 9496 +0x45e68fd - 538 - `TYPE ...` +``` + +Therefore in `mkTyConApp` we have a special case for `Type` to ensure that +only one `TyConApp 'Type []` closure is allocated during the course of +compilation. In order to avoid a potentially expensive series of checks in +`mkTyConApp` only this egregious case is special cased at the moment. +-} + {- %************************************************************************ %* * @@ -1954,3 +2009,50 @@ provSize :: UnivCoProvenance -> Int provSize (PhantomProv co) = 1 + coercionSize co provSize (ProofIrrelProv co) = 1 + coercionSize co provSize (PluginProv _) = 1 + +{- +************************************************************************ +* * + Multiplicities +* * +************************************************************************ + +These definitions are here to avoid module loops, and to keep +GHC.Core.Multiplicity above this module. + +-} + +-- | A shorthand for data with an attached 'Mult' element (the multiplicity). +data Scaled a = Scaled Mult a + deriving (Data.Data) + +instance (Outputable a) => Outputable (Scaled a) where + ppr (Scaled _cnt t) = ppr t + -- Do not print the multiplicity here because it tends to be too verbose + +scaledMult :: Scaled a -> Mult +scaledMult (Scaled m _) = m + +scaledThing :: Scaled a -> a +scaledThing (Scaled _ t) = t + +-- | Apply a function to both the Mult and the Type in a 'Scaled Type' +mapScaledType :: (Type -> Type) -> Scaled Type -> Scaled Type +mapScaledType f (Scaled m t) = Scaled (f m) (f t) + +{- | +Mult is a type alias for Type. + +Mult must contain Type because multiplicity variables are mere type variables +(of kind Multiplicity) in Haskell. So the simplest implementation is to make +Mult be Type. + +Multiplicities can be formed with: +- One: GHC.Types.One (= oneDataCon) +- Many: GHC.Types.Many (= manyDataCon) +- Multiplication: GHC.Types.MultMul (= multMulTyCon) + +So that Mult feels a bit more structured, we provide pattern synonyms and smart +constructors for these. +-} +type Mult = Type diff --git a/compiler/GHC/Core/TyCo/Rep.hs-boot b/compiler/GHC/Core/TyCo/Rep.hs-boot index 25a22435cf..7bc1eb4f81 100644 --- a/compiler/GHC/Core/TyCo/Rep.hs-boot +++ b/compiler/GHC/Core/TyCo/Rep.hs-boot @@ -12,6 +12,9 @@ data TyLit data TyCoBinder data MCoercion +data Scaled a +type Mult = Type + type PredType = Type type Kind = Type type ThetaType = [PredType] diff --git a/compiler/GHC/Core/TyCo/Subst.hs b/compiler/GHC/Core/TyCo/Subst.hs index 88799c2414..b3f51739b5 100644 --- a/compiler/GHC/Core/TyCo/Subst.hs +++ b/compiler/GHC/Core/TyCo/Subst.hs @@ -65,11 +65,10 @@ import {-# SOURCE #-} GHC.Core.Coercion , mkInstCo, mkLRCo, mkTyConAppCo , mkCoercionType , coercionKind, coercionLKind, coVarKindsTypesRole ) +import {-# SOURCE #-} GHC.Core.TyCo.Ppr ( pprTyVar ) import GHC.Core.TyCo.Rep import GHC.Core.TyCo.FVs -import GHC.Core.TyCo.Ppr -import GHC.Core.Multiplicity import GHC.Types.Var import GHC.Types.Var.Set @@ -733,12 +732,15 @@ subst_ty subst ty = go ty where go (TyVarTy tv) = substTyVar subst tv - go (AppTy fun arg) = mkAppTy (go fun) $! (go arg) + go (AppTy fun arg) = (mkAppTy $! (go fun)) $! (go arg) -- The mkAppTy smart constructor is important -- we might be replacing (a Int), represented with App -- by [Int], represented with TyConApp - go (TyConApp tc tys) = let args = map go tys - in args `seqList` TyConApp tc args + go ty@(TyConApp tc []) = tc `seq` ty -- avoid allocation in this common case + go (TyConApp tc tys) = (mkTyConApp $! tc) $! strictMap go tys + -- NB: mkTyConApp, not TyConApp. + -- mkTyConApp has optimizations. + -- See Note [mkTyConApp and Type] in GHC.Core.TyCo.Rep go ty@(FunTy { ft_mult = mult, ft_arg = arg, ft_res = res }) = let !mult' = go mult !arg' = go arg @@ -846,7 +848,7 @@ subst_co subst co -- See Note [Substituting in a coercion hole] go_hole h@(CoercionHole { ch_co_var = cv }) - = h { ch_co_var = updateVarTypeAndMult go_ty cv } + = h { ch_co_var = updateVarType go_ty cv } substForAllCoBndr :: TCvSubst -> TyCoVar -> KindCoercion -> (TCvSubst, TyCoVar, Coercion) diff --git a/compiler/GHC/Core/TyCo/Tidy.hs b/compiler/GHC/Core/TyCo/Tidy.hs index bc586d77c8..dd07a2775f 100644 --- a/compiler/GHC/Core/TyCo/Tidy.hs +++ b/compiler/GHC/Core/TyCo/Tidy.hs @@ -52,7 +52,7 @@ tidyVarBndr tidy_env@(occ_env, subst) var (occ_env', occ') -> ((occ_env', subst'), var') where subst' = extendVarEnv subst var var' - var' = updateVarTypeAndMult (tidyType tidy_env) (setVarName var name') + var' = updateVarType (tidyType tidy_env) (setVarName var name') name' = tidyNameOcc name occ' name = varName var @@ -119,7 +119,7 @@ tidyOpenTyCoVar env@(_, subst) tyvar tidyTyCoVarOcc :: TidyEnv -> TyCoVar -> TyCoVar tidyTyCoVarOcc env@(_, subst) tv = case lookupVarEnv subst tv of - Nothing -> updateVarTypeAndMult (tidyType env) tv + Nothing -> updateVarType (tidyType env) tv Just tv' -> tv' --------------- |