Makefile.in (recog.o): Don't depend on resource.h.

* Makefile.in (recog.o): Don't depend on resource.h.
	* recog.c: Don't include resource.h.
	(recog_last_allowed_insn): Remove.
	(recog_next_insn): Remove.
	(struct peep2_insn_data): New.
	(peep2_insn_data, peep2_current): New.
	(peep2_next_insn): New.
	(peep2_regno_dead_p, peep2_reg_dead_p): New.
	(peep2_find_free_register): New.
	(peephole2_optimize): Track life information by insn as we go.
	* recog.h: Update declarations.
	* resource.c (find_free_register, reg_dead_p): Remove.
	* resource.h: Remove their declarations.
	* toplev.c: Include hard-reg-set.h before recog.h.

	* genconfig.c (max_insns_per_peep2): New.
	(gen_peephole2): New.
	(main): Call it.
	* genemit.c (output_peephole2_scratches): Generate calls to
	peep2_find_free_register; adjust surrounding code.
	(main): Have insn-emit.c include hard-reg-set.h before recog.h.
	* genrecog.c (change_state): Don't track last_insn.
	(write_action): Write into *_pmatch_len before accepting.
	(write_tree): Adjust peephole2_insns and subroutines to match.

	* config/i386/i386.md (all peepholes): Use peep2_regno_dead_p.

From-SVN: r34208
This commit is contained in:
Richard Henderson 2000-05-27 13:23:15 -07:00 committed by Richard Henderson
parent 30196c1ff4
commit 2328013936
11 changed files with 407 additions and 214 deletions

View file

@ -1,3 +1,32 @@
2000-05-27 Richard Henderson <rth@cygnus.com>
* Makefile.in (recog.o): Don't depend on resource.h.
* recog.c: Don't include resource.h.
(recog_last_allowed_insn): Remove.
(recog_next_insn): Remove.
(struct peep2_insn_data): New.
(peep2_insn_data, peep2_current): New.
(peep2_next_insn): New.
(peep2_regno_dead_p, peep2_reg_dead_p): New.
(peep2_find_free_register): New.
(peephole2_optimize): Track life information by insn as we go.
* recog.h: Update declarations.
* resource.c (find_free_register, reg_dead_p): Remove.
* resource.h: Remove their declarations.
* toplev.c: Include hard-reg-set.h before recog.h.
* genconfig.c (max_insns_per_peep2): New.
(gen_peephole2): New.
(main): Call it.
* genemit.c (output_peephole2_scratches): Generate calls to
peep2_find_free_register; adjust surrounding code.
(main): Have insn-emit.c include hard-reg-set.h before recog.h.
* genrecog.c (change_state): Don't track last_insn.
(write_action): Write into *_pmatch_len before accepting.
(write_tree): Adjust peephole2_insns and subroutines to match.
* config/i386/i386.md (all peepholes): Use peep2_regno_dead_p.
2000-05-27 Richard Henderson <rth@cygnus.com>
* function.c (thread_prologue_epilogue_insns): Don't move the

View file

@ -1382,7 +1382,7 @@ final.o : final.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) flags.h intl.h \
dbxout.h $(BASIC_BLOCK_H)
recog.o : recog.c $(CONFIG_H) system.h $(RTL_H) function.h $(BASIC_BLOCK_H) \
$(REGS_H) $(RECOG_H) hard-reg-set.h flags.h insn-config.h insn-attr.h \
insn-flags.h insn-codes.h real.h toplev.h output.h resource.h
insn-flags.h insn-codes.h real.h toplev.h output.h
reg-stack.o : reg-stack.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) $(RECOG_H) \
$(REGS_H) hard-reg-set.h flags.h insn-config.h insn-flags.h toplev.h \
varray.h function.h

View file

@ -9591,10 +9591,11 @@
[(match_scratch:SI 1 "r")
(set (match_operand:SI 0 "memory_operand" "")
(const_int 0))]
"! optimize_size && get_attr_length (insn) >= ix86_cost->large_insn
&& reg_dead_p (insn, gen_rtx_REG (CCmode, FLAGS_REG))
"! optimize_size
&& ! TARGET_USE_MOV0
&& TARGET_SPLIT_LONG_MOVES"
&& TARGET_SPLIT_LONG_MOVES
&& get_attr_length (insn) >= ix86_cost->large_insn
&& peep2_regno_dead_p (0, FLAGS_REG)"
[(parallel [(set (match_dup 1) (const_int 0))
(clobber (reg:CC 17))])
(set (match_dup 0) (match_dup 1))]
@ -9604,10 +9605,11 @@
[(match_scratch:HI 1 "r")
(set (match_operand:HI 0 "memory_operand" "")
(const_int 0))]
"! optimize_size && get_attr_length (insn) >= ix86_cost->large_insn
&& reg_dead_p (insn, gen_rtx_REG (CCmode, FLAGS_REG))
"! optimize_size
&& ! TARGET_USE_MOV0
&& TARGET_SPLIT_LONG_MOVES"
&& TARGET_SPLIT_LONG_MOVES
&& get_attr_length (insn) >= ix86_cost->large_insn
&& peep2_regno_dead_p (0, FLAGS_REG)"
[(parallel [(set (match_dup 2) (const_int 0))
(clobber (reg:CC 17))])
(set (match_dup 0) (match_dup 1))]
@ -9617,10 +9619,11 @@
[(match_scratch:QI 1 "q")
(set (match_operand:QI 0 "memory_operand" "")
(const_int 0))]
"! optimize_size && get_attr_length (insn) >= ix86_cost->large_insn
&& reg_dead_p (insn, gen_rtx_REG (CCmode, FLAGS_REG))
"! optimize_size
&& ! TARGET_USE_MOV0
&& TARGET_SPLIT_LONG_MOVES"
&& TARGET_SPLIT_LONG_MOVES
&& get_attr_length (insn) >= ix86_cost->large_insn
&& peep2_regno_dead_p (0, FLAGS_REG)"
[(parallel [(set (match_dup 2) (const_int 0))
(clobber (reg:CC 17))])
(set (match_dup 0) (match_dup 1))]
@ -9630,7 +9633,8 @@
[(match_scratch:SI 2 "r")
(set (match_operand:SI 0 "memory_operand" "")
(match_operand:SI 1 "immediate_operand" ""))]
"! optimize_size && get_attr_length (insn) >= ix86_cost->large_insn
"! optimize_size
&& get_attr_length (insn) >= ix86_cost->large_insn
&& TARGET_SPLIT_LONG_MOVES"
[(set (match_dup 2) (match_dup 1))
(set (match_dup 0) (match_dup 2))]
@ -9675,14 +9679,14 @@
;; represented using a modRM byte. The XOR replacement is long decoded,
;; so this split helps here as well.
;;
;; Note: Can't do this as a regular split because reg_dead_p assumes
;; resource info is live.
;; Note: Can't do this as a regular split because we can't get proper
;; lifetime information then.
(define_peephole2
[(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
(not:SI (match_operand:SI 1 "nonimmediate_operand" "0")))]
"!optimize_size
&& reg_dead_p (insn, gen_rtx_REG (CCmode, FLAGS_REG))
&& peep2_regno_dead_p (0, FLAGS_REG)
&& ((TARGET_PENTIUM
&& (GET_CODE (operands[0]) != MEM
|| !memory_displacement_operand (operands[0], SImode)))
@ -9696,7 +9700,7 @@
[(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
(not:HI (match_operand:HI 1 "nonimmediate_operand" "0")))]
"!optimize_size
&& reg_dead_p (insn, gen_rtx_REG (CCmode, FLAGS_REG))
&& peep2_regno_dead_p (0, FLAGS_REG)
&& ((TARGET_PENTIUM
&& (GET_CODE (operands[0]) != MEM
|| !memory_displacement_operand (operands[0], HImode)))
@ -9710,7 +9714,7 @@
[(set (match_operand:QI 0 "nonimmediate_operand" "=rm")
(not:QI (match_operand:QI 1 "nonimmediate_operand" "0")))]
"!optimize_size
&& reg_dead_p (insn, gen_rtx_REG (CCmode, FLAGS_REG))
&& peep2_regno_dead_p (0, FLAGS_REG)
&& ((TARGET_PENTIUM
&& (GET_CODE (operands[0]) != MEM
|| !memory_displacement_operand (operands[0], QImode)))
@ -9873,7 +9877,7 @@
|| GET_MODE (operands[0]) == HImode
|| GET_MODE (operands[0]) == SImode)
&& (! TARGET_USE_MOV0 || optimize_size)
&& reg_dead_p (insn, gen_rtx_REG (CCmode, FLAGS_REG))"
&& peep2_regno_dead_p (0, FLAGS_REG)"
[(parallel [(set (match_dup 0) (const_int 0))
(clobber (reg:CC 17))])]
"operands[0] = gen_rtx_REG (SImode, true_regnum (operands[0]));")
@ -9885,7 +9889,7 @@
"(GET_MODE (operands[0]) == HImode
|| GET_MODE (operands[0]) == SImode)
&& (optimize_size || TARGET_PENTIUM)
&& reg_dead_p (insn, gen_rtx_REG (CCmode, FLAGS_REG))"
&& peep2_regno_dead_p (0, FLAGS_REG)"
[(parallel [(set (match_dup 0) (const_int -1))
(clobber (reg:CC 17))])]
"operands[0] = gen_rtx_REG (SImode, true_regnum (operands[0]));")
@ -9896,7 +9900,7 @@
[(set (match_operand:SI 0 "register_operand" "")
(plus:SI (match_dup 0)
(match_operand:SI 1 "nonmemory_operand" "")))]
"reg_dead_p (insn, gen_rtx_REG (CCmode, FLAGS_REG))"
"peep2_regno_dead_p (0, FLAGS_REG)"
[(parallel [(set (match_dup 0) (plus:SI (match_dup 0) (match_dup 1)))
(clobber (reg:CC 17))])]
"")
@ -9905,7 +9909,8 @@
[(set (match_operand:SI 0 "register_operand" "")
(mult:SI (match_dup 0)
(match_operand:SI 1 "immediate_operand" "")))]
"reg_dead_p (insn, gen_rtx_REG (CCmode, FLAGS_REG))"
"exact_log2 (INTVAL (operands[1])) >= 0
&& peep2_regno_dead_p (0, FLAGS_REG)"
[(parallel [(set (match_dup 0) (ashift:SI (match_dup 0) (match_dup 2)))
(clobber (reg:CC 17))])]
"operands[2] = GEN_INT (exact_log2 (INTVAL (operands[1])));")

View file

@ -42,6 +42,9 @@ static int have_peephole2_flag;
/* Maximum number of insns seen in a split. */
static int max_insns_per_split = 1;
/* Maximum number of input insns for peephole2. */
static int max_insns_per_peep2;
static int clobbers_seen_this_insn;
static int dup_operands_seen_this_insn;
@ -239,6 +242,26 @@ gen_peephole (peep)
walk_insn_part (XVECEXP (peep, 0, i), 1, 0);
}
static void
gen_peephole2 (peep)
rtx peep;
{
int i, n;
/* Look through the patterns that are matched
to compute the maximum operand number. */
for (i = XVECLEN (peep, 0) - 1; i >= 0; --i)
walk_insn_part (XVECEXP (peep, 0, i), 1, 0);
/* Look at the number of insns this insn can be matched from. */
for (i = XVECLEN (peep, 0) - 1, n = 0; i >= 0; --i)
if (GET_CODE (XVECEXP (peep, 0, i)) != MATCH_DUP
&& GET_CODE (XVECEXP (peep, 0, i)) != MATCH_SCRATCH)
n++;
if (n > max_insns_per_peep2)
max_insns_per_peep2 = n;
}
extern int main PARAMS ((int, char **));
int
@ -289,7 +312,7 @@ from the machine description file `md'. */\n\n");
case DEFINE_PEEPHOLE2:
have_peephole2_flag = 1;
gen_split (desc);
gen_peephole2 (desc);
break;
case DEFINE_PEEPHOLE:
@ -302,9 +325,8 @@ from the machine description file `md'. */\n\n");
}
}
printf ("\n#define MAX_RECOG_OPERANDS %d\n", max_recog_operands + 1);
printf ("\n#define MAX_DUP_OPERANDS %d\n", max_dup_operands);
printf ("#define MAX_RECOG_OPERANDS %d\n", max_recog_operands + 1);
printf ("#define MAX_DUP_OPERANDS %d\n", max_dup_operands);
/* This is conditionally defined, in case the user writes code which emits
more splits than we can readily see (and knows s/he does it). */
@ -328,7 +350,10 @@ from the machine description file `md'. */\n\n");
printf ("#define HAVE_peephole 1\n");
if (have_peephole2_flag)
{
printf ("#define HAVE_peephole2 1\n");
printf ("#define MAX_INSNS_PER_PEEP2 %d\n", max_insns_per_peep2);
}
fflush (stdout);
return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);

View file

@ -699,10 +699,7 @@ output_peephole2_scratches (split)
int i;
int insn_nr = 0;
printf (" rtx first_insn ATTRIBUTE_UNUSED;\n");
printf (" rtx last_insn ATTRIBUTE_UNUSED;\n");
printf (" HARD_REG_SET _regs_allocated;\n");
printf (" CLEAR_HARD_REG_SET (_regs_allocated);\n");
for (i = 0; i < XVECLEN (split, 0); i++)
@ -721,15 +718,11 @@ output_peephole2_scratches (split)
}
else if (GET_CODE (XVECEXP (split, 0, j)) != MATCH_SCRATCH)
cur_insn_nr++;
printf (" first_insn = recog_next_insn (curr_insn, %d);\n", insn_nr);
if (last_insn_nr > insn_nr)
printf (" last_insn = recog_next_insn (curr_insn, %d);\n",
last_insn_nr - 1);
else
printf (" last_insn = 0;\n");
printf (" if ((operands[%d] = find_free_register (first_insn, last_insn, \"%s\", %smode, &_regs_allocated)) == NULL_RTX)\n\
printf (" if ((operands[%d] = peep2_find_free_register (%d, %d, \"%s\", %smode, &_regs_allocated)) == NULL_RTX)\n\
return NULL;\n",
XINT (elt, 0),
insn_nr, last_insn_nr,
XSTR (elt, 1),
GET_MODE_NAME (GET_MODE (elt)));
@ -777,8 +770,8 @@ from the machine description file `md'. */\n\n");
printf ("#include \"insn-config.h\"\n");
printf ("#include \"insn-flags.h\"\n");
printf ("#include \"insn-codes.h\"\n");
printf ("#include \"recog.h\"\n");
printf ("#include \"hard-reg-set.h\"\n");
printf ("#include \"recog.h\"\n");
printf ("#include \"resource.h\"\n");
printf ("#include \"reload.h\"\n\n");
printf ("#define FAIL return (end_sequence (), _val)\n");

View file

@ -272,8 +272,8 @@ static struct decision *write_switch
static void write_cond
PARAMS ((struct decision_test *, int, enum routine_type));
static void write_action
PARAMS ((struct decision_test *, int, int, struct decision *,
enum routine_type));
PARAMS ((struct decision *, struct decision_test *, int, int,
struct decision *, enum routine_type));
static int is_unconditional
PARAMS ((struct decision_test *, enum routine_type));
static int write_node
@ -1578,10 +1578,6 @@ change_state (oldpos, newpos, afterward, indent)
if (newpos[new_has_insn] >= 'A' && newpos[new_has_insn] <= 'Z')
break;
/* Make sure to reset the last_insn pointer when popping back up. */
if (old_has_insn >= 0 && new_has_insn < 0)
printf ("%slast_insn = insn;\n", indent);
/* Go down to desired level. */
while (depth < ndepth)
{
@ -1591,21 +1587,20 @@ change_state (oldpos, newpos, afterward, indent)
/* We can only fail if we're moving down the tree. */
if (old_has_insn >= 0 && oldpos[old_has_insn] >= newpos[depth])
{
printf ("%slast_insn = recog_next_insn (insn, %d);\n",
printf ("%stem = peep2_next_insn (%d);\n",
indent, newpos[depth] - 'A');
}
else
{
printf ("%stem = recog_next_insn (insn, %d);\n",
printf ("%stem = peep2_next_insn (%d);\n",
indent, newpos[depth] - 'A');
printf ("%sif (tem == NULL_RTX)\n", indent);
if (afterward)
printf ("%s goto L%d;\n", indent, afterward->number);
else
printf ("%s goto ret0;\n", indent);
printf ("%slast_insn = tem;\n", indent);
}
printf ("%sx%d = PATTERN (last_insn);\n", indent, depth + 1);
printf ("%sx%d = PATTERN (tem);\n", indent, depth + 1);
}
else if (newpos[depth] >= 'a' && newpos[depth] <= 'z')
printf ("%sx%d = XVECEXP (x%d, 0, %d);\n",
@ -1888,7 +1883,8 @@ write_cond (p, depth, subroutine_type)
perform a state change. For the `accept' tests we must do more work. */
static void
write_action (test, depth, uncond, success, subroutine_type)
write_action (p, test, depth, uncond, success, subroutine_type)
struct decision *p;
struct decision_test *test;
int depth, uncond;
struct decision *success;
@ -1942,9 +1938,20 @@ write_action (test, depth, uncond, success, subroutine_type)
break;
case PEEPHOLE2:
{
int match_len = 0, i;
for (i = strlen (p->position) - 1; i >= 0; --i)
if (p->position[i] >= 'A' && p->position[i] <= 'Z')
{
match_len = p->position[i] - 'A';
break;
}
printf ("%s*_pmatch_len = %d;\n", indent, match_len);
printf ("%stem = gen_peephole2_%d (insn, operands);\n",
indent, test->u.insn.code_number);
printf ("%sif (tem != 0)\n%s goto ret1;\n", indent, indent);
printf ("%sif (tem != 0)\n%s return tem;\n", indent, indent);
}
break;
default:
@ -2027,7 +2034,7 @@ write_node (p, depth, subroutine_type)
printf (")\n");
}
write_action (last_test, depth, uncond, p->success.first, subroutine_type);
write_action (p, last_test, depth, uncond, p->success.first, subroutine_type);
return uncond > 0;
}
@ -2090,7 +2097,7 @@ write_tree (head, prevpos, type, initial)
};
static const char * const call_suffix[] = {
", pnum_clobbers", "", ", _plast_insn"
", pnum_clobbers", "", ", _pmatch_len"
};
/* This node has been broken out into a separate subroutine.
@ -2167,12 +2174,13 @@ split%s (x0, insn)\n\
rtx insn ATTRIBUTE_UNUSED;\n", s_or_e, extension);
break;
case PEEPHOLE2:
printf ("%srtx peephole2%s PARAMS ((rtx, rtx, rtx *));\n", s_or_e, extension);
printf ("%srtx peephole2%s PARAMS ((rtx, rtx, int *));\n",
s_or_e, extension);
printf ("%srtx\n\
peephole2%s (x0, insn, _plast_insn)\n\
peephole2%s (x0, insn, _pmatch_len)\n\
register rtx x0;\n\
rtx insn ATTRIBUTE_UNUSED;\n\
rtx *_plast_insn ATTRIBUTE_UNUSED;\n", s_or_e, extension);
int *_pmatch_len ATTRIBUTE_UNUSED;\n", s_or_e, extension);
break;
}
@ -2180,8 +2188,6 @@ peephole2%s (x0, insn, _plast_insn)\n\
for (i = 1; i <= max_depth; i++)
printf (" register rtx x%d ATTRIBUTE_UNUSED;\n", i);
if (type == PEEPHOLE2)
printf (" register rtx last_insn = insn;\n");
printf (" %s tem ATTRIBUTE_UNUSED;\n", IS_SPLIT (type) ? "rtx" : "int");
if (head->first)
@ -2189,8 +2195,6 @@ peephole2%s (x0, insn, _plast_insn)\n\
else
printf (" goto ret0;\n");
if (type == PEEPHOLE2)
printf (" ret1:\n *_plast_insn = last_insn;\n return tem;\n");
printf (" ret0:\n return %d;\n}\n\n", IS_SPLIT (type) ? 0 : -1);
}

View file

@ -37,7 +37,6 @@ Boston, MA 02111-1307, USA. */
#include "toplev.h"
#include "basic-block.h"
#include "output.h"
#include "resource.h"
#ifndef STACK_PUSH_CODE
#ifdef STACK_GROWS_DOWNWARD
@ -2682,100 +2681,340 @@ split_all_insns (upd_life)
}
#ifdef HAVE_peephole2
/* This is the last insn we'll allow recog_next_insn to consider. */
static rtx recog_last_allowed_insn;
/* Return the Nth non-note insn after INSN, or return NULL_RTX if it does
not exist. Used by the recognizer to find the next insn to match in a
multi-insn pattern. */
rtx
recog_next_insn (insn, n)
struct peep2_insn_data
{
rtx insn;
regset live_before;
};
static struct peep2_insn_data peep2_insn_data[MAX_INSNS_PER_PEEP2 + 1];
static int peep2_current;
/* A non-insn marker indicating the last insn of the block.
The live_before regset for this element is correct, indicating
global_live_at_end for the block. */
#define PEEP2_EOB pc_rtx
/* Return the Nth non-note insn after `current', or return NULL_RTX if it
does not exist. Used by the recognizer to find the next insn to match
in a multi-insn pattern. */
rtx
peep2_next_insn (n)
int n;
{
if (insn != NULL_RTX)
{
while (n > 0)
{
if (insn == recog_last_allowed_insn)
if (n >= MAX_INSNS_PER_PEEP2 + 1)
abort ();
n += peep2_current;
if (n >= MAX_INSNS_PER_PEEP2 + 1)
n -= MAX_INSNS_PER_PEEP2 + 1;
if (peep2_insn_data[n].insn == PEEP2_EOB)
return NULL_RTX;
return peep2_insn_data[n].insn;
}
insn = NEXT_INSN (insn);
if (insn == NULL_RTX)
/* Return true if REGNO is dead before the Nth non-note insn
after `current'. */
int
peep2_regno_dead_p (ofs, regno)
int ofs;
int regno;
{
if (ofs >= MAX_INSNS_PER_PEEP2 + 1)
abort ();
ofs += peep2_current;
if (ofs >= MAX_INSNS_PER_PEEP2 + 1)
ofs -= MAX_INSNS_PER_PEEP2 + 1;
if (peep2_insn_data[ofs].insn == NULL_RTX)
abort ();
return ! REGNO_REG_SET_P (peep2_insn_data[ofs].live_before, regno);
}
/* Similarly for a REG. */
int
peep2_reg_dead_p (ofs, reg)
int ofs;
rtx reg;
{
int regno, n;
if (ofs >= MAX_INSNS_PER_PEEP2 + 1)
abort ();
ofs += peep2_current;
if (ofs >= MAX_INSNS_PER_PEEP2 + 1)
ofs -= MAX_INSNS_PER_PEEP2 + 1;
if (peep2_insn_data[ofs].insn == NULL_RTX)
abort ();
regno = REGNO (reg);
n = HARD_REGNO_NREGS (regno, GET_MODE (reg));
while (--n >= 0)
if (REGNO_REG_SET_P (peep2_insn_data[ofs].live_before, regno + n))
return 0;
return 1;
}
/* Try to find a hard register of mode MODE, matching the register class in
CLASS_STR, which is available at the beginning of insn CURRENT_INSN and
remains available until the end of LAST_INSN. LAST_INSN may be NULL_RTX,
in which case the only condition is that the register must be available
before CURRENT_INSN.
Registers that already have bits set in REG_SET will not be considered.
If an appropriate register is available, it will be returned and the
corresponding bit(s) in REG_SET will be set; otherwise, NULL_RTX is
returned. */
rtx
peep2_find_free_register (from, to, class_str, mode, reg_set)
int from, to;
const char *class_str;
enum machine_mode mode;
HARD_REG_SET *reg_set;
{
static int search_ofs;
enum reg_class class;
HARD_REG_SET live;
int i;
if (from >= MAX_INSNS_PER_PEEP2 + 1 || to >= MAX_INSNS_PER_PEEP2 + 1)
abort ();
from += peep2_current;
if (from >= MAX_INSNS_PER_PEEP2 + 1)
from -= MAX_INSNS_PER_PEEP2 + 1;
to += peep2_current;
if (to >= MAX_INSNS_PER_PEEP2 + 1)
to -= MAX_INSNS_PER_PEEP2 + 1;
if (peep2_insn_data[from].insn == NULL_RTX)
abort ();
REG_SET_TO_HARD_REG_SET (live, peep2_insn_data[from].live_before);
while (from != to)
{
HARD_REG_SET this_live;
if (++from >= MAX_INSNS_PER_PEEP2 + 1)
from = 0;
if (peep2_insn_data[from].insn == NULL_RTX)
abort ();
REG_SET_TO_HARD_REG_SET (this_live, peep2_insn_data[from].live_before);
IOR_HARD_REG_SET (live, this_live);
}
class = (class_str[0] == 'r' ? GENERAL_REGS
: REG_CLASS_FROM_LETTER (class_str[0]));
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
{
int raw_regno, regno, success, j;
/* Distribute the free registers as much as possible. */
raw_regno = search_ofs + i;
if (raw_regno >= FIRST_PSEUDO_REGISTER)
raw_regno -= FIRST_PSEUDO_REGISTER;
#ifdef REG_ALLOC_ORDER
regno = reg_alloc_order[raw_regno];
#else
regno = raw_regno;
#endif
/* Don't allocate fixed registers. */
if (fixed_regs[regno])
continue;
/* Make sure the register is of the right class. */
if (! TEST_HARD_REG_BIT (reg_class_contents[class], regno))
continue;
/* And can support the mode we need. */
if (! HARD_REGNO_MODE_OK (regno, mode))
continue;
/* And that we don't create an extra save/restore. */
if (! call_used_regs[regno] && ! regs_ever_live[regno])
continue;
/* And we don't clobber traceback for noreturn functions. */
if ((regno == FRAME_POINTER_REGNUM || regno == HARD_FRAME_POINTER_REGNUM)
&& (! reload_completed || frame_pointer_needed))
continue;
success = 1;
for (j = HARD_REGNO_NREGS (regno, mode) - 1; j >= 0; j--)
{
if (TEST_HARD_REG_BIT (*reg_set, regno + j)
|| TEST_HARD_REG_BIT (live, regno + j))
{
success = 0;
break;
}
}
if (success)
{
for (j = HARD_REGNO_NREGS (regno, mode) - 1; j >= 0; j--)
SET_HARD_REG_BIT (*reg_set, regno + j);
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
n -= 1;
/* Start the next search with the next register. */
if (++raw_regno >= FIRST_PSEUDO_REGISTER)
raw_regno = 0;
search_ofs = raw_regno;
return gen_rtx_REG (mode, regno);
}
}
return insn;
search_ofs = 0;
return NULL_RTX;
}
/* Perform the peephole2 optimization pass. */
void
peephole2_optimize (dump_file)
FILE *dump_file ATTRIBUTE_UNUSED;
{
regset_head rs_heads[MAX_INSNS_PER_PEEP2 + 2];
rtx insn, prev;
int i, changed;
regset live;
int i, b;
#ifdef HAVE_conditional_execution
sbitmap blocks;
int changed;
#endif
/* ??? TODO: Arrange with resource.c to start at bb->global_live_at_end
and backtrack insn by insn as we proceed through the block. In this
way we'll not need to keep searching forward from the beginning of
basic blocks to find register life info. */
init_resource_info (NULL);
/* Initialize the regsets we're going to use. */
for (i = 0; i < MAX_INSNS_PER_PEEP2 + 1; ++i)
peep2_insn_data[i].live_before = INITIALIZE_REG_SET (rs_heads[i]);
live = INITIALIZE_REG_SET (rs_heads[i]);
#ifdef HAVE_conditional_execution
blocks = sbitmap_alloc (n_basic_blocks);
sbitmap_zero (blocks);
changed = 0;
#else
count_or_remove_death_notes (NULL, 1);
#endif
for (i = n_basic_blocks - 1; i >= 0; --i)
for (b = n_basic_blocks - 1; b >= 0; --b)
{
basic_block bb = BASIC_BLOCK (i);
basic_block bb = BASIC_BLOCK (b);
struct propagate_block_info *pbi;
/* Since we don't update life info until the very end, we can't
allow matching instructions that we've replaced before. Walk
backward through the basic block so that we don't have to
care about subsequent life info; recog_last_allowed_insn to
restrict how far forward we will allow the match to proceed. */
/* Indicate that all slots except the last holds invalid data. */
for (i = 0; i < MAX_INSNS_PER_PEEP2; ++i)
peep2_insn_data[i].insn = NULL_RTX;
/* Indicate that the last slot contains live_after data. */
peep2_insn_data[MAX_INSNS_PER_PEEP2].insn = PEEP2_EOB;
peep2_current = MAX_INSNS_PER_PEEP2;
/* Start up propagation. */
COPY_REG_SET (live, bb->global_live_at_end);
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, 0);
#else
pbi = init_propagate_block_info (bb, live, NULL, PROP_DEATH_NOTES);
#endif
recog_last_allowed_insn = NEXT_INSN (bb->end);
for (insn = bb->end; ; insn = prev)
{
prev = PREV_INSN (insn);
if (INSN_P (insn))
{
rtx try, last_insn;
rtx try;
int match_len;
try = peephole2_insns (PATTERN (insn), insn, &last_insn);
/* Record this insn. */
if (--peep2_current < 0)
peep2_current = MAX_INSNS_PER_PEEP2;
peep2_insn_data[peep2_current].insn = insn;
propagate_one_insn (pbi, insn);
COPY_REG_SET (peep2_insn_data[peep2_current].live_before, live);
/* Match the peephole. */
try = peephole2_insns (PATTERN (insn), insn, &match_len);
if (try != NULL)
{
flow_delete_insn_chain (insn, last_insn);
i = match_len + peep2_current;
if (i >= MAX_INSNS_PER_PEEP2 + 1)
i -= MAX_INSNS_PER_PEEP2 + 1;
/* Replace the old sequence with the new. */
flow_delete_insn_chain (insn, peep2_insn_data[i].insn);
try = emit_insn_after (try, prev);
if (last_insn == bb->end)
/* Adjust the basic block boundaries. */
if (peep2_insn_data[i].insn == bb->end)
bb->end = try;
if (insn == bb->head)
bb->head = NEXT_INSN (prev);
recog_last_allowed_insn = NEXT_INSN (prev);
SET_BIT (blocks, i);
#ifdef HAVE_conditional_execution
/* With conditional execution, we cannot back up the
live information so easily, since the conditional
death data structures are not so self-contained.
So record that we've made a modification to this
block and update life information at the end. */
SET_BIT (blocks, b);
changed = 1;
for (i = 0; i < MAX_INSNS_PER_PEEP2 + 1; ++i)
peep2_insn_data[i].insn = NULL_RTX;
peep2_insn_data[peep2_current].insn = PEEP2_EOB;
#else
/* Back up lifetime information past the end of the
newly created sequence. */
if (++i >= MAX_INSNS_PER_PEEP2 + 1)
i = 0;
COPY_REG_SET (live, peep2_insn_data[i].live_before);
/* Update life information for the new sequence. */
do
{
if (INSN_P (try))
{
if (--i < 0)
i = MAX_INSNS_PER_PEEP2;
peep2_insn_data[i].insn = try;
propagate_one_insn (pbi, try);
COPY_REG_SET (peep2_insn_data[i].live_before, live);
}
try = PREV_INSN (try);
}
while (try != prev);
/* ??? Should verify that LIVE now matches what we
had before the new sequence. */
peep2_current = i;
#endif
}
}
if (insn == bb->head)
break;
}
free_propagate_block_info (pbi);
}
free_resource_info ();
for (i = 0; i < MAX_INSNS_PER_PEEP2 + 1; ++i)
FREE_REG_SET (peep2_insn_data[i].live_before);
FREE_REG_SET (live);
compute_bb_for_insn (get_max_uid ());
#ifdef HAVE_conditional_execution
count_or_remove_death_notes (blocks, 1);
update_life_info (blocks, UPDATE_LIFE_LOCAL, PROP_DEATH_NOTES);
}
sbitmap_free (blocks);
#endif
}
#endif /* HAVE_peephole2 */

View file

@ -116,9 +116,16 @@ extern void add_clobbers PARAMS ((rtx, int));
extern void insn_extract PARAMS ((rtx));
extern void extract_insn PARAMS ((rtx));
extern void preprocess_constraints PARAMS ((void));
extern rtx recog_next_insn PARAMS ((rtx, int));
extern rtx peep2_next_insn PARAMS ((int));
extern int peep2_regno_dead_p PARAMS ((int, int));
extern int peep2_reg_dead_p PARAMS ((int, rtx));
#ifdef CLEAR_HARD_REG_SET
extern rtx peep2_find_free_register PARAMS ((int, int, const char *,
enum machine_mode,
HARD_REG_SET *));
#endif
extern void peephole2_optimize PARAMS ((FILE *));
extern rtx peephole2_insns PARAMS ((rtx, rtx, rtx *));
extern rtx peephole2_insns PARAMS ((rtx, rtx, int *));
/* Nonzero means volatile operands are recognized. */
extern int volatile_ok;

View file

@ -1268,109 +1268,3 @@ mark_end_of_function_resources (trial, include_delayed_effects)
mark_referenced_resources (trial, &end_of_function_needs,
include_delayed_effects);
}
/* Try to find a hard register of mode MODE, matching the register class in
CLASS_STR, which is available at the beginning of insn CURRENT_INSN and
remains available until the end of LAST_INSN. LAST_INSN may be NULL_RTX,
in which case the only condition is that the register must be available
before CURRENT_INSN.
Registers that already have bits set in REG_SET will not be considered.
If an appropriate register is available, it will be returned and the
corresponding bit(s) in REG_SET will be set; otherwise, NULL_RTX is
returned. */
rtx
find_free_register (current_insn, last_insn, class_str, mode, reg_set)
rtx current_insn, last_insn;
const char *class_str;
int mode;
HARD_REG_SET *reg_set;
{
int i, j;
struct resources used;
unsigned char clet = class_str[0];
enum reg_class class
= (clet == 'r' ? GENERAL_REGS : REG_CLASS_FROM_LETTER (clet));
mark_target_live_regs (get_insns (), current_insn, &used);
if (last_insn)
while (current_insn != last_insn)
{
/* Exclude anything set in this insn. */
mark_set_resources (PATTERN (current_insn), &used, 0,
MARK_SRC_DEST_CALL);
current_insn = next_nonnote_insn (current_insn);
}
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
{
int regno;
int success;
#ifdef REG_ALLOC_ORDER
regno = reg_alloc_order [i];
#else
regno = i;
#endif
/* Don't allocate fixed registers. */
if (fixed_regs[regno])
continue;
/* Make sure the register is of the right class. */
if (! TEST_HARD_REG_BIT (reg_class_contents[class], regno))
continue;
/* And can support the mode we need. */
if (! HARD_REGNO_MODE_OK (regno, mode))
continue;
/* And that we don't create an extra save/restore. */
if (! call_used_regs[regno] && ! regs_ever_live[regno])
continue;
/* And we don't clobber traceback for noreturn functions. */
if ((regno == FRAME_POINTER_REGNUM || regno == HARD_FRAME_POINTER_REGNUM)
&& (! reload_completed || frame_pointer_needed))
continue;
success = 1;
for (j = HARD_REGNO_NREGS (regno, mode) - 1; j >= 0; j--)
{
if (TEST_HARD_REG_BIT (*reg_set, regno + j)
|| TEST_HARD_REG_BIT (used.regs, regno + j))
{
success = 0;
break;
}
}
if (success)
{
for (j = HARD_REGNO_NREGS (regno, mode) - 1; j >= 0; j--)
{
SET_HARD_REG_BIT (*reg_set, regno + j);
}
return gen_rtx_REG (mode, regno);
}
}
return NULL_RTX;
}
/* Return true if REG is dead at CURRENT_INSN. */
int
reg_dead_p (current_insn, reg)
rtx current_insn, reg;
{
struct resources used;
int regno, j;
mark_target_live_regs (get_insns (), current_insn, &used);
regno = REGNO (reg);
for (j = HARD_REGNO_NREGS (regno, GET_MODE (reg)) - 1; j >= 0; j--)
{
if (TEST_HARD_REG_BIT (used.regs, regno + j))
return 0;
}
return 1;
}

View file

@ -50,6 +50,3 @@ extern void incr_ticks_for_insn PARAMS ((rtx));
extern void mark_end_of_function_resources PARAMS ((rtx, int));
extern void init_resource_info PARAMS ((rtx));
extern void free_resource_info PARAMS ((void));
extern rtx find_free_register PARAMS ((rtx, rtx, const char *, int,
HARD_REG_SET *));
extern int reg_dead_p PARAMS ((rtx, rtx));

View file

@ -47,6 +47,7 @@ Boston, MA 02111-1307, USA. */
#include "insn-attr.h"
#include "insn-codes.h"
#include "insn-config.h"
#include "hard-reg-set.h"
#include "recog.h"
#include "defaults.h"
#include "output.h"
@ -54,7 +55,6 @@ Boston, MA 02111-1307, USA. */
#include "function.h"
#include "toplev.h"
#include "expr.h"
#include "hard-reg-set.h"
#include "basic-block.h"
#include "intl.h"
#include "ggc.h"