Инструкции по сборке AVX2 - расчет адреса загрузки

В документации по внутреннему интерфейсу AVX2 собраны команды загрузки, такие как VPGATHERDD:

__m128i _mm_i32gather_epi32 (int const * base, __m128i index, const int scale);

Что мне не понятно из документации, является ли вычисляемый адрес нагрузки адресом элемента или байтовым адресом, то есть адресом загрузки для элемента i:

load_addr = base + index[i] * scale;               // (1) element addressing ?

или

load_addr = (char *)base + index[i] * scale;       // (2) byte addressing ?

Из Intel docs это выглядит так, как будто это может быть (2), но это не имеет большого смысла, учитывая, что наименьший размер элемента для собранных нагрузок составляет 32 бит - зачем вы хотите загружать из неправильно настроенных адресов (например, использовать шкалу < 4)?

Ответ 1

В сборках отсутствуют требования к выравниванию. Поэтому было бы слишком сложно ограничивать адресацию байтов.

Другая причина - согласованность. При адресации SIB мы, очевидно, имеем адрес байта:

MOV eax, [rcx + rdx * 2]

Так как VPGATHERDD - это просто векторный вариант этой инструкции MOV, мы не должны ожидать ничего другого с адресацией VSIB:

VPGATHERDD ymm0, [rcx + ymm2 * 2], ymm3

Что касается использования в реальном времени для адресации байтов, мы можем иметь 24-битное цветное изображение, где каждый пиксель выравнивается по 3 байт. Мы могли бы загрузить 8 пикселей с одной инструкцией VPGATHERDD, но только если поле "scale" в VSIB "1" и VPGATHERDD использует байтовую адресацию.

Ответ 2

Судя по описанию в справочном документе программирования AVX, представленном здесь, похоже, что команды сбора используют байтовую адресацию. В частности, см. Следующие цитаты из описания инструкции VPGATHERDD (на странице 389):

DISP: optional 1, 2, 4 byte displacement;
DATA_ADDR = BASE_ADDR + (SignExtend(VINDEX[i+31:i])*SCALE + DISP;

Поскольку вы можете использовать смещения 1/2/4 байта, я бы предположил, что общий адрес памяти является байтовым адресом. Хотя это не может быть распространенным приложением, могут быть случаи, когда вы захотите прочитать 32- или 64-битное значение с несогласованного адреса. Это одна из наиболее гибких вещей о архитектуре x86 по сравнению с чем-то вроде ARM; у вас есть гибкость для выполнения неправильных доступов, если вы хотите, вместо запуска исключения процессора, как это делают некоторые другие.

Ответ 3

зачем вы хотите загружать из неправильно настроенных адресов (например, использовать шкалу < 4)?

Несбалансированные нагрузки не являются единственным прецедентом для шкалы < размер элемента. У вас могут быть только индексы, которые являются предварительно масштабированными байтовыми смещениями. Или рассмотрите векторизацию цикла над массивом указателей на структуры: вы можете собрать с базовым "адресом" нулевого или малого целочисленного смещения в структуру.

Поддержка этого прецедента - одна из причин того, что Intel разрабатывает инструкцию asm для поддержки этого, потому что сборки должны помочь компиляторам авто-векторизовать больше кода. Он также идеально подходит для того, чтобы байт VSIB был очень близок к SIB в кодировке машинного кода, но они могли бы легко предусмотреть масштабный коэффициент, чтобы дать вам выбор масштаба = 4,8,16,32 (или 8, 16,32,64 для сбора qword) с полем 2-битного шкалы.

Масштабные коэффициенты, превышающие размер элемента, во многих случаях также явно не полезны, и их легко эмулировать с помощью одной команды сдвига слева перед сборкой. Но было бы невозможно обойти закодированный масштабный коэффициент, поэтому предоставление немасштабированных индексов, несомненно, является более гибким выбором дизайна.


Другие прецеденты: сбор 16-битных элементов. Используйте 32-битную сборку и закройте верхнюю половину каждого элемента после сбора. (Или просто оставите его с мусором). Это приведет к смещению нагрузки, если какой-либо из ваших индексов будет нечетным (для масштабного коэффициента 2), поэтому он может быть медленным, если они пересекают границы 4k (в отличие от истинной 16-разрядной сборки).

Вы также можете представить, как использовать сборку как часть функции декомпрессии, где после некоторого декодирования у вас есть вектор смещений в буфер, и вам нужны произвольные 4-байтные или 8-байтовые окна данных.