Выбор между выровненными и не выровненными инструкциями x86 SIMD - PullRequest
0 голосов
/ 03 сентября 2018

Обычно существует два типа SIMD-инструкций:

A. Те, которые работают с выровненными адресами памяти, вызовут исключение общей защиты (#GP), если адрес не выровнен по границе размера операнда:

movaps  xmm0, xmmword ptr [rax]
vmovaps ymm0, ymmword ptr [rax]
vmovaps zmm0, zmmword ptr [rax]

B. А те, которые работают с невыровненными адресами памяти, не вызовут такого исключения:

movups  xmm0, xmmword ptr [rax]
vmovups ymm0, ymmword ptr [rax]
vmovups zmm0, zmmword ptr [rax]

Но мне просто любопытно, зачем мне стрелять себе в ногу и вообще использовать выровненные инструкции памяти первой группы?

Ответы [ 2 ]

0 голосов
/ 18 сентября 2018

Я думаю, что есть небольшая разница между использованием _mm_loadu_ps и _mm_load_ps даже в «Intel Nehalem и более поздних версиях (включая Silvermont и более поздние версии) и AMD Bulldozer и более поздних версиях», которые могут влиять на производительность.

Операции, которые складывают загрузку и другие операции, такие как умножение в одну инструкцию, могут выполняться только с внутренними load, а не loadu, если только вы не компилируете с включенным AVX, чтобы разрешить невыровненные операнды памяти.

Рассмотрим следующий код

#include <x86intrin.h>
__m128 foo(float *x, float *y) {
    __m128 vx = _mm_loadu_ps(x);
    __m128 vy = _mm_loadu_ps(y);
    return vx*vy;
}

Это преобразуется в

movups  xmm0, XMMWORD PTR [rdi]
movups  xmm1, XMMWORD PTR [rsi]
mulps   xmm0, xmm1

однако, если используются встроенные встроенные функции загрузки (_mm_load_ps), он компилируется в

movaps  xmm0, XMMWORD PTR [rdi]
mulps   xmm0, XMMWORD PTR [rsi]

, который сохраняет одну инструкцию. Но если компилятор может использовать нагрузки, закодированные в VEX, для .

это всего лишь две команды .
vmovups xmm0, XMMWORD PTR [rsi]
vmulps  xmm0, xmm0, XMMWORD PTR [rdi]

Поэтому для согласованного доступа нет разницы в производительности при использовании инструкций movaps и movups для Intel Nehalem и более поздних версий, Silvermont и более поздних версий, AMD Bulldozer и более поздних версий.

Но может быть разницей в производительности при использовании _mm_loadu_ps и _mm_load_ps intrinsics при компиляции без включенного AVX, в тех случаях, когда компилятор не компенсирует movaps против movups, это между movups или складыванием нагрузки в инструкцию ALU. (Это происходит, когда вектор используется только как вход для одной вещи, иначе компилятор будет использовать загрузку mov*, чтобы получить результат в регистре для повторного использования.)

0 голосов
/ 03 сентября 2018
  • Нераспределенный доступ: можно использовать только movups/vmovups. Те же самые штрафы, которые обсуждались в случае согласованного доступа (см. Далее), применимы и здесь. Кроме того, доступы, которые пересекают строку кэша или границу виртуальной страницы, всегда влекут за собой штрафы на всех процессорах.
  • Выровненный доступ:
    • В Intel Nehalem и более поздних версиях (включая Silvermont и более поздних) и AMD Bulldozer и более поздних версиях: после предварительного кодирования они выполняются одинаково точно для тех же операндов. Это включает поддержку для устранения движения. Для этапов выборки и предварительного кодирования они потребляют одни и те же точные ресурсы для одинаковых операндов.
    • В версиях до Nehalem, Bonnell и pre-Bulldozer: они декодируются в различные мопы слитых доменов и не слитые домены. movups/vmovups потребляют больше ресурсов (в два раза больше) во внешнем и внутреннем конвейере конвейера. Другими словами, movups/vmovups может быть вдвое медленнее, чем movaps/vmovaps, с точки зрения задержки и / или пропускной способности.

Поэтому, если вы не заботитесь о старых микроархитектурах, оба они технически эквивалентны. Хотя если вы знаете или ожидаете, что данные будут выровнены, вы должны использовать выровненные инструкции, чтобы гарантировать, что данные действительно выровнены, без необходимости добавлять явные проверки в коде.

...