Repository navigation
JIT: raise the cost of ReadyToRun generic lookups - #136731
Conversation
…locks Loop hoisting only hoists trees from blocks that are not executed on every iteration when their cost is at least IND_COST_EX * 16. Runtime lookup helper calls (CORINFO_HELP_READYTORUN_GENERIC_HANDLE, CORINFO_HELP_RUNTIMEHANDLE_*) are costed like cheap calls, so loop-invariant generic dictionary lookups in such blocks stayed in the loop. Exempt these helpers from the speculative cost gate outside of NativeAOT. They are modeled as pure and non-throwing, and CoreCLR already reports type load failures early for unshared code. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
Azure Pipelines: Successfully started running 5 pipeline(s). 10 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
|
Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch |
…erCall Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…isting gate Replace the hoisting exemption with a higher cost for CORINFO_HELP_READYTORUN_GENERIC_HANDLE calls outside of NativeAOT. JIT-mode RUNTIMEHANDLE_* lookups are no longer affected. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
On targets with a JIT, hot R2R methods tier up, so this mostly affects startup code. Locally, the final Tier1 crossgen2 already knows which case it's compiling for ( Note This comment was generated with GitHub Copilot. |
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
NativeAOT compiles generic lookups it failed to build into helpers that throw when invoked, so CORINFO_HELP_READYTORUN_GENERIC_HANDLE is not exception-free there. Report it as throwing through GenTreeCall::CallExceptions, and use that for side effects, hoisting and value numbering. Value numbering gives the exception a value determined by the lookup, so identical lookups can still be CSEd. With the exception modeled, the lookup cost no longer needs an ABI check. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
AndyAyersMS
left a comment
There was a problem hiding this comment.
Instead of introducing a new CallExceptions can't we just fold the NAOT behavior into the existing helper call properties?
Move the NativeAOT special case out of GenTreeCall::CallExceptions into the helper call property table. HelperCallProperties now keeps a NativeAOT exception set alongside the default one, and NoThrow/ThrownExceptions take the ABI. Consumers query the table directly again. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
@AndyAyersMS done in db4999f. Note This reply was generated with GitHub Copilot. |
| isPure = true; | ||
| exceptions = ExceptionSetFlags::None; | ||
| nonNullReturn = true; | ||
| // NativeAOT compiles generic lookups it failed to build into helpers that throw when invoked. |
There was a problem hiding this comment.
This does not look accurate. Regular CoreCLR can throw from this helper as well, for similar reasons as NAOT. This helper calls TypeLoader that can fail for myriad of reasons.
What is this special casing trying to achieve? What would break if the helper is annotated same way on both runtimes?
Loop hoisting only hoists a tree from a block that doesn't run on every iteration when it costs at least
IND_COST_EX * 16.READYTORUN_GENERIC_HANDLEcalls are costed like any other call, although each one calls a helper that performs a generic dictionary lookup, so loop-invariant lookups stay in the loop.SpanHelpers.IndexOfAny<__Canon>makes two lookup calls per iteration in browser-wasm R2R code. This raises their cost.The helper is modeled as non-throwing. That holds for CoreCLR, which already reports type-load failures early for unshared code (at JIT time or in R2R method-entry fixups). NativeAOT instead compiles lookups it couldn't build into helpers that throw when called, so on NativeAOT the call is now reported as throwing, for side effects, hoisting and value numbering. The exception's value number is derived from the lookup, so identical lookups still CSE. SuperPMI shows no NativeAOT diffs.
Measured on browser-wasm R2R (Checked runtime),
IndexOfAny<string>is 2–4% faster; osx-arm64 Release shows no measurable change.Resolves #136723
Note
This PR description was generated with GitHub Copilot.