This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
[Bug tree-optimization/29415] New: [4.2] bad code reordering around inline asm block
- From: "christophe at saout dot de" <gcc-bugzilla at gcc dot gnu dot org>
- To: gcc-bugs at gcc dot gnu dot org
- Date: 10 Oct 2006 15:38:16 -0000
- Subject: [Bug tree-optimization/29415] New: [4.2] bad code reordering around inline asm block
- Reply-to: gcc-bugzilla at gcc dot gnu dot org
Using gcc 4.2 snapshot 20061007 on x86, the compiler is miscompiling glibc 2.5
(see http://sourceware.org/bugzilla/show_bug.cgi?id=3328)
What is happening is that a test of a variable after an inline asm block is
moved around so that the load of the struct member is moved above the asm block
even though it should not do that.
The miscompilation only seems to appear in that particular constellation, all
tries to reproduce the problem using a simpler hand-made test case have failed.
So I've attached the whole preprocessed source file.
Compiler simply called with "gcc -O2 -o test.o -c pthread_mutex_lock.c".
The problem appears in the function __pthread_mutex_lock. There's a switch
statement with some common stuff in the different cases which the compiler
seems to optimize. The case in question (the most common one):
switch (__builtin_expect (mutex->__data.__kind, PTHREAD_MUTEX_TIMED_NP)) {
...
case PTHREAD_MUTEX_TIMED_NP:
simple:
/* Normal mutex. */
LLL_MUTEX_LOCK (mutex->__data.__lock);
assert (mutex->__data.__owner == 0);
break;
...
}
The LLL_MUTEX_LOCK is a macro with an inline assembler statement (cmpxchg and a
conditional jump to another section) that is annotated to tell the compiler
that it clobbers memory, so gcc should never move loads around the inline asm
block. But in this case the load from mutex->__data.__owner (for the assertion)
is executed above LLL_MUTEX_LOCK and the register content is tested below
LLL_MUTEX_LOCK. The content will have changed, but the old value in the
register is wrong and the assertion triggers.
The broken generated code looks like (note that the jump to <_L_mutex_lock_78>
is just an out-of-line call to another function that can wait for some time,
modify the mutex->__data.__owner = 0x8(%ebx) here, and then jump back):
loading mutex->__data.__owner (into %edx):
2f: 8b 53 08 mov 0x8(%ebx),%edx
lll_mutex_lock:
32: 31 c0 xor %eax,%eax
34: b9 01 00 00 00 mov $0x1,%ecx
39: f0 0f b1 0b lock cmpxchg %ecx,(%ebx)
3d: 0f 85 f3 05 00 00 jne 636 <_L_mutex_lock_78>
testing mutex->__data.__owner (%edx from above!):
43: 85 d2 test %edx,%edx
45: 0f 85 7f 04 00 00 jne 4ca <__pthread_mutex_lock+0x4ca>
-> __assert_fail
In constrast, gcc 4.1.1 generated the following correct piece of code:
acquiring mutex (lll_mutex_lock):
3d: 31 c0 xor %eax,%eax
3f: b9 01 00 00 00 mov $0x1,%ecx
44: f0 0f b1 0b lock cmpxchg %ecx,(%ebx)
48: 0f 85 ed 05 00 00 jne 63b <_L_mutex_lock_86>
loading and testing owner:
4e: 8b 43 08 mov 0x8(%ebx),%eax
51: 85 c0 test %eax,%eax
53: 0f 85 71 05 00 00 jne 5ca <__pthread_mutex_lock+0x5ca>
-> __assert_fail
--
Summary: [4.2] bad code reordering around inline asm block
Product: gcc
Version: 4.2.0
Status: UNCONFIRMED
Severity: critical
Priority: P3
Component: tree-optimization
AssignedTo: unassigned at gcc dot gnu dot org
ReportedBy: christophe at saout dot de
GCC build triplet: i686-pc-linux-gnu
GCC host triplet: i686-pc-linux-gnu
GCC target triplet: i686-pc-linux-gnu
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=29415