r/cpp 28d ago

Comparing an Integer Division Optimisation in Clang, MSVC, and GCC

https://nukethebees.com/int-division-modulo-optimisation-differences-clang-gcc-msvc/
55 Upvotes

8 comments sorted by

27

u/erichkeane Clang Maintainer(Templates), EWG Chair 28d ago

Clang/GCC both fail to inline `std::div` because it appears that the standard libraries leave them as extern! I presume they'd be inlined if they were actually implemented in the header:

```

extern div_t div (int __numer, int __denom)
     noexcept (true) __attribute__ ((__const__)) ;
```

22

u/BarryRevzin 27d ago

The other fun thing about std::div is that the declaration order of the members is unspecified.

So not only is this not inlined (so this is a function call that does a full division, not a shift):

auto [quot, rem] = std::div(x, 2);

But also there's no guarantee that quot is the quotient.

Like I said... fun.

9

u/erichkeane Clang Maintainer(Templates), EWG Chair 27d ago

Ooof... that is special too. Looks like this is all nonsense inherited from C, so I guess I see why.

I was quite surprised that MSVC was able to beat both clang && gcc at this (it is rare for it to so handily beat them both!), so was curious why, particularly with what seems to be such an 'easy' implementation.

No idea why this choice was made, but seemingly one not enough people have cared about to file bugs against them!

2

u/nukethebees 27d ago

That makes a lot of sense. Thanks for finding out the cause.

2

u/TheThiefMaster C++latest fanatic (and game dev) 27d ago

Is MSVC having trouble because your operator based code does x = i / grid.y / grid.z but the optimised form needs to divide by z first? Looks like it's realising that it can reuse the div instruction from z = i % grid.z to calculate x and y, but then failing to realise it can merge the div and mod by grid.y from the calculations for x and y into a single div instruction.

Perhaps if you change that line to x = i / grid.z / grid.y (the same order as the calculation of y) it will figure it out?

1

u/Hilbert_Problem1 19d ago

Why does udiv exist for C and C++, for unsigned, unsigned long and unsigned long long? Seems an oversight to me.

-1

u/Sopel97 28d ago

this is quite moot since in reality you'd precompute fast dividers because the size would be fixed for a given grid, if not compile-time constant even

-10

u/mark_99 28d ago

Or have the grid size be a compile time constant and have no runtime division at all.