Skip to content

Optimization: left ?? right can be optimized to left.GetValueOfDefault() when appropriate #22800

@MrJul

Description

@MrJul

While writing some code the other day, I wondered if, for a variable x of type int?, whether x ?? 0 and x.GetValueOrDefault() are really compiled to the same IL (I first assumed that they are). To my surprise, they aren't!

GetValueOrDefault is faster because it's implemented as a single unconditional field load. You can't really get much simpler than that, and it's a great candidate for inlining.

While it's an implementation detail, Roslyn already relies on it: in some cases where it's known that a nullable expression has a value, the compiler generates nullable.GetValueOrDefault() to access the value rather than using nullable.Value.

The change seemed simple enough: lower any left ?? right to left.GetValueOrDefault() when left is T? and right is the default value of T. I've wanted to poke around the Roslyn codebase for a while, so here was my chance :)

Here's the commit implementing this optimization along with a test: https://github.com/MrJul/roslyn/commit/ed21c4d8b025ec203a474e814c91ec701c6ac59f

Is it worth it? While it's a micro optimization, it's still an optimization (BenchmarkDotNet shows a ~60% improvement with RyuJIT x64 and .NET 4.7 on my machine - we're talking about sub-nanoseconds times here), and a pretty straightforward one in my opinion.

I didn't handle the case left ?? right when left is a T? and right is a non-default T constant since GetValueOrDefault(T) (with a parameter) has branches equivalent to what the compiler generates so the only benefit is a very slight reduction in IL size (which might still help with inlining). However, I can add it if needed.

If the team is interested in this change, I'll open a PR.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Area-CompilersResolution-FixedThe bug has been fixed and/or the requested behavior has been implemented

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions