Компилятор [GCC](https://gcc.gnu.org/onlinedocs/gcc/Using-Assembly-Language-with-C.html) предоставляет возможность использовать ассемблерные вставки. Это может быть полезно например для умножения двух 64-битных чисел по 64-битному модулю. ↵
↵
Дело в том, что умножая два 64-битных регистра, процессор сохраняет результат в паре регистров **rdx** (верхнюю часть) и **rax** (нижнюю часть). Деление же работает похожим образом: делимое берется с регистров **rdx** и **rax**, после чего в **rax** сохраняется частное, а в **rdx** остаток. ↵
↵
Используя эти знания можно реализовать аналог следующей функции:↵
↵
~~~~~↵
inline long long mul(long long a, long long b) {↵
return (__int128)a * b % 1000000014018503;↵
}↵
~~~~~↵
↵
Вот таким образом:↵
↵
~~~~~↵
inline long long mul(long long a, long long b) {↵
long long res;↵
asm(↵
"mov %1, %%rax\n"↵
"mov %2, %%rbx\n"↵
"imul %%rbx\n"↵
"mov $1000000014018503, %%rbx\n"↵
"idiv %%rbx\n"↵
"mov %%rdx, %0\n"↵
:"=res"(res)↵
:"a"(a), "b"(b)↵
);↵
return res;↵
}↵
~~~~~↵
↵
Мы указываем на использование переменных **res** на запись, **a** и **b** на чтение. Они соответственно получают обозначения **%0**, **%1**, **%2**. Операции записываются с использованием стандартного _AT&T_ синтаксиса.↵
↵
Теперь вы умеете писать хеши по 64-битному модулю, что эквивалентно использованию пары по 32-битному модулю, без использования ___int128_.↵
↵
Дело в том, что умножая два 64-битных регистра, процессор сохраняет результат в паре регистров **rdx** (верхнюю часть) и **rax** (нижнюю часть). Деление же работает похожим образом: делимое берется с регистров **rdx** и **rax**, после чего в **rax** сохраняется частное, а в **rdx** остаток. ↵
↵
Используя эти знания можно реализовать аналог следующей функции:↵
↵
~~~~~↵
inline long long mul(long long a, long long b) {↵
return (__int128)a * b % 1000000014018503;↵
}↵
~~~~~↵
↵
Вот таким образом:↵
↵
~~~~~↵
inline long long mul(long long a, long long b) {↵
long long res;↵
asm(↵
"mov %1, %%rax\n"↵
"mov %2, %%rbx\n"↵
"imul %%rbx\n"↵
"mov $1000000014018503, %%rbx\n"↵
"idiv %%rbx\n"↵
"mov %%rdx, %0\n"↵
:"=res"(res)↵
:"a"(a), "b"(b)↵
);↵
return res;↵
}↵
~~~~~↵
↵
Мы указываем на использование переменных **res** на запись, **a** и **b** на чтение. Они соответственно получают обозначения **%0**, **%1**, **%2**. Операции записываются с использованием стандартного _AT&T_ синтаксиса.↵
↵
Теперь вы умеете писать хеши по 64-битному модулю, что эквивалентно использованию пары по 32-битному модулю, без использования ___int128_.↵