summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/GHC/Core/Opt/CprAnal.hs22
-rw-r--r--compiler/GHC/Core/Opt/WorkWrap/Utils.hs126
-rw-r--r--compiler/GHC/Core/Utils.hs2
-rw-r--r--compiler/GHC/Types/Demand.hs2
4 files changed, 70 insertions, 82 deletions
diff --git a/compiler/GHC/Core/Opt/CprAnal.hs b/compiler/GHC/Core/Opt/CprAnal.hs
index ddafa72b33..6863dc1358 100644
--- a/compiler/GHC/Core/Opt/CprAnal.hs
+++ b/compiler/GHC/Core/Opt/CprAnal.hs
@@ -25,7 +25,7 @@ import GHC.Types.Id
import GHC.Types.Id.Info
import GHC.Core.DataCon
import GHC.Core.Multiplicity
-import GHC.Core.Utils ( exprIsHNF, dumpIdInfoOfProgram )
+import GHC.Core.Utils ( exprIsHNF, dumpIdInfoOfProgram, normSplitTyConApp_maybe )
import GHC.Core.Type
import GHC.Core.FamInstEnv
import GHC.Core.Opt.WorkWrap.Utils
@@ -33,7 +33,7 @@ import GHC.Utils.Misc
import GHC.Utils.Panic
import GHC.Utils.Logger ( Logger, dumpIfSet_dyn, DumpFormat (..) )
import GHC.Data.Graph.UnVar -- for UnVarSet
-import GHC.Data.Maybe ( isNothing )
+import GHC.Data.Maybe ( isJust )
import Control.Monad ( guard )
import Data.List ( mapAccumL )
@@ -319,10 +319,10 @@ cprAnalBind top_lvl env id rhs
-- possibly trim thunk CPR info
rhs_ty'
-- See Note [CPR for thunks]
- | stays_thunk = trimCprTy rhs_ty
+ | stays_thunk = trimCprTy rhs_ty
-- See Note [CPR for sum types]
- | returns_sum = trimCprTy rhs_ty
- | otherwise = rhs_ty
+ | returns_local_sum = trimCprTy rhs_ty
+ | otherwise = rhs_ty
-- See Note [Arity trimming for CPR signatures]
sig = mkCprSigForArity (idArity id) rhs_ty'
id' = setIdCprSig id sig
@@ -334,8 +334,12 @@ cprAnalBind top_lvl env id rhs
not_strict = not (isStrUsedDmd (idDemandInfo id))
-- See Note [CPR for sum types]
(_, ret_ty) = splitPiTys (idType id)
- not_a_prod = isNothing (splitArgType_maybe (ae_fam_envs env) ret_ty)
- returns_sum = not (isTopLevel top_lvl) && not_a_prod
+ returns_product
+ | Just (tc, _, _) <- normSplitTyConApp_maybe (ae_fam_envs env) ret_ty
+ = isJust (tyConSingleAlgDataCon_maybe tc)
+ | otherwise
+ = False
+ returns_local_sum = not (isTopLevel top_lvl) && not returns_product
isDataStructure :: Id -> CoreExpr -> Bool
-- See Note [CPR for data structures]
@@ -483,7 +487,7 @@ argCprType env arg_ty dmd = CprType 0 (go arg_ty dmd)
where
go ty dmd
| Unbox (DataConPatContext { dcpc_dc = dc, dcpc_tc_args = tc_args }) ds
- <- wantToUnbox (ae_fam_envs env) MaybeArgOfInlineableFun ty dmd
+ <- wantToUnboxArg (ae_fam_envs env) MaybeArgOfInlineableFun ty dmd
-- No existentials; see Note [Which types are unboxed?])
-- Otherwise we'd need to call dataConRepInstPat here and thread a
-- UniqSupply. So argCprType is a bit less aggressive than it could
@@ -545,7 +549,7 @@ This is all done in 'extendSigEnvForArg'.
Note that
- * Whether or not something unboxes is decided by 'wantToUnbox', else we may
+ * Whether or not something unboxes is decided by 'wantToUnboxArg', else we may
get over-optimistic CPR results (e.g., from \(x :: a) -> x!).
* If the demand unboxes deeply, we can give the binder a /nested/ CPR
diff --git a/compiler/GHC/Core/Opt/WorkWrap/Utils.hs b/compiler/GHC/Core/Opt/WorkWrap/Utils.hs
index b257e6d27a..6221804446 100644
--- a/compiler/GHC/Core/Opt/WorkWrap/Utils.hs
+++ b/compiler/GHC/Core/Opt/WorkWrap/Utils.hs
@@ -8,8 +8,8 @@ A library for the ``worker\/wrapper'' back-end to the strictness analyser
module GHC.Core.Opt.WorkWrap.Utils
( WwOpts(..), initWwOpts, mkWwBodies, mkWWstr, mkWorkerArgs
- , DataConPatContext(..), splitArgType_maybe
- , UnboxingDecision(..), ArgOfInlineableFun(..), wantToUnbox
+ , DataConPatContext(..)
+ , UnboxingDecision(..), ArgOfInlineableFun(..), wantToUnboxArg
, findTypeShape
, isWorkerSmallEnough
)
@@ -55,6 +55,8 @@ import GHC.Driver.Ppr
import GHC.Data.FastString
import GHC.Data.List.SetOps
+import Control.Applicative ( (<|>) )
+
{-
************************************************************************
* *
@@ -558,57 +560,8 @@ data DataConPatContext
, dcpc_co :: !Coercion
}
--- | If @splitArgType_maybe ty = Just (dc, tys, co)@
--- then @dc \@tys \@_ex_tys (_args::_arg_tys) :: tc tys@
--- and @co :: ty ~ tc tys@
--- where underscore prefixes are holes, e.g. yet unspecified.
---
--- See Note [Which types are unboxed?].
-splitArgType_maybe :: FamInstEnvs -> Type -> Maybe DataConPatContext
-splitArgType_maybe fam_envs ty
- | Just (tc, tc_args, co) <- normSplitTyConApp_maybe fam_envs ty
- , Just con <- tyConSingleAlgDataCon_maybe tc
- = Just DataConPatContext { dcpc_dc = con
- , dcpc_tc_args = tc_args
- , dcpc_co = co }
-splitArgType_maybe _ _ = Nothing
-
--- | If @splitResultType_maybe n ty = Just (dc, tys, co)@
--- then @dc \@tys \@_ex_tys (_args::_arg_tys) :: tc tys@
--- and @co :: ty ~ tc tys@
--- where underscore prefixes are holes, e.g. yet unspecified.
--- @dc@ is the @n@th data constructor of @tc@.
---
--- See Note [Which types are unboxed?].
-splitResultType_maybe :: FamInstEnvs -> ConTag -> Type -> Maybe DataConPatContext
-splitResultType_maybe fam_envs con_tag ty
- | Just (tc, tc_args, co) <- normSplitTyConApp_maybe fam_envs ty
- , isDataTyCon tc -- NB: rules out unboxed sums and pairs!
- , let cons = tyConDataCons tc
- , cons `lengthAtLeast` con_tag -- This might not be true if we import the
- -- type constructor via a .hs-boot file (#8743)
- , let con = cons `getNth` (con_tag - fIRST_TAG)
- , null (dataConExTyCoVars con) -- no existentials;
- -- See Note [Which types are unboxed?]
- -- and GHC.Core.Opt.CprAnal.extendEnvForDataAlt
- -- where we also check this.
- , all isLinear (dataConInstArgTys con tc_args)
- -- Deactivates CPR worker/wrapper splits on constructors with non-linear
- -- arguments, for the moment, because they require unboxed tuple with variable
- -- multiplicity fields.
- = Just DataConPatContext { dcpc_dc = con
- , dcpc_tc_args = tc_args
- , dcpc_co = co }
-splitResultType_maybe _ _ _ = Nothing
-
-isLinear :: Scaled a -> Bool
-isLinear (Scaled w _ ) =
- case w of
- One -> True
- _ -> False
-
-- | Describes the outer shape of an argument to be unboxed or left as-is
--- Depending on how @s@ is instantiated (e.g., 'Demand').
+-- Depending on how @s@ is instantiated (e.g., 'Demand' or 'Cpr').
data UnboxingDecision s
= StopUnboxing
-- ^ We ran out of strictness info. Leave untouched.
@@ -620,9 +573,9 @@ data UnboxingDecision s
-- The 'DataConPatContext' carries the bits necessary for
-- instantiation with 'dataConRepInstPat'.
-- The @[s]@ carries the bits of information with which we can continue
- -- unboxing, e.g. @s@ will be 'Demand'.
+ -- unboxing, e.g. @s@ will be 'Demand' or 'Cpr'.
--- | A specialised Bool for an argument to 'wantToUnbox'.
+-- | A specialised Bool for an argument to 'wantToUnboxArg'.
-- See Note [Do not unpack class dictionaries].
data ArgOfInlineableFun
= NotArgOfInlineableFun -- ^ Definitely not in an inlineable fun.
@@ -630,14 +583,16 @@ data ArgOfInlineableFun
-- unbox dictionary args.
deriving Eq
-wantToUnbox :: FamInstEnvs -> ArgOfInlineableFun -> Type -> Demand -> UnboxingDecision Demand
+-- | Unboxing strategy for strict arguments.
+wantToUnboxArg :: FamInstEnvs -> ArgOfInlineableFun -> Type -> Demand -> UnboxingDecision Demand
-- See Note [Which types are unboxed?]
-wantToUnbox fam_envs inlineable_flag ty dmd
+wantToUnboxArg fam_envs inlineable_flag ty dmd
| isAbsDmd dmd
= DropAbsent
| isStrUsedDmd dmd
- , Just dcpc@DataConPatContext{ dcpc_dc = dc } <- splitArgType_maybe fam_envs ty
+ , Just (tc, tc_args, co) <- normSplitTyConApp_maybe fam_envs ty
+ , Just dc <- tyConSingleAlgDataCon_maybe tc
, let arity = dataConRepArity dc
-- See Note [Unpacking arguments with product and polymorphic demands]
, Just cs <- split_prod_dmd_arity dmd arity
@@ -647,7 +602,7 @@ wantToUnbox fam_envs inlineable_flag ty dmd
, cs `lengthIs` arity
-- See Note [Add demands for strict constructors]
, let cs' = addDataConStrictness dc cs
- = Unbox dcpc cs'
+ = Unbox (DataConPatContext dc tc_args co) cs'
| otherwise
= StopUnboxing
@@ -660,6 +615,41 @@ wantToUnbox fam_envs inlineable_flag ty dmd
| _ :* Prod ds <- dmd = Just ds
| otherwise = Nothing
+
+-- | Unboxing strategy for constructed results.
+wantToUnboxResult :: FamInstEnvs -> Type -> Cpr -> UnboxingDecision Cpr
+-- See Note [Which types are unboxed?]
+wantToUnboxResult fam_envs ty cpr
+ | Just (con_tag, _cprs) <- asConCpr cpr
+ , Just (tc, tc_args, co) <- normSplitTyConApp_maybe fam_envs ty
+ , isDataTyCon tc -- NB: No unboxed sums or tuples
+ , Just dcs <- tyConAlgDataCons_maybe tc <|> open_body_ty_warning
+ , dcs `lengthAtLeast` con_tag -- This might not be true if we import the
+ -- type constructor via a .hs-boot file (#8743)
+ , let dc = dcs `getNth` (con_tag - fIRST_TAG)
+ , null (dataConExTyCoVars dc) -- no existentials;
+ -- See Note [Which types are unboxed?]
+ -- and GHC.Core.Opt.CprAnal.argCprType
+ -- where we also check this.
+ , all isLinear (dataConInstArgTys dc tc_args)
+ -- Deactivates CPR worker/wrapper splits on constructors with non-linear
+ -- arguments, for the moment, because they require unboxed tuple with variable
+ -- multiplicity fields.
+ = Unbox (DataConPatContext dc tc_args co) []
+
+ | otherwise
+ = StopUnboxing
+
+ where
+ open_body_ty_warning = WARN( True, text "wantToUnboxResult: non-algebraic or open body type" <+> ppr ty ) Nothing
+
+isLinear :: Scaled a -> Bool
+isLinear (Scaled w _ ) =
+ case w of
+ One -> True
+ _ -> False
+
+
{- Note [Which types are unboxed?]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Worker/wrapper will unbox
@@ -690,8 +680,8 @@ Worker/wrapper will unbox
to
> $wf x y = let ... in (# @ex, (a :: ..ex..), (b :: ..ex..) #)
-The respective tests are in 'splitArgType_maybe' and
-'splitResultType_maybe', respectively.
+The respective tests are in 'wantToUnboxArg' and
+'wantToUnboxResult', respectively.
Note that the data constructor /can/ have evidence arguments: equality
constraints, type classes etc. So it can be GADT. These evidence
@@ -919,7 +909,7 @@ mkWWstr_one :: WwOpts
-> Var
-> UniqSM (Bool, [Var], CoreExpr -> CoreExpr, CoreExpr -> CoreExpr)
mkWWstr_one opts inlineable_flag arg =
- case wantToUnbox fam_envs inlineable_flag arg_ty arg_dmd of
+ case wantToUnboxArg fam_envs inlineable_flag arg_ty arg_dmd of
_ | isTyVar arg -> do_nothing
DropAbsent
@@ -1183,16 +1173,10 @@ mkWWcpr opts body_ty cpr
-- CPR explicitly turned off (or in -O0)
| not (wo_cpr_anal opts) = return (False, id, id, body_ty)
-- CPR is turned on by default for -O and O2
+ | Unbox dcpc _arg_cprs <- wantToUnboxResult (wo_fam_envs opts) body_ty cpr
+ = mkWWcpr_help dcpc
| otherwise
- = case asConCpr cpr of
- Nothing -> return (False, id, id, body_ty) -- No CPR info
- Just (con_tag, _cprs)
- | Just dcpc <- splitResultType_maybe (wo_fam_envs opts) con_tag body_ty
- -> mkWWcpr_help dcpc
- | otherwise
- -- See Note [non-algebraic or open body type warning]
- -> WARN( True, text "mkWWcpr: non-algebraic or open body type" <+> ppr body_ty )
- return (False, id, id, body_ty)
+ = return (False, id, id, body_ty)
mkWWcpr_help :: DataConPatContext
-> UniqSM (Bool, CoreExpr -> CoreExpr, CoreExpr -> CoreExpr, Type)
@@ -1238,7 +1222,7 @@ mkWWcpr_help (DataConPatContext { dcpc_dc = dc, dcpc_tc_args = tc_args
con_app = mkConApp2 dc tc_args arg_ids `mkCast` mkSymCo co
tup_con = tupleDataCon Unboxed (length arg_ids)
- ; MASSERT( null _exs ) -- Should have been caught by splitResultType_maybe
+ ; MASSERT( null _exs ) -- Should have been caught by wantToUnboxResult
; return (True
, \ wkr_call -> mkSingleAltCase wkr_call wrap_wild
diff --git a/compiler/GHC/Core/Utils.hs b/compiler/GHC/Core/Utils.hs
index 7d7e5342b9..ff89358809 100644
--- a/compiler/GHC/Core/Utils.hs
+++ b/compiler/GHC/Core/Utils.hs
@@ -2598,7 +2598,7 @@ isEmptyTy ty
= False
-- | If @normSplitTyConApp_maybe _ ty = Just (tc, tys, co)@
--- then @ty |> co = tc tys@. It's 'splitArgType_maybe', but looks through
+-- then @ty |> co = tc tys@. It's 'splitTyConApp_maybe', but looks through
-- coercions via 'topNormaliseType_maybe'. Hence the \"norm\" prefix.
normSplitTyConApp_maybe :: FamInstEnvs -> Type -> Maybe (TyCon, [Type], Coercion)
normSplitTyConApp_maybe fam_envs ty
diff --git a/compiler/GHC/Types/Demand.hs b/compiler/GHC/Types/Demand.hs
index 84e5a9ac67..c4e25a1a47 100644
--- a/compiler/GHC/Types/Demand.hs
+++ b/compiler/GHC/Types/Demand.hs
@@ -719,7 +719,7 @@ the latter, for a regrettable-subtle reason. Consider
g h p2@(_,_) = h p
We want to unbox @p1@ of @f@, but not @p2@ of @g@, because @g@ only uses
@p2@ boxed and we'd have to rebox. So we give @p1@ demand LP(L,L) and @p2@
-demand @L@ to inform 'GHC.Core.Opt.WorkWrap.Utils.wantToUnbox', which will
+demand @L@ to inform 'GHC.Core.Opt.WorkWrap.Utils.wantToUnboxArg', which will
say "unbox" for @p1@ and "don't unbox" for @p2@.
So the solution is: don't aggressively collapse @Prod [topDmd, topDmd]@ to