Bug 100119 - [x86] Conversion unsigned int -> double produces -0 (-m32 -msse2 -mfpmath=sse)
Summary: [x86] Conversion unsigned int -> double produces -0 (-m32 -msse2 -mfpmath=sse)
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: target (show other bugs)
Version: 10.3.0
: P3 normal
Target Milestone: 12.0
Assignee: Not yet assigned to anyone
URL:
Keywords: wrong-code
Depends on:
Blocks:
 
Reported: 2021-04-16 15:32 UTC by Paweł Bylica
Modified: 2021-10-28 16:48 UTC (History)
0 users

See Also:
Host:
Target: i?86-*-*
Build:
Known to work: 12.0
Known to fail: 10.3.0, 11.0, 7.5.0
Last reconfirmed: 2021-04-19 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Paweł Bylica 2021-04-16 15:32:28 UTC
When building for 32-bit x86 but with SSE2 floating-point enabled:
-m32 -msse2 -mfpmath=sse

the conversion from unsigned int 0 to double produces the result of -0.0 when floating-point rounding mode is set to FE_DOWNWARD.

I used -frounding-math and #pragma STDC FENV_ACCESS ON.

This bug is not present on x87 nor x86_64 builds.

The bug seems to be present at least since GCC 5.


#include <fenv.h>

#pragma STDC FENV_ACCESS ON

__attribute__((noinline)) double u32_to_f64(unsigned x) {
  return static_cast<double>(x);
}

int main() {
  fesetround(FE_DOWNWARD);

  double d = u32_to_f64(0);

  return __builtin_signbit(d) != 0;  // signbit should be 0
}


The assembly:

u32_to_f64(unsigned int):
        sub     esp, 12
        pxor    xmm0, xmm0
        mov     eax, DWORD PTR [esp+16]
        add     eax, -2147483648
        cvtsi2sd        xmm0, eax
        addsd   xmm0, QWORD PTR .LC0
        movsd   QWORD PTR [esp], xmm0
        fld     QWORD PTR [esp]
        add     esp, 12
        ret
main:
        lea     ecx, [esp+4]
        and     esp, -16
        push    DWORD PTR [ecx-4]
        push    ebp
        mov     ebp, esp
        push    ecx
        sub     esp, 32
        push    1024
        call    fesetround
        mov     DWORD PTR [esp], 0
        call    u32_to_f64(unsigned int)
        mov     ecx, DWORD PTR [ebp-4]
        add     esp, 16
        fstp    QWORD PTR [ebp-16]
        movsd   xmm0, QWORD PTR [ebp-16]
        leave
        lea     esp, [ecx-4]
        movmskpd        eax, xmm0
        and     eax, 1
        ret
.LC0:
        .long   0
        .long   1105199104


https://godbolt.org/z/rrMWY9jsG
Comment 1 Richard Biener 2021-04-19 07:04:42 UTC
Confirmed.
Comment 2 Uroš Bizjak 2021-04-19 09:14:30 UTC
diff --git a/gcc/config/i386/i386-expand.c b/gcc/config/i386/i386-expand.c
index dda08ff67f2..5a7a00c13bd 100644
--- a/gcc/config/i386/i386-expand.c
+++ b/gcc/config/i386/i386-expand.c
@@ -1550,6 +1550,8 @@ ix86_expand_convert_uns_sixf_sse (rtx, rtx)
   gcc_unreachable ();
 }
 
+static rtx ix86_expand_sse_fabs (rtx op0, rtx *smask);
+
 /* Convert an unsigned SImode value into a DFmode.  Only currently used
    for SSE, but applicable anywhere.  */
 
@@ -1569,6 +1571,11 @@ ix86_expand_convert_uns_sidf_sse (rtx target, rtx input)
   x = const_double_from_real_value (TWO31r, DFmode);
 
   x = expand_simple_binop (DFmode, PLUS, fp, x, target, 0, OPTAB_DIRECT);
+
+  /* Remove the sign with FE_DOWNWARD, where x - x = -0.0.  */
+  if (HONOR_SIGNED_ZEROS (DFmode) && flag_rounding_math)
+    x = ix86_expand_sse_fabs (x, NULL);
+
   if (x != target)
     emit_move_insn (target, x);
 }
Comment 3 GCC Commits 2021-04-22 14:32:32 UTC
The master branch has been updated by Uros Bizjak <uros@gcc.gnu.org>:

https://gcc.gnu.org/g:0cda606d08d6196b76524c7b6ad51d87fed0d54b

commit r12-61-g0cda606d08d6196b76524c7b6ad51d87fed0d54b
Author: Uros Bizjak <ubizjak@gmail.com>
Date:   Thu Apr 22 16:30:38 2021 +0200

    i386: Fix unsigned int -> double conversion on i386 w/ -mfpmath=sse [PR100119]
    
    2021-04-22  Uroš Bizjak  <ubizjak@gmail.com>
    
    gcc/
            PR target/100119
            * config/i386/i386-expand.c (ix86_expand_convert_uns_sidf_sse):
            Remove the sign with FE_DOWNWARD, where x - x = -0.0.
    
    gcc/testsuite/
    
            PR target/100119
            * gcc.target/i386/pr100119.c: New test.
Comment 4 Richard Biener 2021-10-28 13:53:01 UTC
So fixed for GCC 12?
Comment 5 Uroš Bizjak 2021-10-28 16:48:16 UTC
(In reply to Richard Biener from comment #4)
> So fixed for GCC 12?

Yes.