0

I've seen that gcc does a great job in optimizing integer divisions with a constant divisor.

E.g.

uint64_t f(uint64_t x)
{
    return x / 1000;
}

uint64_t f2(uint64_t x)
{
    return x / 10000;
}

becomes:

f:
        push    rbp
        mov     rbp, rsp
        mov     QWORD PTR [rbp-8], rdi
        mov     rax, QWORD PTR [rbp-8]
        shr     rax, 3
        movabs  rdx, 2361183241434822607
        mul     rdx
        mov     rax, rdx
        shr     rax, 4
        pop     rbp
        ret
f2:
        push    rbp
        mov     rbp, rsp
        mov     QWORD PTR [rbp-8], rdi
        mov     rax, QWORD PTR [rbp-8]
        movabs  rdx, 3777893186295716171
        mul     rdx
        mov     rax, rdx
        shr     rax, 11
        pop     rbp
        ret

It seems all divisions can be reduced to a shift + multiplication + shift (not always are all of those operations included).

How is this obtained and how can I get manually the required numbers for those three operations? I specifically need to know this for uint64_t,

Thanks a lot

3
  • 1
    Observe that 2^(64+3+4)=2361183241434822606848≈2361183241434822607*1000 and 2^(64+11)=37778931862957161709568≈3777893186295716171*10000. Commented Jul 18, 2023 at 21:11
  • 1
    Does this answer your question? Why does GCC use multiplication by a strange number in implementing integer division? Commented Jul 20, 2023 at 5:44
  • @NateEldredge This answer indeed covers most of what I need to know (e.g. libdivide is quite helpful) Commented Jul 20, 2023 at 7:14

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.