- Notifications
You must be signed in to change notification settings - Fork5.3k
JIT: enable removal of try/catch if the try can't throw.#110273
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Conversation
If no tree in the try region of a try/catch can throw, thenwe can remove the try and delete the catch.If no tree in the try region of a try/finally can throw, we canremove the try and inline the finally. This slightly generalizesthe empty-try/finally opt we have been doing for a long time.(We should do something similar for try/fault, but don't, yet).Since these optimization passes are cheap, and opportunitiesfor them arise after other optimizations and unblock subsequentoptimizations, run them early, middle, and late.Resolvesdotnet#107191.I expect we'll see more of these cases in the future, say ifwe unblock cloning of loops with EH.
AndyAyersMS commentedNov 29, 2024
@EgorBo PTAL Note we are trusting |
src/coreclr/jit/fgehopt.cpp Outdated
| if (hadDfs) | ||
| { | ||
| fgInvalidateDfsTree(); | ||
| m_dfsTree =fgComputeDfs(); | ||
| if (hadLoops) | ||
| { | ||
| m_loops =FlowGraphNaturalLoops::Find(m_dfsTree); | ||
| } | ||
| } |
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 unnecessary to recompute this in each of the phases. Maybe combine it into one phase, or make the actual phase that needs these annotations compute them if they aren't computed when we get there?
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.
moved recomputation later (to doms for dfs, vn for loops).
VSadov commentedNov 29, 2024
Just wondering - We used to have some special meaning for code in finally with respect to ThreadAbort. Is that no longer a thing or still somehow maintained when finally is inlined? |
MichalPetryka commentedNov 29, 2024
AFAIR all the handling for that was removed. |
AndyAyersMS commentedNov 30, 2024
That is only an issue for .NET Framework. Removal of empty-try / finally has been in .NET Core since 2.x, this just extends it a bit further to some trys that are not empty. |
VSadov commentedNov 30, 2024
I remember long time ago we could do similar optimizations in Roslyn, in theory, but in practice we could not. |
AndyAyersMS commentedNov 30, 2024
On x86 we have callfinallys within the try. In this case inside the try/finally there is a try/catch that returns from the catch, so must invoke the outer finally, thus there is a callfinally pair in the catch. Here T0 is empty and we're trying to remove it and H0. But there is a pred edge into the middle of H0/BB15 from an outside region (BB07), which is not something my simple-minded handler removal code supports yet. |
AndyAyersMS commentedNov 30, 2024
/azp run runtime-coreclr jitstress |
| Azure Pipelines successfully started running 1 pipeline(s). |
7ccf491 intodotnet:mainUh oh!
There was an error while loading.Please reload this page.
If no tree in the try region of a try/catch can throw, thenwe can remove the try and delete the catch.If no tree in the try region of a try/finally can throw, we canremove the try and inline the finally. This slightly generalizesthe empty-try/finally opt we have been doing for a long time.(We should do something similar for try/fault, but don't, yet).Since these optimization passes are cheap, and opportunitiesfor them arise after other optimizations and unblock subsequentoptimizations, run them early, middle, and late.Resolvesdotnet#107191.I expect we'll see more of these cases in the future, say ifwe unblock cloning of loops with EH.
hez2010 commentedDec 5, 2024 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
With this both voidTest1(){varx=42;varz=52;try{vary=14;z=x+y;}finally{Console.WriteLine(z);}}voidTest2(){varx=42;varz=52;try{vary=14;z=x+y;}catch{}Console.WriteLine(z);} codegen: G_M27646_IG01: ;; offset=0x0000;; size=0 bbWeight=1 PerfScore 0.00G_M27646_IG02: ;; offset=0x0000movedi,56;; size=5 bbWeight=1 PerfScore 0.25G_M27646_IG03: ;; offset=0x0005 tail.jmp[System.Console:WriteLine(int)];; size=6 bbWeight=1 PerfScore 2.00 But the codegen of voidTest3(){varx=42;varz=52;try{vary=14;z=x+y;}catch{}finally{Console.WriteLine(z);}} codegen: G_M27646_IG01: ;; offset=0x0000pushrbpsubrsp,16learbp,[rsp+0x10]mov qword ptr[rbp-0x10],rsp;; size=14 bbWeight=1 PerfScore 2.75G_M27646_IG02: ;; offset=0x000Emov dword ptr[rbp-0x04],52;; size=7 bbWeight=1 PerfScore 1.00G_M27646_IG03: ;; offset=0x0015mov dword ptr[rbp-0x04],56;; size=7 bbWeight=1 PerfScore 1.00G_M27646_IG04: ;; offset=0x001Cmovedi,56call[System.Console:WriteLine(int)]nop;; size=12 bbWeight=1 PerfScore 3.50G_M27646_IG05: ;; offset=0x0028addrsp,16poprbpret;; size=6 bbWeight=1 PerfScore 1.75G_M27646_IG06: ;; offset=0x002Epushrbpsubrsp,16movrbp, qword ptr[rdi]mov qword ptr[rsp],rbplearbp,[rbp+0x10];; size=16 bbWeight=0 PerfScore 0.00G_M27646_IG07: ;; offset=0x003Emovedi, dword ptr[rbp-0x04]call[System.Console:WriteLine(int)]nop;; size=10 bbWeight=0 PerfScore 0.00G_M27646_IG08: ;; offset=0x0048addrsp,16poprbpret;; size=6 bbWeight=0 PerfScore 0.00 /cc:@AndyAyersMS |
AndyAyersMS commentedDec 6, 2024
This turns into a try-catch inside a try-finally. We remove the try-catch and convert the try-finally to a try-fault. But we haven't yet implemented (empty)try-fault removal. |
AndyAyersMS commentedDec 6, 2024
Seems like this is actually simple to handle; I'll put up a PR shortly. |
If no tree in the try region of a try/catch can throw, thenwe can remove the try and delete the catch.If no tree in the try region of a try/finally can throw, we canremove the try and inline the finally. This slightly generalizesthe empty-try/finally opt we have been doing for a long time.(We should do something similar for try/fault, but don't, yet).Since these optimization passes are cheap, and opportunitiesfor them arise after other optimizations and unblock subsequentoptimizations, run them early, middle, and late.Resolvesdotnet#107191.I expect we'll see more of these cases in the future, say ifwe unblock cloning of loops with EH.
If no tree in the try region of a try/catch can throw, then we can remove the try and delete the catch.
If no tree in the try region of a try/finally can throw, we can remove the try and inline the finally. This slightly generalizes the empty-try/finally opt we have been doing for a long time. (We should do something similar for try/fault, but don't, yet).
Since these optimization passes are cheap, and opportunities for them arise after other optimizations and unblock subsequent optimizations, run them early, middle, and late.
Resolves#107191.
I expect we'll see more of these cases in the future, say if we unblock cloning of loops with EH.