https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115565

            Bug ID: 115565
           Summary: [4.0/4.1/4.2/4.3/4.4/4.5/4.6/4.7/4.8/4.9/5/6/7/8/9/10/
                    11/12/13/14/15 Regression] CSE: Comparison incorrectly
                    evaluated as constant causing optimization to produce
                    wrong code
           Product: gcc
           Version: 15.0
            Status: UNCONFIRMED
          Keywords: wrong-code
          Severity: normal
          Priority: P3
         Component: rtl-optimization
          Assignee: unassigned at gcc dot gnu.org
          Reporter: macro at orcam dot me.uk
  Target Milestone: ---

Created attachment 58473
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=58473&action=edit
Proposed fix

I've had an emergency case where I chose to revive my old Alpha/Linux
userland based on glibc 2.4 + LinuxThreads built with GCC 4.1.2 release,
which I built decades ago, but never came to verifing.  Now that I came
back to it I found out that numerous key programs hang, making the system
mostly unusable.  Oddly enough bash and GDB worked, which let me debug
this issue over a serial console line in a single-user environment.

Eventually I figured out that a key piece of code has been optimised away
from `pthread_rwlock_unlock' in libpthread.so, causing a write lock never
to be released and consequently the caller to lock up on the next attempt
to reacquire the lock.

Then I have narrowed the problem down to CSE and bisected to commit
08a692679fb8 ("Undefined cse.c behaviour causes 3.4 regression on HPUX"),
<https://gcc.gnu.org/ml/gcc-patches/2004-10/msg02027.html>, staring at
which however and wading through cse.c yielded nothing.

So I went ahead and debugged GCC compiling the problematic piece of code
and finally arrived at this condition:

REG_QTY (REGNO (folded_arg1)) == ent->comparison_qty

incorrectly evaluating to true for `ent' being a memory reference.
Needless to say the left-hand side referred to register 0, so both `qty'
values were -1, for this source code:

rwlock->__rw_writer != thread_self ()

where `thread_self' expanded to a PALcode call to retrieve the thread
pointer and return it in $0.  Evidently an update to the handling of
`comparison_qty' was missed with said commit and -1 now means either
a non-register reference or a register 0 reference that has not been
assigned a quantity.  I have attached an obvious fix for this issue and
will follow with a proper patch submission right away.

Interestingly enough the bug has been covered for my reproducer later on
and as from commit 932ad4d9b550 ("Make CSE path following use the CFG"),
<https://gcc.gnu.org/ml/gcc-patches/2006-12/msg00431.html>, it does not
trigger anymore with the original reproducer (and LinuxThreads have
since been decommissioned anyway, so nobody else might have stumbled
across this issue), however in principle the bug is still there waiting
to bite and the fix proposed cleanly applies unchanged from the version
I originally made for GCC 4.1.2 except for the .c to .cc file rename.

As there can only be a single attachment added per submission, I'll be
following up with tarballs including the reproducer, Alpha assembly code
produced and associated RTL dumps for the last good and first bad commit
respectively, so that this has been recorded for posterity, even though
not directly usable with GCC 15.  See the .cmd files within for the
compilation options used, although just `-O1' should do.

Reply via email to