Writing Loops in IL
Here's a typical loop construct. Remember the assumptions about the purpose of the program stated at the beginning of this article: If the value is larger than 0 and smaller than 10 the code should loop a number of times according to the amount entered.
call void [mscorlib]System.Console::WriteLine(string)
To understand this code you have to know that when execution reaches the LoopPoint
label there is one integer value on the evaluation stack that contains the number of loops still to be performed.
First, the code uses the directive ldc.i4.m1,
which loads the value -1
onto the stack and then calls add
to decrement the loop counter. You could also use ldc.i4.1
to achieve this, and of course you could decrement the counter at the end of the loop instead of the beginning.
Next appears the loop workload. In this case the code simply outputs the string "looping
for each loop iteration. In more typical code, that's the place where your repeating code should go.
After completing each iteration, you need to compare the loop counter to zero to decide whether to jump back to the beginning of the loop or whether the loop is complete and execution should continue with the code lines after the loop. You've already seen how such comparisons pop the value from the evaluation stack. But if you pop the value, you would lose the loop counter. Therefore, a dup
statement clones the topmost stack item, the loop counter, before making the comparison. When writing more complex loops a better idea is to store the counter to a local variable, which gives you greater flexibility and better control of the evaluation stack. You'll see how to do that in the next sample.
directive loads zero onto the evaluation stack. Here's the stack transition diagram for that source line:
Counter, Counter --> Counter, Counter, 0
directive pops the top two items from the evaluation stack and continues execution at the code line marked by the label LoopPoint
if the item that's lower on the stack is greater than the topmost item. This means that the statement will branch until the counter reaches the value 0.
After the loop you want to exit the program, but because you always dup
the value within the loop, you'll still have the counter left on the evaluation stack. You won't need it anymore. Simply pop
it off the stack before calling ret