Bug 37544 - [4.4 Regression] Conversion double -> unsigned long long -> unsigned -> double gives wrong results
Summary: [4.4 Regression] Conversion double -> unsigned long long -> unsigned -> doubl...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: rtl-optimization (show other bugs)
Version: 4.4.0
: P1 normal
Target Milestone: 4.3.3
Assignee: Uroš Bizjak
URL: http://gcc.gnu.org/ml/gcc-patches/200...
Keywords: patch, wrong-code
Depends on:
Blocks:
 
Reported: 2008-09-16 16:40 UTC by Jeroen Demeyer
Modified: 2009-04-29 15:18 UTC (History)
1 user (show)

See Also:
Host: i686-pc-linux-gnu
Target: i686-pc-linux-gnu
Build: i686-pc-linux-gnu
Known to work: 4.2.4 4.3.3
Known to fail: 3.4.6
Last reconfirmed: 2008-09-17 16:13:33


Attachments
Testcase (225 bytes, text/plain)
2008-09-16 16:40 UTC, Jeroen Demeyer
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Jeroen Demeyer 2008-09-16 16:40:02 UTC
Consider the following line of the attached test case, where a is double with value 4294967296.0.

double b = (unsigned int)((unsigned long long int)a % 4294967296ULL);

Then (unsigned long long int)a % 4294967296ULL should be equal to 0ULL, and therefore b should be 0.0.  However, when compiled with -O1 -march=pentium4, b gets the wrong value of 4294967296.0 (the same as a).  Note that the error only occurs with -march=pentium4.

To compile the testcase:
gcc -std=c99 -O1 -march=pentium4 convert-bug.i -o convert-bug

gcc -v:
Using built-in specs.
Target: i686-pc-linux-gnu
Configured with: ../gcc/configure --enable-checking=release --prefix=/home/jdemeyer/local CC=gcc-4.1.2
Thread model: posix
gcc version 4.4.0 20080916 (experimental) (GCC)
Comment 1 Jeroen Demeyer 2008-09-16 16:40:45 UTC
Created attachment 16339 [details]
Testcase
Comment 2 Andrew Pinski 2008-09-16 16:52:46 UTC
This works correctly for i386-darwin.
In fact I tried -std=c99 -O1 -mfpmath=387 -march=pentium4 -mno-sse too.
Comment 3 Jeroen Demeyer 2008-09-16 18:39:28 UTC
In fact, with -mno-sse the problem disappears for me too.
I *do* get the problem with
gcc -std=c99 -O1 -march=i386 -msse2 -mfpmath=387
Comment 4 Andrew Pinski 2008-09-16 18:44:29 UTC
Still works correctly on i386-darwin but that might be because PIC is turned on by default.
Comment 5 Richard Biener 2008-09-16 19:17:21 UTC
Confirmed on i686-linux with -std=c99 -O -msse2 -mfpmath=387 -march=i386.  Fails
since GCC 3.4 at least.
Comment 6 Uroš Bizjak 2008-09-17 08:14:35 UTC
cprop_hardreg pass is propagating DImode ax register, wrongly bypassing DI-SI conversion.

Before cprop_hardreg, we have:

(call_insn/u:HI 27 88 28 4 pr37544.c:9 (set (reg:DI 0 ax)
        (call (mem:QI (symbol_ref:SI ("__fixunsdfdi") [flags 0x41]) [0 S1 A8])
            (const_int 16 [0x10]))) 687 {*call_value_0} (expr_list:REG_UNUSED (reg:SI 1 dx)
        (expr_list:REG_EH_REGION (const_int -1 [0xffffffff])
            (nil)))
    (expr_list:REG_DEP_TRUE (use (mem:DF (plus:SI (reg/f:SI 7 sp)
                    (scratch:SI)) [0 S8 A8]))
        (nil)))

(insn 95 28 104 4 pr37544.c:9 (set (reg:SI 21 xmm0)
        (reg:SI 0 ax [78])) 41 {*movsi_1} (expr_list:REG_DEAD (reg:SI 0 ax [78])
        (nil)))

(insn 104 95 105 4 pr37544.c:9 (set (mem/c:DI (plus:SI (reg/f:SI 6 bp)
                (const_int -8032 [0xffffe0a0])) [0 S8 A64])
        (reg:DI 21 xmm0)) 63 {*movdi_2} (expr_list:REG_DEAD (reg:DI 21 xmm0)
        (nil)))

(insn 105 104 89 4 pr37544.c:9 (set (reg/v:DF 8 st [orig:65 b ] [65])
        (float:DF (mem/c:DI (plus:SI (reg/f:SI 6 bp)
                    (const_int -8032 [0xffffe0a0])) [0 S8 A64]))) 179 {*floatdidf2_i387} (nil))


and after cprop_hardreg:

(call_insn/u:HI 27 88 28 4 pr37544.c:9 (set (reg:DI 0 ax)
        (call (mem:QI (symbol_ref:SI ("__fixunsdfdi") [flags 0x41]) [0 S1 A8])
            (const_int 16 [0x10]))) 687 {*call_value_0} (expr_list:REG_UNUSED (reg:SI 1 dx)
        (expr_list:REG_EH_REGION (const_int -1 [0xffffffff])
            (nil)))
    (expr_list:REG_DEP_TRUE (use (mem:DF (plus:SI (reg/f:SI 7 sp)
                    (scratch:SI)) [0 S8 A8]))
        (nil)))

(insn 95 28 104 4 pr37544.c:9 (set (reg:SI 21 xmm0)
        (reg:SI 0 ax [78])) 41 {*movsi_1} (expr_list:REG_DEAD (reg:SI 0 ax [78])
        (nil)))

(insn 104 95 105 4 pr37544.c:9 (set (mem/c:DI (plus:SI (reg/f:SI 6 bp)
                (const_int -8032 [0xffffe0a0])) [0 S8 A64])
        (reg:DI 0 ax [21])) 63 {*movdi_2} (expr_list:REG_DEAD (reg:DI 21 xmm0)
        (nil)))

(insn 105 104 89 4 pr37544.c:9 (set (reg/v:DF 8 st [orig:65 b ] [65])
        (float:DF (mem/c:DI (plus:SI (reg/f:SI 6 bp)
                    (const_int -8032 [0xffffe0a0])) [0 S8 A64]))) 179 {*floatdidf2_i387} (nil))


Please note, how DImode ax reg propagates into (insn 104), bypassing SImode conversion in (insn 95).
Comment 7 Uroš Bizjak 2008-09-17 08:35:14 UTC
(In reply to comment #5)
> Confirmed on i686-linux with -std=c99 -O -msse2 -mfpmath=387 -march=i386. 

Does not fail for x86_64-linux target with -m32 on x86_64-linux _and_ i686-linux hosts. 
Comment 8 Uroš Bizjak 2008-09-17 10:39:31 UTC
The problem is in regrename.c, function maybe_mode_change. We enter the function with:

orig_mode = DImode
copy_mode = SImode
new_mode = DImode

At the beginning of maybe_mode_change() we have:

  if (orig_mode == new_mode)
    return gen_rtx_raw_REG (new_mode, regno);

we simply discard the change to a narrower mode.
Comment 9 Uroš Bizjak 2008-09-17 11:48:45 UTC
4.2 and 4.3 work OK.
Comment 10 Uroš Bizjak 2008-09-17 12:01:28 UTC
I'm testing following patch:

Index: regrename.c
===================================================================
--- regrename.c (revision 140409)
+++ regrename.c (working copy)
@@ -1314,6 +1314,9 @@
                   enum machine_mode new_mode, unsigned int regno,
                   unsigned int copy_regno ATTRIBUTE_UNUSED)
 {
+  if (GET_MODE_SIZE (copy_mode) < GET_MODE_SIZE (new_mode))
+    return NULL_RTX;
+
   if (orig_mode == new_mode)
     return gen_rtx_raw_REG (new_mode, regno);
   else if (mode_change_ok (orig_mode, new_mode, regno))
Comment 11 Uroš Bizjak 2008-09-17 16:13:33 UTC
Patch at http://gcc.gnu.org/ml/gcc-patches/2008-09/msg01221.html
Comment 12 uros 2008-09-18 10:19:05 UTC
Subject: Bug 37544

Author: uros
Date: Thu Sep 18 10:17:42 2008
New Revision: 140446

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=140446
Log:
	PR rtl-optimization/37544
	* regrename.c (maybe_mode_change): Exit early when copy_mode
	is narrower than orig_mode and narrower than new_mode.

testsuite/ChangeLog:

	PR rtl-optimization/37544
	* gcc.dg/pr37544.c: New test.


Added:
    trunk/gcc/testsuite/gcc.dg/pr37544.c
Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/regrename.c
    trunk/gcc/testsuite/ChangeLog

Comment 13 Uroš Bizjak 2008-09-18 14:31:28 UTC
Fixed for 4.4, latent on 4.3 and 4.2.

BTW: This problem was uncovered by the patch that fixed PR target/13958 [1].

[1] http://gcc.gnu.org/ml/gcc-patches/2008-03/msg01295.html
Comment 14 uros 2008-09-19 08:02:31 UTC
Subject: Bug 37544

Author: uros
Date: Fri Sep 19 08:01:07 2008
New Revision: 140484

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=140484
Log:
	PR rtl-optimization/37544
	* regrename.c (maybe_mode_change): Exit early when copy_mode
	is narrower than orig_mode and narrower than new_mode.

testsuite/ChangeLog:

	PR rtl-optimization/37544
	* gcc.dg/pr37544.c: New test.


Added:
    branches/gcc-4_3-branch/gcc/testsuite/gcc.dg/pr37544.c
Modified:
    branches/gcc-4_3-branch/gcc/ChangeLog
    branches/gcc-4_3-branch/gcc/regrename.c
    branches/gcc-4_3-branch/gcc/testsuite/ChangeLog

Comment 15 uros 2008-09-19 10:06:11 UTC
Subject: Bug 37544

Author: uros
Date: Fri Sep 19 10:04:46 2008
New Revision: 140487

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=140487
Log:
	PR rtl-optimization/37544
	* regrename.c (maybe_mode_change): Exit early when copy_mode
	is narrower than orig_mode and narrower than new_mode.

testsuite/ChangeLog:

	PR rtl-optimization/37544
	* gcc.dg/pr37544.c: New test.


Added:
    branches/gcc-4_2-branch/gcc/testsuite/gcc.dg/pr37544.c
      - copied, changed from r140484, branches/gcc-4_3-branch/gcc/testsuite/gcc.dg/pr37544.c
Modified:
    branches/gcc-4_2-branch/gcc/ChangeLog
    branches/gcc-4_2-branch/gcc/regrename.c
    branches/gcc-4_2-branch/gcc/testsuite/ChangeLog

Comment 16 Uroš Bizjak 2008-09-19 11:11:39 UTC
Fixed everywhere.