ghc-9.6.3: 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
  }
- mkWwBodies :: WwOpts -> Id -> [Var] -> Type -> [Demand] -> Cpr -> UniqSM (Maybe WwResult)
- mkWWstr :: WwOpts -> [Var] -> [StrictnessMark] -> UniqSM (WwUse, [(Var, StrictnessMark)], CoreExpr -> CoreExpr, [CoreExpr])
- mkWWstr_one :: WwOpts -> Var -> StrictnessMark -> UniqSM (WwUse, [(Var, StrictnessMark)], CoreExpr -> CoreExpr, CoreExpr)
- needsVoidWorkerArg :: Id -> [Var] -> [Var] -> Bool
- data DataConPatContext s = DataConPatContext {
  - dcpc_dc :: !DataCon
  - dcpc_tc_args :: ![Type]
  - dcpc_co :: !Coercion
  - dcpc_args :: ![s]
  }
- data UnboxingDecision unboxing_info
  - = DontUnbox
  - | DoUnbox !unboxing_info
  - | DropAbsent
- canUnboxArg :: FamInstEnvs -> Type -> Demand -> UnboxingDecision (DataConPatContext Demand)
- findTypeShape :: FamInstEnvs -> Type -> TypeShape
- data IsRecDataConResult
  - = DefinitelyRecursive
  - | NonRecursiveOrUnsure
- isRecDataCon :: FamInstEnvs -> IntWithInf -> DataCon -> IsRecDataConResult
- mkAbsentFiller :: WwOpts -> Id -> StrictnessMark -> Maybe CoreExpr
- isWorkerSmallEnough :: Int -> Int -> [Var] -> Bool
- dubiousDataConInstArgTys :: DataCon -> [Type] -> [Type]
- boringSplit :: WwUse
- usefulSplit :: WwUse

# Documentation

data WwOpts Source #

Constructors

MkWwOpts |

Fields

- wo_fam_envs :: !FamInstEnvs

  Environment of type/data family instances

- wo_simple_opts :: !SimpleOpts

  Options for the "Simple optimiser"

- wo_cpr_anal :: !Bool

  Whether to enable "Constructed Product Result" analysis. (Originally from DOI: 10.1017/S0956796803004751)

- wo_module :: !Module

  Used for absent argument error message

- wo_unlift_strict :: !Bool

  Generate workers even if the only effect is some args get passed unlifted. See Note [WW for calling convention]

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] -> [StrictnessMark] -> UniqSM (WwUse, [(Var, StrictnessMark)], CoreExpr -> CoreExpr, [CoreExpr]) Source #

mkWWstr_one :: WwOpts -> Var -> StrictnessMark -> UniqSM (WwUse, [(Var, StrictnessMark)], 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].

data DataConPatContext s 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

`s` will be `Demand` or `Cpr`.

Constructors

DataConPatContext |

Fields

- dcpc_dc :: !DataCon
- dcpc_tc_args :: ![Type]
- dcpc_co :: !Coercion
- dcpc_args :: ![s]

data UnboxingDecision unboxing_info 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

DontUnbox | We ran out of strictness info. Leave untouched.
DoUnbox !unboxing_info | The argument is used strictly or the returned product was constructed, so unbox it.
DropAbsent | The argument/field was absent. Drop it.

#### Instances

Instances details

Outputable i => Outputable (UnboxingDecision i) Source # |
Instance details Defined in GHC.Core.Opt.WorkWrap.Utils Methods ppr :: UnboxingDecision i -> SDoc Source #

canUnboxArg Source #

Arguments

:: FamInstEnvs |
-> Type | Type of the argument
-> Demand | How the arg was used
-> UnboxingDecision (DataConPatContext 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-recursiveness, 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 -> StrictnessMark -> 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 this function "dubious"; only use it where type variables aren't substituted for! Why may the data con bind existentials? See Note [Which types are unboxed?]

boringSplit :: WwUse Source #

WW split not profitable

usefulSplit :: WwUse Source #

WW split profitable