Почему оба?vperm2f128 (avx) против vperm2i128 (avx2) - PullRequest
0 голосов
/ 07 декабря 2018

avx ввел инструкцию vperm2f128 (экспонируется через _mm256_permute2f128_si256), в то время как avx2 ввел vperm2i128 (экспонируется через _mm256_permute2x128_si256).

Они оба, кажется, делают то же самое, и ихсоответствующие задержки и пропускная способность также кажутся одинаковыми.

Так почему же существуют обе инструкции?Там должно быть какое-то обоснование этого?Может быть, я что-то упустил из виду?Учитывая, что avx2 работает со структурами данных, представленными в avx, я не могу себе представить, что когда-либо будет существовать процессор, который поддерживает avx2, но не avx.

1 Ответ

0 голосов
/ 07 декабря 2018

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

AVX:

Все 3 из них генерируют точно такую ​​же инструкцию,vperm2f128:

  • _mm256_permute2f128_pd()
  • _mm256_permute2f128_ps()
  • _mm256_permute2f128_si256()

Разница только в типах -которые не существуют на уровне команд.

vperm2f128 - это 256-битная инструкция с плавающей запятой.В AVX нет «настоящих» 256-битных целочисленных SIMD-инструкций.Таким образом, даже если _mm256_permute2f128_si256() является «целочисленным» свойством, на самом деле это просто синтаксический сахар для этого:

_mm256_castpd_si256(
    _mm256_permute2f128_pd(
        _mm256_castsi256_pd(x),
        _mm256_castsi256_pd(y),
        imm
    )
);

, который совершает круговой переход из целочисленного домена в домен FP - таким образом, возникают задержки обхода.Каким бы уродливым это ни выглядело, это единственный способ сделать это на земле только для AVX.

vperm2f128 - не единственная инструкция для получения этого лечения, я нахожу по крайней мере 3 из них:

  • vperm2f128 / _mm256_permute2f128_si256()
  • vextractf128 / _mm256_extractf128_si256()
  • vinsertf128 / _mm256_insertf128_si256()

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

Без этих "хакерских" встроенных функций вам потребуется использовать множество встроенных типов.

В любом случае, компетентный компилятор попытаетсяоптимизировать типы также.Таким образом, он будет генерировать загрузку / сохранение и перемешивание с плавающей точкой, даже если вы используете 256-битные целочисленные загрузки.Это уменьшает количество задержек обхода только до одного слоя.(при переходе от FP-shuffle к 128-разрядному целочисленному вычислению)


AVX2:

AVX2 очищает это безумие, добавляя правильное 256-разрядное целое числоПоддержка SIMD для всего, включая shuffles.

Инструкция vperm2i128 является новой вместе с новым встроенным для нее _mm256_permute2x128_si256().

Это, наряду с _mm256_extracti128_si256() и _mm256_inserti128_si256() позволяет выполнять 256-битное целочисленное SIMD и фактически полностью оставаться в целочисленной области.


Различие между целочисленными версиями FP одной и той же инструкции связано с задержками обхода.В старых процессорах имели место задержки для перемещения данных из доменов int <-> FP.Хотя сами регистры SIMD не зависят от типа, аппаратная реализация - нет.И есть дополнительная задержка, чтобы получить данные, выводимые инструкцией FP, на вход в целочисленную инструкцию.(и наоборот)

Таким образом, было важно (с точки зрения производительности) использовать правильный тип команды для соответствия фактическому типу данных, с которым он работал.

На новейших процессорах (Skylakeи позже?), кажется, больше нет задержек обхода int / FP в отношении команд shuffle.Несмотря на то, что набор команд все еще имеет это различие, команды перетасовки, которые выполняют одно и то же с разными «типами», вероятно, теперь отображаются в один и тот же элемент управления.

...