J'essaie de comprendre à quoi ressemble une boucle while dans IL. J'ai écrit cette fonction C#:While boucle dans IL - pourquoi stloc.0 et ldloc.0?
static void Brackets()
{
while (memory[pointer] > 0)
{
// Snipped body of the while loop, as it's not important
}
}
L'IL ressemble à ceci:
.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
Pour la plupart ce qui est vraiment simple, à l'exception de la partie après tbc.
Ce que je ne comprends pas est le local [0] et le stloc.0/ldloc.0. Dans la mesure où je le vois, cgt pousse le résultat à la pile, stloc.0 obtient le résultat de la pile dans la variable locale, ldloc.0 repousse le résultat dans la pile et brtrue.s lit la pile.
Quel est le but de cette opération? Cela ne pourrait-il pas être raccourci à juste cgt suivi de brtrue.s?
Un nugget supplémentaire pour vous, basé sur "comme c'est pas important" et votre flux twitter ... notez la différence entre 'br * _s' et' br * '. Les variantes '_s' utilisent un petit décalage * relatif *, et ** ne fonctionnera pas ** si les emplacements ne sont pas proches les uns des autres (les variantes non-'_s' utilisent un décalage * absolu * sans la" petite "limitation). Donc, si votre compilateur ne peut pas prédire (à l'avance) la taille du corps, utilisez 'br *' de préférence 'br * _s'. –
@Marc Merci, a rencontré exactement ce problème: D Mon application Démo a une seule instruction pour que le compilateur génère des variantes _s, mais mon vrai compilateur avait un corps de la boucle beaucoup plus long. Effet secondaire positif: J'ai appris quelque chose à partir de cette "Exception illégale d'une branche d'octets" :) –
IIRC, ILGenerator est assez intelligent pour émettre l'opcode correct pour la situation actuelle si vous utilisez la bonne méthode. –