Как это 128-битное целочисленное умножение работает в сборке (x86-64)?

Я читаю "Компьютерные системы: перспектива программиста" , а домашнее задание - описать, как работает этот алгоритм.

Функция C:

void store_prod(__int128 *dest, int64_t x, int64_t y) {
    *dest = x * (__int128)y;
}

Сборка:

movq %rdx, %rax
cqto
movq  %rsi, %rcx
sarq  $63,  %rcx
imulq %rax, %rcx
imulq %rsi, %rdx
addq  %rdx, %rcx
mulq  %rsi
addq  %rcx, %rdx
movq  %rax, (%rdi)
movq  %rdx, 8(%rdi)
ret

Я не знаю, почему он выполняет: xh * yl + yh * xl = value which we add after unsigned multiplication

7
задан denis631 18 нояб. '15 в 22:59
источник поделиться
3 ответов

Что GCC делает, это использование свойства, которое может быть выполнено с помощью следующей формулы.

(hi,lo) = unsigned(x*y)
hi -= ((x<0) ? y : 0)  + ((y<0) ? x : 0)

Несмотря на то, что это не нужно делать, поскольку в этом случае набор команд x86-64 имеет подписанную 64-разрядную * 64-битную и 128-разрядную инструкцию (imul с одним операндом), эта формула полезен в других случаях. Например, для реализации подписанного 128-битного умножения с SSE2/AVX2/AVX512 или для реализации 256-битного умножения, когда набор команд только 128-битное умножение (например, с x86-64).

GCC реализовала эту формулу несколько иначе. Если взять бит знака и распространить его на все слово, вызовите эту функцию sign_ext, тогда функция вернет -1 или 0. Тогда что сделал GCC:

hi += sign_ext(x)*y + sign_ext(y)*x

например sign_ext(x)*y в псевдо-инструкциях для 64-битных слов

sarq  $63, x    ; sign_ext(x)
imulq   y, x    ; sign_ext(x)*y

Итак, теперь вы спрашиваете (или хотите спросить):

Почему эта формула истинна?

Это хорошее qeustion. Я тоже задал этот вопрос и njuffa написал

@Zboson: Он непосредственно следует из двух представлений дополнения комплемента. Например. 32-битные целые числа -n и -m представлены как беззнаковые числа x=2**32-n, y=2**32-m. Если вы умножаете те, у которых есть x*y = 2**64 - 2**32*n - 2**32*m + n*m. Средние условия указывают на необходимые исправления в верхней половине продукта. Простой пример с использованием -1 * -1 должен быть очень поучительным.

2
ответ дан Z boson 25 нояб. '15 в 12:40
источник поделиться

Как всегда, параметры компилятора имеют значение. Этот исходный код с gcc -Og (оптимизация для отладки) создает очень похожий asm для вашего списка (литой знак - расширяет оба операнда до 128 бит, прежде чем делать полный 128x128- > 128 умножить). Это именно то, что должно сказать стандарт C (целое продвижение). Если вы собираетесь поговорить о выходе компилятора, вы всегда должны указать, какую версию компилятора использовать с какими параметрами. Или просто разместите ссылку на него на godbolt, как показано выше.

(Edit: oops, source и asm были из книги, которая не выдавала эту информацию.)

С gcc -O3 gcc использует тот факт, что оба операнда по-прежнему на самом деле всего лишь 64 бит, поэтому достаточно одного imul..


sar $63, %rcx является частью расширяющего знак rsi в rcx:rsi, как и cqto sign-extends rax в rdx:rax.


Большая часть этого ответа уже была дана другими людьми в комментариях, но я не думаю, что кто-то еще заметил, что gcc -Og/-O1 дает почти точно этот выход asm.

4
ответ дан Peter Cordes 19 нояб. '15 в 3:43
источник поделиться

Чтобы понять, зачем мы делаем эти операции, попробуйте интерпретировать int128_t как: 2 ^ 64 * xh + xl

поэтому, если мы хотим умножить два целых числа int128_t, мы сделаем следующее:

x = 2 ^ 64 * xh + xl

y = 2 ^ 64 * yh + yl

так что x * y = (2 ^ 128 * xh * yh) + (2 ^ 64 * xh * yl) + (2 ^ 64 * yh * xl) + (yl * xl)

И это именно то, что делает код сборки:

yh =% rdx yl =% rax

xh =% rcx xl =% rsi

2 ^ 64 * xh * yl: is imulq %rax, %rcx 2 ^ 64 указывает, что нам нужно добавить это к битам высокого порядка

2 ^ 64 * yh * xl: is imulq %rsi, %rdx 2 ^ 64 указывает, что нам нужно добавить это к битам высокого порядка

2 ^ 128 * xh * yh: эта операция не требуется, так как 2^128 * xh * yh не будет входить в 128-битное целое число. Он представляет только информацию о битах знака и может быть проигнорирован.

xl * yl: is mulq %rsi

Надеюсь, это прояснит ситуацию!

1
ответ дан denis631 21 нояб. '15 в 13:11
источник поделиться

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