ghc-9.12.1: GHC/Stg/Utils.hs
{-# LANGUAGE CPP, ScopedTypeVariables, TypeFamilies #-}
{-# LANGUAGE DataKinds #-}
module GHC.Stg.Utils
( mkStgAltTypeFromStgAlts
, bindersOf, bindersOfX, bindersOfTop, bindersOfTopBinds
, stripStgTicksTop, stripStgTicksTopE
, idArgs
, mkUnarisedId, mkUnarisedIds
, allowTopLevelConApp
) where
import GHC.Prelude
import GHC.Platform
import GHC.Types.Id
import GHC.Core.Type
import GHC.Core.TyCon
import GHC.Core.DataCon
import GHC.Core ( AltCon(..) )
import GHC.Types.Tickish
import GHC.Types.Unique.Supply
import GHC.Types.RepType
import GHC.Types.Name ( isDynLinkName )
import GHC.Unit.Module ( Module )
import GHC.Stg.Syntax
import GHC.Utils.Outputable
import GHC.Utils.Panic
import GHC.Data.FastString
mkUnarisedIds :: MonadUnique m => FastString -> [NvUnaryType] -> m [Id]
mkUnarisedIds fs tys = mapM (mkUnarisedId fs) tys
mkUnarisedId :: MonadUnique m => FastString -> NvUnaryType -> m Id
mkUnarisedId s t = mkSysLocalM s ManyTy t
-- Checks if id is a top level error application.
-- isErrorAp_maybe :: Id ->
-- | Extract the default case alternative
-- findDefaultStg :: [Alt b] -> ([Alt b], Maybe (Expr b))
findDefaultStg
:: [GenStgAlt p]
-> ([GenStgAlt p], Maybe (GenStgExpr p))
findDefaultStg (GenStgAlt{ alt_con = DEFAULT
, alt_bndrs = args
, alt_rhs = rhs} : alts) = assert( null args ) (alts, Just rhs)
findDefaultStg alts = (alts, Nothing)
mkStgAltTypeFromStgAlts :: forall p. Id -> [GenStgAlt p] -> AltType
mkStgAltTypeFromStgAlts bndr alts
| isUnboxedTupleType bndr_ty || isUnboxedSumType bndr_ty
= MultiValAlt (length prim_reps) -- always use MultiValAlt for unboxed tuples
| otherwise
= case prim_reps of
[rep] | isGcPtrRep rep ->
case tyConAppTyCon_maybe (unwrapType bndr_ty) of
Just tc
| isAbstractTyCon tc -> look_for_better_tycon
| isAlgTyCon tc -> AlgAlt tc
| otherwise -> assertPpr ( _is_poly_alt_tycon tc) (ppr tc)
PolyAlt
Nothing -> PolyAlt
[non_gcd] -> PrimAlt non_gcd
not_unary -> MultiValAlt (length not_unary)
where
bndr_ty = idType bndr
prim_reps = typePrimRep bndr_ty
_is_poly_alt_tycon tc
= isPrimTyCon tc -- "Any" is lifted but primitive
|| isFamilyTyCon tc -- Type family; e.g. Any, or arising from strict
-- function application where argument has a
-- type-family type
-- Sometimes, the TyCon is a AbstractTyCon which may not have any
-- constructors inside it. Then we may get a better TyCon by
-- grabbing the one from a constructor alternative
-- if one exists.
look_for_better_tycon
| (DataAlt con : _) <- alt_con <$> data_alts =
AlgAlt (dataConTyCon con)
| otherwise =
assert(null data_alts)
PolyAlt
where
(data_alts, _deflt) = findDefaultStg alts
bindersOf :: BinderP a ~ Id => GenStgBinding a -> [Id]
bindersOf (StgNonRec binder _) = [binder]
bindersOf (StgRec pairs) = [binder | (binder, _) <- pairs]
bindersOfX :: GenStgBinding a -> [BinderP a]
bindersOfX (StgNonRec binder _) = [binder]
bindersOfX (StgRec pairs) = [binder | (binder, _) <- pairs]
bindersOfTop :: BinderP a ~ Id => GenStgTopBinding a -> [Id]
bindersOfTop (StgTopLifted bind) = bindersOf bind
bindersOfTop (StgTopStringLit binder _) = [binder]
-- All ids we bind something to on the top level.
bindersOfTopBinds :: BinderP a ~ Id => [GenStgTopBinding a] -> [Id]
-- bindersOfTopBinds binds = mapUnionVarSet (mkVarSet . bindersOfTop) binds
bindersOfTopBinds binds = foldr ((++) . bindersOfTop) [] binds
idArgs :: [StgArg] -> [Id]
idArgs args = [v | StgVarArg v <- args]
-- | Strip ticks of a given type from an STG expression.
stripStgTicksTop :: (StgTickish -> Bool) -> GenStgExpr p -> ([StgTickish], GenStgExpr p)
stripStgTicksTop p = go []
where go ts (StgTick t e) | p t = go (t:ts) e
-- This special case avoid building a thunk for "reverse ts" when there are no ticks
go [] other = ([], other)
go ts other = (reverse ts, other)
-- | Strip ticks of a given type from an STG expression returning only the expression.
stripStgTicksTopE :: (StgTickish -> Bool) -> GenStgExpr p -> GenStgExpr p
stripStgTicksTopE p = go
where go (StgTick t e) | p t = go e
go other = other
-- | Do we allow the given top-level (static) ConApp?
allowTopLevelConApp
:: Platform
-> Bool -- is Opt_ExternalDynamicRefs enabled?
-> Module
-> DataCon
-> [StgArg]
-> Bool
allowTopLevelConApp platform ext_dyn_refs this_mod con args
-- we're not using dynamic linking
| not ext_dyn_refs = True
-- if the target OS is Windows, we only allow top-level ConApps if they don't
-- reference external names (Windows DLLs have a problem with static cross-DLL
-- refs)
| platformOS platform == OSMinGW32 = not is_external_con_app
-- otherwise, allowed
-- Sylvain: shouldn't this be False when (ext_dyn_refs && is_external_con_app)?
| otherwise = True
where
is_external_con_app = isDynLinkName platform this_mod (dataConName con) || any is_dll_arg args
-- NB: typePrimRep1 is legit because any free variables won't have
-- unlifted type (there are no unlifted things at top level)
is_dll_arg :: StgArg -> Bool
is_dll_arg (StgVarArg v) = isAddrRep (typePrimRep1 (idType v))
&& isDynLinkName platform this_mod (idName v)
is_dll_arg _ = False
-- True of machine addresses; these are the things that don't work across DLLs.
-- The key point here is that VoidRep comes out False, so that a top level
-- nullary GADT constructor is True for allowTopLevelConApp
--
-- data T a where
-- T1 :: T Int
--
-- gives
--
-- T1 :: forall a. (a~Int) -> T a
--
-- and hence the top-level binding
--
-- $WT1 :: T Int
-- $WT1 = T1 Int (Coercion (Refl Int))
--
-- The coercion argument here gets VoidRep
isAddrRep :: PrimOrVoidRep -> Bool
isAddrRep (NVRep AddrRep) = True
isAddrRep (NVRep (BoxedRep _)) = True -- FIXME: not true for JavaScript
isAddrRep _ = False