В GNU C inline asm, какие модификаторы для xmm/ymm/zmm для одного операнда?
При попытке ответить встроенные трансляции со встроенными функциями и сборкой я пытался сделать что-то вроде этого:
__m512 mul_broad(__m512 a, float b) {
int scratch = 0;
asm(
"vbroadcastss %k[scalar], %q[scalar]\n\t" // want vbr.. %xmm0, %zmm0
"vmulps %q[scalar], %[vec], %[vec]\n\t"
// how it done for integer registers
"movw symbol(%q[inttmp]), %w[inttmp]\n\t" // movw symbol(%rax), %ax
"movsbl %h[inttmp], %k[inttmp]\n\t" // movsx %ah, %eax
: [vec] "+x" (a), [scalar] "+x" (b), [inttmp] "=r" (scratch)
:
:
);
return a;
}
GNU C x86 Операндовые модификаторы doc задает только модификаторы до q
(размер DI (DoubleInt), 64 бит). Использование q
в векторном регистре всегда сводится к xmm
(от ymm
или zmm
).
Вопрос:
Какие модификаторы изменяются между размерами векторного регистра?
Кроме того, существуют ли ограничения определенного размера для использования с входными или выходными операндами? Что-то другое, чем общий 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_broad(__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;
}
ссылка godbolt
Кроме того, я думаю, что весь этот подход к проблеме, которую я пытался решить, будет тупиком, потому что Multi-Alternative constraints не позволяйте вам давать разные asm для разных шаблонов ограничений. Я надеялся, что ограничения x
и r
в конечном итоге испускают a vbroadcastss
из регистра, а ограничения m
в конечном итоге испускают vmulps (mem_src){1to16}, %zmm_src2, %zmm_dst
(сложенная широковещательная загрузка). Целью этого делать с inline asm является то, что gcc еще не знает, как сбрасывать операнды памяти set1()
в широковещательные нагрузки (но clang делает).
В любом случае, этот конкретный вопрос касается модификаторов операндов и ограничений для векторных регистров. Пожалуйста, сосредоточьтесь на этом, но комментарии и ответы в ответах приветствуются по другому вопросу. (Или лучше, просто прокомментируйте/ответьте на вопрос Z Boson о встроенных трансляциях.)
Ответы
Ответ 1
Из файла gcc/config/i386/i386.c источников GCC:
b -- print the QImode name of the register for the indicated operand.
%b0 would print %al if operands[0] is reg 0.
w -- likewise, print the HImode name of the register.
k -- likewise, print the SImode name of the register.
q -- likewise, print the DImode name of the register.
x -- likewise, print the V4SFmode name of the register.
t -- likewise, print the V8SFmode name of the register.
g -- likewise, print the V16SFmode name of the register.
h -- print the QImode name for a "high" register, either ah, bh, ch or dh.
Аналогично gcc/config/i386/contraints.md:
;; We use the Y prefix to denote any number of conditional register sets:
;; z First SSE register.
;; i SSE2 inter-unit moves to SSE register enabled
;; j SSE2 inter-unit moves from SSE register enabled
;; m MMX inter-unit moves to MMX register enabled
;; n MMX inter-unit moves from MMX register enabled
;; a Integer register when zero extensions with AND are disabled
;; p Integer register when TARGET_PARTIAL_REG_STALL is disabled
;; f x87 register when 80387 floating point arithmetic is enabled
;; r SSE regs not requiring REX prefix when prefixes avoidance is enabled
;; and all SSE regs otherwise
Этот файл также определяет ограничение "Yk", но я не знаю, насколько хорошо он будет работать в инструкции asm:
(define_register_constraint "Yk" "TARGET_AVX512F ? MASK_EVEX_REGS : NO_REGS"
"@internal Any mask register that can be used as predicate, i.e. k1-k7.")
Обратите внимание, что все это скопировано из последней версии SVN. Я не знаю, какой выпуск GCC, если таковой имеется, добавлены определенные модификаторы и ограничения, которые вас интересуют.
Ответ 2
Кажется, что все последние версии GCC будут принимать как "q" , так и "x" в качестве модификаторов для печати версии XMM регистра YMM.
Intel icc хочет принять 'q', но не 'x' (по крайней мере, через версию 13.0.1).
[Edit: Ну, он работал в этом небольшом примере ниже, но в реальном случае у меня возникают проблемы с icc 14.0.3, принимающим "q" , но записывая "ymm".]
[Edit: Тестирование с более поздними версиями icc, я обнаруживаю, что ни icc 15, ни icc 16 не работают с "q" или "x".]
Но Clang 3.6 и ранее не принимают ни синтаксиса. И, по крайней мере, на Godbolt, Clang 3.7 падает с обоими!
// inline assembly modifiers to convert ymm to xmm
#include <x86intrin.h>
#include <stdint.h>
// gcc also accepts "%q1" as "%x1"
// icc accepts "%q1" but not "%x1"
// clang-3.6 accepts neither
// clang-3.7 crashes with both!
#define ASM_MOVD(vec, reg) \
__asm volatile("vmovd %q1, %0" : \
"=r" (reg) : \
"x" (vec) \
);
uint32_t movd_ymm(__m256i ymm) {
uint32_t low;
ASM_MOVD(ymm, low);
return low;
}
uint32_t movd_xmm(__m128i xmm) {
uint32_t low;
ASM_MOVD(xmm, low);
return low;
}
Ссылка на тест на Godbolt: http://goo.gl/bOkjNu
(Извините, что это не полный ответ на ваш вопрос, но мне показалось, что полезная информация делится и была слишком длинной для комментария)