2

Recently I came across the following set of vector instructions:

movq      xmm0, rcx
punpckldq xmm0, 0x4530000043300000
subpd     xmm0, 0x4330000000000000
haddpd    xmm0, xmm0

The only sensible information I found based on the constants is a routine called EmitFPVectorU64ToDouble. Runtime behavior seemed to confirm that these instructions indeed convert an unsigned integer onto scalar double-precision float.

What I'm looking for is an explanation of why these instructions achieve the result, theory behind it.

2

I was wondering the same thing. The idea behind these instructions is to split QWORD in two DWORDs, then to make two floating point numbers corresponding to each and add them up. Here's how this seems to work:

Operands in the snippet look incomplete, let's add missing higher QWORDs to operands:

movq      xmm0, rcx
punpckldq xmm0, 0x00000000000000004530000043300000 
subpd     xmm0, 0x45300000000000004330000000000000
haddpd    xmm0, xmm0

First MOVQ copies QWORD from RCX to lower half of XMM0. Then, PUNPCKLDQ instruction is used to construct two double precision floats in XMM0. It interleaves two DWORDs from source and destination. In pseudocode this can look like this:

xmm0 = ((0x43300000<<32)|xmm0[0:31]) | (((45300000<<32)|xmm0[32:63])<<64)

As a result each of the doubles is made of two parts: some magic constant + 32 bits of integer data. In order to understand what these magics do, we need to look at memory layout of a double. double precision memory layout

So, the magic sets sign, exponent and 20 higher bits of fraction. For the first double (the one with 0x43300000 magic) the exponent is set to 1075 which makes contribution of least significant bit in fraction to be exactly 1. This trick allows to substitute fraction bits with any unsigned integer input without conversion.

LSB_contribution: 2^(1075-1023)*2^(-52) = 2^52*2^(-52) = 1

The second magic sets exponent to 1107 to make contribution of LSB equal to 2^32 instead of 1 to match magnitudes of bits in higher DWORD.

Since floating point representation has implicit 1 bit added to fraction the resulting values has constant offset, which is removed by SUBPD instruction. It subtracts double values with same magic constants and all fraction bits set to 0.

At this point XMM0 contains two double values that correspond to DWORDS of input that can be summed with HADDPD to obtain the final result in lower half of XMM0 (so this is 64 bit unsigned integer to 64 bit floating point conversion).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.