Bug 41577 - Broken code with -O -ftree-vrp
Summary: Broken code with -O -ftree-vrp
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: tree-optimization (show other bugs)
Version: 4.3.4
: P3 normal
Target Milestone: 4.3.5
Assignee: Not yet assigned to anyone
URL:
Keywords: wrong-code
Depends on:
Blocks:
 
Reported: 2009-10-05 11:30 UTC by magnus.christensson@acm.org
Modified: 2009-10-05 13:09 UTC (History)
1 user (show)

See Also:
Host: x86_64-unknown-linux-gnu
Target: x86_64-unknown-linux-gnu
Build: x86_64-unknown-linux-gnu
Known to work: 4.1.2 4.4.1 4.5.0
Known to fail: 4.2.4 4.3.4
Last reconfirmed: 2009-10-05 11:59:36


Attachments
-save-temps output (5.39 KB, application/octet-stream)
2009-10-05 11:31 UTC, magnus.christensson@acm.org
Details
C source code (415 bytes, text/x-csrc)
2009-10-05 11:32 UTC, magnus.christensson@acm.org
Details

Note You need to log in before you can comment on or make changes to this bug.
Description magnus.christensson@acm.org 2009-10-05 11:30:53 UTC
I have narrowed down a problem in my application to the testcase which I will soon attach.

The testcase should output:

Out r8: 0x82ce3350
Out cr: 0x8

Version of GCC: 4.3.4.

Command line which generates broken output: gcc -O2 compiler_issue.c
Command line which generates ok output: gcc -O2 -fno-tree-vrp compiler_issue.c
Comment 1 magnus.christensson@acm.org 2009-10-05 11:31:33 UTC
Created attachment 18707 [details]
-save-temps output
Comment 2 magnus.christensson@acm.org 2009-10-05 11:32:02 UTC
Created attachment 18708 [details]
C source code
Comment 3 magnus.christensson@acm.org 2009-10-05 11:34:34 UTC
I suspect that the problem is that an optimization path does not properly distinguish between signed and unsigned comparisons. You get the same behavior if you remove the "int32 int_res = res;" line and let the following code operate on "res".
Comment 4 Richard Biener 2009-10-05 11:59:36 UTC
Confirmed.
Comment 5 Richard Biener 2009-10-05 11:59:51 UTC
A workaround is to provide -fno-tree-vrp.
Comment 6 Richard Biener 2009-10-05 12:02:20 UTC
Actually the testcase is invalid.

        uint32 res = ((uint16)(cpu->gprs[12]  >> 16) * (uint16)(cpu->gprs[16] >> 16));

performs a signed multiplication which invokes undefined behavior if it
overflows.  Thus the compiler rightfully can assume that the result can
be converted to a positive signed value.
Comment 7 Richard Biener 2009-10-05 12:03:10 UTC
A fix is to write

uint32 res = ((uint32)(uint16)(cpu->gprs[12]  >> 16)
              * (uint32)(uint16)(cpu->gprs[16] >> 16));

instead to force the multiplication in an unsigned type.
Comment 8 magnus.christensson@acm.org 2009-10-05 12:36:41 UTC
(In reply to comment #7)
> A fix is to write
> 
> uint32 res = ((uint32)(uint16)(cpu->gprs[12]  >> 16)
>               * (uint32)(uint16)(cpu->gprs[16] >> 16));
> 
> instead to force the multiplication in an unsigned type.
> 

Thanks. It wasn't obvious to me that a multiply on two unsigned variables would be promoted to signed. The uint32 trick will work here, but won't work if your target machine has 64-bit integers.
Comment 9 Richard Biener 2009-10-05 13:09:43 UTC
with 64bit int the multiplication will never overflow, so it would work there
as well.