Por que o GCC usa a multiplicação por um número estranho na implementação da divisão inteira?
Eu tenho lido sobrediv
emul
operações de montagem e eu decidi vê-las em ação escrevendo um programa simples em C:
#include <stdlib.h>
#include <stdio.h>
int main()
{
size_t i = 9;
size_t j = i / 5;
printf("%zu\n",j);
return 0;
}
E, em seguida, gerando código de linguagem assembly com:
gcc -S division.c -O0 -masm=intel
Mas olhando geradodivision.s
arquivo, ele não contém nenhuma operação div! Em vez disso, ele faz algum tipo de magia negra com números de mágica e deslocamento de bits. Aqui está um trecho de código que calculai/5
:
mov rax, QWORD PTR [rbp-16] ; Move i (=9) to RAX
movabs rdx, -3689348814741910323 ; Move some magic number to RDX (?)
mul rdx ; Multiply 9 by magic number
mov rax, rdx ; Take only the upper 64 bits of the result
shr rax, 2 ; Shift these bits 2 places to the right (?)
mov QWORD PTR [rbp-8], rax ; Magically, RAX contains 9/5=1 now,
; so we can assign it to j
Oque esta acontecendo aqui? Por que o GCC não usa div? Como ele gera esse número mágico e por que tudo funciona?