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

EDIT: This is not a question of whether the GoTo instruction can be used.

This is a question about how to handle the center of the O (n ^ 3) algorithm in .NET / IL without using the GoTo instruction. Supporters and fellow travelers of Dijkstra's philosophy, please pay attention before reading this question.

Consider the following code, in which, for most cases, the use of the For o = 0 to nz cycle will run from 3 to 18 million times. The routine takes its place in my code as an argument to call Parallel.For (). Area m , ny and nz is between 10 and 300.

It is manually optimized to eliminate stack and subroutine calls, in other words, for speed. My desire is to avoid compiling IL, which includes the calli or call calli inside the innermost loop.

To interrupt the innermost three loops after running the test, I use the GoTo operator to cancel unnecessary tests.

The question is, is there a way to code this without GoTo? Is there a way to encode this code that the .net JIT compiler will compile for faster code without call or calli codes ending in 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 
+6
source share
4 answers

Is there any reason not to push it with a separate method, and then decorate this method with MethodImplOptions.AggressiveInlining ("The method should, if possible, be built-in").

This will allow you to use Return and significantly remove your code, as well as skip stacks, jumps, etc.

Unfortunately, with the restrictions that you have imposed, there are not many options.

As requested, an example of use 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 for the compiler, and there are limitations. The following do not support inlining:

  • Virtual methods
  • Recursive methods
  • Methods that take a large value type as a parameter
  • Methods for the MarshalByRef Classes
  • Ways with complex flags
  • Methods that meet other, more exotic criteria.

There may also be a limit on the number of IL bytes (this is 32 bytes without this flag).

+5
source

Although I would suggest you use a dedicated method to execute a loop, if you really want to use a nested loop, there is an alternative to jumping out of a loop that you like:

  Dim list1 = Enumerable.Range(1, 10) Dim list2 = Enumerable.Range(101, 10) Dim list3 = Enumerable.Range(201, 10) Console.WriteLine("Loop Start") For i As Integer = 0 To list1.Count - 1 For j As Integer = 0 To list2.Count - 1 For k As Integer = 0 To list3.Count - 1 Console.WriteLine(k) If list3(k) = 205 Then ' Assume this is the condition to exit k = list3.Count ' -- exit the loop of list3 j = list2.Count ' -- exit the loop of list2 End If Next Next Next Console.WriteLine("Finished") 

I wrote a simpler example (besides using your complex one), this will work with nested loops (regardless of the number of loops). and I believe that overhead would be minimal.

+1
source

Simple - rewrite this piece For m1 = m - 1 To m + 1 as a While loop. Then do Exit While . You can handle multiple GoTo since there is also a Do loop with your Exit Do Read more about MSDN Exit Application .

Although, my preferred solution is to reorganize it as follows:

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

Make sure that this does not hurt performance, and always use Option Strict On . The above, obviously, will not compile with it - just to show the concept.

Please note that I removed the unnecessary indent, so the code has become flatter and, hopefully, more readable.

EDIT:. As a trade-off between performance and maintainability, you can use class-level variables. So yes, you still jump to DoSomething and back, but not a single stack clicks.

+1
source

My desire is to avoid compiling IL, which includes the calli or call calli inside the innermost loop.

You do not have to worry about which IL is generated by your code, the only thing that affects performance is machine code (usually x86).

So what you need to do is write your code in a readable way (using the function using Return for the inner loop), and then measure the performance to see if it has changed or not.

Alternatively, you can look at the compiled machine code to see if the inner loop method has been built in or not.

0
source

All Articles