public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [RFA:] Split REG_LABEL into REG_LABEL_TARGET and REG_LABEL_OPERAND
@ 2006-01-30 20:54 Hans-Peter Nilsson
  2006-01-30 21:31 ` Hans-Peter Nilsson
                   ` (3 more replies)
  0 siblings, 4 replies; 13+ messages in thread
From: Hans-Peter Nilsson @ 2006-01-30 20:54 UTC (permalink / raw)
  To: gcc-patches

:ADDPATCH middle-end:

So, here's the patch to split REG_LABEL into REG_LABEL_TARGET and
REG_LABEL_OPERAND.  See <URL:http://gcc.gnu.org/ml/gcc/2005-12/msg00279.html>
for why this is necessary.  (BTW, it's s/JUMP_TARGET/JUMP_LABEL/ in one
place, not the other way round as the followup says).

This patch has been bootstrapped and regression-tested on
i686-pc-linux-gnu (FC2) and regression-tested cross to cris-axis-elf,
cris-axis-linux-gnu, mmix-knuth-mmixware, sh-elf, sh64-elf and mips-elf.
The documentation changes have been "make info dvi" and those parts of
gccint.dvi visually inspected.

An earlier version with equivalent function but with the code in
propagate_block_delete_insn arranged a little differently (the if-body
split out into a helper function because I initially thought I'd need to
refer to it twice and then forgot to change it back) and with an extra
assert for absence of REG_LABEL_OPERAND notes on insns where a case-table
was deleted (instead of just ignoring them), was also bootstrapped on
x86_64-unknown-linux-gnu (FC4) and powerpc-unknown-linux-gnu (FC4).

I was a bit worried that for some reason this patch would cause
performance regressions or other issues for branch-target targets, so
(with the earlier version of the patch) I compared assembly for sh64-elf
in a tree where I also compiled csibe-2.1.1 with patches similar to those
posted at <URL:http://gcc.gnu.org/ml/gcc/2005-11/msg01318.html> (but
additional changes to work around the -DSTACK_SIZE=N option for sh64-sim)
at -O0, -O1, -O2, -Os and -O3 for "time".  I think that'd be enough to
expose any important regressions.

I found no regressions, but saw (only) these code changes which may
warrant some comments:

diff -upr asm-sh64.nonjmp7/as-15329 asm-sh64/as-15329
--- asm-sh64.nonjmp7/as-15329	2006-01-27 12:11:09.000000000 +0100
+++ asm-sh64/as-15329	2006-01-27 15:42:28.000000000 +0100
@@ -21,13 +21,6 @@ _x:
 .L3:
 	pt	.L3, tr0
 	blink	tr0, r63
-	.align 2
 .L2:
-	add.l	r14, r63, r15
-	ld.l	r15, 0, r14
-	ld.l	r15, 4, r18
-	addi.l	r15, 8, r15
-	ptabs	r18, tr0
-	blink	tr0, r63
 	.size	_x, .-_x
 	.ident	"GCC: (GNU) 4.2.0 20060126 (experimental)"

as-15329 is the -O0 compilation of gcc.c-torture/compile/920501-7.c.  The
(removed) code after L2 would be dead.  The change seems benevolent but
unimportant.  I didn't debug it, but it's probably that the code is
removed due to the first "blink tr0, r63" now getting its JUMP_LABEL field
set sticky and the dead-code-removal-at-O0 pass seeing this where
previously the field was being cleared.

diff -upr asm-sh64.nonjmp7/as-30060 asm-sh64/as-30060
--- asm-sh64.nonjmp7/as-30060	2006-01-27 13:09:05.000000000 +0100
+++ asm-sh64/as-30060	2006-01-27 16:40:23.000000000 +0100
@@ -1043,7 +1043,7 @@ _jpeg_gen_optimal_table:
 	blink	tr0, r18
 	pt	.L167, tr4
 	pt	.L169, tr3
-	pt	.L168, tr0
+	pt	.L168, tr1
 	movi	0, r6
 	movi	1, r5
 	blink	tr4, r63
@@ -1059,7 +1059,7 @@ _jpeg_gen_optimal_table:
 .L169:
 	addi.l	r2, 1, r2
 	movi	256, r1
-	bne	r2, r1, tr0
+	bne	r2, r1, tr1
 	addi.l	r5, 1, r5
 	movi	33, r1
 	bne	r5, r1, tr4
@@ -1090,7 +1090,7 @@ _jpeg_gen_optimal_table:
 .L167:
 	movi	0, r2
 	add.l	r11, r63, r3
-	blink	tr0, r63
+	blink	tr1, r63
 	.size	_jpeg_gen_optimal_table, .-_jpeg_gen_optimal_table
 	.align 2
 	.align 5

as-30060 is CSiBE/src/jpeg-6b/jchuff.c compiled at -O2.  The difference in
register allocation seems as unimportant as the plain renumbering; it's
not shown in the diff, but tr0..tr7 are all used in this function.

diff -upr asm-sh64.nonjmp7/as-31718 asm-sh64/as-31718
--- asm-sh64.nonjmp7/as-31718	2006-01-27 13:22:54.000000000 +0100
+++ asm-sh64/as-31718	2006-01-27 16:53:25.000000000 +0100
@@ -1747,18 +1747,16 @@ _debug_log_proc:
 	.global	_SetCryptKeys
 	.type	_SetCryptKeys, @function
 _SetCryptKeys:
-	gettr	tr5, r1
+	gettr	tr5, r0
 	pt	_strlen, tr5
 	addi.l	r15, -296, r15
-	gettr	tr6, r0
-	st.l	r15, 272, r14
-	st.l	r15, 256, r10
+	st.l	r15, 276, r14
+	st.l	r15, 260, r10
 	st.l	r15, 284, r0
-	st.l	r15, 280, r1
-	st.l	r15, 276, r18
-	st.l	r15, 268, r13
-	st.l	r15, 264, r12
-	st.l	r15, 260, r11
+	st.l	r15, 280, r18
+	st.l	r15, 272, r13
+	st.l	r15, 268, r12
+	st.l	r15, 264, r11
 	add.l	r15, r63, r14
 	add.l	r2, r63, r10
 	blink	tr5, r18
@@ -1861,7 +1859,6 @@ _SetCryptKeys:
 	shori	41525, r1
 	shori	61731, r2
 	st.l	r11, 12, r2
-	pt	.L196, tr6
 	add.l	r14, r63, r13
 	st.l	r11, 8, r1
 	movi	256, r4
@@ -1887,6 +1884,7 @@ _SetCryptKeys:
 	pt	.L193, tr2
 	pt	.L194, tr3
 	pt	.L198, tr4
+	pt	.L196, tr0
 	pt	.L206, tr1
 	movi	0, r8
 	movi	0, r9
@@ -1931,7 +1929,7 @@ _SetCryptKeys:
 	st.b	r7, 0, r3
 	addi.l	r4, 1, r4
 	st.b	r2, 0, r6
-	bne	r5, r0, tr6
+	bne	r5, r0, tr0
 .L194:
 	addi.l	r8, 2, r8
 .L216:
@@ -2134,17 +2132,15 @@ _SetCryptKeys:
 .L206:
 	addi.l	r14, 256, r14
 	add.l	r14, r63, r15
-	ld.l	r15, 20, r18
-	ld.l	r15, 24, r0
-	ld.l	r15, 28, r1
+	ld.l	r15, 24, r18
+	ld.l	r15, 28, r0
+	ld.l	r15, 4, r10
 	ptabs	r18, tr0
 	ptabs	r0, tr5
-	ptabs	r1, tr6
-	ld.l	r15, 0, r10
-	ld.l	r15, 4, r11
-	ld.l	r15, 8, r12
-	ld.l	r15, 12, r13
-	ld.l	r15, 16, r14
+	ld.l	r15, 8, r11
+	ld.l	r15, 12, r12
+	ld.l	r15, 16, r13
+	ld.l	r15, 20, r14
 	addi.l	r15, 40, r15
 	blink	tr0, r63
 	.size	_SetCryptKeys, .-_SetCryptKeys

as-31718 is CSiBE/src/unrarlib-0.4.0/unrarlib/unrarlib.c compiled at -O3.
This looks like a change for the better: in the first and last chunk we
see that tr6 isn't needed and thus not saved and restored.  Yay.  In the
other chunks, we see tr0 used where tr6 was used before the patch.  The
set of tr0 is elsewhere than for tr6, because GCC can't move the tr0 set
all the way up to the earlier tr6 init because of other local allocations
of tr0.

Ok to commit?

gcc:

	Divide REG_LABEL notes into REG_LABEL_OPERAND and REG_LABEL_TARGET.
	* reload.c (find_reloads): Generate REG_LABEL_OPERAND, not
	REG_LABEL when replacing an operand with a LABEL_REF for a
	non-jump insn.
	(subst_reloads): When replacing a LABEL_REG with a register,
	instead of generating a REG_LABEL note, assert that there already
	is one or that the label is a known target for the insn.
	* loop.c (add_label_notes): Generate REG_LABEL_OPERAND notes.
	Adjust head comment accordingly.
	(find_and_verify_loops): Test for REG_LABEL_OPERAND notes instead
	of testing insn type and REG_LABEL presence.
	* rtlanal.c (computed_jump_p): Instead of looking for a REG_LABEL
	note, check the JUMP_LABEL field.  Remove "else" after return.
	* reorg.c (emit_delay_sequence): Replace case for REG_LABEL with
	cases for REG_LABEL_OPERAND and REG_LABEL_TARGET.
	(fill_slots_from_thread): Handle both REG_LABEL_OPERAND and
	REG_LABEL_TARGET notes, including the JUMP_TARGET field on JUMP_P
	insns.  Iterate over all notes; don't assume there's only one.
	* flow.c (propagate_block_delete_insn): Check for a
	REG_LABEL_TARGET note referring to a case-table; ignore
	REG_LABEL_OPERAND notes.
	* cse.c (recorded_label_ref): Adjust comment to refer to
	REG_LABEL_OPERAND.
	(cse_basic_block): Do LABEL_REF check for all INSN_P insns, not
	just NONJUMP_INSN_P.
	(check_for_label_ref): For JUMP_P insns, check that the LABEL_REF
	isn't a jump target.
	(rebuild_jump_labels): Adjust head comment.
	(init_label_info): Ditto.  Remove REG_LABEL_OPERAND notes only;
	don't reset REG_LABEL_TARGET notes, including the JUMP_LABEL field.
	(mark_all_labels): For JUMP_P insns without a target, check if the
	the target is noted on the previous nonjump insn.
	(mark_jump_label_1): New function, guts from mark_jump_label.
	<case IF_THEN_ELSE>: Handle first operand as a non-target when
	marking jump target labels.
	<case LABEL_REF>: Adjust for whether to generate a
	REG_LABEL_TARGET or a REG_LABEL_OPERAND note.
	For 'E' format rtl, iterate in descending element order.
	(delete_related_insns): Handle both REG_LABEL_TARGET and
	REG_LABEL_OPERAND notes.  For JUMP_P insns with labels with zero
	reference count, delete and fallthrough.  Move finding-next-
	non-deleted insn last in the function.  Look at all INSN_P insns
	for REG_LABEL_OPERAND notes.
	(redirect_jump_2): Assert that OLABEL equals the old JUMP_LABEL of
	JUMP.
	* print-rtl.c (print_rtx): For JUMP_P insns and a non-NULL
	JUMP_LABEL, output the INSN_UID of it.
	* gcse.c: Adjust comments as appropriate to say REG_LABEL_OPERAND
	and/or REG_LABEL_TARGET.
	(add_label_notes): Only add REG_LABEL_OPERAND notes.  Put in line
	with jump.c copy by only adding notes for labels actually
	referenced in the insn.
	* emit-rtl.c (try_split): Don't assume only NONJUMP_INSN_P need
	usage count increment; handle all INSN_P trial insns.
	(emit_copy_of_insn_after): Change to not copy REG_LABEL_OPERAND
	notes.
	* rtl.h (struct rtx_def) <volatil>: Adjust to mention
	REG_LABEL_TARGET and REG_LABEL_OPERAND.
	(LABEL_REF_NONLOCAL_P): Allow REG_LABEL_TARGET and
	REG_LABEL_OPERAND.
	* combine.c (distribute_notes): Adjust for REG_LABEL_TARGET on
	JUMP_P insns and REG_LABEL_OPERAND everywhere.
	* sched-rgn.c (is_cfg_nonregular): Check for REG_LABEL_OPERANDS
	on all INSN_P insns.
	* reg-notes.def (LABEL_TARGET, LABEL_OPERAND): Split from LABEL.
	* cfgrtl.c (delete_insn): Adjust to handle REG_LABEL_TARGET and
	REG_LABEL_OPERAND notes.
	* reload1.c (calculate_needs_all_insns): Adjust comments.
	(set_label_offsets): Adjust to look for REG_LABEL_OPERAND notes.
	* config/alpha/alpha.md (split for load of an address into a
	four-insn sequence on Unicos/Mk): Adjust to use
	REG_LABEL_OPERAND.
	* config/sh/sh.md (sh_reorg, final_prescan_insn): Ditto.
	* doc/rtl.texi (Insns): Specify when a label_ref makes a jump_insn.
	Similar for what label_refs can go in the JUMP_TARGET field.  Split
	REG_LABEL documentation into REG_LABEL_TARGET and REG_LABEL_OPERAND.

Index: gcc/reload.c
===================================================================
--- gcc/reload.c	(revision 108225)
+++ gcc/reload.c	(working copy)
@@ -4036,13 +4036,18 @@ find_reloads (rtx insn, int replace, int
 
 	  *recog_data.operand_loc[i] = substitution;
 
-	  /* If we're replacing an operand with a LABEL_REF, we need
-	     to make sure that there's a REG_LABEL note attached to
+	  /* If we're replacing an operand with a LABEL_REF, we need to
+	     make sure that there's a REG_LABEL_OPERAND note attached to
 	     this instruction.  */
-	  if (!JUMP_P (insn)
-	      && GET_CODE (substitution) == LABEL_REF
-	      && !find_reg_note (insn, REG_LABEL, XEXP (substitution, 0)))
-	    REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL,
+	  if (GET_CODE (substitution) == LABEL_REF
+	      && !find_reg_note (insn, REG_LABEL_OPERAND,
+				 XEXP (substitution, 0))
+	      /* For a JUMP_P, if it was a branch target it must have
+		 already been recorded as such.  */
+	      && (!JUMP_P (insn)
+		  || !label_is_jump_target_p (XEXP (substitution, 0),
+					      insn)))
+	    REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL_OPERAND,
 						  XEXP (substitution, 0),
 						  REG_NOTES (insn));
 	}
@@ -5993,17 +5998,15 @@ subst_reloads (rtx insn)
 	    }
 #endif /* ENABLE_CHECKING */
 
-	  /* If we're replacing a LABEL_REF with a register, add a
-	     REG_LABEL note to indicate to flow which label this
+	  /* If we're replacing a LABEL_REF with a register, there must
+	     already be an indication (to e.g. flow) which label this
 	     register refers to.  */
-	  if (GET_CODE (*r->where) == LABEL_REF
-	      && JUMP_P (insn))
-	    {
-	      REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL,
-						    XEXP (*r->where, 0),
-						    REG_NOTES (insn));
-	      JUMP_LABEL (insn) = XEXP (*r->where, 0);
-	   }
+	  gcc_assert (GET_CODE (*r->where) != LABEL_REF
+		      || !JUMP_P (insn)
+		      || find_reg_note (insn,
+					REG_LABEL_OPERAND,
+					XEXP (*r->where, 0))
+		      || label_is_jump_target_p (XEXP (*r->where, 0), insn));
 
 	  /* Encapsulate RELOADREG so its machine mode matches what
 	     used to be there.  Note that gen_lowpart_common will
Index: gcc/loop.c
===================================================================
--- gcc/loop.c	(revision 108225)
+++ gcc/loop.c	(working copy)
@@ -2130,9 +2130,9 @@ rtx_equal_for_loop_p (rtx x, rtx y, stru
   return 1;
 }
 \f
-/* If X contains any LABEL_REF's, add REG_LABEL notes for them to all
-   insns in INSNS which use the reference.  LABEL_NUSES for CODE_LABEL
-   references is incremented once for each added note.  */
+/* If X contains any LABEL_REF's, add REG_LABEL_OPERAND notes for them
+   to all insns in INSNS which use the reference.  LABEL_NUSES for
+   CODE_LABEL references is incremented once for each added note.  */
 
 static void
 add_label_notes (rtx x, rtx insns)
@@ -2152,8 +2152,12 @@ add_label_notes (rtx x, rtx insns)
       for (insn = insns; insn; insn = NEXT_INSN (insn))
 	if (reg_mentioned_p (XEXP (x, 0), insn))
 	  {
-	    REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL, XEXP (x, 0),
-						  REG_NOTES (insn));
+	    /* There's no reason for current users to emit jump-insns
+	       with such a LABEL_REF.  */
+	    gcc_assert (!JUMP_P (insn));
+	    REG_NOTES (insn)
+	      = gen_rtx_INSN_LIST (REG_LABEL_OPERAND, XEXP (x, 0),
+				   REG_NOTES (insn));
 	    if (LABEL_P (XEXP (x, 0)))
 	      LABEL_NUSES (XEXP (x, 0))++;
 	  }
@@ -3124,11 +3128,11 @@ find_and_verify_loops (rtx f, struct loo
      invalidated, because it can be jumped into from anywhere.  */
   for_each_eh_label (invalidate_loops_containing_label);
 
-  /* Now scan all insn's in the function.  If any JUMP_INSN branches into a
-     loop that it is not contained within, that loop is marked invalid.
-     If any INSN or CALL_INSN uses a label's address, then the loop containing
-     that label is marked invalid, because it could be jumped into from
-     anywhere.
+  /* Now scan all insn's in the function.  If any JUMP_INSN branches into
+     a loop that it is not contained within, that loop is marked invalid.
+     If any insn uses a label's address as an operand, then the loop
+     containing that label is marked invalid, because it could be jumped
+     into from anywhere.
 
      Also look for blocks of code ending in an unconditional branch that
      exits the loop.  If such a block is surrounded by a conditional
@@ -3142,11 +3146,15 @@ find_and_verify_loops (rtx f, struct loo
       {
 	struct loop *this_loop = uid_loop[INSN_UID (insn)];
 
-	if (NONJUMP_INSN_P (insn) || CALL_P (insn))
+	if (INSN_P (insn))
 	  {
-	    rtx note = find_reg_note (insn, REG_LABEL, NULL_RTX);
-	    if (note)
-	      invalidate_loops_containing_label (XEXP (note, 0));
+	    rtx note;
+
+	    for (note = find_reg_note (insn, REG_LABEL_OPERAND, NULL_RTX);
+		 note != NULL;
+		 note = XEXP (note, 1))
+	      if (REG_NOTE_KIND (note) == REG_LABEL_OPERAND)
+		invalidate_loops_containing_label (XEXP (note, 0));
 	  }
 
 	if (!JUMP_P (insn))
Index: gcc/rtlanal.c
===================================================================
--- gcc/rtlanal.c	(revision 108225)
+++ gcc/rtlanal.c	(working copy)
@@ -2703,9 +2703,11 @@ computed_jump_p (rtx insn)
     {
       rtx pat = PATTERN (insn);
 
-      if (find_reg_note (insn, REG_LABEL, NULL_RTX))
+      /* If we have a JUMP_LABEL set, we're not a computed jump.  */
+      if (JUMP_LABEL (insn) != NULL)
 	return 0;
-      else if (GET_CODE (pat) == PARALLEL)
+
+      if (GET_CODE (pat) == PARALLEL)
 	{
 	  int len = XVECLEN (pat, 0);
 	  int has_use_labelref = 0;
Index: gcc/reorg.c
===================================================================
--- gcc/reorg.c	(revision 108225)
+++ gcc/reorg.c	(working copy)
@@ -540,7 +540,8 @@ emit_delay_sequence (rtx insn, rtx list,
 	      remove_note (tem, note);
 	      break;
 
-	    case REG_LABEL:
+	    case REG_LABEL_OPERAND:
+	    case REG_LABEL_TARGET:
 	      /* Keep the label reference count up to date.  */
 	      if (LABEL_P (XEXP (note, 0)))
 		LABEL_NUSES (XEXP (note, 0)) ++;
@@ -2719,14 +2720,40 @@ fill_slots_from_thread (rtx insn, rtx co
 		      /* We are moving this insn, not deleting it.  We must
 			 temporarily increment the use count on any referenced
 			 label lest it be deleted by delete_related_insns.  */
-		      note = find_reg_note (trial, REG_LABEL, 0);
-		      /* REG_LABEL could be NOTE_INSN_DELETED_LABEL too.  */
-		      if (note && LABEL_P (XEXP (note, 0)))
+		      for (note = REG_NOTES (trial);
+			   note != NULL;
+			   note = XEXP (note, 1))
+			if (REG_NOTE_KIND (note) == REG_LABEL_OPERAND
+			    || REG_NOTE_KIND (note) == REG_LABEL_TARGET)
+			  {
+			    /* REG_LABEL_OPERAND could be
+			       NOTE_INSN_DELETED_LABEL too.  */
+			    if (LABEL_P (XEXP (note, 0)))
+			      LABEL_NUSES (XEXP (note, 0))++;
+			    else
+			      gcc_assert (REG_NOTE_KIND (note)
+					  == REG_LABEL_OPERAND);
+			  }
+		      if (JUMP_P (trial) && JUMP_LABEL (trial))
 			LABEL_NUSES (XEXP (note, 0))++;
 
 		      delete_related_insns (trial);
 
-		      if (note && LABEL_P (XEXP (note, 0)))
+		      for (note = REG_NOTES (trial);
+			   note != NULL;
+			   note = XEXP (note, 1))
+			if (REG_NOTE_KIND (note) == REG_LABEL_OPERAND
+			    || REG_NOTE_KIND (note) == REG_LABEL_TARGET)
+			  {
+			    /* REG_LABEL_OPERAND could be
+			       NOTE_INSN_DELETED_LABEL too.  */
+			    if (LABEL_P (XEXP (note, 0)))
+			      LABEL_NUSES (XEXP (note, 0))--;
+			    else
+			      gcc_assert (REG_NOTE_KIND (note)
+					  == REG_LABEL_OPERAND);
+			  }
+		      if (JUMP_P (trial) && JUMP_LABEL (trial))
 			LABEL_NUSES (XEXP (note, 0))--;
 		    }
 		  else
Index: gcc/flow.c
===================================================================
--- gcc/flow.c	(revision 108225)
+++ gcc/flow.c	(working copy)
@@ -293,6 +293,7 @@ static void notice_stack_pointer_modific
 static void mark_reg (rtx, void *);
 static void mark_regs_live_at_end (regset);
 static void calculate_global_regs_live (sbitmap, sbitmap, int);
+static bool propagate_block_delete_insn_label_note (rtx);
 static void propagate_block_delete_insn (rtx);
 static rtx propagate_block_delete_libcall (rtx, rtx);
 static int insn_dead_p (struct propagate_block_info *, rtx, int, rtx);
@@ -1598,8 +1599,24 @@ allocate_reg_life_data (void)
 static void
 propagate_block_delete_insn (rtx insn)
 {
-  rtx inote = find_reg_note (insn, REG_LABEL, NULL_RTX);
+  rtx inote = find_reg_note (insn, REG_LABEL_TARGET, NULL_RTX);
 
+  if (inote != NULL
+      && !propagate_block_delete_insn_label_note (XEXP (inote, 0)))
+    /* ADDR_VECs must be referred to as targets, not operands.  */
+    gcc_assert (find_reg_note (insn, REG_LABEL_OPERAND, NULL_RTX) == NULL);
+
+  delete_insn_and_edges (insn);
+  ndead++;
+}
+
+/* Worker function for propagate_block_delete_insn.  Checks whether
+   LABEL refers to a case-table and if so, deletes it.
+   Returns TRUE if a case-table was deleted, FALSE otherwise.  */
+
+static bool
+propagate_block_delete_insn_label_note (rtx label)
+{
   /* If the insn referred to a label, and that 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
@@ -1610,9 +1627,8 @@ propagate_block_delete_insn (rtx insn)
      real good way to fix up the reference to the deleted label
      when the label is deleted, so we just allow it here.  */
 
-  if (inote && LABEL_P (inote))
+  if (LABEL_P (label))
     {
-      rtx label = XEXP (inote, 0);
       rtx next;
 
       /* The label may be forced if it has been put in the constant
@@ -1634,11 +1650,12 @@ propagate_block_delete_insn (rtx insn)
 
 	  delete_insn_and_edges (next);
 	  ndead++;
+
+	  return true;
 	}
     }
 
-  delete_insn_and_edges (insn);
-  ndead++;
+  return false;
 }
 
 /* Delete dead libcalls for propagate_block.  Return the insn
Index: gcc/cse.c
===================================================================
--- gcc/cse.c	(revision 108225)
+++ gcc/cse.c	(working copy)
@@ -381,8 +381,9 @@ static int cse_altered;
 
 static int cse_jumps_altered;
 
-/* Nonzero if we put a LABEL_REF into the hash table for an INSN without a
-   REG_LABEL, we have to rerun jump after CSE to put in the note.  */
+/* Nonzero if we put a LABEL_REF into the hash table for an INSN
+   without a REG_LABEL_OPERAND, we have to rerun jump after CSE to put
+   in the note.  */
 static int recorded_label_ref;
 
 /* canon_hash stores 1 in do_not_record
@@ -6970,7 +6971,7 @@ cse_basic_block (rtx from, rtx to, struc
 	    
 	  /* If we haven't already found an insn where we added a LABEL_REF,
 	     check this one.  */
-	  if (NONJUMP_INSN_P (insn) && ! recorded_label_ref
+	  if (INSN_P (insn) && ! recorded_label_ref
 	      && for_each_rtx (&PATTERN (insn), check_for_label_ref,
 			       (void *) insn))
 	    recorded_label_ref = 1;
@@ -7069,23 +7070,26 @@ cse_basic_block (rtx from, rtx to, struc
   return to ? NEXT_INSN (to) : 0;
 }
 \f
-/* Called via for_each_rtx to see if an insn is using a LABEL_REF for which
-   there isn't a REG_LABEL note.  Return one if so.  DATA is the insn.  */
+/* Called via for_each_rtx to see if an insn is using a LABEL_REF for
+   which there isn't a REG_LABEL_OPERAND note.
+   Return one if so.  DATA is the insn.  */
 
 static int
 check_for_label_ref (rtx *rtl, void *data)
 {
   rtx insn = (rtx) data;
 
-  /* If this insn uses a LABEL_REF and there isn't a REG_LABEL note for it,
-     we must rerun jump since it needs to place the note.  If this is a
-     LABEL_REF for a CODE_LABEL that isn't in the insn chain, don't do this
-     since no REG_LABEL will be added.  */
+  /* If this insn uses a LABEL_REF and there isn't a REG_LABEL_OPERAND
+     note for it, we must rerun jump since it needs to place the note.  If
+     this is a LABEL_REF for a CODE_LABEL that isn't in the insn chain,
+     don't do this since no REG_LABEL_OPERAND will be added.  */
   return (GET_CODE (*rtl) == LABEL_REF
 	  && ! LABEL_REF_NONLOCAL_P (*rtl)
+	  && (!JUMP_P (insn)
+	      || !label_is_jump_target_p (XEXP (*rtl, 0), insn))
 	  && LABEL_P (XEXP (*rtl, 0))
 	  && INSN_UID (XEXP (*rtl, 0)) != 0
-	  && ! find_reg_note (insn, REG_LABEL, XEXP (*rtl, 0)));
+	  && ! find_reg_note (insn, REG_LABEL_OPERAND, XEXP (*rtl, 0)));
 }
 \f
 /* Count the number of times registers are used (not set) in X.
Index: gcc/jump.c
===================================================================
--- gcc/jump.c	(revision 108225)
+++ gcc/jump.c	(working copy)
@@ -68,15 +68,17 @@ Software Foundation, 51 Franklin Street,
 
 static void init_label_info (rtx);
 static void mark_all_labels (rtx);
+static void mark_jump_label_1 (rtx, rtx, bool, bool);
 static void delete_computation (rtx);
 static void redirect_exp_1 (rtx *, rtx, rtx, rtx);
 static int invert_exp_1 (rtx, rtx);
 static int returnjump_p_1 (rtx *, void *);
 static void delete_prior_computation (rtx, rtx);
 \f
-/* Alternate entry into the jump optimizer.  This entry point only rebuilds
-   the JUMP_LABEL field in jumping insns and REG_LABEL notes in non-jumping
-   instructions.  */
+/* This function rebuilds the JUMP_LABEL field and REG_LABEL_TARGET
+   notes in jumping insns and REG_LABEL_OPERAND notes in non-jumping
+   instructions and jumping insns that have labels as operands
+   (e.g. cbranchsi4).  */
 void
 rebuild_jump_labels (rtx f)
 {
@@ -195,31 +197,43 @@ struct tree_opt_pass pass_purge_lineno_n
 };
 
 \f
-/* Initialize LABEL_NUSES and JUMP_LABEL fields.  Delete any REG_LABEL
-   notes whose labels don't occur in the insn any more.  Returns the
-   largest INSN_UID found.  */
+/* Initialize LABEL_NUSES and JUMP_LABEL fields, add REG_LABEL_TARGET
+   for remaining targets for JUMP_P.  Delete any REG_LABEL_OPERAND
+   notes whose labels don't occur in the insn any more.  */
+
 static void
 init_label_info (rtx f)
 {
   rtx insn;
 
   for (insn = f; insn; insn = NEXT_INSN (insn))
-    if (LABEL_P (insn))
-      LABEL_NUSES (insn) = (LABEL_PRESERVE_P (insn) != 0);
-    else if (JUMP_P (insn))
-      JUMP_LABEL (insn) = 0;
-    else if (NONJUMP_INSN_P (insn) || CALL_P (insn))
-      {
-	rtx note, next;
+    {
+      if (LABEL_P (insn))
+	LABEL_NUSES (insn) = (LABEL_PRESERVE_P (insn) != 0);
 
-	for (note = REG_NOTES (insn); note; note = next)
-	  {
-	    next = XEXP (note, 1);
-	    if (REG_NOTE_KIND (note) == REG_LABEL
-		&& ! reg_mentioned_p (XEXP (note, 0), PATTERN (insn)))
-	      remove_note (insn, note);
-	  }
-      }
+      /* REG_LABEL_TARGET notes (including the JUMP_LABEL field) are
+	 sticky and not reset here; that way we won't lose association
+	 with a label when e.g. the source for a target register
+	 disappears out of reach for targets that may use jump-target
+	 registers.  Jump transformations are supposed to transform
+	 any REG_LABEL_TARGET notes.  The target label reference in a
+	 branch may disappear from the branch (and from the
+	 instruction before it) for other reasons, like register
+	 allocation.  */
+
+      if (INSN_P (insn))
+	{
+	  rtx note, next;
+
+	  for (note = REG_NOTES (insn); note; note = next)
+	    {
+	      next = XEXP (note, 1);
+	      if (REG_NOTE_KIND (note) == REG_LABEL_OPERAND
+		  && ! reg_mentioned_p (XEXP (note, 0), PATTERN (insn)))
+		remove_note (insn, note);
+	    }
+	}
+    }
 }
 
 /* Mark the label each jump jumps to.
@@ -229,33 +243,68 @@ static void
 mark_all_labels (rtx f)
 {
   rtx insn;
+  rtx prev_nonjump_insn = NULL;
 
   for (insn = f; insn; insn = NEXT_INSN (insn))
     if (INSN_P (insn))
       {
 	mark_jump_label (PATTERN (insn), insn, 0);
-	if (! INSN_DELETED_P (insn) && JUMP_P (insn))
+
+	/* If the previous non-jump insn sets something to a label,
+	   something that this jump insn uses, make that label the primary
+	   target of this insn if we don't yet have any.  That previous
+	   insn must be a single_set and not refer to more than one label.
+	   The jump insn must not refer to other labels as jump targets
+	   and must be a plain (set (pc) ...), maybe in a parallel, and
+	   may refer to the item being set only directly or as one of the
+	   arms in an IF_THEN_ELSE.  */
+	if (! INSN_DELETED_P (insn)
+	    && JUMP_P (insn)
+	    && JUMP_LABEL (insn) == NULL)
 	  {
-	    /* When we know the LABEL_REF contained in a REG used in
-	       an indirect jump, we'll have a REG_LABEL note so that
-	       flow can tell where it's going.  */
-	    if (JUMP_LABEL (insn) == 0)
+	    rtx label_note = NULL;
+	    rtx pc = pc_set (insn);
+	    rtx pc_src = pc != NULL ? SET_SRC (pc) : NULL;
+
+	    if (prev_nonjump_insn != NULL)
+	      label_note
+		= find_reg_note (prev_nonjump_insn, REG_LABEL_OPERAND, NULL);
+
+	    if (label_note != NULL && pc_src != NULL)
 	      {
-		rtx label_note = find_reg_note (insn, REG_LABEL, NULL_RTX);
-		if (label_note)
+		rtx label_set = single_set (prev_nonjump_insn);
+		rtx label_dest
+		  = label_set != NULL ? SET_DEST (label_set) : NULL;
+
+		if (label_set != NULL
+		    /* The source must be the direct LABEL_REF, not a
+		       PLUS, UNSPEC, IF_THEN_ELSE etc.  */
+		    && GET_CODE (SET_SRC (label_set)) == LABEL_REF
+		    && (rtx_equal_p (label_dest, pc_src)
+			|| (GET_CODE (pc_src) == IF_THEN_ELSE
+			    && (rtx_equal_p (label_dest, XEXP (pc_src, 1))
+				|| rtx_equal_p (label_dest,
+						XEXP (pc_src, 2))))))
+				
 		  {
-		    /* But a LABEL_REF around the REG_LABEL note, so
-		       that we can canonicalize it.  */
-		    rtx label_ref = gen_rtx_LABEL_REF (Pmode,
-						       XEXP (label_note, 0));
-
-		    mark_jump_label (label_ref, insn, 0);
-		    XEXP (label_note, 0) = XEXP (label_ref, 0);
-		    JUMP_LABEL (insn) = XEXP (label_note, 0);
+		    /* The CODE_LABEL referred to in the note must be the
+		       CODE_LABEL in the LABEL_REF of the "set".  We can
+		       conveniently use it for the marker function, which
+		       requires a LABEL_REF wrapping.  */
+		    gcc_assert (XEXP (label_note, 0)
+				== XEXP (SET_SRC (label_set), 0));
+
+		    mark_jump_label_1 (label_set, insn, false, true);
+		    gcc_assert (JUMP_LABEL (insn)
+				== XEXP (SET_SRC (label_set), 0));
 		  }
 	      }
 	  }
+	else if (! INSN_DELETED_P (insn))
+	  prev_nonjump_insn = insn;
       }
+    else if (LABEL_P (insn))
+      prev_nonjump_insn = NULL;
 }
 \f
 /* Move all block-beg, block-end, loop-beg, loop-cont, loop-vtop, loop-end,
@@ -1092,12 +1141,14 @@ follow_jumps (rtx label)
 }
 
 \f
-/* Find all CODE_LABELs referred to in X, and increment their use counts.
-   If INSN is a JUMP_INSN and there is at least one CODE_LABEL referenced
-   in INSN, then store one of them in JUMP_LABEL (INSN).
-   If INSN is an INSN or a CALL_INSN and there is at least one CODE_LABEL
-   referenced in INSN, add a REG_LABEL note containing that label to INSN.
-   Also, when there are consecutive labels, canonicalize on the last of them.
+/* Find all CODE_LABELs referred to in X, and increment their use
+   counts.  If INSN is a JUMP_INSN and there is at least one
+   CODE_LABEL referenced in INSN as a jump target, then store the last
+   one in JUMP_LABEL (INSN).  For a tablejump, this must be the label
+   for the ADDR_VEC.  Store any other jump targets as REG_LABEL_TARGET
+   notes.  If INSN is an INSN or a CALL_INSN or non-target operands of
+   a JUMP_INSN, and there is at least one CODE_LABEL referenced in
+   INSN, add a REG_LABEL_OPERAND note containing that label to INSN.
 
    Note that two labels separated by a loop-beginning note
    must be kept distinct if we have not yet done loop-optimization,
@@ -1108,6 +1159,19 @@ follow_jumps (rtx label)
 void
 mark_jump_label (rtx x, rtx insn, int in_mem)
 {
+  mark_jump_label_1 (x, insn, in_mem != 0,
+		     (insn != NULL && x == PATTERN (insn) && JUMP_P (insn)));
+}
+
+/* Worker function for mark_jump_label.  IN_MEM is TRUE when X occurrs
+   within a (MEM ...).  IS_TARGET is TRUE when X is to be treated as a
+   jump-target; when the JUMP_LABEL field of INSN should be set or a
+   REG_LABEL_TARGET note should be added, not a REG_LABEL_OPERAND
+   note.  */
+
+static void
+mark_jump_label_1 (rtx x, rtx insn, bool in_mem, bool is_target)
+{
   RTX_CODE code = GET_CODE (x);
   int i;
   const char *fmt;
@@ -1124,7 +1188,7 @@ mark_jump_label (rtx x, rtx insn, int in
       return;
 
     case MEM:
-      in_mem = 1;
+      in_mem = true;
       break;
 
     case SYMBOL_REF:
@@ -1133,9 +1197,19 @@ mark_jump_label (rtx x, rtx insn, int in
 
       /* If this is a constant-pool reference, see if it is a label.  */
       if (CONSTANT_POOL_ADDRESS_P (x))
-	mark_jump_label (get_pool_constant (x), insn, in_mem);
+	mark_jump_label_1 (get_pool_constant (x), insn, in_mem, is_target);
       break;
 
+      /* Handle operands in the condition of an if-then-else as for a
+	 non-jump insn.  */
+    case IF_THEN_ELSE:
+      if (!is_target)
+	break;
+      mark_jump_label_1 (XEXP (x, 0), insn, in_mem, false);
+      mark_jump_label_1 (XEXP (x, 1), insn, in_mem, true);
+      mark_jump_label_1 (XEXP (x, 2), insn, in_mem, true);
+      return;
+
     case LABEL_REF:
       {
 	rtx label = XEXP (x, 0);
@@ -1158,17 +1232,21 @@ mark_jump_label (rtx x, rtx insn, int in
 
 	if (insn)
 	  {
-	    if (JUMP_P (insn))
+	    if (is_target
+		&& (JUMP_LABEL (insn) == NULL || JUMP_LABEL (insn) == label))
 	      JUMP_LABEL (insn) = label;
 	    else
 	      {
-		/* Add a REG_LABEL note for LABEL unless there already
-		   is one.  All uses of a label, except for labels
-		   that are the targets of jumps, must have a
-		   REG_LABEL note.  */
-		if (! find_reg_note (insn, REG_LABEL, label))
-		  REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL, label,
-							REG_NOTES (insn));
+		enum reg_note kind
+		  = is_target ? REG_LABEL_TARGET : REG_LABEL_OPERAND;
+
+		/* Add a REG_LABEL_OPERAND or REG_LABEL_TARGET note
+		   for LABEL unless there already is one.  All uses of
+		   a label, except for the primary target of a jump,
+		   must have such a note.  */
+		if (! find_reg_note (insn, kind, label))
+		  REG_NOTES (insn)
+		    = gen_rtx_INSN_LIST (kind, label, REG_NOTES (insn));
 	      }
 	  }
 	return;
@@ -1183,7 +1261,8 @@ mark_jump_label (rtx x, rtx insn, int in
 	  int eltnum = code == ADDR_DIFF_VEC ? 1 : 0;
 
 	  for (i = 0; i < XVECLEN (x, eltnum); i++)
-	    mark_jump_label (XVECEXP (x, eltnum, i), NULL_RTX, in_mem);
+	    mark_jump_label_1 (XVECEXP (x, eltnum, i), NULL_RTX, in_mem,
+			       is_target);
 	}
       return;
 
@@ -1192,15 +1271,21 @@ mark_jump_label (rtx x, rtx insn, int in
     }
 
   fmt = GET_RTX_FORMAT (code);
+
+  /* The primary target of a tablejump is the label of the ADDR_VEC,
+     which is canonically mentioned *last* in the insn.  To get it
+     marked as JUMP_LABEL, we iterate over items in reverse order.  */
   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
     {
       if (fmt[i] == 'e')
-	mark_jump_label (XEXP (x, i), insn, in_mem);
+	mark_jump_label_1 (XEXP (x, i), insn, in_mem, is_target);
       else if (fmt[i] == 'E')
 	{
 	  int j;
-	  for (j = 0; j < XVECLEN (x, i); j++)
-	    mark_jump_label (XVECEXP (x, i, j), insn, in_mem);
+
+	  for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+	    mark_jump_label_1 (XVECEXP (x, i, j), insn, in_mem,
+			       is_target);
 	}
     }
 }
@@ -1430,20 +1515,10 @@ delete_related_insns (rtx insn)
       rtx lab = JUMP_LABEL (insn), lab_next;
 
       if (LABEL_NUSES (lab) == 0)
-	{
-	  /* This can delete NEXT or PREV,
-	     either directly if NEXT is JUMP_LABEL (INSN),
-	     or indirectly through more levels of jumps.  */
-	  delete_related_insns (lab);
-
-	  /* I feel a little doubtful about this loop,
-	     but I see no clean and sure alternative way
-	     to find the first insn after INSN that is not now deleted.
-	     I hope this works.  */
-	  while (next && INSN_DELETED_P (next))
-	    next = NEXT_INSN (next);
-	  return next;
-	}
+	/* This can delete NEXT or PREV,
+	   either directly if NEXT is JUMP_LABEL (INSN),
+	   or indirectly through more levels of jumps.  */
+	delete_related_insns (lab);
       else if (tablejump_p (insn, NULL, &lab_next))
 	{
 	  /* If we're deleting the tablejump, delete the dispatch table.
@@ -1472,10 +1547,12 @@ delete_related_insns (rtx insn)
       return next;
     }
 
-  /* Likewise for an ordinary INSN / CALL_INSN with a REG_LABEL note.  */
-  if (NONJUMP_INSN_P (insn) || CALL_P (insn))
+  /* Likewise for any JUMP_P / INSN / CALL_INSN with a
+     REG_LABEL_OPERAND or REG_LABEL_TARGET note.  */
+  if (INSN_P (insn))
     for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
-      if (REG_NOTE_KIND (note) == REG_LABEL
+      if ((REG_NOTE_KIND (note) == REG_LABEL_OPERAND
+	   || REG_NOTE_KIND (note) == REG_LABEL_TARGET)
 	  /* This could also be a NOTE_INSN_DELETED_LABEL note.  */
 	  && LABEL_P (XEXP (note, 0)))
 	if (LABEL_NUSES (XEXP (note, 0)) == 0)
@@ -1520,6 +1597,12 @@ delete_related_insns (rtx insn)
 	}
     }
 
+  /* I feel a little doubtful about this loop,
+     but I see no clean and sure alternative way
+     to find the first insn after INSN that is not now deleted.
+     I hope this works.  */
+  while (next && INSN_DELETED_P (next))
+    next = NEXT_INSN (next);
   return next;
 }
 \f
@@ -1677,6 +1760,8 @@ redirect_jump_2 (rtx jump, rtx olabel, r
 {
   rtx note;
 
+  gcc_assert (JUMP_LABEL (jump) == olabel);
+
   JUMP_LABEL (jump) = nlabel;
   if (nlabel)
     ++LABEL_NUSES (nlabel);
Index: gcc/print-rtl.c
===================================================================
--- gcc/print-rtl.c	(revision 108225)
+++ gcc/print-rtl.c	(working copy)
@@ -359,6 +359,9 @@ print_rtx (rtx in_rtx)
 		}
 	      }
 	  }
+	else if (i == 9 && JUMP_P (in_rtx) && XEXP (in_rtx, i) != NULL)
+	  /* Output the JUMP_LABEL reference.  */
+	  fprintf (outfile, "\n -> %d", INSN_UID (XEXP (in_rtx, i)));
 	break;
 
       case 'e':
Index: gcc/gcse.c
===================================================================
--- gcc/gcse.c	(revision 108225)
+++ gcc/gcse.c	(working copy)
@@ -4564,17 +4575,18 @@ one_pre_gcse_pass (int pass)
   return changed;
 }
 \f
-/* If X contains any LABEL_REF's, add REG_LABEL notes for them to INSN.
-   If notes are added to an insn which references a CODE_LABEL, the
-   LABEL_NUSES count is incremented.  We have to add REG_LABEL notes,
-   because the following loop optimization pass requires them.  */
+/* If X contains any LABEL_REF's, add REG_LABEL_OPERAND notes for them
+   to INSN.  If such notes are added to an insn which references a
+   CODE_LABEL, the LABEL_NUSES count is incremented.  We have to add
+   that note, because the following loop optimization pass requires
+   them.  */
 
 /* ??? This is very similar to the loop.c add_label_notes function.  We
    could probably share code here.  */
 
 /* ??? If there was a jump optimization pass after gcse and before loop,
    then we would not need to do this here, because jump would add the
-   necessary REG_LABEL notes.  */
+   necessary REG_LABEL_OPERAND and REG_LABEL_TARGET notes.  */
 
 static void
 add_label_notes (rtx x, rtx insn)
@@ -4591,10 +4603,18 @@ add_label_notes (rtx x, rtx insn)
 	 We no longer ignore such label references (see LABEL_REF handling in
 	 mark_jump_label for additional information).  */
 
-      REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL, XEXP (x, 0),
-					    REG_NOTES (insn));
-      if (LABEL_P (XEXP (x, 0)))
-	LABEL_NUSES (XEXP (x, 0))++;
+	if (reg_mentioned_p (XEXP (x, 0), insn))
+	  {
+	    /* There's no reason for current users to emit jump-insns
+	       with such a LABEL_REF, so we don't have to handle
+	       REG_LABEL_TARGET notes.  */
+	    gcc_assert (!JUMP_P (insn));
+	    REG_NOTES (insn)
+	      = gen_rtx_INSN_LIST (REG_LABEL_OPERAND, XEXP (x, 0),
+				   REG_NOTES (insn));
+	    if (LABEL_P (XEXP (x, 0)))
+	      LABEL_NUSES (XEXP (x, 0))++;
+	  }
       return;
     }
 
Index: gcc/emit-rtl.c
===================================================================
--- gcc/emit-rtl.c	(revision 108225)
+++ gcc/emit-rtl.c	(working copy)
@@ -3272,11 +3272,12 @@ try_split (rtx pat, rtx trial, int last)
 
   /* If there are LABELS inside the split insns increment the
      usage count so we don't delete the label.  */
-  if (NONJUMP_INSN_P (trial))
+  if (INSN_P (trial))
     {
       insn = insn_last;
       while (insn != NULL_RTX)
 	{
+	  /* JUMP_P insns have already been "marked" above.  */
 	  if (NONJUMP_INSN_P (insn))
 	    mark_label_nuses (PATTERN (insn));
 
@@ -5438,10 +5439,11 @@ emit_copy_of_insn_after (rtx insn, rtx a
      which may be duplicated by the basic block reordering code.  */
   RTX_FRAME_RELATED_P (new) = RTX_FRAME_RELATED_P (insn);
 
-  /* Copy all REG_NOTES except REG_LABEL since mark_jump_label will
-     make them.  */
+  /* Copy all REG_NOTES except REG_LABEL_OPERAND since mark_jump_label
+     will make them.  REG_LABEL_TARGETs are created there too, but are
+     supposed to be sticky, so we copy them.  */
   for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
-    if (REG_NOTE_KIND (link) != REG_LABEL)
+    if (REG_NOTE_KIND (link) != REG_LABEL_OPERAND)
       {
 	if (GET_CODE (link) == EXPR_LIST)
 	  REG_NOTES (new)
Index: gcc/rtl.h
===================================================================
--- gcc/rtl.h	(revision 108225)
+++ gcc/rtl.h	(working copy)
@@ -208,7 +208,8 @@ struct rtx_def GTY((chain_next ("RTX_NEX
      1 in a REG expression if corresponds to a variable declared by the user,
      0 for an internally generated temporary.
      1 in a SUBREG with a negative value.
-     1 in a LABEL_REF or in a REG_LABEL note for a non-local label.
+     1 in a LABEL_REF, REG_LABEL_TARGET or REG_LABEL_OPERAND note for a
+     non-local label.
      In a SYMBOL_REF, this flag is used for machine-specific purposes.  */
   unsigned int volatil : 1;
   /* 1 in a MEM referring to a field of an aggregate.
@@ -1137,10 +1138,11 @@ do {						\
   (RTL_FLAG_CHECK1("LABEL_OUTSIDE_LOOP_P", (RTX), LABEL_REF)->in_struct)
 
 /* 1 if RTX is a label_ref for a nonlocal label.  */
-/* Likewise in an expr_list for a reg_label note.  */
+/* Likewise in an expr_list for a REG_LABEL_OPERAND or
+   REG_LABEL_TARGET note.  */
 #define LABEL_REF_NONLOCAL_P(RTX)					\
-  (RTL_FLAG_CHECK2("LABEL_REF_NONLOCAL_P", (RTX), LABEL_REF,		\
-		   REG_LABEL)->volatil)
+  (RTL_FLAG_CHECK3("LABEL_REF_NONLOCAL_P", (RTX), LABEL_REF,		\
+		   REG_LABEL_OPERAND, REG_LABEL_TARGET)->volatil)
 
 /* 1 if RTX is a code_label that should always be considered to be needed.  */
 #define LABEL_PRESERVE_P(RTX)						\
Index: gcc/combine.c
===================================================================
--- gcc/combine.c	(revision 108225)
+++ gcc/combine.c	(working copy)
@@ -12142,7 +12142,8 @@ distribute_notes (rtx notes, rtx from_in
 	    }
 	  break;
 
-	case REG_LABEL:
+	case REG_LABEL_TARGET:
+	case REG_LABEL_OPERAND:
 	  /* This can show up in several ways -- either directly in the
 	     pattern, or hidden off in the constant pool with (or without?)
 	     a REG_EQUAL note.  */
@@ -12165,34 +12166,33 @@ distribute_notes (rtx notes, rtx from_in
 		place = i2;
 	    }
 
-	  /* Don't attach REG_LABEL note to a JUMP_INSN.  Add
-	     a JUMP_LABEL instead or decrement LABEL_NUSES.  */
-	  if (place && JUMP_P (place))
+	  /* For REG_LABEL_TARGET on a JUMP_P, we prefer to put the note
+	     as a JUMP_LABEL or decrement LABEL_NUSES if it's already
+	     there.  */
+	  if (place && JUMP_P (place)
+	      && REG_NOTE_KIND (note) == REG_LABEL_TARGET
+	      && (JUMP_LABEL (place) == NULL
+		  || JUMP_LABEL (place) == XEXP (note, 0)))
 	    {
 	      rtx label = JUMP_LABEL (place);
 	      
 	      if (!label)
 		JUMP_LABEL (place) = XEXP (note, 0);
-	      else
-		{
-		  gcc_assert (label == XEXP (note, 0));
-		  if (LABEL_P (label))
-		    LABEL_NUSES (label)--;
-		}
+	      else if (LABEL_P (label))
+		LABEL_NUSES (label)--;
 	      place = 0;
 	    }
-	  if (place2 && JUMP_P (place2))
+	  if (place2 && JUMP_P (place2)
+	      && REG_NOTE_KIND (note) == REG_LABEL_TARGET
+	      && (JUMP_LABEL (place2) == NULL
+		  || JUMP_LABEL (place2) == XEXP (note, 0)))
 	    {
 	      rtx label = JUMP_LABEL (place2);
 	      
 	      if (!label)
 		JUMP_LABEL (place2) = XEXP (note, 0);
-	      else
-		{
-		  gcc_assert (label == XEXP (note, 0));
-		  if (LABEL_P (label))
-		    LABEL_NUSES (label)--;
-		}
+	      else if (LABEL_P (label))
+		LABEL_NUSES (label)--;
 	      place2 = 0;
 	    }
 	  break;
Index: gcc/sched-rgn.c
===================================================================
--- gcc/sched-rgn.c	(revision 108225)
+++ gcc/sched-rgn.c	(working copy)
@@ -305,24 +305,20 @@ is_cfg_nonregular (void)
   if (current_function_has_exception_handlers ())
     return 1;
 
-  /* If we have non-jumping insns which refer to labels, then we consider
-     the cfg not well structured.  */
+  /* If we have insns which refer to labels as non-jumped-to operands,
+     then we consider the cfg not well structured.  */
   FOR_EACH_BB (b)
     FOR_BB_INSNS (b, insn)
       {
-	/* Check for labels referred by non-jump insns.  */
-	if (NONJUMP_INSN_P (insn) || CALL_P (insn))
-	  {
-	    rtx note = find_reg_note (insn, REG_LABEL, NULL_RTX);
-	    if (note
-		&& ! (JUMP_P (NEXT_INSN (insn))
-		      && find_reg_note (NEXT_INSN (insn), REG_LABEL,
-					XEXP (note, 0))))
-	      return 1;
-	  }
+	/* Check for labels referred to but (at least not directly) as
+	   jump targets.  */
+	if (INSN_P (insn)
+	    && find_reg_note (insn, REG_LABEL_OPERAND, NULL_RTX))
+	  return 1;
+
 	/* If this function has a computed jump, then we consider the cfg
 	   not well structured.  */
-	else if (JUMP_P (insn) && computed_jump_p (insn))
+	if (JUMP_P (insn) && computed_jump_p (insn))
 	  return 1;
       }
 
Index: gcc/reg-notes.def
===================================================================
--- gcc/reg-notes.def	(revision 108225)
+++ gcc/reg-notes.def	(working copy)
@@ -92,10 +92,16 @@ REG_NOTE (UNUSED)
 REG_NOTE (CC_SETTER)
 REG_NOTE (CC_USER)
 
-/* Points to a CODE_LABEL.  Used by non-JUMP_INSNs to say that the
-   CODE_LABEL contained in the REG_LABEL note is used by the insn.
-   This note is an INSN_LIST.  */
-REG_NOTE (LABEL)
+/* Points to a CODE_LABEL.  Used by JUMP_INSNs to say that the CODE_LABEL
+   contained in the REG_LABEL_TARGET note is a possible jump target of
+   this insn.  This note is an INSN_LIST.  */
+REG_NOTE (LABEL_TARGET)
+
+/* Points to a CODE_LABEL.  Used by any insn to say that the CODE_LABEL
+   contained in the REG_LABEL_OPERAND note is used by the insn, but as an
+   operand, not as a jump target (though it may indirectly be a jump
+   target for a later jump insn).  This note is an INSN_LIST.  */
+REG_NOTE (LABEL_OPERAND)
 
 /* REG_DEP_ANTI and REG_DEP_OUTPUT are used in LOG_LINKS to represent
    write-after-read and write-after-write dependencies respectively.  */
Index: gcc/cfgrtl.c
===================================================================
--- gcc/cfgrtl.c	(revision 108225)
+++ gcc/cfgrtl.c	(working copy)
@@ -140,15 +140,15 @@ delete_insn (rtx insn)
 
   /* If deleting a jump, decrement the use count of the label.  Deleting
      the label itself should happen in the normal course of block merging.  */
-  if (JUMP_P (insn)
-      && JUMP_LABEL (insn)
-      && LABEL_P (JUMP_LABEL (insn)))
-    LABEL_NUSES (JUMP_LABEL (insn))--;
-
-  /* Also if deleting an insn that references a label.  */
-  else
+  if (JUMP_P (insn))
     {
-      while ((note = find_reg_note (insn, REG_LABEL, NULL_RTX)) != NULL_RTX
+      if (JUMP_LABEL (insn)
+	  && LABEL_P (JUMP_LABEL (insn)))
+	LABEL_NUSES (JUMP_LABEL (insn))--;
+
+      /* If there are more targets, remove them too.  */
+      while ((note
+	      = find_reg_note (insn, REG_LABEL_TARGET, NULL_RTX)) != NULL_RTX
 	     && LABEL_P (XEXP (note, 0)))
 	{
 	  LABEL_NUSES (XEXP (note, 0))--;
@@ -156,6 +156,14 @@ delete_insn (rtx insn)
 	}
     }
 
+  /* Also if deleting any insn that references a label as an operand.  */
+  while ((note = find_reg_note (insn, REG_LABEL_OPERAND, NULL_RTX)) != NULL_RTX
+	 && LABEL_P (XEXP (note, 0)))
+    {
+      LABEL_NUSES (XEXP (note, 0))--;
+      remove_note (insn, note);
+    }
+
   if (JUMP_P (insn)
       && (GET_CODE (PATTERN (insn)) == ADDR_VEC
 	  || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC))
Index: gcc/reload1.c
===================================================================
--- gcc/reload1.c	(revision 108225)
+++ gcc/reload1.c	(working copy)
@@ -1445,8 +1445,8 @@ calculate_needs_all_insns (int global)
       chain->need_operand_change = 0;
 
       /* If this is a label, a JUMP_INSN, or has REG_NOTES (which might
-	 include REG_LABEL), we need to see what effects this has on the
-	 known offsets at labels.  */
+	 include REG_LABEL_OPERAND and REG_LABEL_TARGET), we need to see
+	 what effects this has on the known offsets at labels.  */
 
       if (LABEL_P (insn) || JUMP_P (insn)
 	  || (INSN_P (insn) && REG_NOTES (insn) != 0))
@@ -2165,10 +2165,11 @@ set_label_offsets (rtx x, rtx insn, int 
 
     case INSN:
     case CALL_INSN:
-      /* Any labels mentioned in REG_LABEL notes can be branched to indirectly
-	 and hence must have all eliminations at their initial offsets.  */
+      /* Any labels mentioned in REG_LABEL_OPERAND notes can be branched
+	 to indirectly and hence must have all eliminations at their
+	 initial offsets.  */
       for (tem = REG_NOTES (x); tem; tem = XEXP (tem, 1))
-	if (REG_NOTE_KIND (tem) == REG_LABEL)
+	if (REG_NOTE_KIND (tem) == REG_LABEL_OPERAND)
 	  set_label_offsets (XEXP (tem, 0), insn, 1);
       return;
 
Index: gcc/config/alpha/alpha.md
===================================================================
--- gcc/config/alpha/alpha.md	(revision 108426)
+++ gcc/config/alpha/alpha.md	(working copy)
@@ -5323,9 +5323,9 @@ (define_split
 
 ;; Split the load of an address into a four-insn sequence on Unicos/Mk.
 ;; Always generate a REG_EQUAL note for the last instruction to facilitate
-;; optimizations. If the symbolic operand is a label_ref, generate REG_LABEL
-;; notes and update LABEL_NUSES because this is not done automatically.
-;; Labels may be incorrectly deleted if we don't do this.
+;; optimizations. If the symbolic operand is a label_ref, generate
+;; REG_LABEL_OPERAND notes and update LABEL_NUSES because this is not done
+;; automatically.  Labels may be incorrectly deleted if we don't do this.
 ;;
 ;; Describing what the individual instructions do correctly is too complicated
 ;; so use UNSPECs for each of the three parts of an address.
@@ -5349,11 +5349,11 @@ (define_split
       rtx label;
 
       label = XEXP (operands[1], 0);
-      REG_NOTES (insn1) = gen_rtx_EXPR_LIST (REG_LABEL, label,
+      REG_NOTES (insn1) = gen_rtx_EXPR_LIST (REG_LABEL_OPERAND, label,
 					     REG_NOTES (insn1));
-      REG_NOTES (insn2) = gen_rtx_EXPR_LIST (REG_LABEL, label,
+      REG_NOTES (insn2) = gen_rtx_EXPR_LIST (REG_LABEL_OPERAND, label,
 					     REG_NOTES (insn2));
-      REG_NOTES (insn3) = gen_rtx_EXPR_LIST (REG_LABEL, label,
+      REG_NOTES (insn3) = gen_rtx_EXPR_LIST (REG_LABEL_OPERAND, label,
 					     REG_NOTES (insn3));
       LABEL_NUSES (label) += 3;
     }
Index: gcc/config/sh/sh.c
===================================================================
--- gcc/config/sh/sh.c	(revision 108426)
+++ gcc/config/sh/sh.c	(working copy)
@@ -4309,8 +4309,8 @@ sh_reorg (void)
   mdep_reorg_phase = SH_INSERT_USES_LABELS;
   if (TARGET_RELAX)
     {
-      /* Remove all REG_LABEL notes.  We want to use them for our own
-	 purposes.  This works because none of the remaining passes
+      /* Remove all REG_LABEL_OPERAND notes.  We want to use them for our
+	 own purposes.  This works because none of the remaining passes
 	 need to look at them.
 
 	 ??? But it may break in the future.  We should use a machine
@@ -4321,7 +4321,8 @@ sh_reorg (void)
 	    {
 	      rtx note;
 
-	      while ((note = find_reg_note (insn, REG_LABEL, NULL_RTX)) != 0)
+	      while ((note = find_reg_note (insn, REG_LABEL_OPERAND,
+					    NULL_RTX)) != 0)
 		remove_note (insn, note);
 	    }
 	}
@@ -4496,16 +4497,16 @@ sh_reorg (void)
 	      continue;
 	    }
 
-	  /* Create a code label, and put it in a REG_LABEL note on
-             the insn which sets the register, and on each call insn
-             which uses the register.  In final_prescan_insn we look
-             for the REG_LABEL notes, and output the appropriate label
+	  /* Create a code label, and put it in a REG_LABEL_OPERAND note
+             on the insn which sets the register, and on each call insn
+             which uses the register.  In final_prescan_insn we look for
+             the REG_LABEL_OPERAND notes, and output the appropriate label
              or pseudo-op.  */
 
 	  label = gen_label_rtx ();
-	  REG_NOTES (link) = gen_rtx_INSN_LIST (REG_LABEL, label,
+	  REG_NOTES (link) = gen_rtx_INSN_LIST (REG_LABEL_OPERAND, label,
 						REG_NOTES (link));
-	  REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL, label,
+	  REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL_OPERAND, label,
 						REG_NOTES (insn));
 	  if (rescan)
 	    {
@@ -4521,7 +4522,8 @@ sh_reorg (void)
 			  || ((reg2 = sfunc_uses_reg (scan))
 			      && REGNO (reg2) == REGNO (reg))))
 		    REG_NOTES (scan)
-		      = gen_rtx_INSN_LIST (REG_LABEL, label, REG_NOTES (scan));
+		      = gen_rtx_INSN_LIST (REG_LABEL_OPERAND, label,
+					   REG_NOTES (scan));
 		}
 	      while (scan != dies);
 	    }
@@ -5016,7 +5018,7 @@ final_prescan_insn (rtx insn, rtx *opvec
     {
       rtx note;
 
-      note = find_reg_note (insn, REG_LABEL, NULL_RTX);
+      note = find_reg_note (insn, REG_LABEL_OPERAND, NULL_RTX);
       if (note)
 	{
 	  rtx pattern;
Index: doc/rtl.texi
===================================================================
--- doc/rtl.texi	(revision 110246)
+++ doc/rtl.texi	(working copy)
@@ -2961,9 +2961,10 @@ mandatory ones listed above.  These four
 @findex jump_insn
 @item jump_insn
 The expression code @code{jump_insn} is used for instructions that may
-jump (or, more generally, may contain @code{label_ref} expressions).  If
-there is an instruction to return from the current function, it is
-recorded as a @code{jump_insn}.
+jump (or, more generally, may contain @code{label_ref} expressions to
+which @code{pc} can be set in that instruction).  If there is an
+instruction to return from the current function, it is recorded as a
+@code{jump_insn}.
 
 @findex JUMP_LABEL
 @code{jump_insn} insns have the same extra fields as @code{insn} insns,
@@ -2973,9 +2974,11 @@ accessed in the same way and in addition
 For simple conditional and unconditional jumps, this field contains
 the @code{code_label} to which this insn will (possibly conditionally)
 branch.  In a more complex jump, @code{JUMP_LABEL} records one of the
-labels that the insn refers to; the only way to find the others is to
-scan the entire body of the insn.  In an @code{addr_vec},
-@code{JUMP_LABEL} is @code{NULL_RTX}.
+labels that the insn refers to; other jump target labels are recorded
+as @code{REG_LABEL_TARGET} notes.  The exception is @code{addr_vec}
+and @code{addr_diff_vec}, where @code{JUMP_LABEL} is @code{NULL_RTX}
+and the only way to find the labels is to scan the entire body of the
+insn.
 
 Return insns count as jumps, but since they do not refer to any
 labels, their @code{JUMP_LABEL} is @code{NULL_RTX}.
@@ -3302,14 +3305,25 @@ note giving the expression being compute
 with @code{REG_LIBCALL} and @code{REG_RETVAL} notes on the first and
 last insns, respectively.
 
-@findex REG_LABEL
-@item REG_LABEL
+@findex REG_LABEL_OPERAND
+@item REG_LABEL_OPERAND
 This insn uses @var{op}, a @code{code_label} or a @code{note} of type
-@code{NOTE_INSN_DELETED_LABEL}, but is not a
-@code{jump_insn}, or it is a @code{jump_insn} that required the label to
-be held in a register.  The presence of this note allows jump
-optimization to be aware that @var{op} is, in fact, being used, and flow
-optimization to build an accurate flow graph.
+@code{NOTE_INSN_DELETED_LABEL}, but is not a @code{jump_insn}, or it
+is a @code{jump_insn} that refers to the operand as an ordinary
+operand.  The label may still eventually be a jump target, but if so
+in an indirect jump in a subsequent insn.  The presence of this note
+allows jump optimization to be aware that @var{op} is, in fact, being
+used, and flow optimization to build an accurate flow graph.
+
+@findex REG_LABEL_TARGET
+@item REG_LABEL_TARGET
+This insn is a @code{jump_insn} but not a @code{addr_vec} or
+@code{addr_diff_vec}.  It uses @var{op}, a @code{code_label} as a
+direct or indirect jump target.  Its purpose is similar to that of
+@code{REG_LABEL_OPERAND}.  This note is only present if the insn has
+multiple targets; the last label in the insn (in the highest numbered
+insn-field) goes into the @code{JUMP_LABEL} field and does not have a
+@code{REG_LABEL_TARGET} note.  @xref{Insns, JUMP_LABEL}.
 
 @findex REG_CROSSING_JUMP
 @item REG_CROSSING_JUMP

brgds, H-P

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFA:] Split REG_LABEL into REG_LABEL_TARGET and REG_LABEL_OPERAND
  2006-01-30 20:54 [RFA:] Split REG_LABEL into REG_LABEL_TARGET and REG_LABEL_OPERAND Hans-Peter Nilsson
@ 2006-01-30 21:31 ` Hans-Peter Nilsson
  2006-01-30 22:18 ` Hans-Peter Nilsson
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 13+ messages in thread
From: Hans-Peter Nilsson @ 2006-01-30 21:31 UTC (permalink / raw)
  To: gcc-patches

> Date: Mon, 30 Jan 2006 21:31:10 +0100
> From: Hans-Peter Nilsson <hp@axis.com>

> This patch has been bootstrapped and regression-tested on
> i686-pc-linux-gnu (FC2) and regression-tested cross to cris-axis-elf,
> cris-axis-linux-gnu, mmix-knuth-mmixware, sh-elf, sh64-elf and mips-elf.
> The documentation changes have been "make info dvi" and those parts of
> gccint.dvi visually inspected.

I forgot to mention that I also built cc1 for an alpha target
(which one, I've since forgot) with the earlier version, to
sanity-check the (purely textual) alpha.md changes.

brgds, H-P

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFA:] Split REG_LABEL into REG_LABEL_TARGET and REG_LABEL_OPERAND
  2006-01-30 20:54 [RFA:] Split REG_LABEL into REG_LABEL_TARGET and REG_LABEL_OPERAND Hans-Peter Nilsson
  2006-01-30 21:31 ` Hans-Peter Nilsson
@ 2006-01-30 22:18 ` Hans-Peter Nilsson
  2006-02-25  0:05 ` Geoffrey Keating
  2007-09-04  5:12 ` [RFA:] " Hans-Peter Nilsson
  3 siblings, 0 replies; 13+ messages in thread
From: Hans-Peter Nilsson @ 2006-01-30 22:18 UTC (permalink / raw)
  To: gcc-patches

> Date: Mon, 30 Jan 2006 21:31:10 +0100
> From: Hans-Peter Nilsson <hp@axis.com>

> An earlier version with equivalent function but with the code in
> propagate_block_delete_insn arranged a little differently (the if-body
> split out into a helper function because I initially thought I'd need to
> refer to it twice and then forgot to change it back) and with an extra
> assert for absence of REG_LABEL_OPERAND notes on insns where a case-table
> was deleted (instead of just ignoring them), was also bootstrapped on
> x86_64-unknown-linux-gnu (FC4) and powerpc-unknown-linux-gnu (FC4).

... and *that* was the one I actually sent - only the ChangeLog
was updated.  Gah!  :-(  Here's the updated flow.c part; the
other patch parts are the same.

Index: flow.c
===================================================================
--- flow.c	(revision 110246)
+++ flow.c	(working copy)
@@ -1600,7 +1600,7 @@ allocate_reg_life_data (void)
 static void
 propagate_block_delete_insn (rtx insn)
 {
-  rtx inote = find_reg_note (insn, REG_LABEL, NULL_RTX);
+  rtx inote = find_reg_note (insn, REG_LABEL_TARGET, NULL_RTX);
 
   /* If the insn referred to a label, and that label was attached to
      an ADDR_VEC, it's safe to delete the ADDR_VEC.  In fact, it's
@@ -1639,6 +1639,9 @@ propagate_block_delete_insn (rtx insn)
 	}
     }
 
+  /* ADDR_VECs must be referred to as targets, not operands, so we
+     don't check REG_LABEL_OPERAND notes.  */
+
   delete_insn_and_edges (insn);
   ndead++;
 }


brgds, H-P

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re:[RFA:] Split REG_LABEL into REG_LABEL_TARGET and REG_LABEL_OPERAND
  2006-01-30 20:54 [RFA:] Split REG_LABEL into REG_LABEL_TARGET and REG_LABEL_OPERAND Hans-Peter Nilsson
  2006-01-30 21:31 ` Hans-Peter Nilsson
  2006-01-30 22:18 ` Hans-Peter Nilsson
@ 2006-02-25  0:05 ` Geoffrey Keating
  2007-09-04  5:12 ` [RFA:] " Hans-Peter Nilsson
  3 siblings, 0 replies; 13+ messages in thread
From: Geoffrey Keating @ 2006-02-25  0:05 UTC (permalink / raw)
  To: Hans-Peter Nilsson; +Cc: gcc-patches@gcc.gnu.org Patches

[-- Attachment #1: Type: text/plain, Size: 4268 bytes --]

> Divide REG_LABEL notes into REG_LABEL_OPERAND and REG_LABEL_TARGET.
> * reload.c (find_reloads): Generate REG_LABEL_OPERAND, not
> REG_LABEL when replacing an operand with a LABEL_REF for a
> non-jump insn.
> (subst_reloads): When replacing a LABEL_REG with a register,
> instead of generating a REG_LABEL note, assert that there already
> is one or that the label is a known target for the insn.
> * loop.c (add_label_notes): Generate REG_LABEL_OPERAND notes.
> Adjust head comment accordingly.
> (find_and_verify_loops): Test for REG_LABEL_OPERAND notes instead
> of testing insn type and REG_LABEL presence.
> * rtlanal.c (computed_jump_p): Instead of looking for a REG_LABEL
> note, check the JUMP_LABEL field.  Remove "else" after return.
> * reorg.c (emit_delay_sequence): Replace case for REG_LABEL with
> cases for REG_LABEL_OPERAND and REG_LABEL_TARGET.
> (fill_slots_from_thread): Handle both REG_LABEL_OPERAND and
> REG_LABEL_TARGET notes, including the JUMP_TARGET field on JUMP_P
> insns.  Iterate over all notes; don't assume there's only one.
> * flow.c (propagate_block_delete_insn): Check for a
> REG_LABEL_TARGET note referring to a case-table; ignore
> REG_LABEL_OPERAND notes.
> * cse.c (recorded_label_ref): Adjust comment to refer to
> REG_LABEL_OPERAND.
> (cse_basic_block): Do LABEL_REF check for all INSN_P insns, not
> just NONJUMP_INSN_P.
> (check_for_label_ref): For JUMP_P insns, check that the LABEL_REF
> isn't a jump target.
> (rebuild_jump_labels): Adjust head comment.
> (init_label_info): Ditto.  Remove REG_LABEL_OPERAND notes only;
> don't reset REG_LABEL_TARGET notes, including the JUMP_LABEL field.
> (mark_all_labels): For JUMP_P insns without a target, check if the
> the target is noted on the previous nonjump insn.
> (mark_jump_label_1): New function, guts from mark_jump_label.
> <case IF_THEN_ELSE>: Handle first operand as a non-target when
> marking jump target labels.
> <case LABEL_REF>: Adjust for whether to generate a
> REG_LABEL_TARGET or a REG_LABEL_OPERAND note.
> For 'E' format rtl, iterate in descending element order.
> (delete_related_insns): Handle both REG_LABEL_TARGET and
> REG_LABEL_OPERAND notes.  For JUMP_P insns with labels with zero
> reference count, delete and fallthrough.  Move finding-next-
> non-deleted insn last in the function.  Look at all INSN_P insns
> for REG_LABEL_OPERAND notes.
> (redirect_jump_2): Assert that OLABEL equals the old JUMP_LABEL of
> JUMP.
> * print-rtl.c (print_rtx): For JUMP_P insns and a non-NULL
> JUMP_LABEL, output the INSN_UID of it.
> * gcse.c: Adjust comments as appropriate to say REG_LABEL_OPERAND
> and/or REG_LABEL_TARGET.
> (add_label_notes): Only add REG_LABEL_OPERAND notes.  Put in line
> with jump.c copy by only adding notes for labels actually
> referenced in the insn.
> * emit-rtl.c (try_split): Don't assume only NONJUMP_INSN_P need
> usage count increment; handle all INSN_P trial insns.
> (emit_copy_of_insn_after): Change to not copy REG_LABEL_OPERAND
> notes.
> * rtl.h (struct rtx_def) <volatil>: Adjust to mention
> REG_LABEL_TARGET and REG_LABEL_OPERAND.
> (LABEL_REF_NONLOCAL_P): Allow REG_LABEL_TARGET and
> REG_LABEL_OPERAND.
> * combine.c (distribute_notes): Adjust for REG_LABEL_TARGET on
> JUMP_P insns and REG_LABEL_OPERAND everywhere.
> * sched-rgn.c (is_cfg_nonregular): Check for REG_LABEL_OPERANDS
> on all INSN_P insns.
> * reg-notes.def (LABEL_TARGET, LABEL_OPERAND): Split from LABEL.
> * cfgrtl.c (delete_insn): Adjust to handle REG_LABEL_TARGET and
> REG_LABEL_OPERAND notes.
> * reload1.c (calculate_needs_all_insns): Adjust comments.
> (set_label_offsets): Adjust to look for REG_LABEL_OPERAND notes.
> * config/alpha/alpha.md (split for load of an address into a
> four-insn sequence on Unicos/Mk): Adjust to use
> REG_LABEL_OPERAND.
> * config/sh/sh.md (sh_reorg, final_prescan_insn): Ditto.
> * doc/rtl.texi (Insns): Specify when a label_ref makes a jump_insn.
> Similar for what label_refs can go in the JUMP_TARGET field.  Split
> REG_LABEL documentation into REG_LABEL_TARGET and REG_LABEL_OPERAND.

This patch is OK.

I think the code changes you saw were because of the way this patch  
prefers to use JUMP_TARGET rather than adding a REG_LABEL_TARGET  
note.  That's probably a good thing.

:REVIEWMAIL:


[-- Attachment #2: smime.p7s --]
[-- Type: application/pkcs7-signature, Size: 2408 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFA:] Split REG_LABEL into REG_LABEL_TARGET and REG_LABEL_OPERAND
  2006-01-30 20:54 [RFA:] Split REG_LABEL into REG_LABEL_TARGET and REG_LABEL_OPERAND Hans-Peter Nilsson
                   ` (2 preceding siblings ...)
  2006-02-25  0:05 ` Geoffrey Keating
@ 2007-09-04  5:12 ` Hans-Peter Nilsson
  2007-09-09  7:13   ` Hans-Peter Nilsson
  3 siblings, 1 reply; 13+ messages in thread
From: Hans-Peter Nilsson @ 2007-09-04  5:12 UTC (permalink / raw)
  To: gcc-patches

> Date: Mon, 30 Jan 2006 21:31:10 +0100
> From: Hans-Peter Nilsson <hp@axis.com>

> So, here's the patch to split REG_LABEL into REG_LABEL_TARGET and
> REG_LABEL_OPERAND.  See <URL:http://gcc.gnu.org/ml/gcc/2005-12/msg00279.html>
> for why this is necessary.

I intend to update the patch at
<http://gcc.gnu.org/ml/gcc-patches/2006-01/msg02142.html> and
commit it ASAP after testing.  It was approved by Geoff at
<http://gcc.gnu.org/ml/gcc-patches/2006-02/msg01884.html> and
(IIRC) Ian approved the idea on IRC earlier, so I don't perceive
any controversy with its contents, but if there is, don't be
afraid to speak up now. ;-)  Sorry for the delay.

brgds, H-P

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFA:] Split REG_LABEL into REG_LABEL_TARGET and REG_LABEL_OPERAND
  2007-09-04  5:12 ` [RFA:] " Hans-Peter Nilsson
@ 2007-09-09  7:13   ` Hans-Peter Nilsson
  2007-09-09 10:47     ` Eric Botcazou
  0 siblings, 1 reply; 13+ messages in thread
From: Hans-Peter Nilsson @ 2007-09-09  7:13 UTC (permalink / raw)
  To: gcc-patches

> Date: Tue, 4 Sep 2007 07:12:00 +0200
> From: Hans-Peter Nilsson <hp@axis.com>

> I intend to update the patch at
> <http://gcc.gnu.org/ml/gcc-patches/2006-01/msg02142.html> and
> commit it ASAP after testing.

Committed as 128287.  Regtested the updated patch (128059,
before recent regressions) native for x86_64-unknown-linux-gnu
(no ada, no multilib), cross with no regressions to
 cris-elf (again rebuilt as a sanity-check with 128285)
 mmix-knuth-mmixware
 sh64-elf
 arm-elf
 v850-elf
 sh-elf
 mips-elf
 mips64-elf
(had to disable some languages but with at least C and C++ for all)
also built all-gcc (cc1) for alpha-unknown-linux-gnu and
finally, "make dvi-gcc" and info-gcc.

gcc:
	Divide REG_LABEL notes into REG_LABEL_OPERAND and REG_LABEL_TARGET.
	* doc/rtl.texi (Insns): Specify when a label_ref makes a jump_insn.
	Similar for what label_refs can go in the JUMP_TARGET field.  Split
	REG_LABEL documentation into REG_LABEL_TARGET and REG_LABEL_OPERAND.
	* reload.c (find_reloads): Generate REG_LABEL_OPERAND, not
	REG_LABEL when replacing an operand with a LABEL_REF for a
	non-jump insn.
	(subst_reloads): When replacing a LABEL_REG with a register,
	instead of generating a REG_LABEL note, assert that there already
	is one or that the label is a known target for the insn.
	* rtlanal.c (computed_jump_p): Instead of looking for a REG_LABEL
	note, check the JUMP_LABEL field.  Remove "else" after return.
	* reorg.c (emit_delay_sequence): Replace case for REG_LABEL with
	cases for REG_LABEL_OPERAND and REG_LABEL_TARGET.
	(fill_slots_from_thread): Handle both REG_LABEL_OPERAND and
	REG_LABEL_TARGET notes, including the JUMP_TARGET field on JUMP_P
	insns.  Iterate over all notes; don't assume there's only one.
	* cse.c (recorded_label_ref): Adjust comment to refer to
	REG_LABEL_OPERAND.
	(cse_extended_basic_block): Do LABEL_REF check for all INSN_P
	insns, not just NONJUMP_INSN_P.
	(check_for_label_ref): For JUMP_P insns, check that the LABEL_REF
	isn't a jump target.
	* jump.c (rebuild_jump_labels): Adjust head comment.
	(init_label_info): Ditto.  Remove REG_LABEL_OPERAND notes only;
	don't reset REG_LABEL_TARGET notes, including the JUMP_LABEL field.
	(mark_all_labels): For JUMP_P insns without a target, check if the
	the target is noted on the previous nonjump insn.
	(mark_jump_label_1): New function, guts from mark_jump_label.
	<case IF_THEN_ELSE>: Handle first operand as a non-target when
	marking jump target labels.
	<case LABEL_REF>: Adjust for whether to generate a
	REG_LABEL_TARGET or a REG_LABEL_OPERAND note.
	For 'E' format rtl, iterate in descending element order.
	(delete_related_insns): Handle both REG_LABEL_TARGET and
	REG_LABEL_OPERAND notes.  For JUMP_P insns with labels with zero
	reference count, delete and fallthrough.  Move finding-next-
	non-deleted insn last in the function.  Look at all INSN_P insns
	for REG_LABEL_OPERAND notes.
	(redirect_jump_2): Assert that OLABEL equals the old JUMP_LABEL of
	JUMP.
	* print-rtl.c (print_rtx): For JUMP_P insns and a non-NULL
	JUMP_LABEL, output the INSN_UID of it.
	* gcse.c: Adjust comments as appropriate to say REG_LABEL_OPERAND
	and/or REG_LABEL_TARGET.
	(add_label_notes): Only add REG_LABEL_OPERAND notes.  Put in line
	with jump.c copy by only adding notes for labels actually
	referenced in the insn.
	* emit-rtl.c (try_split): Don't assume only NONJUMP_INSN_P need
	usage count increment; handle all INSN_P trial insns.
	(emit_copy_of_insn_after): Change to not copy REG_LABEL_OPERAND
	notes.
	* rtl.h (struct rtx_def) <volatil>: Adjust to mention
	REG_LABEL_TARGET and REG_LABEL_OPERAND.
	(LABEL_REF_NONLOCAL_P): Allow REG_LABEL_TARGET and
	REG_LABEL_OPERAND.
	* combine.c (distribute_notes): Adjust for REG_LABEL_TARGET on
	JUMP_P insns and REG_LABEL_OPERAND everywhere.
	* sched-rgn.c (is_cfg_nonregular): Check for REG_LABEL_OPERANDS
	on all INSN_P insns.
	* reg-notes.def (LABEL_TARGET, LABEL_OPERAND): Split from LABEL.
	* cfgrtl.c (delete_insn): Adjust to handle REG_LABEL_TARGET and
	REG_LABEL_OPERAND notes.
	* reload1.c (calculate_needs_all_insns): Adjust comments.
	(set_label_offsets): Adjust to look for REG_LABEL_OPERAND notes.
	* config/alpha/alpha.md (split for load of an address into a
	four-insn sequence on Unicos/Mk): Adjust to use
	REG_LABEL_OPERAND.
	* config/sh/sh.md (sh_reorg, final_prescan_insn): Ditto.

Index: gcc/doc/rtl.texi
===================================================================
--- gcc/doc/rtl.texi	(revision 128285)
+++ gcc/doc/rtl.texi	(working copy)
@@ -3201,9 +3201,10 @@ mandatory ones listed above.  These four
 @findex jump_insn
 @item jump_insn
 The expression code @code{jump_insn} is used for instructions that may
-jump (or, more generally, may contain @code{label_ref} expressions).  If
-there is an instruction to return from the current function, it is
-recorded as a @code{jump_insn}.
+jump (or, more generally, may contain @code{label_ref} expressions to
+which @code{pc} can be set in that instruction).  If there is an
+instruction to return from the current function, it is recorded as a
+@code{jump_insn}.
 
 @findex JUMP_LABEL
 @code{jump_insn} insns have the same extra fields as @code{insn} insns,
@@ -3213,9 +3214,11 @@ accessed in the same way and in addition
 For simple conditional and unconditional jumps, this field contains
 the @code{code_label} to which this insn will (possibly conditionally)
 branch.  In a more complex jump, @code{JUMP_LABEL} records one of the
-labels that the insn refers to; the only way to find the others is to
-scan the entire body of the insn.  In an @code{addr_vec},
-@code{JUMP_LABEL} is @code{NULL_RTX}.
+labels that the insn refers to; other jump target labels are recorded
+as @code{REG_LABEL_TARGET} notes.  The exception is @code{addr_vec}
+and @code{addr_diff_vec}, where @code{JUMP_LABEL} is @code{NULL_RTX}
+and the only way to find the labels is to scan the entire body of the
+insn.
 
 Return insns count as jumps, but since they do not refer to any
 labels, their @code{JUMP_LABEL} is @code{NULL_RTX}.
@@ -3531,14 +3534,25 @@ note giving the expression being compute
 with @code{REG_LIBCALL} and @code{REG_RETVAL} notes on the first and
 last insns, respectively.
 
-@findex REG_LABEL
-@item REG_LABEL
+@findex REG_LABEL_OPERAND
+@item REG_LABEL_OPERAND
 This insn uses @var{op}, a @code{code_label} or a @code{note} of type
-@code{NOTE_INSN_DELETED_LABEL}, but is not a
-@code{jump_insn}, or it is a @code{jump_insn} that required the label to
-be held in a register.  The presence of this note allows jump
-optimization to be aware that @var{op} is, in fact, being used, and flow
-optimization to build an accurate flow graph.
+@code{NOTE_INSN_DELETED_LABEL}, but is not a @code{jump_insn}, or it
+is a @code{jump_insn} that refers to the operand as an ordinary
+operand.  The label may still eventually be a jump target, but if so
+in an indirect jump in a subsequent insn.  The presence of this note
+allows jump optimization to be aware that @var{op} is, in fact, being
+used, and flow optimization to build an accurate flow graph.
+
+@findex REG_LABEL_TARGET
+@item REG_LABEL_TARGET
+This insn is a @code{jump_insn} but not a @code{addr_vec} or
+@code{addr_diff_vec}.  It uses @var{op}, a @code{code_label} as a
+direct or indirect jump target.  Its purpose is similar to that of
+@code{REG_LABEL_OPERAND}.  This note is only present if the insn has
+multiple targets; the last label in the insn (in the highest numbered
+insn-field) goes into the @code{JUMP_LABEL} field and does not have a
+@code{REG_LABEL_TARGET} note.  @xref{Insns, JUMP_LABEL}.
 
 @findex REG_CROSSING_JUMP
 @item REG_CROSSING_JUMP
Index: gcc/reload.c
===================================================================
--- gcc/reload.c	(revision 128285)
+++ gcc/reload.c	(working copy)
@@ -4103,13 +4103,18 @@ find_reloads (rtx insn, int replace, int
 
 	  *recog_data.operand_loc[i] = substitution;
 
-	  /* If we're replacing an operand with a LABEL_REF, we need
-	     to make sure that there's a REG_LABEL note attached to
+	  /* If we're replacing an operand with a LABEL_REF, we need to
+	     make sure that there's a REG_LABEL_OPERAND note attached to
 	     this instruction.  */
-	  if (!JUMP_P (insn)
-	      && GET_CODE (substitution) == LABEL_REF
-	      && !find_reg_note (insn, REG_LABEL, XEXP (substitution, 0)))
-	    REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL,
+	  if (GET_CODE (substitution) == LABEL_REF
+	      && !find_reg_note (insn, REG_LABEL_OPERAND,
+				 XEXP (substitution, 0))
+	      /* For a JUMP_P, if it was a branch target it must have
+		 already been recorded as such.  */
+	      && (!JUMP_P (insn)
+		  || !label_is_jump_target_p (XEXP (substitution, 0),
+					      insn)))
+	    REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL_OPERAND,
 						  XEXP (substitution, 0),
 						  REG_NOTES (insn));
 	}
@@ -6123,17 +6128,15 @@ subst_reloads (rtx insn)
 	    }
 #endif /* DEBUG_RELOAD */
 
-	  /* If we're replacing a LABEL_REF with a register, add a
-	     REG_LABEL note to indicate to flow which label this
+	  /* If we're replacing a LABEL_REF with a register, there must
+	     already be an indication (to e.g. flow) which label this
 	     register refers to.  */
-	  if (GET_CODE (*r->where) == LABEL_REF
-	      && JUMP_P (insn))
-	    {
-	      REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL,
-						    XEXP (*r->where, 0),
-						    REG_NOTES (insn));
-	      JUMP_LABEL (insn) = XEXP (*r->where, 0);
-	   }
+	  gcc_assert (GET_CODE (*r->where) != LABEL_REF
+		      || !JUMP_P (insn)
+		      || find_reg_note (insn,
+					REG_LABEL_OPERAND,
+					XEXP (*r->where, 0))
+		      || label_is_jump_target_p (XEXP (*r->where, 0), insn));
 
 	  /* Encapsulate RELOADREG so its machine mode matches what
 	     used to be there.  Note that gen_lowpart_common will
Index: gcc/rtlanal.c
===================================================================
--- gcc/rtlanal.c	(revision 128285)
+++ gcc/rtlanal.c	(working copy)
@@ -2703,9 +2703,11 @@ computed_jump_p (const_rtx insn)
     {
       rtx pat = PATTERN (insn);
 
-      if (find_reg_note (insn, REG_LABEL, NULL_RTX))
+      /* If we have a JUMP_LABEL set, we're not a computed jump.  */
+      if (JUMP_LABEL (insn) != NULL)
 	return 0;
-      else if (GET_CODE (pat) == PARALLEL)
+
+      if (GET_CODE (pat) == PARALLEL)
 	{
 	  int len = XVECLEN (pat, 0);
 	  int has_use_labelref = 0;
Index: gcc/reorg.c
===================================================================
--- gcc/reorg.c	(revision 128285)
+++ gcc/reorg.c	(working copy)
@@ -541,7 +541,8 @@ emit_delay_sequence (rtx insn, rtx list,
 	      remove_note (tem, note);
 	      break;
 
-	    case REG_LABEL:
+	    case REG_LABEL_OPERAND:
+	    case REG_LABEL_TARGET:
 	      /* Keep the label reference count up to date.  */
 	      if (LABEL_P (XEXP (note, 0)))
 		LABEL_NUSES (XEXP (note, 0)) ++;
@@ -2736,14 +2737,40 @@ fill_slots_from_thread (rtx insn, rtx co
 		      /* We are moving this insn, not deleting it.  We must
 			 temporarily increment the use count on any referenced
 			 label lest it be deleted by delete_related_insns.  */
-		      note = find_reg_note (trial, REG_LABEL, 0);
-		      /* REG_LABEL could be NOTE_INSN_DELETED_LABEL too.  */
-		      if (note && LABEL_P (XEXP (note, 0)))
+		      for (note = REG_NOTES (trial);
+			   note != NULL;
+			   note = XEXP (note, 1))
+			if (REG_NOTE_KIND (note) == REG_LABEL_OPERAND
+			    || REG_NOTE_KIND (note) == REG_LABEL_TARGET)
+			  {
+			    /* REG_LABEL_OPERAND could be
+			       NOTE_INSN_DELETED_LABEL too.  */
+			    if (LABEL_P (XEXP (note, 0)))
+			      LABEL_NUSES (XEXP (note, 0))++;
+			    else
+			      gcc_assert (REG_NOTE_KIND (note)
+					  == REG_LABEL_OPERAND);
+			  }
+		      if (JUMP_P (trial) && JUMP_LABEL (trial))
 			LABEL_NUSES (XEXP (note, 0))++;
 
 		      delete_related_insns (trial);
 
-		      if (note && LABEL_P (XEXP (note, 0)))
+		      for (note = REG_NOTES (trial);
+			   note != NULL;
+			   note = XEXP (note, 1))
+			if (REG_NOTE_KIND (note) == REG_LABEL_OPERAND
+			    || REG_NOTE_KIND (note) == REG_LABEL_TARGET)
+			  {
+			    /* REG_LABEL_OPERAND could be
+			       NOTE_INSN_DELETED_LABEL too.  */
+			    if (LABEL_P (XEXP (note, 0)))
+			      LABEL_NUSES (XEXP (note, 0))--;
+			    else
+			      gcc_assert (REG_NOTE_KIND (note)
+					  == REG_LABEL_OPERAND);
+			  }
+		      if (JUMP_P (trial) && JUMP_LABEL (trial))
 			LABEL_NUSES (XEXP (note, 0))--;
 		    }
 		  else
Index: gcc/cse.c
===================================================================
--- gcc/cse.c	(revision 128285)
+++ gcc/cse.c	(working copy)
@@ -353,8 +353,9 @@ static HARD_REG_SET hard_regs_in_table;
 
 static int cse_jumps_altered;
 
-/* Nonzero if we put a LABEL_REF into the hash table for an INSN without a
-   REG_LABEL, we have to rerun jump after CSE to put in the note.  */
+/* Nonzero if we put a LABEL_REF into the hash table for an INSN
+   without a REG_LABEL_OPERAND, we have to rerun jump after CSE to put
+   in the note.  */
 static int recorded_label_ref;
 
 /* canon_hash stores 1 in do_not_record
@@ -6091,7 +6092,7 @@ cse_extended_basic_block (struct cse_bas
 	    
 	      /* If we haven't already found an insn where we added a LABEL_REF,
 		 check this one.  */
-	      if (NONJUMP_INSN_P (insn) && ! recorded_label_ref
+	      if (INSN_P (insn) && ! recorded_label_ref
 		  && for_each_rtx (&PATTERN (insn), check_for_label_ref,
 				   (void *) insn))
 		recorded_label_ref = 1;
@@ -6277,23 +6278,26 @@ cse_main (rtx f ATTRIBUTE_UNUSED, int nr
   return cse_jumps_altered || recorded_label_ref;
 }
 \f
-/* Called via for_each_rtx to see if an insn is using a LABEL_REF for which
-   there isn't a REG_LABEL note.  Return one if so.  DATA is the insn.  */
+/* Called via for_each_rtx to see if an insn is using a LABEL_REF for
+   which there isn't a REG_LABEL_OPERAND note.
+   Return one if so.  DATA is the insn.  */
 
 static int
 check_for_label_ref (rtx *rtl, void *data)
 {
   rtx insn = (rtx) data;
 
-  /* If this insn uses a LABEL_REF and there isn't a REG_LABEL note for it,
-     we must rerun jump since it needs to place the note.  If this is a
-     LABEL_REF for a CODE_LABEL that isn't in the insn chain, don't do this
-     since no REG_LABEL will be added.  */
+  /* If this insn uses a LABEL_REF and there isn't a REG_LABEL_OPERAND
+     note for it, we must rerun jump since it needs to place the note.  If
+     this is a LABEL_REF for a CODE_LABEL that isn't in the insn chain,
+     don't do this since no REG_LABEL_OPERAND will be added.  */
   return (GET_CODE (*rtl) == LABEL_REF
 	  && ! LABEL_REF_NONLOCAL_P (*rtl)
+	  && (!JUMP_P (insn)
+	      || !label_is_jump_target_p (XEXP (*rtl, 0), insn))
 	  && LABEL_P (XEXP (*rtl, 0))
 	  && INSN_UID (XEXP (*rtl, 0)) != 0
-	  && ! find_reg_note (insn, REG_LABEL, XEXP (*rtl, 0)));
+	  && ! find_reg_note (insn, REG_LABEL_OPERAND, XEXP (*rtl, 0)));
 }
 \f
 /* Count the number of times registers are used (not set) in X.
Index: gcc/jump.c
===================================================================
--- gcc/jump.c	(revision 128285)
+++ gcc/jump.c	(working copy)
@@ -67,13 +67,15 @@ along with GCC; see the file COPYING3.  
 
 static void init_label_info (rtx);
 static void mark_all_labels (rtx);
+static void mark_jump_label_1 (rtx, rtx, bool, bool);
 static void redirect_exp_1 (rtx *, rtx, rtx, rtx);
 static int invert_exp_1 (rtx, rtx);
 static int returnjump_p_1 (rtx *, void *);
 \f
-/* Alternate entry into the jump optimizer.  This entry point only rebuilds
-   the JUMP_LABEL field in jumping insns and REG_LABEL notes in non-jumping
-   instructions.  */
+/* This function rebuilds the JUMP_LABEL field and REG_LABEL_TARGET
+   notes in jumping insns and REG_LABEL_OPERAND notes in non-jumping
+   instructions and jumping insns that have labels as operands
+   (e.g. cbranchsi4).  */
 void
 rebuild_jump_labels (rtx f)
 {
@@ -138,31 +140,43 @@ struct tree_opt_pass pass_cleanup_barrie
 };
 
 \f
-/* Initialize LABEL_NUSES and JUMP_LABEL fields.  Delete any REG_LABEL
-   notes whose labels don't occur in the insn any more.  Returns the
-   largest INSN_UID found.  */
+/* Initialize LABEL_NUSES and JUMP_LABEL fields, add REG_LABEL_TARGET
+   for remaining targets for JUMP_P.  Delete any REG_LABEL_OPERAND
+   notes whose labels don't occur in the insn any more.  */
+
 static void
 init_label_info (rtx f)
 {
   rtx insn;
 
   for (insn = f; insn; insn = NEXT_INSN (insn))
-    if (LABEL_P (insn))
-      LABEL_NUSES (insn) = (LABEL_PRESERVE_P (insn) != 0);
-    else if (JUMP_P (insn))
-      JUMP_LABEL (insn) = 0;
-    else if (NONJUMP_INSN_P (insn) || CALL_P (insn))
-      {
-	rtx note, next;
+    {
+      if (LABEL_P (insn))
+	LABEL_NUSES (insn) = (LABEL_PRESERVE_P (insn) != 0);
 
-	for (note = REG_NOTES (insn); note; note = next)
-	  {
-	    next = XEXP (note, 1);
-	    if (REG_NOTE_KIND (note) == REG_LABEL
-		&& ! reg_mentioned_p (XEXP (note, 0), PATTERN (insn)))
-	      remove_note (insn, note);
-	  }
-      }
+      /* REG_LABEL_TARGET notes (including the JUMP_LABEL field) are
+	 sticky and not reset here; that way we won't lose association
+	 with a label when e.g. the source for a target register
+	 disappears out of reach for targets that may use jump-target
+	 registers.  Jump transformations are supposed to transform
+	 any REG_LABEL_TARGET notes.  The target label reference in a
+	 branch may disappear from the branch (and from the
+	 instruction before it) for other reasons, like register
+	 allocation.  */
+
+      if (INSN_P (insn))
+	{
+	  rtx note, next;
+
+	  for (note = REG_NOTES (insn); note; note = next)
+	    {
+	      next = XEXP (note, 1);
+	      if (REG_NOTE_KIND (note) == REG_LABEL_OPERAND
+		  && ! reg_mentioned_p (XEXP (note, 0), PATTERN (insn)))
+		remove_note (insn, note);
+	    }
+	}
+    }
 }
 
 /* Mark the label each jump jumps to.
@@ -172,34 +186,69 @@ static void
 mark_all_labels (rtx f)
 {
   rtx insn;
+  rtx prev_nonjump_insn = NULL;
 
   for (insn = f; insn; insn = NEXT_INSN (insn))
     if (INSN_P (insn))
       {
 	mark_jump_label (PATTERN (insn), insn, 0);
-	if (! INSN_DELETED_P (insn) && JUMP_P (insn))
+
+	/* If the previous non-jump insn sets something to a label,
+	   something that this jump insn uses, make that label the primary
+	   target of this insn if we don't yet have any.  That previous
+	   insn must be a single_set and not refer to more than one label.
+	   The jump insn must not refer to other labels as jump targets
+	   and must be a plain (set (pc) ...), maybe in a parallel, and
+	   may refer to the item being set only directly or as one of the
+	   arms in an IF_THEN_ELSE.  */
+	if (! INSN_DELETED_P (insn)
+	    && JUMP_P (insn)
+	    && JUMP_LABEL (insn) == NULL)
 	  {
-	    /* When we know the LABEL_REF contained in a REG used in
-	       an indirect jump, we'll have a REG_LABEL note so that
-	       flow can tell where it's going.  */
-	    if (JUMP_LABEL (insn) == 0)
+	    rtx label_note = NULL;
+	    rtx pc = pc_set (insn);
+	    rtx pc_src = pc != NULL ? SET_SRC (pc) : NULL;
+
+	    if (prev_nonjump_insn != NULL)
+	      label_note
+		= find_reg_note (prev_nonjump_insn, REG_LABEL_OPERAND, NULL);
+
+	    if (label_note != NULL && pc_src != NULL)
 	      {
-		rtx label_note = find_reg_note (insn, REG_LABEL, NULL_RTX);
-		if (label_note)
+		rtx label_set = single_set (prev_nonjump_insn);
+		rtx label_dest
+		  = label_set != NULL ? SET_DEST (label_set) : NULL;
+
+		if (label_set != NULL
+		    /* The source must be the direct LABEL_REF, not a
+		       PLUS, UNSPEC, IF_THEN_ELSE etc.  */
+		    && GET_CODE (SET_SRC (label_set)) == LABEL_REF
+		    && (rtx_equal_p (label_dest, pc_src)
+			|| (GET_CODE (pc_src) == IF_THEN_ELSE
+			    && (rtx_equal_p (label_dest, XEXP (pc_src, 1))
+				|| rtx_equal_p (label_dest,
+						XEXP (pc_src, 2))))))
+				
 		  {
-		    /* But a LABEL_REF around the REG_LABEL note, so
-		       that we can canonicalize it.  */
-		    rtx label_ref = gen_rtx_LABEL_REF (Pmode,
-						       XEXP (label_note, 0));
-
-		    mark_jump_label (label_ref, insn, 0);
-		    XEXP (label_note, 0) = XEXP (label_ref, 0);
-		    JUMP_LABEL (insn) = XEXP (label_note, 0);
+		    /* The CODE_LABEL referred to in the note must be the
+		       CODE_LABEL in the LABEL_REF of the "set".  We can
+		       conveniently use it for the marker function, which
+		       requires a LABEL_REF wrapping.  */
+		    gcc_assert (XEXP (label_note, 0)
+				== XEXP (SET_SRC (label_set), 0));
+
+		    mark_jump_label_1 (label_set, insn, false, true);
+		    gcc_assert (JUMP_LABEL (insn)
+				== XEXP (SET_SRC (label_set), 0));
 		  }
 	      }
 	  }
+	else if (! INSN_DELETED_P (insn))
+	  prev_nonjump_insn = insn;
       }
-  
+    else if (LABEL_P (insn))
+      prev_nonjump_insn = NULL;
+
   /* If we are in cfglayout mode, there may be non-insns between the
      basic blocks.  If those non-insns represent tablejump data, they
      contain label references that we must record.  */
@@ -904,12 +953,14 @@ sets_cc0_p (const_rtx x)
 }
 #endif
 \f
-/* Find all CODE_LABELs referred to in X, and increment their use counts.
-   If INSN is a JUMP_INSN and there is at least one CODE_LABEL referenced
-   in INSN, then store one of them in JUMP_LABEL (INSN).
-   If INSN is an INSN or a CALL_INSN and there is at least one CODE_LABEL
-   referenced in INSN, add a REG_LABEL note containing that label to INSN.
-   Also, when there are consecutive labels, canonicalize on the last of them.
+/* Find all CODE_LABELs referred to in X, and increment their use
+   counts.  If INSN is a JUMP_INSN and there is at least one
+   CODE_LABEL referenced in INSN as a jump target, then store the last
+   one in JUMP_LABEL (INSN).  For a tablejump, this must be the label
+   for the ADDR_VEC.  Store any other jump targets as REG_LABEL_TARGET
+   notes.  If INSN is an INSN or a CALL_INSN or non-target operands of
+   a JUMP_INSN, and there is at least one CODE_LABEL referenced in
+   INSN, add a REG_LABEL_OPERAND note containing that label to INSN.
 
    Note that two labels separated by a loop-beginning note
    must be kept distinct if we have not yet done loop-optimization,
@@ -920,6 +971,19 @@ sets_cc0_p (const_rtx x)
 void
 mark_jump_label (rtx x, rtx insn, int in_mem)
 {
+  mark_jump_label_1 (x, insn, in_mem != 0,
+		     (insn != NULL && x == PATTERN (insn) && JUMP_P (insn)));
+}
+
+/* Worker function for mark_jump_label.  IN_MEM is TRUE when X occurrs
+   within a (MEM ...).  IS_TARGET is TRUE when X is to be treated as a
+   jump-target; when the JUMP_LABEL field of INSN should be set or a
+   REG_LABEL_TARGET note should be added, not a REG_LABEL_OPERAND
+   note.  */
+
+static void
+mark_jump_label_1 (rtx x, rtx insn, bool in_mem, bool is_target)
+{
   RTX_CODE code = GET_CODE (x);
   int i;
   const char *fmt;
@@ -936,7 +1000,7 @@ mark_jump_label (rtx x, rtx insn, int in
       return;
 
     case MEM:
-      in_mem = 1;
+      in_mem = true;
       break;
 
     case SEQUENCE:
@@ -951,9 +1015,19 @@ mark_jump_label (rtx x, rtx insn, int in
 
       /* If this is a constant-pool reference, see if it is a label.  */
       if (CONSTANT_POOL_ADDRESS_P (x))
-	mark_jump_label (get_pool_constant (x), insn, in_mem);
+	mark_jump_label_1 (get_pool_constant (x), insn, in_mem, is_target);
       break;
 
+      /* Handle operands in the condition of an if-then-else as for a
+	 non-jump insn.  */
+    case IF_THEN_ELSE:
+      if (!is_target)
+	break;
+      mark_jump_label_1 (XEXP (x, 0), insn, in_mem, false);
+      mark_jump_label_1 (XEXP (x, 1), insn, in_mem, true);
+      mark_jump_label_1 (XEXP (x, 2), insn, in_mem, true);
+      return;
+
     case LABEL_REF:
       {
 	rtx label = XEXP (x, 0);
@@ -976,17 +1050,21 @@ mark_jump_label (rtx x, rtx insn, int in
 
 	if (insn)
 	  {
-	    if (JUMP_P (insn))
+	    if (is_target
+		&& (JUMP_LABEL (insn) == NULL || JUMP_LABEL (insn) == label))
 	      JUMP_LABEL (insn) = label;
 	    else
 	      {
-		/* Add a REG_LABEL note for LABEL unless there already
-		   is one.  All uses of a label, except for labels
-		   that are the targets of jumps, must have a
-		   REG_LABEL note.  */
-		if (! find_reg_note (insn, REG_LABEL, label))
-		  REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL, label,
-							REG_NOTES (insn));
+		enum reg_note kind
+		  = is_target ? REG_LABEL_TARGET : REG_LABEL_OPERAND;
+
+		/* Add a REG_LABEL_OPERAND or REG_LABEL_TARGET note
+		   for LABEL unless there already is one.  All uses of
+		   a label, except for the primary target of a jump,
+		   must have such a note.  */
+		if (! find_reg_note (insn, kind, label))
+		  REG_NOTES (insn)
+		    = gen_rtx_INSN_LIST (kind, label, REG_NOTES (insn));
 	      }
 	  }
 	return;
@@ -1001,7 +1079,8 @@ mark_jump_label (rtx x, rtx insn, int in
 	  int eltnum = code == ADDR_DIFF_VEC ? 1 : 0;
 
 	  for (i = 0; i < XVECLEN (x, eltnum); i++)
-	    mark_jump_label (XVECEXP (x, eltnum, i), NULL_RTX, in_mem);
+	    mark_jump_label_1 (XVECEXP (x, eltnum, i), NULL_RTX, in_mem,
+			       is_target);
 	}
       return;
 
@@ -1010,15 +1089,21 @@ mark_jump_label (rtx x, rtx insn, int in
     }
 
   fmt = GET_RTX_FORMAT (code);
+
+  /* The primary target of a tablejump is the label of the ADDR_VEC,
+     which is canonically mentioned *last* in the insn.  To get it
+     marked as JUMP_LABEL, we iterate over items in reverse order.  */
   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
     {
       if (fmt[i] == 'e')
-	mark_jump_label (XEXP (x, i), insn, in_mem);
+	mark_jump_label_1 (XEXP (x, i), insn, in_mem, is_target);
       else if (fmt[i] == 'E')
 	{
 	  int j;
-	  for (j = 0; j < XVECLEN (x, i); j++)
-	    mark_jump_label (XVECEXP (x, i, j), insn, in_mem);
+
+	  for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+	    mark_jump_label_1 (XVECEXP (x, i, j), insn, in_mem,
+			       is_target);
 	}
     }
 }
@@ -1062,20 +1147,10 @@ delete_related_insns (rtx insn)
       rtx lab = JUMP_LABEL (insn), lab_next;
 
       if (LABEL_NUSES (lab) == 0)
-	{
-	  /* This can delete NEXT or PREV,
-	     either directly if NEXT is JUMP_LABEL (INSN),
-	     or indirectly through more levels of jumps.  */
-	  delete_related_insns (lab);
-
-	  /* I feel a little doubtful about this loop,
-	     but I see no clean and sure alternative way
-	     to find the first insn after INSN that is not now deleted.
-	     I hope this works.  */
-	  while (next && INSN_DELETED_P (next))
-	    next = NEXT_INSN (next);
-	  return next;
-	}
+	/* This can delete NEXT or PREV,
+	   either directly if NEXT is JUMP_LABEL (INSN),
+	   or indirectly through more levels of jumps.  */
+	delete_related_insns (lab);
       else if (tablejump_p (insn, NULL, &lab_next))
 	{
 	  /* If we're deleting the tablejump, delete the dispatch table.
@@ -1104,10 +1179,12 @@ delete_related_insns (rtx insn)
       return next;
     }
 
-  /* Likewise for an ordinary INSN / CALL_INSN with a REG_LABEL note.  */
-  if (NONJUMP_INSN_P (insn) || CALL_P (insn))
+  /* Likewise for any JUMP_P / INSN / CALL_INSN with a
+     REG_LABEL_OPERAND or REG_LABEL_TARGET note.  */
+  if (INSN_P (insn))
     for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
-      if (REG_NOTE_KIND (note) == REG_LABEL
+      if ((REG_NOTE_KIND (note) == REG_LABEL_OPERAND
+	   || REG_NOTE_KIND (note) == REG_LABEL_TARGET)
 	  /* This could also be a NOTE_INSN_DELETED_LABEL note.  */
 	  && LABEL_P (XEXP (note, 0)))
 	if (LABEL_NUSES (XEXP (note, 0)) == 0)
@@ -1151,6 +1228,12 @@ delete_related_insns (rtx insn)
 	}
     }
 
+  /* I feel a little doubtful about this loop,
+     but I see no clean and sure alternative way
+     to find the first insn after INSN that is not now deleted.
+     I hope this works.  */
+  while (next && INSN_DELETED_P (next))
+    next = NEXT_INSN (next);
   return next;
 }
 \f
@@ -1307,6 +1390,8 @@ redirect_jump_2 (rtx jump, rtx olabel, r
 {
   rtx note;
 
+  gcc_assert (JUMP_LABEL (jump) == olabel);
+
   /* Negative DELETE_UNUSED used to be used to signalize behavior on
      moving FUNCTION_END note.  Just sanity check that no user still worry
      about this.  */
Index: gcc/print-rtl.c
===================================================================
--- gcc/print-rtl.c	(revision 128285)
+++ gcc/print-rtl.c	(working copy)
@@ -335,6 +335,9 @@ print_rtx (const_rtx in_rtx)
 		break;
 	      }
 	  }
+	else if (i == 9 && JUMP_P (in_rtx) && XEXP (in_rtx, i) != NULL)
+	  /* Output the JUMP_LABEL reference.  */
+	  fprintf (outfile, "\n -> %d", INSN_UID (XEXP (in_rtx, i)));
 	break;
 
       case 'e':
Index: gcc/gcse.c
===================================================================
--- gcc/gcse.c	(revision 128285)
+++ gcc/gcse.c	(working copy)
@@ -4584,14 +4584,15 @@ one_pre_gcse_pass (int pass)
   return changed;
 }
 \f
-/* If X contains any LABEL_REF's, add REG_LABEL notes for them to INSN.
-   If notes are added to an insn which references a CODE_LABEL, the
-   LABEL_NUSES count is incremented.  We have to add REG_LABEL notes,
-   because the following loop optimization pass requires them.  */
+/* If X contains any LABEL_REF's, add REG_LABEL_OPERAND notes for them
+   to INSN.  If such notes are added to an insn which references a
+   CODE_LABEL, the LABEL_NUSES count is incremented.  We have to add
+   that note, because the following loop optimization pass requires
+   them.  */
 
 /* ??? If there was a jump optimization pass after gcse and before loop,
    then we would not need to do this here, because jump would add the
-   necessary REG_LABEL notes.  */
+   necessary REG_LABEL_OPERAND and REG_LABEL_TARGET notes.  */
 
 static void
 add_label_notes (rtx x, rtx insn)
@@ -4608,10 +4609,18 @@ add_label_notes (rtx x, rtx insn)
 	 We no longer ignore such label references (see LABEL_REF handling in
 	 mark_jump_label for additional information).  */
 
-      REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL, XEXP (x, 0),
-					    REG_NOTES (insn));
-      if (LABEL_P (XEXP (x, 0)))
-	LABEL_NUSES (XEXP (x, 0))++;
+	if (reg_mentioned_p (XEXP (x, 0), insn))
+	  {
+	    /* There's no reason for current users to emit jump-insns
+	       with such a LABEL_REF, so we don't have to handle
+	       REG_LABEL_TARGET notes.  */
+	    gcc_assert (!JUMP_P (insn));
+	    REG_NOTES (insn)
+	      = gen_rtx_INSN_LIST (REG_LABEL_OPERAND, XEXP (x, 0),
+				   REG_NOTES (insn));
+	    if (LABEL_P (XEXP (x, 0)))
+	      LABEL_NUSES (XEXP (x, 0))++;
+	  }
       return;
     }
 
Index: gcc/emit-rtl.c
===================================================================
--- gcc/emit-rtl.c	(revision 128285)
+++ gcc/emit-rtl.c	(working copy)
@@ -3355,11 +3355,12 @@ try_split (rtx pat, rtx trial, int last)
 
   /* If there are LABELS inside the split insns increment the
      usage count so we don't delete the label.  */
-  if (NONJUMP_INSN_P (trial))
+  if (INSN_P (trial))
     {
       insn = insn_last;
       while (insn != NULL_RTX)
 	{
+	  /* JUMP_P insns have already been "marked" above.  */
 	  if (NONJUMP_INSN_P (insn))
 	    mark_label_nuses (PATTERN (insn));
 
@@ -5529,10 +5530,11 @@ emit_copy_of_insn_after (rtx insn, rtx a
      which may be duplicated by the basic block reordering code.  */
   RTX_FRAME_RELATED_P (new) = RTX_FRAME_RELATED_P (insn);
 
-  /* Copy all REG_NOTES except REG_LABEL since mark_jump_label will
-     make them.  */
+  /* Copy all REG_NOTES except REG_LABEL_OPERAND since mark_jump_label
+     will make them.  REG_LABEL_TARGETs are created there too, but are
+     supposed to be sticky, so we copy them.  */
   for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
-    if (REG_NOTE_KIND (link) != REG_LABEL)
+    if (REG_NOTE_KIND (link) != REG_LABEL_OPERAND)
       {
 	if (GET_CODE (link) == EXPR_LIST)
 	  REG_NOTES (new)
Index: gcc/rtl.h
===================================================================
--- gcc/rtl.h	(revision 128285)
+++ gcc/rtl.h	(working copy)
@@ -265,7 +265,8 @@ struct rtx_def GTY((chain_next ("RTX_NEX
      1 in a REG expression if corresponds to a variable declared by the user,
      0 for an internally generated temporary.
      1 in a SUBREG with a negative value.
-     1 in a LABEL_REF or in a REG_LABEL note for a non-local label.
+     1 in a LABEL_REF, REG_LABEL_TARGET or REG_LABEL_OPERAND note for a
+     non-local label.
      In a SYMBOL_REF, this flag is used for machine-specific purposes.  */
   unsigned int volatil : 1;
   /* 1 in a MEM referring to a field of an aggregate.
@@ -1224,10 +1225,11 @@ do {						\
    MEM_ATTRS (LHS) = MEM_ATTRS (RHS))
 
 /* 1 if RTX is a label_ref for a nonlocal label.  */
-/* Likewise in an expr_list for a reg_label note.  */
+/* Likewise in an expr_list for a REG_LABEL_OPERAND or
+   REG_LABEL_TARGET note.  */
 #define LABEL_REF_NONLOCAL_P(RTX)					\
-  (RTL_FLAG_CHECK2("LABEL_REF_NONLOCAL_P", (RTX), LABEL_REF,		\
-		   REG_LABEL)->volatil)
+  (RTL_FLAG_CHECK3("LABEL_REF_NONLOCAL_P", (RTX), LABEL_REF,		\
+		   REG_LABEL_OPERAND, REG_LABEL_TARGET)->volatil)
 
 /* 1 if RTX is a code_label that should always be considered to be needed.  */
 #define LABEL_PRESERVE_P(RTX)						\
Index: gcc/combine.c
===================================================================
--- gcc/combine.c	(revision 128285)
+++ gcc/combine.c	(working copy)
@@ -12408,7 +12408,8 @@ distribute_notes (rtx notes, rtx from_in
 	    }
 	  break;
 
-	case REG_LABEL:
+	case REG_LABEL_TARGET:
+	case REG_LABEL_OPERAND:
 	  /* This can show up in several ways -- either directly in the
 	     pattern, or hidden off in the constant pool with (or without?)
 	     a REG_EQUAL note.  */
@@ -12431,34 +12432,33 @@ distribute_notes (rtx notes, rtx from_in
 		place = i2;
 	    }
 
-	  /* Don't attach REG_LABEL note to a JUMP_INSN.  Add
-	     a JUMP_LABEL instead or decrement LABEL_NUSES.  */
-	  if (place && JUMP_P (place))
+	  /* For REG_LABEL_TARGET on a JUMP_P, we prefer to put the note
+	     as a JUMP_LABEL or decrement LABEL_NUSES if it's already
+	     there.  */
+	  if (place && JUMP_P (place)
+	      && REG_NOTE_KIND (note) == REG_LABEL_TARGET
+	      && (JUMP_LABEL (place) == NULL
+		  || JUMP_LABEL (place) == XEXP (note, 0)))
 	    {
 	      rtx label = JUMP_LABEL (place);
 
 	      if (!label)
 		JUMP_LABEL (place) = XEXP (note, 0);
-	      else
-		{
-		  gcc_assert (label == XEXP (note, 0));
-		  if (LABEL_P (label))
-		    LABEL_NUSES (label)--;
-		}
-	      place = 0;
+	      else if (LABEL_P (label))
+		LABEL_NUSES (label)--;
 	    }
-	  if (place2 && JUMP_P (place2))
+
+	  if (place2 && JUMP_P (place2)
+	      && REG_NOTE_KIND (note) == REG_LABEL_TARGET
+	      && (JUMP_LABEL (place2) == NULL
+		  || JUMP_LABEL (place2) == XEXP (note, 0)))
 	    {
 	      rtx label = JUMP_LABEL (place2);
 
 	      if (!label)
 		JUMP_LABEL (place2) = XEXP (note, 0);
-	      else
-		{
-		  gcc_assert (label == XEXP (note, 0));
-		  if (LABEL_P (label))
-		    LABEL_NUSES (label)--;
-		}
+	      else if (LABEL_P (label))
+		LABEL_NUSES (label)--;
 	      place2 = 0;
 	    }
 	  break;
Index: gcc/sched-rgn.c
===================================================================
--- gcc/sched-rgn.c	(revision 128285)
+++ gcc/sched-rgn.c	(working copy)
@@ -315,24 +315,20 @@ is_cfg_nonregular (void)
   if (current_function_has_exception_handlers ())
     return 1;
 
-  /* If we have non-jumping insns which refer to labels, then we consider
-     the cfg not well structured.  */
+  /* If we have insns which refer to labels as non-jumped-to operands,
+     then we consider the cfg not well structured.  */
   FOR_EACH_BB (b)
     FOR_BB_INSNS (b, insn)
       {
-	/* Check for labels referred by non-jump insns.  */
-	if (NONJUMP_INSN_P (insn) || CALL_P (insn))
-	  {
-	    rtx note = find_reg_note (insn, REG_LABEL, NULL_RTX);
-	    if (note
-		&& ! (JUMP_P (NEXT_INSN (insn))
-		      && find_reg_note (NEXT_INSN (insn), REG_LABEL,
-					XEXP (note, 0))))
-	      return 1;
-	  }
+	/* Check for labels referred to but (at least not directly) as
+	   jump targets.  */
+	if (INSN_P (insn)
+	    && find_reg_note (insn, REG_LABEL_OPERAND, NULL_RTX))
+	  return 1;
+
 	/* If this function has a computed jump, then we consider the cfg
 	   not well structured.  */
-	else if (JUMP_P (insn) && computed_jump_p (insn))
+	if (JUMP_P (insn) && computed_jump_p (insn))
 	  return 1;
       }
 
Index: gcc/config/alpha/alpha.md
===================================================================
--- gcc/config/alpha/alpha.md	(revision 128285)
+++ gcc/config/alpha/alpha.md	(working copy)
@@ -5375,9 +5375,9 @@ (define_split
 
 ;; Split the load of an address into a four-insn sequence on Unicos/Mk.
 ;; Always generate a REG_EQUAL note for the last instruction to facilitate
-;; optimizations. If the symbolic operand is a label_ref, generate REG_LABEL
-;; notes and update LABEL_NUSES because this is not done automatically.
-;; Labels may be incorrectly deleted if we don't do this.
+;; optimizations. If the symbolic operand is a label_ref, generate
+;; REG_LABEL_OPERAND notes and update LABEL_NUSES because this is not done
+;; automatically.  Labels may be incorrectly deleted if we don't do this.
 ;;
 ;; Describing what the individual instructions do correctly is too complicated
 ;; so use UNSPECs for each of the three parts of an address.
@@ -5401,11 +5401,11 @@ (define_split
       rtx label;
 
       label = XEXP (operands[1], 0);
-      REG_NOTES (insn1) = gen_rtx_EXPR_LIST (REG_LABEL, label,
+      REG_NOTES (insn1) = gen_rtx_EXPR_LIST (REG_LABEL_OPERAND, label,
 					     REG_NOTES (insn1));
-      REG_NOTES (insn2) = gen_rtx_EXPR_LIST (REG_LABEL, label,
+      REG_NOTES (insn2) = gen_rtx_EXPR_LIST (REG_LABEL_OPERAND, label,
 					     REG_NOTES (insn2));
-      REG_NOTES (insn3) = gen_rtx_EXPR_LIST (REG_LABEL, label,
+      REG_NOTES (insn3) = gen_rtx_EXPR_LIST (REG_LABEL_OPERAND, label,
 					     REG_NOTES (insn3));
       LABEL_NUSES (label) += 3;
     }
Index: gcc/config/sh/sh.c
===================================================================
--- gcc/config/sh/sh.c	(revision 128285)
+++ gcc/config/sh/sh.c	(working copy)
@@ -4716,8 +4716,8 @@ sh_reorg (void)
   mdep_reorg_phase = SH_INSERT_USES_LABELS;
   if (TARGET_RELAX)
     {
-      /* Remove all REG_LABEL notes.  We want to use them for our own
-	 purposes.  This works because none of the remaining passes
+      /* Remove all REG_LABEL_OPERAND notes.  We want to use them for our
+	 own purposes.  This works because none of the remaining passes
 	 need to look at them.
 
 	 ??? But it may break in the future.  We should use a machine
@@ -4728,7 +4728,8 @@ sh_reorg (void)
 	    {
 	      rtx note;
 
-	      while ((note = find_reg_note (insn, REG_LABEL, NULL_RTX)) != 0)
+	      while ((note = find_reg_note (insn, REG_LABEL_OPERAND,
+					    NULL_RTX)) != 0)
 		remove_note (insn, note);
 	    }
 	}
@@ -4879,16 +4880,16 @@ sh_reorg (void)
 	      continue;
 	    }
 
-	  /* Create a code label, and put it in a REG_LABEL note on
-             the insn which sets the register, and on each call insn
-             which uses the register.  In final_prescan_insn we look
-             for the REG_LABEL notes, and output the appropriate label
+	  /* Create a code label, and put it in a REG_LABEL_OPERAND note
+             on the insn which sets the register, and on each call insn
+             which uses the register.  In final_prescan_insn we look for
+             the REG_LABEL_OPERAND notes, and output the appropriate label
              or pseudo-op.  */
 
 	  label = gen_label_rtx ();
-	  REG_NOTES (link) = gen_rtx_INSN_LIST (REG_LABEL, label,
+	  REG_NOTES (link) = gen_rtx_INSN_LIST (REG_LABEL_OPERAND, label,
 						REG_NOTES (link));
-	  REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL, label,
+	  REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL_OPERAND, label,
 						REG_NOTES (insn));
 	  if (rescan)
 	    {
@@ -4904,7 +4905,8 @@ sh_reorg (void)
 			  || ((reg2 = sfunc_uses_reg (scan))
 			      && REGNO (reg2) == REGNO (reg))))
 		    REG_NOTES (scan)
-		      = gen_rtx_INSN_LIST (REG_LABEL, label, REG_NOTES (scan));
+		      = gen_rtx_INSN_LIST (REG_LABEL_OPERAND, label,
+					   REG_NOTES (scan));
 		}
 	      while (scan != dies);
 	    }
@@ -5405,7 +5407,7 @@ final_prescan_insn (rtx insn, rtx *opvec
     {
       rtx note;
 
-      note = find_reg_note (insn, REG_LABEL, NULL_RTX);
+      note = find_reg_note (insn, REG_LABEL_OPERAND, NULL_RTX);
       if (note)
 	{
 	  rtx pattern;
Index: gcc/reg-notes.def
===================================================================
--- gcc/reg-notes.def	(revision 128285)
+++ gcc/reg-notes.def	(working copy)
@@ -91,10 +91,16 @@ REG_NOTE (UNUSED)
 REG_NOTE (CC_SETTER)
 REG_NOTE (CC_USER)
 
-/* Points to a CODE_LABEL.  Used by non-JUMP_INSNs to say that the
-   CODE_LABEL contained in the REG_LABEL note is used by the insn.
-   This note is an INSN_LIST.  */
-REG_NOTE (LABEL)
+/* Points to a CODE_LABEL.  Used by JUMP_INSNs to say that the CODE_LABEL
+   contained in the REG_LABEL_TARGET note is a possible jump target of
+   this insn.  This note is an INSN_LIST.  */
+REG_NOTE (LABEL_TARGET)
+
+/* Points to a CODE_LABEL.  Used by any insn to say that the CODE_LABEL
+   contained in the REG_LABEL_OPERAND note is used by the insn, but as an
+   operand, not as a jump target (though it may indirectly be a jump
+   target for a later jump insn).  This note is an INSN_LIST.  */
+REG_NOTE (LABEL_OPERAND)
 
 /* REG_DEP_OUTPUT and REG_DEP_ANTI are used in scheduler dependencies lists
    to represent write-after-write and write-after-read dependencies
Index: gcc/cfgrtl.c
===================================================================
--- gcc/cfgrtl.c	(revision 128285)
+++ gcc/cfgrtl.c	(working copy)
@@ -138,15 +138,15 @@ delete_insn (rtx insn)
 
   /* If deleting a jump, decrement the use count of the label.  Deleting
      the label itself should happen in the normal course of block merging.  */
-  if (JUMP_P (insn)
-      && JUMP_LABEL (insn)
-      && LABEL_P (JUMP_LABEL (insn)))
-    LABEL_NUSES (JUMP_LABEL (insn))--;
-
-  /* Also if deleting an insn that references a label.  */
-  else
+  if (JUMP_P (insn))
     {
-      while ((note = find_reg_note (insn, REG_LABEL, NULL_RTX)) != NULL_RTX
+      if (JUMP_LABEL (insn)
+	  && LABEL_P (JUMP_LABEL (insn)))
+	LABEL_NUSES (JUMP_LABEL (insn))--;
+
+      /* If there are more targets, remove them too.  */
+      while ((note
+	      = find_reg_note (insn, REG_LABEL_TARGET, NULL_RTX)) != NULL_RTX
 	     && LABEL_P (XEXP (note, 0)))
 	{
 	  LABEL_NUSES (XEXP (note, 0))--;
@@ -154,6 +154,14 @@ delete_insn (rtx insn)
 	}
     }
 
+  /* Also if deleting any insn that references a label as an operand.  */
+  while ((note = find_reg_note (insn, REG_LABEL_OPERAND, NULL_RTX)) != NULL_RTX
+	 && LABEL_P (XEXP (note, 0)))
+    {
+      LABEL_NUSES (XEXP (note, 0))--;
+      remove_note (insn, note);
+    }
+
   if (JUMP_P (insn)
       && (GET_CODE (PATTERN (insn)) == ADDR_VEC
 	  || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC))
Index: gcc/reload1.c
===================================================================
--- gcc/reload1.c	(revision 128285)
+++ gcc/reload1.c	(working copy)
@@ -1539,8 +1539,8 @@ calculate_needs_all_insns (int global)
       chain->need_operand_change = 0;
 
       /* If this is a label, a JUMP_INSN, or has REG_NOTES (which might
-	 include REG_LABEL), we need to see what effects this has on the
-	 known offsets at labels.  */
+	 include REG_LABEL_OPERAND and REG_LABEL_TARGET), we need to see
+	 what effects this has on the known offsets at labels.  */
 
       if (LABEL_P (insn) || JUMP_P (insn)
 	  || (INSN_P (insn) && REG_NOTES (insn) != 0))
@@ -2295,10 +2295,11 @@ set_label_offsets (rtx x, rtx insn, int 
 
     case INSN:
     case CALL_INSN:
-      /* Any labels mentioned in REG_LABEL notes can be branched to indirectly
-	 and hence must have all eliminations at their initial offsets.  */
+      /* Any labels mentioned in REG_LABEL_OPERAND notes can be branched
+	 to indirectly and hence must have all eliminations at their
+	 initial offsets.  */
       for (tem = REG_NOTES (x); tem; tem = XEXP (tem, 1))
-	if (REG_NOTE_KIND (tem) == REG_LABEL)
+	if (REG_NOTE_KIND (tem) == REG_LABEL_OPERAND)
 	  set_label_offsets (XEXP (tem, 0), insn, 1);
       return;
 
@@ -8049,7 +8050,7 @@ gen_reload (rtx out, rtx in, int opnum, 
   else if (OBJECT_P (in) || GET_CODE (in) == SUBREG)
     {
       tem = emit_insn (gen_move_insn (out, in));
-      /* IN may contain a LABEL_REF, if so add a REG_LABEL note.  */
+      /* IN may contain a LABEL_REF, if so add a REG_LABEL_OPERAND note.  */
       mark_jump_label (in, tem, 0);
     }
 
brgds, H-P

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFA:] Split REG_LABEL into REG_LABEL_TARGET and REG_LABEL_OPERAND
  2007-09-09  7:13   ` Hans-Peter Nilsson
@ 2007-09-09 10:47     ` Eric Botcazou
  2007-09-13  3:17       ` Hans-Peter Nilsson
                         ` (2 more replies)
  0 siblings, 3 replies; 13+ messages in thread
From: Eric Botcazou @ 2007-09-09 10:47 UTC (permalink / raw)
  To: Hans-Peter Nilsson; +Cc: gcc-patches

> Index: gcc/reload.c
> ===================================================================
> --- gcc/reload.c	(revision 128285)
> +++ gcc/reload.c	(working copy)
> @@ -4103,13 +4103,18 @@ find_reloads (rtx insn, int replace, int
>
>  	  *recog_data.operand_loc[i] = substitution;
>
> -	  /* If we're replacing an operand with a LABEL_REF, we need
> -	     to make sure that there's a REG_LABEL note attached to
> +	  /* If we're replacing an operand with a LABEL_REF, we need to
> +	     make sure that there's a REG_LABEL_OPERAND note attached to
>  	     this instruction.  */
> -	  if (!JUMP_P (insn)
> -	      && GET_CODE (substitution) == LABEL_REF
> -	      && !find_reg_note (insn, REG_LABEL, XEXP (substitution, 0)))
> -	    REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL,
> +	  if (GET_CODE (substitution) == LABEL_REF
> +	      && !find_reg_note (insn, REG_LABEL_OPERAND,
> +				 XEXP (substitution, 0))
> +	      /* For a JUMP_P, if it was a branch target it must have
> +		 already been recorded as such.  */
> +	      && (!JUMP_P (insn)
> +		  || !label_is_jump_target_p (XEXP (substitution, 0),
> +					      insn)))
> +	    REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL_OPERAND,
>  						  XEXP (substitution, 0),
>  						  REG_NOTES (insn));
>  	}

You're not updating label_is_jump_target_p to take into account the operands 
of REG_LABEL_TARGET notes, so can't you be creating REG_LABEL_OPERAND notes
for them?

> @@ -6123,17 +6128,15 @@ subst_reloads (rtx insn)
>  	    }
>  #endif /* DEBUG_RELOAD */
>
> -	  /* If we're replacing a LABEL_REF with a register, add a
> -	     REG_LABEL note to indicate to flow which label this
> +	  /* If we're replacing a LABEL_REF with a register, there must
> +	     already be an indication (to e.g. flow) which label this
>  	     register refers to.  */
> -	  if (GET_CODE (*r->where) == LABEL_REF
> -	      && JUMP_P (insn))
> -	    {
> -	      REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL,
> -						    XEXP (*r->where, 0),
> -						    REG_NOTES (insn));
> -	      JUMP_LABEL (insn) = XEXP (*r->where, 0);
> -	   }
> +	  gcc_assert (GET_CODE (*r->where) != LABEL_REF
> +		      || !JUMP_P (insn)
> +		      || find_reg_note (insn,
> +					REG_LABEL_OPERAND,
> +					XEXP (*r->where, 0))
> +		      || label_is_jump_target_p (XEXP (*r->where, 0), insn));
>
>  	  /* Encapsulate RELOADREG so its machine mode matches what
>  	     used to be there.  Note that gen_lowpart_common will

Same question: what about operands of REG_LABEL_TARGET notes?

> @@ -2736,14 +2737,40 @@ fill_slots_from_thread (rtx insn, rtx co
>  		      /* We are moving this insn, not deleting it.  We must
>  			 temporarily increment the use count on any referenced
>  			 label lest it be deleted by delete_related_insns.  */
> -		      note = find_reg_note (trial, REG_LABEL, 0);
> -		      /* REG_LABEL could be NOTE_INSN_DELETED_LABEL too.  */
> -		      if (note && LABEL_P (XEXP (note, 0)))
> +		      for (note = REG_NOTES (trial);
> +			   note != NULL;
> +			   note = XEXP (note, 1))
> +			if (REG_NOTE_KIND (note) == REG_LABEL_OPERAND
> +			    || REG_NOTE_KIND (note) == REG_LABEL_TARGET)
> +			  {
> +			    /* REG_LABEL_OPERAND could be
> +			       NOTE_INSN_DELETED_LABEL too.  */
> +			    if (LABEL_P (XEXP (note, 0)))
> +			      LABEL_NUSES (XEXP (note, 0))++;
> +			    else
> +			      gcc_assert (REG_NOTE_KIND (note)
> +					  == REG_LABEL_OPERAND);
> +			  }
> +		      if (JUMP_P (trial) && JUMP_LABEL (trial))
>  			LABEL_NUSES (XEXP (note, 0))++;

AFAICS note == NULL at this point (and it should be NULL_RTX instead of NULL).

>  		      delete_related_insns (trial);
>
> -		      if (note && LABEL_P (XEXP (note, 0)))
> +		      for (note = REG_NOTES (trial);
> +			   note != NULL;
> +			   note = XEXP (note, 1))
> +			if (REG_NOTE_KIND (note) == REG_LABEL_OPERAND
> +			    || REG_NOTE_KIND (note) == REG_LABEL_TARGET)
> +			  {
> +			    /* REG_LABEL_OPERAND could be
> +			       NOTE_INSN_DELETED_LABEL too.  */
> +			    if (LABEL_P (XEXP (note, 0)))
> +			      LABEL_NUSES (XEXP (note, 0))--;
> +			    else
> +			      gcc_assert (REG_NOTE_KIND (note)
> +					  == REG_LABEL_OPERAND);
> +			  }
> +		      if (JUMP_P (trial) && JUMP_LABEL (trial))
>  			LABEL_NUSES (XEXP (note, 0))--;

Likewise.

>  static int
>  check_for_label_ref (rtx *rtl, void *data)
>  {
>    rtx insn = (rtx) data;
>
> -  /* If this insn uses a LABEL_REF and there isn't a REG_LABEL note for
> it, -     we must rerun jump since it needs to place the note.  If this is
> a -     LABEL_REF for a CODE_LABEL that isn't in the insn chain, don't do
> this -     since no REG_LABEL will be added.  */
> +  /* If this insn uses a LABEL_REF and there isn't a REG_LABEL_OPERAND
> +     note for it, we must rerun jump since it needs to place the note.  If
> +     this is a LABEL_REF for a CODE_LABEL that isn't in the insn chain,
> +     don't do this since no REG_LABEL_OPERAND will be added.  */
>    return (GET_CODE (*rtl) == LABEL_REF
>  	  && ! LABEL_REF_NONLOCAL_P (*rtl)
> +	  && (!JUMP_P (insn)
> +	      || !label_is_jump_target_p (XEXP (*rtl, 0), insn))
>  	  && LABEL_P (XEXP (*rtl, 0))
>  	  && INSN_UID (XEXP (*rtl, 0)) != 0
> -	  && ! find_reg_note (insn, REG_LABEL, XEXP (*rtl, 0)));
> +	  && ! find_reg_note (insn, REG_LABEL_OPERAND, XEXP (*rtl, 0)));

What about operands of REG_LABEL_TARGET notes?

> @@ -172,34 +186,69 @@ static void
>  mark_all_labels (rtx f)
>  {
>    rtx insn;
> +  rtx prev_nonjump_insn = NULL;
>
>    for (insn = f; insn; insn = NEXT_INSN (insn))
>      if (INSN_P (insn))
>        {
>  	mark_jump_label (PATTERN (insn), insn, 0);
> -	if (! INSN_DELETED_P (insn) && JUMP_P (insn))
> +
> +	/* If the previous non-jump insn sets something to a label,
> +	   something that this jump insn uses, make that label the primary
> +	   target of this insn if we don't yet have any.  That previous
> +	   insn must be a single_set and not refer to more than one label.
> +	   The jump insn must not refer to other labels as jump targets
> +	   and must be a plain (set (pc) ...), maybe in a parallel, and
> +	   may refer to the item being set only directly or as one of the
> +	   arms in an IF_THEN_ELSE.  */
> +	if (! INSN_DELETED_P (insn)
> +	    && JUMP_P (insn)
> +	    && JUMP_LABEL (insn) == NULL)

Why do you need to do this?  Is it an optimization?

> @@ -976,17 +1050,21 @@ mark_jump_label (rtx x, rtx insn, int in
>
>  	if (insn)
>  	  {
> -	    if (JUMP_P (insn))
> +	    if (is_target
> +		&& (JUMP_LABEL (insn) == NULL || JUMP_LABEL (insn) == label))
>  	      JUMP_LABEL (insn) = label;

Please add a small comment, one can easily think there is a typo in the second 
part of the disjunction: JUMP_LABEL (insn) != label.

> @@ -4608,10 +4609,18 @@ add_label_notes (rtx x, rtx insn)
>  	 We no longer ignore such label references (see LABEL_REF handling in
>  	 mark_jump_label for additional information).  */
>
> -      REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL, XEXP (x, 0),
> -					    REG_NOTES (insn));
> -      if (LABEL_P (XEXP (x, 0)))
> -	LABEL_NUSES (XEXP (x, 0))++;
> +	if (reg_mentioned_p (XEXP (x, 0), insn))
> +	  {
> +	    /* There's no reason for current users to emit jump-insns
> +	       with such a LABEL_REF, so we don't have to handle
> +	       REG_LABEL_TARGET notes.  */
> +	    gcc_assert (!JUMP_P (insn));
> +	    REG_NOTES (insn)
> +	      = gen_rtx_INSN_LIST (REG_LABEL_OPERAND, XEXP (x, 0),
> +				   REG_NOTES (insn));
> +	    if (LABEL_P (XEXP (x, 0)))
> +	      LABEL_NUSES (XEXP (x, 0))++;
> +	  }
>        return;
>      }

"Put in line with jump.c copy by only adding notes for labels actually 
referenced in the insn" but AFAICS mark_jump_label doesn't do that.

> Index: gcc/sched-rgn.c
> ===================================================================
> --- gcc/sched-rgn.c	(revision 128285)
> +++ gcc/sched-rgn.c	(working copy)
> @@ -315,24 +315,20 @@ is_cfg_nonregular (void)
>    if (current_function_has_exception_handlers ())
>      return 1;
>
> -  /* If we have non-jumping insns which refer to labels, then we consider
> -     the cfg not well structured.  */
> +  /* If we have insns which refer to labels as non-jumped-to operands,
> +     then we consider the cfg not well structured.  */
>    FOR_EACH_BB (b)
>      FOR_BB_INSNS (b, insn)
>        {
> -	/* Check for labels referred by non-jump insns.  */
> -	if (NONJUMP_INSN_P (insn) || CALL_P (insn))
> -	  {
> -	    rtx note = find_reg_note (insn, REG_LABEL, NULL_RTX);
> -	    if (note
> -		&& ! (JUMP_P (NEXT_INSN (insn))
> -		      && find_reg_note (NEXT_INSN (insn), REG_LABEL,
> -					XEXP (note, 0))))
> -	      return 1;
> -	  }
> +	/* Check for labels referred to but (at least not directly) as
> +	   jump targets.  */
> +	if (INSN_P (insn)
> +	    && find_reg_note (insn, REG_LABEL_OPERAND, NULL_RTX))
> +	  return 1;
> +
>  	/* If this function has a computed jump, then we consider the cfg
>  	   not well structured.  */
> -	else if (JUMP_P (insn) && computed_jump_p (insn))
> +	if (JUMP_P (insn) && computed_jump_p (insn))
>  	  return 1;
>        }

Why did you drop the check on NEXT_INSN altogether?

-- 
Eric Botcazou

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFA:] Split REG_LABEL into REG_LABEL_TARGET and REG_LABEL_OPERAND
  2007-09-09 10:47     ` Eric Botcazou
@ 2007-09-13  3:17       ` Hans-Peter Nilsson
  2007-09-13 13:15         ` Eric Botcazou
  2007-11-14  0:24       ` Hans-Peter Nilsson
  2007-11-15 12:14       ` Hans-Peter Nilsson
  2 siblings, 1 reply; 13+ messages in thread
From: Hans-Peter Nilsson @ 2007-09-13  3:17 UTC (permalink / raw)
  To: ebotcazou; +Cc: hans-peter.nilsson, gcc-patches

> From: Eric Botcazou <ebotcazou@libertysurf.fr>
> Date: Sun, 9 Sep 2007 11:00:37 +0200

Sorry for not replying sooner.  Some of your questions warrant a
bit of an investigation (details no longer in the head-cache and
then there's the df impact) but here's a partial reply:

> > Index: gcc/reload.c
> > ===================================================================
> > --- gcc/reload.c	(revision 128285)
> > +++ gcc/reload.c	(working copy)
> > @@ -4103,13 +4103,18 @@ find_reloads (rtx insn, int replace, int
> >
> >  	  *recog_data.operand_loc[i] = substitution;
> >
> > -	  /* If we're replacing an operand with a LABEL_REF, we need
> > -	     to make sure that there's a REG_LABEL note attached to
> > +	  /* If we're replacing an operand with a LABEL_REF, we need to
> > +	     make sure that there's a REG_LABEL_OPERAND note attached to
> >  	     this instruction.  */
> > -	  if (!JUMP_P (insn)
> > -	      && GET_CODE (substitution) == LABEL_REF
> > -	      && !find_reg_note (insn, REG_LABEL, XEXP (substitution, 0)))
> > -	    REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL,
> > +	  if (GET_CODE (substitution) == LABEL_REF
> > +	      && !find_reg_note (insn, REG_LABEL_OPERAND,
> > +				 XEXP (substitution, 0))
> > +	      /* For a JUMP_P, if it was a branch target it must have
> > +		 already been recorded as such.  */
> > +	      && (!JUMP_P (insn)
> > +		  || !label_is_jump_target_p (XEXP (substitution, 0),
> > +					      insn)))
> > +	    REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL_OPERAND,
> >  						  XEXP (substitution, 0),
> >  						  REG_NOTES (insn));
> >  	}
> 
> You're not updating label_is_jump_target_p to take into account the operands 
> of REG_LABEL_TARGET notes, so can't you be creating REG_LABEL_OPERAND notes
> for them?

(I assume you mean s/can't/shouldn't/ and "REG_LABEL_TARGET
notes for them".  If not, please rephrase the question.)

To trig that case, a target is needed that can jump to more than
one location in the same insn (e.g. a conditional branch that
doesn't fall through) but which isn't a *simple* tablejump,
because otherwise label_is_jump_target_p fits as-is.  (Hm, the
CRIS "*casesi_adds_w" insn seems to match that somewhat; the
label for the jump-table is possibly dangling unless tablejumps
are explicitly handled... need to investigate.)

If there's a problem, the remedy would be to update
label_is_jump_target_p to be less simplified than its heading
says; to handle REG_LABEL_TARGET notes.  (I *think* code
elsewhere will fail for non-tablejump insns with more than one
branch target, but anyway consistency is a reason to update it.)

The code here just needs to cope with updating REG_LABEL_OPERAND
notes; labels that aren't trivially jumped to (see original,
"-"-marked code).  All REG_LABEL_TARGET notes are added long
before reload.

> > @@ -6123,17 +6128,15 @@ subst_reloads (rtx insn)
> >  	    }
> >  #endif /* DEBUG_RELOAD */
> >
> > -	  /* If we're replacing a LABEL_REF with a register, add a
> > -	     REG_LABEL note to indicate to flow which label this
> > +	  /* If we're replacing a LABEL_REF with a register, there must
> > +	     already be an indication (to e.g. flow) which label this
> >  	     register refers to.  */
> > -	  if (GET_CODE (*r->where) == LABEL_REF
> > -	      && JUMP_P (insn))
> > -	    {
> > -	      REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL,
> > -						    XEXP (*r->where, 0),
> > -						    REG_NOTES (insn));
> > -	      JUMP_LABEL (insn) = XEXP (*r->where, 0);
> > -	   }
> > +	  gcc_assert (GET_CODE (*r->where) != LABEL_REF
> > +		      || !JUMP_P (insn)
> > +		      || find_reg_note (insn,
> > +					REG_LABEL_OPERAND,
> > +					XEXP (*r->where, 0))
> > +		      || label_is_jump_target_p (XEXP (*r->where, 0), insn));
> >
> >  	  /* Encapsulate RELOADREG so its machine mode matches what
> >  	     used to be there.  Note that gen_lowpart_common will
> 
> Same question: what about operands of REG_LABEL_TARGET notes?

They've already been generated when we come to reload; for a
simple un/conditional jump the label sticks to the JUMP_LABEL
field.  The semantics are changed to be sticky, so they don't
need to be added again.  Note the old code adding them to both
the JUMP_LABEL field and as a REG_LABEL note!

(For this code and the one above; since you have to ask, this
code needs a comment to the effect of my reply.)

> > @@ -2736,14 +2737,40 @@ fill_slots_from_thread (rtx insn, rtx co
> >  		      /* We are moving this insn, not deleting it.  We must
> >  			 temporarily increment the use count on any referenced
> >  			 label lest it be deleted by delete_related_insns.  */
> > -		      note = find_reg_note (trial, REG_LABEL, 0);
> > -		      /* REG_LABEL could be NOTE_INSN_DELETED_LABEL too.  */
> > -		      if (note && LABEL_P (XEXP (note, 0)))
> > +		      for (note = REG_NOTES (trial);
> > +			   note != NULL;
> > +			   note = XEXP (note, 1))
> > +			if (REG_NOTE_KIND (note) == REG_LABEL_OPERAND
> > +			    || REG_NOTE_KIND (note) == REG_LABEL_TARGET)
> > +			  {
> > +			    /* REG_LABEL_OPERAND could be
> > +			       NOTE_INSN_DELETED_LABEL too.  */
> > +			    if (LABEL_P (XEXP (note, 0)))
> > +			      LABEL_NUSES (XEXP (note, 0))++;
> > +			    else
> > +			      gcc_assert (REG_NOTE_KIND (note)
> > +					  == REG_LABEL_OPERAND);
> > +			  }
> > +		      if (JUMP_P (trial) && JUMP_LABEL (trial))
> >  			LABEL_NUSES (XEXP (note, 0))++;
> 
> AFAICS note == NULL at this point (and it should be NULL_RTX instead of NULL).
> ...
> Likewise.

Yes... typo: they should just move inside the closing bracket on
the previous line.  I'm curious this didn't trig a SEGV in my
testing.  Investigating.

> >  static int
> >  check_for_label_ref (rtx *rtl, void *data)
> >  {
> >    rtx insn = (rtx) data;
> >
> > -  /* If this insn uses a LABEL_REF and there isn't a REG_LABEL note for
> > it, -     we must rerun jump since it needs to place the note.  If this is
> > a -     LABEL_REF for a CODE_LABEL that isn't in the insn chain, don't do
> > this -     since no REG_LABEL will be added.  */
> > +  /* If this insn uses a LABEL_REF and there isn't a REG_LABEL_OPERAND
> > +     note for it, we must rerun jump since it needs to place the note.  If
> > +     this is a LABEL_REF for a CODE_LABEL that isn't in the insn chain,
> > +     don't do this since no REG_LABEL_OPERAND will be added.  */
> >    return (GET_CODE (*rtl) == LABEL_REF
> >  	  && ! LABEL_REF_NONLOCAL_P (*rtl)
> > +	  && (!JUMP_P (insn)
> > +	      || !label_is_jump_target_p (XEXP (*rtl, 0), insn))
> >  	  && LABEL_P (XEXP (*rtl, 0))
> >  	  && INSN_UID (XEXP (*rtl, 0)) != 0
> > -	  && ! find_reg_note (insn, REG_LABEL, XEXP (*rtl, 0)));
> > +	  && ! find_reg_note (insn, REG_LABEL_OPERAND, XEXP (*rtl, 0)));
> 
> What about operands of REG_LABEL_TARGET notes?

They aren't supposed to (must not) be handled here.  This code
is only for REG_LABEL_OPERAND notes needing to be updated;
non-jump-insns moved around without notes being updated.  Same
comment about label_is_jump_target_p maybe being too simple
applies.  (Since you have to ask, this function needs a comment
to this effect.)

> > @@ -172,34 +186,69 @@ static void
> >  mark_all_labels (rtx f)
> >  {
> >    rtx insn;
> > +  rtx prev_nonjump_insn = NULL;
> >
> >    for (insn = f; insn; insn = NEXT_INSN (insn))
> >      if (INSN_P (insn))
> >        {
> >  	mark_jump_label (PATTERN (insn), insn, 0);
> > -	if (! INSN_DELETED_P (insn) && JUMP_P (insn))
> > +
> > +	/* If the previous non-jump insn sets something to a label,
> > +	   something that this jump insn uses, make that label the primary
> > +	   target of this insn if we don't yet have any.  That previous
> > +	   insn must be a single_set and not refer to more than one label.
> > +	   The jump insn must not refer to other labels as jump targets
> > +	   and must be a plain (set (pc) ...), maybe in a parallel, and
> > +	   may refer to the item being set only directly or as one of the
> > +	   arms in an IF_THEN_ELSE.  */
> > +	if (! INSN_DELETED_P (insn)
> > +	    && JUMP_P (insn)
> > +	    && JUMP_LABEL (insn) == NULL)
> 
> Why do you need to do this?  Is it an optimization?

It's the core machinery for targets with branch-target
registers, to have the label recorded as a branch target before
further optimizations moves the set and use of that register
apart.  Otherwise, those branches will all be treated as
computed jumps.  Hm, we'll still have the REG_LABEL_OPERAND note
on the register load, but then again, so we did before too.
I'll check that this still happens and add a comment actually
mentioning "branch-target register"!

> 
> > @@ -976,17 +1050,21 @@ mark_jump_label (rtx x, rtx insn, int in
> >
> >  	if (insn)
> >  	  {
> > -	    if (JUMP_P (insn))
> > +	    if (is_target
> > +		&& (JUMP_LABEL (insn) == NULL || JUMP_LABEL (insn) == label))
> >  	      JUMP_LABEL (insn) = label;
> 
> Please add a small comment, one can easily think there is a typo in the second 
> part of the disjunction: JUMP_LABEL (insn) != label.

Will do.

> > @@ -4608,10 +4609,18 @@ add_label_notes (rtx x, rtx insn)
> >  	 We no longer ignore such label references (see LABEL_REF handling in
> >  	 mark_jump_label for additional information).  */
> >
> > -      REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL, XEXP (x, 0),
> > -					    REG_NOTES (insn));
> > -      if (LABEL_P (XEXP (x, 0)))
> > -	LABEL_NUSES (XEXP (x, 0))++;
> > +	if (reg_mentioned_p (XEXP (x, 0), insn))
> > +	  {
> > +	    /* There's no reason for current users to emit jump-insns
> > +	       with such a LABEL_REF, so we don't have to handle
> > +	       REG_LABEL_TARGET notes.  */
> > +	    gcc_assert (!JUMP_P (insn));
> > +	    REG_NOTES (insn)
> > +	      = gen_rtx_INSN_LIST (REG_LABEL_OPERAND, XEXP (x, 0),
> > +				   REG_NOTES (insn));
> > +	    if (LABEL_P (XEXP (x, 0)))
> > +	      LABEL_NUSES (XEXP (x, 0))++;
> > +	  }
> >        return;
> >      }
> 
> "Put in line with jump.c copy by only adding notes for labels actually 
> referenced in the insn" but AFAICS mark_jump_label doesn't do that.

Uhm, it does; it iterates on the insn, and when it finds
LABEL_REFs, it adds unique REG_LABEL_OPERAND notes (and sets the
JUMP_LABEL field and emits REG_LABEL_TARGET notes, but they
weren't the issue here).  It no longer emit duplicates.
Rephrase suggested?  Perhaps just "Make sure not to add
duplicate REG_LABEL_OPERAND notes" and referring to consistency
by adding a comment in the add_label_notes code?

> > Index: gcc/sched-rgn.c
> > ===================================================================
> > --- gcc/sched-rgn.c	(revision 128285)
> > +++ gcc/sched-rgn.c	(working copy)
> > @@ -315,24 +315,20 @@ is_cfg_nonregular (void)
> >    if (current_function_has_exception_handlers ())
> >      return 1;
> >
> > -  /* If we have non-jumping insns which refer to labels, then we consider
> > -     the cfg not well structured.  */
> > +  /* If we have insns which refer to labels as non-jumped-to operands,
> > +     then we consider the cfg not well structured.  */
> >    FOR_EACH_BB (b)
> >      FOR_BB_INSNS (b, insn)
> >        {
> > -	/* Check for labels referred by non-jump insns.  */
> > -	if (NONJUMP_INSN_P (insn) || CALL_P (insn))
> > -	  {
> > -	    rtx note = find_reg_note (insn, REG_LABEL, NULL_RTX);
> > -	    if (note
> > -		&& ! (JUMP_P (NEXT_INSN (insn))
> > -		      && find_reg_note (NEXT_INSN (insn), REG_LABEL,
> > -					XEXP (note, 0))))
> > -	      return 1;
> > -	  }
> > +	/* Check for labels referred to but (at least not directly) as
> > +	   jump targets.  */
> > +	if (INSN_P (insn)
> > +	    && find_reg_note (insn, REG_LABEL_OPERAND, NULL_RTX))
> > +	  return 1;
> > +
> >  	/* If this function has a computed jump, then we consider the cfg
> >  	   not well structured.  */
> > -	else if (JUMP_P (insn) && computed_jump_p (insn))
> > +	if (JUMP_P (insn) && computed_jump_p (insn))
> >  	  return 1;
> >        }
> 
> Why did you drop the check on NEXT_INSN altogether?

Because that old code was sloppily only trying to deal with the
immediately consecutive (no notes or anything in-between!) insn
pair (set branch-target-reg label) (set pc branch-target-reg) as
a non-computed jump (the whole REG_LABEL ambiguity).  Hm, the
new code will still have a REG_LABEL_OPERAND on the (set
branch-target-reg label) so that'll always be seen as
is_cfg_nonregular.  Will investigate the impact and how to merge
identifiable set/jump pairs as non-computed.  I hope REG_DEAD
notes are present here...

brgds, H-P

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFA:] Split REG_LABEL into REG_LABEL_TARGET and REG_LABEL_OPERAND
  2007-09-13  3:17       ` Hans-Peter Nilsson
@ 2007-09-13 13:15         ` Eric Botcazou
  0 siblings, 0 replies; 13+ messages in thread
From: Eric Botcazou @ 2007-09-13 13:15 UTC (permalink / raw)
  To: Hans-Peter Nilsson; +Cc: gcc-patches

> > You're not updating label_is_jump_target_p to take into account the
> > operands of REG_LABEL_TARGET notes, so can't you be creating
> > REG_LABEL_OPERAND notes for them?
>
> (I assume you mean s/can't/shouldn't/ and "REG_LABEL_TARGET
> notes for them".  If not, please rephrase the question.)

Can't the new code in find_reloads create REG_LABEL_OPERAND notes for operands 
of REG_LABEL_TARGET notes on the same insn, because label_is_jump_target_p 
only returns true for the JUMP_LABEL?

> If there's a problem, the remedy would be to update
> label_is_jump_target_p to be less simplified than its heading
> says; to handle REG_LABEL_TARGET notes. 

Yes, that was exactly what I was wondering about.

> They aren't supposed to (must not) be handled here.  This code
> is only for REG_LABEL_OPERAND notes needing to be updated;
> non-jump-insns moved around without notes being updated.  Same
> comment about label_is_jump_target_p maybe being too simple
> applies.  (Since you have to ask, this function needs a comment
> to this effect.)

Yes, it's again the non-handling of REG_LABEL_TARGET notes by 
label_is_jump_target_p that I was thinking of.

> It's the core machinery for targets with branch-target
> registers, to have the label recorded as a branch target before
> further optimizations moves the set and use of that register
> apart.  Otherwise, those branches will all be treated as
> computed jumps.  Hm, we'll still have the REG_LABEL_OPERAND note
> on the register load, but then again, so we did before too.
> I'll check that this still happens and add a comment actually
> mentioning "branch-target register"!

OK, but IIUC this is a new feature, isn't it?

> > Please add a small comment, one can easily think there is a typo in the
> > second part of the disjunction: JUMP_LABEL (insn) != label.
>
> Will do.

Thanks.

> > "Put in line with jump.c copy by only adding notes for labels actually
> > referenced in the insn" but AFAICS mark_jump_label doesn't do that.
>
> Uhm, it does; it iterates on the insn, and when it finds
> LABEL_REFs, it adds unique REG_LABEL_OPERAND notes (and sets the
> JUMP_LABEL field and emits REG_LABEL_TARGET notes, but they
> weren't the issue here).  It no longer emit duplicates.

AFAICS it iterates on X, not INSN, and never checks that X is mentioned in 
INSN like add_label_notes now does.

-- 
Eric Botcazou

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFA:] Split REG_LABEL into REG_LABEL_TARGET and REG_LABEL_OPERAND
  2007-09-09 10:47     ` Eric Botcazou
  2007-09-13  3:17       ` Hans-Peter Nilsson
@ 2007-11-14  0:24       ` Hans-Peter Nilsson
  2007-11-24 21:12         ` Eric Botcazou
  2007-11-15 12:14       ` Hans-Peter Nilsson
  2 siblings, 1 reply; 13+ messages in thread
From: Hans-Peter Nilsson @ 2007-11-14  0:24 UTC (permalink / raw)
  To: ebotcazou; +Cc: hans-peter.nilsson, gcc-patches

> From: Eric Botcazou <ebotcazou@libertysurf.fr>
> Date: Sun, 9 Sep 2007 11:00:37 +0200

(I replied to this your first comment rather than your last comment,
to fit better with the patch.  Sorry again for the delay.)

> > +++ gcc/reload.c	(working copy)
> > @@ -4103,13 +4103,18 @@ find_reloads (rtx insn, int replace, int

> You're not updating label_is_jump_target_p to take into account the operands 
> of REG_LABEL_TARGET notes, so can't you be creating REG_LABEL_OPERAND notes
> for them?

This and related comments are fixed in the patch for
label_is_jump_target_p below.

> Same question: what about operands of REG_LABEL_TARGET notes?

Ditto.

(reorg.c)
> 
> > @@ -2736,14 +2737,40 @@ fill_slots_from_thread (rtx insn, rtx co
> > +		      if (JUMP_P (trial) && JUMP_LABEL (trial))
> >  			LABEL_NUSES (XEXP (note, 0))++;
> 
> AFAICS note == NULL at this point (and it should be NULL_RTX instead of NULL).

I meant JUMP_LABEL (trial), doh.  See patch.

A bit odd that *none* of mips, mips64, cris and sh (all having branch
slots) hit this bug in testing but then again reorg.c does not lack
corner cases.

(jump.c)
> > @@ -172,34 +186,69 @@ static void
> >  mark_all_labels (rtx f)
> >  {
> >    rtx insn;
> > +  rtx prev_nonjump_insn = NULL;
> >
> >    for (insn = f; insn; insn = NEXT_INSN (insn))
> >      if (INSN_P (insn))
> >        {
> >  	mark_jump_label (PATTERN (insn), insn, 0);
> > -	if (! INSN_DELETED_P (insn) && JUMP_P (insn))
> > +
> > +	/* If the previous non-jump insn sets something to a label,
> > +	   something that this jump insn uses, make that label the primary
> > +	   target of this insn if we don't yet have any.  That previous
> > +	   insn must be a single_set and not refer to more than one label.
> > +	   The jump insn must not refer to other labels as jump targets
> > +	   and must be a plain (set (pc) ...), maybe in a parallel, and
> > +	   may refer to the item being set only directly or as one of the
> > +	   arms in an IF_THEN_ELSE.  */
> > +	if (! INSN_DELETED_P (insn)
> > +	    && JUMP_P (insn)
> > +	    && JUMP_LABEL (insn) == NULL)
> 
> Why do you need to do this?  Is it an optimization?

This code rarely hits these days (post DF), if ever.  I thought it was
just about necessary for targets with branch-target registers for
conditional branches like sh64 (unique in this aspect AFAICT) but that
target doesn't split the branch-target-register-load from the branch
until register allocation and by that time, JUMP_LABEL is safely set.
I instrumented the code with a gcc_unreachable, and this code only
hits for gcc.c-torture/compile/920501-7.c (for most targets).  If you
prefer, I can remove this code.  The situation may of course change if
more passes start calling mark_all_labels.

> 
> > @@ -976,17 +1050,21 @@ mark_jump_label (rtx x, rtx insn, int in
> >
> >  	if (insn)
> >  	  {
> > -	    if (JUMP_P (insn))
> > +	    if (is_target
> > +		&& (JUMP_LABEL (insn) == NULL || JUMP_LABEL (insn) == label))
> >  	      JUMP_LABEL (insn) = label;
> 
> Please add a small comment, one can easily think there is a typo in the second 
> part of the disjunction: JUMP_LABEL (insn) != label.

See patch.

(gcse.c)
> > @@ -4608,10 +4609,18 @@ add_label_notes (rtx x, rtx insn)
> >  	 We no longer ignore such label references (see LABEL_REF handling in
> >  	 mark_jump_label for additional information).  */
> >
> > -      REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL, XEXP (x, 0),
> > -					    REG_NOTES (insn));
> > -      if (LABEL_P (XEXP (x, 0)))
> > -	LABEL_NUSES (XEXP (x, 0))++;
> > +	if (reg_mentioned_p (XEXP (x, 0), insn))
> > +	  {
> > +	    /* There's no reason for current users to emit jump-insns
> > +	       with such a LABEL_REF, so we don't have to handle
> > +	       REG_LABEL_TARGET notes.  */
> > +	    gcc_assert (!JUMP_P (insn));
> > +	    REG_NOTES (insn)
> > +	      = gen_rtx_INSN_LIST (REG_LABEL_OPERAND, XEXP (x, 0),
> > +				   REG_NOTES (insn));
> > +	    if (LABEL_P (XEXP (x, 0)))
> > +	      LABEL_NUSES (XEXP (x, 0))++;
> > +	  }
> >        return;
> >      }
> 
> "Put in line with jump.c copy by only adding notes for labels actually 
> referenced in the insn" but AFAICS mark_jump_label doesn't do that.

Quite so.  Conditional removed in the patch.  I experimented with
replacing it with an gcc_assert (reg_mentioned_p (XEXP (x, 0), insn)),
and also a corresponding one in mark_jump_label_1, but the latter hits
for arm/thumb when loading a label from the constant pool and also for
the load-label-feed-jump code above (doh).  Anyway, for 130081 there
was only one caller of the static function add_label_notes, so an
assert didn't seem very necessary.

> 
> > Index: gcc/sched-rgn.c

> Why did you drop the check on NEXT_INSN altogether?

(Not yet fixed; may "only" affect optimization.  I'm on it.)

Please consider this patch for all but the last issue, built and
tested natively for x86_64-unknown-linux-gnu (without multilibs due to
lack of 32-bit libs) and regtested using btest-gcc.sh (with fortran as
applicable with my BTEST_GCC_EXTRA_TESTLOGS patch) for
 cris-elf
 mmix-knuth-mmixware
 sh64-elf (no fortran; 130081 ICEd building libgfortran/generated/matmul_r4.c)
 arm-elf
 v850-elf
 sh-elf (no fortran; ICE for generated/_sign_r8.F90)
 mips-elf
 mips64-elf

Ok to commit?

gcc:
	* rtlanal.c (label_is_jump_target_p): Return true for a matching
	REG_LABEL_TARGET.
	* reorg.c (fill_slots_from_thread): Correct last change to use
	NULL_RTX, not NULL.  Outside of REG_NOTES loop, increase and
	decrease LABEL_NUSES for JUMP_LABEL (trial), not XEXP (note, 0).
	* jump.c (mark_jump_label_1): Add comment for last change
	regarding JUMP_LABEL setting.
	* gcse.c (add_label_notes): Remove conditional that the label is
	mentioned in insn before adding regnote.

Index: rtlanal.c
===================================================================
--- rtlanal.c	(revision 130159)
+++ rtlanal.c	(working copy)
@@ -3434,6 +3434,9 @@ label_is_jump_target_p (const_rtx label,
 	  return true;
     }
 
+  if (find_reg_note (jump_insn, REG_LABEL_TARGET, label))
+    return true;
+
   return false;
 }
 
Index: reorg.c
===================================================================
--- reorg.c	(revision 130159)
+++ reorg.c	(working copy)
@@ -2740,7 +2740,7 @@ fill_slots_from_thread (rtx insn, rtx co
 			 temporarily increment the use count on any referenced
 			 label lest it be deleted by delete_related_insns.  */
 		      for (note = REG_NOTES (trial);
-			   note != NULL;
+			   note != NULL_RTX;
 			   note = XEXP (note, 1))
 			if (REG_NOTE_KIND (note) == REG_LABEL_OPERAND
 			    || REG_NOTE_KIND (note) == REG_LABEL_TARGET)
@@ -2754,12 +2754,12 @@ fill_slots_from_thread (rtx insn, rtx co
 					  == REG_LABEL_OPERAND);
 			  }
 		      if (JUMP_P (trial) && JUMP_LABEL (trial))
-			LABEL_NUSES (XEXP (note, 0))++;
+			LABEL_NUSES (JUMP_LABEL (trial))++;
 
 		      delete_related_insns (trial);
 
 		      for (note = REG_NOTES (trial);
-			   note != NULL;
+			   note != NULL_RTX;
 			   note = XEXP (note, 1))
 			if (REG_NOTE_KIND (note) == REG_LABEL_OPERAND
 			    || REG_NOTE_KIND (note) == REG_LABEL_TARGET)
@@ -2773,7 +2773,7 @@ fill_slots_from_thread (rtx insn, rtx co
 					  == REG_LABEL_OPERAND);
 			  }
 		      if (JUMP_P (trial) && JUMP_LABEL (trial))
-			LABEL_NUSES (XEXP (note, 0))--;
+			LABEL_NUSES (JUMP_LABEL (trial))--;
 		    }
 		  else
 		    new_thread = next_active_insn (trial);
Index: jump.c
===================================================================
--- jump.c	(revision 130159)
+++ jump.c	(working copy)
@@ -1051,6 +1051,9 @@ mark_jump_label_1 (rtx x, rtx insn, bool
 	if (insn)
 	  {
 	    if (is_target
+		/* Do not change a previous setting of JUMP_LABEL.  If the
+		   JUMP_LABEL slot is occupied by a different label,
+		   create a note for this label.  */
 		&& (JUMP_LABEL (insn) == NULL || JUMP_LABEL (insn) == label))
 	      JUMP_LABEL (insn) = label;
 	    else
Index: gcse.c
===================================================================
--- gcse.c	(revision 130159)
+++ gcse.c	(working copy)
@@ -4613,18 +4613,16 @@ add_label_notes (rtx x, rtx insn)
 	 We no longer ignore such label references (see LABEL_REF handling in
 	 mark_jump_label for additional information).  */
 
-	if (reg_mentioned_p (XEXP (x, 0), insn))
-	  {
-	    /* There's no reason for current users to emit jump-insns
-	       with such a LABEL_REF, so we don't have to handle
-	       REG_LABEL_TARGET notes.  */
-	    gcc_assert (!JUMP_P (insn));
-	    REG_NOTES (insn)
-	      = gen_rtx_INSN_LIST (REG_LABEL_OPERAND, XEXP (x, 0),
-				   REG_NOTES (insn));
-	    if (LABEL_P (XEXP (x, 0)))
-	      LABEL_NUSES (XEXP (x, 0))++;
-	  }
+      /* There's no reason for current users to emit jump-insns with
+	 such a LABEL_REF, so we don't have to handle REG_LABEL_TARGET
+	 notes.  */
+      gcc_assert (!JUMP_P (insn));
+      REG_NOTES (insn)
+	= gen_rtx_INSN_LIST (REG_LABEL_OPERAND, XEXP (x, 0),
+			     REG_NOTES (insn));
+      if (LABEL_P (XEXP (x, 0)))
+	LABEL_NUSES (XEXP (x, 0))++;
+
       return;
     }
 


brgds, H-P

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFA:] Split REG_LABEL into REG_LABEL_TARGET and REG_LABEL_OPERAND
  2007-09-09 10:47     ` Eric Botcazou
  2007-09-13  3:17       ` Hans-Peter Nilsson
  2007-11-14  0:24       ` Hans-Peter Nilsson
@ 2007-11-15 12:14       ` Hans-Peter Nilsson
  2007-11-24 21:16         ` Eric Botcazou
  2 siblings, 1 reply; 13+ messages in thread
From: Hans-Peter Nilsson @ 2007-11-15 12:14 UTC (permalink / raw)
  To: ebotcazou; +Cc: hans-peter.nilsson, gcc-patches

This and
<http://gcc.gnu.org/ml/gcc-patches/2007-11/msg00755.html> (the
previous patch by the same subject) should be considered before
4.3 branches.

:ADDPATCH middle-end:

> From: Eric Botcazou <ebotcazou@libertysurf.fr>
> Date: Sun, 9 Sep 2007 11:00:37 +0200

> > Index: gcc/sched-rgn.c
> > ===================================================================
> > --- gcc/sched-rgn.c	(revision 128285)
> > +++ gcc/sched-rgn.c	(working copy)
> > @@ -315,24 +315,20 @@ is_cfg_nonregular (void)
> >    if (current_function_has_exception_handlers ())
> >      return 1;
> >
> > -  /* If we have non-jumping insns which refer to labels, then we consider
> > -     the cfg not well structured.  */
> > +  /* If we have insns which refer to labels as non-jumped-to operands,
> > +     then we consider the cfg not well structured.  */
> >    FOR_EACH_BB (b)
> >      FOR_BB_INSNS (b, insn)
> >        {
> > -	/* Check for labels referred by non-jump insns.  */
> > -	if (NONJUMP_INSN_P (insn) || CALL_P (insn))
> > -	  {
> > -	    rtx note = find_reg_note (insn, REG_LABEL, NULL_RTX);
> > -	    if (note
> > -		&& ! (JUMP_P (NEXT_INSN (insn))
> > -		      && find_reg_note (NEXT_INSN (insn), REG_LABEL,
> > -					XEXP (note, 0))))
> > -	      return 1;
> > -	  }
> > +	/* Check for labels referred to but (at least not directly) as
> > +	   jump targets.  */
> > +	if (INSN_P (insn)
> > +	    && find_reg_note (insn, REG_LABEL_OPERAND, NULL_RTX))
> > +	  return 1;
> > +
> >  	/* If this function has a computed jump, then we consider the cfg
> >  	   not well structured.  */
> > -	else if (JUMP_P (insn) && computed_jump_p (insn))
> > +	if (JUMP_P (insn) && computed_jump_p (insn))
> >  	  return 1;
> >        }
> 
> Why did you drop the check on NEXT_INSN altogether?

An oversight; the code seemed redundant with the next iteration,
but on closer inspection it wasn't. However, the case you refer
to is rarely executed for most targets, at least after the rest
of the REG_LABEL_* patches, now after DF.

(FWIW, the code was incomplet and buggy too: all you had to have
were two insns next to each other, both mentioning the same
label, with the second one being a jump.  Liveness was not
considered, neither was whether the second insn actually had
anything to do with (was fed by) the first insn.)

I instrumented the code as follows (on top of the patches
mentioned above):

Index: sched-rgn.c
===================================================================
--- sched-rgn.c	(revision 130081)
+++ sched-rgn.c	(working copy)
@@ -320,12 +320,22 @@
   FOR_EACH_BB (b)
     FOR_BB_INSNS (b, insn)
       {
-	/* Check for labels referred to but (at least not directly) as
-	   jump targets.  */
-	if (INSN_P (insn)
-	    && find_reg_note (insn, REG_LABEL_OPERAND, NULL_RTX))
-	  return 1;
+	rtx note = find_reg_note (insn, REG_LABEL_OPERAND, NULL_RTX);
 
+	if (note != NULL_RTX && INSN_P (insn))
+	  {
+	    /* To matter, this must be a single-set feeding a jump
+	       *only*.  But let's ignore that, because the old code
+	       certainly ignored that...  */
+	    rtx next = next_nonnote_insn (insn);
+	    if (next == NULL_RTX
+		|| !JUMP_P (next)
+		|| JUMP_LABEL (next) != XEXP (note, 0))
+	      return 1;
+
+	    gcc_unreachable (); /* not returning 1 for this note. */
+	  }
+
 	/* If this function has a computed jump, then we consider the cfg
 	   not well structured.  */
 	if (JUMP_P (insn) && computed_jump_p (insn))


Testing the instrumented code on native x86_64-unknown-linux-gnu
and crosses to mips-elf, sh64-elf(!), cris-elf showed no
regressions.  But for sh-elf, it trigged in sched1 when building
newlib; a label load was feeding a casesi insn.  The combination
seemed valid, but I was a bit surprised to see it not trig for
sh64.

Below is a patch to reinstate the intention of the previous code
AFAICT, hopefully without the bugs.  A step-through with gdb
says it catches the sh case.  Regtested natively for
x86_64-unknown-linux-gnu (without multilibs due to lack of
32-bit libs) and regtested using btest-gcc.sh (with fortran as
applicable with my BTEST_GCC_EXTRA_TESTLOGS patch) cross to
 cris-elf
 mmix-knuth-mmixware
 sh64-elf (no fortran; 130081 ICEd building libgfortran/generated/matmul_r4.c)
 arm-elf
 v850-elf
 sh-elf (no fortran; ICE for generated/_sign_r8.F90)
 mips-elf
 mips64-elf

Ok to commit?

gcc:
	* sched-rgn.c (is_cfg_nonregular): Don't return 1 for a
	single_set insn only feeding a label to a jump through a
	register that dies there.

Index: sched-rgn.c
===================================================================
--- sched-rgn.c	(revision 130159)
+++ sched-rgn.c	(working copy)
@@ -320,16 +320,40 @@ is_cfg_nonregular (void)
   FOR_EACH_BB (b)
     FOR_BB_INSNS (b, insn)
       {
-	/* Check for labels referred to but (at least not directly) as
-	   jump targets.  */
-	if (INSN_P (insn)
-	    && find_reg_note (insn, REG_LABEL_OPERAND, NULL_RTX))
-	  return 1;
+	rtx note, next, set, dest;
 
 	/* If this function has a computed jump, then we consider the cfg
 	   not well structured.  */
 	if (JUMP_P (insn) && computed_jump_p (insn))
 	  return 1;
+
+	if (!INSN_P (insn))
+	  continue;
+
+	note = find_reg_note (insn, REG_LABEL_OPERAND, NULL_RTX);
+	if (note == NULL_RTX)
+	  continue;
+
+	/* For that label not to be seen as a referred-to label, this
+	   must be a single-set which is feeding a jump *only*.  This
+	   could be a conditional jump with the label split off for
+	   machine-specific reasons or a casesi/tablejump.  */
+	next = next_nonnote_insn (insn);
+	if (next == NULL_RTX
+	    || !JUMP_P (next)
+	    || (JUMP_LABEL (next) != XEXP (note, 0)
+		&& find_reg_note (next, REG_LABEL_TARGET,
+				  XEXP (note, 0)) == NULL_RTX)
+	    || BLOCK_FOR_INSN (insn) != BLOCK_FOR_INSN (next))
+	  return 1;
+
+	set = single_set (insn);
+	if (set == NULL_RTX)
+	  return 1;
+
+	dest = SET_DEST (set);
+	if (!REG_P (dest) || !dead_or_set_p (next, dest))
+	  return 1;
       }
 
   /* Unreachable loops with more than one basic block are detected

brgds, H-P

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFA:] Split REG_LABEL into REG_LABEL_TARGET and REG_LABEL_OPERAND
  2007-11-14  0:24       ` Hans-Peter Nilsson
@ 2007-11-24 21:12         ` Eric Botcazou
  0 siblings, 0 replies; 13+ messages in thread
From: Eric Botcazou @ 2007-11-24 21:12 UTC (permalink / raw)
  To: Hans-Peter Nilsson; +Cc: gcc-patches

[Sorry for the delay too. :-)]

> This code rarely hits these days (post DF), if ever.  I thought it was
> just about necessary for targets with branch-target registers for
> conditional branches like sh64 (unique in this aspect AFAICT) but that
> target doesn't split the branch-target-register-load from the branch
> until register allocation and by that time, JUMP_LABEL is safely set.
> I instrumented the code with a gcc_unreachable, and this code only
> hits for gcc.c-torture/compile/920501-7.c (for most targets).  If you
> prefer, I can remove this code.  The situation may of course change if
> more passes start calling mark_all_labels.

OK, let's keep it then.

> 	* rtlanal.c (label_is_jump_target_p): Return true for a matching
> 	REG_LABEL_TARGET.
> 	* reorg.c (fill_slots_from_thread): Correct last change to use
> 	NULL_RTX, not NULL.  Outside of REG_NOTES loop, increase and
> 	decrease LABEL_NUSES for JUMP_LABEL (trial), not XEXP (note, 0).

OK for mainline, thanks for following up on this.

-- 
Eric Botcazou

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFA:] Split REG_LABEL into REG_LABEL_TARGET and REG_LABEL_OPERAND
  2007-11-15 12:14       ` Hans-Peter Nilsson
@ 2007-11-24 21:16         ` Eric Botcazou
  0 siblings, 0 replies; 13+ messages in thread
From: Eric Botcazou @ 2007-11-24 21:16 UTC (permalink / raw)
  To: Hans-Peter Nilsson; +Cc: gcc-patches

> :ADDPATCH middle-end:

rtl-optimization, otherwise I cannot approve it. :-)

> Testing the instrumented code on native x86_64-unknown-linux-gnu
> and crosses to mips-elf, sh64-elf(!), cris-elf showed no
> regressions.  But for sh-elf, it trigged in sched1 when building
> newlib; a label load was feeding a casesi insn.  The combination
> seemed valid, but I was a bit surprised to see it not trig for
> sh64.

Thanks for conducting the experiment.

> 	* sched-rgn.c (is_cfg_nonregular): Don't return 1 for a
> 	single_set insn only feeding a label to a jump through a
> 	register that dies there.

OK.


:REVIEWMAIL:

-- 
Eric Botcazou

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2007-11-24 17:01 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-01-30 20:54 [RFA:] Split REG_LABEL into REG_LABEL_TARGET and REG_LABEL_OPERAND Hans-Peter Nilsson
2006-01-30 21:31 ` Hans-Peter Nilsson
2006-01-30 22:18 ` Hans-Peter Nilsson
2006-02-25  0:05 ` Geoffrey Keating
2007-09-04  5:12 ` [RFA:] " Hans-Peter Nilsson
2007-09-09  7:13   ` Hans-Peter Nilsson
2007-09-09 10:47     ` Eric Botcazou
2007-09-13  3:17       ` Hans-Peter Nilsson
2007-09-13 13:15         ` Eric Botcazou
2007-11-14  0:24       ` Hans-Peter Nilsson
2007-11-24 21:12         ` Eric Botcazou
2007-11-15 12:14       ` Hans-Peter Nilsson
2007-11-24 21:16         ` Eric Botcazou

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).