0

I need an x86 sequence to convert a 64-bit unsigned integer into a floating point. This would be simple enough with a signed integer, but there doesn't seem to be an instruction that can do so with one that is unsigned. I believe you could normally use VCVTUSI2SD, but this is not accessible by my assembler.

So in terms of assembly, it would accomplish this:

unsigned long long x = ... ;
double y = (double)x;

Another similar question was posted here but involves 32-bit register manipulation. This requires the conversion of 64-bit values instead, which adds some complexity to the math.

prz
  • 25
  • 4
  • 5
    Have you tried compiling the equivalent C code and see what the compiler generates? – sj95126 Aug 08 '22 at 21:53
  • Which instruction set extensions are you permitted to use? Which assembler do you use? Note that assembly is assembled, not compiled. – fuz Aug 08 '22 at 23:04
  • `VCVTUSI2SD` is AVX-512. If you're targeting a recent cloud server, then yes, it's normally available. If you need to run on client CPUs other than Ice Lake / Tiger Lake, you're out of luck :/ – Peter Cordes Aug 09 '22 at 00:54
  • re: your edit: [How to convert an unsigned integer to floating-point in x86 (32-bit) assembly?](https://stackoverflow.com/a/11725575) has an answer with 64-bit code from GCC output. It also has an AVX-512 answer where the extraction/insertion of 32-bit halves is separate from the actual conversion, so you'd just use `vmovq`. Or use `VCVTUSI2SD` in the first place. – Peter Cordes Jul 28 '23 at 18:25

1 Answers1

3

I assume Intel x86_64 here. You would typically use cvtsi2sd in these cases with treatment of sign

https://www.felixcloutier.com/x86/cvtsi2sd

//
// prototype: double convert(uint64_t value)
//
convert(unsigned long):        
        testq   %rdi, %rdi
        js      .Negative
        pxor    %xmm0, %xmm0
        cvtsi2sdq       %rdi, %xmm0
        ret
.Negative:
        movq    %rdi, %rax
        andl    $1, %edi
        pxor    %xmm0, %xmm0
        shrq    %rax
        orq     %rdi, %rax
        cvtsi2sdq       %rax, %xmm0
        addsd   %xmm0, %xmm0
        ret

Basically because cvtsi2sdq takes a signed integer, you obviously have to treat the case where the uint64_t would be recognized as a negative.

Basically what this code is doing is something like this:

double signed_convert( int64_t value ); // trivial

double convert( uint64_t value ) {
   if ( value>>63 == 0 ) return signed_convert( value );
   double half = signed_convert( (value>>1) | (value&1) );
   return 2*half;
}
Something Something
  • 3,999
  • 1
  • 6
  • 21
  • You can hoist `pxor %xmm0, %xmm0` ahead of the `test/js`, since you want it in both sides of the branch. (Or neither if you happen to know that XMM0 is "cold", or at least wasn't part of some otherwise-independent dep chain with high latency.) – Peter Cordes Aug 12 '22 at 19:56
  • Oh, this is just copy/pasted GCC output for `double cvt(unsigned long x){ return x; }`, which you forgot to mention. https://godbolt.org/z/97jGGqdY4 – Peter Cordes Aug 12 '22 at 20:07
  • @PeterCordes this type of acidic comments is the reason why I stopped contributing to StackOverflow long ago. – Something Something Jul 29 '23 at 23:54
  • Sorry for the phrasing. I think I'd been looking through it to try to verify correctness, and then finding out it was GCC's algorithm made me unhappy that I'd spent a bunch of time on it. (GCC and clang code-gen can generally be assumed to be correct for all corner cases.) I later regretted the negative tone. But it's a good idea to mention where code is from, so future readers can also be confident of the correctness. Also as a reminder that compilers can answer questions like (e.g. the same thing but for other ISAs, or float instead of double) this without needing to ask other humans. – Peter Cordes Jul 30 '23 at 00:31
  • @PeterCordes Well if it was not a pattern from all the interactions that I had with you for the past two years or so then yes, I'd understand. I think you have major anger issues that you need to deal with. – Something Something Aug 02 '23 at 15:06
  • I looked through your previous answers in the [assembly] tag and noticed I'd commented on many of them. But in at least some cases, you thanked me for pointing out a bug or improvement, and I didn't notice anything particularly negative, just straight to the facts and ideas I wanted to point out in limited comment space. I don't want to be hostile to people that are making a reasonable effort to post helpful answers, so I'd appreciate if you could explain how some of my earlier comments came across as "acidic" so I could make an effort to avoid in the future. (I understand if you'd rather not) – Peter Cordes Aug 02 '23 at 19:18
  • (this discussion belongs in chat but the system hasn't given the move-to-chat option yet) – Peter Cordes Aug 02 '23 at 19:21