Dead store elimination patch for switch statements

Geoff Keating geoffk@ozemail.com.au
Tue Oct 26 21:31:00 GMT 1999


This was causing a test case failure on ppc.  What was happening is
that:

- cse determines that a switch statement is operating on a constant,
  and replaces it with an unconditional jump.
- The addr_diff_vec is not deleted, because there are instructions
  that refer to its label (they used to be adding the address of
  the addr_diff_vec back in, to get the actual address to branch to).
- Flow later deletes these instructions, because their result
  is no longer used.
- Now there's an addr_diff_vec lying around with nothing referencing
  it, which as you might expect causes trouble.

The real fix is to treat switch tables in the same way as other
constants, for instance CONST_DOUBLE, and have them explicitly inside
the jump instruction and emitted to the constant pool in the usual
way.  In the meantime, this fixes the bug by causing flow to delete
the switch statement.  It may also help by keeping LABEL_NUSES fields
more up-to-date, which is probably a good thing.

It's possible to generate contrived test-cases in which this situation
(deleting an insn that references a label) causes other trouble, but
they are probably very rare in practise.  This patch may help them a
bit too.

-- 
Geoffrey Keating <geoffk@cygnus.com>

===File ~/patches/cygnus/egcs-xswitch-2.patch===============
md5sum: f9ed65f0e9c8ab84 024944fca7a413de 377605
Index: egcs/gcc/ChangeLog
0a
Wed Oct 27 14:10:27 1999  Geoffrey Keating  <geoffk@cygnus.com>

	* flow.c (propagate_block): When the last reference to a label
 	before an ADDR_VEC is deleted because the reference is a dead
 	store, delete the ADDR_VEC.

.
Changed files:
egcs/gcc/ChangeLog
egcs/gcc/flow.c
md5sum: bddb6a2c91612cab dc472d88c31bbaa8 181452
--- /sloth/disk0/co/egcs-mainline/egcs/gcc/flow.c	Tue Oct 26 11:41:59 1999
+++ egcs/gcc/flow.c	Wed Oct 27 14:09:38 1999
@@ -3320,6 +3320,40 @@ propagate_block (old, first, last, signi
 	     can cause trouble for first or last insn in a basic block.  */
 	  if ((flags & PROP_KILL_DEAD_CODE) && insn_is_dead)
 	    {
+	      rtx inote;
+	      /* If the insn referred to a label, note that the label is
+		 now less used.  */
+	      for (inote = REG_NOTES (insn); inote; inote = XEXP (inote, 1))
+		{
+		  if (REG_NOTE_KIND (inote) == REG_LABEL)
+		    {
+		      rtx label = XEXP (inote, 0);
+		      rtx next;
+		      LABEL_NUSES (label)--;
+
+		      /* If this label was attached to an ADDR_VEC, it's
+			 safe to delete the ADDR_VEC.  In fact, it's pretty much
+			 mandatory to delete it, because the ADDR_VEC may
+			 be referencing labels that no longer exist.  */
+		      if (LABEL_NUSES (label) == 0
+			  && (next = next_nonnote_insn (label)) != NULL
+			  && GET_CODE (next) == JUMP_INSN
+			  && (GET_CODE (PATTERN (next)) == ADDR_VEC
+			      || GET_CODE (PATTERN (next)) == ADDR_DIFF_VEC))
+			{
+			  rtx pat = PATTERN (next);
+			  int diff_vec_p = GET_CODE (pat) == ADDR_DIFF_VEC;
+			  int len = XVECLEN (pat, diff_vec_p);
+			  int i;
+			  for (i = 0; i < len; i++)
+			    LABEL_NUSES (XEXP (XVECEXP (pat, diff_vec_p, i), 0))--;
+			  PUT_CODE (next, NOTE);
+			  NOTE_LINE_NUMBER (next) = NOTE_INSN_DELETED;
+			  NOTE_SOURCE_FILE (next) = 0;
+			}
+		    }
+		}
+
 	      PUT_CODE (insn, NOTE);
 	      NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
 	      NOTE_SOURCE_FILE (insn) = 0;
============================================================


More information about the Gcc-patches mailing list