2013-05-15 4 views
7

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

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

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

+4

В SSE или AVX нет 128-разрядных арифметических операций (кроме побитовых операций). –

+3

В SSE/AVX нет 128-битного * add *. Вы можете эмулировать его с помощью побитовых операций и сдвигов, но учитывая, что у вас уже есть правильные 64-разрядные скалярные арифметические инструкции в x86-64, которые легко объединяются для 128-битных операций, из этого ничего не получится. –

+0

Спасибо @Paul. Я сделал ответ, надеюсь, вы не против. –

ответ

11

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

Во-первых, как описано PaulR в комментариях: «Там нет 128 бит арифметических операций в SSE или AVX (кроме поразрядными операций)». Учитывая это, 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.

5

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

+3

Это объясняется очень хорошо [в Википедии] (https://en.wikipedia.org/wiki/128-bit): «Большинство современных процессоров имеют наборы команд SIMD (SSE, AltiVec и т. Д.), Где 128-битные векторные регистры используются для хранения нескольких меньших номеров, таких как четыре 32-битных числа с плавающей запятой. Одна команда может работать со всеми этими значениями параллельно. Однако эти процессоры не работают с отдельными номерами, длина которых составляет 128 двоичных цифр, только их регистры имеют размер 128 бит ». –

4

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

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

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

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

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

  • так 80386, 32бит CPU может сделать 64бит умножение/деление с помощью EAX: EDX пару
  • так 8086/88, 16 бит процессор может сделать 32бит умножение/разделение с помощью AX: DX пара

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

+0

«Конечно, у процессора нет надлежащего 128-битного ALU, поэтому они, вероятно, частично поддерживаются микрокодом». Действительно, вы думаете, что умножение 64x64, ** только ** вид умножения, доступный для 64-битных операндов GPR в x86 -64 ISA, реализуется микрокодом, потому что «у процессора нет надлежащего 128-битного ALU»? –

+0

@PascalCuoq: Я плохо сформулировал свои идеи. (Извините, но не носитель). (Для записи, назад с 80386, внутреннее умножение было реализовано внутри с петлей дополнений. Чем больше результат умножения -> чем больше времени требуется для получения результата.) Технология перешла к недавние процессоры, но я подозреваю *, что, поскольку Intel официально рекламирует их ALU как 64 бита, что если вы хотите получить большие результаты int (64x64 = 128 вместо 64x64 = 64), это возможно *, что эти дополнительные 64 бит будут стоить вы несколько дополнительных микроопераций. – DrYak

+0

, в ISA имеется только одно умножение 64-разрядных операндов GPR. Считаете ли вы, что Intel и AMD не делают это так быстро, как их возможно, зная, что это единственный, который программисты могут назвать, даже если им нужны только самые младшие 64 бит результата **? «64-битные ALU» и «128-битные ALU» - только упрощения. Когда вы знаете, что единственная команда умножения - 64x64-> 128, вы делаете ALU, который поддерживает умножение 64x64-> 128, период. –