diff options
author | Andreas Klebinger <klebinger.andreas@gmx.at> | 2022-02-28 12:16:12 +0100 |
---|---|---|
committer | Andreas Klebinger <klebinger.andreas@gmx.at> | 2022-03-07 10:38:11 +0000 |
commit | 239fa853563977e05f46b4bc008e954b05963a1b (patch) | |
tree | b6f22534f59fd9699d9c2db00af73409ec37bc40 | |
parent | 706deee0524ca6af26c8b8d5cff17a6e401a2c18 (diff) | |
download | haskell-239fa853563977e05f46b4bc008e954b05963a1b.tar.gz |
Expand and improve the Note [Strict Worker Ids].wip/andreask/docs_sfi
I've added an explicit mention of the invariants surrounding those. As well as adding
more direct cross references to the Strict Field Invariant.
-rw-r--r-- | compiler/GHC/Stg/InferTags.hs | 4 | ||||
-rw-r--r-- | compiler/GHC/Types/Id/Info.hs | 25 |
2 files changed, 24 insertions, 5 deletions
diff --git a/compiler/GHC/Stg/InferTags.hs b/compiler/GHC/Stg/InferTags.hs index 2a42b4c7de..79acaa14f5 100644 --- a/compiler/GHC/Stg/InferTags.hs +++ b/compiler/GHC/Stg/InferTags.hs @@ -82,6 +82,8 @@ and will be tagged with `001` or `010` respectively. It will never point to a thunk, nor will it be tagged `000` (meaning "might be a thunk"). NB: Note that the proper tag for some objects is indeed `000`. Currently this is the case for PAPs. +This works analogous to how `StrictWorkerId`s work. See also Note [Strict Worker Ids]. + Why do we care? Because if we have code like: case strictPair of @@ -119,6 +121,8 @@ evaluated will allocate the constructor. So we do our best to establish that `x` is already tagged (which it almost always is) to avoid this cost. In my benchmarks I haven't seen any cases where this causes regressions. +Note that there are similar constraints around Note [Strict Worker Ids]. + Note [How untagged pointers can end up in strict fields] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Consider diff --git a/compiler/GHC/Types/Id/Info.hs b/compiler/GHC/Types/Id/Info.hs index 670935251a..4bbf0ba86f 100644 --- a/compiler/GHC/Types/Id/Info.hs +++ b/compiler/GHC/Types/Id/Info.hs @@ -178,6 +178,8 @@ data IdDetails | JoinId JoinArity (Maybe [CbvMark]) -- ^ An 'Id' for a join point taking n arguments -- Note [Join points] in "GHC.Core" + -- Can also work as a StrictWorkerId if given `CbvMark`s. + -- See Note [Strict Worker Ids] | StrictWorkerId [CbvMark] -- ^ An 'Id' for a worker function, which expects some arguments to be -- passed both evaluated and tagged. @@ -186,11 +188,11 @@ data IdDetails {- Note [Strict Worker Ids] ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -StrictWorkerId essentially constrains the calling convention for the given Id. -It requires arguments marked as tagged to be passed properly evaluated+*tagged*. +A StrictWorkerId essentially constrains the calling convention for the given Id. +It requires arguments marked as `MarkedCbv` to be passed evaluated+*properly tagged*. -While we were always able to express the fact that an argument is evaluated -via attaching a evaldUnfolding to the functions arguments there used to be +While we were always able to express the fact that an argument is evaluated once we +entered it's RHS via attaching a evaldUnfolding to it there used to be no way to express that an lifted argument is already properly tagged once we jump into the RHS. This means when branching on a value the RHS always needed to perform @@ -200,7 +202,20 @@ already ruling out thunks). StrictWorkerIds give us this additional expressiveness which we use to improve runtime. This is all part of the TagInference work. See also Note [Tag Inference]. -What we do is: +The invariants around the arguments of Strict Worker 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 `StrictWorkerId` + * Some `JoinId` bindings. + +This works analogous to the Strict Field Invariant. See also Note [Strict Field Invariant]. + +To make this work what we do is: * If we think a function might benefit from passing certain arguments unlifted for performance reasons we attach an evaldUnfolding to these arguments. * Either during W/W, but at latest during Tidy VanillaIds with arguments that |