[Bug c/91373] New: gcc6.2.0: ((U32)((U16 * U16)) >> 31) cannot always get correct result with gcc -O2

2019-08-05 Thread qiang.fu at verisilicon dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91373

Bug ID: 91373
   Summary: gcc6.2.0: ((U32)((U16 * U16)) >> 31) cannot always get
correct result with gcc -O2
   Product: gcc
   Version: 6.2.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c
  Assignee: unassigned at gcc dot gnu.org
  Reporter: qiang.fu at verisilicon dot com
  Target Milestone: ---

Created attachment 46676
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=46676&action=edit
main.c

Hi,

I met an issue with gcc6.2.0:  ((U16 * U16) >> 31) cannot always get expected
result for gcc optimization switch '-O2'.
e.g.
 (63139 * 36032) >> 30 = 0x2 // right
 (63139 * 36032) >> 31 = 0x0 // wrong, should be 0x1.

I create a test case for it, see the attachement(main.c). It passed on gcc
4.6.3, but failed with gcc6.2.0 + release build(gcc -O2) 


gcc -O2 main.c -o test
./test 63139 36032
data1: 0x879a1e40, data1 >> 31: 1, data1 >> 30: 2
data2: 0x879a1e40, data2 >> 31: 0, data1 >> 30: 2


This test passed if build with -O0 or -O1 with gcc6.2.0


GCC version: 6.2.0
 *
 gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/local/libexec/gcc/x86_64-pc-linux-gnu/6.2.0/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: ../configure -enable-checking=release -enable-languages=c,c++
-disable-multilib
Thread model: posix
gcc version 6.2.0 (GCC)

[Bug c/91373] gcc6.2.0: ((U32)((U16 * U16)) >> 31) cannot always get correct result with gcc -O2

2019-08-06 Thread qiang.fu at verisilicon dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91373

--- Comment #2 from Qiang  ---
Hi Andrew, 

Thank your for your quickly reply.
I still have some questions about this issue.

It's very natural to write down the following code.
All arguments are declared with 'U16', and the return type is 'U32'. 

U32 foo(U16 d1, U16 d2)
{
U32 data2 = d1 * d2;
printf("data2: 0x%08x, data2 >> 31: %d, data2 >> 30: %d\n", data2, data2 >>
31, data2 >> 30);
return data2;
}

It works under the old gcc like (gcc4.6.3 + '-O2') or VS2015. Also works under
gcc5.4.0/gcc6.2.0 + '-O0'/'-O1'.
But it failed under gcc5.4.0/gcc6.2.0 + '-O2'.

If GCC need to follow rule, it should not be relative to GCC optimization. 
Why does it get different result with different optimization level?

Even if there is U16 overflow issue, it's natural that user want GCC tool to
take them as 'U32' argument because the return type is 'U32'.

The following code works, but it's a burden that tool need user to explicitly
cast it too follow the implicit rule, isn't it?

U32 data2 = (U32)d1 * (U32)d2;

[Bug c/91373] gcc6.2.0: ((U32)((U16 * U16)) >> 31) cannot always get correct result with gcc -O2

2019-08-06 Thread qiang.fu at verisilicon dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91373

--- Comment #7 from Qiang  ---
Sorry to be a bother and thanks all of you.
'-fsanitize=undefined' & '-fwrapv' are new item to me.
'-fsanitize=undefined' is helpful to me to find out the similar issue in our
code.
'-fwrapv' may hide other potential issue.

I'll do more check later follow the following instructions before reporting a
bug:
  'Before reporting that GCC compiles your code incorrectly, compile it with
gcc -Wall -Wextra and see whether this shows anything wrong with your code.
Similarly, if compiling with -fno-strict-aliasing -fwrapv
-fno-aggressive-loop-optimizations makes a difference, or if compiling with
-fsanitize=undefined produces any run-time errors, then your code is probably
not correct.'