unrolling bug

Jeffrey A Law law@cygnus.com
Fri Dec 4 16:58:00 GMT 1998


This is causing gcc to mis-compile g++, at least on the x86.

Compile this testcase either on x86-linux native or with an x86 cross
compiler using -O -funroll-loops

typedef union tree_node *tree;
extern tree void_list_node;
tree
commonparms (p1, p2)
     tree p1, p2;
{
  tree oldargs = p1, newargs, n;
  int i, len;
  int any_change = 0;
  char *first_obj = (char *) oballoc (0);
  len = list_length (p1);
  newargs = tree_last (p1);
  if (newargs == void_list_node)
    i = 1;
  else
    {
      i = 0;
      newargs = 0;
    }
  for (; i < len; i++)
    newargs = tree_cons ((tree) ((void *)0)  , (tree) ((void *)0)  , newargs);
  return newargs;
}


We start off with a loop like this:

(code_label 56 54 102 3 "")

(insn 102 56 103 (set (cc0)
        (compare (reg/v:SI 27)
            (reg/v:SI 28))) 12 {cmpsi_1} (nil)
    (nil))

(jump_insn 103 102 58 (set (pc)
        (if_then_else (ge (cc0)
                (const_int 0))
            (label_ref 89)
            (pc))) 286 {bleu+1} (nil)
    (nil))

(note 58 103 64 "" NOTE_INSN_LOOP_BEG)

(code_label 64 58 67 7 "")

[ ... ]

(note 79 78 82 "" NOTE_INSN_LOOP_CONT)

(insn 82 79 106 (set (reg/v:SI 27)
        (plus:SI (reg/v:SI 27)
            (const_int 1))) 148 {addsi3+1} (nil)
    (nil))

(note 106 82 60 "" NOTE_INSN_LOOP_VTOP)

(insn 60 106 61 (set (cc0)
        (compare (reg/v:SI 27)
            (reg/v:SI 28))) 12 {cmpsi_1} (nil)
    (nil))

(jump_insn 61 60 88 (set (pc)
        (if_then_else (lt (cc0)
                (const_int 0))
            (label_ref 64)
            (pc))) 286 {bleu+1} (nil)
    (nil))

(note 88 61 89 "" NOTE_INSN_LOOP_END)


Note it is a count up loop.  The biv is reg 27, the upper limit is in
reg28 and the increment is +1.

check_dbra_loop will successfully reverse the loop.  After reversal the loop
looks like this:


(code_label 56 54 102 3 "")

(insn 102 56 103 (set (cc0)
        (compare (reg/v:SI 27)
            (reg/v:SI 28))) 12 {cmpsi_1} (nil)
    (nil))

(jump_insn 103 102 108 (set (pc)
        (if_then_else (ge (cc0)
                (const_int 0))
            (label_ref 89)
            (pc))) 286 {bleu+1} (nil)
    (nil))

(insn 108 103 58 (set (reg/v:SI 27)
        (minus:SI (reg/v:SI 28)
            (reg/v:SI 27))) -1 (nil)
    (nil))

(note 58 108 64 "" NOTE_INSN_LOOP_BEG)

(code_label 64 58 67 7 "")

[ ... ]

(note 79 78 111 "" NOTE_INSN_LOOP_CONT)

(insn 111 79 106 (set (reg/v:SI 27)
        (plus:SI (reg/v:SI 27)
            (const_int -1))) -1 (nil)
    (nil))

(note 106 111 115 "" NOTE_INSN_LOOP_VTOP)

(insn 115 106 116 (set (cc0)
        (reg/v:SI 27)) -1 (nil)
    (nil))

(jump_insn 116 115 88 (set (pc)
        (if_then_else (ne (cc0)
                (const_int 0))
            (label_ref 64)
            (pc))) -1 (nil)
    (nil))

(note 88 116 114 "" NOTE_INSN_LOOP_END)


Note the adjustment to r27 before the body of the loop begins and that we now
r27 count down to zero.


Then the unroller kicks in.

And we get this code before the loop:

(code_label 56 54 102 3 "")

(insn 102 56 103 (set (cc0)
        (compare (reg/v:SI 27)
            (reg/v:SI 28))) 12 {cmpsi_1} (nil)
    (nil))

(jump_insn 103 102 108 (set (pc)
        (if_then_else (ge (cc0)
                (const_int 0))
            (label_ref 89)
            (pc))) 286 {bleu+1} (nil)
    (nil))

(insn 108 103 118 (set (reg/v:SI 27)
        (minus:SI (reg/v:SI 28)
            (reg/v:SI 27))) -1 (nil)
    (nil))

(insn 118 108 119 (set (reg:SI 33)
        (minus:SI (reg/v:SI 28)
            (reg/v:SI 27))) -1 (nil)
    (nil))

(insn 119 118 120 (set (reg:SI 34)
        (and:SI (reg:SI 33)
            (const_int 3))) -1 (nil)
    (nil))

Note that the unroller has also subtracted r27 from r28, but it did so after
the insn which had already modified r27 for the loop reversal.

The net effect is we get the wrong value for r33, which screws up the loop
preconditioning and we execute the loop the wrong number of times causing bad
things to happen.

Can you take a look at it?  It would be greatly appreciated.  Thanks!
jeff























More information about the Gcc-bugs mailing list