Skip to content

C# compiler generates highly suboptimal code for compound assignments with struct ref variables #100008

@uio139021

Description

@uio139021

Description

When working on my program performance optimization and inspecting the generated code, I came across the following issue. Here is a small piece of C# code and what it gets compiled into:
`
S s = default;

ref int r = ref s.i;

r += 1;
r = r + 1;

ref S rs = ref s;

rs.i += 1; // this line generates some stupid machine code (esp. 'cmp' opcode)
rs.i = rs.i + 1; // while this line compiles perfectly

s.i += 1; // this allocates a redundant var on stack
s.i = s.i + 1; // ok

public struct S
{
public int i;
}
`

The Disassembly output shows this:
`
ref int r = ref s.i;
00007FF9DC807164 lea rcx,[rbp+48h]
00007FF9DC807168 mov qword ptr [rbp+40h],rcx

r += 1;
00007FF9DC80716C mov rcx,qword ptr [rbp+40h]
00007FF9DC807170 inc dword ptr [rcx]
r = r + 1;
00007FF9DC807172 mov rcx,qword ptr [rbp+40h]
00007FF9DC807176 inc dword ptr [rcx]

ref S rs = ref s;
00007FF9DC807178 lea rcx,[rbp+48h]
00007FF9DC80717C mov qword ptr [rbp+38h],rcx

rs.i += 1; // this line generates some stupid machine code (esp. 'cmp' opcode)
00007FF9DC807180 mov rcx,qword ptr [rbp+38h]
00007FF9DC807184 cmp byte ptr [rcx],cl
00007FF9DC807186 mov rcx,qword ptr [rbp+38h]
00007FF9DC80718A mov qword ptr [rbp+30h],rcx
00007FF9DC80718E mov rcx,qword ptr [rbp+30h]
00007FF9DC807192 inc dword ptr [rcx]
rs.i = rs.i + 1; // while this line compiles perfectly
00007FF9DC807194 mov rcx,qword ptr [rbp+38h]
00007FF9DC807198 inc dword ptr [rcx]

s.i += 1; // this allocates a redundant var on stack
00007FF9DC80719A lea rcx,[rbp+48h]
00007FF9DC80719E mov qword ptr [rbp+28h],rcx
00007FF9DC8071A2 mov rcx,qword ptr [rbp+28h]
00007FF9DC8071A6 inc dword ptr [rcx]
s.i = s.i + 1; // ok
00007FF9DC8071A8 mov ecx,dword ptr [rbp+48h]
00007FF9DC8071AB inc ecx
00007FF9DC8071AD mov dword ptr [rbp+48h],ecx
`

It follows then, that using compound assignment ops with struct refs leads to sub-optimal code compared to equivalent unfolded assignment statement.

Configuration

.NET 8.0 (C# 12.0), Visual C 17.9.4
OS: Windows 10
Arch: x64

Regression?

No

Metadata

Metadata

Assignees

Labels

area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMIneeds-author-actionAn issue or pull request that requires more info or actions from the author.tenet-performancePerformance related issueuntriagedNew issue has not been triaged by the area owner

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions