Могут ли длинные целочисленные подпрограммы получить выгоду от SSE?

Я все еще работаю над процедурами для произвольных длинных целых чисел на C ++. До сих пор я реализовал сложение / вычитание и умножение для 64-битных процессоров Intel.

Все работает нормально, но мне было интересно, смогу ли я немного ускорить это с помощью SSE. Я просмотрел документы SSE и списки инструкций процессора, но не смог найти ничего, что, по моему мнению, можно было бы использовать, и вот почему:

  • SSE имеет несколько целочисленных инструкций, но большинство инструкций обрабатывают числа с плавающей запятой. Не похоже, что он был разработан для использования с целыми числами (например, есть ли целочисленное сравнение за меньшее?)

  • Идея SSE - это SIMD (одна и та же инструкция, несколько данных), поэтому она предоставляет инструкции для 2 или 4 независимых операций. Я, с другой стороны, хотел бы иметь что-то вроде 128-битного целочисленного сложения (128-битный ввод и вывод). Кажется, этого не существует. (Еще? Может быть, в AVX2?)

  • Сложение и вычитание целых чисел не обрабатывают ни входных, ни выходных переносов. Так что делать это вручную очень громоздко (и, следовательно, медленно).

Мой вопрос: верна ли моя оценка или я что-то упустил? Могут ли длинные целочисленные подпрограммы получить выгоду от SSE? В частности, могут ли они помочь мне написать более быструю процедуру добавления, подпрограммы или сложения?


person cxxl    schedule 15.01.2012    source источник


Ответы (1)


В прошлом ответ на этот вопрос был твердым «нет». Но по состоянию на 2017 год ситуация меняется.

Но прежде чем я продолжу, время для некоторой базовой терминологии:

  1. Полная арифметика слов
  2. Арифметика с частичными словами


Арифметика полного слова:

Это стандартное представление, в котором число хранится в базе 2 32 или 2 64 с использованием массива 32-битных или 64-битных целых чисел. Многие библиотеки и приложения bignum (включая GMP) используют это представление.

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

Именно это распространение переноса делает почти невозможным векторизацию большой арифметики.


Арифметика с неполным словом

Это менее используемое представление, в котором число использует основание меньше аппаратного размера слова. Например, в каждое 64-битное слово помещается только 60 бит. Или используйте базу 1,000,000,000 с 32-битным размером слова для десятичной арифметики.

Авторы GMP называют это «гвоздями», где «гвоздь» - неиспользованная часть слова.

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


Проблемы с арифметикой полного слова:

Векторизация полнословной арифметики исторически была безнадежным делом:

  1. SSE / AVX2 не поддерживает распространение переноса.
  2. SSE / AVX2 не имеет 128-битного добавления / подпрограммы.
  3. SSE / AVX2 не поддерживает 64 x 64-битное целочисленное умножение. *

* AVX512-DQ добавляет нижнюю половину 64x64-битного умножения. Но инструкции в верхней половине по-прежнему нет.

Кроме того, в x86 / x64 есть множество специализированных скалярных инструкций для больших чисел:

  • Надстройка с переносом: adc, adcx, adox.
  • Умножение на двойное слово: одинарные операнды mul и mulx.

В свете этого, для SIMD трудно превзойти скаляр на x64 как с bignum-add, так и с bignum-multiply. Определенно не с SSE или AVX.

В AVX2 SIMD почти конкурирует со скалярным bignum-умножением, если вы переупорядочиваете данные, чтобы включить «вертикальную векторизацию» 4 различных (и независимых) умножений одинаковой длины на каждой из 4 дорожек SIMD.

AVX512 еще больше склоняется в пользу SIMD, снова предполагая вертикальную векторизацию.

Но по большей части «горизонтальная векторизация» бигнумов остается безнадежным делом, если у вас их много (одинакового размера) и вы не можете позволить себе стоимость их транспонирования, чтобы сделать их «вертикальными».


Векторизация арифметики с частичными словами

В арифметике с частичным словом дополнительные биты «гвоздя» позволяют задерживать распространение переноса.

Итак, пока вы не переполняете слово, добавление / добавление SIMD можно выполнить напрямую. Во многих реализациях представление частичного слова использует целые числа со знаком, чтобы слова были отрицательными.

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

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

Умножение сложнее с арифметикой с частичными словами, поскольку вам нужно иметь дело с кусочками гвоздя. Но, как и в случае с add / sub, тем не менее, это можно эффективно сделать на горизонтально-векторизованных больших изображениях.

AVX512-IFMA (идущий с процессорами Cannonlake) будет иметь инструкции, которые дают полные 104 бита умножения 52 x 52 бита (предположительно с использованием аппаратного обеспечения FPU). Это будет очень хорошо работать с представлениями частичных слов, которые используют 52 бита на слово.


Большое умножение с использованием БПФ

Для действительно больших больших чисел умножение наиболее эффективно выполняется с помощью быстрых преобразований Фурье (БПФ) < / а>.

БПФ полностью векторизуемы, поскольку они работают с независимыми double. Это возможно, потому что, по сути, представление, которое использует БПФ, является частичным представлением слов.


Подводя итог, можно сказать, что векторизация арифметики bignum возможна. Но нужно приносить жертвы.

Если вы ожидаете, что SSE / AVX сможет ускорить некоторый существующий код bignum без фундаментальных изменений в представлении и / или макете данных, это вряд ли произойдет.

Но, тем не менее, большую арифметику можно векторизовать.


Раскрытие:

Я автор y-cruncher, который выполняет множество арифметических операций с большими числами.

person Mysticial    schedule 15.01.2012
comment
Отличный ответ. Думаю, я еще один из многих, кто пытался, но потерпел неудачу. - person Z boson; 13.03.2015
comment
Но я не понимаю, в чем нет 128-битного целочисленного добавления / подпрограммы. Почему это проблема? В регистрах общего назначения / скалярных регистрах для этого тоже нет оборудования. Способ сделать это - два запоминания высоких и низких значений в отдельных регистрах SIMD. - person Z boson; 13.03.2015
comment
@Zboson Скалярные инструкции имеют добавление с переносом. Этого достаточно для эффективной реализации 128-битных добавлений / подписок. Стоит отметить, что Knights Corner Xeon Phi имеет надстройку SIMD с переносом с использованием регистров маски. Но взяли из AVX512. Я предполагаю, что это усложняет конструкцию, поскольку требует, чтобы регистры маски были связаны с исполнительными модулями. - person Mysticial; 13.03.2015
comment
Ваше утверждение Нет 64 x 64-битное целочисленное умножение. (низкий или высокий ...) неточно. AVX512 будет иметь размер от 64x64 до 64 (низкий), но даже если бы он был таким же быстрым, как от 32x32 до 64, это сильно помогло бы. Настоящая проблема - не от 64x64 до 128. Думаю, я имею в виду, что утверждение не должно быть 64 x 64-битное целочисленное умножение. (низкий и высокий ...) - person Z boson; 13.03.2015
comment
@Mysticial, я не знал, что в Knights Corner есть надстройка с переносом с регистрами маски. Это интересно. - person Z boson; 13.03.2015