From: Richard Henderson Date: Sat, 27 May 2000 20:23:15 +0000 (-0700) Subject: Makefile.in (recog.o): Don't depend on resource.h. X-Git-Tag: prereleases/libstdc++-2.92~6149 X-Git-Url: https://gcc.gnu.org/git/?a=commitdiff_plain;h=232801393614cd0dd2d1d9edb0821a08fe57e767;p=gcc.git 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 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6dfc95421f16..b8c478e72e39 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,32 @@ +2000-05-27 Richard Henderson + + * 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 * function.c (thread_prologue_epilogue_insns): Don't move the diff --git a/gcc/Makefile.in b/gcc/Makefile.in index c362db2b1310..5456c473fe73 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -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 diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 5696c2645a76..cdadf5d0e71e 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -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,8 +9633,9 @@ [(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 - && TARGET_SPLIT_LONG_MOVES" + "! 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])));") diff --git a/gcc/genconfig.c b/gcc/genconfig.c index 6508c39d9060..e7964aba6803 100644 --- a/gcc/genconfig.c +++ b/gcc/genconfig.c @@ -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 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); diff --git a/gcc/genemit.c b/gcc/genemit.c index dab819bf6b10..54793d46a470 100644 --- a/gcc/genemit.c +++ b/gcc/genemit.c @@ -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"); diff --git a/gcc/genrecog.c b/gcc/genrecog.c index 7c435a071df8..b955eb061494 100644 --- a/gcc/genrecog.c +++ b/gcc/genrecog.c @@ -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: - 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); + { + 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 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); } diff --git a/gcc/recog.c b/gcc/recog.c index bac7e471621c..876004129ded 100644 --- a/gcc/recog.c +++ b/gcc/recog.c @@ -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; +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. */ -/* 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) - rtx insn; +peep2_next_insn (n) int n; { - if (insn != NULL_RTX) + 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; +} + +/* 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) { - while (n > 0) + 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) { - if (insn == recog_last_allowed_insn) - return NULL_RTX; + for (j = HARD_REGNO_NREGS (regno, mode) - 1; j >= 0; j--) + SET_HARD_REG_BIT (*reg_set, regno + j); - insn = NEXT_INSN (insn); - if (insn == NULL_RTX) - break; + /* Start the next search with the next register. */ + if (++raw_regno >= FIRST_PSEUDO_REGISTER) + raw_regno = 0; + search_ofs = raw_regno; - if (GET_RTX_CLASS (GET_CODE (insn)) == 'i') - n -= 1; + 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; + + /* 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; - /* 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. */ + /* 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; - - try = peephole2_insns (PATTERN (insn), insn, &last_insn); + rtx try; + int match_len; + + /* 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 */ diff --git a/gcc/recog.h b/gcc/recog.h index 51f6fb0bde3c..465013a73070 100644 --- a/gcc/recog.h +++ b/gcc/recog.h @@ -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; diff --git a/gcc/resource.c b/gcc/resource.c index d84fabeee1d2..af1b4edf6d00 100644 --- a/gcc/resource.c +++ b/gcc/resource.c @@ -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; -} diff --git a/gcc/resource.h b/gcc/resource.h index 718ec651341f..4f0173102aad 100644 --- a/gcc/resource.h +++ b/gcc/resource.h @@ -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)); diff --git a/gcc/toplev.c b/gcc/toplev.c index 30ef18a74368..1fc72f1fcb0a 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -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"