This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RFA: highpart life analysis


Bootstrapped on i686-pc-linux-gnu.  Regtested there native and X sh64-elf.

2004-01-28  J"orn Rennecke <joern.rennecke@superh.com>

	* basic-block.h (struct basic_block_def): New members
	global_high_live_at_start and global_high_live_at_end.
	(PROP_HIGH_LIFE, PROP_KILL_DEAD_EXTENDS): New defines.
	(propagate_block, propagate_block_info): Take another regset argument.
	* cfg.c (entry_exit_blocks, dump_flow_info): Add (handling for)
	global_high_live_at_start and global_high_live_at_end members.
	* cfglayout.c (cfg_layout_duplicate_bb): Handle global_high_life_at_*
	members.
	* cfgrtl.c (rtl_split_block, merge_blocks_nomove): Likewise.
	(force_nonfallthru_and_redirect, rtl_split_edge): Likewise.
	(rtl_dump_bb, print_rtl_with_bb): Likewise.
	* flow.c ("insn-attr.h"): Include.
	(struct propagate_block_info) New members highpart_disposition,
	reg_high_live and high_out.
	(life_analysis): Initialize EXIT_BLOCK_PTR->global_high_live_at_start.
	(update_life_info): Handle global_high_life_at_* members.
	Pass PROP_HIGH_LIFE and PROP_KILL_DEAD_EXTENDS where appropriate.
	(calculate_global_regs_live): Handle global_high_life_at_* members.
	(allocate_bb_life_data): Likewise.
	(enum attr_highpart): Define in ! HAVE_HIGH_LIFE case.
	(propagate_one_insn): Set highpart_disposition.
	If PROP_KILL_DEAD_EXTENDS is included in flags, kill sign extends
	that are dead according to the high life information.
	Clear pbi->high_out.
	(init_propagate_block_info, propagate_block): New argument high_live.
	(highpart_dead_p, high_life_optimize): New functions.
	(mark_set_1): Update pbi->reg_live and pbi->high_out.
	(mark_used_reg): Update pbi->reg_high_live.
	* genconfig.c (have_high_life_flag): New static variable.
	(main): Set it when encountering an attribute "highpart".
	Print HAVE_HIGH_LIFE with a value of 0 or 1, as the case might be.
	* ifcvt.c (merge_if_block): Handle global_high_life_at_* members.
	(find_if_case_1, find_if_case_2): Likewise.
	(dead_or_predicatble): Update calls to init_propagate_block_info.
	* lcm.c (optimize_mode_switching): Handle global_high_life_at_* members.
	* recog.c (peephole2_optimize): Update call to
	init_propagate_block_info.
	* rtl.h (high_life_started): Declare.
	(high_life_optimize): Prototype.
	* timevar.def (TV_HIGH_LIFE): New entry.
	* toplev.c (high_life_started): New global variable.
	(dump_file_index): New value DFI_high_life.
	(dump_file): Add entry for high-life.
	(rest_of_handle_life): Pass PROP_HIGH_LIFE flag to life_analysis.
	Wrap life_analysis/cleanup_cfg calls in init_recog /
	init_recog_no_volatile.
	(rest_of_high_life): New function.
	(rest_of_compilation): Call it when optimizing.
	Clear high_life_started at the end.
	* doc/md.texi: Document highpart attribute.

	* sh.md (attribute highpart): New.

	* cfgrtl.c (redirect_branch_edge): Don't make VOIDmode LABEL_REF.

Index: basic-block.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/basic-block.h,v
retrieving revision 1.189
diff -p -u -r1.189 basic-block.h
--- basic-block.h	23 Jan 2004 11:02:06 -0000	1.189
+++ basic-block.h	28 Jan 2004 21:18:59 -0000
@@ -218,6 +218,9 @@ typedef struct basic_block_def {
   regset global_live_at_start;
   /* The registers that are live on exit from this block.  */
   regset global_live_at_end;
+  /* The registers the highparts of which are live on entry / exit
+     from this block.  */
+  regset global_high_live_at_start, global_high_live_at_end;
 
   /* Auxiliary info specific to a pass.  */
   void *aux;
@@ -473,7 +476,9 @@ enum update_life_extent
 #define PROP_AUTOINC		64	/* Create autoinc mem references.  */
 #define PROP_EQUAL_NOTES	128	/* Take into account REG_EQUAL notes.  */
 #define PROP_SCAN_DEAD_STORES	256	/* Scan for dead code.  */
-#define PROP_ASM_SCAN		512	/* Internal flag used within flow.c
+#define PROP_HIGH_LIFE		512	/* Do highpart life analysis.  */
+#define PROP_KILL_DEAD_EXTENDS 1024	/* Do highpart optimizations.  */
+#define PROP_ASM_SCAN	       2048	/* Internal flag used within flow.c
 					   to flag analysis of asms.  */
 #define PROP_FINAL		(PROP_DEATH_NOTES | PROP_LOG_LINKS  \
 				 | PROP_REG_INFO | PROP_KILL_DEAD_CODE  \
@@ -504,12 +509,12 @@ extern void life_analysis (rtx, FILE *, 
 extern int update_life_info (sbitmap, enum update_life_extent, int);
 extern int update_life_info_in_dirty_blocks (enum update_life_extent, int);
 extern int count_or_remove_death_notes (sbitmap, int);
-extern int propagate_block (basic_block, regset, regset, regset, int);
+extern int propagate_block (basic_block, regset, regset, regset, regset, int);
 
 struct propagate_block_info;
 extern rtx propagate_one_insn (struct propagate_block_info *, rtx);
 extern struct propagate_block_info *init_propagate_block_info
- (basic_block, regset, regset, regset, int);
+ (basic_block, regset, regset, regset, regset, int);
 extern void free_propagate_block_info (struct propagate_block_info *);
 
 /* In lcm.c */
Index: cfg.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfg.c,v
retrieving revision 1.57
diff -p -u -r1.57 cfg.c
--- cfg.c	21 Jan 2004 20:39:52 -0000	1.57
+++ cfg.c	28 Jan 2004 21:18:59 -0000
@@ -105,6 +105,8 @@ struct basic_block_def entry_exit_blocks
     NULL,			/* cond_local_set */
     NULL,			/* global_live_at_start */
     NULL,			/* global_live_at_end */
+    NULL,			/* global_high_live_at_start */
+    NULL,			/* global_high_live_at_end */
     NULL,			/* aux */
     ENTRY_BLOCK,		/* index */
     NULL,			/* prev_bb */
@@ -128,6 +130,8 @@ struct basic_block_def entry_exit_blocks
     NULL,			/* cond_local_set */
     NULL,			/* global_live_at_start */
     NULL,			/* global_live_at_end */
+    NULL,			/* global_high_live_at_start */
+    NULL,			/* global_high_live_at_end */
     NULL,			/* aux */
     EXIT_BLOCK,			/* index */
     ENTRY_BLOCK_PTR,		/* prev_bb */
@@ -570,6 +574,18 @@ dump_flow_info (FILE *file)
 
       fprintf (file, "\nRegisters live at end:");
       dump_regset (bb->global_live_at_end, file);
+
+      if (bb->global_high_live_at_start)
+	{
+	  fprintf (file, "\nRegister highparts live at start:");
+	  dump_regset (bb->global_high_live_at_start, file);
+	}
+
+      if (bb->global_high_live_at_end)
+	{
+	  fprintf (file, "\nRegister highparts live at end:");
+	  dump_regset (bb->global_high_live_at_end, file);
+	}
 
       putc ('\n', file);
 
Index: cfglayout.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfglayout.c,v
retrieving revision 1.50
diff -p -u -r1.50 cfglayout.c
--- cfglayout.c	30 Dec 2003 10:40:50 -0000	1.50
+++ cfglayout.c	28 Jan 2004 21:18:59 -0000
@@ -1060,6 +1060,15 @@ cfg_layout_duplicate_bb (basic_block bb,
       COPY_REG_SET (new_bb->global_live_at_start, bb->global_live_at_start);
       COPY_REG_SET (new_bb->global_live_at_end, bb->global_live_at_end);
     }
+  if (HAVE_HIGH_LIFE && bb->global_high_live_at_start)
+    {
+      new_bb->global_high_live_at_start = OBSTACK_ALLOC_REG_SET (&flow_obstack);
+      new_bb->global_high_live_at_end = OBSTACK_ALLOC_REG_SET (&flow_obstack);
+      COPY_REG_SET (new_bb->global_high_live_at_start,
+		    bb->global_high_live_at_start);
+      COPY_REG_SET (new_bb->global_high_live_at_end,
+		    bb->global_high_live_at_end);
+    }
 
   new_bb->loop_depth = bb->loop_depth;
   new_bb->flags = bb->flags;
Index: cfgrtl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfgrtl.c,v
retrieving revision 1.106
diff -p -u -r1.106 cfgrtl.c
--- cfgrtl.c	21 Jan 2004 20:39:52 -0000	1.106
+++ cfgrtl.c	28 Jan 2004 21:18:59 -0000
@@ -514,7 +514,26 @@ rtl_split_block (basic_block bb, void *i
 	 at the end of the original basic block and get
 	 propagate_block to determine which registers are live.  */
       COPY_REG_SET (new_bb->global_live_at_start, bb->global_live_at_end);
-      propagate_block (new_bb, new_bb->global_live_at_start, NULL, NULL, 0);
+
+      if (HAVE_HIGH_LIFE && bb->global_high_live_at_start)
+	{
+	  new_bb->global_high_live_at_start
+	    = OBSTACK_ALLOC_REG_SET (&flow_obstack);
+	  new_bb->global_high_live_at_end
+	    = OBSTACK_ALLOC_REG_SET (&flow_obstack);
+	  COPY_REG_SET (new_bb->global_high_live_at_end,
+			bb->global_high_live_at_end);
+	  COPY_REG_SET (new_bb->global_high_live_at_start,
+			bb->global_high_live_at_end);
+	  propagate_block (new_bb, new_bb->global_live_at_start,
+			   new_bb->global_high_live_at_start, NULL, NULL,
+			   PROP_HIGH_LIFE);
+	  COPY_REG_SET (bb->global_high_live_at_end,
+			new_bb->global_high_live_at_start);
+	}
+      else
+	propagate_block (new_bb, new_bb->global_live_at_start,
+			 new_bb->global_high_live_at_start, NULL, NULL, 0);
       COPY_REG_SET (bb->global_live_at_end,
 		    new_bb->global_live_at_start);
 #ifdef HAVE_conditional_execution
@@ -554,6 +573,8 @@ update_cfg_after_block_merging (basic_bl
   /* B hasn't quite yet ceased to exist.  Attempt to prevent mishap.  */
   b->pred = b->succ = NULL;
   a->global_live_at_end = b->global_live_at_end;
+  if (HAVE_HIGH_LIFE)
+    a->global_high_live_at_end = b->global_high_live_at_end;
 
   expunge_block (b);
 }
@@ -915,7 +936,7 @@ redirect_branch_edge (edge e, basic_bloc
 	  && GET_CODE (XEXP (SET_SRC (tmp), 2)) == LABEL_REF
 	  && XEXP (XEXP (SET_SRC (tmp), 2), 0) == old_label)
 	{
-	  XEXP (SET_SRC (tmp), 2) = gen_rtx_LABEL_REF (VOIDmode,
+	  XEXP (SET_SRC (tmp), 2) = gen_rtx_LABEL_REF (Pmode,
 						       new_label);
 	  --LABEL_NUSES (old_label);
 	  ++LABEL_NUSES (new_label);
@@ -1091,6 +1112,18 @@ force_nonfallthru_and_redirect (edge e, 
 			target->global_live_at_start);
 	}
 
+      if (HAVE_HIGH_LIFE && target->global_high_live_at_start)
+	{
+	  jump_block->global_high_live_at_start
+	    = OBSTACK_ALLOC_REG_SET (&flow_obstack);
+	  jump_block->global_high_live_at_end
+	    = OBSTACK_ALLOC_REG_SET (&flow_obstack);
+	  COPY_REG_SET (jump_block->global_high_live_at_start,
+			target->global_high_live_at_start);
+	  COPY_REG_SET (jump_block->global_high_live_at_end,
+			target->global_high_live_at_start);
+	}
+
       /* Wire edge in.  */
       new_edge = make_edge (e->src, jump_block, EDGE_FALLTHRU);
       new_edge->probability = e->probability;
@@ -1361,6 +1394,16 @@ rtl_split_edge (edge edge_in)
 		    edge_in->dest->global_live_at_start);
     }
 
+  if (HAVE_HIGH_LIFE && edge_in->dest->global_high_live_at_start)
+    {
+      bb->global_high_live_at_start = OBSTACK_ALLOC_REG_SET (&flow_obstack);
+      bb->global_high_live_at_end = OBSTACK_ALLOC_REG_SET (&flow_obstack);
+      COPY_REG_SET (bb->global_high_live_at_start,
+		    edge_in->dest->global_high_live_at_start);
+      COPY_REG_SET (bb->global_high_live_at_end,
+		    edge_in->dest->global_high_live_at_start);
+    }
+
   make_single_succ_edge (bb, edge_in->dest, EDGE_FALLTHRU);
 
   /* For non-fallthru edges, we must adjust the predecessor's
@@ -1725,6 +1768,12 @@ rtl_dump_bb (basic_block bb, FILE *outf)
   fputs (";; Registers live at start:", outf);
   dump_regset (bb->global_live_at_start, outf);
   putc ('\n', outf);
+  if (HAVE_HIGH_LIFE && bb->global_high_live_at_start)
+    {
+      fputs (";; Register highparts live at start:", outf);
+      dump_regset (bb->global_high_live_at_start, outf);
+      putc ('\n', outf);
+    }
 
   for (insn = BB_HEAD (bb), last = NEXT_INSN (BB_END (bb)); insn != last;
        insn = NEXT_INSN (insn))
@@ -1733,6 +1782,13 @@ rtl_dump_bb (basic_block bb, FILE *outf)
   fputs (";; Registers live at end:", outf);
   dump_regset (bb->global_live_at_end, outf);
   putc ('\n', outf);
+  if (HAVE_HIGH_LIFE && bb->global_high_live_at_end)
+    {
+      fputs (";; Register highparts live at end:", outf);
+      dump_regset (bb->global_high_live_at_end, outf);
+      putc ('\n', outf);
+    }
+
 }
 
 /* Like print_rtl, but also print out live information for the start of each
@@ -1784,6 +1840,12 @@ print_rtl_with_bb (FILE *outf, rtx rtx_f
 		       bb->index);
 	      dump_regset (bb->global_live_at_start, outf);
 	      putc ('\n', outf);
+	      if (HAVE_HIGH_LIFE && bb->global_high_live_at_start)
+		{
+		  fprintf (outf, ";; register highparts live:");
+		  dump_regset (bb->global_high_live_at_start, outf);
+		  putc ('\n', outf);
+		}
 	    }
 
 	  if (in_bb_p[INSN_UID (tmp_rtx)] == NOT_IN_BB
@@ -1801,6 +1863,12 @@ print_rtl_with_bb (FILE *outf, rtx rtx_f
 		       bb->index);
 	      dump_regset (bb->global_live_at_end, outf);
 	      putc ('\n', outf);
+	      if (HAVE_HIGH_LIFE && bb->global_high_live_at_end)
+		{
+		  fprintf (outf, ";; Register highparts live:\n");
+		  dump_regset (bb->global_high_live_at_end, outf);
+		  putc ('\n', outf);
+		}
 	    }
 
 	  if (did_output)
Index: flow.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/flow.c,v
retrieving revision 1.573
diff -p -u -r1.573 flow.c
--- flow.c	25 Jan 2004 03:52:41 -0000	1.573
+++ flow.c	28 Jan 2004 21:18:59 -0000
@@ -1,6 +1,6 @@
 /* Data flow analysis for GNU compiler.
    Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -137,6 +137,7 @@ Software Foundation, 59 Temple Place - S
 #include "recog.h"
 #include "expr.h"
 #include "timevar.h"
+#include "insn-attr.h"
 
 #include "obstack.h"
 #include "splay-tree.h"
@@ -264,6 +265,18 @@ struct propagate_block_info
 
   /* Flags controlling the set of information propagate_block collects.  */
   int flags;
+
+  /* How the current instructions handles highparts - the result of the
+     "highpart" attribute.  This is an enum attr_highpart if it is used,
+     but we use int to avoid riddling the code with #if statements.  */
+  int highpart_disposition;
+
+  /* Bit N is set if the highpart of register N is conditionally or
+     unconditionally live.  */
+  regset reg_high_live;
+
+  /* The currently processed instruction computes a highpart which is live.  */
+  int high_out;
 };
 
 /* Number of dead insns removed.  */
@@ -286,6 +299,7 @@ static void propagate_block_delete_insn 
 static rtx propagate_block_delete_libcall (rtx, rtx);
 static int insn_dead_p (struct propagate_block_info *, rtx, int, rtx);
 static int libcall_dead_p (struct propagate_block_info *, rtx, rtx);
+static int highpart_dead_p (struct propagate_block_info *, rtx);
 static void mark_set_regs (struct propagate_block_info *, rtx, rtx);
 static void mark_set_1 (struct propagate_block_info *, enum rtx_code, rtx,
 			rtx, rtx, int);
@@ -447,6 +461,9 @@ life_analysis (rtx f, FILE *file, int fl
 
   /* Find the set of registers live on function exit.  */
   mark_regs_live_at_end (EXIT_BLOCK_PTR->global_live_at_start);
+  if (HAVE_HIGH_LIFE && (flags & PROP_HIGH_LIFE))
+    COPY_REG_SET (EXIT_BLOCK_PTR->global_high_live_at_start,
+		  EXIT_BLOCK_PTR->global_live_at_start);
 
   /* "Update" life info from zero.  It'd be nice to begin the
      relaxation with just the exit and noreturn blocks, but that set
@@ -596,13 +613,15 @@ verify_local_live_at_start (regset new_l
 int
 update_life_info (sbitmap blocks, enum update_life_extent extent, int prop_flags)
 {
-  regset tmp;
-  regset_head tmp_head;
+  regset tmp, tmp2 = NULL;
+  regset_head tmp_head, tmp2_head;
   int i;
   int stabilized_prop_flags = prop_flags;
   basic_block bb;
 
   tmp = INITIALIZE_REG_SET (tmp_head);
+  if (HAVE_HIGH_LIFE && (prop_flags & PROP_HIGH_LIFE))
+    tmp2 = INITIALIZE_REG_SET (tmp2_head);
   ndead = 0;
 
   timevar_push ((extent == UPDATE_LIFE_LOCAL || blocks)
@@ -624,7 +643,8 @@ update_life_info (sbitmap blocks, enum u
 	  calculate_global_regs_live (blocks, blocks,
 				prop_flags & (PROP_SCAN_DEAD_CODE
 					      | PROP_SCAN_DEAD_STORES
-					      | PROP_ALLOW_CFG_CHANGES));
+					      | PROP_ALLOW_CFG_CHANGES
+					      | PROP_HIGH_LIFE));
 
 	  if ((prop_flags & (PROP_KILL_DEAD_CODE | PROP_ALLOW_CFG_CHANGES))
 	      != (PROP_KILL_DEAD_CODE | PROP_ALLOW_CFG_CHANGES))
@@ -635,10 +655,14 @@ update_life_info (sbitmap blocks, enum u
 	  FOR_EACH_BB_REVERSE (bb)
 	    {
 	      COPY_REG_SET (tmp, bb->global_live_at_end);
-	      changed |= propagate_block (bb, tmp, NULL, NULL,
+	      if (HAVE_HIGH_LIFE && (prop_flags & PROP_HIGH_LIFE))
+		COPY_REG_SET (tmp2, bb->global_high_live_at_end);
+	      changed |= propagate_block (bb, tmp, tmp2, NULL, NULL,
 				prop_flags & (PROP_SCAN_DEAD_CODE
 					      | PROP_SCAN_DEAD_STORES
-					      | PROP_KILL_DEAD_CODE));
+					      | PROP_KILL_DEAD_CODE
+					      | PROP_KILL_DEAD_EXTENDS
+					      | PROP_HIGH_LIFE));
 	    }
 
 	  /* Don't pass PROP_SCAN_DEAD_CODE or PROP_KILL_DEAD_CODE to
@@ -647,7 +671,7 @@ update_life_info (sbitmap blocks, enum u
 	     is supposed to be finalized for this call after this loop.  */
 	  stabilized_prop_flags
 	    &= ~(PROP_SCAN_DEAD_CODE | PROP_SCAN_DEAD_STORES
-		 | PROP_KILL_DEAD_CODE);
+		 | PROP_KILL_DEAD_CODE | PROP_KILL_DEAD_EXTENDS);
 
 	  if (! changed)
 	    break;
@@ -667,6 +691,12 @@ update_life_info (sbitmap blocks, enum u
 	      CLEAR_REG_SET (bb->global_live_at_start);
 	      CLEAR_REG_SET (bb->global_live_at_end);
 	    }
+	  if (HAVE_HIGH_LIFE && (prop_flags & PROP_HIGH_LIFE))
+	    FOR_EACH_BB (bb)
+	      {
+		CLEAR_REG_SET (bb->global_high_live_at_start);
+		CLEAR_REG_SET (bb->global_high_live_at_end);
+	      }
 	}
 
       /* If asked, remove notes from the blocks we'll update.  */
@@ -685,7 +715,16 @@ update_life_info (sbitmap blocks, enum u
 	  bb = BASIC_BLOCK (i);
 
 	  COPY_REG_SET (tmp, bb->global_live_at_end);
-	  propagate_block (bb, tmp, NULL, NULL, stabilized_prop_flags);
+	  if (HAVE_HIGH_LIFE && (prop_flags & PROP_HIGH_LIFE))
+	    COPY_REG_SET (tmp2, bb->global_high_live_at_end);
+	  propagate_block (bb, tmp, tmp2, NULL, NULL, stabilized_prop_flags);
+	  /* If highpart liveness information got stale, zap it.  */
+	  if (HAVE_HIGH_LIFE && ! (prop_flags & PROP_HIGH_LIFE)
+	      && bb->global_high_live_at_start)
+	    {
+	      CLEAR_REG_SET (bb->global_high_live_at_start);
+	      CLEAR_REG_SET (bb->global_high_live_at_end);
+	    }
 
 	  if (extent == UPDATE_LIFE_LOCAL)
 	    verify_local_live_at_start (tmp, bb);
@@ -696,8 +735,17 @@ update_life_info (sbitmap blocks, enum u
       FOR_EACH_BB_REVERSE (bb)
 	{
 	  COPY_REG_SET (tmp, bb->global_live_at_end);
+	  if (HAVE_HIGH_LIFE && (stabilized_prop_flags & PROP_HIGH_LIFE))
+	    COPY_REG_SET (tmp2, bb->global_high_live_at_end);
 
-	  propagate_block (bb, tmp, NULL, NULL, stabilized_prop_flags);
+	  propagate_block (bb, tmp, tmp2, NULL, NULL, stabilized_prop_flags);
+	  /* If highpart liveness information got stale, zap it.  */
+	  if (HAVE_HIGH_LIFE && ! (prop_flags & PROP_HIGH_LIFE)
+	      && bb->global_high_live_at_start)
+	    {
+	      CLEAR_REG_SET (bb->global_high_live_at_start);
+	      CLEAR_REG_SET (bb->global_high_live_at_end);
+	    }
 
 	  if (extent == UPDATE_LIFE_LOCAL)
 	    verify_local_live_at_start (tmp, bb);
@@ -1037,9 +1085,10 @@ static void
 calculate_global_regs_live (sbitmap blocks_in, sbitmap blocks_out, int flags)
 {
   basic_block *queue, *qhead, *qtail, *qend, bb;
-  regset tmp, new_live_at_end, invalidated_by_call;
-  regset_head tmp_head, invalidated_by_call_head;
+  regset tmp, tmp2, new_live_at_end, new_high_live_at_end, invalidated_by_call;
+  regset_head tmp_head, tmp2_head, invalidated_by_call_head;
   regset_head new_live_at_end_head;
+  regset_head new_high_live_at_end_head;
   int i;
 
   /* Some passes used to forget clear aux field of basic block causing
@@ -1052,6 +1101,14 @@ calculate_global_regs_live (sbitmap bloc
 
   tmp = INITIALIZE_REG_SET (tmp_head);
   new_live_at_end = INITIALIZE_REG_SET (new_live_at_end_head);
+  if (HAVE_HIGH_LIFE && (flags & PROP_HIGH_LIFE))
+    {
+      tmp2 = INITIALIZE_REG_SET (tmp2_head);
+      new_high_live_at_end = INITIALIZE_REG_SET (new_high_live_at_end_head);
+    }
+  else
+    tmp2 = 0;
+
   invalidated_by_call = INITIALIZE_REG_SET (invalidated_by_call_head);
 
   /* Inconveniently, this is only readily available in hard reg set form.  */
@@ -1126,6 +1183,8 @@ calculate_global_regs_live (sbitmap bloc
 
       /* Begin by propagating live_at_start from the successor blocks.  */
       CLEAR_REG_SET (new_live_at_end);
+      if (HAVE_HIGH_LIFE && (flags & PROP_HIGH_LIFE))
+	CLEAR_REG_SET (new_high_live_at_end);
 
       if (bb->succ)
 	for (e = bb->succ; e; e = e->succ_next)
@@ -1141,16 +1200,31 @@ calculate_global_regs_live (sbitmap bloc
 		bitmap_operation (tmp, sb->global_live_at_start,
 				  invalidated_by_call, BITMAP_AND_COMPL);
 		IOR_REG_SET (new_live_at_end, tmp);
+		if (HAVE_HIGH_LIFE && (flags & PROP_HIGH_LIFE))
+		  {
+		    bitmap_operation (tmp, sb->global_high_live_at_start,
+				      invalidated_by_call, BITMAP_AND_COMPL);
+		    IOR_REG_SET (new_high_live_at_end, tmp);
+		  }
 	      }
 	    else
-	      IOR_REG_SET (new_live_at_end, sb->global_live_at_start);
+	      {
+	        IOR_REG_SET (new_live_at_end, sb->global_live_at_start);
+		if (HAVE_HIGH_LIFE && (flags & PROP_HIGH_LIFE))
+		  IOR_REG_SET (new_high_live_at_end,
+			       sb->global_high_live_at_start);
+	      }
 
 	    /* If a target saves one register in another (instead of on
 	       the stack) the save register will need to be live for EH.  */
 	    if (e->flags & EDGE_EH)
 	      for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
 		if (EH_USES (i))
-		  SET_REGNO_REG_SET (new_live_at_end, i);
+		  {
+		    SET_REGNO_REG_SET (new_live_at_end, i);
+		    if (HAVE_HIGH_LIFE && (flags & PROP_HIGH_LIFE))
+		      SET_REGNO_REG_SET (new_high_live_at_end, i);
+		  }
 	  }
       else
 	{
@@ -1159,11 +1233,17 @@ calculate_global_regs_live (sbitmap bloc
 	     debugging.  */
 	  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
 	    if (EH_USES (i))
-	      SET_REGNO_REG_SET (new_live_at_end, i);
+	      {
+		SET_REGNO_REG_SET (new_live_at_end, i);
+		if (HAVE_HIGH_LIFE && (flags & PROP_HIGH_LIFE))
+		  SET_REGNO_REG_SET (new_high_live_at_end, i);
+	      }
 	}
 
       /* The all-important stack pointer must always be live.  */
       SET_REGNO_REG_SET (new_live_at_end, STACK_POINTER_REGNUM);
+      if (HAVE_HIGH_LIFE && (flags & PROP_HIGH_LIFE))
+	SET_REGNO_REG_SET (new_high_live_at_end, STACK_POINTER_REGNUM);
 
       /* Before reload, there are a few registers that must be forced
 	 live everywhere -- which might not already be the case for
@@ -1178,19 +1258,41 @@ calculate_global_regs_live (sbitmap bloc
 	  /* Pseudos with argument area equivalences may require
 	     reloading via the argument pointer.  */
 	  if (fixed_regs[ARG_POINTER_REGNUM])
-	    SET_REGNO_REG_SET (new_live_at_end, ARG_POINTER_REGNUM);
+	    {
+	      SET_REGNO_REG_SET (new_live_at_end, ARG_POINTER_REGNUM);
+	      if (HAVE_HIGH_LIFE && (flags & PROP_HIGH_LIFE))
+		SET_REGNO_REG_SET (new_high_live_at_end, ARG_POINTER_REGNUM);
+	    }
 #endif
 
 	  /* Any constant, or pseudo with constant equivalences, may
 	     require reloading from memory using the pic register.  */
 	  if ((unsigned) PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM
 	      && fixed_regs[PIC_OFFSET_TABLE_REGNUM])
-	    SET_REGNO_REG_SET (new_live_at_end, PIC_OFFSET_TABLE_REGNUM);
+	    {
+	      SET_REGNO_REG_SET (new_live_at_end, PIC_OFFSET_TABLE_REGNUM);
+	      if (HAVE_HIGH_LIFE && (flags & PROP_HIGH_LIFE))
+		SET_REGNO_REG_SET (new_high_live_at_end,
+				   PIC_OFFSET_TABLE_REGNUM);
+           }
 	}
 
+#ifdef ENABLE_CHECKING
+      /* A highpart of a register should never be considered to
+	 be live if the register is not considered to be live.  */
+      if (HAVE_HIGH_LIFE && (flags & PROP_HIGH_LIFE))
+	{
+	  CLEAR_REG_SET (tmp);
+	  if (bitmap_operation (tmp, new_high_live_at_end,
+				new_live_at_end, BITMAP_AND_COMPL))
+	    abort ();
+	}
+#endif
       if (bb == ENTRY_BLOCK_PTR)
 	{
 	  COPY_REG_SET (bb->global_live_at_end, new_live_at_end);
+	  if (HAVE_HIGH_LIFE && (flags & PROP_HIGH_LIFE))
+	    COPY_REG_SET (bb->global_high_live_at_end, new_live_at_end);
 	  continue;
 	}
 
@@ -1213,6 +1315,13 @@ calculate_global_regs_live (sbitmap bloc
 	  CLEAR_REG_SET (tmp);
 	  rescan = bitmap_operation (tmp, bb->global_live_at_end,
 				     new_live_at_end, BITMAP_AND_COMPL);
+	  if (HAVE_HIGH_LIFE && (flags & PROP_HIGH_LIFE) && !rescan)
+	    {
+	      CLEAR_REG_SET (tmp);
+	      rescan = bitmap_operation (tmp, bb->global_high_live_at_end,
+					 new_high_live_at_end,
+					 BITMAP_AND_COMPL);
+	    }
 
 	  if (! rescan)
 	    {
@@ -1235,6 +1344,14 @@ calculate_global_regs_live (sbitmap bloc
 	      CLEAR_REG_SET (tmp);
 	      changed = bitmap_operation (tmp, bb->global_live_at_end,
 					  new_live_at_end, BITMAP_XOR);
+	      if (HAVE_HIGH_LIFE && (flags & PROP_HIGH_LIFE))
+		{
+		  CLEAR_REG_SET (tmp2);
+		  changed
+		    |= bitmap_operation (tmp2, bb->global_high_live_at_end,
+					 new_high_live_at_end, BITMAP_XOR);
+		}
+
 	      if (! changed)
 		continue;
 
@@ -1243,6 +1360,9 @@ calculate_global_regs_live (sbitmap bloc
 		 the AND with ~local_set turning off bits.  */
 	      rescan = bitmap_operation (tmp, tmp, bb->local_set,
 					 BITMAP_AND_COMPL);
+	      if (HAVE_HIGH_LIFE && (flags & PROP_HIGH_LIFE))
+		rescan |= bitmap_operation (tmp2, tmp2, bb->local_set,
+					    BITMAP_AND_COMPL);
 	    }
 	}
 
@@ -1263,23 +1383,54 @@ calculate_global_regs_live (sbitmap bloc
 	  changed = bitmap_operation (bb->global_live_at_start,
 				      bb->global_live_at_start,
 				      tmp, BITMAP_IOR);
+	  if (HAVE_HIGH_LIFE && (flags & PROP_HIGH_LIFE))
+	    {
+	      bitmap_operation (tmp, new_high_live_at_end,
+				bb->global_high_live_at_end, BITMAP_AND_COMPL);
+	      COPY_REG_SET (bb->global_high_live_at_end, new_high_live_at_end);
+
+	      changed |= bitmap_operation (bb->global_high_live_at_start,
+					   bb->global_high_live_at_start,
+					   tmp, BITMAP_IOR);
+	    }
 	  if (! changed)
 	    continue;
 	}
       else
 	{
 	  COPY_REG_SET (bb->global_live_at_end, new_live_at_end);
+	  if (HAVE_HIGH_LIFE && (flags & PROP_HIGH_LIFE))
+	    COPY_REG_SET (bb->global_high_live_at_end, new_high_live_at_end);
+	  else
+	    new_high_live_at_end = NULL;
 
 	  /* Rescan the block insn by insn to turn (a copy of) live_at_end
 	     into live_at_start.  */
-	  propagate_block (bb, new_live_at_end, bb->local_set,
-			   bb->cond_local_set, flags);
+	  propagate_block (bb, new_live_at_end, new_high_live_at_end,
+			   bb->local_set, bb->cond_local_set, flags);
 
 	  /* If live_at start didn't change, no need to go farther.  */
-	  if (REG_SET_EQUAL_P (bb->global_live_at_start, new_live_at_end))
+	  if (REG_SET_EQUAL_P (bb->global_live_at_start, new_live_at_end)
+	      && (!HAVE_HIGH_LIFE
+		  || ! (flags & PROP_HIGH_LIFE)
+		  || REG_SET_EQUAL_P (bb->global_high_live_at_start,
+				      new_high_live_at_end)))
 	    continue;
 
+#ifdef ENABLE_CHECKING
+	  /* A highpart of a register should never be considered to
+	     be live if the register is not considered to be live.  */
+	  if (HAVE_HIGH_LIFE && (flags & PROP_HIGH_LIFE))
+	    {
+	      CLEAR_REG_SET (tmp);
+	      if (bitmap_operation (tmp, new_high_live_at_end,
+				    new_live_at_end, BITMAP_AND_COMPL))
+		abort ();
+	    }
+#endif
 	  COPY_REG_SET (bb->global_live_at_start, new_live_at_end);
+	  if (HAVE_HIGH_LIFE && (flags & PROP_HIGH_LIFE))
+	    COPY_REG_SET (bb->global_high_live_at_start, new_high_live_at_end);
 	}
 
       /* Queue all predecessors of BB so that we may re-examine
@@ -1299,6 +1450,8 @@ calculate_global_regs_live (sbitmap bloc
 
   FREE_REG_SET (tmp);
   FREE_REG_SET (new_live_at_end);
+  if (HAVE_HIGH_LIFE && (flags & PROP_HIGH_LIFE))
+    FREE_REG_SET (new_high_live_at_end);
   FREE_REG_SET (invalidated_by_call);
 
   if (blocks_out)
@@ -1446,6 +1599,11 @@ allocate_bb_life_data (void)
     {
       bb->global_live_at_start = OBSTACK_ALLOC_REG_SET (&flow_obstack);
       bb->global_live_at_end = OBSTACK_ALLOC_REG_SET (&flow_obstack);
+      if (HAVE_HIGH_LIFE)
+	{
+	  bb->global_high_live_at_start = OBSTACK_ALLOC_REG_SET (&flow_obstack);
+	  bb->global_high_live_at_end = OBSTACK_ALLOC_REG_SET (&flow_obstack);
+	}
     }
 
   regs_live_at_setjmp = OBSTACK_ALLOC_REG_SET (&flow_obstack);
@@ -1538,6 +1696,14 @@ propagate_block_delete_libcall (rtx insn
   return before;
 }
 
+#if ! HAVE_HIGH_LIFE
+enum attr_highpart
+{
+  HIGHPART_USER, HIGHPART_IGNORE, HIGHPART_EXTEND, HIGHPART_DEPEND,
+  HIGHPART_MUST_SPLIT
+};
+#endif
+
 /* Update the life-status of regs for one insn.  Return the previous insn.  */
 
 rtx
@@ -1553,6 +1719,17 @@ propagate_one_insn (struct propagate_blo
   if (! INSN_P (insn))
     return prev;
 
+#if HAVE_HIGH_LIFE
+  if (pbi->flags & PROP_HIGH_LIFE)
+    {
+      if (GET_CODE (PATTERN (insn)) == USE)
+	pbi->highpart_disposition = HIGHPART_USER;
+      else if (GET_CODE (PATTERN (insn)) == CLOBBER)
+	pbi->highpart_disposition = HIGHPART_IGNORE;
+      else
+	pbi->highpart_disposition = get_attr_highpart (insn);
+    }
+#endif
   note = find_reg_note (insn, REG_RETVAL, NULL_RTX);
   if (flags & PROP_SCAN_DEAD_CODE)
     {
@@ -1632,6 +1809,46 @@ propagate_one_insn (struct propagate_blo
 
       return prev;
     }
+  else if (HAVE_HIGH_LIFE
+	   && (flags & PROP_HIGH_LIFE)
+	   && (flags & PROP_KILL_DEAD_EXTENDS)
+	   && pbi->highpart_disposition == HIGHPART_EXTEND)
+    {
+      int high_dead;
+      rtx src, dst, inner_src, inner_dst;
+
+      extract_insn (insn);
+      inner_src = src = recog_data.operand[1];
+      if ((GET_CODE (src) == SUBREG && subreg_lowpart_p (src))
+	  || GET_CODE (src) == TRUNCATE)
+	inner_src = XEXP (src, 0);
+      inner_dst = dst = recog_data.operand[0];
+      if (GET_CODE (dst) == SUBREG && subreg_lowpart_p (dst))
+	inner_dst = SUBREG_REG (dst);
+      high_dead = highpart_dead_p (pbi, inner_dst);
+      if (high_dead
+	  && GET_CODE (src) == REG
+	  && GET_CODE (dst) == REG
+	  && REGNO (src) == REGNO (dst))
+	{
+	  rtx prev = PREV_INSN (insn);
+
+	  propagate_block_delete_insn (insn);
+	  return prev;
+	}
+      else if (high_dead && GET_CODE (inner_src) == REG)
+	{
+	  if (GET_MODE (inner_dst) == GET_MODE (src))
+	    dst = inner_dst;
+	  else
+	    src = (simplify_gen_subreg (
+		   GET_MODE (dst), inner_src, GET_MODE (inner_src),
+		   subreg_lowpart_offset (GET_MODE (dst),
+					  GET_MODE (inner_src))));
+	  PATTERN (insn) = gen_rtx_SET (VOIDmode, dst, src);
+	  INSN_CODE (insn) = -1;
+	}
+    }
 
   /* See if this is an increment or decrement that can be merged into
      a following memory address.  */
@@ -1691,6 +1908,9 @@ propagate_one_insn (struct propagate_blo
 	EXECUTE_IF_SET_IN_REG_SET (pbi->reg_live, 0, i,
 				   { REG_N_CALLS_CROSSED (i)++; });
 
+      if (HAVE_HIGH_LIFE)
+	pbi->high_out = 0;
+
       /* Record sets.  Do this even for dead instructions, since they
 	 would have killed the values if they hadn't been deleted.  */
       mark_set_regs (pbi, PATTERN (insn), insn);
@@ -1807,13 +2027,14 @@ propagate_one_insn (struct propagate_blo
    the user can use the regsets provided here.  */
 
 struct propagate_block_info *
-init_propagate_block_info (basic_block bb, regset live, regset local_set,
-			   regset cond_local_set, int flags)
+init_propagate_block_info (basic_block bb, regset live, regset high_live,
+			   regset local_set, regset cond_local_set, int flags)
 {
   struct propagate_block_info *pbi = xmalloc (sizeof (*pbi));
 
   pbi->bb = bb;
   pbi->reg_live = live;
+  pbi->reg_high_live = high_live;
   pbi->mem_set_list = NULL_RTX;
   pbi->mem_set_list_len = 0;
   pbi->local_set = local_set;
@@ -2001,14 +2222,15 @@ free_propagate_block_info (struct propag
    Return nonzero if an INSN is deleted (i.e. by dead code removal).  */
 
 int
-propagate_block (basic_block bb, regset live, regset local_set,
-		 regset cond_local_set, int flags)
+propagate_block (basic_block bb, regset live, regset high_live,
+		 regset local_set, regset cond_local_set, int flags)
 {
   struct propagate_block_info *pbi;
   rtx insn, prev;
   int changed;
 
-  pbi = init_propagate_block_info (bb, live, local_set, cond_local_set, flags);
+  pbi = init_propagate_block_info (bb, live, high_live, local_set,
+				   cond_local_set, flags);
 
   if (flags & PROP_REG_INFO)
     {
@@ -2235,6 +2457,35 @@ insn_dead_p (struct propagate_block_info
   return 0;
 }
 
+/* Return 1 if R is a register with a highpart that is dead after the
+   current insn.
+   PBI points to the regsets that says which regs are alive after the insn.  */
+
+static int
+highpart_dead_p (struct propagate_block_info *pbi, rtx r)
+{
+  if (GET_CODE (r) == REG)
+    {
+      int regno = REGNO (r);
+
+      /* Obvious.  */
+      if (REGNO_REG_SET_P (pbi->reg_high_live, regno))
+        return 0;
+
+      /* If this is a multi-reg hard register, bail out.
+	 The highpart of the object will be in one or more
+	 of the actual hard registers, but not visible as a highpart there.
+	 We'd need to know which registers these are, and then do a liveness
+	 check on these.  That would require new target hooks, and is likely
+	 not to accomplish anything.  */
+      if (regno < FIRST_PSEUDO_REGISTER
+	  && HARD_REGNO_NREGS (regno, GET_MODE (r)) > 1)
+	return 0;
+      return 1;
+    }
+  return 0;
+}
+
 /* If INSN is the last insn in a libcall, and assuming INSN is dead,
    return 1 if the entire library call is dead.
    This is true if INSN copies a register (hard or pseudo)
@@ -2801,9 +3052,22 @@ mark_set_1 (struct propagate_block_info 
 	     errors.  */
 	  && regno_first != STACK_POINTER_REGNUM)
 	{
-	  for (i = regno_first; i <= regno_last; ++i)
-	    if (!(not_dead & (((unsigned long) 1) << (i - regno_first))))
-	      CLEAR_REGNO_REG_SET (pbi->reg_live, i);
+	  if (HAVE_HIGH_LIFE && (flags & PROP_HIGH_LIFE))
+	    {
+	      for (i = regno_first; i <= regno_last; ++i)
+		if (!(not_dead & (((unsigned long) 1) << (i - regno_first))))
+		  {
+		    CLEAR_REGNO_REG_SET (pbi->reg_live, i);
+		    pbi->high_out |= REGNO_REG_SET_P (pbi->reg_high_live, i);
+		    CLEAR_REGNO_REG_SET (pbi->reg_high_live, i);
+		  }
+	    }
+	  else
+	    {
+	      for (i = regno_first; i <= regno_last; ++i)
+		if (!(not_dead & (((unsigned long) 1) << (i - regno_first))))
+		  CLEAR_REGNO_REG_SET (pbi->reg_live, i);
+	    }
 	}
     }
   else if (GET_CODE (reg) == REG)
@@ -3600,6 +3864,12 @@ mark_used_reg (struct propagate_block_in
 #endif
 
       SET_REGNO_REG_SET (pbi->reg_live, i);
+      if (HAVE_HIGH_LIFE
+	  && (pbi->flags & PROP_HIGH_LIFE)
+	  && (pbi->highpart_disposition == HIGHPART_USER
+	      || (pbi->highpart_disposition == HIGHPART_DEPEND
+		  && pbi->high_out)))
+	SET_REGNO_REG_SET (pbi->reg_high_live, i);
 
 #ifdef HAVE_conditional_execution
       /* If this is a conditional use, record that fact.  If it is later
@@ -4322,4 +4592,78 @@ reg_set_to_hard_reg_set (HARD_REG_SET *t
 	 return;
        SET_HARD_REG_BIT (*to, i);
      });
+}
+
+/* Split all insns in the function, then do a dead code elimination pass
+   including highpart lifeness calculations.  */
+
+void
+high_life_optimize (void)
+{
+#if HAVE_HIGH_LIFE
+  sbitmap blocks;
+  int changed;
+  basic_block bb;
+
+  blocks = sbitmap_alloc (last_basic_block);
+  sbitmap_zero (blocks);
+  changed = 0;
+
+  high_life_started = 1;
+  FOR_EACH_BB_REVERSE (bb)
+    {
+      rtx insn, next;
+      bool finish = false;
+
+      for (insn = BB_HEAD (bb); !finish ; insn = next)
+	{
+	  rtx last;
+
+	  /* Can't use `next_real_insn' because that might go across
+	     CODE_LABELS and short-out basic blocks.  */
+	  next = NEXT_INSN (insn);
+	  finish = (insn == BB_END (bb));
+	  if (INSN_P (insn)
+	      && GET_CODE (PATTERN (insn)) != USE
+	      && GET_CODE (PATTERN (insn)) != CLOBBER
+	      && get_attr_highpart (insn) == HIGHPART_MUST_SPLIT)
+	    {
+	      last = try_split (PATTERN (insn), insn, 1);
+	      if (last != insn)
+		{
+		  /* try_split returns the NOTE that INSN became.  */
+		  PUT_CODE (insn, NOTE);
+		  NOTE_SOURCE_FILE (insn) = 0;
+		  NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+
+		  /* The split sequence may include barrier, but the
+		     BB boundary we are interested in will be set to
+		     the previous insn.  */
+
+		  while (GET_CODE (last) == BARRIER)
+		    last = PREV_INSN (last);
+		  SET_BIT (blocks, bb->index);
+		  changed = 1;
+		  insn = last;
+		}
+	    }
+	}
+    }
+
+  if (changed)
+    {
+      find_many_sub_basic_blocks (blocks);
+      count_or_remove_death_notes (blocks, 1);
+    }
+
+  update_life_info (NULL, UPDATE_LIFE_GLOBAL,
+		    (PROP_HIGH_LIFE | PROP_KILL_DEAD_EXTENDS
+		     | PROP_SCAN_DEAD_CODE | PROP_KILL_DEAD_CODE
+		     | PROP_DEATH_NOTES));
+#ifdef ENABLE_CHECKING
+  verify_flow_info ();
+#endif
+
+  sbitmap_free (blocks);
+#endif
 }
Index: genconfig.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/genconfig.c,v
retrieving revision 1.50
diff -p -u -r1.50 genconfig.c
--- genconfig.c	1 Jun 2003 15:59:08 -0000	1.50
+++ genconfig.c	28 Jan 2004 21:18:59 -0000
@@ -40,6 +40,7 @@ static int have_cond_exec_flag;
 static int have_lo_sum_flag;
 static int have_peephole_flag;
 static int have_peephole2_flag;
+static int have_high_life_flag;
 
 /* Maximum number of insns seen in a split.  */
 static int max_insns_per_split = 1;
@@ -315,6 +316,11 @@ main (int argc, char **argv)
 	    gen_peephole (desc);
 	    break;
 
+	  case DEFINE_ATTR:
+	    if (strcmp (XSTR (desc, 0), "highpart") == 0)
+	      have_high_life_flag = 1;
+	    break;
+
 	  default:
 	    break;
 	}
@@ -356,6 +362,8 @@ main (int argc, char **argv)
       printf ("#define HAVE_peephole2 1\n");
       printf ("#define MAX_INSNS_PER_PEEP2 %d\n", max_insns_per_peep2);
     }
+
+  printf ("#define HAVE_HIGH_LIFE %d\n", have_high_life_flag);
 
   puts("\n#endif /* GCC_INSN_CONFIG_H */");
 
Index: ifcvt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/ifcvt.c,v
retrieving revision 1.137
diff -p -u -r1.137 ifcvt.c
--- ifcvt.c	25 Jan 2004 03:52:42 -0000	1.137
+++ ifcvt.c	28 Jan 2004 21:18:59 -0000
@@ -2120,6 +2120,9 @@ merge_if_block (struct ce_if_block * ce_
       if (combo_bb->global_live_at_end)
 	COPY_REG_SET (combo_bb->global_live_at_end,
 		      then_bb->global_live_at_end);
+      if (HAVE_HIGH_LIFE && combo_bb->global_high_live_at_end)
+	COPY_REG_SET (combo_bb->global_high_live_at_end,
+		      then_bb->global_high_live_at_end);
       if (dom_computed[CDI_POST_DOMINATORS] >= DOM_NO_FAST_QUERY)
 	delete_from_dominance_info (CDI_POST_DOMINATORS, then_bb);
       merge_blocks (combo_bb, then_bb);
@@ -2187,6 +2190,9 @@ merge_if_block (struct ce_if_block * ce_
       if (combo_bb->global_live_at_end)
 	COPY_REG_SET (combo_bb->global_live_at_end,
 		      join_bb->global_live_at_end);
+      if (HAVE_HIGH_LIFE && combo_bb->global_high_live_at_end)
+	COPY_REG_SET (combo_bb->global_high_live_at_end,
+		      join_bb->global_high_live_at_end);
 
       if (dom_computed[CDI_POST_DOMINATORS] >= DOM_NO_FAST_QUERY)
 	delete_from_dominance_info (CDI_POST_DOMINATORS, join_bb);
@@ -2826,6 +2832,10 @@ find_if_case_1 (basic_block test_bb, edg
   bitmap_operation (test_bb->global_live_at_end,
 		    else_bb->global_live_at_start,
 		    then_bb->global_live_at_end, BITMAP_IOR);
+  if (HAVE_HIGH_LIFE && else_bb->global_high_live_at_start)
+    bitmap_operation (test_bb->global_high_live_at_end,
+		      else_bb->global_high_live_at_start,
+		      then_bb->global_high_live_at_end, BITMAP_IOR);
 
   new_bb = redirect_edge_and_branch_force (FALLTHRU_EDGE (test_bb), else_bb);
   then_bb_index = then_bb->index;
@@ -2908,6 +2918,10 @@ find_if_case_2 (basic_block test_bb, edg
   bitmap_operation (test_bb->global_live_at_end,
 		    then_bb->global_live_at_start,
 		    else_bb->global_live_at_end, BITMAP_IOR);
+  if (HAVE_HIGH_LIFE && then_bb->global_high_live_at_start)
+    bitmap_operation (test_bb->global_high_live_at_end,
+		      then_bb->global_high_live_at_start,
+		      else_bb->global_high_live_at_end, BITMAP_IOR);
 
   if (dom_computed[CDI_POST_DOMINATORS] >= DOM_NO_FAST_QUERY)
     delete_from_dominance_info (CDI_POST_DOMINATORS, else_bb);
@@ -3068,7 +3082,7 @@ dead_or_predicable (basic_block test_bb,
       /* ??? bb->local_set is only valid during calculate_global_regs_live,
 	 so we must recompute usage for MERGE_BB.  Not so bad, I suppose,
          since we've already asserted that MERGE_BB is small.  */
-      propagate_block (merge_bb, tmp, merge_set, merge_set, 0);
+      propagate_block (merge_bb, tmp, NULL, merge_set, merge_set, 0);
 
       /* For small register class machines, don't lengthen lifetimes of
 	 hard registers before reload.  */
@@ -3088,8 +3102,8 @@ dead_or_predicable (basic_block test_bb,
 	 Moreover, we're interested in the insns live from OTHER_BB.  */
 
       COPY_REG_SET (test_live, other_bb->global_live_at_start);
-      pbi = init_propagate_block_info (test_bb, test_live, test_set, test_set,
-				       0);
+      pbi = init_propagate_block_info (test_bb, test_live, NULL,
+				       test_set, test_set, 0);
 
       for (insn = jump; ; insn = prev)
 	{
Index: lcm.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/lcm.c,v
retrieving revision 1.58
diff -p -u -r1.58 lcm.c
--- lcm.c	11 Dec 2003 00:20:45 -0000	1.58
+++ lcm.c	28 Jan 2004 21:18:59 -0000
@@ -1029,6 +1029,18 @@ optimize_mode_switching (FILE *file)
 	  pre_exit = split_edge (eg);
 	  COPY_REG_SET (pre_exit->global_live_at_start, live_at_end);
 	  COPY_REG_SET (pre_exit->global_live_at_end, live_at_end);
+	  if (HAVE_HIGH_LIFE)
+	    {
+	      regset high_live_at_end = eg->src->global_high_live_at_end;
+
+	      if (high_live_at_end)
+		{
+		  COPY_REG_SET (pre_exit->global_high_live_at_start,
+				high_live_at_end);
+	          COPY_REG_SET (pre_exit->global_high_live_at_end,
+				high_live_at_end);
+		}
+	    }
 	}
   }
 #endif
Index: recog.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/recog.c,v
retrieving revision 1.195
diff -p -u -r1.195 recog.c
--- recog.c	23 Jan 2004 23:49:36 -0000	1.195
+++ recog.c	28 Jan 2004 21:18:59 -0000
@@ -3072,9 +3072,10 @@ peephole2_optimize (FILE *dump_file ATTR
       COPY_REG_SET (peep2_insn_data[MAX_INSNS_PER_PEEP2].live_before, live);
 
 #ifdef HAVE_conditional_execution
-      pbi = init_propagate_block_info (bb, live, NULL, NULL, 0);
+      pbi = init_propagate_block_info (bb, live, NULL, NULL, NULL, 0);
 #else
-      pbi = init_propagate_block_info (bb, live, NULL, NULL, PROP_DEATH_NOTES);
+      pbi = init_propagate_block_info (bb, live, NULL, NULL, NULL,
+				       PROP_DEATH_NOTES);
 #endif
 
       for (insn = BB_END (bb); ; insn = prev)
Index: rtl.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/rtl.h,v
retrieving revision 1.452
diff -p -u -r1.452 rtl.h
--- rtl.h	23 Jan 2004 21:05:17 -0000	1.452
+++ rtl.h	28 Jan 2004 21:18:59 -0000
@@ -1987,6 +1987,9 @@ extern int cse_not_expected;
    generate any new pseudo registers.  */
 extern int no_new_pseudos;
 
+/* Set to nonzero once highpart lifeness optimizations start.  */
+extern int high_life_started;
+
 /* Translates rtx code to tree code, for those codes needed by
    REAL_ARITHMETIC.  The function returns an int because the caller may not
    know what `enum tree_code' means.  */
@@ -2161,6 +2164,7 @@ extern rtx move_by_pieces (rtx, rtx, uns
 extern void recompute_reg_usage (rtx, int);
 extern int initialize_uninitialized_subregs (void);
 extern void delete_dead_jumptables (void);
+extern void high_life_optimize (void);
 #ifdef BUFSIZ
 extern void print_rtl_with_bb (FILE *, rtx);
 extern void dump_flow_info (FILE *);
Index: timevar.def
===================================================================
RCS file: /cvs/gcc/gcc/gcc/timevar.def,v
retrieving revision 1.22
diff -p -u -r1.22 timevar.def
--- timevar.def	21 Nov 2003 04:05:05 -0000	1.22
+++ timevar.def	28 Jan 2004 21:18:59 -0000
@@ -76,6 +76,7 @@ DEFTIMEVAR (TV_VPT                   , "
 DEFTIMEVAR (TV_FLOW                  , "flow analysis")
 DEFTIMEVAR (TV_COMBINE               , "combiner")
 DEFTIMEVAR (TV_IFCVT		     , "if-conversion")
+DEFTIMEVAR (TV_HIGH_LIFE             , "high life")
 DEFTIMEVAR (TV_REGMOVE               , "regmove")
 DEFTIMEVAR (TV_MODE_SWITCH           , "mode switching")
 DEFTIMEVAR (TV_SCHED                 , "scheduling")
Index: toplev.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/toplev.c,v
retrieving revision 1.869
diff -p -u -r1.869 toplev.c
--- toplev.c	23 Jan 2004 21:05:17 -0000	1.869
+++ toplev.c	28 Jan 2004 21:19:00 -0000
@@ -194,6 +194,9 @@ struct line_maps line_table;
 /* Nonzero if it is unsafe to create any new pseudo registers.  */
 int no_new_pseudos;
 
+/* Nonzero once highpart lifeness optimizations have started.  */
+int high_life_started;
+
 /* Stack of currently pending input files.  */
 
 struct file_stack *input_file_stack;
@@ -275,6 +278,7 @@ enum dump_file_index
   DFI_life,
   DFI_combine,
   DFI_ce2,
+  DFI_high_life,
   DFI_regmove,
   DFI_sched,
   DFI_lreg,
@@ -326,6 +330,7 @@ static struct dump_file_info dump_file[D
   { "life",	'f', 1, 0, 0 },	/* Yes, duplicate enable switch.  */
   { "combine",	'c', 1, 0, 0 },
   { "ce2",	'C', 1, 0, 0 },
+  { "high-life",'f', 1, 0, 0 },	/* Yes, duplicate enable switch.  */
   { "regmove",	'N', 1, 0, 0 },
   { "sched",	'S', 1, 0, 0 },
   { "lreg",	'l', 1, 0, 0 },
@@ -2809,11 +2814,13 @@ rest_of_handle_life (tree decl, rtx insn
 #ifdef ENABLE_CHECKING
   verify_flow_info ();
 #endif
-  life_analysis (insns, rtl_dump_file, PROP_FINAL);
+  init_recog (); /* Needed in order to test highpart attribute.  */
+  life_analysis (insns, rtl_dump_file, PROP_FINAL | PROP_HIGH_LIFE);
   if (optimize)
     cleanup_cfg ((optimize ? CLEANUP_EXPENSIVE : 0) | CLEANUP_UPDATE_LIFE
 		 | CLEANUP_LOG_LINKS
 		 | (flag_thread_jumps ? CLEANUP_THREADING : 0));
+  init_recog_no_volatile ();
   timevar_pop (TV_FLOW);
 
   if (warn_uninitialized)
@@ -3081,6 +3088,22 @@ rest_of_handle_loop2 (tree decl, rtx ins
   ggc_collect ();
 }
 
+/* Perform highpart life analysis.  */
+static void
+rest_of_high_life (tree decl, rtx insns)
+{
+#ifdef HAVE_HIGH_LIFE
+  timevar_push (TV_HIGH_LIFE);
+  open_dump_file (DFI_high_life, decl);
+
+  high_life_optimize ();
+
+  close_dump_file (DFI_high_life, print_rtl_with_bb, insns);
+  timevar_pop (TV_HIGH_LIFE);
+
+  ggc_collect ();
+#endif /* HAVE_HIGH_LIFE */
+}
 /* This is called from finish_function (within langhooks.parse_file)
    after each top-level definition is parsed.
    It is supposed to compile that function or variable
@@ -3364,6 +3387,9 @@ rest_of_compilation (tree decl)
   if (flag_if_conversion)
     rest_of_handle_if_after_combine (decl, insns);
 
+  if (optimize > 0)
+    rest_of_high_life (decl, insns);
+
   if (optimize > 0 && (flag_regmove || flag_expensive_optimizations))
     rest_of_handle_regmove (decl, insns);
 
@@ -3619,6 +3645,7 @@ rest_of_compilation (tree decl)
     sdbout_types (NULL_TREE);
 #endif
 
+  high_life_started = 0;
   reload_completed = 0;
   epilogue_completed = 0;
   flow2_completed = 0;
Index: config/sh/sh.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/sh/sh.md,v
retrieving revision 1.165
diff -p -u -r1.165 sh.md
--- config/sh/sh.md	12 Jan 2004 16:20:14 -0000	1.165
+++ config/sh/sh.md	28 Jan 2004 21:19:00 -0000
@@ -589,6 +589,9 @@
 	 (const_string "yes")]
 	(const_string "no")))
 
+(define_attr "highpart" "user, ignore, extend, depend, must_split"
+  (const_string "user"))
+
 (define_delay
   (eq_attr "needs_delay_slot" "yes")
   [(eq_attr "in_delay_slot" "yes") (nil) (nil)])
@@ -1023,7 +1026,8 @@
 		  (match_operand:SI 2 "extend_reg_or_0_operand" "rN"))))]
   "TARGET_SHMEDIA"
   "addz.l	%1, %N2, %0"
-  [(set_attr "type" "arith_media")])
+  [(set_attr "type" "arith_media")
+   (set_attr "highpart" "ignore")])
 
 (define_insn "adddi3_compact"
   [(set (match_operand:DI 0 "arith_reg_operand" "=&r")
@@ -1096,7 +1100,8 @@
   "@
 	add.l	%1, %2, %0
 	addi.l	%1, %2, %0"
-  [(set_attr "type" "arith_media")])
+  [(set_attr "type" "arith_media")
+   (set_attr "highpart" "ignore")])
 
 (define_insn "*addsi3_compact"
   [(set (match_operand:SI 0 "arith_reg_operand" "=r")
@@ -1201,7 +1206,8 @@
 		  (match_operand:SI 2 "extend_reg_operand" "r")))]
   "TARGET_SHMEDIA"
   "sub.l	%N1, %2, %0"
-  [(set_attr "type" "arith_media")])
+  [(set_attr "type" "arith_media")
+   (set_attr "highpart" "ignore")])
 
 ;; Convert `constant - reg' to `neg rX; add rX, #const' since this
 ;; will sometimes save one instruction.  Otherwise we might get
@@ -1766,7 +1772,8 @@
 		 (sign_extend:DI (match_operand:SI 2 "extend_reg_operand" "r"))))]
   "TARGET_SHMEDIA"
   "muls.l	%1, %2, %0"
-  [(set_attr "type" "dmpy_media")])
+  [(set_attr "type" "dmpy_media")
+   (set_attr "highpart" "ignore")])
 
 (define_insn "mulsidi3_compact"
   [(set (match_operand:DI 0 "arith_reg_operand" "=r")
@@ -1837,7 +1844,8 @@
 		 (zero_extend:DI (match_operand:SI 2 "extend_reg_operand" "r"))))]
   "TARGET_SHMEDIA"
   "mulu.l	%1, %2, %0"
-  [(set_attr "type" "dmpy_media")])
+  [(set_attr "type" "dmpy_media")
+   (set_attr "highpart" "ignore")])
 
 (define_insn "umulsidi3_compact"
   [(set (match_operand:DI 0 "arith_reg_operand" "=r")
@@ -2308,7 +2316,8 @@
   "@
 	shlld.l	%1, %2, %0
 	shlli.l	%1, %2, %0"
-  [(set_attr "type" "arith_media")])
+  [(set_attr "type" "arith_media")
+   (set_attr "highpart" "ignore")])
 
 (define_expand "ashlsi3"
   [(parallel [(set (match_operand:SI 0 "arith_reg_operand" "")
@@ -2463,7 +2472,8 @@
   "@
 	shard.l	%1, %2, %0
 	shari.l	%1, %2, %0"
-  [(set_attr "type" "arith_media")])
+  [(set_attr "type" "arith_media")
+   (set_attr "highpart" "ignore")])
 
 (define_expand "ashrsi3"
   [(parallel [(set (match_operand:SI 0 "arith_reg_operand" "")
@@ -2552,7 +2562,8 @@
   "@
 	shlrd.l	%1, %2, %0
 	shlri.l	%1, %2, %0"
-  [(set_attr "type" "arith_media")])
+  [(set_attr "type" "arith_media")
+    (set_attr "highpart" "ignore")])
 
 (define_expand "lshrsi3"
   [(parallel [(set (match_operand:SI 0 "arith_reg_operand" "")
@@ -2993,7 +3004,8 @@
 	(zero_extend:DI (match_operand:SI 1 "extend_reg_operand" "r")))]
   "TARGET_SHMEDIA"
   "addz.l	%1, r63, %0"
-  [(set_attr "type" "arith_media")])
+  [(set_attr "type" "arith_media")
+   (set_attr "highpart" "extend")])
 
 (define_insn "zero_extendhidi2"
   [(set (match_operand:DI 0 "register_operand" "=r,r")
@@ -3002,7 +3014,8 @@
   "@
 	#
 	ld%M1.uw	%m1, %0"
-  [(set_attr "type" "*,load_media")])
+  [(set_attr "type" "*,load_media")
+   (set_attr "highpart" "ignore")])
 
 (define_split
   [(set (match_operand:DI 0 "register_operand" "")
@@ -3034,7 +3047,8 @@
   "@
 	andi	%1, 255, %0
 	ld%M1.ub	%m1, %0"
-  [(set_attr "type" "arith_media,load_media")])
+  [(set_attr "type" "arith_media,load_media")
+   (set_attr "highpart" "ignore")])
 
 (define_expand "zero_extendhisi2"
   [(set (match_operand:SI 0 "arith_reg_operand" "")
@@ -3060,7 +3074,8 @@
   "@
 	#
 	ld%M1.uw	%m1, %0"
-  [(set_attr "type" "arith_media,load_media")])
+  [(set_attr "type" "arith_media,load_media")
+   (set_attr "highpart" "ignore")])
 
 (define_split
   [(set (match_operand:SI 0 "register_operand" "")
@@ -3098,7 +3113,8 @@
   "@
 	andi	%1, 255, %0
 	ld%M1.ub	%m1, %0"
-  [(set_attr "type" "arith_media,load_media")])
+  [(set_attr "type" "arith_media,load_media")
+   (set_attr "highpart" "ignore")])
 
 (define_insn "zero_extendqihi2"
   [(set (match_operand:HI 0 "arith_reg_operand" "=r")
@@ -3122,7 +3138,8 @@
   "@
 	add.l	%1, r63, %0
 	ld%M1.l	%m1, %0"
-  [(set_attr "type" "arith_media,load_media")])
+  [(set_attr "type" "arith_media,load_media")
+   (set_attr "highpart" "extend")])
 
 (define_insn "extendhidi2"
   [(set (match_operand:DI 0 "register_operand" "=r,r")
@@ -3131,7 +3148,8 @@
   "@
 	#
 	ld%M1.w	%m1, %0"
-  [(set_attr "type" "*,load_media")])
+  [(set_attr "type" "*,load_media")
+   (set_attr "highpart" "ignore")])
 
 (define_split
   [(set (match_operand:DI 0 "register_operand" "")
@@ -3152,7 +3170,8 @@
   "@
 	#
 	ld%M1.b	%m1, %0"
-  [(set_attr "type" "*,load_media")])
+  [(set_attr "type" "*,load_media")
+   (set_attr "highpart" "ignore")])
 
 (define_split
   [(set (match_operand:DI 0 "register_operand" "")
@@ -3188,7 +3207,8 @@
   "@
 	#
 	ld%M1.w	%m1, %0"
-  [(set_attr "type" "arith_media,load_media")])
+  [(set_attr "type" "arith_media,load_media")
+   (set_attr "highpart" "ignore")])
 
 (define_split
   [(set (match_operand:SI 0 "register_operand" "")
@@ -3224,7 +3244,8 @@
   "@
 	#
 	ld%M1.b	%m1, %0"
-  [(set_attr "type" "arith_media,load_media")])
+  [(set_attr "type" "arith_media,load_media")
+   (set_attr "highpart" "ignore")])
 
 (define_split
   [(set (match_operand:SI 0 "register_operand" "")
@@ -3261,7 +3282,8 @@
 	fmov.ls	%1, %0
 	fmov.sl	%T1, %0
 	fmov.s	%T1, %0"
-  [(set_attr "type"   "arith_media,store_media,fstore_media,fload_media,fpconv_media,fmove_media")])
+  [(set_attr "type"   "arith_media,store_media,fstore_media,fload_media,fpconv_media,fmove_media")
+   (set_attr "highpart" "extend")])
 
 
 (define_insn "truncdihi2"
@@ -3272,7 +3294,8 @@
 	shlli\\t%1,48,%0\;shlri\\t%0,48,%0
 	st%M0.w	%m0, %1"
   [(set_attr "type"   "arith_media,store_media")
-   (set_attr "length" "8,4")])
+   (set_attr "length" "8,4")
+   (set_attr "highpart" "extend")])
 
 ; N.B. This should agree with LOAD_EXTEND_OP and movqi.
 ; Because we use zero extension, we can't provide signed QImode compares
@@ -3284,7 +3307,8 @@
   "@
 	andi	%1, 255, %0
 	st%M0.b	%m0, %1"
-  [(set_attr "type"   "arith_media,store")])
+  [(set_attr "type"   "arith_media,store")
+   (set_attr "highpart" "extend")])
 
 ;; -------------------------------------------------------------------------
 ;; Move instructions
@@ -3521,7 +3545,8 @@
 	gettr	%1, %0
 	pt	%1, %0"
   [(set_attr "type"   "arith_media,arith_media,*,load_media,store_media,fload_media,fstore_media,fload_media,fpconv_media,fmove_media,ptabs_media,gettr_media,pt_media")
-   (set_attr "length" "4,4,8,4,4,4,4,4,4,4,4,4,12")])
+   (set_attr "length" "4,4,8,4,4,4,4,4,4,4,4,4,12")
+   (set_attr "highpart" "ignore")])
 
 (define_insn "*movsi_media_nofpu"
   [(set (match_operand:SI 0 "general_movdst_operand"
@@ -3541,7 +3566,8 @@
 	gettr	%1, %0
 	pt	%1, %0"
   [(set_attr "type"   "arith_media,arith_media,*,load_media,store_media,ptabs_media,gettr_media,pt_media")
-   (set_attr "length" "4,4,8,4,4,4,4,12")])
+   (set_attr "length" "4,4,8,4,4,4,4,12")
+   (set_attr "highpart" "ignore")])
 
 (define_split
   [(set (match_operand:SI 0 "arith_reg_operand" "")
@@ -3685,7 +3711,8 @@
 	movi	%1, %0
 	ld%M1.ub	%m1, %0
 	st%M0.b	%m0, %N1"
-  [(set_attr "type" "arith_media,arith_media,load_media,store_media")])
+  [(set_attr "type" "arith_media,arith_media,load_media,store_media")
+   (set_attr "highpart" "ignore")])
 
 (define_expand "movqi"
   [(set (match_operand:QI 0 "general_operand" "")
@@ -3743,7 +3770,8 @@
 	#
 	ld%M1.w	%m1, %0
 	st%M0.w	%m0, %N1"
-  [(set_attr "type" "arith_media,arith_media,*,load_media,store_media")])
+  [(set_attr "type" "arith_media,arith_media,*,load_media,store_media")
+   (set_attr "highpart" "ignore")])
 
 (define_split
   [(set (match_operand:HI 0 "register_operand" "")
@@ -4853,7 +4881,8 @@
 	fst%M0.s	%m0, %1
 	ld%M1.l	%m1, %0
 	st%M0.l	%m0, %N1"
-  [(set_attr "type" "fmove_media,fload_media,fpconv_media,arith_media,*,fload_media,fstore_media,load_media,store_media")])
+  [(set_attr "type" "fmove_media,fload_media,fpconv_media,arith_media,*,fload_media,fstore_media,load_media,store_media")
+   (set_attr "highpart" "ignore")])
 
 (define_insn "movsf_media_nofpu"
   [(set (match_operand:SF 0 "general_movdst_operand" "=r,r,r,m")
@@ -4866,7 +4895,8 @@
 	#
 	ld%M1.l	%m1, %0
 	st%M0.l	%m0, %N1"
-  [(set_attr "type" "arith_media,*,load_media,store_media")])
+  [(set_attr "type" "arith_media,*,load_media,store_media")
+   (set_attr "highpart" "ignore")])
 
 (define_split
   [(set (match_operand:SF 0 "arith_reg_operand" "")
@@ -9528,7 +9558,8 @@ mov.l\\t1f,r0\\n\\
 	ld%M1.l	%m1, %0
 	st%M0.l	%m0, %N1"
   [(set_attr "type"   "arith_media,arith_media,*,load_media,store_media")
-   (set_attr "length" "4,4,16,4,4")])
+   (set_attr "length" "4,4,16,4,4")
+   (set_attr "highpart" "ignore")])
 
 (define_expand "movv4hi"
   [(set (match_operand:V4HI 0 "general_movdst_operand" "")
@@ -9549,7 +9580,8 @@ mov.l\\t1f,r0\\n\\
 	ld%M1.q	%m1, %0
 	st%M0.q	%m0, %N1"
   [(set_attr "type"   "arith_media,arith_media,*,load_media,store_media")
-   (set_attr "length" "4,4,16,4,4")])
+   (set_attr "length" "4,4,16,4,4")
+   (set_attr "highpart" "depend")])
 
 (define_expand "movv2si"
   [(set (match_operand:V2SI 0 "general_movdst_operand" "")
@@ -9570,7 +9602,8 @@ mov.l\\t1f,r0\\n\\
 	ld%M1.q	%m1, %0
 	st%M0.q	%m0, %N1"
   [(set_attr "type"   "arith_media,arith_media,*,load_media,store_media")
-   (set_attr "length" "4,4,16,4,4")])
+   (set_attr "length" "4,4,16,4,4")
+   (set_attr "highpart" "depend")])
 
 ;; Multimedia Intrinsics
 
@@ -9579,14 +9612,16 @@ mov.l\\t1f,r0\\n\\
 	(abs:V2SI (match_operand:V2SI 1 "arith_reg_operand" "r")))]
   "TARGET_SHMEDIA"
   "mabs.l	%1, %0"
-  [(set_attr "type" "mcmp_media")])
+  [(set_attr "type" "mcmp_media")
+   (set_attr "highpart" "depend")])
 
 (define_insn "absv4hi2"
   [(set (match_operand:V4HI 0 "arith_reg_dest" "=r")
 	(abs:V4HI (match_operand:V4HI 1 "arith_reg_operand" "r")))]
   "TARGET_SHMEDIA"
   "mabs.w	%1, %0"
-  [(set_attr "type" "mcmp_media")])
+  [(set_attr "type" "mcmp_media")
+   (set_attr "highpart" "depend")])
 
 (define_insn "addv2si3"
   [(set (match_operand:V2SI 0 "arith_reg_dest" "=r")
@@ -9594,7 +9629,8 @@ mov.l\\t1f,r0\\n\\
 		   (match_operand:V2SI 2 "arith_reg_operand" "r")))]
   "TARGET_SHMEDIA"
   "madd.l	%1, %2, %0"
-  [(set_attr "type" "arith_media")])
+  [(set_attr "type" "arith_media")
+   (set_attr "highpart" "depend")])
 
 (define_insn "addv4hi3"
   [(set (match_operand:V4HI 0 "arith_reg_dest" "=r")
@@ -9602,7 +9638,8 @@ mov.l\\t1f,r0\\n\\
 		   (match_operand:V4HI 2 "arith_reg_operand" "r")))]
   "TARGET_SHMEDIA"
   "madd.w	%1, %2, %0"
-  [(set_attr "type" "arith_media")])
+  [(set_attr "type" "arith_media")
+   (set_attr "highpart" "depend")])
 
 (define_insn "ssaddv2si3"
   [(set (match_operand:V2SI 0 "arith_reg_dest" "=r")
@@ -9610,7 +9647,8 @@ mov.l\\t1f,r0\\n\\
 		      (match_operand:V2SI 2 "arith_reg_operand" "r")))]
   "TARGET_SHMEDIA"
   "madds.l	%1, %2, %0"
-  [(set_attr "type" "mcmp_media")])
+  [(set_attr "type" "mcmp_media")
+   (set_attr "highpart" "depend")])
 
 (define_insn "usaddv8qi3"
   [(set (match_operand:V8QI 0 "arith_reg_dest" "=r")
@@ -9618,7 +9656,8 @@ mov.l\\t1f,r0\\n\\
 		      (match_operand:V8QI 2 "arith_reg_operand" "r")))]
   "TARGET_SHMEDIA"
   "madds.ub	%1, %2, %0"
-  [(set_attr "type" "mcmp_media")])
+  [(set_attr "type" "mcmp_media")
+   (set_attr "highpart" "depend")])
 
 (define_insn "ssaddv4hi3"
   [(set (match_operand:V4HI 0 "arith_reg_dest" "=r")
@@ -9626,7 +9665,8 @@ mov.l\\t1f,r0\\n\\
 		      (match_operand:V4HI 2 "arith_reg_operand" "r")))]
   "TARGET_SHMEDIA"
   "madds.w	%1, %2, %0"
-  [(set_attr "type" "mcmp_media")])
+  [(set_attr "type" "mcmp_media")
+   (set_attr "highpart" "depend")])
 
 (define_insn "negcmpeqv8qi"
   [(set (match_operand:V8QI 0 "arith_reg_dest" "=r")
@@ -9634,7 +9674,8 @@ mov.l\\t1f,r0\\n\\
 			   (match_operand:V8QI 2 "arith_reg_or_0_operand" "rZ"))))]
   "TARGET_SHMEDIA"
   "mcmpeq.b	%N1, %N2, %0"
-  [(set_attr "type" "mcmp_media")])
+  [(set_attr "type" "mcmp_media")
+   (set_attr "highpart" "depend")])
 
 (define_insn "negcmpeqv2si"
   [(set (match_operand:V2SI 0 "arith_reg_dest" "=r")
@@ -9642,7 +9683,8 @@ mov.l\\t1f,r0\\n\\
 			   (match_operand:V2SI 2 "arith_reg_or_0_operand" "rZ"))))]
   "TARGET_SHMEDIA"
   "mcmpeq.l	%N1, %N2, %0"
-  [(set_attr "type" "mcmp_media")])
+  [(set_attr "type" "mcmp_media")
+   (set_attr "highpart" "depend")])
 
 (define_insn "negcmpeqv4hi"
   [(set (match_operand:V4HI 0 "arith_reg_dest" "=r")
@@ -9650,7 +9692,8 @@ mov.l\\t1f,r0\\n\\
 			   (match_operand:V4HI 2 "arith_reg_or_0_operand" "rZ"))))]
   "TARGET_SHMEDIA"
   "mcmpeq.w	%N1, %N2, %0"
-  [(set_attr "type" "mcmp_media")])
+  [(set_attr "type" "mcmp_media")
+   (set_attr "highpart" "depend")])
 
 (define_insn "negcmpgtuv8qi"
   [(set (match_operand:V8QI 0 "arith_reg_dest" "=r")
@@ -9658,7 +9701,8 @@ mov.l\\t1f,r0\\n\\
 			    (match_operand:V8QI 2 "arith_reg_or_0_operand" "rZ"))))]
   "TARGET_SHMEDIA"
   "mcmpgt.ub	%N1, %N2, %0"
-  [(set_attr "type" "mcmp_media")])
+  [(set_attr "type" "mcmp_media")
+   (set_attr "highpart" "depend")])
 
 (define_insn "negcmpgtv2si"
   [(set (match_operand:V2SI 0 "arith_reg_dest" "=r")
@@ -9666,7 +9710,8 @@ mov.l\\t1f,r0\\n\\
 			   (match_operand:V2SI 2 "arith_reg_or_0_operand" "rZ"))))]
   "TARGET_SHMEDIA"
   "mcmpgt.l	%N1, %N2, %0"
-  [(set_attr "type" "mcmp_media")])
+  [(set_attr "type" "mcmp_media")
+   (set_attr "highpart" "depend")])
 
 (define_insn "negcmpgtv4hi"
   [(set (match_operand:V4HI 0 "arith_reg_dest" "=r")
@@ -9674,7 +9719,8 @@ mov.l\\t1f,r0\\n\\
 			   (match_operand:V4HI 2 "arith_reg_or_0_operand" "rZ"))))]
   "TARGET_SHMEDIA"
   "mcmpgt.w	%N1, %N2, %0"
-  [(set_attr "type" "mcmp_media")])
+  [(set_attr "type" "mcmp_media")
+   (set_attr "highpart" "depend")])
 
 (define_insn "mcmv"
   [(set (match_operand:DI 0 "arith_reg_dest" "=r")
@@ -9684,7 +9730,8 @@ mov.l\\t1f,r0\\n\\
 			(not:DI (match_dup 2)))))]
   "TARGET_SHMEDIA"
   "mcmv	%N1, %2, %0"
-  [(set_attr "type" "arith_media")])
+  [(set_attr "type" "arith_media")
+   (set_attr "highpart" "depend")])
 
 (define_insn "mcnvs_lw"
   [(set (match_operand:V4HI 0 "arith_reg_dest" "=r")
@@ -9859,7 +9906,8 @@ mov.l\\t1f,r0\\n\\
 	   (const_int 1)))))]
   "TARGET_SHMEDIA"
   "mmacfx.wl	%2, %3, %0"
-  [(set_attr "type" "mac_media")])
+  [(set_attr "type" "mac_media")
+   (set_attr "highpart" "depend")])
 
 (define_expand "mmacnfx_wl"
   [(match_operand:V2SI 0 "arith_reg_dest" "")
@@ -9887,7 +9935,8 @@ mov.l\\t1f,r0\\n\\
 	   (const_int 1)))))]
   "TARGET_SHMEDIA"
   "mmacnfx.wl	%2, %3, %0"
-  [(set_attr "type" "mac_media")])
+  [(set_attr "type" "mac_media")
+   (set_attr "highpart" "depend")])
 
 (define_insn "mulv2si3"
   [(set (match_operand:V2SI 0 "arith_reg_dest" "=r")
@@ -9895,7 +9944,8 @@ mov.l\\t1f,r0\\n\\
 		   (match_operand:V2SI 2 "arith_reg_operand" "r")))]
   "TARGET_SHMEDIA"
   "mmul.l	%1, %2, %0"
-  [(set_attr "type" "d2mpy_media")])
+  [(set_attr "type" "d2mpy_media")
+   (set_attr "highpart" "depend")])
 
 (define_insn "mulv4hi3"
   [(set (match_operand:V4HI 0 "arith_reg_dest" "=r")
@@ -9903,7 +9953,8 @@ mov.l\\t1f,r0\\n\\
 		   (match_operand:V4HI 2 "arith_reg_operand" "r")))]
   "TARGET_SHMEDIA"
   "mmul.w	%1, %2, %0"
-  [(set_attr "type" "dmpy_media")])
+  [(set_attr "type" "dmpy_media")
+   (set_attr "highpart" "depend")])
 
 (define_insn "mmulfx_l"
   [(set (match_operand:V2SI 0 "arith_reg_dest" "=r")
@@ -9915,7 +9966,8 @@ mov.l\\t1f,r0\\n\\
 	  (const_int 31))))]
   "TARGET_SHMEDIA"
   "mmulfx.l	%1, %2, %0"
-  [(set_attr "type" "d2mpy_media")])
+  [(set_attr "type" "d2mpy_media")
+   (set_attr "highpart" "depend")])
 
 (define_insn "mmulfx_w"
   [(set (match_operand:V4HI 0 "arith_reg_dest" "=r")
@@ -9927,7 +9979,8 @@ mov.l\\t1f,r0\\n\\
 	  (const_int 15))))]
   "TARGET_SHMEDIA"
   "mmulfx.w	%1, %2, %0"
-  [(set_attr "type" "dmpy_media")])
+  [(set_attr "type" "dmpy_media")
+   (set_attr "highpart" "depend")])
 
 (define_insn "mmulfxrp_w"
   [(set (match_operand:V4HI 0 "arith_reg_dest" "=r")
@@ -9941,7 +9994,8 @@ mov.l\\t1f,r0\\n\\
 	  (const_int 15))))]
   "TARGET_SHMEDIA"
   "mmulfxrp.w	%1, %2, %0"
-  [(set_attr "type" "dmpy_media")])
+  [(set_attr "type" "dmpy_media")
+   (set_attr "highpart" "depend")])
 
 (define_expand "mmulhi_wl"
   [(match_operand:V2SI 0 "arith_reg_dest" "")
@@ -9978,7 +10032,10 @@ mov.l\\t1f,r0\\n\\
   "* return (TARGET_LITTLE_ENDIAN
 	     ? \"mmulhi.wl	%1, %2, %0\"
 	     : \"mmullo.wl	%1, %2, %0\");"
-  [(set_attr "type" "dmpy_media")])
+  [(set_attr "type" "dmpy_media")
+   (set (attr "highpart")
+	(if_then_else (eq_attr "endian" "little")
+		      (const_string "user") (const_string "ignore")))])
 
 (define_insn "mmul01_wl"
   [(set (match_operand:V2SI 0 "arith_reg_dest" "=r")
@@ -9991,7 +10048,10 @@ mov.l\\t1f,r0\\n\\
   "* return (TARGET_LITTLE_ENDIAN
 	     ? \"mmullo.wl	%1, %2, %0\"
 	     : \"mmulhi.wl	%1, %2, %0\");"
-  [(set_attr "type" "dmpy_media")])
+  [(set_attr "type" "dmpy_media")
+   (set (attr "highpart")
+	(if_then_else (eq_attr "endian" "little")
+		      (const_string "ignore") (const_string "user")))])
 
 (define_expand "mmulsum_wq"
   [(match_operand:DI 0 "arith_reg_dest" "")
@@ -10080,7 +10140,8 @@ mov.l\\t1f,r0\\n\\
 					  "trunc_hi_operand" "r"))))]
   "TARGET_SHMEDIA"
   "mperm.w	%1, r63, %0"
-  [(set_attr "type" "arith_media")])
+  [(set_attr "type" "arith_media")
+   (set_attr "highpart" "ignore")])
 
 (define_expand "msad_ubq"
   [(match_operand:DI 0 "arith_reg_dest" "")
@@ -10147,7 +10208,8 @@ mov.l\\t1f,r0\\n\\
 		  (const_int 31)))))]
   "TARGET_SHMEDIA"
   "mshalds.l	%1, %2, %0"
-  [(set_attr "type" "mcmp_media")])
+  [(set_attr "type" "mcmp_media")
+   (set_attr "highpart" "depend")])
 
 (define_insn "mshalds_w"
   [(set (match_operand:V4HI 0 "arith_reg_dest" "=r")
@@ -10158,7 +10220,8 @@ mov.l\\t1f,r0\\n\\
 		  (const_int 15)))))]
   "TARGET_SHMEDIA"
   "mshalds.w	%1, %2, %0"
-  [(set_attr "type" "mcmp_media")])
+  [(set_attr "type" "mcmp_media")
+   (set_attr "highpart" "depend")])
 
 (define_insn "ashrv2si3"
   [(set (match_operand:V2SI 0 "arith_reg_dest" "=r")
@@ -10166,7 +10229,8 @@ mov.l\\t1f,r0\\n\\
 		       (match_operand:DI 2 "arith_reg_operand" "r")))]
   "TARGET_SHMEDIA"
   "mshard.l	%1, %2, %0"
-  [(set_attr "type" "arith_media")])
+  [(set_attr "type" "arith_media")
+   (set_attr "highpart" "depend")])
 
 (define_insn "ashrv4hi3"
   [(set (match_operand:V4HI 0 "arith_reg_dest" "=r")
@@ -10174,7 +10238,8 @@ mov.l\\t1f,r0\\n\\
 		       (match_operand:DI 2 "arith_reg_operand" "r")))]
   "TARGET_SHMEDIA"
   "mshard.w	%1, %2, %0"
-  [(set_attr "type" "arith_media")])
+  [(set_attr "type" "arith_media")
+   (set_attr "highpart" "depend")])
 
 (define_insn "mshards_q"
   [(set (match_operand:HI 0 "arith_reg_dest" "=r")
@@ -10271,7 +10336,10 @@ mov.l\\t1f,r0\\n\\
   "* return (TARGET_LITTLE_ENDIAN
 	     ? \"mshfhi.l	%N1, %N2, %0\"
 	     : \"mshflo.l	%N1, %N2, %0\");"
-  [(set_attr "type" "arith_media")])
+  [(set_attr "type" "arith_media")
+   (set (attr "highpart")
+	(if_then_else (eq_attr "endian" "little")
+		      (const_string "user") (const_string "ignore")))])
 
 (define_insn "mshf0_l"
   [(set (match_operand:V2SI 0 "arith_reg_dest" "=r")
@@ -10283,7 +10351,10 @@ mov.l\\t1f,r0\\n\\
   "* return (TARGET_LITTLE_ENDIAN
 	     ? \"mshflo.l	%N1, %N2, %0\"
 	     : \"mshfhi.l	%N1, %N2, %0\");"
-  [(set_attr "type" "arith_media")])
+  [(set_attr "type" "arith_media")
+   (set (attr "highpart")
+	(if_then_else (eq_attr "endian" "little")
+		      (const_string "ignore") (const_string "user")))])
 
 (define_expand "mshfhi_w"
   [(match_operand:V4HI 0 "arith_reg_dest" "")
@@ -10319,7 +10390,10 @@ mov.l\\t1f,r0\\n\\
   "* return (TARGET_LITTLE_ENDIAN
 	     ? \"mshfhi.w	%N1, %N2, %0\"
 	     : \"mshflo.w	%N1, %N2, %0\");"
-  [(set_attr "type" "arith_media")])
+  [(set_attr "type" "arith_media")
+   (set (attr "highpart")
+	(if_then_else (eq_attr "endian" "little")
+		      (const_string "user") (const_string "ignore")))])
 
 (define_insn "mshf0_w"
   [(set (match_operand:V4HI 0 "arith_reg_dest" "=r")
@@ -10331,7 +10405,10 @@ mov.l\\t1f,r0\\n\\
   "* return (TARGET_LITTLE_ENDIAN
 	     ? \"mshflo.w	%N1, %N2, %0\"
 	     : \"mshfhi.w	%N1, %N2, %0\");"
-  [(set_attr "type" "arith_media")])
+  [(set_attr "type" "arith_media")
+   (set (attr "highpart")
+	(if_then_else (eq_attr "endian" "little")
+		      (const_string "ignore") (const_string "user")))])
 
 (define_insn "mshflo_w_x"
   [(set (match_operand:V4HI 0 "arith_reg_dest" "=r")
@@ -10341,7 +10418,8 @@ mov.l\\t1f,r0\\n\\
 	 (parallel [(const_int 2) (const_int 0) (const_int 3) (const_int 1)])))]
   "TARGET_SHMEDIA"
   "mshflo.w	%N1, %N2, %0"
-  [(set_attr "type" "arith_media")])
+  [(set_attr "type" "arith_media")
+   (set_attr "highpart" "ignore")])
 
 /* These are useful to expand ANDs and as combiner patterns.  */
 (define_insn_and_split "mshfhi_l_di"
@@ -10405,7 +10483,8 @@ mov.l\\t1f,r0\\n\\
 
   "TARGET_SHMEDIA"
   "mshflo.l	%N1, %N2, %0"
-  [(set_attr "type" "arith_media")])
+  [(set_attr "type" "arith_media")
+   (set_attr "highpart" "ignore")])
 
 (define_insn "*mshflo_l_di_rev"
   [(set (match_operand:DI 0 "arith_reg_dest" "=r")
@@ -10416,7 +10495,8 @@ mov.l\\t1f,r0\\n\\
 
   "TARGET_SHMEDIA"
   "mshflo.l	%N2, %N1, %0"
-  [(set_attr "type" "arith_media")])
+  [(set_attr "type" "arith_media")
+   (set_attr "highpart" "ignore")])
 
 ;; Combiner pattern for trampoline initialization.
 (define_insn_and_split "*double_shori"
@@ -10438,7 +10518,8 @@ mov.l\\t1f,r0\\n\\
   emit_insn (gen_shori_media (operands[0], operands[0],
 			      gen_int_mode (v, HImode)));
   DONE;
-}")
+}"
+  [(set_attr "highpart" "ignore")])
 
 
 (define_insn "*mshflo_l_di_x"
@@ -10450,7 +10531,8 @@ mov.l\\t1f,r0\\n\\
 
   "TARGET_SHMEDIA"
   "mshflo.l	%N1, %N2, %0"
-  [(set_attr "type" "arith_media")])
+  [(set_attr "type" "arith_media")
+   (set_attr "highpart" "ignore")])
 
 (define_insn_and_split "concat_v2sf"
   [(set (match_operand:V2SF 0 "register_operand" "=r,f,f?")
@@ -10472,7 +10554,8 @@ mov.l\\t1f,r0\\n\\
   operands[3] = simplify_gen_subreg (SFmode, operands[0], V2SFmode, 0);
   operands[4] = simplify_gen_subreg (SFmode, operands[0], V2SFmode, 4);
 }"
-  [(set_attr "type" "arith_media")])
+  [(set_attr "type" "arith_media")
+   (set_attr "highpart" "ignore")])
 
 (define_insn "*mshflo_l_di_x_rev"
   [(set (match_operand:DI 0 "arith_reg_dest" "=r")
@@ -10482,7 +10565,8 @@ mov.l\\t1f,r0\\n\\
 
   "TARGET_SHMEDIA"
   "mshflo.l	%N2, %N1, %0"
-  [(set_attr "type" "arith_media")])
+  [(set_attr "type" "arith_media")
+   (set_attr "highpart" "ignore")])
 
 (define_insn "ashlv2si3"
   [(set (match_operand:V2SI 0 "arith_reg_dest" "=r")
@@ -10490,7 +10574,8 @@ mov.l\\t1f,r0\\n\\
 		     (match_operand:DI 2 "arith_reg_operand" "r")))]
   "TARGET_SHMEDIA"
   "mshlld.l	%1, %2, %0"
-  [(set_attr "type" "arith_media")])
+  [(set_attr "type" "arith_media")
+   (set_attr "highpart" "depend")])
 
 (define_insn "ashlv4hi3"
   [(set (match_operand:V4HI 0 "arith_reg_dest" "=r")
@@ -10498,7 +10583,8 @@ mov.l\\t1f,r0\\n\\
 		     (match_operand:DI 2 "arith_reg_operand" "r")))]
   "TARGET_SHMEDIA"
   "mshlld.w	%1, %2, %0"
-  [(set_attr "type" "arith_media")])
+  [(set_attr "type" "arith_media")
+   (set_attr "highpart" "depend")])
 
 (define_insn "lshrv2si3"
   [(set (match_operand:V2SI 0 "arith_reg_dest" "=r")
@@ -10506,7 +10592,8 @@ mov.l\\t1f,r0\\n\\
 		       (match_operand:DI 2 "arith_reg_operand" "r")))]
   "TARGET_SHMEDIA"
   "mshlrd.l	%1, %2, %0"
-  [(set_attr "type" "arith_media")])
+  [(set_attr "type" "arith_media")
+   (set_attr "highpart" "depend")])
 
 (define_insn "lshrv4hi3"
   [(set (match_operand:V4HI 0 "arith_reg_dest" "=r")
@@ -10514,7 +10601,8 @@ mov.l\\t1f,r0\\n\\
 		       (match_operand:DI 2 "arith_reg_operand" "r")))]
   "TARGET_SHMEDIA"
   "mshlrd.w	%1, %2, %0"
-  [(set_attr "type" "arith_media")])
+  [(set_attr "type" "arith_media")
+   (set_attr "highpart" "depend")])
 
 (define_insn "subv2si3"
   [(set (match_operand:V2SI 0 "arith_reg_dest" "=r")
@@ -10522,7 +10610,8 @@ mov.l\\t1f,r0\\n\\
 		    (match_operand:V2SI 2 "arith_reg_operand" "r")))]
   "TARGET_SHMEDIA"
   "msub.l	%N1, %2, %0"
-  [(set_attr "type" "arith_media")])
+  [(set_attr "type" "arith_media")
+   (set_attr "highpart" "depend")])
 
 (define_insn "subv4hi3"
   [(set (match_operand:V4HI 0 "arith_reg_dest" "=r")
@@ -10530,7 +10619,8 @@ mov.l\\t1f,r0\\n\\
 		    (match_operand:V4HI 2 "arith_reg_operand" "r")))]
   "TARGET_SHMEDIA"
   "msub.w	%N1, %2, %0"
-  [(set_attr "type" "arith_media")])
+  [(set_attr "type" "arith_media")
+   (set_attr "highpart" "depend")])
 
 (define_insn "sssubv2si3"
   [(set (match_operand:V2SI 0 "arith_reg_dest" "=r")
@@ -10538,7 +10628,8 @@ mov.l\\t1f,r0\\n\\
 		       (match_operand:V2SI 2 "arith_reg_operand" "r")))]
   "TARGET_SHMEDIA"
   "msubs.l	%N1, %2, %0"
-  [(set_attr "type" "mcmp_media")])
+  [(set_attr "type" "mcmp_media")
+   (set_attr "highpart" "depend")])
 
 (define_insn "ussubv8qi3"
   [(set (match_operand:V8QI 0 "arith_reg_dest" "=r")
@@ -10546,7 +10637,8 @@ mov.l\\t1f,r0\\n\\
 		       (match_operand:V8QI 2 "arith_reg_operand" "r")))]
   "TARGET_SHMEDIA"
   "msubs.ub	%1, %2, %0"
-  [(set_attr "type" "mcmp_media")])
+  [(set_attr "type" "mcmp_media")
+   (set_attr "highpart" "depend")])
 
 (define_insn "sssubv4hi3"
   [(set (match_operand:V4HI 0 "arith_reg_dest" "=r")
@@ -10554,7 +10646,8 @@ mov.l\\t1f,r0\\n\\
 		       (match_operand:V4HI 2 "arith_reg_operand" "r")))]
   "TARGET_SHMEDIA"
   "msubs.w	%N1, %2, %0"
-  [(set_attr "type" "mcmp_media")])
+  [(set_attr "type" "mcmp_media")
+   (set_attr "highpart" "depend")])
 
 ;; Floating Point Intrinsics
 
Index: doc/md.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/doc/md.texi,v
retrieving revision 1.86
diff -p -u -r1.86 md.texi
--- doc/md.texi	18 Jan 2004 11:57:13 -0000	1.86
+++ doc/md.texi	28 Jan 2004 21:19:00 -0000
@@ -4812,6 +4812,7 @@ to track the condition codes.
 * Insn Lengths::        Computing the length of insns.
 * Constant Attributes:: Defining attributes that are constant.
 * Delay Slots::         Defining delay slots required for a machine.
+* Highpart Attribute::  Enabling Highpart data flow analysis.
 * Processor pipeline description:: Specifying information for insn scheduling.
 @end menu
 
@@ -5435,6 +5436,39 @@ branch is true, we might represent this 
                (eq_attr "type" "!branch,call") (nil) (nil)])
 @end smallexample
 @c the above is *still* too long.  --mew 4feb93
+
+@node Highpart Attribute
+@subsection Highpart Attribute
+@cindex highpart
+
+Another special attribute is the @code{highpart} attribute.  If it is
+defined, data flow analysis before reload will keep track of the lifeness
+of the highpart of registers (a target port is free to define what the
+highpart is for this purpose, as long as it is consistent).
+For this to work, the @code{highpart} attribute must be defined to
+have specific values depending on how an instruction affects the lifeness
+of the highpart of register sources and destinations:
+
+@itemize @bullet
+@item
+@code{user} The instruction uses the highpart of one or more of its
+inputs.  This is a safe default value.
+
+@item
+@code{depend}: If the highparts of all outputs are dead, the highparts
+of all inputs are dead, too.
+
+@item
+@code{ignore}: The instruction does not use any highpart of its inputs.
+
+@item
+@code{extend}: This is an instruction with two operands, operands[0]
+being the output, and operands[1] being the input.  The lowpart
+(i.e. everything that is not the highpart) of the input is copied
+ unaltered to the output.  The highpart of the input is ignored.
+These instructions will be deleted or replaced with a copy if the
+highpart of the output is found to be dead.
+@end itemize
 
 @node Processor pipeline description
 @subsection Specifying processor pipeline description


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