-
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 doesn't elide some "this != null" checks when accessing fixed-size buffers in structs #49180
Comments
Seems like Here we have and indir though
but we fail to deduce that
can be optimized away. |
Seems to work out as expected... will kick off more detailed testing. ; V01 arg1 [V01,T01] ( 4, 3.50) int -> rdx
;# V02 OutArgs [V02 ] ( 1, 1 ) lclBlk ( 0) [rsp+0x00] "OutgoingArgSpace"
; V03 tmp1 [V03,T03] ( 3, 2 ) ubyte -> rcx "Inline return value spill temp"
-; V04 tmp2 [V04,T02] ( 3, 4 ) byref -> rcx "Inlining Arg"
+; V04 tmp2 [V04,T02] ( 2, 3 ) byref -> rcx "Inlining Arg"
;
; Lcl frame size = 0
@@ -22,11 +22,10 @@ G_M44576_IG02:
jae SHORT G_M44576_IG04
;; bbWeight=1 PerfScore 3.50
G_M44576_IG03:
- cmp dword ptr [rcx], ecx
mov eax, edx
movzx rcx, byte ptr [rcx+rax]
jmp SHORT G_M44576_IG05
- ;; bbWeight=0.50 PerfScore 3.12
+ ;; bbWeight=0.50 PerfScore 2.12
G_M44576_IG04:
xor ecx, ecx
;; bbWeight=0.50 PerfScore 0.12
@@ -34,7 +33,7 @@ G_M44576_IG05:
jmp Console:WriteLine(int)
;; bbWeight=1 PerfScore 2.00
-; Total bytes of code 29, prolog size 0, PerfScore 11.65, instruction count 10, allocated bytes for code 29 (MethodHash=7cd251df) for method C:M(int):this
+; Total bytes of code 27, prolog size 0, PerfScore 10.45, instruction count 9, allocated bytes for code 27 (MethodHash=7cd251df) for method C:M(int):this |
Note there are likely more places in assertion prop where we miss things by looking at the IR not destructuring the VNs instead. |
In addition to checking for assertions based on the VN of an address, try and destructure the VN to find the "base" address, and check its VNs as well. This lets us get rid of some extra null checks, typically ones that are at an offset from an existing non-null pointer. Closes dotnet#49180.
In addition to checking for assertions based on the VN of an address, try and destructure the VN to find the "base" address, and check its VNs as well. This lets us get rid of some extra null checks, typically ones that are at an offset from an existing non-null pointer. Closes #49180.
When accessing fixed-sized buffers inside a struct's instance methods, the JIT sometimes unnecessarily includes defenses against the case where "this == nullptr". In one-off instance methods this isn't a huge problem, but when calling these instance methods within hot loops it bloats codegen and lowers throughput.
Repro code, demonstrating the problem outside of a loop:
x64 codegen, courtesy SharpLab:
If the helper method is made an instance method of the class which has MyStruct as a field - rather than an instance method of MyStruct itself - the check is properly elided, as shown below.
Moving this logic down is a viable workaround, but it harms code maintainability. It means that I can no longer keep the unsafe code wholly self-contained within the struct. It must instead be split across a few different types, and it leaks implementation details to callers who really shouldn't need to deal with unsafe concepts.
The text was updated successfully, but these errors were encountered: