Ich versuche, Inline-x86-64-Assembly für GCC zu schreiben, um den MULQ-Befehl effizient zu verwenden. MULQ multipliziert das 64-Bit-Register RAX mit einem anderen 64-Bit-Wert. Der andere Wert kann ein beliebiges 64-Bit-Register (selbst RAX) oder ein Wert im Speicher sein. MULQ setzt die hohen 64 Bits des Produkts in RDX und die niedrigen 64 Bits in RAX.Kann GCC verschiedene Befehls-Mnemonik ausgeben, wenn zwischen mehreren alternativen Operandenbedingungen der Inline-Assemblierung gewählt wird?
Jetzt ist es einfach genug, um eine korrekte MULQ als Inline-Montage zum Ausdruck bringen:
#include <stdint.h>
static inline void mulq(uint64_t *high, uint64_t *low, uint64_t x, uint64_t y)
{
asm ("mulq %[y]"
: "=d" (*high), "=a" (*low)
: "a" (x), [y] "rm" (y)
);
}
Dieser Code ist richtig, aber nicht optimal. MULQ ist kommutativ, also wenn y
zufällig bereits in RAX ist, dann wäre es korrekt, y
zu verlassen, wo es ist und die Multiplikation zu machen. Aber GCC weiß das nicht, daher wird es zusätzliche Anweisungen ausgeben, um die Operanden an ihre vordefinierten Orte zu verschieben. Ich möchte GCC sagen, dass es beide Eingaben an jedem Ort vornehmen kann, solange man in RAX landet und der MULQ auf den anderen Ort verweist. GCC hat dafür eine Syntax namens "multiple alternative constraints". Beachten Sie die Kommas (aber die Gesamt asm() ist gebrochen, siehe unten):
asm ("mulq %[y]"
: "=d,d" (*high), "=a,a" (*low)
: "a,rm" (x), [y] "rm,a" (y)
);
Leider ist dies nicht stimmt. Wenn GCC die zweite alternative Einschränkung auswählt, wird "mulq% rax" ausgegeben. Um klar sein, sollten Sie diese Funktion:
uint64_t f()
{
uint64_t high, low;
uint64_t rax;
asm("or %0,%0": "=a" (rax));
mulq(&high, &low, 7, rax);
return high;
}
Zusammengestellt mit gcc -O3 -c -fkeep-inline-functions mulq.c
sendet GCC diese Versammlung:
0000000000000010 <f>:
10: or %rax,%rax
13: mov $0x7,%edx
18: mul %rax
1b: mov %rdx,%rax
1e: retq
Die "mul% rax" sollte "mul% RDX" sein.
Wie kann diese Inline-Asm umgeschrieben werden, so dass in jedem Fall die richtige Ausgabe generiert wird?
Eine Problemumgehung ist, ein Assembler-Makro in die Inline-Assembly zu setzen, etwa 'MULQ_FIX_OPERANDS (% 2,% 3)', das den Nicht-RAX-Operanden auswählt, aber das sieht wirklich hässlich aus. Ich hoffe, jemand hat eine bessere Lösung. – staufk
GCC unterstützt die Einschränkung "%", um kommutative Operanden zwischen alternativen Bedingungen auszudrücken, aber das löst das Problem nicht, da MULQ nur den Operanden verwendet. Wenn nur "Gas" dachte "MULQ RAX, r/m64" war ein gültiges Format für diese Anweisung! – staufk