This is the mail archive of the gcc@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]

RFC -- More problems with disappearing labels



Compile the following on the PPC with -O2:
static void
foo ()
{
  long maplength;
  int type;
  {
    const long nibbles = 8;
    char buf1[nibbles + 1];
    char buf2[nibbles + 1];
    char buf3[nibbles + 1];
    ((nibbles) <= 16
     ? (({
       void *__s = (buf2);
       union
	 {
	   unsigned int __ui;
	   unsigned short int __usi;
	   unsigned char __uc;
	 } *__u;
       unsigned char __c = (unsigned char)('0');
       switch ((unsigned int) (nibbles))
	 {
	  case 16:
	   __u->__ui = __c * 0x01010101;
	   __u = __extension__ ((void *) __u + 4);
	  case 12:
	   __u->__ui = __c * 0x01010101;
	   __u = __extension__ ((void *) __u + 4);
	  case 8:
	   __u->__ui = __c * 0x01010101; 
	   __u = __extension__ ((void *) __u + 4);
	  case 4:
	   __u->__ui = __c * 0x01010101;
	  case 0:
	   break;
	 }
       __s;
     }))
     : 0);
  }
}



>From the .loop dump we have:

(insn 122 139 124 (set (reg/f:SI 79)
        (label_ref:SI 127)) 35 {*movsi_1} (nil)
    (insn_list:REG_LABEL 127 (expr_list:REG_EQUAL (label_ref:SI 127)
            (nil))))

(insn 124 122 125 (set (reg:SI 80)
        (mem/u:SI (plus:SI (mult:SI (reg/v/u:SI 44)
                    (const_int 4 [0x4]))
                (reg/f:SI 79)) 0)) 35 {*movsi_1} (nil)
    (expr_list:REG_EQUAL (mem/u:SI (plus:SI (mult:SI (const_int 4 [0x4])
                    (const_int 8 [0x8]))
                (reg/f:SI 79)) 0)
        (nil)))

(jump_insn 125 124 126 (parallel[
            (set (pc)
                (reg:SI 80))
            (use (label_ref 127))
        ] ) 328 {tablejump} (nil)
    (nil))

(barrier 126 125 127)

(code_label 127 126 128 8 "" "" [2 uses])

(jump_insn 128 127 129 (addr_vec:SI[
            (label_ref:SI 130)
            (label_ref:SI 130)
            (label_ref:SI 130)
            (label_ref:SI 130)
            (label_ref:SI 97)
            (label_ref:SI 130)
            (label_ref:SI 130)
            (label_ref:SI 130)
            (label_ref:SI 75)
            (label_ref:SI 130)
            (label_ref:SI 130)
            (label_ref:SI 130)
            (label_ref:SI 53)
            (label_ref:SI 130)
            (label_ref:SI 130)
            (label_ref:SI 130)
            (label_ref:SI 31)
        ] ) -1 (nil)
    (nil))

Note carefully the REG_EQUAL note on insn 124.  It is what is going to enable
cse2 to realize that this sequence will always jump to (label_ref:SI 75).

After CSE completes (but before we re-run the jump optimizer) we get the
following:

(insn 122 139 124 (set (reg/f:SI 79)
        (label_ref:SI 127)) 35 {*movsi_1} (nil)
    (insn_list:REG_LABEL 127 (expr_list:REG_EQUAL (label_ref:SI 127)
            (nil))))

(insn 124 122 152 (set (reg:SI 80)
        (label_ref:SI 75)) 35 {*movsi_1} (nil)
    (expr_list:REG_EQUAL (label_ref:SI 75)
        (nil)))

(jump_insn 152 124 153 (set (pc)
        (label_ref 75)) -1 (nil)
    (nil))

(barrier 153 152 125)

(jump_insn 125 153 126 (parallel[
            (set (pc)
                (label_ref:SI 75))
            (use (label_ref 127))
        ] ) 328 {tablejump} (nil)
    (nil))

(barrier 126 125 127)

(code_label 127 126 128 8 "" "" [2 uses])

(jump_insn 128 127 129 (addr_vec:SI[
            (label_ref:SI 130)
            (label_ref:SI 130)
            (label_ref:SI 130)
            (label_ref:SI 130)
            (label_ref:SI 97)
            (label_ref:SI 130)
            (label_ref:SI 130)
            (label_ref:SI 130)
            (label_ref:SI 75)
            (label_ref:SI 130)
            (label_ref:SI 130)
            (label_ref:SI 130)
            (label_ref:SI 53)
            (label_ref:SI 130)
            (label_ref:SI 130)
            (label_ref:SI 130)
            (label_ref:SI 31)
        ] ) -1 (nil)
    (nil))

(barrier 129 128 31)

The sequence above is not ideal, but it's still correct and valid.  After
jump.c cleans things up a little we get the following:

(insn 122 139 124 (set (reg/f:SI 79)
        (label_ref:SI 127)) 35 {*movsi_1} (nil)
    (insn_list:REG_LABEL 127 (expr_list:REG_EQUAL (label_ref:SI 127)
            (nil))))

(insn 124 122 152 (set (reg:SI 80)
        (label_ref:SI 75)) 35 {*movsi_1} (nil)
    (insn_list:REG_LABEL 75 (expr_list:REG_EQUAL (label_ref:SI 75)
            (nil))))

(jump_insn 152 124 153 (set (pc)
        (label_ref 75)) -1 (nil)
    (nil))

(barrier 153 152 127)

(code_label 127 153 140 8 "" "" [1 uses])

It's still not ideal since we would have liked to have zapped insn 122, since
it's only purpose is setup for the tablejump.  But regardless, this sequence
is still valid.

A short while later we build the cfg.  Before simplification the CFG looks
like this:

5 basic blocks, 7 edges.

Basic block 0: first insn 138, last 120, loop_depth 0, count 0.
Predecessors:  ENTRY (fallthru)
Successors:  1 (fallthru) 4 (crit)
Registers live at start: (nil)
Registers live at end: (nil)

Basic block 1: first insn 139, last 152, loop_depth 0, count 0.
Predecessors:  0 (fallthru)
Successors:  3
Registers live at start: (nil)
Registers live at end: (nil)

Basic block 2: first insn 127, last 72, loop_depth 0, count 0.
Predecessors:
Successors:  3 (fallthru)
Registers live at start: (nil)
Registers live at end: (nil)

Basic block 3: first insn 75, last 113, loop_depth 0, count 0.
Predecessors:  2 (fallthru) 1
Successors:  4 (fallthru)
Registers live at start: (nil)
Registers live at end: (nil)

Basic block 4: first insn 130, last 144, loop_depth 0, count 0.
Predecessors:  3 (fallthru) 0 (crit)
Successors:  EXIT (fallthru)
Registers live at start: (nil)
Registers live at end: (nil)


The first thing to note is that block 2 is unreachable, it will be removed.
Doing so leaves us with:

(insn 122 139 124 (set (reg/f:SI 79)
        (label_ref:SI [127 deleted])) 35 {*movsi_1} (nil)
    (insn_list:REG_LABEL 127 (expr_list:REG_EQUAL (label_ref:SI [127 deleted])
            (nil))))

(insn 124 122 127 (set (reg/f:SI 80)
        (label_ref:SI 75)) 35 {*movsi_1} (nil)
    (insn_list:REG_LABEL 75 (expr_list:REG_EQUAL (label_ref:SI 75)
            (nil))))

(note 127 124 32 "" NOTE_INSN_DELETED_LABEL 8)

(note 32 127 48 ("j.c") 24 -1347440721)

(note 48 32 54 ("j.c") 25 -1347440721)

(note 54 48 70 ("j.c") 27 -1347440721)

(note 70 54 75 ("j.c") 28 -1347440721)

(code_label 75 70 142 5 "" "" [2 uses])

(note 142 75 76 [bb 2] NOTE_INSN_BASIC_BLOCK -1347440721)

Note how we have a reference to a deleted label at insn 122.  I think this
is the first point at which something is really wrong.

It almost seems to me that when delete_unreachable_blocks removes a label
that we should ensure no dangling REG_LABEL fields are hanging around.

Anyway, let's pretend that's not a problem right now and move on to
After block merging we have the following:

(insn 122 139 124 (set (reg/f:SI 79)
        (label_ref:SI [127 deleted])) 35 {*movsi_1} (nil)
    (insn_list:REG_LABEL 127 (expr_list:REG_EQUAL (label_ref:SI [127 deleted])
            (nil))))

(insn 124 122 127 (set (reg/f:SI 80)
        (label_ref:SI [75 deleted])) 35 {*movsi_1} (nil)
    (insn_list:REG_LABEL 75 (expr_list:REG_EQUAL (label_ref:SI [75 deleted])
            (nil))))

(note 127 124 32 "" NOTE_INSN_DELETED_LABEL 8)

(note 32 127 48 ("j.c") 24 -1347440721)

(note 48 32 54 ("j.c") 25 -1347440721)

(note 54 48 70 ("j.c") 27 -1347440721)

(note 70 54 75 ("j.c") 28 -1347440721)

(note 75 70 76 "" NOTE_INSN_DELETED_LABEL 5)

Notice how block merging has created a dangling REG_LABEL reference.  Ugh.
The process is similar, we tie together two blocks because the CFG says it
is useful to do so, in the process we zap a label that happens to have a
reference via a REG_LABEL note.


That made me think that maybe we should hook in the code which actually 
deletes the CODE_LABELs.  However, it seems rather expensive to have to
search through the insn stream for a REG_LABEL note every time we delete
a CODE_LABEL.

Another approach would be to defer the cleanup a little so that we can
do it all in a single pass over the insn stream.

If we deferred cleaup until life analysis, then we could actually verify
that when we find a dangling REG_LABEL note that the destination of set in
the insn with the REG_LABEL note is never used.

I'm open to all three suggestions.

jeff











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