Эмулируется ли __int128_t арифметикой GCC даже с SSE?

Я слышал, что 128-битные целочисленные типы данных, такие как __int128_t предоставляемые GCC эмулируются и поэтому работают медленно. Однако я понимаю, что в различных наборах инструкций SSE (SSE, SSE2, ..., AVX) были введены, по крайней мере, некоторые инструкции для 128-битных регистров. Я не очень разбираюсь в SSE или сборке / машинном коде, поэтому мне было интересно, может ли кто-нибудь объяснить мне, арифметика с __int128_t эмулируется или не использует современные версии GCC.

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

Итак, какие части __int128_t арифметика эмулируется GCC, и какие части реализованы с помощью инструкций SSE (если есть)?

3 ответа

Решение

Я путал две разные вещи в моем вопросе.

Во-первых, как пояснил PaulR в комментариях: "В SSE или AVX нет 128-битных арифметических операций (кроме битовых операций)". Учитывая это, 128-битная арифметика должна эмулироваться на современных процессорах на базе x86-64 (например, AMD Family 10 или архитектура Intel Core). Это не имеет ничего общего с GCC.

Вторая часть вопроса заключается в том, выигрывает ли 128-битная арифметическая эмуляция в GCC от инструкций или регистров SSE/AVX. Как подразумевается в комментариях PaulR, в SSE/AVX не так много всего, что позволит вам более легко выполнять 128-битную арифметику; скорее всего, для этого будут использованы инструкции x86-64. Код, который меня интересует, не может быть скомпилирован -mno-sse, но он прекрасно компилируется с -mno-sse2 -mno-sse3 -mno-ssse3 -mno-sse4 -mno-sse4.1 -mno-sse4.2 -mno-avx -mno-avx2 и производительность не влияет. Так что мой код не выигрывает от современных инструкций SSE.

Инструкции SSE2-AVX доступны для 8,16,32,64-битных целочисленных типов данных. Они в основном предназначены для совместной обработки упакованных данных, например, 128-битный регистр может содержать четыре 32-битных целых числа и так далее.

Хотя SSE/AVX/AVX512/ и т.д. не имеют 128-битного режима (их векторные элементы строго 64-битные макс., и операции будут просто переполнены), как подразумевал Пол Р., основной ЦП поддерживает ограниченные 128-битные операции, используя пару регистров.

  • При умножении двух обычных 64-битных чисел MUL/IMUL может выводить свой 128-битный результат в регистровой паре RAX/RDX.
  • И наоборот, при делении DIV/IDIV можно использовать входные данные от пары RAX/RDX для деления 128-го числа на 64-битный делитель (и выдает 64-битное отношение + 64-битное по модулю)

Конечно, ALU процессора 64-битный, поэтому, как подразумевается в документации Intel, эти более высокие 64-битные стоят за счет дополнительных микроопераций в микрокоде. Это более драматично для подразделений (> в 3 раза больше), которые уже требуют много микроопераций для обработки.

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

Это было доступно в течение длительного времени:

  • начиная с 80386, 32-битный процессор может выполнять 64-битное умножение / деление с использованием пары EAX:EDX
  • начиная с 8086/88, 16-битный процессор мог делать 32-битное умножение / деление, используя пару AX:DX

(Что касается дополнений и вычитаний: благодаря поддержке переноса, добавление / вычитание чисел любой произвольной длины, которые могут заполнить ваше хранилище, совершенно тривиально).

Другие вопросы по тегам