[Git][ghc/ghc][wip/nested-cpr-2019] Consider unboxing effects of WW better and get rid of hack

Sebastian Graf gitlab at gitlab.haskell.org
Tue Apr 21 16:41:31 UTC 2020



Sebastian Graf pushed to branch wip/nested-cpr-2019 at Glasgow Haskell Compiler / GHC


Commits:
063b38a6 by Sebastian Graf at 2020-04-21T18:41:23+02:00
Consider unboxing effects of WW better and get rid of hack

- - - - -


3 changed files:

- compiler/GHC/Core/Arity.hs
- compiler/GHC/Core/Op/CprAnal.hs
- compiler/GHC/Types/Cpr.hs


Changes:

=====================================
compiler/GHC/Core/Arity.hs
=====================================
@@ -12,7 +12,7 @@
 
 -- | Arity and eta expansion
 module GHC.Core.Arity
-   ( manifestArity, joinRhsArity, exprArity, typeArity
+   ( manifestArity, joinRhsArity, exprArity, typeArity, splitFunNewTys
    , exprEtaExpandArity, findRhsArity, etaExpand
    , etaExpandToJoinPoint, etaExpandToJoinPointRule
    , exprBotStrictness_maybe
@@ -41,6 +41,7 @@ import GHC.Driver.Session ( DynFlags, GeneralFlag(..), gopt )
 import Outputable
 import FastString
 import Util     ( debugIsOn )
+import Maybes
 
 {-
 ************************************************************************
@@ -117,33 +118,37 @@ typeArity :: Type -> [OneShotInfo]
 -- How many value arrows are visible in the type?
 -- We look through foralls, and newtypes
 -- See Note [exprArity invariant]
-typeArity ty
-  = go initRecTc ty
+typeArity ty = mapMaybe go (fst (splitPiNewTys ty))
   where
-    go rec_nts ty
-      | Just (_, ty')  <- splitForAllTy_maybe ty
-      = go rec_nts ty'
-
-      | Just (arg,res) <- splitFunTy_maybe ty
-      = typeOneShot arg : go rec_nts res
+    -- Important to look through non-recursive newtypes, so that, eg
+    --      (f x)   where f has arity 2, f :: Int -> IO ()
+    -- Here we want to get arity 1 for the result!
+    --
+    -- AND through a layer of recursive newtypes
+    -- e.g. newtype Stream m a b = Stream (m (Either b (a, Stream m a b)))
+    go ty_co_bndr = typeOneShot <$> binderRelevantType_maybe ty_co_bndr
+
+-- | Like 'splitFunTys', but this one also looks through newtypes and foralls.
+splitFunNewTys :: Type -> ([Type], Type)
+splitFunNewTys ty = (mapMaybe binderRelevantType_maybe arg_bndrs, res_ty)
+  where
+    (arg_bndrs, res_ty) = splitPiNewTys ty
 
+-- | Like 'splitPiTys', but this one also looks through newtypes.
+splitPiNewTys :: Type -> ([TyCoBinder], Type)
+splitPiNewTys ty = go initRecTc ty []
+  where
+    go rec_nts ty arg_tys
+      -- ForAllTys and FunTys
+      | Just (arg, res_ty)  <- splitPiTy_maybe ty
+      = go rec_nts res_ty (arg:arg_tys)
+      -- See Note [Expanding newtypes] in GHC.Core.TyCon
       | Just (tc,tys) <- splitTyConApp_maybe ty
       , Just (ty', _) <- instNewTyCon_maybe tc tys
-      , Just rec_nts' <- checkRecTc rec_nts tc  -- See Note [Expanding newtypes]
-                                                -- in GHC.Core.TyCon
---   , not (isClassTyCon tc)    -- Do not eta-expand through newtype classes
---                              -- See Note [Newtype classes and eta expansion]
---                              (no longer required)
-      = go rec_nts' ty'
-        -- Important to look through non-recursive newtypes, so that, eg
-        --      (f x)   where f has arity 2, f :: Int -> IO ()
-        -- Here we want to get arity 1 for the result!
-        --
-        -- AND through a layer of recursive newtypes
-        -- e.g. newtype Stream m a b = Stream (m (Either b (a, Stream m a b)))
-
+      , Just rec_nts' <- checkRecTc rec_nts tc
+      = go rec_nts' ty' arg_tys
       | otherwise
-      = []
+      = (reverse arg_tys, ty)
 
 ---------------
 exprBotStrictness_maybe :: CoreExpr -> Maybe (Arity, StrictSig)


=====================================
compiler/GHC/Core/Op/CprAnal.hs
=====================================
@@ -17,6 +17,7 @@ import GHC.Driver.Session
 import GHC.Types.Demand
 import GHC.Types.Cpr
 import GHC.Core
+import GHC.Core.Arity   ( splitFunNewTys )
 import GHC.Core.Seq
 import Outputable
 import GHC.Types.Var.Env
@@ -206,7 +207,7 @@ cprAnal' env args (Case scrut case_bndr ty alts)
     (whnf_flag, case_bndr_ty) = forceCprTy (getStrDmd seqDmd) scrut_ty
     -- Regardless of whether scrut had the CPR property or not, the case binder
     -- certainly has it. See 'extendEnvForDataAlt'.
-    (alt_tys, alts') = mapAndUnzip (cprAnalAlt env args scrut case_bndr case_bndr_ty) alts
+    (alt_tys, alts') = mapAndUnzip (cprAnalAlt env args case_bndr case_bndr_ty) alts
     res_ty           = foldl' lubCprType botCprType alt_tys `bothCprType` whnf_flag
 
 cprAnal' env args (Let (NonRec id rhs) body)
@@ -225,18 +226,17 @@ cprAnal' env args (Let (Rec pairs) body)
 cprAnalAlt
   :: AnalEnv
   -> [CprType]      -- ^ info about incoming arguments
-  -> CoreExpr       -- ^ scrutinee
   -> Id             -- ^ case binder
   -> CprType        -- ^ info about the case binder
   -> Alt Var        -- ^ current alternative
   -> (CprType, Alt Var)
-cprAnalAlt env args scrut case_bndr case_bndr_ty (con@(DataAlt dc),bndrs,rhs)
+cprAnalAlt env args case_bndr case_bndr_ty (con@(DataAlt dc),bndrs,rhs)
   -- See 'extendEnvForDataAlt' and Note [CPR in a DataAlt case alternative]
   = (rhs_ty, (con, bndrs, rhs'))
   where
-    env_alt        = extendEnvForDataAlt env scrut case_bndr case_bndr_ty dc bndrs
+    env_alt        = extendEnvForDataAlt env case_bndr case_bndr_ty dc bndrs
     (rhs_ty, rhs') = cprAnal env_alt args rhs
-cprAnalAlt env args _ case_bndr case_bndr_ty (con,bndrs,rhs)
+cprAnalAlt env args case_bndr case_bndr_ty (con,bndrs,rhs)
   = (rhs_ty, (con, bndrs, rhs'))
   where
     env' = extendAnalEnv env case_bndr (CprSig case_bndr_ty)
@@ -330,6 +330,18 @@ pruneSig d (CprSig cpr_ty)
   --       behavior.
   = CprSig $ cpr_ty { ct_cpr = pruneDeepCpr d (ct_cpr cpr_ty `lubCpr` initRecFunCpr) }
 
+unboxingStrategy :: AnalEnv -> UnboxingStrategy
+unboxingStrategy env ty dmd
+  = prj <$> wantToUnbox (ae_fam_envs env) has_inlineable_prag ty dmd
+  where
+    prj (dmds, DataConAppContext { dcac_dc = dc, dcac_arg_tys = tys_w_str })
+      = (dc, map fst tys_w_str, dmds)
+    -- Rather than maintaining in AnalEnv whether we are in an INLINEABLE
+    -- function, we just assume that we aren't. That flag is only relevant
+    -- to Note [Do not unpack class dictionaries], the few unboxing
+    -- opportunities on dicts it prohibits are probably irrelevant to CPR.
+    has_inlineable_prag = False
+
 -- | Process the RHS of the binding for a sensible arity, add the CPR signature
 -- to the Id, and augment the environment with the signature as well.
 cprAnalBind
@@ -342,20 +354,23 @@ cprAnalBind
 cprAnalBind top_lvl env args id rhs
   = (id', rhs')
   where
+    arg_tys             = fst (splitFunNewTys (idType id))
     -- We compute the Termination and CPR transformer based on the strictness
     -- signature. There is no point in pretending that an arg we are strict in
     -- could lead to non-termination, as the signature then trivially
     -- MightDiverge. Instead we assume that call sites make sure to force the
     -- arguments appropriately and unleash the TerminationFlag there.
-    assumed_arg_tys = argCprTypesFromStrictSig (idStrictness id)
+    assumed_arg_cpr_tys = argCprTypesFromStrictSig (unboxingStrategy env)
+                                                   arg_tys
+                                                   (idStrictness id)
 
     -- TODO: Not sure if that special handling of join points is really
     -- necessary. It might even be harmful if the excess 'args' aren't unboxed
     -- and we blindly assume that they have the CPR property! So we should
     -- try out getting rid of this special case and 'args'.
     (rhs_ty, rhs')
-      | isJoinId id = cprAnal env (assumed_arg_tys ++ args) rhs
-      | otherwise   = cprAnal env assumed_arg_tys rhs
+      | isJoinId id = cprAnal env (assumed_arg_cpr_tys ++ args) rhs
+      | otherwise   = cprAnal env assumed_arg_cpr_tys rhs
 
     -- possibly trim thunk CPR info
     rhs_ty'
@@ -438,86 +453,48 @@ emptyAnalEnv fam_envs
   , ae_fam_envs = fam_envs
   }
 
--- | Extend an environment with the strictness IDs attached to the id
+extendAnalEnv :: AnalEnv -> Id -> CprSig -> AnalEnv
+extendAnalEnv env id sig
+  = env { ae_sigs = extendVarEnv (ae_sigs env) id sig }
+
+extendAnalEnvList :: AnalEnv -> [(Id, CprSig)] -> AnalEnv
+extendAnalEnvList env ids_cprs
+  = env { ae_sigs = extendVarEnvList (ae_sigs env) ids_cprs }
+
+-- | Extend an environment with the CPR signatures attached to the id
 extendAnalEnvs :: AnalEnv -> [Id] -> AnalEnv
 extendAnalEnvs env ids
   = env { ae_sigs = sigs' }
   where
     sigs' = extendVarEnvList (ae_sigs env) [ (id, idCprInfo id) | id <- ids ]
 
-extendAnalEnv :: AnalEnv -> Id -> CprSig -> AnalEnv
-extendAnalEnv env id sig
-  = env { ae_sigs = extendVarEnv (ae_sigs env) id sig }
-
 lookupSigEnv :: AnalEnv -> Id -> Maybe CprSig
 lookupSigEnv env id = lookupVarEnv (ae_sigs env) id
 
 nonVirgin :: AnalEnv -> AnalEnv
 nonVirgin env = env { ae_virgin = False }
 
-dummyArgs :: DataCon -> [CprType]
-dummyArgs dc = take (dataConRepArity dc) (repeat topCprType)
-
--- | A version of 'extendAnalEnv' for a binder of which we don't see the RHS
--- needed to compute a 'CprSig' (e.g. lambdas and DataAlt field binders).
--- In this case, we can still look at their demand to attach CPR signatures
--- anticipating the unboxing done by worker/wrapper.
--- See Note [CPR for binders that will be unboxed].
-extendAnalEnvForDemand :: AnalEnv -> Id -> Demand -> CprType -> AnalEnv
-extendAnalEnvForDemand env id dmd ty
-  | isId id
-  , Just (_, DataConAppContext { dcac_dc = dc })
-      <- wantToUnbox (ae_fam_envs env) has_inlineable_prag (idType id) dmd
-  -- TODO: Make this deep, depending on the StrDmd
-  = extendAnalEnv env id $ CprSig $
-      markConCprType Terminates (dataConTag dc) (dummyArgs dc) $
-      -- TODO: There has to be a better way of forcing
-      snd $ forceCprTy (getStrDmd dmd) ty
-  | otherwise
-  = env
-  where
-    -- Rather than maintaining in AnalEnv whether we are in an INLINEABLE
-    -- function, we just assume that we aren't. That flag is only relevant
-    -- to Note [Do not unpack class dictionaries], the few unboxing
-    -- opportunities on dicts it prohibits are probably irrelevant to CPR.
-    has_inlineable_prag = False
-
-extendEnvForDataAlt :: AnalEnv -> CoreExpr -> Id -> CprType -> DataCon -> [Var] -> AnalEnv
+extendEnvForDataAlt :: AnalEnv -> Id -> CprType -> DataCon -> [Var] -> AnalEnv
 -- See Note [CPR in a DataAlt case alternative]
-extendEnvForDataAlt env scrut case_bndr case_bndr_ty dc bndrs
-  = foldl' do_con_arg env' ids_w_strs
+extendEnvForDataAlt env case_bndr case_bndr_ty dc bndrs
+  = extendAnalEnv env' case_bndr (CprSig case_bndr_ty')
   where
-    env' = extendAnalEnv env case_bndr (CprSig case_bndr_sig)
-
-    ids_w_strs    = filter isId bndrs `zip` dataConRepStrictness dc
-
     tycon          = dataConTyCon dc
     is_product     = isJust (isDataProductTyCon_maybe tycon)
     is_sum         = isJust (isDataSumTyCon_maybe tycon)
-    case_bndr_sig
-      | is_product || is_sum = undefined -- markConCprType  (dataConTag dc) (dummyArgs dc) case_bndr_ty
+    case_bndr_ty'
+      | is_product || is_sum = markConCprType dc case_bndr_ty
       -- Any of the constructors had existentials. This is a little too
       -- conservative (after all, we only care about the particular data con),
       -- but there is no easy way to write is_sum and this won't happen much.
-      | otherwise  = case_bndr_ty
-
-    -- We could have much deeper CPR info here with Nested CPR, which could
-    -- propagate available unboxed things from the scrutinee, getting rid of
-    -- the is_var_scrut heuristic. See Note [CPR in a DataAlt case alternative].
-    -- Giving strict binders the CPR property only makes sense for products, as
-    -- the arguments in Note [CPR for binders that will be unboxed] don't apply
-    -- to sums (yet); we lack WW for strict binders of sum type.
-    do_con_arg env (id, str)
-       | is_var scrut
-       -- See Note [Add demands for strict constructors] in WorkWrap.Lib
-       , let dmd = applyWhen (isMarkedStrict str) strictifyDmd (idDemandInfo id)
-       = extendAnalEnvForDemand env id dmd topCprType
-       | otherwise
-       = env
-
-    is_var (Cast e _) = is_var e
-    is_var (Var v)    = isLocalId v
-    is_var _          = False
+      | otherwise            = case_bndr_ty
+    env'
+      | Just fields <- splitConCprTy dc case_bndr_ty'
+      , let ids     = filter isId bndrs
+      , let cpr_tys = map (CprSig . CprType 0) fields
+      = extendAnalEnvList env (zipEqual "extendEnvForDataAlt" ids cpr_tys)
+      | otherwise
+      = env
 
 {- Note [Ensuring termination of fixed-point iteration]
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


=====================================
compiler/GHC/Types/Cpr.hs
=====================================
@@ -10,11 +10,11 @@
 module GHC.Types.Cpr (
     TerminationFlag (Terminates),
     Cpr, topCpr, botCpr, conCpr, initRecFunCpr, lubCpr, asConCpr,
-    CprType (..), topCprType, botCprType, conCprType, pruneDeepCpr,
-    markConCprType, lubCprType, applyCprTy, abstractCprTy, abstractCprTyNTimes,
-    ensureCprTyArity, trimCprTy,
+    CprType (..), topCprType, botCprType, lubCprType, conCprType,
+    pruneDeepCpr, markConCprType, splitConCprTy, applyCprTy, abstractCprTy,
+    abstractCprTyNTimes, ensureCprTyArity, trimCprTy,
     forceCprTy, forceCpr, bothCprType,
-    cprTransformDataConSig, cprTransformSig, argCprTypesFromStrictSig,
+    cprTransformDataConSig, UnboxingStrategy, cprTransformSig, argCprTypesFromStrictSig,
     CprSig (..), mkCprSig, mkCprSigForArity,
     topCprSig, seqCprSig
   ) where
@@ -26,6 +26,7 @@ import GhcPrelude
 import GHC.Types.Basic
 import GHC.Types.Demand
 import GHC.Core.DataCon
+import GHC.Core.Type
 import Outputable
 import Binary
 import Util
@@ -179,7 +180,7 @@ initRecFunCpr :: Cpr
 initRecFunCpr = Cpr MightDiverge Bot
 
 conCpr :: TerminationFlag -> ConTag -> [Cpr] -> Cpr
-conCpr tm t fs = Cpr tm (Levitate (Con t fs))
+conCpr tf t fs = Cpr tf (Levitate (Con t fs))
 
 -- | Forget encoded CPR info, but keep termination info.
 forgetCpr :: Cpr -> Termination
@@ -244,6 +245,18 @@ topCprType = CprType 0 topCpr
 botCprType :: CprType
 botCprType = CprType 0 botCpr
 
+lubCprType :: CprType -> CprType -> CprType
+lubCprType ty1@(CprType n1 cpr1) ty2@(CprType n2 cpr2)
+  | ct_cpr ty1 == botCpr && n1 <= n2 = ty2
+  | ct_cpr ty2 == botCpr && n2 <= n1 = ty1
+  -- There might be non-bottom CPR types with mismatching arities.
+  -- Consider test DmdAnalGADTs. We want to return topCpr in these cases.
+  -- Returning topCprType is a safe default.
+  | n1 == n2
+  = CprType n1 (lubCpr cpr1 cpr2)
+  | otherwise
+  = topCprType
+
 extractArgCprAndTermination :: [CprType] -> [Cpr]
 extractArgCprAndTermination = map go
   where
@@ -256,22 +269,30 @@ conCprType con_tag args = CprType 0 (conCpr Terminates con_tag cprs)
   where
     cprs = extractArgCprAndTermination args
 
-markConCprType :: TerminationFlag -> ConTag -> [CprType] -> CprType -> CprType
-markConCprType tf con_tag args ty = ASSERT( ct_arty ty == 0 ) ty { ct_cpr = conCpr tf con_tag cprs }
+markConCprType :: DataCon -> CprType -> CprType
+markConCprType dc _ty@(CprType n cpr)
+  = ASSERT2( n == 0, ppr _ty ) CprType 0 (conCpr Terminates con_tag fields)
   where
-    cprs = extractArgCprAndTermination args
-
-lubCprType :: CprType -> CprType -> CprType
-lubCprType ty1@(CprType n1 cpr1) ty2@(CprType n2 cpr2)
-  | ct_cpr ty1 == botCpr && n1 <= n2 = ty2
-  | ct_cpr ty2 == botCpr && n2 <= n1 = ty1
-  -- There might be non-bottom CPR types with mismatching arities.
-  -- Consider test DmdAnalGADTs. We want to return topCpr in these cases.
-  -- Returning topCprType is a safe default.
-  | n1 == n2
-  = CprType n1 (lubCpr cpr1 cpr2)
-  | otherwise
-  = topCprType
+    con_tag   = dataConTag dc
+    wkr_arity = dataConRepArity dc
+    fields    = case cpr of
+      NoMoreCpr (Term _ (Levitate (Con t terms)))
+        | con_tag == t       -> map NoMoreCpr terms
+      NoMoreCpr (Term _ Bot) -> replicate wkr_arity (NoMoreCpr botTerm)
+      Cpr _ (Levitate (Con t cprs))
+        | con_tag == t       -> cprs
+      Cpr _ Bot              -> replicate wkr_arity botCpr
+      _                      -> replicate wkr_arity topCpr
+
+splitConCprTy :: DataCon -> CprType -> Maybe [Cpr]
+splitConCprTy dc (CprType 0 (Cpr _ l))
+  | Bot <- l
+  = Just (replicate (dataConRepArity dc) botCpr)
+  | Levitate (Con t fields) <- l
+  , dataConTag dc == t
+  = Just fields
+splitConCprTy _  _
+  = Nothing
 
 applyCprTy :: CprType -> CprType
 applyCprTy (CprType n cpr)
@@ -392,18 +413,15 @@ forceCpr str cpr = runTerminationM (forceCprM str cpr)
 
 -- | 'lubTerm's the given outer @TerminationFlag@ on the @CprType at s 'ct_term'.
 bothCprType :: CprType -> TerminationFlag -> CprType
--- deepTerm because we only want to affect the WHNF layer.
--- If tm = Terminates, it's just 'id'.
--- If tm = MightDiverge, it will only set the WHNF layer to MightDiverge,
+-- If tf = Terminates, it's just 'id'.
+-- If tf = MightDiverge, it will only set the WHNF layer to MightDiverge,
 -- leaving nested termination info (e.g. on product components) intact.
-bothCprType ct tf = ct { ct_cpr = bothCpr (ct_cpr ct) tf }
-
-bothCpr :: Cpr -> TerminationFlag -> Cpr
-bothCpr (NoMoreCpr t)  tf  = NoMoreCpr (bothTerm t tf)
-bothCpr (Cpr tf1 l_sh) tf2 = Cpr (lubTermFlag tf1 tf2) l_sh
+bothCprType ct Terminates   = ct
+bothCprType ct MightDiverge = ct { ct_cpr = shallowDivCpr (ct_cpr ct) }
 
-bothTerm :: Termination -> TerminationFlag -> Termination
-bothTerm (Term tf1 l_sh) tf2 = Term (lubTermFlag tf1 tf2) l_sh
+shallowDivCpr :: Cpr -> Cpr
+shallowDivCpr (NoMoreCpr (Term _ l_sh)) = NoMoreCpr (Term MightDiverge l_sh)
+shallowDivCpr (Cpr _ l_sh)              = Cpr MightDiverge l_sh
 
 seqCprType :: CprType -> ()
 seqCprType (CprType _ cpr) = seqCpr cpr
@@ -461,20 +479,24 @@ cprTransformDataConSig con args
 
 cprTransformSig :: StrictSig -> CprSig -> [CprType] -> CprType
 cprTransformSig str_sig (CprSig sig_ty) arg_tys
-  | arg_strs <- argStrsFromStrictSig str_sig
-  , arg_tys `equalLength` arg_strs
-  , ASSERT( length arg_tys == ct_arty sig_ty ) True
-  , (tf, _) <- runTerminationM $ zipWithM_ forceCprTyM arg_strs arg_tys
+  | arg_strs <- map getStrDmd $ argDmdsFromStrictSig str_sig
+  , arg_strs `leLength` arg_tys
+  , arg_tys `lengthIs` ct_arty sig_ty
+  -- Maybe we should use resTypeArgDmd instead of strTop here. On the other
+  -- hand, I don't think it makes much of a difference; We basically only need
+  -- to pad with strTop when str_sig was topSig to begin with.
+  , (tf, _) <- runTerminationM $ zipWithM_ forceCprTyM (arg_strs ++ repeat strTop) arg_tys
   = sig_ty `bothCprType` tf
-  -- TODO: Think about what happens if arg_tys is longer than arg_strs.
   | otherwise
   = topCprType
 
 -- | We have to be sure that 'cprTransformSig' and 'argCprTypesFromStrictSig'
--- agree in how they compute the 'ArgStr's for which the 'CprSig' is computed.
--- This function encodes the common logic.
-argStrsFromStrictSig :: StrictSig -> [ArgStr]
-argStrsFromStrictSig = map getStrDmd . fst . splitStrictSig
+-- agree in how they compute the 'Demand's for which the 'CprSig' is computed.
+-- This function encodes the common (trivial) logic.
+argDmdsFromStrictSig :: StrictSig -> [Demand]
+argDmdsFromStrictSig = fst . splitStrictSig
+
+type UnboxingStrategy = Type -> Demand -> Maybe (DataCon, [Type], [Demand])
 
 -- | Produces 'CprType's the termination info of which match the given
 -- strictness signature. Examples:
@@ -482,11 +504,15 @@ argStrsFromStrictSig = map getStrDmd . fst . splitStrictSig
 --   - A head-strict demand @S@ would translate to @#@, a
 --   - A tuple demand @S(S,L)@ would translate to @#(#,*)@
 --   - A call demand @C(S)@ would translate to @strTop -> #(#,*)@
-argCprTypesFromStrictSig :: StrictSig -> [CprType]
-argCprTypesFromStrictSig sig = arg_tys
+argCprTypesFromStrictSig :: UnboxingStrategy -> [Type] -> StrictSig -> [CprType]
+argCprTypesFromStrictSig want_to_unbox arg_tys sig
+  = zipWith go arg_tys (argDmdsFromStrictSig sig)
   where
-    arg_strs = argStrsFromStrictSig sig
-    arg_tys  = zipWith ((snd .) . forceCprTy) arg_strs (repeat topCprType)
+    go arg_ty arg_dmd
+      | Just (dc, arg_tys, arg_dmds) <- want_to_unbox arg_ty arg_dmd
+      = conCprType (dataConTag dc) (zipWith go arg_tys arg_dmds)
+      | otherwise
+      = snd $ forceCprTy (getStrDmd arg_dmd) topCprType
 
 ---------------
 -- * Outputable
@@ -547,8 +573,8 @@ instance Binary r => Binary (KnownShape r) where
   get  bh = Con <$> get bh <*> get bh
 
 instance Binary TerminationFlag where
-  put_ bh MightDiverge = put_ bh False
   put_ bh Terminates   = put_ bh True
+  put_ bh MightDiverge = put_ bh False
   get  bh = do
     b <- get bh
     if b



View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/063b38a6a8575219f0a4d7e8d5eab2a58060b01d

-- 
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/063b38a6a8575219f0a4d7e8d5eab2a58060b01d
You're receiving this email because of your account on gitlab.haskell.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/ghc-commits/attachments/20200421/cb20706c/attachment-0001.html>


More information about the ghc-commits mailing list