Uh oh!
There was an error while loading. Please reload this page.
JIT: Extend escape analysis to account for arrays with non-gcref elements - #104906
Conversation
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
AndyAyersMS
left a comment
There was a problem hiding this comment.
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.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
| #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.
I removed R2R support more completely
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
| 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.
| 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.
Ditto below, more things can switch to use fgNewStmtFromTree
Uh oh!
There was an error while loading. Please reload this page.
| @@ -181,6 +254,11 @@ inline bool ObjectAllocator::CanAllocateLclVarOnStack(unsigned int lclNu | |||
| return false; | |||
| } | |||
There was a problem hiding this comment.
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.
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.
Does this actually show up as benefits?
There was a problem hiding this comment.
In some limited cases, yes... eg we can const propagate through a[2] = 1; y = a[2];
AndyAyersMS
commented
Jan 21, 2025
@jakobbotsch think I've addressed most of the key points. Overall size limit will come in a future PR. |
jakobbotsch
commented
Jan 22, 2025
@AndyAyersMS Did you push those changes? |
AndyAyersMS
commented
Jan 22, 2025
Ah, I pushed to my fork, but ... this PR is not from my fork. |
AndyAyersMS
commented
Jan 22, 2025
@jakobbotsch changes are there now |
| GTF_CALL_M_CAST_CAN_BE_EXPANDED = 0x04000000, // this cast (helper call) can be expanded if it's profitable. To be removed. | ||
| GTF_CALL_M_CAST_OBJ_NONNULL = 0x08000000, // if we expand this specific cast we don't need to check the input object for null | ||
| // NOTE: if needed, this flag can be removed, and we can introduce new _NONNUL cast helpers | ||
| GTF_CALL_M_STACK_ARRAY = 0x10000000, // this call is a new array helper for a stack allocated array. |
There was a problem hiding this comment.
I suppose we weren't able to get rid of this since it's also used in VN.
| // modHeap = false; | ||
| } | ||
| else if (vnf == VNF_JitReadyToRunNewArr) | ||
| { | ||
| vnf = VNF_JitReadyToRunNewLclArr; | ||
| // modHeap = false; |
There was a problem hiding this comment.
Nit: commented code (feel free to remove as part of a follow up)
| } | ||
| } | ||
| if (isAlloc && ((call->gtCallMoreFlags & GTF_CALL_M_STACK_ARRAY) != 0)) |
There was a problem hiding this comment.
I suppose this could be changed to FindWellKnownArg(StackArrayLocal) != nullptr to get rid of the flag
AndyAyersMS
commented
Jan 22, 2025
Thanks. I have more changes in this area so I can handle the last few bits in a subsequent PR. |
AndyAyersMS
commented
Jan 22, 2025
@hez2010 thanks for all the work you did here. |
Positive case:
Codegen:
Negative case:
Codegen:
Benchmark on Mandelbrot:
Diff: https://www.diffchecker.com/bNP4qHdF/