ghc-lib-9.4.3.20221104: The GHC API, decoupled from GHC versions
Safe HaskellSafe-Inferred
LanguageHaskell2010

GHC.Core.Opt.WorkWrap.Utils

Synopsis

Documentation

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.

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

Inserts a `Void#` arg before the first argument.

Why as the first argument? See Note [SpecConst needs to add void args first] in SpecConstr.

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 

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.

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

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 -> 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.

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!