2016-11-14 1 views
4

Das ist mein C# -Code:Wie erzwinge Compiler, ldc.i8 IL-Anweisung anstelle von ldc.i4 plus conv.i8 zu verwenden?

const long pSize = 20; 

Egal, ob ich mal 64 oder irgendein CPU verwenden Sie es in Release-Modus zu bauen, habe ich unten MSIL Anweisungen:

IL_0010: ldc.i4.s 20 
    IL_0012: conv.i8 

jedoch MSIL LDC hat. i8 Anweisung. Wie man Compiler macht, um das zu benutzen?

+2

Warum möchten Sie tun, was Compiler normalerweise verantwortlich ist? – Sinatr

+0

Sie möchten also den Compiler zwingen, längeren Code als nötig zu generieren? – hvd

+2

Sie möchten die MSIL * weniger * effizient machen, ldc.i8 benötigt 4 weitere Bytes. Kein Punkt dazu. –

Antwort

24

MSIL hat ldc.i8 Anweisung. Wie man Compiler macht, um das zu benutzen?

Sie nicht. Das wäre schlechter Code.

ldc.i4.s 20 
conv.i8 

ist drei Bytes Code: zwei für die Anweisungen und eine für die Konstante. Wobei

ldc.i8 20 

ist neun Bytes: eins für die Anweisung und acht für die Konstante.

Der Compiler ist intelligent genug, um sechs unnötige Bytes zu vermeiden. Denken Sie daran, dass die Geschwindigkeit des Codes durch die Anzahl der Seitenfehler beeinträchtigt werden kann, die benötigt werden, um den Code in den Speicher zu laden. Generieren Code dreimal größer als es sein muss funktioniert gegen dieses Ziel.

Aber warten Sie, es gibt mehr, und es ist alles schlecht.

Je größer ein einfacher Codeblock ist, desto wahrscheinlicher ist es, dass ein Zweig um ihn herum länger ist als in das kompakte Verzweigungsbefehlsformat passt. Das bedeutet, dass diese De-Optimierung Verzweigungsbefehle groß machen kann, was wiederum die Basisblöcke größer macht, und jetzt vielleicht Zweige um sie sind nicht kompakt, und die ganze Sache kann Schneeball.

Es sind nicht nur die sechs zusätzlichen Bytes; es sind alle Konsequenzen dieser sechs zusätzlichen Bytes, die andere Code größer machen; Sie müssen diese Kosten auch berücksichtigen.

Der Compiler macht einen guten Job. Lass es seine Arbeit machen.

Wenn Sie einen Compiler verwenden, der schlechteren Code generiert, ist der Quellcode des Compilers verfügbar. Fühlen Sie sich frei, einen de-optimierenden Compiler zu schreiben, wenn Sie wirklich einen aus irgendeinem Grund brauchen.

+0

Was ist der tatsächliche Effekt der Anweisung "conv.i8"? Mein C# -Code möchte 20 als "lang" behandeln und später mit einer anderen langen Zahl multiplizieren. Ich dachte conv.i8 konvertiert 20 von Byte zu lang. – Sheen

+1

@Sheen: Die Opcode-Semantik ist eindeutig dokumentiert; Recherchiere. Außerdem finde ich es etwas verstörend, dass Sie gefragt haben, wie man den Compiler dazu zwingt, eine alternative Befehlssequenz * zu erzeugen, ohne zu wissen, was die aktuellen Anweisungen der tatsächlichen Befehlsfolge tun *. C# ist so konzipiert, dass Sie über Ihren Code wissen können, der die Semantik von C# kennt; Mach dir keine Sorgen über die IL. Die generierte IL ist korrekt. –

+0

Eric, danke für den Vorschlag. Ich habe die MSDN-Seite gelesen. Es sagt 3 Schritte: 1. Wert wird auf den Stapel geschoben. 2. Der Wert wird vom Stapel ausgegeben und die Konvertierung wird versucht. 3. Wenn die Konvertierung erfolgreich ist, wird der resultierende Wert auf den Stapel geschoben. Also in der Laufzeit ist es besser, Int64 direkt auf Stack zu setzen? – Sheen

Verwandte Themen