diff options
author | Sebastian Graf <sebastian.graf@kit.edu> | 2020-11-30 17:08:40 +0100 |
---|---|---|
committer | Marge Bot <ben+marge-bot@smart-cactus.org> | 2020-12-23 10:21:56 -0500 |
commit | f0ec06c76ccd6797d42736fd423adbbb238723b4 (patch) | |
tree | c6eade36b2649f83df8172ac319f716c5f30ebe0 /compiler/GHC/Core/TyCon.hs | |
parent | 56841432ae4e38dabdada1a280ef0e0878e895f1 (diff) | |
download | haskell-f0ec06c76ccd6797d42736fd423adbbb238723b4.tar.gz |
WorkWrap: Unbox constructors with existentials (#18982)
Consider
```hs
data Ex where
Ex :: e -> Int -> Ex
f :: Ex -> Int
f (Ex e n) = e `seq` n + 1
```
Worker/wrapper should build the following worker for `f`:
```hs
$wf :: forall e. e -> Int# -> Int#
$wf e n = e `seq` n +# 1#
```
But previously it didn't, because `Ex` binds an existential.
This patch lifts that condition. That entailed having to instantiate
existential binders in `GHC.Core.Opt.WorkWrap.Utils.mkWWstr` via
`GHC.Core.Utils.dataConRepFSInstPat`, requiring a bit of a refactoring
around what is now `DataConPatContext`.
CPR W/W still won't unbox DataCons with existentials.
See `Note [Which types are unboxed?]` for details.
I also refactored the various `tyCon*DataCon(s)_maybe` functions in
`GHC.Core.TyCon`, deleting some of them which are no longer needed
(`isDataProductType_maybe` and `isDataSumType_maybe`).
I cleaned up a couple of call sites, some of which weren't very explicit
about whether they cared for existentials or not.
The test output of `T18013` changed, because we now unbox the `Rule`
data type. Its constructor carries existential state and will be
w/w'd now. In the particular example, the worker functions inlines right
back into the wrapper, which then unnecessarily has a (quite big) stable
unfolding. I think this kind of fallout is inevitable;
see also Note [Don't w/w inline small non-loop-breaker things].
There's a new regression test case `T18982`.
Fixes #18982.
Diffstat (limited to 'compiler/GHC/Core/TyCon.hs')
-rw-r--r-- | compiler/GHC/Core/TyCon.hs | 99 |
1 files changed, 20 insertions, 79 deletions
diff --git a/compiler/GHC/Core/TyCon.hs b/compiler/GHC/Core/TyCon.hs index a038fd646c..0cd1463b46 100644 --- a/compiler/GHC/Core/TyCon.hs +++ b/compiler/GHC/Core/TyCon.hs @@ -58,8 +58,7 @@ module GHC.Core.TyCon( isKindTyCon, isLiftedTypeKindTyConName, isTauTyCon, isFamFreeTyCon, isForgetfulSynTyCon, - isDataTyCon, isProductTyCon, isDataProductTyCon_maybe, - isDataSumTyCon_maybe, + isDataTyCon, isEnumerationTyCon, isNewTyCon, isAbstractTyCon, isFamilyTyCon, isOpenFamilyTyCon, @@ -84,6 +83,7 @@ module GHC.Core.TyCon( tyConCType, tyConCType_maybe, tyConDataCons, tyConDataCons_maybe, tyConSingleDataCon_maybe, tyConSingleDataCon, + tyConAlgDataCons_maybe, tyConSingleAlgDataCon_maybe, tyConFamilySize, tyConStupidTheta, @@ -143,7 +143,7 @@ import {-# SOURCE #-} GHC.Builtin.Types , multiplicityTyCon , vecCountTyCon, vecElemTyCon, liftedTypeKind ) import {-# SOURCE #-} GHC.Core.DataCon - ( DataCon, dataConExTyCoVars, dataConFieldLabels + ( DataCon, dataConFieldLabels , dataConTyCon, dataConFullSig , isUnboxedSumDataCon ) import GHC.Builtin.Uniques @@ -1976,72 +1976,6 @@ unwrapNewTyConEtad_maybe (AlgTyCon { algTcRhs = NewTyCon { nt_co = co, = Just (tvs, rhs, co) unwrapNewTyConEtad_maybe _ = Nothing -isProductTyCon :: TyCon -> Bool --- True of datatypes or newtypes that have --- one, non-existential, data constructor --- See Note [Product types] -isProductTyCon tc@(AlgTyCon {}) - = case algTcRhs tc of - TupleTyCon {} -> True - DataTyCon{ data_cons = [data_con] } - -> null (dataConExTyCoVars data_con) - NewTyCon {} -> True - _ -> False -isProductTyCon _ = False - -isDataProductTyCon_maybe :: TyCon -> Maybe DataCon --- True of datatypes (not newtypes) with --- one, vanilla, data constructor --- See Note [Product types] -isDataProductTyCon_maybe (AlgTyCon { algTcRhs = rhs }) - = case rhs of - DataTyCon { data_cons = [con] } - | null (dataConExTyCoVars con) -- non-existential - -> Just con - TupleTyCon { data_con = con } - -> Just con - _ -> Nothing -isDataProductTyCon_maybe _ = Nothing - -isDataSumTyCon_maybe :: TyCon -> Maybe [DataCon] -isDataSumTyCon_maybe (AlgTyCon { algTcRhs = rhs }) - = case rhs of - DataTyCon { data_cons = cons } - | cons `lengthExceeds` 1 - , all (null . dataConExTyCoVars) cons -- FIXME(osa): Why do we need this? - -> Just cons - SumTyCon { data_cons = cons } - | all (null . dataConExTyCoVars) cons -- FIXME(osa): Why do we need this? - -> Just cons - _ -> Nothing -isDataSumTyCon_maybe _ = Nothing - -{- Note [Product types] -~~~~~~~~~~~~~~~~~~~~~~~ -A product type is - * A data type (not a newtype) - * With one, boxed data constructor - * That binds no existential type variables - -The main point is that product types are amenable to unboxing for - * Strict function calls; we can transform - f (D a b) = e - to - fw a b = e - via the worker/wrapper transformation. (Question: couldn't this - work for existentials too?) - - * CPR for function results; we can transform - f x y = let ... in D a b - to - fw x y = let ... in (# a, b #) - -Note that the data constructor /can/ have evidence arguments: equality -constraints, type classes etc. So it can be GADT. These evidence -arguments are simply value arguments, and should not get in the way. --} - - -- | Is this a 'TyCon' representing a regular H98 type synonym (@type@)? {-# INLINE isTypeSynonymTyCon #-} -- See Note [Inlining coreView] in GHC.Core.Type isTypeSynonymTyCon :: TyCon -> Bool @@ -2382,8 +2316,7 @@ tyConDataCons_maybe _ = Nothing -- | If the given 'TyCon' has a /single/ data constructor, i.e. it is a @data@ -- type with one alternative, a tuple type or a @newtype@ then that constructor -- is returned. If the 'TyCon' has more than one constructor, or represents a --- primitive or function type constructor then @Nothing@ is returned. In any --- other case, the function panics +-- primitive or function type constructor then @Nothing@ is returned. tyConSingleDataCon_maybe :: TyCon -> Maybe DataCon tyConSingleDataCon_maybe (AlgTyCon { algTcRhs = rhs }) = case rhs of @@ -2393,21 +2326,29 @@ tyConSingleDataCon_maybe (AlgTyCon { algTcRhs = rhs }) _ -> Nothing tyConSingleDataCon_maybe _ = Nothing +-- | Like 'tyConSingleDataCon_maybe', but panics if 'Nothing'. tyConSingleDataCon :: TyCon -> DataCon tyConSingleDataCon tc = case tyConSingleDataCon_maybe tc of Just c -> c Nothing -> pprPanic "tyConDataCon" (ppr tc) +-- | Like 'tyConSingleDataCon_maybe', but returns 'Nothing' for newtypes. tyConSingleAlgDataCon_maybe :: TyCon -> Maybe DataCon --- Returns (Just con) for single-constructor --- *algebraic* data types *not* newtypes -tyConSingleAlgDataCon_maybe (AlgTyCon { algTcRhs = rhs }) - = case rhs of - DataTyCon { data_cons = [c] } -> Just c - TupleTyCon { data_con = c } -> Just c - _ -> Nothing -tyConSingleAlgDataCon_maybe _ = Nothing +tyConSingleAlgDataCon_maybe tycon + | isNewTyCon tycon = Nothing + | otherwise = tyConSingleDataCon_maybe tycon + +-- | Returns @Just dcs@ if the given 'TyCon' is a @data@ type, a tuple type +-- or a sum type with data constructors dcs. If the 'TyCon' has more than one +-- constructor, or represents a primitive or function type constructor then +-- @Nothing@ is returned. +-- +-- Like 'tyConDataCons_maybe', but returns 'Nothing' for newtypes. +tyConAlgDataCons_maybe :: TyCon -> Maybe [DataCon] +tyConAlgDataCons_maybe tycon + | isNewTyCon tycon = Nothing + | otherwise = tyConDataCons_maybe tycon -- | Determine the number of value constructors a 'TyCon' has. Panics if the -- 'TyCon' is not algebraic or a tuple |