Red Hat Bugzilla – Bug 841598
Miscompilation on s390 with -O2
Last modified: 2012-07-20 08:15:31 EDT
Description of problem:
When backporting fix from grep I encountered code that miscompiles on s390 with -O2.
Version-Release number of selected component (if applicable):
Steps to Reproduce:
1. Try to build grep-2.13-2.fc18.src.rpm (currently the latest Fedora version) for RHEL-6.4 on s390.
It compiles correctly on:
- any arch other than s390 (e.g 390x compiles OK)
- on s390 with -O0 or -O1
- on s390 with -O2 if newer gcc is used (gcc from Fedora 16 and up seems to work correctly).
Stripped down reproducer will be attached.
Created attachment 599173 [details]
Stripped down reproducer
On s390, gcc-4.4.6-4.el6.s390
$ gcc -O2 -o test test.c
In all other cases (e.g. -O1 or -O2 on s390x, x86, ...):
$ gcc -O2 -o test test.c
Warning reported to grep upstream, ticket:
But I think the warning is not the core of this problem.
Assembly for the first case:
40052c: 90 ef f0 38 stm %r14,%r15,56(%r15)
400530: c0 20 00 00 00 88 larl %r2,400640 <__dso_handle+0x10>
400536: a7 fa ff 98 ahi %r15,-104
40053a: a7 38 00 01 lhi %r3,1
40053e: a7 18 00 02 lhi %r1,2
400542: 50 10 f0 64 st %r1,100(%r15)
400546: c0 e5 ff ff ff 07 brasl %r14,400354 <printf@plt>
40054c: 98 ef f0 a0 lm %r14,%r15,160(%r15)
400550: 07 fe br %r14
400552: 07 07 nopr %r7
I guess the opcode on 40053a is wrong.
Assembly for s390x:
8000056c: eb ef f0 70 00 24 stmg %r14,%r15,112(%r15)
80000572: a7 39 00 02 lghi %r3,2
80000576: e3 f0 ff 58 ff 71 lay %r15,-168(%r15)
8000057c: c0 20 00 00 00 9a larl %r2,800006b0 <__dso_handle+0x10>
80000582: e3 30 f0 a0 00 24 stg %r3,160(%r15)
80000588: c0 e5 ff ff ff 46 brasl %r14,80000414 <printf@plt>
8000058e: eb ef f1 18 00 04 lmg %r14,%r15,280(%r15)
80000594: 07 fe br %r14
80000596: 07 07 nopr %r7
That testcase is not valid C. On s390 32-bit ptrdiff_t is int while size_t is unsigned long int, so the above violates ISO C99 6.5 (7). While those two types have on s390 32-bit the same size, size_t isn't signed/unsigned versions corresponding to the effective type of ptrdiff_t. On most of the other architectures size_t/ptrdiff_t types are actually either unsigned int/int or
unsigned long/long or unsigned long long/long long, so it is valid C then.
You can work around it by using -fno-strict-aliasing, or much better just fix the code not to violate C/C++ aliasing requirements.
Sorry for false positive. I was checking both types in stddef.h and through sizeof() and didn't notice that they are built-ins and differ.