Jaro Reinders pushed to branch wip/reduce-type-in-stg at Glasgow Haskell Compiler / GHC
Commits:
-
f7411bb6
by Jaro Reinders at 2026-02-27T12:01:45+00:00
-
e8ccf617
by Jaro Reinders at 2026-02-27T12:57:32+00:00
-
14f8cd8d
by Jaro Reinders at 2026-02-27T17:58:58+00:00
10 changed files:
- compiler/GHC/CoreToStg.hs
- compiler/GHC/Stg/BcPrep.hs
- compiler/GHC/Stg/Make.hs
- compiler/GHC/Stg/Syntax.hs
- compiler/GHC/Stg/Unarise.hs
- compiler/GHC/StgToByteCode.hs
- compiler/GHC/StgToCmm/Expr.hs
- compiler/GHC/StgToCmm/Foreign.hs
- compiler/GHC/StgToCmm/Prim.hs
- compiler/GHC/StgToJS/Expr.hs
Changes:
| ... | ... | @@ -566,7 +566,7 @@ mkStgApp f how_bound core_args stg_args res_ty |
| 566 | 566 | |
| 567 | 567 | -- A regular foreign call.
|
| 568 | 568 | FCallId call -> assert exactly_saturated $
|
| 569 | - StgOpApp (StgFCallOp call (idType f)) stg_args res_kind
|
|
| 569 | + StgOpApp (StgFCallOp call (collectStgFArgTypes (idType f))) stg_args res_kind
|
|
| 570 | 570 | |
| 571 | 571 | TickBoxOpId {} -> pprPanic "coreToStg TickBox" $ ppr (f,stg_args)
|
| 572 | 572 | |
| ... | ... | @@ -722,7 +722,7 @@ coreToMkStgRhs bndr expr = do |
| 722 | 722 | let mk_rhs = MkStgRhs
|
| 723 | 723 | { rhs_args = args'
|
| 724 | 724 | , rhs_expr = body'
|
| 725 | - , rhs_type = exprType body
|
|
| 725 | + , rhs_kind = MkStgKind (typeKind (exprType body))
|
|
| 726 | 726 | , rhs_is_join = isJoinId bndr
|
| 727 | 727 | }
|
| 728 | 728 | pure mk_rhs
|
| ... | ... | @@ -50,7 +50,7 @@ bcPrepRHS con@StgRhsCon{} = pure con |
| 50 | 50 | bcPrepExpr :: StgExpr -> BcPrepM StgExpr
|
| 51 | 51 | -- explicitly match all constructors so we get a warning if we miss any
|
| 52 | 52 | bcPrepExpr (StgTick bp@(Breakpoint tick_ty _ _) rhs)
|
| 53 | - | isLiftedTypeKind (typeKind tick_ty) = do
|
|
| 53 | + | isLiftedTypeKind tick_kind = do
|
|
| 54 | 54 | id <- newId tick_ty
|
| 55 | 55 | rhs' <- bcPrepExpr rhs
|
| 56 | 56 | let expr' = StgTick bp rhs'
|
| ... | ... | @@ -59,7 +59,7 @@ bcPrepExpr (StgTick bp@(Breakpoint tick_ty _ _) rhs) |
| 59 | 59 | ReEntrant
|
| 60 | 60 | []
|
| 61 | 61 | expr'
|
| 62 | - tick_ty
|
|
| 62 | + (MkStgKind tick_kind)
|
|
| 63 | 63 | )
|
| 64 | 64 | letExp = StgLet noExtFieldSilent bnd (StgApp id [])
|
| 65 | 65 | pure letExp
|
| ... | ... | @@ -72,9 +72,10 @@ bcPrepExpr (StgTick bp@(Breakpoint tick_ty _ _) rhs) |
| 72 | 72 | ReEntrant
|
| 73 | 73 | [voidArgId]
|
| 74 | 74 | expr'
|
| 75 | - tick_ty
|
|
| 75 | + (MkStgKind tick_kind)
|
|
| 76 | 76 | )
|
| 77 | 77 | pure $ StgLet noExtFieldSilent bnd (StgApp id [StgVarArg realWorldPrimId])
|
| 78 | + where tick_kind = typeKind tick_ty
|
|
| 78 | 79 | bcPrepExpr (StgTick tick rhs) =
|
| 79 | 80 | StgTick tick <$> bcPrepExpr rhs
|
| 80 | 81 | bcPrepExpr (StgLet xlet bnds expr) =
|
| ... | ... | @@ -11,7 +11,6 @@ import GHC.Prelude |
| 11 | 11 | import GHC.Unit.Module
|
| 12 | 12 | |
| 13 | 13 | import GHC.Core.DataCon
|
| 14 | -import GHC.Core.Type (Type)
|
|
| 15 | 14 | |
| 16 | 15 | import GHC.Stg.Syntax
|
| 17 | 16 | import GHC.Stg.Utils (stripStgTicksTop)
|
| ... | ... | @@ -27,7 +26,7 @@ import GHC.Types.Tickish |
| 27 | 26 | data MkStgRhs = MkStgRhs
|
| 28 | 27 | { rhs_args :: [Id] -- ^ Empty for thunks
|
| 29 | 28 | , rhs_expr :: StgExpr -- ^ RHS expression
|
| 30 | - , rhs_type :: Type -- ^ RHS type (only used in the JS backend: layering violation)
|
|
| 29 | + , rhs_kind :: StgKind -- ^ RHS kind (only used in the JS backend: layering violation)
|
|
| 31 | 30 | , rhs_is_join :: !Bool -- ^ Is it a RHS for a join-point?
|
| 32 | 31 | }
|
| 33 | 32 | |
| ... | ... | @@ -37,7 +36,7 @@ data MkStgRhs = MkStgRhs |
| 37 | 36 | mkTopStgRhs :: (Module -> DataCon -> [StgArg] -> Bool)
|
| 38 | 37 | -> Bool -> Module -> CollectedCCs
|
| 39 | 38 | -> Id -> MkStgRhs -> (StgRhs, CollectedCCs)
|
| 40 | -mkTopStgRhs allow_toplevel_con_app opt_AutoSccsOnIndividualCafs this_mod ccs bndr mk_rhs@(MkStgRhs bndrs rhs typ _)
|
|
| 39 | +mkTopStgRhs allow_toplevel_con_app opt_AutoSccsOnIndividualCafs this_mod ccs bndr mk_rhs@(MkStgRhs bndrs rhs kind _)
|
|
| 41 | 40 | -- try to make a StgRhsCon first
|
| 42 | 41 | | Just rhs_con <- mkTopStgRhsCon_maybe (allow_toplevel_con_app this_mod) mk_rhs
|
| 43 | 42 | = ( rhs_con, ccs )
|
| ... | ... | @@ -47,20 +46,20 @@ mkTopStgRhs allow_toplevel_con_app opt_AutoSccsOnIndividualCafs this_mod ccs bnd |
| 47 | 46 | ( StgRhsClosure noExtFieldSilent
|
| 48 | 47 | dontCareCCS
|
| 49 | 48 | ReEntrant
|
| 50 | - bndrs rhs typ
|
|
| 49 | + bndrs rhs kind
|
|
| 51 | 50 | , ccs )
|
| 52 | 51 | |
| 53 | 52 | -- Otherwise it's a CAF, see Note [Cost-centre initialization plan].
|
| 54 | 53 | | opt_AutoSccsOnIndividualCafs
|
| 55 | 54 | = ( StgRhsClosure noExtFieldSilent
|
| 56 | 55 | caf_ccs
|
| 57 | - upd_flag [] rhs typ
|
|
| 56 | + upd_flag [] rhs kind
|
|
| 58 | 57 | , collectCC caf_cc caf_ccs ccs )
|
| 59 | 58 | |
| 60 | 59 | | otherwise
|
| 61 | 60 | = ( StgRhsClosure noExtFieldSilent
|
| 62 | 61 | all_cafs_ccs
|
| 63 | - upd_flag [] rhs typ
|
|
| 62 | + upd_flag [] rhs kind
|
|
| 64 | 63 | , ccs )
|
| 65 | 64 | |
| 66 | 65 | where
|
| ... | ... | @@ -82,7 +81,7 @@ mkTopStgRhs allow_toplevel_con_app opt_AutoSccsOnIndividualCafs this_mod ccs bnd |
| 82 | 81 | -- Generate a non-top-level RHS. Cost-centre is always currentCCS,
|
| 83 | 82 | -- see Note [Cost-centre initialization plan].
|
| 84 | 83 | mkStgRhs :: Id -> MkStgRhs -> StgRhs
|
| 85 | -mkStgRhs bndr mk_rhs@(MkStgRhs bndrs rhs typ is_join)
|
|
| 84 | +mkStgRhs bndr mk_rhs@(MkStgRhs bndrs rhs kind is_join)
|
|
| 86 | 85 | -- try to make a StgRhsCon first
|
| 87 | 86 | | Just rhs_con <- mkStgRhsCon_maybe mk_rhs
|
| 88 | 87 | = rhs_con
|
| ... | ... | @@ -90,7 +89,7 @@ mkStgRhs bndr mk_rhs@(MkStgRhs bndrs rhs typ is_join) |
| 90 | 89 | | otherwise
|
| 91 | 90 | = StgRhsClosure noExtFieldSilent
|
| 92 | 91 | currentCCS
|
| 93 | - upd_flag bndrs rhs typ
|
|
| 92 | + upd_flag bndrs rhs kind
|
|
| 94 | 93 | where
|
| 95 | 94 | upd_flag | is_join = JumpedTo
|
| 96 | 95 | | not (null bndrs) = ReEntrant
|
| ... | ... | @@ -151,22 +150,22 @@ isPAP env _ = False |
| 151 | 150 | |
| 152 | 151 | -- | Try to make a non top-level StgRhsCon if appropriate
|
| 153 | 152 | mkStgRhsCon_maybe :: MkStgRhs -> Maybe StgRhs
|
| 154 | -mkStgRhsCon_maybe (MkStgRhs bndrs rhs typ is_join)
|
|
| 153 | +mkStgRhsCon_maybe (MkStgRhs bndrs rhs kind is_join)
|
|
| 155 | 154 | | [] <- bndrs
|
| 156 | 155 | , not is_join
|
| 157 | 156 | , (ticks, StgConApp con mn args _) <- stripStgTicksTop (not . tickishIsCode) rhs
|
| 158 | - = Just (StgRhsCon currentCCS con mn ticks args typ)
|
|
| 157 | + = Just (StgRhsCon currentCCS con mn ticks args kind)
|
|
| 159 | 158 | |
| 160 | 159 | | otherwise = Nothing
|
| 161 | 160 | |
| 162 | 161 | |
| 163 | 162 | -- | Try to make a top-level StgRhsCon if appropriate
|
| 164 | 163 | mkTopStgRhsCon_maybe :: (DataCon -> [StgArg] -> Bool) -> MkStgRhs -> Maybe StgRhs
|
| 165 | -mkTopStgRhsCon_maybe allow_static_con_app (MkStgRhs bndrs rhs typ is_join)
|
|
| 164 | +mkTopStgRhsCon_maybe allow_static_con_app (MkStgRhs bndrs rhs kind is_join)
|
|
| 166 | 165 | | [] <- bndrs
|
| 167 | 166 | , not is_join -- shouldn't happen at top-level
|
| 168 | 167 | , (ticks, StgConApp con mn args _) <- stripStgTicksTop (not . tickishIsCode) rhs
|
| 169 | 168 | , allow_static_con_app con args
|
| 170 | - = Just (StgRhsCon dontCareCCS con mn ticks args typ)
|
|
| 169 | + = Just (StgRhsCon dontCareCCS con mn ticks args kind)
|
|
| 171 | 170 | |
| 172 | 171 | | otherwise = Nothing |
| ... | ... | @@ -16,6 +16,9 @@ generation. |
| 16 | 16 | module GHC.Stg.Syntax (
|
| 17 | 17 | StgKind(..),
|
| 18 | 18 | |
| 19 | + StgFArgType(..),
|
|
| 20 | + collectStgFArgTypes,
|
|
| 21 | + |
|
| 19 | 22 | StgArg(..),
|
| 20 | 23 | |
| 21 | 24 | GenStgTopBinding(..), GenStgBinding(..), GenStgExpr(..), GenStgRhs(..),
|
| ... | ... | @@ -77,7 +80,7 @@ import GHC.Types.CostCentre ( CostCentreStack ) |
| 77 | 80 | import GHC.Core ( AltCon )
|
| 78 | 81 | import GHC.Core.DataCon
|
| 79 | 82 | import GHC.Core.TyCon ( PrimRep(..), PrimOrVoidRep(..), TyCon )
|
| 80 | -import GHC.Core.Type ( Type )
|
|
| 83 | +import GHC.Core.Type ( Type, tyConAppTyCon )
|
|
| 81 | 84 | import GHC.Core.Ppr( {- instances -} )
|
| 82 | 85 | |
| 83 | 86 | import GHC.Types.ForeignCall ( ForeignCall )
|
| ... | ... | @@ -85,7 +88,7 @@ import GHC.Types.Id |
| 85 | 88 | import GHC.Types.Tickish ( StgTickish )
|
| 86 | 89 | import GHC.Types.Var.Set
|
| 87 | 90 | import GHC.Types.Literal ( Literal, literalType )
|
| 88 | -import GHC.Types.RepType ( typePrimRep, typePrimRep1, typePrimRepU, typePrimRep_maybe )
|
|
| 91 | +import GHC.Types.RepType ( typePrimRep, typePrimRep1, typePrimRepU, typePrimRep_maybe, unwrapType )
|
|
| 89 | 92 | |
| 90 | 93 | import GHC.Utils.Outputable
|
| 91 | 94 | import GHC.Utils.Panic.Plain
|
| ... | ... | @@ -96,6 +99,14 @@ import Data.ByteString ( ByteString ) |
| 96 | 99 | import Data.Data ( Data )
|
| 97 | 100 | import Data.List ( intersperse )
|
| 98 | 101 | import GHC.Tc.Utils.TcType (Kind)
|
| 102 | +import GHC.Core.TyCo.Rep (Type(..))
|
|
| 103 | +import GHC.Builtin.Types.Prim
|
|
| 104 | + ( arrayPrimTyCon,
|
|
| 105 | + byteArrayPrimTyCon,
|
|
| 106 | + mutableArrayPrimTyCon,
|
|
| 107 | + mutableByteArrayPrimTyCon,
|
|
| 108 | + smallArrayPrimTyCon,
|
|
| 109 | + smallMutableArrayPrimTyCon )
|
|
| 99 | 110 | |
| 100 | 111 | newtype StgKind = MkStgKind { getStgKind :: Kind }
|
| 101 | 112 | |
| ... | ... | @@ -414,7 +425,7 @@ data GenStgRhs pass |
| 414 | 425 | [BinderP pass] -- ^ arguments; if empty, then not a function;
|
| 415 | 426 | -- as above, order is important.
|
| 416 | 427 | (GenStgExpr pass) -- ^ body
|
| 417 | - Type -- ^ result type
|
|
| 428 | + StgKind -- ^ result kind
|
|
| 418 | 429 | |
| 419 | 430 | {-
|
| 420 | 431 | An example may be in order. Consider:
|
| ... | ... | @@ -444,7 +455,7 @@ important): |
| 444 | 455 | ConstructorNumber
|
| 445 | 456 | [StgTickish]
|
| 446 | 457 | [StgArg] -- Saturated Args. See Note [Constructor applications in STG]
|
| 447 | - Type -- Type, for rewriting to an StgRhsClosure
|
|
| 458 | + StgKind -- Kind, for rewriting to an StgRhsClosure
|
|
| 448 | 459 | |
| 449 | 460 | -- | Like 'GHC.Hs.Extension.NoExtField', but with an 'Outputable' instance that
|
| 450 | 461 | -- returns 'empty'.
|
| ... | ... | @@ -701,6 +712,51 @@ isUpdatable SingleEntry = False |
| 701 | 712 | isUpdatable Updatable = True
|
| 702 | 713 | isUpdatable JumpedTo = False
|
| 703 | 714 | |
| 715 | +-- The minimum amount of information needed to determine
|
|
| 716 | +-- the offset to apply to an argument to a foreign call.
|
|
| 717 | +-- See Note [Unlifted boxed arguments to foreign calls]
|
|
| 718 | +data StgFArgType
|
|
| 719 | + = StgPlainType
|
|
| 720 | + | StgArrayType
|
|
| 721 | + | StgSmallArrayType
|
|
| 722 | + | StgByteArrayType
|
|
| 723 | + |
|
| 724 | +-- From a function, extract information needed to determine
|
|
| 725 | +-- the offset of each argument when used as a C FFI argument.
|
|
| 726 | +-- See Note [Unlifted boxed arguments to foreign calls]
|
|
| 727 | +collectStgFArgTypes :: Type -> [StgFArgType]
|
|
| 728 | +collectStgFArgTypes = go []
|
|
| 729 | + where
|
|
| 730 | + -- Skip foralls
|
|
| 731 | + go bs (ForAllTy _ res) = go bs res
|
|
| 732 | + go bs (AppTy{}) = reverse bs
|
|
| 733 | + go bs (TyConApp{}) = reverse bs
|
|
| 734 | + go bs (LitTy{}) = reverse bs
|
|
| 735 | + go bs (TyVarTy{}) = reverse bs
|
|
| 736 | + go _ (CastTy{}) = panic "myCollectTypeArgs: CastTy"
|
|
| 737 | + go _ (CoercionTy{}) = panic "myCollectTypeArgs: CoercionTy"
|
|
| 738 | + go bs (FunTy {ft_arg = arg, ft_res=res}) =
|
|
| 739 | + go (typeToStgFArgType arg:bs) res
|
|
| 740 | + |
|
| 741 | +-- Choose the offset based on the type. For anything other
|
|
| 742 | +-- than an unlifted boxed type, there is no offset.
|
|
| 743 | +-- See Note [Unlifted boxed arguments to foreign calls]
|
|
| 744 | +typeToStgFArgType :: Type -> StgFArgType
|
|
| 745 | +typeToStgFArgType typ
|
|
| 746 | + | tycon == arrayPrimTyCon = StgArrayType
|
|
| 747 | + | tycon == mutableArrayPrimTyCon = StgArrayType
|
|
| 748 | + | tycon == smallArrayPrimTyCon = StgSmallArrayType
|
|
| 749 | + | tycon == smallMutableArrayPrimTyCon = StgSmallArrayType
|
|
| 750 | + | tycon == byteArrayPrimTyCon = StgByteArrayType
|
|
| 751 | + | tycon == mutableByteArrayPrimTyCon = StgByteArrayType
|
|
| 752 | + | otherwise = StgPlainType
|
|
| 753 | + where
|
|
| 754 | + -- Should be a tycon app, since this is a foreign call. We look
|
|
| 755 | + -- through newtypes so the offset does not change if a user replaces
|
|
| 756 | + -- a type in a foreign function signature with a representationally
|
|
| 757 | + -- equivalent newtype.
|
|
| 758 | + tycon = tyConAppTyCon (unwrapType typ)
|
|
| 759 | + |
|
| 704 | 760 | {-
|
| 705 | 761 | ************************************************************************
|
| 706 | 762 | * *
|
| ... | ... | @@ -717,11 +773,12 @@ data StgOp |
| 717 | 773 | |
| 718 | 774 | | StgPrimCallOp PrimCall
|
| 719 | 775 | |
| 720 | - | StgFCallOp ForeignCall Type
|
|
| 721 | - -- The Type, which is obtained from the foreign import declaration
|
|
| 722 | - -- itself, is needed by the stg-to-cmm pass to determine the offset to
|
|
| 723 | - -- apply to unlifted boxed arguments in GHC.StgToCmm.Foreign. See Note
|
|
| 724 | - -- [Unlifted boxed arguments to foreign calls]
|
|
| 776 | + | StgFCallOp ForeignCall [StgFArgType]
|
|
| 777 | + -- The foreign argument types, which are obtained from the foreign
|
|
| 778 | + -- import declaration itself, areneeded by the stg-to-cmm pass to
|
|
| 779 | + -- determine the offset to apply to unlifted boxed arguments in
|
|
| 780 | + -- GHC.StgToCmm.Foreign.
|
|
| 781 | + -- See Note [Unlifted boxed arguments to foreign calls]
|
|
| 725 | 782 | |
| 726 | 783 | | StgTagToEnumOp TyCon
|
| 727 | 784 | |
| ... | ... | @@ -915,6 +972,8 @@ pprStgOp :: StgOp -> SDoc |
| 915 | 972 | pprStgOp (StgPrimOp op) = ppr op
|
| 916 | 973 | pprStgOp (StgPrimCallOp op)= ppr op
|
| 917 | 974 | pprStgOp (StgFCallOp op _) = ppr op
|
| 975 | +-- TODO: how do we want to pretty print this?
|
|
| 976 | +pprStgOp (StgTagToEnumOp tyc) = text "TagToEnumOp" <+> ppr tyc
|
|
| 918 | 977 | |
| 919 | 978 | instance Outputable StgOp where
|
| 920 | 979 | ppr = pprStgOp
|
| ... | ... | @@ -494,7 +494,7 @@ unariseBinding rho top_level (StgRec xrhss) |
| 494 | 494 | = StgRec <$> mapM (\(x, rhs) -> (x,) <$> unariseRhs rho top_level rhs) xrhss
|
| 495 | 495 | |
| 496 | 496 | unariseRhs :: UnariseEnv -> Bool -> StgRhs -> UniqSM StgRhs
|
| 497 | -unariseRhs rho top_level (StgRhsClosure ext ccs update_flag args expr typ)
|
|
| 497 | +unariseRhs rho top_level (StgRhsClosure ext ccs update_flag args expr kind)
|
|
| 498 | 498 | = do (rho', args1) <- unariseFunArgBinders rho args
|
| 499 | 499 | expr' <- unariseExpr rho' expr
|
| 500 | 500 | -- Unarisation can lead to a StgRhsClosure becoming a StgRhsCon.
|
| ... | ... | @@ -515,7 +515,7 @@ unariseRhs rho top_level (StgRhsClosure ext ccs update_flag args expr typ) |
| 515 | 515 | let mk_rhs = MkStgRhs
|
| 516 | 516 | { rhs_args = args1
|
| 517 | 517 | , rhs_expr = expr'
|
| 518 | - , rhs_type = typ
|
|
| 518 | + , rhs_kind = kind
|
|
| 519 | 519 | , rhs_is_join = update_flag == JumpedTo
|
| 520 | 520 | }
|
| 521 | 521 | if | top_level
|
| ... | ... | @@ -527,7 +527,7 @@ unariseRhs rho top_level (StgRhsClosure ext ccs update_flag args expr typ) |
| 527 | 527 | -> pure rhs_con
|
| 528 | 528 | |
| 529 | 529 | | otherwise
|
| 530 | - -> pure (StgRhsClosure ext ccs update_flag args1 expr' typ)
|
|
| 530 | + -> pure (StgRhsClosure ext ccs update_flag args1 expr' kind)
|
|
| 531 | 531 | |
| 532 | 532 | unariseRhs rho _top (StgRhsCon ccs con mu ts args typ)
|
| 533 | 533 | = assert (not (isUnboxedTupleDataCon con || isUnboxedSumDataCon con))
|
| ... | ... | @@ -47,7 +47,6 @@ import GHC.Utils.Misc |
| 47 | 47 | import GHC.Utils.Logger
|
| 48 | 48 | import GHC.Types.Var.Set
|
| 49 | 49 | import GHC.Builtin.Types.Prim
|
| 50 | -import GHC.Core.TyCo.Ppr ( pprType )
|
|
| 51 | 50 | import GHC.Utils.Error
|
| 52 | 51 | import GHC.Builtin.Uniques
|
| 53 | 52 | import GHC.Data.FastString
|
| ... | ... | @@ -2171,7 +2170,7 @@ mkDummyLiteral platform pr |
| 2171 | 2170 | |
| 2172 | 2171 | maybe_is_tagToEnum_call :: CgStgExpr -> Maybe (StgArg, [Name])
|
| 2173 | 2172 | -- Detect and extract relevant info for the tagToEnum kludge.
|
| 2174 | -maybe_is_tagToEnum_call (StgOpApp (StgTagToEnumOp tyc) args t)
|
|
| 2173 | +maybe_is_tagToEnum_call (StgOpApp (StgTagToEnumOp tyc) args _)
|
|
| 2175 | 2174 | | [v] <- args
|
| 2176 | 2175 | = Just (v, extract_constr_Names tyc)
|
| 2177 | 2176 | | otherwise
|
| ... | ... | @@ -688,6 +688,7 @@ isSimpleOp (StgPrimOp op) stg_args = do |
| 688 | 688 | -- See Note [Inlining out-of-line primops and heap checks]
|
| 689 | 689 | return $! shouldInlinePrimOp cfg op arg_exprs
|
| 690 | 690 | isSimpleOp (StgPrimCallOp _) _ = return False
|
| 691 | +isSimpleOp (StgTagToEnumOp _) _ = return True
|
|
| 691 | 692 | |
| 692 | 693 | -----------------
|
| 693 | 694 | chooseReturnBndrs :: Id -> AltType -> [CgStgAlt] -> [NonVoid Id]
|
| ... | ... | @@ -42,7 +42,6 @@ import GHC.Cmm.Reg ( GlobalArgRegs(..) ) |
| 42 | 42 | import GHC.Cmm.Utils
|
| 43 | 43 | import GHC.Cmm.Graph
|
| 44 | 44 | import GHC.Cmm.CallConv
|
| 45 | -import GHC.Core.Type
|
|
| 46 | 45 | import GHC.Types.RepType
|
| 47 | 46 | import GHC.Cmm.CLabel
|
| 48 | 47 | import GHC.Runtime.Heap.Layout
|
| ... | ... | @@ -53,8 +52,6 @@ import GHC.Types.Basic |
| 53 | 52 | import GHC.Types.Unique.DSM
|
| 54 | 53 | import GHC.Unit.Types
|
| 55 | 54 | |
| 56 | -import GHC.Core.TyCo.Rep
|
|
| 57 | -import GHC.Builtin.Types.Prim
|
|
| 58 | 55 | import GHC.Utils.Misc (zipEqual)
|
| 59 | 56 | |
| 60 | 57 | import Control.Monad
|
| ... | ... | @@ -67,13 +64,13 @@ import Control.Monad |
| 67 | 64 | -- Precondition: the length of the arguments list is the same as the
|
| 68 | 65 | -- arity of the foreign function.
|
| 69 | 66 | cgForeignCall :: ForeignCall -- the op
|
| 70 | - -> Type -- type of foreign function
|
|
| 67 | + -> [StgFArgType]
|
|
| 71 | 68 | -> [StgArg] -- x,y arguments
|
| 72 | 69 | -> StgKind -- result kind
|
| 73 | 70 | -> FCode ReturnKind
|
| 74 | 71 | |
| 75 | -cgForeignCall (CCall (CCallSpec target cconv safety)) typ stg_args res_kind
|
|
| 76 | - = do { cmm_args <- getFCallArgs stg_args typ
|
|
| 72 | +cgForeignCall (CCall (CCallSpec target cconv safety)) arg_tys stg_args res_kind
|
|
| 73 | + = do { cmm_args <- getFCallArgs stg_args arg_tys
|
|
| 77 | 74 | -- ; traceM $ show cmm_args
|
| 78 | 75 | ; (res_regs, res_hints) <- newUnboxedTupleRegs (getStgKind res_kind)
|
| 79 | 76 | ; let ((call_args, arg_hints), cmm_target)
|
| ... | ... | @@ -711,15 +708,15 @@ closureField profile off = off + fixedHdrSize profile |
| 711 | 708 | |
| 712 | 709 | getFCallArgs ::
|
| 713 | 710 | [StgArg]
|
| 714 | - -> Type -- the type of the foreign function
|
|
| 711 | + -> [StgFArgType]
|
|
| 715 | 712 | -> FCode [(CmmExpr, ForeignHint)]
|
| 716 | 713 | -- (a) Drop void args
|
| 717 | 714 | -- (b) Add foreign-call shim code
|
| 718 | 715 | -- It's (b) that makes this differ from getNonVoidArgAmodes
|
| 719 | 716 | -- Precondition: args and typs have the same length
|
| 720 | 717 | -- See Note [Unlifted boxed arguments to foreign calls]
|
| 721 | -getFCallArgs args typ
|
|
| 722 | - = do { mb_cmms <- mapM get (zipEqual args (collectStgFArgTypes typ))
|
|
| 718 | +getFCallArgs args arg_tys
|
|
| 719 | + = do { mb_cmms <- mapM get (zipEqual args arg_tys)
|
|
| 723 | 720 | ; return (catMaybes mb_cmms) }
|
| 724 | 721 | where
|
| 725 | 722 | get (arg,typ)
|
| ... | ... | @@ -734,15 +731,6 @@ getFCallArgs args typ |
| 734 | 731 | arg_reps = typePrimRep arg_ty
|
| 735 | 732 | hint = typeForeignHint arg_ty
|
| 736 | 733 | |
| 737 | --- The minimum amount of information needed to determine
|
|
| 738 | --- the offset to apply to an argument to a foreign call.
|
|
| 739 | --- See Note [Unlifted boxed arguments to foreign calls]
|
|
| 740 | -data StgFArgType
|
|
| 741 | - = StgPlainType
|
|
| 742 | - | StgArrayType
|
|
| 743 | - | StgSmallArrayType
|
|
| 744 | - | StgByteArrayType
|
|
| 745 | - |
|
| 746 | 734 | -- See Note [Unlifted boxed arguments to foreign calls]
|
| 747 | 735 | add_shim :: Profile -> StgFArgType -> CmmExpr -> CmmExpr
|
| 748 | 736 | add_shim profile ty expr = case ty of
|
| ... | ... | @@ -752,39 +740,3 @@ add_shim profile ty expr = case ty of |
| 752 | 740 | StgByteArrayType -> cmmOffsetB platform expr (arrWordsHdrSize profile)
|
| 753 | 741 | where
|
| 754 | 742 | platform = profilePlatform profile |
| 755 | - |
|
| 756 | --- From a function, extract information needed to determine
|
|
| 757 | --- the offset of each argument when used as a C FFI argument.
|
|
| 758 | --- See Note [Unlifted boxed arguments to foreign calls]
|
|
| 759 | -collectStgFArgTypes :: Type -> [StgFArgType]
|
|
| 760 | -collectStgFArgTypes = go []
|
|
| 761 | - where
|
|
| 762 | - -- Skip foralls
|
|
| 763 | - go bs (ForAllTy _ res) = go bs res
|
|
| 764 | - go bs (AppTy{}) = reverse bs
|
|
| 765 | - go bs (TyConApp{}) = reverse bs
|
|
| 766 | - go bs (LitTy{}) = reverse bs
|
|
| 767 | - go bs (TyVarTy{}) = reverse bs
|
|
| 768 | - go _ (CastTy{}) = panic "myCollectTypeArgs: CastTy"
|
|
| 769 | - go _ (CoercionTy{}) = panic "myCollectTypeArgs: CoercionTy"
|
|
| 770 | - go bs (FunTy {ft_arg = arg, ft_res=res}) =
|
|
| 771 | - go (typeToStgFArgType arg:bs) res
|
|
| 772 | - |
|
| 773 | --- Choose the offset based on the type. For anything other
|
|
| 774 | --- than an unlifted boxed type, there is no offset.
|
|
| 775 | --- See Note [Unlifted boxed arguments to foreign calls]
|
|
| 776 | -typeToStgFArgType :: Type -> StgFArgType
|
|
| 777 | -typeToStgFArgType typ
|
|
| 778 | - | tycon == arrayPrimTyCon = StgArrayType
|
|
| 779 | - | tycon == mutableArrayPrimTyCon = StgArrayType
|
|
| 780 | - | tycon == smallArrayPrimTyCon = StgSmallArrayType
|
|
| 781 | - | tycon == smallMutableArrayPrimTyCon = StgSmallArrayType
|
|
| 782 | - | tycon == byteArrayPrimTyCon = StgByteArrayType
|
|
| 783 | - | tycon == mutableByteArrayPrimTyCon = StgByteArrayType
|
|
| 784 | - | otherwise = StgPlainType
|
|
| 785 | - where
|
|
| 786 | - -- Should be a tycon app, since this is a foreign call. We look
|
|
| 787 | - -- through newtypes so the offset does not change if a user replaces
|
|
| 788 | - -- a type in a foreign function signature with a representationally
|
|
| 789 | - -- equivalent newtype.
|
|
| 790 | - tycon = tyConAppTyCon (unwrapType typ) |
| ... | ... | @@ -36,6 +36,7 @@ import GHC.Stg.Syntax |
| 36 | 36 | import GHC.Cmm
|
| 37 | 37 | import GHC.Unit ( rtsUnit )
|
| 38 | 38 | import GHC.Core.Type ( typeKind )
|
| 39 | +import GHC.Core.TyCon ( isEnumerationTyCon )
|
|
| 39 | 40 | import GHC.Cmm.CLabel
|
| 40 | 41 | import GHC.Cmm.Info ( closureInfoPtr )
|
| 41 | 42 | import GHC.Cmm.Utils
|
| ... | ... | @@ -85,6 +86,22 @@ cgOpApp (StgPrimCallOp primcall) args _res_ty |
| 85 | 86 | ; let fun = CmmLit (CmmLabel (mkPrimCallLabel primcall))
|
| 86 | 87 | ; emitCall (NativeNodeCall, NativeReturn) fun cmm_args }
|
| 87 | 88 | |
| 89 | +-- tagToEnum# is special: we need to pull the constructor
|
|
| 90 | +-- out of the table, and perform an appropriate return.
|
|
| 91 | +cgOpApp (StgTagToEnumOp tyc) args _ = do
|
|
| 92 | + amodes <- getNonVoidArgAmodes args
|
|
| 93 | + case amodes of
|
|
| 94 | + [amode] -> do
|
|
| 95 | + -- If you're reading this code in the attempt to figure
|
|
| 96 | + -- out why the compiler panic'ed here, it is probably because
|
|
| 97 | + -- you used tagToEnum# in a non-monomorphic setting, e.g.,
|
|
| 98 | + -- intToTg :: Enum a => Int -> a ; intToTg (I# x#) = tagToEnum# x#
|
|
| 99 | + -- That won't work.
|
|
| 100 | + massert (isEnumerationTyCon tyc)
|
|
| 101 | + platform <- getPlatform
|
|
| 102 | + emitReturn [tagToClosure platform tyc amode]
|
|
| 103 | + _ -> pprPanic "cgOpApp: tagToEnum# should be applied to exactly one argument" (ppr args)
|
|
| 104 | + |
|
| 88 | 105 | cmmPrimOpApp :: StgToCmmConfig -> PrimOp -> [CmmExpr] -> Maybe StgKind -> FCode ReturnKind
|
| 89 | 106 | cmmPrimOpApp cfg primop cmm_args mres_ty =
|
| 90 | 107 | case emitPrimOp cfg primop cmm_args of
|
| ... | ... | @@ -1670,7 +1687,7 @@ emitPrimOp cfg primop = |
| 1670 | 1687 | |
| 1671 | 1688 | -- tagToEnum# is removed in CoreToStg and rewritten to a special StgTagToEnumOp
|
| 1672 | 1689 | -- See Note [?]
|
| 1673 | - TagToEnumOp -> panic "emitPrimOp: TagToEnumOp should have been gone by now"
|
|
| 1690 | + TagToEnumOp -> panic "emitPrimOp: TagToEnumOp should have been gone by now"
|
|
| 1674 | 1691 | |
| 1675 | 1692 | -- Out of line primops.
|
| 1676 | 1693 | -- TODO compiler need not know about these
|
| ... | ... | @@ -307,9 +307,9 @@ genBody :: HasDebugCallStack |
| 307 | 307 | -> StgReg
|
| 308 | 308 | -> [Id]
|
| 309 | 309 | -> CgStgExpr
|
| 310 | - -> Type
|
|
| 310 | + -> StgKind
|
|
| 311 | 311 | -> G JStgStat
|
| 312 | -genBody ctx startReg args e typ = do
|
|
| 312 | +genBody ctx startReg args e kind = do
|
|
| 313 | 313 | -- load arguments into local variables
|
| 314 | 314 | la <- do
|
| 315 | 315 | args' <- concatMapM genIdArgI args
|
| ... | ... | @@ -320,7 +320,7 @@ genBody ctx startReg args e typ = do |
| 320 | 320 | |
| 321 | 321 | -- compute PrimReps and their number of slots required to return the result of
|
| 322 | 322 | -- i applied to args.
|
| 323 | - let res_vars = resultSize typ
|
|
| 323 | + let res_vars = resultSize kind
|
|
| 324 | 324 | |
| 325 | 325 | -- compute typed expressions for each slot and assign registers
|
| 326 | 326 | let go_var regs = \case
|
| ... | ... | @@ -338,6 +338,12 @@ genBody ctx startReg args e typ = do |
| 338 | 338 | |
| 339 | 339 | return $ la <> lav <> e <> returnStack
|
| 340 | 340 | |
| 341 | +-- TODO: move to a proper place
|
|
| 342 | +stgKindPrimRep :: StgKind -> [PrimRep]
|
|
| 343 | +stgKindPrimRep (MkStgKind kind) = case kindPrimRep_maybe kind of
|
|
| 344 | + Just rs -> rs
|
|
| 345 | + r -> pprPanic "stgKindPrimRep" (ppr r)
|
|
| 346 | + |
|
| 341 | 347 | -- | Find the result type after applying the function to the arguments
|
| 342 | 348 | --
|
| 343 | 349 | -- It's trickier than it looks because:
|
| ... | ... | @@ -361,12 +367,12 @@ genBody ctx startReg args e typ = do |
| 361 | 367 | -- In case of failure to determine the type, we default to LiftedRep as it's
|
| 362 | 368 | -- probably what it is.
|
| 363 | 369 | --
|
| 364 | -resultSize :: HasDebugCallStack => Type -> [(PrimRep, Int)]
|
|
| 365 | -resultSize ty = result
|
|
| 370 | +resultSize :: HasDebugCallStack => StgKind -> [(PrimRep, Int)]
|
|
| 371 | +resultSize kind = result
|
|
| 366 | 372 | where
|
| 367 | 373 | result = result_reps `zip` result_slots
|
| 368 | 374 | result_slots = fmap (slotCount . primRepSize) result_reps
|
| 369 | - result_reps = typePrimRep ty
|
|
| 375 | + result_reps = stgKindPrimRep kind
|
|
| 370 | 376 | |
| 371 | 377 | -- | Ensure that the set of identifiers has valid 'RuntimeRep's. This function
|
| 372 | 378 | -- returns a no-op when 'csRuntimeAssert' in 'StgToJSConfig' is False.
|
| ... | ... | @@ -1121,6 +1127,8 @@ genPrimOp ctx op args = do |
| 1121 | 1127 | |
| 1122 | 1128 | genTagToEnumOp :: ExprCtx -> TyCon -> StgArg -> State.StateT GenState IO (JStgStat, ExprResult)
|
| 1123 | 1129 | genTagToEnumOp ctx tyc arg = do
|
| 1124 | - [tag] <- genArg arg
|
|
| 1125 | - let [v] = concatMap typex_expr $ ctxTarget ctx
|
|
| 1126 | - pure (v |= if tyc == boolTyCon then IfExpr tag true_ false_ else app hdTagToEnum [tag], ExprInline) |
|
| \ No newline at end of file | ||
| 1130 | + tags <- genArg arg
|
|
| 1131 | + case (tags, concatMap typex_expr $ ctxTarget ctx) of
|
|
| 1132 | + ([tag], [v]) ->
|
|
| 1133 | + pure (v |= if tyc == boolTyCon then IfExpr tag true_ false_ else app hdTagToEnum [tag], ExprInline)
|
|
| 1134 | + _ -> pprPanic "genTagToEnumOp: should be applied to exactly one argument and have one result" (ppr ctx <+> ppr tyc <+> ppr arg) |
|
| \ No newline at end of file |