This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

HAIFA scheduler bug?


I'm have a problem with the following configuration:
  EGCS-1.0.2
  RS6000 (Linux/PPC)
  HAIFA enabled

The attached program will generate incorrect code when compiled in
this configuration with "-O2 -DBUG".  When compiled with an equivalent compiler
that does not have HAIFA, the code is correct.  Also, if you don't
define "BUG", the code will be correct.  Correct behaviour prints
"OK", incorrect behaviour will not print anything.

I also believe that this problem could occur with any
I can only provide an analysis of the problem; I don't understand enough
of the scheduler internals to find a solution.

The problem is that when "BUG" is not defined, the variable "line_number"
which is last calculated on line #47 becomes dead (because it's not
used anywhere else in the loop) and the code block at lines 46..50 will
be eliminated.  This occurs during the "jump 2" phase (second time 'jump'
is called from "toplev.c").  What happens though is that since the
instruction scheduler(?) along with the combiner and CSE collapsed the
"buffer[point]" expression on line 50 to be the same as the one on line 46.
After the scheduler, this result ends up in register 'r0'.  When the
block 46..50 is eliminated, the common evaluation of "buffer[point]" 
goes with it, thus leading to the incorrect code.  Lines 51..54 end up
as a loop that tries to check for '"' (thinking it is in 'r0') but the
value is not updated within the loop, giving incorrect results.  The
following assembly snippet is from lines 51..54:

.L33:
        addi 9,9,1
        cmpwi 6,0,34
        bc 12,26,.L32
        addi 31,31,1
        cmpw 1,31,30
        bc 12,4,.L33
.L32:

You see the compare of 'r0' against the constant '"', but 'r0' (which
is supposed to correspond to "buffer[point]") is not being updated
within this loop.

I tracked this down by examining the RTL dumps and found that the 
missing expression was deleted during 'jump 2'.  I believe that this
happened when it was realized that the result on line 47 was not being
used, thus the block where it was calculated was not necessary.

I have tried this with the mainline EGCS as well.  Alas, it handles
this test case, but not the real file (more compilicated) that I 
distilled it from.  The original is at "egcs/texinfo/info/makedoc.c"!
The mainline compiler still compiles this one incorrectly.

I have also found out that "-fno-sched-interblock" will keep the code
correct as follows:

.L33:
        lbz 0,0(9)
        addi 9,9,1
        rlwinm 0,0,0,0xff
        cmpwi 1,0,34
        bc 12,6,.L32
        addi 31,31,1
        cmpw 1,31,30
        bc 12,4,.L33
.L32:

I hope that this is enough to go on;  I'm sorry I can't help more
with the solution.

------------------------------------------------------------------------
Gary Thomas                              |
The Open Group / Research Institute      | "Fine wine is a necessity of
2 Avenue de Vignate                      |        life for me"
38610 Gieres - FRANCE                    |
+33 4 76 63 48 74                        |      Thomas Jefferson
email: g.thomas@opengroup.org            |
<http://www.opengroup.org/~gdt>          |
   ... opinions expressed here are mine  |
       and no one else would claim them! |
------------------------------------------------------------------------


#include <stdio.h>
#include <sys/stat.h>

#define DECLARATION_STRING "\nDECLARE_INFO_COMMAND"
#define O_RDONLY 0

#if !defined (whitespace)
#  define whitespace(c) ((c == ' ') || (c == '\t'))
#endif /* !whitespace */

#if !defined (whitespace_or_newline)
#  define whitespace_or_newline(c) (whitespace (c) || (c == '\n'))
#endif /* !whitespace_or_newline */

char buffer[] = "DECLARE_INFO_COMMAND (info_next_line, \"Move down to the next l
ine\")";

static void
process_one_file (filename)
     char *filename;
{
  int descriptor;
  long offset;
  long file_size;

  file_size = sizeof(buffer);
  offset = 0;

  while (1) {
    long point = 0;
    long line_start = 0;
    int line_number = 0;
    char *func = "bad";

    point = 22; line_number = 1; line_start = 17229;

    /* Now looking at name of function.  Get it. */
    for (offset = point; buffer[offset] != ','; offset++);

    _f(line_number, line_start);

    /* Find doc string. */
    point = offset + 1;

    while (point < file_size){
      // BAD BLOCK
      if (buffer[point] == '\n') {
	line_number++;
	line_start = point + 1;
      }
      if (buffer[point] == '"')
	break;
      else
	point++;
    }

#ifdef BUG
    _f(point);
#else
    _f(line_number);
#endif

    offset = point + 1;

    while (offset < file_size) {
      if (buffer[offset] == '"')
	break;
      else
	offset++;
    }

    offset++;
    if (offset >= file_size)
      break;

    fprintf (stderr, "function OK: %s\n", func);
    break;
  }
}

main()
{
  process_one_file("session.c");
}

_f(int p) {}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]