Ответ 1
Как отмечает Питер Кордес, GCC не позволяет вам указать другой шаблон для разных альтернатив ограничения. Поэтому вместо моего решения ассемблер выбирает правильную инструкцию в соответствии с выбранными операндами.
У меня нет версии GCC, которая поддерживает регистры ZMM, поэтому в следующем примере используются регистры XMM и несколько несуществующих инструкций, чтобы продемонстрировать, как вы можете добиться того, что вы ищете.
typedef __attribute__((vector_size(16))) float v4sf;
v4sf
foo(v4sf a, float b) {
v4sf ret;
asm(".ifndef isxmm\n\t"
".altmacro\n\t"
".macro ifxmm operand, rnum\n\t"
".ifc \"\\operand\",\"%%xmm\\rnum\"\n\t"
".set isxmm, 1\n\t"
".endif\n\t"
".endm\n\t"
".endif\n\t"
".set isxmm, 0\n\t"
".set regnum, 0\n\t"
".rept 8\n\t"
"ifxmm <%2>, %%regnum\n\t"
".set regnum, regnum + 1\n\t"
".endr\n\t"
".if isxmm\n\t"
"alt-1 %1, %2, %0\n\t"
".else\n\t"
"alt-2 %1, %2, %0\n\t"
".endif\n\t"
: "=x,x" (ret)
: "x,x" (a), "x,m" (b));
return ret;
}
v4sf
bar(v4sf a, v4sf b) {
return foo(a, b[0]);
}
Этот пример должен быть скомпилирован с помощью gcc -m32 -msse -O3
и должен генерировать два сообщения об ошибках ассемблера, похожие на следующие:
t103.c: Assembler messages:
t103.c:24: Error: no such instruction: `alt-2 %xmm0,4(%esp),%xmm0'
t103.c:22: Error: no such instruction: `alt-1 %xmm0,%xmm1,%xmm0'
Основная идея здесь - ассемблер проверяет, является ли второй операнд (%2
) регистром XMM или чем-то еще, предположительно, местом памяти. Поскольку ассемблер GNU не поддерживает много операций в строках, второй операнд сравнивается со всеми возможными регистрами XMM по одному в цикле .rept
. Макрос isxmm
используется для вставки %xmm
и номера регистра вместе.
Для вашей конкретной проблемы вам, вероятно, потребуется переписать ее примерно так:
__m512
mul_broad(__m512 a, float b) {
__m512 ret;
__m512 dummy;
asm(".ifndef isxmm\n\t"
".altmacro\n\t"
".macro ifxmm operand, rnum\n\t"
".ifc \"\\operand\",\"%%zmm\\rnum\"\n\t"
".set isxmm, 1\n\t"
".endif\n\t"
".endm\n\t"
".endif\n\t"
".set isxmm, 0\n\t"
".set regnum, 0\n\t"
".rept 32\n\t"
"ifxmm <%[b]>, %%regnum\n\t"
".set regnum, regnum + 1\n\t"
".endr\n\t"
".if isxmm\n\t"
"vbroadcastss %x[b], %[b]\n\t"
"vmulps %[a], %[b], %[ret]\n\t"
".else\n\t"
"vmulps %[b] %{1to16%}, %[a], %[ret]\n\t"
"# dummy = %[dummy]\n\t"
".endif\n\t"
: [ret] "=x,x" (ret), [dummy] "=xm,x" (dummy)
: [a] "x,xm" (a), [b] "m,[dummy]" (b));
return ret;
}