GHC.Core.Opt.WorkWrap.Utils

ghc-9.4.0.20220501: The GHC API

Safe Haskell | Safe-Inferred
Language | Haskell2010

GHC.Core.Opt.WorkWrap.Utils

Synopsis

- data WwOpts = MkWwOpts {
  - wo_fam_envs :: !FamInstEnvs
  - wo_simple_opts :: !SimpleOpts
  - wo_cpr_anal :: !Bool
  - wo_module :: !Module
  - wo_unlift_strict :: !Bool
  }
- initWwOpts :: Module -> DynFlags -> FamInstEnvs -> WwOpts
- mkWwBodies :: WwOpts -> Id -> [Var] -> Type -> [Demand] -> Cpr -> UniqSM (Maybe WwResult)
- mkWWstr :: WwOpts -> [Var] -> [CbvMark] -> UniqSM (Bool, [(Var, CbvMark)], CoreExpr -> CoreExpr, [CoreExpr])
- mkWWstr_one :: WwOpts -> Var -> CbvMark -> UniqSM (Bool, [(Var, CbvMark)], CoreExpr -> CoreExpr, CoreExpr)
- needsVoidWorkerArg :: Id -> [Var] -> [Var] -> Bool
- addVoidWorkerArg :: [Var] -> [CbvMark] -> ([Var], [Var], [CbvMark])
- data DataConPatContext = DataConPatContext {
  - dcpc_dc :: !DataCon
  - dcpc_tc_args :: ![Type]
  - dcpc_co :: !Coercion
  }
- data UnboxingDecision s
  - = StopUnboxing
  - | DropAbsent
  - | Unbox !DataConPatContext [s]
  - | Unlift
- wantToUnboxArg :: Bool -> FamInstEnvs -> Type -> Demand -> UnboxingDecision Demand
- findTypeShape :: FamInstEnvs -> Type -> TypeShape
- data IsRecDataConResult
  - = DefinitelyRecursive
  - | NonRecursiveOrUnsure
- isRecDataCon :: FamInstEnvs -> IntWithInf -> DataCon -> IsRecDataConResult
- mkAbsentFiller :: WwOpts -> Id -> Maybe CoreExpr
- isWorkerSmallEnough :: Int -> Int -> [Var] -> Bool
- dubiousDataConInstArgTys :: DataCon -> [Type] -> [Type]
- isGoodWorker :: Bool -> Bool
- badWorker :: Bool
- goodWorker :: Bool

# Documentation

data WwOpts Source #

Constructors

MkWwOpts |
Fields wo_fam_envs :: !FamInstEnvs wo_simple_opts :: !SimpleOpts wo_cpr_anal :: !Bool wo_module :: !Module wo_unlift_strict :: !Bool

initWwOpts :: Module -> DynFlags -> FamInstEnvs -> WwOpts Source #

mkWwBodies Source #

Arguments

:: WwOpts |
-> Id | The original function
-> [Var] | Manifest args of original function
-> Type | Result type of the original function, after being stripped of args
-> [Demand] | Strictness of original function
-> Cpr | Info about function result
-> UniqSM (Maybe WwResult) |

Given a function definition

    data T = MkT Int Bool Char
    f :: (a, b) -> Int -> T
    f = \x y -> E

`mkWwBodies _ `f` ['x::(a,b)','y::Int'] '(a,b)' ['1P(L,L)', '1P(L)'] '1'` returns

- The wrapper body context for the call to the worker function, lacking only the `Id` for the worker function:

    W[_] :: Id -> CoreExpr
    W[work_fn] = \x y ->          -- args of the wrapper    (cloned_arg_vars)
      case x of (a, b) ->         -- unbox wrapper args     (wrap_fn_str)
      case y of I# n ->           --
      case <work_fn> a b n of     -- call to the worker fun (call_work)
      (# i, b, c #) -> MkT i b c  -- rebox result           (wrap_fn_cpr)

- The worker body context that wraps around its hole reboxing defns for x and y, as well as returning CPR transit variables of the unboxed MkT result in an unboxed tuple:

    w[_] :: CoreExpr -> CoreExpr
    w[fn_rhs] = \a b n ->              -- args of the worker       (work_lam_args)
      let { y = I# n; x = (a, b) } in  -- reboxing wrapper args    (work_fn_str)
      case <fn_rhs> x y of             -- call to the original RHS (call_rhs)
      MkT i b c -> (# i, b, c #)       -- return CPR transit vars  (work_fn_cpr)

NB: The wrap_rhs hole is to be filled with the original wrapper RHS `x y -> E`. This is so that we can also use `w` to transform stable unfoldings, the lambda args of which may be different than x and y.

- Id details for the worker function like demands on arguments and its join arity.

All without looking at E (except for beta reduction, see Note [Join points and beta-redexes]), which allows us to apply the same split to function body and its unfolding(s) alike.

mkWWstr :: WwOpts -> [Var] -> [CbvMark] -> UniqSM (Bool, [(Var, CbvMark)], CoreExpr -> CoreExpr, [CoreExpr]) Source #

mkWWstr_one :: WwOpts -> Var -> CbvMark -> UniqSM (Bool, [(Var, CbvMark)], CoreExpr -> CoreExpr, CoreExpr) Source #

needsVoidWorkerArg :: Id -> [Var] -> [Var] -> Bool Source #

Whether the worker needs an additional `Void#` arg as per Note [Protecting the last value argument] or Note [Preserving float barriers].

addVoidWorkerArg :: [Var] -> [CbvMark] -> ([Var], [Var], [CbvMark]) Source #

Inserts a `Void#` arg before the first value argument (but after leading type args).

data DataConPatContext Source #

The information needed to build a pattern for a DataCon to be unboxed. The pattern can be generated from `dcpc_dc` and `dcpc_tc_args` via `dataConRepInstPat`. The coercion `dcpc_co` is for newtype wrappers.

If we get `DataConPatContext dc tys co` for some type `ty` and `dataConRepInstPat ... dc tys = (exs, flds)`, then

- `dc` exs flds :: T tys@

-     co :: T tys ~ ty

Constructors

DataConPatContext |
Fields dcpc_dc :: !DataCon dcpc_tc_args :: ![Type] dcpc_co :: !Coercion

data UnboxingDecision s Source #

Describes the outer shape of an argument to be unboxed or left as-is Depending on how `s` is instantiated (e.g., `Demand` or `Cpr`).

Constructors

StopUnboxing | We ran out of strictness info. Leave untouched.
DropAbsent | The argument/field was absent. Drop it.
Unbox !DataConPatContext [s] | The argument is used strictly or the returned product was constructed, so unbox it. 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` or `Cpr`.
Unlift | The argument can't be unboxed, but we want it to be passed evaluated to the worker.

wantToUnboxArg Source #

Arguments

:: Bool | Consider unlifting
-> FamInstEnvs |
-> Type | Type of the argument
-> Demand | How the arg was used
-> UnboxingDecision Demand |

Unwraps the `Boxity` decision encoded in the given `SubDemand` and returns a `DataConPatContext` as well the nested demands on fields of the `DataCon` to unbox.

findTypeShape :: FamInstEnvs -> Type -> TypeShape Source #

data IsRecDataConResult Source #

Returned by `isRecDataCon`. See also Note [Detecting recursive data constructors].

Constructors

DefinitelyRecursive | The algorithm detected a loop
NonRecursiveOrUnsure | The algorithm detected no loop, went out of fuel or hit an .hs-boot file

#### Instances

Instances details

Show IsRecDataConResult Source # |
Instance details Defined in GHC.Core.Opt.WorkWrap.Utils Methods showsPrec :: Int -> IsRecDataConResult -> ShowS Source # show :: IsRecDataConResult -> String Source # showList :: [IsRecDataConResult] -> ShowS Source #
Outputable IsRecDataConResult Source # |
Instance details Defined in GHC.Core.Opt.WorkWrap.Utils Methods ppr :: IsRecDataConResult -> SDoc Source #
Eq IsRecDataConResult Source # |
Instance details Defined in GHC.Core.Opt.WorkWrap.Utils Methods (==) :: IsRecDataConResult -> IsRecDataConResult -> Bool # (/=) :: IsRecDataConResult -> IsRecDataConResult -> Bool #

isRecDataCon :: FamInstEnvs -> IntWithInf -> DataCon -> IsRecDataConResult Source #

`isRecDataCon _ fuel dc`, where `tc = dataConTyCon dc` returns

- `DefinitelyRecursive` if the analysis found that `tc` is reachable through one of `dc`'s `arg_tys`.
- `NonRecursiveOrUnsure` if the analysis found that `tc` is not reachable through one of `dc`'s fields (so surely non-recursive).
- `NonRecursiveOrUnsure` when `fuel /= Infinity` and `fuel` expansions of nested data TyCons were not enough to prove non-recursivenss, nor arrive at an occurrence of `tc` thus proving recursiveness. (So not sure if non-recursive.)
- `NonRecursiveOrUnsure` when we hit an abstract TyCon (one without visible DataCons), such as those imported from .hs-boot files. Similarly for stuck type and data families.

If `fuel = `Infinity`` and there are no boot files involved, then the result is never `Nothing` and the analysis is a depth-first search. If `fuel = `Int` f`, then the analysis behaves like a depth-limited DFS and returns `Nothing` if the search was inconclusive.

See Note [Detecting recursive data constructors] for which recursive DataCons we want to flag.

mkAbsentFiller :: WwOpts -> Id -> Maybe CoreExpr Source #

Tries to find a suitable absent filler to bind the given absent identifier to. See Note [Absent fillers].

If `mkAbsentFiller _ id == Just e`, then `e` is an absent filler with the same type as `id`. Otherwise, no suitable filler could be found.

isWorkerSmallEnough :: Int -> Int -> [Var] -> Bool Source #

dubiousDataConInstArgTys :: DataCon -> [Type] -> [Type] Source #

Exactly `dataConInstArgTys`, but lacks the (ASSERT'ed) precondition that the `DataCon` may not have existentials. The lack of cloning the existentials compared to `dataConInstExAndArgVars` makes this function "dubious"; only use it where type variables aren't substituted for!

isGoodWorker :: Bool -> Bool Source #

badWorker :: Bool Source #

goodWorker :: Bool Source #