Compiler [GCC](https://gcc.gnu.org/onlinedocs/gcc/Using-Assembly-Language-with-C.html ) provides the ability to use assembler inserts. This can be useful, for example, for multiplying two 64-bit numbers by a 64-bit module.↵
↵
The fact is that multiplying two 64-bit registers, the processor stores the result in a pair of registers **rdx** (upper part) and **rax** (lower part). Division works in a similar way: the divisible is taken from the registers **rdx** and **rax**, after which the quotient is stored in **rax**, and the remainder is stored in **rdx**.↵
↵
Using this knowledge, you can implement an analog of the following function:↵
↵
~~~~~↵
inline long long mul(long long a, long long b) {↵
return (__int128)a * b % 1000000014018503;↵
}↵
~~~~~↵
↵
In this way:↵
↵
~~~~~↵
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;↵
}↵
~~~~~↵
↵
We indicate the use of variables **res** for writing, **a** and **b** for reading. They accordingly receive designations **%0**, **%1**, **%2**. Operations are written using the standard _AT&T_ syntax.↵
↵
Now you can write hashes using a 64-bit module, which is equivalent to using a pair using a 32-bit module, without using ___int128_.
↵
The fact is that multiplying two 64-bit registers, the processor stores the result in a pair of registers **rdx** (upper part) and **rax** (lower part). Division works in a similar way: the divisible is taken from the registers **rdx** and **rax**, after which the quotient is stored in **rax**, and the remainder is stored in **rdx**.↵
↵
Using this knowledge, you can implement an analog of the following function:↵
↵
~~~~~↵
inline long long mul(long long a, long long b) {↵
return (__int128)a * b % 1000000014018503;↵
}↵
~~~~~↵
↵
In this way:↵
↵
~~~~~↵
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;↵
}↵
~~~~~↵
↵
We indicate the use of variables **res** for writing, **a** and **b** for reading. They accordingly receive designations **%0**, **%1**, **%2**. Operations are written using the standard _AT&T_ syntax.↵
↵
Now you can write hashes using a 64-bit module, which is equivalent to using a pair using a 32-bit module, without using ___int128_.