Note [CBV Function Ids]

GHC/Types/Id/Info.hs:251 compiler

A WorkerLikeId essentially allows us to constrain the calling convention
for the given Id. Each such Id carries with it a list of CbvMarks
with each element representing a value argument. Arguments who have
a matching `MarkedCbv` entry in the list need to be passed evaluated+*properly tagged*.

CallByValueFunIds give us additional expressiveness which we use to improve
runtime. This is all part of the EPT enforcement work. See also Note [EPT enforcement].

They allows us to express the fact that an argument is not only evaluated to WHNF once we
entered it's RHS but also that an lifted argument is already *properly tagged* once we jump
into the RHS.
This means when e.g. branching on such an argument the RHS doesn't needed to perform
an eval check to ensure the argument isn't an indirection. All seqs on such an argument in
the functions body become no-ops as well.

The invariants around the arguments of call by value function like Ids are then:

* In any call `(f e1 .. en)`, if `f`'s i'th argument is marked `MarkedCbv`,
  then the caller must ensure that the i'th argument
  * points directly to the value (and hence is certainly evaluated before the call)
  * is a properly tagged pointer to that value

* The following functions (and only these functions) have `CbvMarks`:
  * Any `WorkerLikeId`
  * Some `JoinId` bindings.

This works analogous to the EPT Invariant. See also Note [EPT enforcement].

To make this work what we do is:
* During W/W and SpecConstr any worker/specialized binding we introduce
  is marked as a worker binding by `asWorkerLikeId`.
* W/W and SpecConstr further set OtherCon[] unfoldings on arguments which
  represent contents of a strict fields.
* During Tidy we look at all bindings.
  For any callByValueLike Id and join point we mark arguments as cbv if they
  Are strict. We don't do so for regular bindings.
  See Note [Use CBV semantics only for join points and workers] for why.
  We might have made some ids rhs *more* strict in order to make their arguments
  be passed CBV. See Note [Call-by-value for worker args] for why.
* During CorePrep calls to CallByValueFunIds are eta expanded.
* During Stg CodeGen:
  * When we see a call to a callByValueLike Id:
    * We check if all arguments marked to be passed unlifted are already tagged.
    * If they aren't we will wrap the call in case expressions which will evaluate+tag
      these arguments before jumping to the function.
* During Cmm codeGen:
  * When generating code for the RHS of a StrictWorker binding
    we omit tag checks when using arguments marked as tagged.

We only use this for workers and specialized versions of SpecConstr
But we also check other functions during tidy and potentially turn some of them into
call by value functions and mark some of their arguments as call-by-value by looking at
argument unfoldings.

NB: I choose to put the information into a new Id constructor since these are loaded
at all optimization levels. This makes it trivial to ensure the additional
calling convention demands are available at all call sites. Putting it into
IdInfo would require us at the very least to always decode the IdInfo
just to decide if we need to throw it away or not after.

References 3

Referenced by 23