-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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
Consider CALLFINALLY block as pred of finally block during assertion props #55674
Conversation
@dotnet/jit-contrib , @sandreenko |
It seems to me like the issue is that jump threading is creating unexpected flow. It seems like we should prevent it from doing so, instead of fixing the general dataflow algorithm. In particular, there is an assumption that a handler is only reachable from the |
I see what you mean. Let me investigate it further. |
Jump threading is already checking that the flow it creates lies entirely within the same EH region. I'd need to look closer to see why that's not a sufficient constraint. |
I think this is the |
That is correct. For runtime/src/coreclr/jit/jiteh.cpp Lines 4115 to 4118 in bd9d4e0
Relevant portion from JITDUMP:
Earlier, we used to check all the preds of a finally block, but #160 optimized it to just restrict it to try's first/last block. I briefly try to see if it eliminates the range check which the PR claimed to do, but I don't see any difference. @sandreenko , is my repro code correct? It's a different issue why range check is not eliminated here. private static int Issue_55131()
{
int[] array = new int[100];
int i = 0;
int result = 0;
while (i < 100)
{
try
{
result += i;
}
catch (IndexOutOfRangeException)
{
array[i] = i; // < -that bounds check can't be eliminated without that change.
}
array[i] = i; // < -that bounds check can't be eliminated without that change.
i++;
}
return result;
} Assembly code; Assembly listing for method MiniBench.Program:Issue_55131():int
; Emitting BLENDED_CODE for X64 CPU with AVX - Windows
; optimized code
; rbp based frame
; fully interruptible
; No PGO data
; Final local variable assignments
;
; V00 loc0 [V00,T02] ( 3, 8 ) ref -> [rbp-10H] class-hnd exact EH-live single-def
; V01 loc1 [V01,T00] ( 11, 53 ) int -> [rbp-04H] do-not-enreg[Z] EH-live
; V02 loc2 [V02,T01] ( 4, 10 ) int -> [rbp-08H] do-not-enreg[Z] EH-live
; V03 OutArgs [V03 ] ( 1, 1 ) lclBlk (32) [rsp+00H] "OutgoingArgSpace"
;* V04 tmp1 [V04 ] ( 0, 0 ) ref -> zero-ref class-hnd "impSpillSpecialSideEff"
; V05 PSPSym [V05 ] ( 1, 1 ) long -> [rbp-20H] do-not-enreg[X] addr-exposed "PSPSym"
;
; Lcl frame size = 64
G_M42278_IG01:
push rbp
sub rsp, 64
lea rbp, [rsp+40H]
mov qword ptr [rbp-20H], rsp
;; bbWeight=1 PerfScore 2.75
G_M42278_IG02:
mov rcx, 0xD1FFAB1E
mov edx, 100
call CORINFO_HELP_NEWARR_1_VC
mov gword ptr [rbp-10H], rax
xor edx, edx
mov dword ptr [rbp-04H], edx
mov dword ptr [rbp-08H], edx
;; bbWeight=1 PerfScore 4.75
G_M42278_IG03:
mov edx, dword ptr [rbp-08H]
add edx, dword ptr [rbp-04H]
mov dword ptr [rbp-08H], edx
;; bbWeight=4 PerfScore 12.00
G_M42278_IG04:
cmp dword ptr [rbp-04H], 100
jae SHORT G_M42278_IG07
mov eax, dword ptr [rbp-04H]
movsxd rax, eax
mov edx, dword ptr [rbp-04H]
mov rcx, gword ptr [rbp-10H]
mov dword ptr [rcx+4*rax+16], edx
mov eax, dword ptr [rbp-04H]
inc eax
mov dword ptr [rbp-04H], eax
cmp dword ptr [rbp-04H], 100
mov rax, rcx
jl SHORT G_M42278_IG03
;; bbWeight=8 PerfScore 86.00
G_M42278_IG05:
mov eax, dword ptr [rbp-08H]
;; bbWeight=1 PerfScore 1.00
G_M42278_IG06:
add rsp, 64
pop rbp
ret
;; bbWeight=1 PerfScore 1.75
G_M42278_IG07:
call CORINFO_HELP_RNGCHKFAIL
int3
;; bbWeight=0 PerfScore 0.00
G_M42278_IG08:
push rbp
sub rsp, 48
mov rbp, qword ptr [rcx+32]
mov qword ptr [rsp+20H], rbp
lea rbp, [rbp+40H]
;; bbWeight=0 PerfScore 0.00
G_M42278_IG09:
cmp dword ptr [rbp-04H], 100
jae SHORT G_M42278_IG11
mov eax, dword ptr [rbp-04H]
movsxd rax, eax
mov edx, dword ptr [rbp-04H]
mov rcx, gword ptr [rbp-10H]
mov dword ptr [rcx+4*rax+16], edx
lea rax, G_M42278_IG04
;; bbWeight=0 PerfScore 0.00
G_M42278_IG10:
add rsp, 48
pop rbp
ret
;; bbWeight=0 PerfScore 0.00
G_M42278_IG11:
call CORINFO_HELP_RNGCHKFAIL
int3
;; bbWeight=0 PerfScore 0.00
; Total bytes of code 170, prolog size 14, PerfScore 125.25, instruction count 51, allocated bytes for code 170 (MethodHash=b4be5ad9) for method MiniBench.Program:Issue_55131():int This PR still retains the optimization(?) made in #160 but also fix the correctness issue to consider |
We could also try and leverage Or perhaps more simply, disable jump threading for the first block of a try (either always, or only under |
Yes, it effectively realizes the try is empty and so all that will happen on entry to the try is a handler invocation, and so that's the flow it sets up. |
I'm fine with this change or with inhibiting jump threading. I have a slight preference for this change as it seems risky to simply assume flow can't reach a handler if we actually see that it can. If we go the inhibit route we should add suitable assertion checking to make sure nothing else can cause this. |
I disable the jump threading for first block of try. However, we should continue to keep the changes in dataflow because there might be other codepaths that makes the flowgraph of having a jump to |
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.
We don't need (and shouldn't have) the dataflow changes.
Instead, I've written an assert that should cover preventing the problematic case: #55858
I think in that case, I should just add an assert in dataflow to make sure we don't see such flows. |
In #160, we started considering only first and last block of try for calculating assertions of finally block. However, we should also consider the assertion out of CALLFINALLY block.
No asmdiffs.
Fixes: #55131