Пытаясь ответить на встроенные трансляции с встроенными функциями и сборкой, я пытался сделать что-то вроде этого:
__m512 mul_bcast(__m512 a, float b) {
asm(
"vbroadcastss %k[scalar], %q[scalar]\n\t" // want vbcast.. %xmm0, %zmm0
"vmulps %q[scalar], %[vec], %[vec]\n\t"
: [vec] "+x" (a), [scalar] "+&x" (b)
: :
);
return a;
}
В документе GNU C x86 Operand Modifiers указаны модификаторы только до q
(размер DI (DoubleInt), 64 бита). Использование q
в векторном регистре всегда будет понижать его до xmm
(с ymm
или zmm
). например скалярные регистры:
long scratch = 0; // not useful instructions, just syntax demo
asm(
"movw symbol(%q[inttmp]), %w[inttmp]\n\t" // movw symbol(%rax), %ax
"movsbl %h[inttmp], %k[inttmp]\n\t" // movsx %ah, %eax
: [inttmp] "+r" (scratch)
:: "memory" // we read some index in symbol[]
);
Вопрос:
Какие модификаторы можно изменять между размерами векторного регистра?
Кроме того, существуют ли какие-либо ограничения конкретного размера для использования с входными или выходными операндами? Нечто другое, кроме общего x
, которое может оказаться xmm, ymm или zmm в зависимости от типа выражения, которое вы поместили в круглые скобки.
Не по теме:
clang, похоже, имеет некоторые Yi
/ Yt
ограничения (не модификаторы), но я тоже не могу найти документацию по этому поводу. clang даже не скомпилирует это, даже если векторные инструкции закомментированы, потому что ему не нравится +x
как ограничение для вектора __m512
.
Предпосылки / мотивация
Я могу получить желаемый результат, передав скаляр в качестве входного операнда, который должен находиться в том же регистре, что и более широкий выходной операнд, но это более неуклюже. (Самым большим недостатком этого варианта использования является то, что AFAIK ограничение сопоставления может ссылаться только по номеру операнда, а не по [symbolic_name]
, поэтому оно подвержено поломке при добавлении / удалении ограничений вывода.)
// does what I want, by using a paired output and input constraint
__m512 mul_bcast(__m512 a, float b) {
__m512 tmpvec;
asm(
"vbroadcastss %[scalar], %[tmpvec]\n\t"
"vmulps %[tmpvec], %[vec], %[vec]\n\t"
: [vec] "+x" (a), [tmpvec] "=&x" (tmpvec)
: [scalar] "1" (b)
:
);
return a;
}
Кроме того, я думаю, что весь этот подход к проблеме, которую я пытался решить, будет тупиком, потому что Множественные альтернативные ограничения не позволяет вам указывать разные asm для разных шаблонов ограничений. Я надеялся, что ограничения x
и r
приведут к выдаче vbroadcastss
из регистра, в то время как ограничения m
будут выдавать vmulps (mem_src){1to16}, %zmm_src2, %zmm_dst
(сложенная широковещательная загрузка). Цель выполнения этого с помощью встроенного asm заключается в том, что gcc еще не знает, как свернуть set1()
операнды памяти в широковещательные загрузки (но clang знает).
В любом случае, этот конкретный вопрос касается модификаторов операндов и ограничений для векторных регистров. Пожалуйста, сосредоточьтесь на этом, но комментарии и отступления в ответах приветствуются по другому вопросу. (Или лучше просто прокомментируйте / ответьте на вопрос Z Boson о встроенных трансляциях.)
asm("" : [me] "=a" (a) : "[me]"(7));
. - person David Wohlferd   schedule 25.12.2015"[me]"
. Это было главным возражением против метода ограничения выходного соответствия. - person Peter Cordes   schedule 25.12.2015%g0
для получения ZMM-имени входа или выхода"x"(__m256)
- person Peter Cordes   schedule 21.09.2018