summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Klebinger <klebinger.andreas@gmx.at>2022-02-28 12:16:12 +0100
committerAndreas Klebinger <klebinger.andreas@gmx.at>2022-03-07 10:38:11 +0000
commit239fa853563977e05f46b4bc008e954b05963a1b (patch)
treeb6f22534f59fd9699d9c2db00af73409ec37bc40
parent706deee0524ca6af26c8b8d5cff17a6e401a2c18 (diff)
downloadhaskell-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.hs4
-rw-r--r--compiler/GHC/Types/Id/Info.hs25
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