From 64b31cb6db389a16a38288a5d2944dc0c6e51080 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Fri, 23 May 2014 18:03:08 -0400
Subject: [PATCH 2/5] Introduce rtx_code_label subclass of rtx_def

Add an rtx_code_label subclass of rtx_def.

This doesn't add any fields, merely the invariant that:

	GET_CODE (X) == CODE_LABEL

Strengthen fields of core types to be rtx_code_label * rather than
an rtx:

	(struct rtl_data) x_return_label
	(struct rtl_data) x_naked_return_label
	(struct hwloop_info_d): end_label

Update various APIs to require an rtx_code_label * rather than
an rtx:

	jumpifnot
	jumpifnot_1
	jumpif
	jumpif_1
	do_jump
	do_jump_1
	do_compare_rtx_and_jump
	emit_label_before

and update various APIs to return an rtx_code_label * rather than
an rtx:

	gen_label_rtx
	emit_label_before
	label_rtx
	force_label_rtx

Doing so required touching the following target-specific code:

	* config/bfin/bfin.c
	* config/c6x/c6x.c
	* config/mep/mep.c
	* config/spu/spu.c
	* config/sh/sh.c

gcc/
	* rtl.h: Include is-a.h
	(struct rtx_def): Add dummy "desc" and "tag" GTY options as a
	workaround to ensure gengtype knows inheritance is occurring,
	whilst continuing to use the pre-existing special-casing for
	rtx_def.
	(struct rtx_code_label): New subclass of rtx_def, adding the
	invariant that GET_CODE (X) == CODE_LABEL.
	(is_a_helper <rtx_code_label *>::test): New.
	(NULL_RTX_CODE_LABEL): New.
	(gen_label_rtx): Strengthen return type from rtx to
	rtx_code_label *.
	(emit_label_before): Likewise; also similarly strengthen param
	"label".

	* coretypes.h (rtx_code_label): Add forward declaration.

	* basic-block.h (block_label): Strengthen return type from rtx to
	rtx_code_label *.

	* expr.h (jumpifnot): Strengthen param from rtx to
	rtx_code_label *.
	(jumpifnot_1): Likewise.
	(jumpif): Likewise.
	(jumpif_1): Likewise.
	(do_jump): Likewise (two params).
	(do_jump_1): Likewise.
	(do_compare_rtx_and_jump): Likewise.
	(label_rtx): Strengthen return type from rtx to rtx_code_label *.
	(force_label_rtx): Likewise.

	* function.h (struct rtl_data): Strengthen fields "x_return_label"
	and "x_naked_return_label" from rtx to rtx_code_label *.

	* hw-doloop.h (struct hwloop_info_d): Strengthen field "end_label"
	from rtx to rtx_code_label *.

	* builtins.c (expand_errno_check): Strengthen local "lab" from rtx
	to rtx_code_label *.
	* cfgexpand.c (lab_rtx_for_bb): Strengthen from pointer_map<rtx> to
	pointer_map<rtx_code_label *>.
	(label_rtx_for_bb): Strengthen return type from rtx to
	rtx_code_label *.
	(expand_gimple_basic_block): Update local "elt" for strengthening
	of type of lab_rtx_for_bb.
	(pass_expand::execute): Update construction of lab_rtx_for_bb to
	reflect new type.

	* cfgrtl.c (block_label): Strengthen return type from rtx to
	rtx_code_label *.
	(rtl_lv_add_condition_to_bb): Strengthen local "label" from rtx
	to rtx_code_label *.  Update call to do_compare_rtx_and_jump to
	use NULL_RTX_CODE_LABEL rather than NULL_RTX.

	* dojump.c (jumpifnot): Strengthen param "label" from rtx to
	rtx_code_label *.
	(jumpifnot_1): Likewise.
	(jumpif): Likewise.
	(jumpif_1): Likewise.
	(do_jump_1): Likewise for params "if_false_label" and
	"if_true_label" and for local "drop_through_label"; use
	NULL_RTX_CODE_LABEL rather than NULL_RTX as appropriate.
	(do_jump): Likewise, with locals "label1", "set_label" and
	"clr_label".
	(do_jump_by_parts_greater_rtx): Likewise, and for local
	"drop_through_label".
	(do_jump_by_parts_greater): Likewise.
	(do_jump_by_parts_zero_rtx): Likewise.
	(do_jump_by_parts_equality_rtx): Likewise.
	(do_jump_by_parts_equality): Likewise.
	(do_compare_rtx_and_jump): Likewise, and for locals
	"dummy_label" and "dest_label.  Eliminate top-level local "tem" in
	favor of more tightly scoped locals, strengthening one from rtx to
	rtx_code_label *.
	(do_compare_and_jump): Likewise.

	* emit-rtl.c (gen_label_rtx): Strengthen return type from rtx to
	rtx_code_label *.
	(emit_label_before): Likewise; also similarly strengthen param "label".

	* expmed.c (expand_smod_pow2): Strengthen local "label" from rtx to
	rtx_code_label *.
	(expand_sdiv_pow2): Likewise.
	(expand_divmod): Likewise; also for the locals "label1" through
	"label5", "lab", and all of the multiple locals sharing these
	names in various scopes within this function.
	(emit_store_flag_force): Likewise for local "label".  Update call
	to do_compare_rtx_and_jump to use NULL_RTX_CODE_LABEL rather than
	NULL_RTX.
	(do_cmp_and_jump): Strengthen param "label" from rtx to
	rtx_code_label *. Update call to do_compare_rtx_and_jump to
	use NULL_RTX_CODE_LABEL rather than NULL_RTX.

	* expr.c (store_expr): Likewise for locals "lab1" and "lab2".
	(store_constructor): Likewise for locals "loop_start" and
	"loop_end".
	(expand_expr_real_2): Update call to do_compare_rtx_and_jump to use
	NULL_RTX_CODE_LABEL rather than NULL_RTX.  Introduce locals
	"op_label0" and "op_label1" and use in place of "op0" and "op1"
	where the rtx is known to be a CODE_LABEL.
	(expand_expr_real_1): Strengthen local "label" from rtx to
	rtx_code_label *.

	* loop-doloop.c (add_test): Strengthen local "label" from rtx to
	rtx_code_label *.  Update call to do_compare_rtx_and_jump to use
	NULL_RTX_CODE_LABEL rather than NULL_RTX.

	* loop-unroll.c (compare_and_jump_seq): Strengthen param "label"
	from rtx to rtx_code_label *.  Update call to
	do_compare_rtx_and_jump to use NULL_RTX_CODE_LABEL rather than
	NULL_RTX.

	* optabs.c (expand_doubleword_shift): Strengthen locals
	"subword_label" and "done_label" from rtx to rtx_code_label *.
	(expand_abs): Likewise for local "op1".  Update call to
	do_compare_rtx_and_jump to use NULL_RTX_CODE_LABEL rather than
	NULL_RTX.

	* stmt.c (label_rtx): Strengthen return type from rtx to
	rtx_code_label *, adding a checked cast.
	(force_label_rtx): Strengthen return type from rtx to
	rtx_code_label *.
	(do_jump_if_equal): Strengthen param "label" from rtx to
	rtx_code_label *.  Update call to do_compare_rtx_and_jump to
	use NULL_RTX_CODE_LABEL rather than NULL_RTX.
	(expand_sjlj_dispatch_table): Strengthen local "lab" from rtx to
	rtx_code_label *.

	* config/bfin/bfin.c (hwloop_optimize): Strengthen local
	"end_label" from rtx to rtx_code_label *.

	* config/c6x/c6x.c (reorg_split_calls): Strengthen param
	"call_labels" from rtx * to rtx_code_label **; strengthen local
	"label" from rtx to rtx_code_label *.
	(reorg_emit_nops): Strengthen param "call_labels" from rtx * to
	rtx_code_label **.
	(c6x_reorg): Strengthen local "label" from rtx * to
	rtx_code_label **.

	* config/mep/mep.c (mep_insert_repeat_label_last): Strengthen param
	"label" from rtx to rtx_code_label *.
	(mep_reorg_repeat): Strengthen local "repeat_label" from rtx to
	rtx_code_label *.
	(mep_reorg_erepeat): Strengthen local "l" from rtx to
	rtx_code_label *.

	* config/sh/sh.c (add_constant): Strengthen return type from rtx
	to rtx_code_label *; likewise for locals "lab" and "new_rtx".
	(struct label_ref_list_d): Strengthen field "label" from rtx to
	rtx_code_label *.
	(pool_node): Likewise.
	(pool_window_label): Strengthen from rtx to rtx_code_label *.
	(dump_table): Strengthen local "lab" from rtx to rtx_code_label *.
	Add checked casts to rtx_code_label * to each of the 6 iterations
	that walk the chain of labels within a pool: although this uses
	LABEL_REFS, this chain consists of CODE_LABEL nodes (it is
	constructed by add_constant).  Update NULLing of pool_window_label
	to use NULL_RTX_CODE_LABEL rather than NULL_RTX.

	* config/spu/spu.c (spu_emit_branch_hint): Strengthen local
	"branch_label" from rtx to an rtx_code_label *, splitting out
	uses as a LABEL_REF into a new local "branch_label_ref".
---
 gcc/basic-block.h      |   2 +-
 gcc/builtins.c         |   4 +-
 gcc/cfgexpand.c        |  10 ++--
 gcc/cfgrtl.c           |  11 +++--
 gcc/config/bfin/bfin.c |   3 +-
 gcc/config/c6x/c6x.c   |  10 ++--
 gcc/config/mep/mep.c   |  12 +++--
 gcc/config/sh/sh.c     |  40 +++++++++------
 gcc/config/spu/spu.c   |   7 +--
 gcc/coretypes.h        |   5 ++
 gcc/dojump.c           | 129 ++++++++++++++++++++++++++++---------------------
 gcc/emit-rtl.c         |  11 +++--
 gcc/expmed.c           |  40 ++++++++-------
 gcc/expr.c             |  32 ++++++------
 gcc/expr.h             |  20 ++++----
 gcc/function.h         |   4 +-
 gcc/hw-doloop.h        |   2 +-
 gcc/loop-doloop.c      |   5 +-
 gcc/loop-unroll.c      |   6 +--
 gcc/optabs.c           |   7 +--
 gcc/rtl.h              |  45 +++++++++++++++--
 gcc/stmt.c             |  18 ++++---
 22 files changed, 257 insertions(+), 166 deletions(-)

diff --git a/gcc/basic-block.h b/gcc/basic-block.h
index 0bf6e87..5d06822 100644
--- a/gcc/basic-block.h
+++ b/gcc/basic-block.h
@@ -786,7 +786,7 @@ extern bitmap compute_idf (bitmap, struct bitmap_head *);
 extern basic_block * single_pred_before_succ_order (void);
 
 /* In cfgrtl.c  */
-extern rtx block_label (basic_block);
+extern rtx_code_label *block_label (basic_block);
 extern rtx bb_note (basic_block);
 extern bool purge_all_dead_edges (void);
 extern bool purge_dead_edges (basic_block);
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 140d6ba..49618bf 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -1995,12 +1995,12 @@ mathfn_built_in (tree type, enum built_in_function fn)
 static void
 expand_errno_check (tree exp, rtx target)
 {
-  rtx lab = gen_label_rtx ();
+  rtx_code_label *lab = gen_label_rtx ();
 
   /* Test the result; if it is NaN, set errno=EDOM because
      the argument was not in the domain.  */
   do_compare_rtx_and_jump (target, target, EQ, 0, GET_MODE (target),
-			   NULL_RTX, NULL_RTX, lab,
+			   NULL_RTX, NULL_RTX_CODE_LABEL, lab,
 			   /* The jump is very likely.  */
 			   REG_BR_PROB_BASE - (REG_BR_PROB_BASE / 2000 - 1));
 
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index d124d94..b51894f 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -1956,17 +1956,17 @@ maybe_dump_rtl_for_gimple_stmt (gimple stmt, rtx since)
 
 /* Maps the blocks that do not contain tree labels to rtx labels.  */
 
-static struct pointer_map<rtx> *lab_rtx_for_bb;
+static struct pointer_map<rtx_code_label *> *lab_rtx_for_bb;
 
 /* Returns the label_rtx expression for a label starting basic block BB.  */
 
-static rtx
+static rtx_code_label *
 label_rtx_for_bb (basic_block bb ATTRIBUTE_UNUSED)
 {
   gimple_stmt_iterator gsi;
   tree lab;
   gimple lab_stmt;
-  rtx *elt;
+  rtx_code_label **elt;
 
   if (bb->flags & BB_RTL)
     return block_label (bb);
@@ -4880,7 +4880,7 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
   rtx note, last;
   edge e;
   edge_iterator ei;
-  rtx *elt;
+  rtx_code_label **elt;
 
   if (dump_file)
     fprintf (dump_file, "\n;; Generating RTL for gimple basic block %d\n",
@@ -5797,7 +5797,7 @@ pass_expand::execute (function *fun)
   FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR_FOR_FN (fun)->succs)
     e->flags &= ~EDGE_EXECUTABLE;
 
-  lab_rtx_for_bb = new pointer_map <rtx>;
+  lab_rtx_for_bb = new pointer_map <rtx_code_label *>;
   FOR_BB_BETWEEN (bb, init_block->next_bb, EXIT_BLOCK_PTR_FOR_FN (fun),
 		  next_bb)
     bb = expand_gimple_basic_block (bb, var_ret_seq != NULL_RTX);
diff --git a/gcc/cfgrtl.c b/gcc/cfgrtl.c
index 49faf2e..fe42bb3 100644
--- a/gcc/cfgrtl.c
+++ b/gcc/cfgrtl.c
@@ -972,18 +972,18 @@ rtl_can_merge_blocks (basic_block a, basic_block b)
 /* Return the label in the head of basic block BLOCK.  Create one if it doesn't
    exist.  */
 
-rtx
+rtx_code_label *
 block_label (basic_block block)
 {
   if (block == EXIT_BLOCK_PTR_FOR_FN (cfun))
-    return NULL_RTX;
+    return NULL_RTX_CODE_LABEL;
 
   if (!LABEL_P (BB_HEAD (block)))
     {
       BB_HEAD (block) = emit_label_before (gen_label_rtx (), BB_HEAD (block));
     }
 
-  return BB_HEAD (block);
+  return as_a <rtx_code_label *> (BB_HEAD (block));
 }
 
 /* Attempt to perform edge redirection by replacing possibly complex jump
@@ -4896,7 +4896,8 @@ rtl_lv_add_condition_to_bb (basic_block first_head ,
 			    basic_block second_head ATTRIBUTE_UNUSED,
 			    basic_block cond_bb, void *comp_rtx)
 {
-  rtx label, seq, jump;
+  rtx_code_label *label;
+  rtx seq, jump;
   rtx op0 = XEXP ((rtx)comp_rtx, 0);
   rtx op1 = XEXP ((rtx)comp_rtx, 1);
   enum rtx_code comp = GET_CODE ((rtx)comp_rtx);
@@ -4912,7 +4913,7 @@ rtl_lv_add_condition_to_bb (basic_block first_head ,
   op0 = force_operand (op0, NULL_RTX);
   op1 = force_operand (op1, NULL_RTX);
   do_compare_rtx_and_jump (op0, op1, comp, 0,
-			   mode, NULL_RTX, NULL_RTX, label, -1);
+			   mode, NULL_RTX, NULL_RTX_CODE_LABEL, label, -1);
   jump = get_last_insn ();
   JUMP_LABEL (jump) = label;
   LABEL_NUSES (label)++;
diff --git a/gcc/config/bfin/bfin.c b/gcc/config/bfin/bfin.c
index 7945de4..f1db052 100644
--- a/gcc/config/bfin/bfin.c
+++ b/gcc/config/bfin/bfin.c
@@ -3437,7 +3437,8 @@ hwloop_optimize (hwloop_info loop)
 {
   basic_block bb;
   rtx insn, last_insn;
-  rtx loop_init, start_label, end_label;
+  rtx loop_init, start_label;
+  rtx_code_label *end_label;
   rtx iter_reg, scratchreg, scratch_init, scratch_init_insn;
   rtx lc_reg, lt_reg, lb_reg;
   rtx seq, seq_end;
diff --git a/gcc/config/c6x/c6x.c b/gcc/config/c6x/c6x.c
index 339da13..6fa8a06 100644
--- a/gcc/config/c6x/c6x.c
+++ b/gcc/config/c6x/c6x.c
@@ -4849,7 +4849,7 @@ find_last_same_clock (rtx insn)
    the SEQUENCEs that represent execute packets.  */
 
 static void
-reorg_split_calls (rtx *call_labels)
+reorg_split_calls (rtx_code_label **call_labels)
 {
   unsigned int reservation_mask = 0;
   rtx insn = get_insns ();
@@ -4871,7 +4871,7 @@ reorg_split_calls (rtx *call_labels)
 
       if (returning_call_p (insn))
 	{
-	  rtx label = gen_label_rtx ();
+	  rtx_code_label *label = gen_label_rtx ();
 	  rtx labelref = gen_rtx_LABEL_REF (Pmode, label);
 	  rtx reg = gen_rtx_REG (SImode, RETURN_ADDR_REGNO);
 
@@ -5022,7 +5022,7 @@ reorg_split_calls (rtx *call_labels)
    scheduling was run earlier.  */
 
 static void
-reorg_emit_nops (rtx *call_labels)
+reorg_emit_nops (rtx_code_label **call_labels)
 {
   bool first;
   rtx prev, last_call;
@@ -5907,7 +5907,7 @@ static void
 c6x_reorg (void)
 {
   basic_block bb;
-  rtx *call_labels;
+  rtx_code_label **call_labels;
   bool do_selsched = (c6x_flag_schedule_insns2 && flag_selective_scheduling2
 		      && !maybe_skip_selective_scheduling ());
 
@@ -5953,7 +5953,7 @@ c6x_reorg (void)
     }
   sched_no_dce = false;
 
-  call_labels = XCNEWVEC (rtx, get_max_uid () + 1);
+  call_labels = XCNEWVEC (rtx_code_label *, get_max_uid () + 1);
 
   reorg_split_calls (call_labels);
 
diff --git a/gcc/config/mep/mep.c b/gcc/config/mep/mep.c
index 107f1fa..0dc16c7 100644
--- a/gcc/config/mep/mep.c
+++ b/gcc/config/mep/mep.c
@@ -199,7 +199,7 @@ static unsigned int mep_section_type_flags (tree, const char *, int);
 static void mep_asm_named_section (const char *, unsigned int, tree);
 static bool mep_mentioned_p (rtx, rtx, int);
 static void mep_reorg_regmove (rtx);
-static rtx mep_insert_repeat_label_last (rtx, rtx, bool, bool);
+static rtx mep_insert_repeat_label_last (rtx, rtx_code_label *, bool, bool);
 static void mep_reorg_repeat (rtx);
 static bool mep_invertable_branch_p (rtx);
 static void mep_invert_branch (rtx, rtx);
@@ -5013,8 +5013,8 @@ mep_reorg_regmove (rtx insns)
    Return the last instruction in the adjusted loop.  */
 
 static rtx
-mep_insert_repeat_label_last (rtx last_insn, rtx label, bool including,
-			      bool shared)
+mep_insert_repeat_label_last (rtx last_insn, rtx_code_label *label,
+			      bool including, bool shared)
 {
   rtx next, prev;
   int count = 0, code, icode;
@@ -5351,7 +5351,8 @@ mep_reorg_repeat (rtx insns)
     if (mep_repeat_loop_p (loop))
       {
 	/* Case (1) or (2).  */
-	rtx repeat_label, label_ref;
+	rtx_code_label *repeat_label;
+	rtx label_ref;
 
 	/* Create a new label for the repeat insn.  */
 	repeat_label = gen_label_rtx ();
@@ -5521,7 +5522,8 @@ mep_invert_branch (rtx insn, rtx after)
 static void
 mep_reorg_erepeat (rtx insns)
 {
-  rtx insn, prev, l, x;
+  rtx insn, prev, x;
+  rtx_code_label *l;
   int count;
 
   for (insn = insns; insn; insn = NEXT_INSN (insn))
diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c
index a0c4628..f467236 100644
--- a/gcc/config/sh/sh.c
+++ b/gcc/config/sh/sh.c
@@ -185,7 +185,7 @@ static bool shmedia_space_reserved_for_target_registers;
 static void split_branches (rtx);
 static int branch_dest (rtx);
 static void print_slot (rtx);
-static rtx add_constant (rtx, enum machine_mode, rtx);
+static rtx_code_label *add_constant (rtx, enum machine_mode, rtx);
 static void dump_table (rtx, rtx);
 static bool broken_move (rtx);
 static bool mova_p (rtx);
@@ -4506,7 +4506,7 @@ static alloc_pool label_ref_list_pool;
 
 typedef struct label_ref_list_d
 {
-  rtx label;
+  rtx_code_label *label;
   struct label_ref_list_d *next;
 } *label_ref_list_t;
 
@@ -4566,7 +4566,7 @@ typedef struct label_ref_list_d
 typedef struct
 {
   rtx value;			/* Value in table.  */
-  rtx label;			/* Label of value.  */
+  rtx_code_label *label;	/* Label of value.  */
   label_ref_list_t wend;	/* End of window.  */
   enum machine_mode mode;	/* Mode of value.  */
 
@@ -4582,7 +4582,7 @@ typedef struct
 #define MAX_POOL_SIZE 372
 static pool_node pool_vector[MAX_POOL_SIZE];
 static int pool_size;
-static rtx pool_window_label;
+static rtx_code_label *pool_window_label;
 static int pool_window_last;
 
 static int max_labelno_before_reorg;
@@ -4598,11 +4598,11 @@ static int max_labelno_before_reorg;
    necessary.  */
 
 /* Add a constant to the pool and return its label.  */
-static rtx
+static rtx_code_label *
 add_constant (rtx x, enum machine_mode mode, rtx last_value)
 {
   int i;
-  rtx lab, new_rtx;
+  rtx_code_label *lab, *new_rtx;
   label_ref_list_t ref, newref;
 
   /* First see if we've already got it.  */
@@ -4682,7 +4682,7 @@ dump_table (rtx start, rtx barrier)
   rtx scan = barrier;
   int i;
   bool need_align = true;
-  rtx lab;
+  rtx_code_label *lab;
   label_ref_list_t ref;
   bool have_df = false;
 
@@ -4699,7 +4699,9 @@ dump_table (rtx start, rtx barrier)
 	      scan = emit_insn_after (gen_align_2 (), scan);
 	      need_align = false;
 	    }
-	  for (lab = p->label; lab; lab = LABEL_REFS (lab))
+	  for (lab = p->label;
+	       lab;
+	       lab = as_a <rtx_code_label *> (LABEL_REFS (lab)))
 	    scan = emit_label_after (lab, scan);
 	  scan = emit_insn_after (gen_consttable_2 (p->value, const0_rtx),
 				  scan);
@@ -4749,7 +4751,9 @@ dump_table (rtx start, rtx barrier)
 	    case SFmode:
 	      if (align_insn && !p->part_of_sequence_p)
 		{
-		  for (lab = p->label; lab; lab = LABEL_REFS (lab))
+		  for (lab = p->label;
+		       lab;
+		       lab = as_a <rtx_code_label *> (LABEL_REFS (lab)))
 		    emit_label_before (lab, align_insn);
 		  emit_insn_before (gen_consttable_4 (p->value, const0_rtx),
 				    align_insn);
@@ -4765,7 +4769,9 @@ dump_table (rtx start, rtx barrier)
 		}
 	      else
 		{
-		  for (lab = p->label; lab; lab = LABEL_REFS (lab))
+		  for (lab = p->label;
+		       lab;
+		       lab = as_a <rtx_code_label *> (LABEL_REFS (lab)))
 		    scan = emit_label_after (lab, scan);
 		  scan = emit_insn_after (gen_consttable_4 (p->value,
 							    const0_rtx), scan);
@@ -4780,7 +4786,9 @@ dump_table (rtx start, rtx barrier)
 		  need_align = false;
 		}
 	    case DImode:
-	      for (lab = p->label; lab; lab = LABEL_REFS (lab))
+	      for (lab = p->label;
+		   lab;
+		   lab = as_a <rtx_code_label *> (LABEL_REFS (lab)))
 		scan = emit_label_after (lab, scan);
 	      scan = emit_insn_after (gen_consttable_8 (p->value, const0_rtx),
 				      scan);
@@ -4819,7 +4827,9 @@ dump_table (rtx start, rtx barrier)
 	      scan = emit_label_after (gen_label_rtx (), scan);
 	      scan = emit_insn_after (gen_align_4 (), scan);
 	    }
-	  for (lab = p->label; lab; lab = LABEL_REFS (lab))
+	  for (lab = p->label;
+	       lab;
+	       lab = as_a <rtx_code_label *> (LABEL_REFS (lab)))
 	    scan = emit_label_after (lab, scan);
 	  scan = emit_insn_after (gen_consttable_4 (p->value, const0_rtx),
 				  scan);
@@ -4832,7 +4842,9 @@ dump_table (rtx start, rtx barrier)
 	      scan = emit_label_after (gen_label_rtx (), scan);
 	      scan = emit_insn_after (gen_align_4 (), scan);
 	    }
-	  for (lab = p->label; lab; lab = LABEL_REFS (lab))
+	  for (lab = p->label;
+	       lab;
+	       lab = as_a <rtx_code_label *> (LABEL_REFS (lab)))
 	    scan = emit_label_after (lab, scan);
 	  scan = emit_insn_after (gen_consttable_8 (p->value, const0_rtx),
 				  scan);
@@ -4854,7 +4866,7 @@ dump_table (rtx start, rtx barrier)
   scan = emit_insn_after (gen_consttable_end (), scan);
   scan = emit_barrier_after (scan);
   pool_size = 0;
-  pool_window_label = NULL_RTX;
+  pool_window_label = NULL_RTX_CODE_LABEL;
   pool_window_last = 0;
 }
 
diff --git a/gcc/config/spu/spu.c b/gcc/config/spu/spu.c
index 41d3c2c..31698cc 100644
--- a/gcc/config/spu/spu.c
+++ b/gcc/config/spu/spu.c
@@ -2101,7 +2101,8 @@ static void
 spu_emit_branch_hint (rtx before, rtx branch, rtx target,
 		      int distance, sbitmap blocks)
 {
-  rtx branch_label = 0;
+  rtx_code_label *branch_label = 0;
+  rtx branch_label_ref;
   rtx hint;
   rtx insn;
   rtx table;
@@ -2122,10 +2123,10 @@ spu_emit_branch_hint (rtx before, rtx branch, rtx target,
   LABEL_NUSES (branch_label)++;
   LABEL_PRESERVE_P (branch_label) = 1;
   insn = emit_label_before (branch_label, branch);
-  branch_label = gen_rtx_LABEL_REF (VOIDmode, branch_label);
+  branch_label_ref = gen_rtx_LABEL_REF (VOIDmode, branch_label);
   bitmap_set_bit (blocks, BLOCK_FOR_INSN (branch)->index);
 
-  hint = emit_insn_before (gen_hbr (branch_label, target), before);
+  hint = emit_insn_before (gen_hbr (branch_label_ref, target), before);
   recog_memoized (hint);
   INSN_LOCATION (hint) = INSN_LOCATION (branch);
   HINTED_P (branch) = 1;
diff --git a/gcc/coretypes.h b/gcc/coretypes.h
index 41ad1a3..6465281 100644
--- a/gcc/coretypes.h
+++ b/gcc/coretypes.h
@@ -61,6 +61,11 @@ typedef const struct rtvec_def *const_rtvec;
 struct hwivec_def;
 typedef struct hwivec_def *hwivec;
 typedef const struct hwivec_def *const_hwivec;
+
+/* Subclasses of rtx_def.
+   Keep this list in the same order as in rtl.def.  */
+class rtx_code_label;
+
 union tree_node;
 typedef union tree_node *tree;
 typedef const union tree_node *const_tree;
diff --git a/gcc/dojump.c b/gcc/dojump.c
index 1748690..3a81ffb 100644
--- a/gcc/dojump.c
+++ b/gcc/dojump.c
@@ -37,10 +37,12 @@ along with GCC; see the file COPYING3.  If not see
 #include "tm_p.h"
 
 static bool prefer_and_bit_test (enum machine_mode, int);
-static void do_jump_by_parts_greater (tree, tree, int, rtx, rtx, int);
-static void do_jump_by_parts_equality (tree, tree, rtx, rtx, int);
-static void do_compare_and_jump	(tree, tree, enum rtx_code, enum rtx_code, rtx,
-				 rtx, int);
+static void do_jump_by_parts_greater (tree, tree, int, rtx_code_label *,
+				      rtx_code_label *, int);
+static void do_jump_by_parts_equality (tree, tree, rtx_code_label *,
+				       rtx_code_label *, int);
+static void do_compare_and_jump (tree, tree, enum rtx_code, enum rtx_code,
+				 rtx_code_label *, rtx_code_label *, int);
 
 /* Invert probability if there is any.  -1 stands for unknown.  */
 
@@ -127,29 +129,31 @@ restore_pending_stack_adjust (saved_pending_stack_adjust *save)
    functions here.  */
 
 void
-jumpifnot (tree exp, rtx label, int prob)
+jumpifnot (tree exp, rtx_code_label *label, int prob)
 {
-  do_jump (exp, label, NULL_RTX, inv (prob));
+  do_jump (exp, label, NULL_RTX_CODE_LABEL, inv (prob));
 }
 
 void
-jumpifnot_1 (enum tree_code code, tree op0, tree op1, rtx label, int prob)
+jumpifnot_1 (enum tree_code code, tree op0, tree op1, rtx_code_label *label,
+	     int prob)
 {
-  do_jump_1 (code, op0, op1, label, NULL_RTX, inv (prob));
+  do_jump_1 (code, op0, op1, label, NULL_RTX_CODE_LABEL, inv (prob));
 }
 
 /* Generate code to evaluate EXP and jump to LABEL if the value is nonzero.  */
 
 void
-jumpif (tree exp, rtx label, int prob)
+jumpif (tree exp, rtx_code_label *label, int prob)
 {
-  do_jump (exp, NULL_RTX, label, prob);
+  do_jump (exp, NULL_RTX_CODE_LABEL, label, prob);
 }
 
 void
-jumpif_1 (enum tree_code code, tree op0, tree op1, rtx label, int prob)
+jumpif_1 (enum tree_code code, tree op0, tree op1, rtx_code_label *label,
+	  int prob)
 {
-  do_jump_1 (code, op0, op1, NULL_RTX, label, prob);
+  do_jump_1 (code, op0, op1, NULL_RTX_CODE_LABEL, label, prob);
 }
 
 /* Used internally by prefer_and_bit_test.  */
@@ -201,10 +205,11 @@ prefer_and_bit_test (enum machine_mode mode, int bitnum)
 
 void
 do_jump_1 (enum tree_code code, tree op0, tree op1,
-	   rtx if_false_label, rtx if_true_label, int prob)
+	   rtx_code_label *if_false_label, rtx_code_label *if_true_label,
+	   int prob)
 {
   enum machine_mode mode;
-  rtx drop_through_label = 0;
+  rtx_code_label *drop_through_label = 0;
 
   switch (code)
     {
@@ -357,12 +362,12 @@ do_jump_1 (enum tree_code code, tree op0, tree op1,
         if (if_false_label == NULL_RTX)
           {
             drop_through_label = gen_label_rtx ();
-            do_jump (op0, drop_through_label, NULL_RTX, op0_prob);
-            do_jump (op1, NULL_RTX, if_true_label, op1_prob);
+            do_jump (op0, drop_through_label, NULL_RTX_CODE_LABEL, op0_prob);
+            do_jump (op1, NULL_RTX_CODE_LABEL, if_true_label, op1_prob);
           }
         else
           {
-            do_jump (op0, if_false_label, NULL_RTX, op0_prob);
+            do_jump (op0, if_false_label, NULL_RTX_CODE_LABEL, op0_prob);
             do_jump (op1, if_false_label, if_true_label, op1_prob);
           }
         break;
@@ -385,12 +390,12 @@ do_jump_1 (enum tree_code code, tree op0, tree op1,
         if (if_true_label == NULL_RTX)
           {
             drop_through_label = gen_label_rtx ();
-            do_jump (op0, NULL_RTX, drop_through_label, op0_prob);
-            do_jump (op1, if_false_label, NULL_RTX, op1_prob);
+            do_jump (op0, NULL_RTX_CODE_LABEL, drop_through_label, op0_prob);
+            do_jump (op1, if_false_label, NULL_RTX_CODE_LABEL, op1_prob);
           }
         else
           {
-            do_jump (op0, NULL_RTX, if_true_label, op0_prob);
+            do_jump (op0, NULL_RTX_CODE_LABEL, if_true_label, op0_prob);
             do_jump (op1, if_false_label, if_true_label, op1_prob);
           }
         break;
@@ -419,14 +424,15 @@ do_jump_1 (enum tree_code code, tree op0, tree op1,
    PROB is probability of jump to if_true_label, or -1 if unknown.  */
 
 void
-do_jump (tree exp, rtx if_false_label, rtx if_true_label, int prob)
+do_jump (tree exp, rtx_code_label *if_false_label,
+	 rtx_code_label *if_true_label, int prob)
 {
   enum tree_code code = TREE_CODE (exp);
   rtx temp;
   int i;
   tree type;
   enum machine_mode mode;
-  rtx drop_through_label = 0;
+  rtx_code_label *drop_through_label = 0;
 
   switch (code)
     {
@@ -476,7 +482,7 @@ do_jump (tree exp, rtx if_false_label, rtx if_true_label, int prob)
 
     case COND_EXPR:
       {
-	rtx label1 = gen_label_rtx ();
+	rtx_code_label *label1 = gen_label_rtx ();
 	if (!if_true_label || !if_false_label)
 	  {
 	    drop_through_label = gen_label_rtx ();
@@ -487,7 +493,7 @@ do_jump (tree exp, rtx if_false_label, rtx if_true_label, int prob)
 	  }
 
         do_pending_stack_adjust ();
-	do_jump (TREE_OPERAND (exp, 0), label1, NULL_RTX, -1);
+	do_jump (TREE_OPERAND (exp, 0), label1, NULL_RTX_CODE_LABEL, -1);
 	do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label, prob);
         emit_label (label1);
 	do_jump (TREE_OPERAND (exp, 2), if_false_label, if_true_label, prob);
@@ -531,7 +537,7 @@ do_jump (tree exp, rtx if_false_label, rtx if_true_label, int prob)
       if (integer_onep (TREE_OPERAND (exp, 1)))
 	{
 	  tree exp0 = TREE_OPERAND (exp, 0);
-	  rtx set_label, clr_label;
+	  rtx_code_label *set_label, *clr_label;
 	  int setclr_prob = prob;
 
 	  /* Strip narrowing integral type conversions.  */
@@ -660,11 +666,11 @@ do_jump (tree exp, rtx if_false_label, rtx if_true_label, int prob)
 
 static void
 do_jump_by_parts_greater_rtx (enum machine_mode mode, int unsignedp, rtx op0,
-			      rtx op1, rtx if_false_label, rtx if_true_label,
-			      int prob)
+			      rtx op1, rtx_code_label *if_false_label,
+			      rtx_code_label *if_true_label, int prob)
 {
   int nwords = (GET_MODE_SIZE (mode) / UNITS_PER_WORD);
-  rtx drop_through_label = 0;
+  rtx_code_label *drop_through_label = 0;
   bool drop_through_if_true = false, drop_through_if_false = false;
   enum rtx_code code = GT;
   int i;
@@ -711,7 +717,8 @@ do_jump_by_parts_greater_rtx (enum machine_mode mode, int unsignedp, rtx op0,
 
       /* All but high-order word must be compared as unsigned.  */
       do_compare_rtx_and_jump (op0_word, op1_word, code, (unsignedp || i > 0),
-			       word_mode, NULL_RTX, NULL_RTX, if_true_label,
+			       word_mode, NULL_RTX,
+			       NULL_RTX_CODE_LABEL, if_true_label,
 			       prob);
 
       /* Emit only one comparison for 0.  Do not emit the last cond jump.  */
@@ -720,7 +727,8 @@ do_jump_by_parts_greater_rtx (enum machine_mode mode, int unsignedp, rtx op0,
 
       /* Consider lower words only if these are equal.  */
       do_compare_rtx_and_jump (op0_word, op1_word, NE, unsignedp, word_mode,
-			       NULL_RTX, NULL_RTX, if_false_label, inv (prob));
+			       NULL_RTX, NULL_RTX_CODE_LABEL, if_false_label,
+			       inv (prob));
     }
 
   if (!drop_through_if_false)
@@ -736,7 +744,9 @@ do_jump_by_parts_greater_rtx (enum machine_mode mode, int unsignedp, rtx op0,
 
 static void
 do_jump_by_parts_greater (tree treeop0, tree treeop1, int swap,
-			  rtx if_false_label, rtx if_true_label, int prob)
+			  rtx_code_label *if_false_label,
+			  rtx_code_label *if_true_label,
+			  int prob)
 {
   rtx op0 = expand_normal (swap ? treeop1 : treeop0);
   rtx op1 = expand_normal (swap ? treeop0 : treeop1);
@@ -754,7 +764,9 @@ do_jump_by_parts_greater (tree treeop0, tree treeop1, int swap,
 
 static void
 do_jump_by_parts_zero_rtx (enum machine_mode mode, rtx op0,
-			   rtx if_false_label, rtx if_true_label, int prob)
+			   rtx_code_label *if_false_label,
+			   rtx_code_label *if_true_label,
+			   int prob)
 {
   int nwords = GET_MODE_SIZE (mode) / UNITS_PER_WORD;
   rtx part;
@@ -787,7 +799,7 @@ do_jump_by_parts_zero_rtx (enum machine_mode mode, rtx op0,
   for (i = 0; i < nwords; i++)
     do_compare_rtx_and_jump (operand_subword_force (op0, i, mode),
                              const0_rtx, EQ, 1, word_mode, NULL_RTX,
-			     if_false_label, NULL_RTX, prob);
+			     if_false_label, NULL_RTX_CODE_LABEL, prob);
 
   if (if_true_label)
     emit_jump (if_true_label);
@@ -798,12 +810,13 @@ do_jump_by_parts_zero_rtx (enum machine_mode mode, rtx op0,
 
 /* Test for the equality of two RTX expressions OP0 and OP1 in mode MODE,
    where MODE is an integer mode too wide to be compared with one insn.
-   Either (but not both) of IF_TRUE_LABEL and IF_FALSE_LABEL may be NULL_RTX
-   to indicate drop through.  */
+   Either (but not both) of IF_TRUE_LABEL and IF_FALSE_LABEL may be
+   NULL_RTX_CODE_LABEL to indicate drop through.  */
 
 static void
 do_jump_by_parts_equality_rtx (enum machine_mode mode, rtx op0, rtx op1,
-			       rtx if_false_label, rtx if_true_label, int prob)
+			       rtx_code_label *if_false_label,
+			       rtx_code_label *if_true_label, int prob)
 {
   int nwords = (GET_MODE_SIZE (mode) / UNITS_PER_WORD);
   rtx drop_through_label = 0;
@@ -829,7 +842,7 @@ do_jump_by_parts_equality_rtx (enum machine_mode mode, rtx op0, rtx op1,
     do_compare_rtx_and_jump (operand_subword_force (op0, i, mode),
                              operand_subword_force (op1, i, mode),
                              EQ, 0, word_mode, NULL_RTX,
-			     if_false_label, NULL_RTX, prob);
+			     if_false_label, NULL_RTX_CODE_LABEL, prob);
 
   if (if_true_label)
     emit_jump (if_true_label);
@@ -841,8 +854,10 @@ do_jump_by_parts_equality_rtx (enum machine_mode mode, rtx op0, rtx op1,
    with one insn, test the comparison and jump to the appropriate label.  */
 
 static void
-do_jump_by_parts_equality (tree treeop0, tree treeop1, rtx if_false_label,
-			   rtx if_true_label, int prob)
+do_jump_by_parts_equality (tree treeop0, tree treeop1,
+			   rtx_code_label *if_false_label,
+			   rtx_code_label *if_true_label,
+			   int prob)
 {
   rtx op0 = expand_normal (treeop0);
   rtx op1 = expand_normal (treeop1);
@@ -937,11 +952,11 @@ split_comparison (enum rtx_code code, enum machine_mode mode,
 
 void
 do_compare_rtx_and_jump (rtx op0, rtx op1, enum rtx_code code, int unsignedp,
-			 enum machine_mode mode, rtx size, rtx if_false_label,
-			 rtx if_true_label, int prob)
+			 enum machine_mode mode, rtx size,
+			 rtx_code_label *if_false_label, rtx_code_label *if_true_label,
+			 int prob)
 {
-  rtx tem;
-  rtx dummy_label = NULL_RTX;
+  rtx_code_label *dummy_label = NULL_RTX_CODE_LABEL;
 
   /* Reverse the comparison if that is safe and we want to jump if it is
      false.  Also convert to the reverse comparison if the target can
@@ -963,7 +978,7 @@ do_compare_rtx_and_jump (rtx op0, rtx op1, enum rtx_code code, int unsignedp,
       if (can_compare_p (rcode, mode, ccp_jump)
 	  || (code == ORDERED && ! can_compare_p (ORDERED, mode, ccp_jump)))
 	{
-          tem = if_true_label;
+          rtx_code_label *tem = if_true_label;
           if_true_label = if_false_label;
           if_false_label = tem;
 	  code = rcode;
@@ -976,7 +991,7 @@ do_compare_rtx_and_jump (rtx op0, rtx op1, enum rtx_code code, int unsignedp,
 
   if (swap_commutative_operands_p (op0, op1))
     {
-      tem = op0;
+      rtx tem = op0;
       op0 = op1;
       op1 = tem;
       code = swap_condition (code);
@@ -984,14 +999,17 @@ do_compare_rtx_and_jump (rtx op0, rtx op1, enum rtx_code code, int unsignedp,
 
   do_pending_stack_adjust ();
 
+  rtx tem;
+
   code = unsignedp ? unsigned_condition (code) : code;
   if (0 != (tem = simplify_relational_operation (code, mode, VOIDmode,
 						 op0, op1)))
     {
       if (CONSTANT_P (tem))
 	{
-	  rtx label = (tem == const0_rtx || tem == CONST0_RTX (mode))
-		      ? if_false_label : if_true_label;
+	  rtx_code_label *label
+	    = ((tem == const0_rtx || tem == CONST0_RTX (mode))
+	       ? if_false_label : if_true_label);
 	  if (label)
 	    emit_jump (label);
 	  return;
@@ -1110,7 +1128,7 @@ do_compare_rtx_and_jump (rtx op0, rtx op1, enum rtx_code code, int unsignedp,
 		first_prob = REG_BR_PROB_BASE - REG_BR_PROB_BASE / 100;
 	      if (and_them)
 		{
-		  rtx dest_label;
+		  rtx_code_label *dest_label;
 		  /* If we only jump if true, just bypass the second jump.  */
 		  if (! if_false_label)
 		    {
@@ -1121,13 +1139,13 @@ do_compare_rtx_and_jump (rtx op0, rtx op1, enum rtx_code code, int unsignedp,
 		  else
 		    dest_label = if_false_label;
                   do_compare_rtx_and_jump (op0, op1, first_code, unsignedp, mode,
-					   size, dest_label, NULL_RTX,
-					   first_prob);
+					   size, dest_label,
+					   NULL_RTX_CODE_LABEL, first_prob);
 		}
               else
                 do_compare_rtx_and_jump (op0, op1, first_code, unsignedp, mode,
-					 size, NULL_RTX, if_true_label,
-					 first_prob);
+					 size, NULL_RTX_CODE_LABEL,
+					 if_true_label, first_prob);
 	    }
 	}
 
@@ -1143,7 +1161,7 @@ do_compare_rtx_and_jump (rtx op0, rtx op1, enum rtx_code code, int unsignedp,
 
 /* Generate code for a comparison expression EXP (including code to compute
    the values to be compared) and a conditional jump to IF_FALSE_LABEL and/or
-   IF_TRUE_LABEL.  One of the labels can be NULL_RTX, in which case the
+   IF_TRUE_LABEL.  One of the labels can be NULL_RTX_CODE_LABEL, in which case the
    generated code will drop through.
    SIGNED_CODE should be the rtx operation for this comparison for
    signed data; UNSIGNED_CODE, likewise for use if data is unsigned.
@@ -1153,8 +1171,9 @@ do_compare_rtx_and_jump (rtx op0, rtx op1, enum rtx_code code, int unsignedp,
 
 static void
 do_compare_and_jump (tree treeop0, tree treeop1, enum rtx_code signed_code,
-		     enum rtx_code unsigned_code, rtx if_false_label,
-		     rtx if_true_label, int prob)
+		     enum rtx_code unsigned_code,
+		     rtx_code_label *if_false_label,
+		     rtx_code_label *if_true_label, int prob)
 {
   rtx op0, op1;
   tree type;
diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
index 5515244..5eb8190 100644
--- a/gcc/emit-rtl.c
+++ b/gcc/emit-rtl.c
@@ -2468,11 +2468,12 @@ set_mem_attrs_for_spill (rtx mem)
 
 /* Return a newly created CODE_LABEL rtx with a unique label number.  */
 
-rtx
+rtx_code_label *
 gen_label_rtx (void)
 {
-  return gen_rtx_CODE_LABEL (VOIDmode, NULL_RTX, NULL_RTX,
-			     NULL, label_num++, NULL);
+  return as_a <rtx_code_label *> (
+	   gen_rtx_CODE_LABEL (VOIDmode, NULL_RTX, NULL_RTX,
+			       NULL, label_num++, NULL));
 }
 
 /* For procedure integration.  */
@@ -4354,8 +4355,8 @@ emit_barrier_before (rtx before)
 
 /* Emit the label LABEL before the insn BEFORE.  */
 
-rtx
-emit_label_before (rtx label, rtx before)
+rtx_code_label *
+emit_label_before (rtx_code_label *label, rtx before)
 {
   gcc_checking_assert (INSN_UID (label) == 0);
   INSN_UID (label) = cur_insn_uid++;
diff --git a/gcc/expmed.c b/gcc/expmed.c
index e76b6fc..bd3c366 100644
--- a/gcc/expmed.c
+++ b/gcc/expmed.c
@@ -65,7 +65,8 @@ static rtx extract_fixed_bit_field_1 (enum machine_mode, rtx,
 static rtx lshift_value (enum machine_mode, unsigned HOST_WIDE_INT, int);
 static rtx extract_split_bit_field (rtx, unsigned HOST_WIDE_INT,
 				    unsigned HOST_WIDE_INT, int);
-static void do_cmp_and_jump (rtx, rtx, enum rtx_code, enum machine_mode, rtx);
+static void do_cmp_and_jump (rtx, rtx, enum rtx_code, enum machine_mode,
+			     rtx_code_label *);
 static rtx expand_smod_pow2 (enum machine_mode, rtx, HOST_WIDE_INT);
 static rtx expand_sdiv_pow2 (enum machine_mode, rtx, HOST_WIDE_INT);
 
@@ -3647,7 +3648,8 @@ expmed_mult_highpart (enum machine_mode mode, rtx op0, rtx op1,
 static rtx
 expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
 {
-  rtx result, temp, shift, label;
+  rtx result, temp, shift;
+  rtx_code_label *label;
   int logd;
   int prec = GET_MODE_PRECISION (mode);
 
@@ -3743,7 +3745,8 @@ expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
 static rtx
 expand_sdiv_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
 {
-  rtx temp, label;
+  rtx temp;
+  rtx_code_label *label;
   int logd;
 
   logd = floor_log2 (d);
@@ -4477,7 +4480,7 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
 	    /* This could be computed with a branch-less sequence.
 	       Save that for later.  */
 	    rtx tem;
-	    rtx label = gen_label_rtx ();
+	    rtx_code_label *label = gen_label_rtx ();
 	    do_cmp_and_jump (remainder, const0_rtx, EQ, compute_mode, label);
 	    tem = expand_binop (compute_mode, xor_optab, op0, op1,
 				NULL_RTX, 0, OPTAB_WIDEN);
@@ -4491,7 +4494,7 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
 	/* No luck with division elimination or divmod.  Have to do it
 	   by conditionally adjusting op0 *and* the result.  */
 	{
-	  rtx label1, label2, label3, label4, label5;
+	  rtx_code_label *label1, *label2, *label3, *label4, *label5;
 	  rtx adjusted_op0;
 	  rtx tem;
 
@@ -4552,7 +4555,7 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
 				      compute_mode, 1, 1);
 		if (t3 == 0)
 		  {
-		    rtx lab;
+		    rtx_code_label *lab;
 		    lab = gen_label_rtx ();
 		    do_cmp_and_jump (t2, const0_rtx, EQ, compute_mode, lab);
 		    expand_inc (t1, const1_rtx);
@@ -4592,7 +4595,7 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
 	      {
 		/* This could be computed with a branch-less sequence.
 		   Save that for later.  */
-		rtx label = gen_label_rtx ();
+		rtx_code_label *label = gen_label_rtx ();
 		do_cmp_and_jump (remainder, const0_rtx, EQ,
 				 compute_mode, label);
 		expand_inc (quotient, const1_rtx);
@@ -4604,7 +4607,7 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
 	    /* No luck with division elimination or divmod.  Have to do it
 	       by conditionally adjusting op0 *and* the result.  */
 	    {
-	      rtx label1, label2;
+	      rtx_code_label *label1, *label2;
 	      rtx adjusted_op0, tem;
 
 	      quotient = gen_reg_rtx (compute_mode);
@@ -4649,7 +4652,7 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
 				      compute_mode, 1, 1);
 		if (t3 == 0)
 		  {
-		    rtx lab;
+		    rtx_code_label *lab;
 		    lab = gen_label_rtx ();
 		    do_cmp_and_jump (t2, const0_rtx, EQ, compute_mode, lab);
 		    expand_inc (t1, const1_rtx);
@@ -4689,7 +4692,7 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
 		/* This could be computed with a branch-less sequence.
 		   Save that for later.  */
 		rtx tem;
-		rtx label = gen_label_rtx ();
+		rtx_code_label *label = gen_label_rtx ();
 		do_cmp_and_jump (remainder, const0_rtx, EQ,
 				 compute_mode, label);
 		tem = expand_binop (compute_mode, xor_optab, op0, op1,
@@ -4704,7 +4707,7 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
 	    /* No luck with division elimination or divmod.  Have to do it
 	       by conditionally adjusting op0 *and* the result.  */
 	    {
-	      rtx label1, label2, label3, label4, label5;
+	      rtx_code_label *label1, *label2, *label3, *label4, *label5;
 	      rtx adjusted_op0;
 	      rtx tem;
 
@@ -4779,7 +4782,7 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
 	if (unsignedp)
 	  {
 	    rtx tem;
-	    rtx label;
+	    rtx_code_label *label;
 	    label = gen_label_rtx ();
 	    quotient = gen_reg_rtx (compute_mode);
 	    remainder = gen_reg_rtx (compute_mode);
@@ -4802,7 +4805,7 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
 	else
 	  {
 	    rtx abs_rem, abs_op1, tem, mask;
-	    rtx label;
+	    rtx_code_label *label;
 	    label = gen_label_rtx ();
 	    quotient = gen_reg_rtx (compute_mode);
 	    remainder = gen_reg_rtx (compute_mode);
@@ -5744,7 +5747,8 @@ rtx
 emit_store_flag_force (rtx target, enum rtx_code code, rtx op0, rtx op1,
 		       enum machine_mode mode, int unsignedp, int normalizep)
 {
-  rtx tem, label;
+  rtx tem;
+  rtx_code_label *label;
   rtx trueval, falseval;
 
   /* First see if emit_store_flag can do the job.  */
@@ -5766,7 +5770,7 @@ emit_store_flag_force (rtx target, enum rtx_code code, rtx op0, rtx op1,
     {
       label = gen_label_rtx ();
       do_compare_rtx_and_jump (target, const0_rtx, EQ, unsignedp,
-			       mode, NULL_RTX, NULL_RTX, label, -1);
+			       mode, NULL_RTX, NULL_RTX_CODE_LABEL, label, -1);
       emit_move_insn (target, trueval);
       emit_label (label);
       return target;
@@ -5804,7 +5808,7 @@ emit_store_flag_force (rtx target, enum rtx_code code, rtx op0, rtx op1,
   emit_move_insn (target, trueval);
   label = gen_label_rtx ();
   do_compare_rtx_and_jump (op0, op1, code, unsignedp, mode, NULL_RTX,
-			   NULL_RTX, label, -1);
+			   NULL_RTX_CODE_LABEL, label, -1);
 
   emit_move_insn (target, falseval);
   emit_label (label);
@@ -5818,9 +5822,9 @@ emit_store_flag_force (rtx target, enum rtx_code code, rtx op0, rtx op1,
 
 static void
 do_cmp_and_jump (rtx arg1, rtx arg2, enum rtx_code op, enum machine_mode mode,
-		 rtx label)
+		 rtx_code_label *label)
 {
   int unsignedp = (op == LTU || op == LEU || op == GTU || op == GEU);
   do_compare_rtx_and_jump (arg1, arg2, op, unsignedp, mode,
-			   NULL_RTX, NULL_RTX, label, -1);
+			   NULL_RTX, NULL_RTX_CODE_LABEL, label, -1);
 }
diff --git a/gcc/expr.c b/gcc/expr.c
index 2868d9d..9b6f228 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -5151,7 +5151,8 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal)
 	 side.  This avoids the creation of unnecessary temporaries.
 	 For non-BLKmode, it is more efficient not to do this.  */
 
-      rtx lab1 = gen_label_rtx (), lab2 = gen_label_rtx ();
+      rtx_code_label *lab1 = gen_label_rtx ();
+      rtx_code_label *lab2 = gen_label_rtx ();
 
       do_pending_stack_adjust ();
       NO_DEFER_POP;
@@ -6173,8 +6174,8 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
 		  }
 		else
 		  {
-		    rtx loop_start = gen_label_rtx ();
-		    rtx loop_end = gen_label_rtx ();
+		    rtx_code_label *loop_start = gen_label_rtx ();
+		    rtx_code_label *loop_end = gen_label_rtx ();
 		    tree exit_cond;
 
 		    expand_normal (hi_index);
@@ -8009,6 +8010,7 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
 		    enum expand_modifier modifier)
 {
   rtx op0, op1, op2, temp;
+  rtx_code_label *op_label0, *op_label1;
   tree type;
   int unsignedp;
   enum machine_mode mode;
@@ -8811,8 +8813,8 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
 
 	temp = gen_label_rtx ();
 	do_compare_rtx_and_jump (target, cmpop1, comparison_code,
-				 unsignedp, mode, NULL_RTX, NULL_RTX, temp,
-				 -1);
+				 unsignedp, mode, NULL_RTX, NULL_RTX_CODE_LABEL,
+				 as_a <rtx_code_label *> (temp), -1);
       }
       emit_move_insn (target, op1);
       emit_label (temp);
@@ -8914,15 +8916,15 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
 
       emit_move_insn (target, const0_rtx);
 
-      op1 = gen_label_rtx ();
-      jumpifnot_1 (code, treeop0, treeop1, op1, -1);
+      op_label1 = gen_label_rtx ();
+      jumpifnot_1 (code, treeop0, treeop1, op_label1, -1);
 
       if (TYPE_PRECISION (type) == 1 && !TYPE_UNSIGNED (type))
 	emit_move_insn (target, constm1_rtx);
       else
 	emit_move_insn (target, const1_rtx);
 
-      emit_label (op1);
+      emit_label (op_label1);
       return target;
 
     case COMPLEX_EXPR:
@@ -9147,21 +9149,21 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
 
       do_pending_stack_adjust ();
       NO_DEFER_POP;
-      op0 = gen_label_rtx ();
-      op1 = gen_label_rtx ();
-      jumpifnot (treeop0, op0, -1);
+      op_label0 = gen_label_rtx ();
+      op_label1 = gen_label_rtx ();
+      jumpifnot (treeop0, op_label0, -1);
       store_expr (treeop1, temp,
 		  modifier == EXPAND_STACK_PARM,
 		  false);
 
-      emit_jump_insn (gen_jump (op1));
+      emit_jump_insn (gen_jump (op_label1));
       emit_barrier ();
-      emit_label (op0);
+      emit_label (op_label0);
       store_expr (treeop2, temp,
 		  modifier == EXPAND_STACK_PARM,
 		  false);
 
-      emit_label (op1);
+      emit_label (op_label1);
       OK_DEFER_POP;
       return temp;
 
@@ -10531,7 +10533,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 	    && integer_onep (DECL_SIZE (TREE_OPERAND (lhs, 1)))
 	    && integer_onep (DECL_SIZE (TREE_OPERAND (TREE_OPERAND (rhs, 1), 1))))
 	  {
-	    rtx label = gen_label_rtx ();
+	    rtx_code_label *label = gen_label_rtx ();
 	    int value = TREE_CODE (rhs) == BIT_IOR_EXPR;
 	    do_jump (TREE_OPERAND (rhs, 1),
 		     value ? label : 0,
diff --git a/gcc/expr.h b/gcc/expr.h
index 1823feb..93d5868 100644
--- a/gcc/expr.h
+++ b/gcc/expr.h
@@ -512,20 +512,22 @@ extern void restore_pending_stack_adjust (saved_pending_stack_adjust *);
 extern tree string_constant (tree, tree *);
 
 /* Generate code to evaluate EXP and jump to LABEL if the value is zero.  */
-extern void jumpifnot (tree, rtx, int);
-extern void jumpifnot_1 (enum tree_code, tree, tree, rtx, int);
+extern void jumpifnot (tree, rtx_code_label *, int);
+extern void jumpifnot_1 (enum tree_code, tree, tree, rtx_code_label *, int);
 
 /* Generate code to evaluate EXP and jump to LABEL if the value is nonzero.  */
-extern void jumpif (tree, rtx, int);
-extern void jumpif_1 (enum tree_code, tree, tree, rtx, int);
+extern void jumpif (tree, rtx_code_label *, int);
+extern void jumpif_1 (enum tree_code, tree, tree, rtx_code_label *, int);
 
 /* Generate code to evaluate EXP and jump to IF_FALSE_LABEL if
    the result is zero, or IF_TRUE_LABEL if the result is one.  */
-extern void do_jump (tree, rtx, rtx, int);
-extern void do_jump_1 (enum tree_code, tree, tree, rtx, rtx, int);
+extern void do_jump (tree, rtx_code_label *, rtx_code_label *, int);
+extern void do_jump_1 (enum tree_code, tree, tree, rtx_code_label *,
+		       rtx_code_label *, int);
 
 extern void do_compare_rtx_and_jump (rtx, rtx, enum rtx_code, int,
-				     enum machine_mode, rtx, rtx, rtx, int);
+				     enum machine_mode, rtx, rtx_code_label *,
+				     rtx_code_label *, int);
 
 /* Two different ways of generating switch statements.  */
 extern int try_casesi (tree, tree, tree, tree, rtx, rtx, rtx, int);
@@ -569,12 +571,12 @@ extern void locate_and_pad_parm (enum machine_mode, tree, int, int, int,
 				 struct locate_and_pad_arg_data *);
 
 /* Return the CODE_LABEL rtx for a LABEL_DECL, creating it if necessary.  */
-extern rtx label_rtx (tree);
+extern rtx_code_label *label_rtx (tree);
 
 /* As label_rtx, but additionally the label is placed on the forced label
    list of its containing function (i.e. it is treated as reachable even
    if how is not obvious).  */
-extern rtx force_label_rtx (tree);
+extern rtx_code_label *force_label_rtx (tree);
 
 /* Return an rtx like arg but sans any constant terms.
    Returns the original rtx if it has no constant terms.
diff --git a/gcc/function.h b/gcc/function.h
index a8294b2..b5480cc 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -271,12 +271,12 @@ struct GTY(()) rtl_data {
   /* Label that will go on function epilogue.
      Jumping to this label serves as a "return" instruction
      on machines which require execution of the epilogue on all returns.  */
-  rtx x_return_label;
+  rtx_code_label *x_return_label;
 
   /* Label that will go on the end of function epilogue.
      Jumping to this label serves as a "naked return" instruction
      on machines which require execution of the epilogue on all returns.  */
-  rtx x_naked_return_label;
+  rtx_code_label *x_naked_return_label;
 
   /* List (chain of EXPR_LISTs) of all stack slots in this function.
      Made for the sake of unshare_all_rtl.  */
diff --git a/gcc/hw-doloop.h b/gcc/hw-doloop.h
index 9fc3c15..668592b 100644
--- a/gcc/hw-doloop.h
+++ b/gcc/hw-doloop.h
@@ -78,7 +78,7 @@ struct GTY (()) hwloop_info_d
   rtx start_label;
 
   /* The new label placed at the end of the loop. */
-  rtx end_label;
+  rtx_code_label *end_label;
 
   /* The length of the loop.  */
   int length;
diff --git a/gcc/loop-doloop.c b/gcc/loop-doloop.c
index d03d13c..28c91ee 100644
--- a/gcc/loop-doloop.c
+++ b/gcc/loop-doloop.c
@@ -336,7 +336,8 @@ cleanup:
 static bool
 add_test (rtx cond, edge *e, basic_block dest)
 {
-  rtx seq, jump, label;
+  rtx seq, jump;
+  rtx_code_label *label;
   enum machine_mode mode;
   rtx op0 = XEXP (cond, 0), op1 = XEXP (cond, 1);
   enum rtx_code code = GET_CODE (cond);
@@ -351,7 +352,7 @@ add_test (rtx cond, edge *e, basic_block dest)
   op1 = force_operand (op1, NULL_RTX);
   label = block_label (dest);
   do_compare_rtx_and_jump (op0, op1, code, 0, mode, NULL_RTX,
-			   NULL_RTX, label, -1);
+			   NULL_RTX_CODE_LABEL, label, -1);
 
   jump = get_last_insn ();
   if (!jump || !JUMP_P (jump))
diff --git a/gcc/loop-unroll.c b/gcc/loop-unroll.c
index 5797d20..0c1603a 100644
--- a/gcc/loop-unroll.c
+++ b/gcc/loop-unroll.c
@@ -1059,8 +1059,8 @@ split_edge_and_insert (edge e, rtx insns)
    in order to create a jump.  */
 
 static rtx
-compare_and_jump_seq (rtx op0, rtx op1, enum rtx_code comp, rtx label, int prob,
-		      rtx cinsn)
+compare_and_jump_seq (rtx op0, rtx op1, enum rtx_code comp,
+		      rtx_code_label *label, int prob, rtx cinsn)
 {
   rtx seq, jump, cond;
   enum machine_mode mode;
@@ -1093,7 +1093,7 @@ compare_and_jump_seq (rtx op0, rtx op1, enum rtx_code comp, rtx label, int prob,
       op0 = force_operand (op0, NULL_RTX);
       op1 = force_operand (op1, NULL_RTX);
       do_compare_rtx_and_jump (op0, op1, comp, 0,
-			       mode, NULL_RTX, NULL_RTX, label, -1);
+			       mode, NULL_RTX, NULL_RTX_CODE_LABEL, label, -1);
       jump = get_last_insn ();
       gcc_assert (JUMP_P (jump));
       JUMP_LABEL (jump) = label;
diff --git a/gcc/optabs.c b/gcc/optabs.c
index fc58b63..6894856 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -1011,7 +1011,7 @@ expand_doubleword_shift (enum machine_mode op1_mode, optab binoptab,
 			 unsigned HOST_WIDE_INT shift_mask)
 {
   rtx superword_op1, tmp, cmp1, cmp2;
-  rtx subword_label, done_label;
+  rtx_code_label *subword_label, *done_label;
   enum rtx_code cmp_code;
 
   /* See if word-mode shifts by BITS_PER_WORD...BITS_PER_WORD * 2 - 1 will
@@ -3451,7 +3451,8 @@ rtx
 expand_abs (enum machine_mode mode, rtx op0, rtx target,
 	    int result_unsignedp, int safe)
 {
-  rtx temp, op1;
+  rtx temp;
+  rtx_code_label *op1;
 
   if (GET_MODE_CLASS (mode) != MODE_INT
       || ! flag_trapv)
@@ -3481,7 +3482,7 @@ expand_abs (enum machine_mode mode, rtx op0, rtx target,
   NO_DEFER_POP;
 
   do_compare_rtx_and_jump (target, CONST0_RTX (mode), GE, 0, mode,
-			   NULL_RTX, NULL_RTX, op1, -1);
+			   NULL_RTX, NULL_RTX_CODE_LABEL, op1, -1);
 
   op0 = expand_unop (mode, result_unsignedp ? neg_optab : negv_optab,
                      target, target, 0);
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 10ae1e9..6718c30 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -31,6 +31,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "hashtab.h"
 #include "wide-int.h"
 #include "flags.h"
+#include "is-a.h"
 
 /* Value used by some passes to "recognize" noop moves as valid
  instructions.  */
@@ -266,8 +267,24 @@ struct GTY((variable_size)) hwivec_def {
 
 /* RTL expression ("rtx").  */
 
-struct GTY((chain_next ("RTX_NEXT (&%h)"),
-	    chain_prev ("RTX_PREV (&%h)"))) rtx_def {
+/* The GTY "desc" and "tag" options below are a kludge: we need a desc
+   field for for gengtype to recognize that inheritance is occurring,
+   so that all subclasses are redirected to the traversal hook for the
+   base class.
+   However, all of the fields are in the base class, and special-casing
+   is at work.  Hence we use desc and tag of 0, generating a switch
+   statement of the form:
+     switch (0)
+       {
+       case 0: // all the work happens here
+       }
+   in order to work with the existing special-casing in gengtype.  */
+
+struct GTY((desc("0"), tag("0"),
+	    chain_next ("RTX_NEXT (&%h)"),
+	    chain_prev ("RTX_PREV (&%h)")))
+  rtx_def
+{
   /* The kind of expression this is.  */
   ENUM_BITFIELD(rtx_code) code: 16;
 
@@ -385,8 +402,27 @@ struct GTY((chain_next ("RTX_NEXT (&%h)"),
     struct fixed_value fv;
     struct hwivec_def hwiv;
   } GTY ((special ("rtx_def"), desc ("GET_CODE (&%0)"))) u;
+
+};
+
+
+/* An expression with the invariant that:
+     GET_CODE (X) == CODE_LABEL
+   i.e. a "code_label".  */
+
+struct GTY(()) rtx_code_label : public rtx_def
+{
+  /* No extra fields, but adds invariant: (GET_CODE (X) == CODE_LABEL).  */
 };
 
+template <>
+template <>
+inline bool
+is_a_helper <rtx_code_label *>::test (rtx rt)
+{
+  return rt->code == CODE_LABEL;
+}
+
 /* The size in bytes of an rtx header (code, mode and flags).  */
 #define RTX_HDR_SIZE offsetof (struct rtx_def, u)
 
@@ -394,6 +430,7 @@ struct GTY((chain_next ("RTX_NEXT (&%h)"),
 #define RTX_CODE_SIZE(CODE) rtx_code_size[CODE]
 
 #define NULL_RTX (rtx) 0
+#define NULL_RTX_CODE_LABEL (rtx_code_label *) 0
 
 /* The "next" and "previous" RTX, relative to this one.  */
 
@@ -1991,7 +2028,7 @@ extern rtx gen_reg_rtx (enum machine_mode);
 extern rtx gen_rtx_REG_offset (rtx, enum machine_mode, unsigned int, int);
 extern rtx gen_reg_rtx_offset (rtx, enum machine_mode, int);
 extern rtx gen_reg_rtx_and_attrs (rtx);
-extern rtx gen_label_rtx (void);
+extern rtx_code_label *gen_label_rtx (void);
 extern rtx gen_lowpart_common (enum machine_mode, rtx);
 
 /* In cse.c */
@@ -2075,7 +2112,7 @@ extern rtx emit_debug_insn_before (rtx, rtx);
 extern rtx emit_debug_insn_before_noloc (rtx, rtx);
 extern rtx emit_debug_insn_before_setloc (rtx, rtx, int);
 extern rtx emit_barrier_before (rtx);
-extern rtx emit_label_before (rtx, rtx);
+extern rtx_code_label *emit_label_before (rtx_code_label *, rtx);
 extern rtx emit_note_before (enum insn_note, rtx);
 extern rtx emit_insn_after (rtx, rtx);
 extern rtx emit_insn_after_noloc (rtx, rtx, basic_block);
diff --git a/gcc/stmt.c b/gcc/stmt.c
index 163d495..935ea2b 100644
--- a/gcc/stmt.c
+++ b/gcc/stmt.c
@@ -119,28 +119,29 @@ static void emit_case_nodes (rtx, case_node_ptr, rtx, int, tree);
 /* Return the rtx-label that corresponds to a LABEL_DECL,
    creating it if necessary.  */
 
-rtx
+rtx_code_label *
 label_rtx (tree label)
 {
   gcc_assert (TREE_CODE (label) == LABEL_DECL);
 
   if (!DECL_RTL_SET_P (label))
     {
-      rtx r = gen_label_rtx ();
+      rtx_code_label *r = gen_label_rtx ();
       SET_DECL_RTL (label, r);
       if (FORCED_LABEL (label) || DECL_NONLOCAL (label))
 	LABEL_PRESERVE_P (r) = 1;
     }
 
-  return DECL_RTL (label);
+  /* FIXME: making this typesafe requires making tree labels typesafe.  */
+  return as_a <rtx_code_label *> (DECL_RTL (label));
 }
 
 /* As above, but also put it on the forced-reference list of the
    function that contains it.  */
-rtx
+rtx_code_label *
 force_label_rtx (tree label)
 {
-  rtx ref = label_rtx (label);
+  rtx_code_label *ref = label_rtx (label);
   tree function = decl_function_context (label);
 
   gcc_assert (function);
@@ -730,12 +731,13 @@ expand_naked_return (void)
 /* Generate code to jump to LABEL if OP0 and OP1 are equal in mode MODE. PROB
    is the probability of jumping to LABEL.  */
 static void
-do_jump_if_equal (enum machine_mode mode, rtx op0, rtx op1, rtx label,
+do_jump_if_equal (enum machine_mode mode, rtx op0, rtx op1,
+		  rtx_code_label *label,
 		  int unsignedp, int prob)
 {
   gcc_assert (prob <= REG_BR_PROB_BASE);
   do_compare_rtx_and_jump (op0, op1, EQ, unsignedp, mode,
-			   NULL_RTX, NULL_RTX, label, prob);
+			   NULL_RTX, NULL_RTX_CODE_LABEL, label, prob);
 }
 
 /* Do the insertion of a case label into case_list.  The labels are
@@ -1338,7 +1340,7 @@ expand_sjlj_dispatch_table (rtx dispatch_index,
       for (int i = 0; i < ncases; i++)
         {
 	  tree elt = dispatch_table[i];
-	  rtx lab = label_rtx (CASE_LABEL (elt));
+	  rtx_code_label *lab = label_rtx (CASE_LABEL (elt));
 	  do_jump_if_equal (index_mode, index, zero, lab, 0, -1);
 	  force_expand_binop (index_mode, sub_optab,
 			      index, CONST1_RTX (index_mode),
-- 
1.8.5.3

