This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
RFA: highpart life analysis
- From: Joern Rennecke <joern dot rennecke at superh dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Thu, 29 Jan 2004 17:45:11 +0000 (GMT)
- Subject: 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