Skip to content

RyuJIT: optimize comparisons for const strings #33338

Closed
@EgorBo

Description

@EgorBo

Let's say I have a code:

public bool Test()
{
    return Validate("FAILED");
}

bool Validate(string name)
{
    return name != "FAILED";
}

Validate is inlined into Test like this:

public bool Test(string name)
{
    return !string.Equals("FAILED", "FAILED");
}

And it's not optimized into just false constant.
There are 3 solutions to fix it:

  1. Intrinsify string.Equals, working prototype: EgorBo@06eca1c
  2. Make string.Equals always inlineable via [MethodImpl(MethodImplOptions.AggressiveInlining)] and it will work! However, it will significantly regress non-constant cases - definitely not an option.
  3. Tweak the inliner a bit, because it almost passes the threshold due to constant args + conditions, a simple repro:
public bool Test()
{
    // should be inlined but currently is not.
    return !String_Equals("hello", "hello");
}

public static bool String_Equals(string a, string b) // Code size: 36
{
    if (object.ReferenceEquals(a, b))
    {
        return true;
    }
    // `a is null` and `b is null` increase the multiplier (constant args into constant tests), good
    if (a is null || b is null || a.Length != b.Length) // jit doesn't know `a.Length` and `b.Length
                                                        // will be optimized into constants (see https://github.com/dotnet/runtime/pull/1378)
    {
        return false;
    }

    return EqualsHelper(a, b);
}

[MethodImpl(MethodImplOptions.NoInlining)]
private static bool EqualsHelper(string a, string b) => false;
Inline candidate looks like a wrapper method.  Multiplier increased to 1.
Inline candidate has an arg that feeds a constant test.  Multiplier increased to 2.
Inline candidate has const arg that feeds a conditional.  Multiplier increased to 5.
Inline candidate callsite is boring.  Multiplier increased to 6.3.
calleeNativeSizeEstimate=521
callsiteNativeSizeEstimate=115
benefit multiplier=6.3
threshold=724
Native estimate for function size is within threshold for inlining 52.1 <= 72.4 (multiplier = 6.3)
// but doesn't pass max amount of BB check :-( 

E.g. if I remove object.ReferenceEquals(a, b) it will be inlined!

category:cq
theme:inlining
skill-level:intermediate
cost:medium

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions