-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
JIT: Extend escape analysis to account for arrays with non-gcref elements #104906
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For arrays (and also perhaps boxes and ref classes) we ought to have some kind of size limit... possibly similar to the one we use for stackallocs.
We need to be careful we don't allocate a lot of stack for an object that might not be heavily used, as we'll pay per-call prolog zeroing costs.
…-array-stack-alloc
Merged in the changes from #111284. |
@dotnet/jit-contrib PTAL SPMI will be fairly accurate here... kicked off another collection which should have even fewer misses. Code size increases but mostly from clr test where small fixed-sized arrays are unusually frequent.
a[0] = 3;
f();
= a[0];
|
Seeing AVs in osx crossgen2, oddly in both base and diff jits:
Will try and look at this locally |
Failing here:
Looks like this map should always be present since morph always calls Tolerating this in #111555. |
Merged the main branch to include #111555. |
Try a late dead store removal |
@AndyAyersMS Just experimented a bit with late dead stores removal by unexposing locals in the liveness and repeating to convergence: commit Before adding late dead stores removal: diffs Relative diffs:
Diffs look interesting but TP impacts are too high. Now I'm reverting the experiment commit. |
3450580
to
1915450
Compare
@jakobbotsch can you look this one over again? |
src/coreclr/jit/objectalloc.cpp
Outdated
#ifdef FEATURE_READYTORUN | ||
if (comp->opts.IsReadyToRun() && data->IsHelperCall(comp, CORINFO_HELP_READYTORUN_NEWARR_1)) | ||
{ | ||
len = data->AsCall()->gtArgs.GetArgByIndex(0)->GetNode(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dead code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I removed R2R support more completely
src/coreclr/jit/helperexpansion.cpp
Outdated
GenTree* const mtStore = gtNewStoreLclFldNode(lclNum, TYP_I_IMPL, 0, mt); | ||
Statement* const mtStmt = gtNewStmt(mtStore); | ||
|
||
fgInsertStmtBefore(block, newStmt, mtStmt); | ||
gtSetStmtInfo(mtStmt); | ||
fgSetStmtSeq(mtStmt); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GenTree* const mtStore = gtNewStoreLclFldNode(lclNum, TYP_I_IMPL, 0, mt); | |
Statement* const mtStmt = gtNewStmt(mtStore); | |
fgInsertStmtBefore(block, newStmt, mtStmt); | |
gtSetStmtInfo(mtStmt); | |
fgSetStmtSeq(mtStmt); | |
GenTree* const mtStore = gtNewStoreLclFldNode(lclNum, TYP_I_IMPL, 0, mt); | |
Statement* const mtStmt = fgNewStmtFromTree(mtStore); | |
fgInsertStmtBefore(block, newStmt, mtStmt); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto below, more things can switch to use fgNewStmtFromTree
@@ -181,6 +254,11 @@ inline bool ObjectAllocator::CanAllocateLclVarOnStack(unsigned int lclNu | |||
return false; | |||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like we should have a limit on the aggregate stack allocated size. That's somewhat preexisting, but probably more important now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree but will do that in a future PR
// If this is a local array, there are no asyncronous modifications, so we can set the | ||
// conservative VN to the liberal VN. | ||
// | ||
VNFuncApp arrFn; | ||
if (vnStore->IsVNNewLocalArr(arrVN, &arrFn)) | ||
{ | ||
loadTree->gtVNPair.SetConservative(loadValueVN); | ||
} | ||
else | ||
{ | ||
loadTree->gtVNPair.SetConservative(vnStore->VNForExpr(compCurBB, loadType)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this actually show up as benefits?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In some limited cases, yes... eg we can const propagate through a[2] = 1; y = a[2];
@jakobbotsch think I've addressed most of the key points. Overall size limit will come in a future PR. |
@AndyAyersMS Did you push those changes? |
Ah, I pushed to my fork, but ... this PR is not from my fork. |
@jakobbotsch changes are there now |
Positive case:
Codegen:
Negative case:
Codegen:
Benchmark on Mandelbrot:
Diff: https://www.diffchecker.com/bNP4qHdF/