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
Created attachment 18707 [details] -save-temps output
Created attachment 18708 [details] C source code
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".
Confirmed.
A workaround is to provide -fno-tree-vrp.
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.
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.
(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.
with 64bit int the multiplication will never overflow, so it would work there as well.