Are there unsigned equivalents of the x87 FILD and SSE CVTSI2SD instructions?

前端 未结 5 1359
离开以前
离开以前 2021-01-18 20:12

I want to implement the equivalent of C\'s uint-to-double cast in the GHC Haskell compiler. We already implement int-to-double

5条回答
  •  离开以前
    2021-01-18 21:00

    As someone said, "Good Artists Copy; Great Artists Steal". So we can just check how other compiler writers solved this issue. I used a simple snippet:

    volatile unsigned int x;
    int main()
    {
      volatile double  y = x;
      return y;
    }
    

    (volatiles added to ensure the compiler does not optimize out the conversions)

    Results (irrelevant instructions skipped):

    Visual C++ 2010 cl /Ox (x86)

      __real@41f0000000000000 DQ 041f0000000000000r ; 4.29497e+009
    
      mov   eax, DWORD PTR ?x@@3IC          ; x
      fild  DWORD PTR ?x@@3IC           ; x
      test  eax, eax
      jns   SHORT $LN4@main
      fadd  QWORD PTR __real@41f0000000000000
    $LN4@main:
      fstp  QWORD PTR _y$[esp+8]
    

    So basically the compiler is adding an adjustment value in case the sign bit was set.

    Visual C++ 2010 cl /Ox (x64)

      mov   eax, DWORD PTR ?x@@3IC          ; x
      pxor  xmm0, xmm0
      cvtsi2sd xmm0, rax
      movsdx    QWORD PTR y$[rsp], xmm0
    

    No need to adjust here because the compiler knows that rax will have the sign bit cleared.

    Visual C++ 2012 cl /Ox

      __xmm@41f00000000000000000000000000000 DB 00H, 00H, 00H, 00H, 00H, 00H, 00H
      DB 00H, 00H, 00H, 00H, 00H, 00H, 00H, 0f0H, 'A'
    
      mov   eax, DWORD PTR ?x@@3IC          ; x
      movd  xmm0, eax
      cvtdq2pd xmm0, xmm0
      shr   eax, 31                 ; 0000001fH
      addsd xmm0, QWORD PTR __xmm@41f00000000000000000000000000000[eax*8]
      movsd QWORD PTR _y$[esp+8], xmm0
    

    This uses branchless code to add 0 or the magic adjustment depending on whether the sign bit was cleared or set.

提交回复
热议问题