Skip to main content
GameDev.net gamedev.net
🔒 Locked

x64 DIV intrinsic

Started by Ryan_001 Sep 13, 2008 at 3:56 PM 6 replies 8.4k views
Original Post
Ryan_001
Ryan_001
I'm working on a few fixed point math routines, and need a long divide (128 bit dividend, 64 bit divisor). I found the multiplication equivalent (_mul128) which is a long multiply. 64 bit processors have a long divide instruction (div), but I can't seem to find the intrinsic for it (wouldn't be a problem if I could use inline assembly, but thats a complaint for another time).
Ryan_001
Ryan_001
I should point out that this is for the visual C++ 9.0 compiler (the one that comes with the Windows SDK).

That said, 71 views and no one's ever tried to do a long divide?
frob
frob
Compilers go to great lengths to avoid DIV and IDIV instructions.

I'm not surprised that you can't find an intrinsic for them, since they are generally something to avoid.




Division is typically a slow operation and is very frequently optimized into faster instructions by the compiler.

Division by powers of two is trivially optimized to extremely fast operations for both integral and floating point types. For integers it is a shift right, for floating point it is subtracting from the exp bits.

Division for many numbers can involve simple lookup tables. Through a combination of lookups, additions, and shifts, and bitwise ops, it is usually easy to outperform the CPU's division operations.

Division is equivalent multiplication by the reciprocal. Multiplication is a much faster operation than division. Finding the reciprocal can be expensive if the divisor isn't a constant, so this may or may not be a performance difference -- but the compiler writers know the cost of each instruction in terms of the microops that are generated.



Division is a very slow operation. There are thousands of tricks to make it faster. This is one case where you really ought to trust the compiler's authors to optimize the code for you.


implicit
implicit
I seem to recall someone else complaining about the lack of 128-bit division intrinsics. No great surprise really, the set of intrinsics has always been patchy and demand for ones not supported on 32-bit machines is probably low.

The obvious solution is use a short assembly snippet.
If you can't/don't want to do that then I guess you could synthesize it from a pair of 64-bit divisions, but judging from the implementation in Hacker's Delight that seems to involve two pages of bizarre and inexplicable bit twiddling.
There's plenty of multi-precision arithmetic libraries out there if you don't care about performance..

Quote:
Original post by frob
Division is a very slow operation. There are thousands of tricks to make it faster. This is one case where you really ought to trust the compiler's authors to optimize the code for you.
There's nothing to trust the compiler with, MSVC won't just let you apply the division operator on 128-bit integers.
And, sure, there are all kinds of neat tricks to do fast approximate division. But I rather think the OP would be using floating point instead of messing with 128-bit intrinsics if precision wasn't an issue.
frob
frob
Quote:
Original post by implicit
IThere's nothing to trust the compiler with, MSVC won't just let you apply the division operator on 128-bit integers.

__int128 a = 1234;
__int64 b = 617;
__int128 c = a / b;

Does this not work for you?
implicit
implicit
Quote:
Original post by frob
Quote:
Original post by implicit
IThere's nothing to trust the compiler with, MSVC won't just let you apply the division operator on 128-bit integers.

__int128 a = 1234;
__int64 b = 617;
__int128 c = a / b;

Does this not work for you?
Oh. I apologize then, I could've sworn it wasn't supported last time I tried. I don't run 64-bit Windows on my machine at home but I'll take your word for it. Oddly enough __int128 doesn't seem to be documented at all on MSDN.

Any chance you could post the generated assembly code? The semantics for doing this in C are slightly different from the native division instruction, as DIV only generates 64-bit results and overflows generate exceptions so I imagine you'd need some interesting workarounds to deal with it.
If my experiences with 64-bit arithmetic on MSVC for x86 are anything to go by I'd expect a call to a general 128-by-128 division routine.
Ryan_001
Ryan_001

implicit:
__int128 is supported on 64 bit machines, like __int64 is supported on 32 bit machines.

frob:
I was gonna actually fall back to that one if I couldn't find an intrinsic, but I'd assume they'd promote b to a __int128 prior to division, and then emulate it somehow. The funny thing is there is a __mul128 intrinsic. Why would they not support __div128 or whatever is beyond me. As first I thought maybe I was just looking in the wrong spot, now I'm begining to think it may just not exist.

As far as speed/accuracy/avoiding div goes. Yes I am aware div is quite slow, but its a fixed point type library, u can't just ignore an operator cause u won't use it often, there are times when u need a full precision divide. I do have fall-back code, which does the long division manually, but its horrendously slow (as u can imagine). Either way though its kinda a moot point, as there's no way I'm gonna out perform a built in hardware OP (not even the compiler is gonna out-optimize the engineers that built the hardware in this case).

/rant
The part that annoys me is inline assembly is not allowed in 64-bit programs, ur supposed to use intrinsics instead, but how are u supposed to use it if even the most fundamental operations aren't support (I mean its a divide for crying out loud, not some weird packed multiply by power of three kittens SSE26x2.0 op). At the very least they could mention it somewhere on the MSDN site.
/end rant

Ahhh well, thx for the responses anyways. Maybe this is just a sign to move onto a different compiler. Too bad the intel one costs, its pretty darn sweet.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.