Skip to content
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

No way to avoid bounds checks when multiple spans are involved #97285

Closed
stephentoub opened this issue Jan 22, 2024 · 6 comments
Closed

No way to avoid bounds checks when multiple spans are involved #97285

stephentoub opened this issue Jan 22, 2024 · 6 comments
Assignees
Labels
area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI
Milestone

Comments

@stephentoub
Copy link
Member

Given a pattern like:

for (int i = 0; i < span.Length; i++)
{
    span[i] *= 2;
}

the JIT can elide the bounds checks on the span, but if there are multiple spans involved, e.g.

using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

public class C
{
    public void M1(ReadOnlySpan<int> source, Span<int> destination)
    {
        if (source.Length > destination.Length) Throw();

        for (int i = 0; i < source.Length; i++)
        {
            destination[i] = source[i] * 2;
        }
    }
    
    private static void Throw() => throw new Exception();
}

the JIT doesn't elide the bounds checks on both source and destination, only on source. The only way today to get rid of all these bounds checks is to use unsafe code.

@ghost ghost added the untriaged New issue has not been triaged by the area owner label Jan 22, 2024
@dotnet-issue-labeler dotnet-issue-labeler bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Jan 22, 2024
@ghost
Copy link

ghost commented Jan 22, 2024

Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in area-owners.md if you want to be subscribed.

Issue Details

Given a pattern like:

for (int i = 0; i < span.Length; i++)
{
    span[i] *= 2;
}

the JIT can elide the bounds checks on the span, but if there are multiple spans involved, e.g.

using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

public class C
{
    public void M1(ReadOnlySpan<int> source, Span<int> destination)
    {
        if (source.Length > destination.Length) Throw();

        for (int i = 0; i < source.Length; i++)
        {
            destination[i] = source[i] * 2;
        }
    }
    
    private static void Throw() => throw new Exception();
}

the JIT doesn't elide the bounds checks on both source and destination, only on source. The only way today to get rid of all these bounds checks is to use unsafe code.

Author: stephentoub
Assignees: -
Labels:

area-CodeGen-coreclr, untriaged

Milestone: -

@jakobbotsch
Copy link
Member

This is related to/a duplicate of #9977. Cases like these should be handled once we have loop cloning for spans (#82946).

@jakobbotsch jakobbotsch added this to the 9.0.0 milestone Jan 22, 2024
@ghost ghost removed the untriaged New issue has not been triaged by the area owner label Jan 22, 2024
@jakobbotsch jakobbotsch changed the title No way to avoid bounds checks when multiple spans/arrays involved No way to avoid bounds checks when multiple spans are involved Jan 22, 2024
@tannergooding
Copy link
Member

Cases like these should be handled once we have loop cloning for span

@jakobbotsch, is this a case where we might be able to avoid loop cloning for some kinds of trivial inputs?

I don't believe we require cloning for single spans and instead simply emit one loop with no bounds checks. Ideally we'd be able to recognize some of these patterns and similarly not require a cloned loop for multiple spans, to help avoid code bloat and assembly size increases for "trivial" cases like this.

@jakobbotsch
Copy link
Member

@jakobbotsch, is this a case where we might be able to avoid loop cloning for some kinds of trivial inputs?

I don't believe we require cloning for single spans and instead simply emit one loop with no bounds checks. Ideally we'd be able to recognize some of these patterns and similarly not require a cloned loop for multiple spans, to help avoid code bloat and assembly size increases for "trivial" cases like this.

Loop cloning should not result in any bloat for cases like this. You can see that the array version has the bounds checks optimized away without any bloat, despite the fact that loop cloning is what made that possible. The cold version only exists temporarily -- the JIT is later able to remove it because it notices that there is a dominating compare that makes the cold version unreachable.

@tannergooding
Copy link
Member

Gotcha, I had thought we had a special path to handle the common case and avoid the temporary IR introduction. But if that's not the case then sounds like all will be right anyways 👍

@stephentoub
Copy link
Member Author

Closing as duplicate.

@stephentoub stephentoub closed this as not planned Won't fix, can't repro, duplicate, stale Mar 10, 2024
@github-actions github-actions bot locked and limited conversation to collaborators Apr 9, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI
Projects
None yet
Development

No branches or pull requests

4 participants