В 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

(Извините, что это не полный ответ на ваш вопрос, но мне показалось, что полезная информация делится и была слишком длинной для комментария)