Skip to content

Commit

Permalink
Update the first class structs document
Browse files Browse the repository at this point in the history
Remove references to things that no longer exist.
  • Loading branch information
SingleAccretion committed Jun 7, 2022
1 parent 6ec53a0 commit c7bc540
Showing 1 changed file with 7 additions and 28 deletions.
35 changes: 7 additions & 28 deletions docs/design/coreclr/jit/first-class-structs.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,6 @@ Current Representation of Struct Values

These struct-typed nodes are created by the importer, but transformed in morph, and so are not
encountered by most phases of the JIT:
* `GT_INDEX`: This is transformed to a `GT_IND`
* Currently, the IND is marked with `GTF_IND_ARR_INDEX` and the node pointer of the `GT_IND` acts as a key
into the array info map.
* Proposed: This should be transformed into a `GT_OBJ` when it represents a struct type, and then the
class handle would no longer need to be obtained from the array info map.
* `GT_FIELD`: This is transformed to a `GT_LCL_VAR` by the `Compiler::fgMarkAddressExposedLocals()` phase
if it's a promoted struct field, or to a `GT_LCL_FLD` or GT_IND` by `fgMorphField()`.
* Proposed: A non-promoted struct typed field should be transformed into a `GT_OBJ`, so that consistently all struct
Expand All @@ -90,9 +85,7 @@ encountered by most phases of the JIT:
### Struct “objects” as lvalues

* The lhs of a struct assignment is a block or local node:
* `GT_OBJ` nodes represent the “shape” info via a struct handle, along with the GC info
(location and type of GC references within the struct).
* These are currently used only to represent struct values that contain GC references (although see below).
* `GT_OBJ` nodes represent struct types with a handle, and store a pointer to the `ClassLayout` object.
* `GT_BLK` nodes represent struct types with no GC references, or opaque blocks of fixed size.
* These have no struct handle, resulting in some pessimization or even incorrect
code when the appropriate struct handle can't be determined.
Expand All @@ -101,12 +94,12 @@ encountered by most phases of the JIT:
[#21705](https://github.com/dotnet/coreclr/pull/21705) they are no longer large nodes.
* `GT_STORE_OBJ` and `GT_STORE_BLK` have the same structure as `GT_OBJ` and `GT_BLK`, respectively
* `Data()` is op2
* `GT_DYN_BLK` and `GT_STORE_DYN_BLK` (GenTreeDynBlk extends GenTreeBlk)
* `GT_STORE_DYN_BLK` (GenTreeStoreDynBlk extends GenTreeBlk)
* Additional child `gtDynamicSize`
* Note that these aren't really struct types; they represent dynamically sized blocks
* Note that these aren't really struct stores; they represent dynamically sized blocks
of arbitrary data.
* For `GT_LCL_FLD` nodes, we don't retain shape information, except indirectly via the `FieldSeqNode`.
* For `GT_LCL_VAR` nodes, the`ClassLayout` is obtained from the `LclVarDsc`.
* For `GT_LCL_FLD` nodes, we store a pointer to `ClassLayout` in the node.
* For `GT_LCL_VAR` nodes, the `ClassLayout` is obtained from the `LclVarDsc`.

### Struct “objects” as rvalues

Expand All @@ -131,10 +124,6 @@ After morph, a struct-typed value on the RHS of assignment is one of:
* `GT_CALL`
* `GT_LCL_VAR`
* `GT_LCL_FLD`
* Note: With `compDoOldStructRetyping()`, a GT_LCL_FLD` with a primitive type of the same size as the struct
is used to represent a reference to the full struct when it is passed in a register.
This forces the struct to live on the stack, and makes it more difficult to optimize these struct values,
which is why this mechanism is being phased out.
* `GT_SIMD`
* `GT_OBJ` nodes can also be used as rvalues when they are call arguments
* Proposed: `GT_OBJ` nodes can be used in any context where a struct rvalue or lvalue might occur,
Expand Down Expand Up @@ -173,8 +162,7 @@ There are three main phases in the JIT that make changes to the representation o
registers. The necessary transformations for correct code generation would be
made in `Lowering`.

* With `compDoOldStructRetyping()`, if it is passed in a single register, it is morphed into a
`GT_LCL_FLD` node of the appropriate primitive type.
* If it is passed in a single register, it is morphed into a `GT_LCL_FLD` node of the appropriate primitive type.
* This may involve making a copy, if the size cannot be safely loaded.
* Proposed: This would remain a `GT_OBJ` and would be appropriately transformed in `Lowering`,
e.g. using `GT_BITCAST`.
Expand Down Expand Up @@ -310,22 +298,13 @@ This would be enabled first by [Defer ABI-specific transformations to Lowering](
for block copies. See [\#21711 Improve init/copy block codegen](https://github.com/dotnet/coreclr/pull/21711).

* This also includes cleanup of the block morphing methods such that block nodes needn't be visited multiple
times, such as `fgMorphBlkToInd` (may be simply unneeded), `fgMorphBlkNode` and `fgMorphBlkOperand`.
times, such as `fgMorphBlkNode` and `fgMorphBlkOperand`.
These methods were introduced to preserve old behavior, but should be simplified.

* Somewhat related is the handling of struct-typed array elements. Currently, after the `GT_INDEX` is transformed
into a `GT_IND`, that node must be retained as the key into the `ArrayInfoMap`. For structs, this is then
wrapped in `OBJ(ADDR(...))`. We should be able to change the IND to OBJ and avoid wrapping, and should also be
able to remove the class handle from the array info map and instead used the one provided by the `GT_OBJ`.

### Miscellaneous Cleanup

These are all marked with `TODO-1stClassStructs` or `TODO-Cleanup` in the last case:

* The handling of `DYN_BLK` is unnecessarily complicated to duplicate previous behavior (i.e. to enable previous
refactorings to be zero-diff). These nodes are infrequent so the special handling should just be eliminated
(e.g. see `GenTree::GetChild()`).

* The checking at the end of `gtNewTempAssign()` should be simplified.

* When we create a struct assignment, we use `impAssignStruct()`. This code will, in some cases, create
Expand Down

0 comments on commit c7bc540

Please sign in to comment.