.netvb.netperformancegotoil

Is there a way to write this without a GoTo statement?


EDIT: This is not a question about whether it's OK to use a GoTo statement.

It is a question about how to handle the center of an O(n^3) algorithm in .NET/IL without using a GoTo statement. Adherents and fellow travelers of Dijkstra's philosophies, please take note before failing to read the question.

Consider the following code, in which for most use cases the contents of the For o = 0 to nz loop will be executed between 3 million and 18 million times. The subroutine takes its place in my code as an argument for a Parallel.For() call. The domain of m, ny, and nz are all between 10 and 300.

It is hand-optimized to avoid stack pushes and subroutine calls, in other words, for speed. My desire is to avoid a compilation to IL which includes a calli or call opcode inside the innermost loop.

To abort the innermost three loops once a test is satisfied, I use a GoTo statement to abort unneeded tests.

The question is, is there a way to code this without the GoTo? Is there a way to code this which the .net JIT-Compiler will compile to faster code without call or calli opcodes ending up in the object code?

Sub SomeLambda(m As Integer, newarray As Short(,,))
    For n = 0 To ny
        For o = 0 To nz
            If newarray(m, n, o) <> 1 AndAlso newarray(m, n, o) <> -1 Then
                For m1 = m - 1 To m + 1
                    For n1 = n - 1 To n + 1
                        For o1 = o - 1 To o + 1
                            If SomeCondition = True Then 'the array is not out of bounds '
                                Dim testVal = newarray(m1, n1, o1)
                                If testVal = -1 Then
                                    newarray(m, n, o) = -2
                                    GoTo Exitloopslabel2
                                End If
                            End If
                        Next
                    Next
                Next
   Exitloopslabel2: 
            End If
        Next
    Next
End Sub

Solution

  • Is there any reason not to push it out to a seperate method and then decorate that method with MethodImplOptions.AggressiveInlining ("The method should be inlined if possible").

    As long as the method meets certain requirements (see below), the compiler will make a copy of the method at the point where it's called.

    This would let you use Return and tidy up your code considerably while also skipping the stack pushes, jumps, etc. usually associated with a method call.

    Unfortunately, with the constraints you've imposed, there aren't many alternatives.

    As requested, some example usage in VB.Net:

    Imports System.Runtime.CompilerServices
    
    <MethodImpl(MethodImplOptions.AggressiveInlining)>
    Public Function Blah() As String 
        ...
    End Function
    

    and C#

    using System.Runtime.CompilerServices;
    
    [MethodImpl(MethodImplOptions.AggressiveInlining)] 
    public string Blah() {
        ...
    }
    

    I should mention that this is a hint to the compiler, and there are limits. The following don't support inlining;

    There may also be an IL byte count limit (There's a limit of 32 bytes without this flag, which is either increased or removed entirely). I haven't been able to find adequate documentation.