Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.

Struct & SIMD improvements #22255

Merged
merged 4 commits into from
Mar 28, 2019
Merged

Conversation

CarolEidt
Copy link

  • Enable CSE of struct values when handle is available (and add code to get the handle of HW SIMD types)
  • Don't require block nodes for SIMD assignments
  • Don't set GTF_GLOB_REF on GT_OBJ if it is local
  • Set lvRegStruct on promoted SIMD fields
  • Add tests for #19910 (fixed with this PR) and #3539 & #19910 (fixed with Don't struct-promote opaque vectors #21314)
  • Additional cleanup

ArrayStack<GenTree*>& parents,
CORINFO_METHOD_HANDLE callHnd,
void RewriteNodeAsCall(GenTree** use,
Compiler::GenTreeStack& parents,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the change?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm that change is presumably no longer relevant, since I can't see the need for it. At one point I believe I needed to call an existing method that took a GenTreeStack and the compiler didn't think that ArrayStack<GenTree*> was equivalent. In any case it probably makes sense for it to use the typedef'd type.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd keep ArrayStack<GenTree*>. It's not some convoluted template instantiation that warrants the use of a typedef and the GenTreeStack typedef is used only in 3 places so it's best not to add more (and remove it at some point).

@AndyAyersMS
Copy link
Member

Any chance this can CSE the repeated use of Range.Start or Range.End in something like:

public Span<T> this[Range range]
{
get
{
int start = range.Start.FromEnd ? _length - range.Start.Value : range.Start.Value;
int end = range.End.FromEnd ? _length - range.End.Value : range.End.Value;
return Slice(start, end - start);
}
}

@mrange
Copy link

mrange commented Mar 19, 2019

👍 I really hope for this in dotnet 3.0 release.

@CarolEidt
Copy link
Author

I really hope for this in dotnet 3.0 release.

Working on it, and hope to get it in.

- Enable CSE of struct values when handle is available (and add code to get the handle of HW SIMD types)
- Don't require block nodes for SIMD assignments
- Don't set `GTF_GLOB_REF` on `GT_OBJ` if it is local
- Set `lvRegStruct` on promoted SIMD fields
- Add tests for #19910 (fixed with this PR) and #3539 & #19438 (fixed with dotnet#21314)
- Additional cleanup

Fix #19910
@CarolEidt
Copy link
Author

@dotnet-bot test Windows_NT arm64 Cross Checked Innerloop Build and Test

@CarolEidt CarolEidt changed the title [WIP] Struct & SIMD improvements Struct & SIMD improvements Mar 22, 2019
@CarolEidt
Copy link
Author

@dotnet/jit-contrib PTAL

Copy link
Member

@AndyAyersMS AndyAyersMS left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still looking this over, so may have more comments later.

I'm assuming this generates a fair number of diffs, and that you've done some tuning for CSE and similar already.

Can you start characterizing the diffs?

CORINFO_FIELD_HANDLE fieldHnd = fieldSeq->m_fieldHnd;
CorInfoType fieldCorType = info.compCompHnd->getFieldType(fieldHnd, &structHnd);
assert(fieldCorType == CORINFO_TYPE_VALUECLASS);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is similar handle searching logic in gtGetClassHandle -- perhaps factor this out as a helper method?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They're really quite different, and though some logic could be sharable, the ref context seems quite different from the value-type context.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we just get rid of this completly? It seems preferrable to keep GT_OBJ nodes around and extract the struct handle from those instead of attempting to recover handles from GT_IND this way.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that we'd like to get rid of this in the long term, but this code is to deal with cases where we have already made that transformation. I'm going to look into this a bit further, so that I better understand the cases that require this.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, my comment was targeted at long term. Well, maybe not that long, just only after I'm done with #21705 that makes GT_OBJ node "small" and overall cheap.

src/jit/optcse.cpp Show resolved Hide resolved
src/jit/optcse.cpp Show resolved Hide resolved
src/jit/simd.cpp Show resolved Hide resolved
noway_assert(asgType != TYP_STRUCT);
if (varTypeIsStruct(asgType))
{
destLclVarTree = fgIsIndirOfAddrOfLocal(dest);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting, the OperIsBlk() branch above uses impIsAddressInLocal rather than fgIsIndirOfAddrOfLocal. I suspect that using impIsAddressInLocal there is actually incorrect but that's another story.

@CarolEidt
Copy link
Author

I'm assuming this generates a fair number of diffs, and that you've done some tuning for CSE and similar already.

I did a small amount of tuning; more is probably warranted.

Can you start characterizing the diffs?

For x64 windows checked (frameworks + tests):

Total bytes of diff: -41406 (-0.04% of base)
4520 total methods with size differences (4236 improved, 284 regressed), 469768 unchanged.

Most of the diffs are due to not marking things as do-not-enregister and additional CSE's. The biggest impacts are in methods that use SIMD or vector types, but there are also some cases where we enregister promoted (non-SIMD) structs that were previously not enregistered.

There are some regressions (of which I looked at many, but not nearly all), due to CSE'd values that cause spill, extra callee-save reg save/restore in prolog/epilog, and a case where we're doing a tail call (local was previously marked address-exposed when it was only address-taken.

break;
// Rewrite these as GT_IND.
assert(node->TypeGet() == TYP_STRUCT || !use.User()->OperIsInitBlkOp());
RewriteSIMDOperand(use, false);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this would be clearer if the call to RewriteSIMDOperand is wrapped in if (varTypeIsSIMD(node)) like in the GT_IND case. And the // Rewrite these as GT_IND. comment should be inside the if.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Copy link
Member

@AndyAyersMS AndyAyersMS left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looked things over once again and everything I'd comment on seems covered.

@CarolEidt CarolEidt closed this Mar 26, 2019
@CarolEidt CarolEidt reopened this Mar 26, 2019
@CarolEidt
Copy link
Author

@dotnet-bot test Ubuntu x64 Checked CoreFX Tests

@CarolEidt CarolEidt closed this Mar 26, 2019
@CarolEidt CarolEidt reopened this Mar 26, 2019
@mmitche
Copy link
Member

mmitche commented Mar 26, 2019

@dotnet-bot test Windows_NT arm Cross Checked Innerloop Build and Test

@mmitche
Copy link
Member

mmitche commented Mar 26, 2019

@dotnet-bot test Windows_NT arm64 Cross Checked Innerloop Build and Test

Copy link

@sandreenko sandreenko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@CarolEidt
Copy link
Author

@dotnet-bot test Ubuntu arm Cross Checked crossgen_comparison Build and Test
@dotnet-bot test Ubuntu arm Cross Release crossgen_comparison Build and Test

@CarolEidt
Copy link
Author

@dotnet/jit-contrib - any objections to merging this? I can't seem to re-trigger the "Test Pri0 Linux arm checked" that was "Cancelled" and I'm not optimistic that a re-try will address it.

@AndyAyersMS
Copy link
Member

No objection...

@CarolEidt CarolEidt merged commit 3d4a1d5 into dotnet:master Mar 28, 2019
@mrange
Copy link

mrange commented Mar 28, 2019

Cool, how can I test this?

@CarolEidt
Copy link
Author

@mrange - now that this is merged, you can build the coreclr repo and use it. (Instructions here: https://github.com/dotnet/coreclr/blob/master/Documentation/workflow/UsingYourBuild.md)
Or, you can download the daily (I think) build once this has been incorporated here: https://github.com/dotnet/core-sdk and some advice about finding the commit can be found here: https://github.com/dotnet/core-setup/blob/master/Documentation/project-docs/how-to-track-changes.md#what-git-commit-was-a-particular-binary-built-from
Ping me (or post an issue) if you find problems with the documentation.

{
// TODO-1stClassStructs: Previously, spillGlobEffects was set to true for
// GT_INITBLK and GT_COPYBLK, but this is overly conservative, and should be
// revisited. (Note that it was NOT set to true for GT_COPYOBJ.)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was where we were previously always spilling on a non-COPYOBJ block assignment. This was (clearly) overly conservative, but by eliminating this conservatism, I failed to add the struct case to the code in impImportBlockCode (at the SPILL_APPEND: label in importer.cpp) (bug #23545, fixed in PR #23570)

picenka21 pushed a commit to picenka21/runtime that referenced this pull request Feb 18, 2022
* [WIP] Struct & SIMD improvements

- Enable CSE of struct values when handle is available (and add code to get the handle of HW SIMD types)
- Don't require block nodes for SIMD assignments
- Don't set `GTF_GLOB_REF` on `GT_OBJ` if it is local
- Set `lvRegStruct` on promoted SIMD fields
- Add tests for dotnet/coreclr#19910 (fixed with this PR) and dotnet/coreclr#3539 & dotnet/coreclr#19438 (fixed with dotnet/coreclr#21314)
- Additional cleanup

Fix dotnet/coreclr#19910

Commit migrated from dotnet/coreclr@3d4a1d5
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants