Frage

Wer weiß, wie kann ich die folgenden Assembler Warnung loswerden?

-Code ist x86, 32-Bit:

int test (int x)
{
  int y;
  // do a bit-rotate by 8 on the lower word. leave upper word intact.
  asm ("rorw $8, %0\n\t": "=q"(y) :"0"(x));
  return y;
}

Wenn ich kompilieren bekomme ich folgende (sehr gültig) Warnung:

Warning: using `%ax' instead of `%eax' due to `w' suffix

Was ich suche ist eine Möglichkeit, den Compiler / Assembler zu sagen, dass ich die unteren 16 Bit-Unterregister% 0 zugreifen möchten. Zugriff auf das Byte-Unterregister (in diesem Fall AL und AH) wäre schön, so gut zu kennen.

Ich habe bereits die "q" Modifikator ausgewählt, so dass der Compiler gezwungen wird, EAX, EBX, ECX oder EDX zu verwenden. Ich habe gemacht, dass der Compiler ein Register wählen hat, die Unterregister hat.

Ich weiß, dass ich den asm-Code erzwingen kann ein bestimmtes Register (und dessen Unterregister) zu verwenden, aber ich will bis zum Compiler des Register-Zuordnung Job verlassen.

War es hilfreich?

Lösung

Sie können %w0 verwenden, wenn ich mich recht erinnere. Getestet habe ich es einfach, auch. : -)

int
test(int x)
{
    int y;
    asm ("rorw $8, %w0" : "=q" (y) : "0" (x));
    return y;
}

Edit: Als Antwort auf die OP, ja, können Sie Folgendes tun auch:

int
test(int x)
{
    int y;
    asm ("xchg %b0, %h0" : "=Q" (y) : "0" (x));
    return y;
}

Zur Zeit der einzige Ort, (die ich kenne) dokumentiert ist in ist gcc/config/i386/i386.md, nicht in einen der Standard-Dokumentation.

Andere Tipps

Vor langer Zeit, aber ich brauche dies wahrscheinlich für meine eigene Zukunft Referenz ...

Das Hinzufügen auf Chris feine Antwort sagt, ist der Schlüssel zu einem Modifikator zwischen dem ‚%‘ und der Nummer des Ausgangsoperand verwenden. Zum Beispiel könnte "MOV %1, %0" "MOV %q1, %w0" werden.

Ich kann nichts in constraints.md finden, aber Output Template der GCC Internals Dokumentation:

  

‚% cdigit‘ kann verwendet werden, um einen Operanden zu ersetzen, die eine Konstante ist   Wert ohne die Syntax, die normalerweise einen unmittelbaren Operanden angibt.

     

‚% ndigit‘ ist wie ‚% cdigit‘, außer dass der Wert der Konstante ist   negiert vor dem Druck.

     

‚% adigit‘ kann verwendet werden, um einen Operanden zu ersetzen, als ob es ein Speicher war   Referenz, mit dem tatsächlichen Operanden als Adresse behandelt. Das mag sein   nützlich, wenn eine „Last-Adresse“ Anweisung ausgibt, weil oft die   Assembler-Syntax für eine solche Anweisung erfordert, dass Sie die schreiben   Operanden, als ob es sich um eine Speicherreferenz waren.

     

‚% ldigit‘ verwendet wird, eine label_ref in einen Sprungbefehl zu ersetzen.

     

‚% =‘ gibt eine Zahl, die jeden Befehl in der einzigartigen   gesamte Zusammenstellung. Dies ist nützlich für die Herstellung von lokalen Labels zu sein   in einer einzigen Vorlage mehr als einmal bezeichnet, die erzeugt   mehrere Assembler-Anweisungen.

Das ‚%c2‘ Konstrukt ermöglicht man eine LEA Anweisung richtig formatiert wird unter Verwendung eines Offset:

#define ASM_LEA_ADD_BYTES(ptr, bytes)                            \
    __asm volatile("lea %c1(%0), %0" :                           \
                   /* reads/writes %0 */  "+r" (ptr) :           \
                   /* reads */ "i" (bytes));

Beachten Sie die wichtigen, aber spärlich dokumentiert 'c' in '%c1'. Dieses Makro ist äquivalent zu

ptr = (char *)ptr + bytes

aber ohne Verwendung der üblichen Integer-Arithmetik Ausführung Ports zu machen.

Bearbeiten hinzuzufügen:

direkte Anrufe in x64 machen kann schwierig sein, da es noch eine weitere undokumentierte Modifikator erfordert: ‚%P0

(die für die PIC zu sein scheint)
#define ASM_CALL_FUNC(func)                                         \
    __asm volatile("call %P0") :                                    \
              /* no writes */ :                                     \
              /* reads %0 */ "i" (func))                           

Ein klein ‚p‘ Modifikator scheint auch das gleiche in GCC zu funktionieren, obwohl nur die Hauptstadt ‚P‘ von ICC anerkannt wird. Weitere Details sind wahrscheinlich finden Sie unter / gcc / config / i386 / i386.c . Suche nach " 'p'".

Während ich darüber denke ... sollten Sie die „q“ Constraint mit einem Kapital „Q“ Constraint in Chris zweite Lösung ersetzt werden:

int
test(int x)
{
    int y;
    asm ("xchg %b0, %h0" : "=Q" (y) : "0" (x));
    return y;
}

"q" und "Q" sind etwas anders in 64-Bit-Modus, in dem Sie das niedrigste Byte für alle ganzzahligen Register erhalten können (ax, bx, cx, dx, si, Di, sp, bp, r8 R15). Aber man kann nur erhalten die zweitniedrigste Byte (z ah) für die vier ursprünglichen 386 Register (ax, bx, cx, dx).

So anscheinend gibt es Tricks, dies zu tun ... aber es kann nicht so effizient sein. 32-Bit-x86-Prozessoren sind in der Regel langsam bei Manipulation von 16-Bit-Daten in Registern für allgemeine Zwecke. Sie sollten Benchmark es zu, wenn die Leistung wichtig ist.

Es sei denn, dies ist (a) die Leistung kritisch und (b) beweisen viel schneller zu sein, würde ich mir etwas Wartung Ärger sparen und tun Sie es einfach in C:

uint32_t y, hi=(x&~0xffff), lo=(x&0xffff);
y = hi + (((lo >> 8) + (lo << 8))&0xffff);

Mit GCC 4.2 und -O2 diese auf sechs Anweisungen optimiert wird ...

Gotcha. Nun, wenn es eine primitive Routine, die Sie gehen immer und immer wieder werden die Wiederverwendung, ich habe keinen Streit mit ihm ... der Register Namen Trick, dass Chris wies darauf hin, ist ein schöner, die ich bin zu haben, sich zu erinnern.

Es wäre schön, wenn es sie in die Standard-GCC-Dokumentation zu gemacht!

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top