Ich versuche zu verstehen, wie eine While-Schleife in IL aussieht. Ich habe diese C# Funktion geschrieben:While-Schleife in IL - warum Stloc.0 und Idloc.0?
static void Brackets()
{
while (memory[pointer] > 0)
{
// Snipped body of the while loop, as it's not important
}
}
Die IL sieht wie folgt aus:
.method private hidebysig static void Brackets() cil managed
{
// Code size 37 (0x25)
.maxstack 2
.locals init ([0] bool CS$4$0000)
IL_0000: nop
IL_0001: br.s IL_0012
IL_0003: nop
// Snipped body of the while loop, as it's not important
IL_0011: nop
IL_0012: ldsfld uint8[] BFHelloWorldCSharp.Program::memory
IL_0017: ldsfld int16 BFHelloWorldCSharp.Program::pointer
IL_001c: ldelem.u1
IL_001d: ldc.i4.0
IL_001e: cgt
IL_0020: stloc.0
IL_0021: ldloc.0
IL_0022: brtrue.s IL_0003
IL_0024: ret
} // end of method Program::Brackets
Zum größten Teil ist dies wirklich einfach, mit Ausnahme des Teils nach cgt.
Was ich nicht verstehe, ist die lokale [0] und die stloc.0/ldloc.0. Soweit ich es sehe, schiebt cgt das Ergebnis auf den Stack, stloc.0 holt das Ergebnis vom Stack in die lokale Variable, ldloc.0 schiebt das Ergebnis wieder auf den Stack und bratrue.s liest vom Stack.
Was ist der Zweck, dies zu tun? Könnte das nicht auf nur cgt gefolgt von brtrue.s verkürzt werden?
Ein extra Nugget für Sie, basierend auf "wie es nicht wichtig ist" und Ihrem Twitter-Feed ... beachten Sie den Unterschied zwischen 'br * _s' und' br * '. Die '_s'-Varianten verwenden einen kleinen * relativen * Offset, und ** funktioniert nicht **, wenn die Positionen nicht nahe beieinander liegen (die Nicht-'_s'-Varianten verwenden einen * absoluten * Offset ohne die" kleine "Einschränkung). Wenn also Ihr Compiler die Größe des Körpers nicht voraussehen kann, verwenden Sie 'br *' gegenüber 'br * _s'. –
@Marc Danke, genau in dieses Problem: D Meine Demo-App hat eine einzige Anweisung, so dass der Compiler _s Varianten erzeugte, aber mein echter Compiler hatte einen viel längeren Loop-Body. Positiver Nebeneffekt: Ich habe etwas aus dem "Illegalen Ein-Byte-Zweig" gelernt. Ausnahme: –
IIRC, ILGenerator ist intelligent genug, um den richtigen Opcode für die vorliegende Situation auszugeben, wenn Sie die richtige Methode dafür verwenden. –