Repository navigation
JIT: Peel offsets from spilled addresses for store decomposition - #85889
Conversation
For a block operation like ``` ▌ ASG struct (copy) ├──▌ BLK struct<System.Nullable`1, 8> │ └──▌ ADD byref │ ├──▌ LCL_VAR ref V00 this │ └──▌ CNS_INT long 40 Fseq[<unknown field>] └──▌ LCL_VAR struct<System.Nullable`1, 8>(P) V06 tmp2 └──▌ bool V06.<unknown class>:hasValue (offs=0x00) -> V12 tmp8 (last use) └──▌ int V06.<unknown class>:value (offs=0x04) -> V13 tmp9 (last use) ``` We would previously spill the ADD(V00, 40) to a local and end up producing: ``` ▌ COMMA void ├──▌ COMMA void │ ├──▌ ASG byref │ │ ├──▌ LCL_VAR byref V15 tmp11 │ │ └──▌ ADD byref │ │ ├──▌ LCL_VAR ref V00 this │ │ └──▌ CNS_INT long 40 Fseq[<unknown field>] │ └──▌ ASG bool │ ├──▌ IND bool │ │ └──▌ LCL_VAR byref V15 tmp11 │ └──▌ LCL_VAR bool V12 tmp8 └──▌ ASG int ├──▌ IND int │ └──▌ ADD byref │ ├──▌ LCL_VAR byref V15 tmp11 │ └──▌ CNS_INT long 4 └──▌ LCL_VAR int V13 tmp9 ``` Instead of this we can include the offsets with the field offsets. In many cases that allows us to avoid any temporary locals, while in other cases it usually allows us to avoid an instruction in favor of two larger containments. In this case we instead end up with: ``` ▌ COMMA void ├──▌ ASG bool │ ├──▌ IND bool │ │ └──▌ ADD byref │ │ ├──▌ LCL_VAR ref V00 this │ │ └──▌ CNS_INT long 40 Fseq[<unknown field>] │ └──▌ LCL_VAR bool V12 tmp8 └──▌ ASG int ├──▌ IND int │ └──▌ ADD byref │ ├──▌ LCL_VAR ref V00 this │ └──▌ CNS_INT long 44 Fseq[<unknown field>, 4] └──▌ LCL_VAR int V13 tmp9 ```
|
Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch Issue DetailsFor a block operation like ▌ ASG struct (copy)
├──▌ BLK struct<System.Nullable`1, 8>
│ └──▌ ADD byref
│ ├──▌ LCL_VAR ref V00 this
│ └──▌ CNS_INT long 40 Fseq[<unknown field>]
└──▌ LCL_VAR struct<System.Nullable`1, 8>(P) V06 tmp2
└──▌ bool V06.<unknown class>:hasValue (offs=0x00) -> V12 tmp8 (last use)
└──▌ int V06.<unknown class>:value (offs=0x04) -> V13 tmp9 (last use)We would previously spill the ADD(V00, 40) to a local and end up producing: ▌ COMMA void
├──▌ COMMA void
│ ├──▌ ASG byref
│ │ ├──▌ LCL_VAR byref V15 tmp11
│ │ └──▌ ADD byref
│ │ ├──▌ LCL_VAR ref V00 this
│ │ └──▌ CNS_INT long 40 Fseq[<unknown field>]
│ └──▌ ASG bool
│ ├──▌ IND bool
│ │ └──▌ LCL_VAR byref V15 tmp11
│ └──▌ LCL_VAR bool V12 tmp8
└──▌ ASG int
├──▌ IND int
│ └──▌ ADD byref
│ ├──▌ LCL_VAR byref V15 tmp11
│ └──▌ CNS_INT long 4
└──▌ LCL_VAR int V13 tmp9Instead of this we can include the offsets with the field offsets. In many cases that allows us to avoid any temporary locals, while in other cases it usually allows us to avoid an instruction in favor of two larger containments. In this case we instead end up with: ▌ COMMA void
├──▌ ASG bool
│ ├──▌ IND bool
│ │ └──▌ ADD byref
│ │ ├──▌ LCL_VAR ref V00 this
│ │ └──▌ CNS_INT long 40 Fseq[<unknown field>]
│ └──▌ LCL_VAR bool V12 tmp8
└──▌ ASG int
├──▌ IND int
│ └──▌ ADD byref
│ ├──▌ LCL_VAR ref V00 this
│ └──▌ CNS_INT long 44 Fseq[<unknown field>, 4]
└──▌ LCL_VAR int V13 tmp9
|
|
/azp run runtime-coreclr jitstress, runtime-coreclr libraries-jitstress, Fuzzlyn |
|
Azure Pipelines successfully started running 3 pipeline(s). |
|
cc @dotnet/jit-contrib PTAL @EgorBo @SingleAccretion. Diffs. Regressions are because:
|
|
Just noting the larger containment "might" be worse in some cases as the optimization manuals cover that there is a "cheap" and "expensive" form of LEA addressing. In particular, memory addressing that has 1 or 2 operands can be dispatched on 2 different ports (1 or 5) and takes 1 cycle, while those that have three operands can only dispatch on a single port (1) and takes 3 cycles. The "expensive" form in particular is:
Don't think its particularly relevant, but might be something for us to keep in mind. |
|
We could anti-preference the allocator from using RBP/R13 for LEA base registers. |
|
If larger offsets are not actually more costly (except for the The |
This sounds like a good/small up for grabs issue.
That case should be fine as its just - add rcx, 16
- mov reg, [rcx+rdx] ; base + scaled-index
+ mov reg, [rcx+rdx+16] ; base + scaled-index + offset |
I see, in that case I don't think this PR should hit problems since it will always be the "base + offset" form. |
|
/azp run runtime-coreclr jitstress, runtime-coreclr libraries-jitstress, Fuzzlyn |
|
Azure Pipelines successfully started running 3 pipeline(s). |
|
Fuzzlyn failure is a macOS spurious failure that did not repro when it tried to reduce it. NAOT timeouts are known. |
For a block operation like
We would previously spill the ADD(V00, 40) to a local and end up producing:
Instead of this we can include the offsets with the field offsets. In many cases that allows us to avoid any temporary locals, while in other cases it usually allows us to avoid an instruction in favor of two larger containments. In this case we instead end up with: