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


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

ia32: peephole2


The object of the peephole2 is arbitrary rtl->rtl transformations
with multiple insns in and multiple insns out.  In addition, a 
SCRATCH pattern in the output template matches iff there is a 
free register of the proper class.

This is a superset of the functionality provided by the pgcc
"riscify" code.

This is dependant on the recently posted resource patch.


r~


	* final.c (peephole): Conditionalize decl on HAVE_peephole.
	(final_scan_insn): Likewise for the invocation of peephole.
	* genconfig.c (main): Look for peephole and peephole2 patterns.
	Emit HAVE_peephole* accordingly.
	* genpeep.c (main): Conditionalize entire output on HAVE_peephole.
	* flags.h (flag_peephole2): Declare.
	* toplev.c: New pass peephole2.  New flag -fpeephole2.

	* genattrtab.c (main): Count DEFINE_PEEPHOLE2.
	* gencodes.c (main): Likewise.
	* genextract.c (main): Likewise.
	* genoutput.c (main): Likewise.
	* genemit.c (max_operand_1): Look for the max scratch operand.
	(gen_rtx_scratch): New.
	(gen_exp): Use it, and pass on new arg subroutine_type.
	(gen_expand): Take max scratch into account.
	(gen_split): Emit peephole2 functions.
	(output_peephole2_scratch): New.
	(main): Include hard-reg-set.h and resource.h.  Handle peephole2.
	* genrecog.c (routine_type): Add PEEPHOLE2.
	(IS_SPLIT): New.
	(make_insn_sequence): Match outer parallel for peep2.
	(add_to_sequence): New args insn_type and top.  Update all callers.
	Handle toplevel peep2 matching insns.
	(write_subroutine): Handle peep2.
	(write_tree_1): Likewise.
	(write_tree): Likewise.
	(main): Likewise.
	(change_state): New arg afterward.  Update all callers.
	Handle matching separate insns.
	* recog.c (recog_next_insn): New.
	(peephole2_optimize): New.
	* rtl.def (DEFINE_PEEPHOLE2): New.
	
Index: final.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/final.c,v
retrieving revision 1.82
diff -c -p -d -r1.82 final.c
*** final.c	1999/08/09 13:59:43	1.82
--- final.c	1999/08/10 03:58:52
*************** struct bb_str {
*** 284,290 ****
--- 284,292 ----
    int length;			/* string length */
  };
  
+ #ifdef HAVE_peephole
  extern rtx peephole		PROTO((rtx));
+ #endif
  
  static struct bb_str *sbb_head	= 0;		/* Head of string list.  */
  static struct bb_str **sbb_tail	= &sbb_head;	/* Ptr to store next bb str */
*************** final_scan_insn (insn, file, optimize, p
*** 2827,2832 ****
--- 2829,2835 ----
  
  #endif
  
+ #ifdef HAVE_peephole
  	/* Do machine-specific peephole optimizations if desired.  */
  
  	if (optimize && !flag_no_peephole && !nopeepholes)
*************** final_scan_insn (insn, file, optimize, p
*** 2857,2862 ****
--- 2860,2866 ----
  	    /* PEEPHOLE might have changed this.  */
  	    body = PATTERN (insn);
  	  }
+ #endif
  
  	/* Try to recognize the instruction.
  	   If successful, verify that the operands satisfy the
Index: flags.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/flags.h,v
retrieving revision 1.29
diff -c -p -d -r1.29 flags.h
*** flags.h	1999/08/09 13:59:44	1.29
--- flags.h	1999/08/10 03:58:52
*************** extern int flag_regmove;
*** 471,476 ****
--- 471,479 ----
  
  /* Instrument functions with calls at entry and exit, for profiling.  */
  extern int flag_instrument_function_entry_exit;
+ 
+ /* Perform a peephole pass before sched2. */
+ extern int flag_peephole2;
  
  /* Other basic status info about current function.  */
  
Index: genattrtab.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/genattrtab.c,v
retrieving revision 1.48
diff -c -p -d -r1.48 genattrtab.c
*** genattrtab.c	1999/04/16 19:52:21	1.48
--- genattrtab.c	1999/08/10 03:58:53
*************** from the machine description file `md'. 
*** 6047,6052 ****
--- 6047,6055 ----
        else if (GET_CODE (desc) == DEFINE_SPLIT)
  	insn_code_number++, insn_index_number++;
  
+       else if (GET_CODE (desc) == DEFINE_PEEPHOLE2)
+ 	insn_code_number++, insn_index_number++;
+ 
        else if (GET_CODE (desc) == DEFINE_ATTR)
  	{
  	  gen_attr (desc);
Index: gencodes.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/gencodes.c,v
retrieving revision 1.17
diff -c -p -d -r1.17 gencodes.c
*** gencodes.c	1999/04/16 19:52:23	1.17
--- gencodes.c	1999/08/10 03:58:53
*************** from the machine description file `md'. 
*** 159,164 ****
--- 159,165 ----
  	  insn_code_number++;
  	}
        if (GET_CODE (desc) == DEFINE_PEEPHOLE
+ 	  || GET_CODE (desc) == DEFINE_PEEPHOLE2
  	  || GET_CODE (desc) == DEFINE_SPLIT)
  	{
  	  insn_code_number++;
Index: genconfig.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/genconfig.c,v
retrieving revision 1.18
diff -c -p -d -r1.18 genconfig.c
*** genconfig.c	1999/04/16 19:52:24	1.18
--- genconfig.c	1999/08/10 03:58:53
*************** static int register_constraint_flag;
*** 42,47 ****
--- 42,49 ----
  static int have_cc0_flag;
  static int have_cmove_flag;
  static int have_lo_sum_flag;
+ static int have_peephole_flag;
+ static int have_peephole2_flag;
  
  /* Maximum number of insns seen in a split.  */
  static int max_insns_per_split = 1;
*************** from the machine description file `md'. 
*** 347,354 ****
  	gen_expand (desc);
        if (GET_CODE (desc) == DEFINE_SPLIT)
  	gen_split (desc);
        if (GET_CODE (desc) == DEFINE_PEEPHOLE)
! 	gen_peephole (desc);
      }
  
    printf ("\n#define MAX_RECOG_OPERANDS %d\n", max_recog_operands + 1);
--- 349,364 ----
  	gen_expand (desc);
        if (GET_CODE (desc) == DEFINE_SPLIT)
  	gen_split (desc);
+       if (GET_CODE (desc) == DEFINE_PEEPHOLE2)
+ 	{
+ 	  have_peephole2_flag = 1;
+ 	  gen_split (desc);
+ 	}
        if (GET_CODE (desc) == DEFINE_PEEPHOLE)
! 	{
! 	  have_peephole_flag = 1;
! 	  gen_peephole (desc);
! 	}
      }
  
    printf ("\n#define MAX_RECOG_OPERANDS %d\n", max_recog_operands + 1);
*************** from the machine description file `md'. 
*** 371,376 ****
--- 381,392 ----
  
    if (have_lo_sum_flag)
      printf ("#define HAVE_lo_sum\n");
+ 
+   if (have_peephole_flag)
+     printf ("#define HAVE_peephole\n");
+ 
+   if (have_peephole2_flag)
+     printf ("#define HAVE_peephole2\n");
  
    fflush (stdout);
    exit (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
Index: genemit.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/genemit.c,v
retrieving revision 1.31
diff -c -p -d -r1.31 genemit.c
*** genemit.c	1999/08/09 13:59:44	1.31
--- genemit.c	1999/08/10 03:58:53
*************** char **insn_name_ptr = 0;
*** 39,44 ****
--- 39,45 ----
  
  static int max_opno;
  static int max_dup_opno;
+ static int max_scratch_opno;
  static int register_constraints;
  static int insn_code_number;
  static int insn_index_number;
*************** struct clobber_ent
*** 66,77 ****
  static void max_operand_1		PROTO((rtx));
  static int max_operand_vec		PROTO((rtx, int));
  static void print_code			PROTO((RTX_CODE));
! static void gen_exp			PROTO((rtx));
  static void gen_insn			PROTO((rtx));
  static void gen_expand			PROTO((rtx));
  static void gen_split			PROTO((rtx));
  static void output_add_clobbers		PROTO((void));
  static void output_init_mov_optab	PROTO((void));
  
  
  static void
--- 67,80 ----
  static void max_operand_1		PROTO((rtx));
  static int max_operand_vec		PROTO((rtx, int));
  static void print_code			PROTO((RTX_CODE));
! static void gen_exp			PROTO((rtx, enum rtx_code));
  static void gen_insn			PROTO((rtx));
  static void gen_expand			PROTO((rtx));
  static void gen_split			PROTO((rtx));
  static void output_add_clobbers		PROTO((void));
  static void output_init_mov_optab	PROTO((void));
+ static void gen_rtx_scratch		PROTO((rtx, enum rtx_code));
+ static void output_peephole2_scratch	PROTO((rtx));
  
  
  static void
*************** max_operand_1 (x)
*** 97,102 ****
--- 100,107 ----
      max_opno = MAX (max_opno, XINT (x, 0));
    if (code == MATCH_DUP || code == MATCH_OP_DUP || code == MATCH_PAR_DUP)
      max_dup_opno = MAX (max_dup_opno, XINT (x, 0));
+   if (code == MATCH_SCRATCH)
+     max_scratch_opno = MAX (max_scratch_opno, XINT (x, 0));
  
    fmt = GET_RTX_FORMAT (code);
    len = GET_RTX_LENGTH (code);
*************** max_operand_vec (insn, arg)
*** 123,128 ****
--- 128,134 ----
  
    max_opno = -1;
    max_dup_opno = -1;
+   max_scratch_opno = -1;
  
    for (i = 0; i < len; i++)
      max_operand_1 (XVECEXP (insn, arg, i));
*************** print_code (code)
*** 144,155 ****
      }
  }
  
  /* Print a C expression to construct an RTX just like X,
     substituting any operand references appearing within.  */
  
  static void
! gen_exp (x)
       rtx x;
  {
    register RTX_CODE code;
    register int i;
--- 150,177 ----
      }
  }
  
+ static void
+ gen_rtx_scratch (x, subroutine_type)
+      rtx x;
+      enum rtx_code subroutine_type;
+ {
+   if (subroutine_type == DEFINE_PEEPHOLE2)
+     {
+       printf ("operand%d", XINT (x, 0));
+     }
+   else
+     {
+       printf ("gen_rtx_SCRATCH (%smode)", GET_MODE_NAME (GET_MODE (x)));
+     }
+ }
+ 
  /* Print a C expression to construct an RTX just like X,
     substituting any operand references appearing within.  */
  
  static void
! gen_exp (x, subroutine_type)
       rtx x;
+      enum rtx_code subroutine_type;
  {
    register RTX_CODE code;
    register int i;
*************** gen_exp (x)
*** 180,186 ****
        for (i = 0; i < XVECLEN (x, 1); i++)
  	{
  	  printf (",\n\t\t");
! 	  gen_exp (XVECEXP (x, 1, i));
  	}
        printf (")");
        return;
--- 202,208 ----
        for (i = 0; i < XVECLEN (x, 1); i++)
  	{
  	  printf (",\n\t\t");
! 	  gen_exp (XVECEXP (x, 1, i), subroutine_type);
  	}
        printf (")");
        return;
*************** gen_exp (x)
*** 191,197 ****
        for (i = 0; i < XVECLEN (x, 2); i++)
  	{
  	  printf (",\n\t\t");
! 	  gen_exp (XVECEXP (x, 2, i));
  	}
        printf (")");
        return;
--- 213,219 ----
        for (i = 0; i < XVECLEN (x, 2); i++)
  	{
  	  printf (",\n\t\t");
! 	  gen_exp (XVECEXP (x, 2, i), subroutine_type);
  	}
        printf (")");
        return;
*************** gen_exp (x)
*** 202,208 ****
        return;
  
      case MATCH_SCRATCH:
!       printf ("gen_rtx_SCRATCH (%smode)", GET_MODE_NAME (GET_MODE (x)));
        return;
  
      case ADDRESS:
--- 224,230 ----
        return;
  
      case MATCH_SCRATCH:
!       gen_rtx_scratch (x, subroutine_type);
        return;
  
      case ADDRESS:
*************** gen_exp (x)
*** 254,260 ****
  	break;
        printf (",\n\t");
        if (fmt[i] == 'e' || fmt[i] == 'u')
! 	gen_exp (XEXP (x, i));
        else if (fmt[i] == 'i')
  	printf ("%u", XINT (x, i));
        else if (fmt[i] == 's')
--- 276,282 ----
  	break;
        printf (",\n\t");
        if (fmt[i] == 'e' || fmt[i] == 'u')
! 	gen_exp (XEXP (x, i), subroutine_type);
        else if (fmt[i] == 'i')
  	printf ("%u", XINT (x, i));
        else if (fmt[i] == 's')
*************** gen_exp (x)
*** 266,272 ****
  	  for (j = 0; j < XVECLEN (x, i); j++)
  	    {
  	      printf (",\n\t\t");
! 	      gen_exp (XVECEXP (x, i, j));
  	    }
  	  printf (")");
  	}
--- 288,294 ----
  	  for (j = 0; j < XVECLEN (x, i); j++)
  	    {
  	      printf (",\n\t\t");
! 	      gen_exp (XVECEXP (x, i, j), subroutine_type);
  	    }
  	  printf (")");
  	}
*************** gen_insn (insn)
*** 378,384 ****
    if (XVECLEN (insn, 1) == 1)
      {
        printf ("  return ");
!       gen_exp (XVECEXP (insn, 1, 0));
        printf (";\n}\n\n");
      }
    else
--- 400,406 ----
    if (XVECLEN (insn, 1) == 1)
      {
        printf ("  return ");
!       gen_exp (XVECEXP (insn, 1, 0), DEFINE_INSN);
        printf (";\n}\n\n");
      }
    else
*************** gen_insn (insn)
*** 387,393 ****
        for (i = 0; i < XVECLEN (insn, 1); i++)
  	{
  	  printf (",\n\t\t");
! 	  gen_exp (XVECEXP (insn, 1, i));
  	}
        printf ("));\n}\n\n");
      }
--- 409,415 ----
        for (i = 0; i < XVECLEN (insn, 1); i++)
  	{
  	  printf (",\n\t\t");
! 	  gen_exp (XVECEXP (insn, 1, i), DEFINE_INSN);
  	}
        printf ("));\n}\n\n");
      }
*************** gen_expand (expand)
*** 430,436 ****
        && XVECLEN (expand, 1) == 1)
      {
        printf ("  return ");
!       gen_exp (XVECEXP (expand, 1, 0));
        printf (";\n}\n\n");
        return;
      }
--- 452,458 ----
        && XVECLEN (expand, 1) == 1)
      {
        printf ("  return ");
!       gen_exp (XVECEXP (expand, 1, 0), DEFINE_EXPAND);
        printf (";\n}\n\n");
        return;
      }
*************** gen_expand (expand)
*** 439,446 ****
       make a local variable.  */
    for (i = operands; i <= max_dup_opno; i++)
      printf ("  rtx operand%d;\n", i);
!   if (operands > 0 || max_dup_opno >= 0)
!     printf ("  rtx operands[%d];\n", MAX (operands, max_dup_opno + 1));
    printf ("  rtx _val = 0;\n");
    printf ("  start_sequence ();\n");
  
--- 461,471 ----
       make a local variable.  */
    for (i = operands; i <= max_dup_opno; i++)
      printf ("  rtx operand%d;\n", i);
!   for (; i <= max_scratch_opno; i++)
!     printf ("  rtx operand%d;\n", i);
!   if (operands > 0 || max_dup_opno >= 0 || max_scratch_opno >= 0)
!     printf ("  rtx operands[%d];\n",
! 	    MAX (operands, MAX (max_scratch_opno, max_dup_opno) + 1));
    printf ("  rtx _val = 0;\n");
    printf ("  start_sequence ();\n");
  
*************** gen_expand (expand)
*** 468,473 ****
--- 493,500 ----
  	    printf ("  operand%d = operands[%d];\n", i, i);
  	  for (; i <= max_dup_opno; i++)
  	    printf ("  operand%d = operands[%d];\n", i, i);
+ 	  for (; i <= max_scratch_opno; i++)
+ 	    printf ("  operand%d = operands[%d];\n", i, i);
  	}
      }
  
*************** gen_expand (expand)
*** 503,509 ****
  	printf ("  emit (");
        else
  	printf ("  emit_insn (");
!       gen_exp (next);
        printf (");\n");
        if (GET_CODE (next) == SET && GET_CODE (SET_DEST (next)) == PC
  	  && GET_CODE (SET_SRC (next)) == LABEL_REF)
--- 530,536 ----
  	printf ("  emit (");
        else
  	printf ("  emit_insn (");
!       gen_exp (next, DEFINE_EXPAND);
        printf (");\n");
        if (GET_CODE (next) == SET && GET_CODE (SET_DEST (next)) == PC
  	  && GET_CODE (SET_SRC (next)) == LABEL_REF)
*************** gen_split (split)
*** 526,552 ****
  {
    register int i;
    int operands;
  
    if (XVEC (split, 0) == 0)
!     fatal ("define_split (definition %d) lacks a pattern", insn_index_number);
    else if (XVEC (split, 2) == 0)
!     fatal ("define_split (definition %d) lacks a replacement pattern",
  	   insn_index_number);
  
    /* Find out how many operands this function has.  */
  
    max_operand_vec (split, 2);
!   operands = MAX (max_opno, max_dup_opno) + 1;
  
    /* Output the function name and argument declarations.  */
!   printf ("rtx\ngen_split_%d (operands)\n     rtx *operands;\n",
! 	  insn_code_number);
    printf ("{\n");
  
    /* Declare all local variables.  */
    for (i = 0; i < operands; i++)
      printf ("  rtx operand%d;\n", i);
    printf ("  rtx _val = 0;\n");
    printf ("  start_sequence ();\n");
  
    /* The fourth operand of DEFINE_SPLIT is some code to be executed
--- 553,606 ----
  {
    register int i;
    int operands;
+   const char *name = "split";
  
+   if (GET_CODE (split) == DEFINE_PEEPHOLE2)
+     name = "peephole2";
+ 
    if (XVEC (split, 0) == 0)
!     fatal ("define_%s (definition %d) lacks a pattern", name,
! 	   insn_index_number);
    else if (XVEC (split, 2) == 0)
!     fatal ("define_%s (definition %d) lacks a replacement pattern", name,
  	   insn_index_number);
  
    /* Find out how many operands this function has.  */
  
    max_operand_vec (split, 2);
!   operands = MAX (max_opno, MAX (max_dup_opno, max_scratch_opno)) + 1;
  
    /* Output the function name and argument declarations.  */
!   if (GET_CODE (split) == DEFINE_PEEPHOLE2)
!     {
!       printf ("rtx\ngen_%s_%d (curr_insn, operands)\n     rtx curr_insn;\n\
!     rtx *operands;\n", 
! 	      name,
! 	      insn_code_number);
!     }
!   else
!     {
!       printf ("rtx\ngen_%s_%d (operands)\n     rtx *operands;\n", name,
! 	      insn_code_number);
!     }
    printf ("{\n");
  
    /* Declare all local variables.  */
    for (i = 0; i < operands; i++)
      printf ("  rtx operand%d;\n", i);
    printf ("  rtx _val = 0;\n");
+ 
+   if (GET_CODE (split) == DEFINE_PEEPHOLE2)
+     {
+       printf ("  HARD_REG_SET _regs_allocated;\n");
+       printf ("  CLEAR_HARD_REG_SET (_regs_allocated);\n");
+ 
+       for (i = 0; i < XVECLEN (split, 2); i++)
+ 	{
+ 	  output_peephole2_scratch (XVECEXP (split, 2, i));
+ 	}
+     }
+ 
    printf ("  start_sequence ();\n");
  
    /* The fourth operand of DEFINE_SPLIT is some code to be executed
*************** gen_split (split)
*** 591,597 ****
  	printf ("  emit (");
        else
  	printf ("  emit_insn (");
!       gen_exp (next);
        printf (");\n");
        if (GET_CODE (next) == SET && GET_CODE (SET_DEST (next)) == PC
  	  && GET_CODE (SET_SRC (next)) == LABEL_REF)
--- 645,651 ----
  	printf ("  emit (");
        else
  	printf ("  emit_insn (");
!       gen_exp (next, GET_CODE (split));
        printf (");\n");
        if (GET_CODE (next) == SET && GET_CODE (SET_DEST (next)) == PC
  	  && GET_CODE (SET_SRC (next)) == LABEL_REF)
*************** output_add_clobbers ()
*** 631,637 ****
        for (i = clobber->first_clobber; i < XVECLEN (clobber->pattern, 1); i++)
  	{
  	  printf ("      XVECEXP (pattern, 0, %d) = ", i);
! 	  gen_exp (XVECEXP (clobber->pattern, 1, i));
  	  printf (";\n");
  	}
  
--- 685,692 ----
        for (i = clobber->first_clobber; i < XVECLEN (clobber->pattern, 1); i++)
  	{
  	  printf ("      XVECEXP (pattern, 0, %d) = ", i);
! 	  gen_exp (XVECEXP (clobber->pattern, 1, i),
! 		   GET_CODE (clobber->pattern));
  	  printf (";\n");
  	}
  
*************** output_add_clobbers ()
*** 644,649 ****
--- 699,740 ----
    printf ("}\n");
  }
  
+ /* Generate code to invoke find_free_register () as needed for the
+    scratch registers used by the peephole2 pattern in INSN. */
+ 
+ static void
+ output_peephole2_scratch (rtx insn)
+ {
+   RTX_CODE code = GET_CODE (insn);
+ 
+   if (code == MATCH_SCRATCH)
+     {
+       printf ("  if ((operands[%d] = find_free_register (curr_insn, \"%s\", %smode, &_regs_allocated)) == NULL_RTX)\n\
+     return NULL;\n", 
+ 	      XINT (insn, 0),
+ 	      XSTR (insn, 1),
+ 	      GET_MODE_NAME (GET_MODE (insn)));
+     }
+   else
+     {
+       int i;
+       char *fmt = GET_RTX_FORMAT (code);
+       int len = GET_RTX_LENGTH (code);
+ 
+       for (i = 0; i < len; i++)
+ 	{
+ 	  if (fmt[i] == 'e' || fmt[i] == 'u')
+ 	    output_peephole2_scratch (XEXP (insn, i));
+ 	  else if (fmt[i] == 'E')
+ 	    {
+ 	      int j;
+ 	      for (j = 0; j < XVECLEN (insn, i); j++)
+ 		output_peephole2_scratch (XVECEXP (insn, i, j));
+ 	    }
+ 	}
+     }
+ }
+ 
  /* Write a function, init_mov_optab, that is called to set up entries
     in mov_optab for EXTRA_CC_MODES.  */
  
*************** from the machine description file `md'. 
*** 779,784 ****
--- 870,877 ----
    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 \"resource.h\"\n");
    printf ("#include \"reload.h\"\n\n");
    printf ("extern rtx recog_operand[];\n");
    printf ("#define operands emit_operand\n\n");
*************** from the machine description file `md'. 
*** 795,800 ****
--- 888,894 ----
        ungetc (c, infile);
  
        desc = read_rtx (infile);
+ 
        if (GET_CODE (desc) == DEFINE_INSN)
  	{
  	  gen_insn (desc);
*************** from the machine description file `md'. 
*** 806,811 ****
--- 900,910 ----
  	  ++insn_code_number;
  	}
        if (GET_CODE (desc) == DEFINE_SPLIT)
+ 	{
+ 	  gen_split (desc);
+ 	  ++insn_code_number;
+ 	}
+       if (GET_CODE (desc) == DEFINE_PEEPHOLE2)
  	{
  	  gen_split (desc);
  	  ++insn_code_number;
Index: genextract.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/genextract.c,v
retrieving revision 1.26
diff -c -p -d -r1.26 genextract.c
*** genextract.c	1999/04/16 19:52:27	1.26
--- genextract.c	1999/08/10 03:58:53
*************** from the machine description file `md'. 
*** 496,501 ****
--- 496,502 ----
  	}
  
        else if (GET_CODE (desc) == DEFINE_EXPAND
+ 	       || GET_CODE (desc) == DEFINE_PEEPHOLE2
  	       || GET_CODE (desc) == DEFINE_SPLIT)
  	++insn_code_number;
      }
Index: genoutput.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/genoutput.c,v
retrieving revision 1.24
diff -c -p -d -r1.24 genoutput.c
*** genoutput.c	1999/08/09 13:59:44	1.24
--- genoutput.c	1999/08/10 03:58:53
*************** main (argc, argv)
*** 1025,1031 ****
  	gen_peephole (desc);
        if (GET_CODE (desc) == DEFINE_EXPAND)
  	gen_expand (desc);
!       if (GET_CODE (desc) == DEFINE_SPLIT)
  	gen_split (desc);
        next_index_number++;
      }
--- 1025,1032 ----
  	gen_peephole (desc);
        if (GET_CODE (desc) == DEFINE_EXPAND)
  	gen_expand (desc);
!       if (GET_CODE (desc) == DEFINE_SPLIT
!  	  || GET_CODE (desc) == DEFINE_PEEPHOLE2)
  	gen_split (desc);
        next_index_number++;
      }
Index: genpeep.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/genpeep.c,v
retrieving revision 1.26
diff -c -p -d -r1.26 genpeep.c
*** genpeep.c	1999/08/09 15:23:24	1.26
--- genpeep.c	1999/08/10 03:58:53
*************** from the machine description file `md'. 
*** 479,484 ****
--- 479,485 ----
    printf ("#include \"except.h\"\n\n");
    printf ("#include \"function.h\"\n\n");
  
+   printf ("#ifdef HAVE_peephole\n");
    printf ("extern rtx peep_operand[];\n\n");
    printf ("#define operands peep_operand\n\n");
  
*************** from the machine description file `md'. 
*** 519,524 ****
--- 520,526 ----
      max_opno = 1;
  
    printf ("rtx peep_operand[%d];\n", max_opno + 1);
+   printf ("#endif\n");
  
    fflush (stdout);
    exit (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
Index: genrecog.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/genrecog.c,v
retrieving revision 1.33
diff -c -p -d -r1.33 genrecog.c
*** genrecog.c	1999/04/16 19:52:35	1.33
--- genrecog.c	1999/08/10 03:58:53
*************** struct decision
*** 110,120 ****
  
  static int next_subroutine_number;
  
! /* We can write two types of subroutines: One for insn recognition and
!    one to split insns.  This defines which type is being written.  */
  
! enum routine_type {RECOG, SPLIT};
  
  /* Next available node number for tree nodes.  */
  
  static int next_number;
--- 110,123 ----
  
  static int next_subroutine_number;
  
! /* We can write three types of subroutines: One for insn recognition,
!    one to split insns, and one for peephole-type optimizations.  This
!    defines which type is being written.  */
  
! enum routine_type {RECOG, SPLIT, PEEPHOLE2};
  
+ #define IS_SPLIT(X) ((X) == SPLIT || (X)==PEEPHOLE2)
+ 
  /* Next available node number for tree nodes.  */
  
  static int next_number;
*************** static struct pred_table
*** 172,178 ****
  
  static struct decision_head make_insn_sequence PROTO((rtx, enum routine_type));
  static struct decision *add_to_sequence PROTO((rtx, struct decision_head *,
! 					       const char *));
  static int not_both_true	PROTO((struct decision *, struct decision *,
  				       int));
  static int position_merit	PROTO((struct decision *, enum machine_mode,
--- 175,182 ----
  
  static struct decision_head make_insn_sequence PROTO((rtx, enum routine_type));
  static struct decision *add_to_sequence PROTO((rtx, struct decision_head *,
! 					       const char *, 
! 					       enum routine_type, int));
  static int not_both_true	PROTO((struct decision *, struct decision *,
  				       int));
  static int position_merit	PROTO((struct decision *, enum machine_mode,
*************** static void clear_modes		PROTO((struct d
*** 192,198 ****
  static void write_tree		PROTO((struct decision *, const char *,
  				       struct decision *, int,
  				       enum routine_type));
! static void change_state	PROTO((const char *, const char *, int));
  void fatal		PVPROTO((const char *, ...))
    ATTRIBUTE_PRINTF_1 ATTRIBUTE_NORETURN;
  void fancy_abort		PROTO((void)) ATTRIBUTE_NORETURN;
--- 196,203 ----
  static void write_tree		PROTO((struct decision *, const char *,
  				       struct decision *, int,
  				       enum routine_type));
! static void change_state	PROTO((const char *, const char *, int,
! 				       struct decision *));
  void fatal		PVPROTO((const char *, ...))
    ATTRIBUTE_PRINTF_1 ATTRIBUTE_NORETURN;
  void fancy_abort		PROTO((void)) ATTRIBUTE_NORETURN;
*************** make_insn_sequence (insn, type)
*** 223,230 ****
  	new_size = (insn_name_ptr_size ? insn_name_ptr_size * 2 : 512);
  	insn_name_ptr =
  	  (char **) xrealloc (insn_name_ptr, sizeof(char *) * new_size);
! 	bzero ((PTR)(insn_name_ptr + insn_name_ptr_size),
! 	       sizeof(char *) * (new_size - insn_name_ptr_size));
  	insn_name_ptr_size = new_size;
        }
  
--- 228,235 ----
  	new_size = (insn_name_ptr_size ? insn_name_ptr_size * 2 : 512);
  	insn_name_ptr =
  	  (char **) xrealloc (insn_name_ptr, sizeof(char *) * new_size);
! 	memset (insn_name_ptr + insn_name_ptr_size, 0,
! 		sizeof(char *) * (new_size - insn_name_ptr_size));
  	insn_name_ptr_size = new_size;
        }
  
*************** make_insn_sequence (insn, type)
*** 244,250 ****
      insn_name_ptr[next_insn_code] = name;
    }  
  
!   if (XVECLEN (insn, type == RECOG) == 1)
      x = XVECEXP (insn, type == RECOG, 0);
    else
      {
--- 249,257 ----
      insn_name_ptr[next_insn_code] = name;
    }  
  
!   /* peephole2 always gets an outer parallel even if it's only one
!      entry. */
!   if (type != PEEPHOLE2 && XVECLEN (insn, type == RECOG) == 1)
      x = XVECEXP (insn, type == RECOG, 0);
    else
      {
*************** make_insn_sequence (insn, type)
*** 253,259 ****
        PUT_MODE (x, VOIDmode);
      }
  
!   last = add_to_sequence (x, &head, "");
  
    if (c_test[0])
      last->c_test = c_test;
--- 260,266 ----
        PUT_MODE (x, VOIDmode);
      }
  
!   last = add_to_sequence (x, &head, "", type, 1);
  
    if (c_test[0])
      last->c_test = c_test;
*************** make_insn_sequence (insn, type)
*** 291,297 ****
  		XVECEXP (new, 0, j) = XVECEXP (x, 0, j);
  	    }
  
! 	  last = add_to_sequence (new, &clobber_head, "");
  
  	  if (c_test[0])
  	    last->c_test = c_test;
--- 298,304 ----
  		XVECEXP (new, 0, j) = XVECEXP (x, 0, j);
  	    }
  
! 	  last = add_to_sequence (new, &clobber_head, "", type, 1);
  
  	  if (c_test[0])
  	    last->c_test = c_test;
*************** make_insn_sequence (insn, type)
*** 308,313 ****
--- 315,324 ----
      /* Define the subroutine we will call below and emit in genemit.  */
      printf ("extern rtx gen_split_%d ();\n", last->insn_code_number);
  
+   if (type == PEEPHOLE2)
+     /* Define the subroutine we will call below and emit in genemit.  */
+     printf ("extern rtx gen_peephole2_%d ();\n", last->insn_code_number);
+ 
    return head;
  }
  
*************** make_insn_sequence (insn, type)
*** 319,331 ****
  
     POSITION is the string representing the current position in the insn.
  
     A pointer to the final node in the chain is returned.  */
  
  static struct decision *
! add_to_sequence (pattern, last, position)
       rtx pattern;
       struct decision_head *last;
       const char *position;
  {
    register RTX_CODE code;
    register struct decision *new
--- 330,346 ----
  
     POSITION is the string representing the current position in the insn.
  
+    INSN_TYPE is the type of insn for which we are emitting code.
+ 
     A pointer to the final node in the chain is returned.  */
  
  static struct decision *
! add_to_sequence (pattern, last, position, insn_type, top)
       rtx pattern;
       struct decision_head *last;
       const char *position;
+      enum routine_type insn_type;
+      int top;
  {
    register RTX_CODE code;
    register struct decision *new
*************** add_to_sequence (pattern, last, position
*** 382,387 ****
--- 397,427 ----
  
    switch (code)
      {
+     case PARALLEL:
+       /* Toplevel peephole pattern. */
+       if (insn_type == PEEPHOLE2 && top)
+ 	{
+ 	  struct decision_head *place = last;
+ 
+ 	  for (i = 0; i < XVECLEN (pattern, 0); i++)
+ 	    {
+ 	      /* Which insn we're looking at is represented by A-Z. We don't
+ 	         ever use 'A', however; it is always implied. */
+ 	      if (i > 0)
+ 		{
+ 		  newpos[depth] = 'A' + i;
+ 		}
+ 	      else
+ 		{
+ 		  newpos[depth] = 0;
+ 		}
+ 	      new = add_to_sequence (XVECEXP (pattern, 0, i),
+ 				     place, newpos, insn_type, 0);
+ 	      place = &new->success;
+ 	    }
+ 	  return new;
+ 	}
+       break;
      case MATCH_OPERAND:
      case MATCH_SCRATCH:
      case MATCH_OPERATOR:
*************** add_to_sequence (pattern, last, position
*** 453,459 ****
  	    {
  	      newpos[depth] = i + (code == MATCH_OPERATOR ? '0': 'a');
  	      new = add_to_sequence (XVECEXP (pattern, 2, i),
! 				     &new->success, newpos);
  	    }
  	}
  
--- 493,499 ----
  	    {
  	      newpos[depth] = i + (code == MATCH_OPERATOR ? '0': 'a');
  	      new = add_to_sequence (XVECEXP (pattern, 2, i),
! 				     &new->success, newpos, insn_type, 0);
  	    }
  	}
  
*************** add_to_sequence (pattern, last, position
*** 468,474 ****
  	{
  	  newpos[depth] = i + '0';
  	  new = add_to_sequence (XVECEXP (pattern, 1, i),
! 				 &new->success, newpos);
  	}
        return new;
  
--- 508,514 ----
  	{
  	  newpos[depth] = i + '0';
  	  new = add_to_sequence (XVECEXP (pattern, 1, i),
! 				 &new->success, newpos, insn_type, 0);
  	}
        return new;
  
*************** add_to_sequence (pattern, last, position
*** 498,507 ****
  	  fatal ("mode mismatch in SET");
  	}
        newpos[depth] = '0';
!       new = add_to_sequence (SET_DEST (pattern), &new->success, newpos);
        this->success.first->enforce_mode = 1;
        newpos[depth] = '1';
!       new = add_to_sequence (SET_SRC (pattern), &new->success, newpos);
  
        /* If set are setting CC0 from anything other than a COMPARE, we
  	 must enforce the mode so that we do not produce ambiguous insns.  */
--- 538,549 ----
  	  fatal ("mode mismatch in SET");
  	}
        newpos[depth] = '0';
!       new = add_to_sequence (SET_DEST (pattern), &new->success, newpos, 
! 			     insn_type, 0);
        this->success.first->enforce_mode = 1;
        newpos[depth] = '1';
!       new = add_to_sequence (SET_SRC (pattern), &new->success, newpos,
! 			     insn_type, 0);
  
        /* If set are setting CC0 from anything other than a COMPARE, we
  	 must enforce the mode so that we do not produce ambiguous insns.  */
*************** add_to_sequence (pattern, last, position
*** 514,520 ****
      case ZERO_EXTEND:
      case STRICT_LOW_PART:
        newpos[depth] = '0';
!       new = add_to_sequence (XEXP (pattern, 0), &new->success, newpos);
        this->success.first->enforce_mode = 1;
        return new;
  
--- 556,563 ----
      case ZERO_EXTEND:
      case STRICT_LOW_PART:
        newpos[depth] = '0';
!       new = add_to_sequence (XEXP (pattern, 0), &new->success, newpos, 
! 			     insn_type, 0);
        this->success.first->enforce_mode = 1;
        return new;
  
*************** add_to_sequence (pattern, last, position
*** 522,540 ****
        this->test_elt_one_int = 1;
        this->elt_one_int = XINT (pattern, 1);
        newpos[depth] = '0';
!       new = add_to_sequence (XEXP (pattern, 0), &new->success, newpos);
        this->success.first->enforce_mode = 1;
        return new;
  
      case ZERO_EXTRACT:
      case SIGN_EXTRACT:
        newpos[depth] = '0';
!       new = add_to_sequence (XEXP (pattern, 0), &new->success, newpos);
        this->success.first->enforce_mode = 1;
        newpos[depth] = '1';
!       new = add_to_sequence (XEXP (pattern, 1), &new->success, newpos);
        newpos[depth] = '2';
!       new = add_to_sequence (XEXP (pattern, 2), &new->success, newpos);
        return new;
  
      case EQ:   case NE:   case LE:   case LT:   case GE:  case GT:
--- 565,587 ----
        this->test_elt_one_int = 1;
        this->elt_one_int = XINT (pattern, 1);
        newpos[depth] = '0';
!       new = add_to_sequence (XEXP (pattern, 0), &new->success, newpos,
! 			     insn_type, 0);
        this->success.first->enforce_mode = 1;
        return new;
  
      case ZERO_EXTRACT:
      case SIGN_EXTRACT:
        newpos[depth] = '0';
!       new = add_to_sequence (XEXP (pattern, 0), &new->success, newpos,
! 			     insn_type, 0);
        this->success.first->enforce_mode = 1;
        newpos[depth] = '1';
!       new = add_to_sequence (XEXP (pattern, 1), &new->success, newpos,
! 			     insn_type, 0);
        newpos[depth] = '2';
!       new = add_to_sequence (XEXP (pattern, 2), &new->success, newpos,
! 			     insn_type, 0);
        return new;
  
      case EQ:   case NE:   case LE:   case LT:   case GE:  case GT:
*************** add_to_sequence (pattern, last, position
*** 549,558 ****
      case COMPARE:
        /* Enforce the mode on the first operand to avoid ambiguous insns.  */
        newpos[depth] = '0';
!       new = add_to_sequence (XEXP (pattern, 0), &new->success, newpos);
        this->success.first->enforce_mode = 1;
        newpos[depth] = '1';
!       new = add_to_sequence (XEXP (pattern, 1), &new->success, newpos);
        return new;
        
      default:
--- 596,607 ----
      case COMPARE:
        /* Enforce the mode on the first operand to avoid ambiguous insns.  */
        newpos[depth] = '0';
!       new = add_to_sequence (XEXP (pattern, 0), &new->success, newpos,
! 			     insn_type, 0);
        this->success.first->enforce_mode = 1;
        newpos[depth] = '1';
!       new = add_to_sequence (XEXP (pattern, 1), &new->success, newpos,
! 			     insn_type, 0);
        return new;
        
      default:
*************** add_to_sequence (pattern, last, position
*** 565,571 ****
      {
        newpos[depth] = '0' + i;
        if (fmt[i] == 'e' || fmt[i] == 'u')
! 	new = add_to_sequence (XEXP (pattern, i), &new->success, newpos);
        else if (fmt[i] == 'i' && i == 0)
  	{
  	  this->test_elt_zero_int = 1;
--- 614,621 ----
      {
        newpos[depth] = '0' + i;
        if (fmt[i] == 'e' || fmt[i] == 'u')
! 	new = add_to_sequence (XEXP (pattern, i), &new->success, newpos,
! 			       insn_type, 0);
        else if (fmt[i] == 'i' && i == 0)
  	{
  	  this->test_elt_zero_int = 1;
*************** add_to_sequence (pattern, last, position
*** 597,603 ****
  	    {
  	      newpos[depth] = 'a' + j;
  	      new = add_to_sequence (XVECEXP (pattern, i, j),
! 				     &new->success, newpos);
  	    }
  	}
        else if (fmt[i] != '0')
--- 647,653 ----
  	    {
  	      newpos[depth] = 'a' + j;
  	      new = add_to_sequence (XVECEXP (pattern, i, j),
! 				     &new->success, newpos, insn_type, 0);
  	    }
  	}
        else if (fmt[i] != '0')
*************** write_subroutine (tree, type)
*** 1031,1054 ****
  {
    int i;
  
!   if (type == SPLIT)
      printf ("rtx\nsplit");
    else
      printf ("int\nrecog");
  
    if (tree != 0 && tree->subroutine_number > 0)
      printf ("_%d", tree->subroutine_number);
!   else if (type == SPLIT)
      printf ("_insns");
  
    printf (" (x0, insn");
    if (type == RECOG)
      printf (", pnum_clobbers");
  
    printf (")\n");
    printf ("     register rtx x0;\n     rtx insn ATTRIBUTE_UNUSED;\n");
    if (type == RECOG)
      printf ("     int *pnum_clobbers ATTRIBUTE_UNUSED;\n");
  
    printf ("{\n");
    printf ("  register rtx *ro = &recog_operand[0];\n");
--- 1081,1112 ----
  {
    int i;
  
!   if (type == PEEPHOLE2)
!     printf ("rtx\npeephole2");
!   else if (type == SPLIT)
      printf ("rtx\nsplit");
    else
      printf ("int\nrecog");
  
    if (tree != 0 && tree->subroutine_number > 0)
      printf ("_%d", tree->subroutine_number);
!   else if (IS_SPLIT (type))
      printf ("_insns");
  
    printf (" (x0, insn");
    if (type == RECOG)
      printf (", pnum_clobbers");
+   if (type == PEEPHOLE2)
+     printf (", _last_insn");
  
    printf (")\n");
+   /* The peephole2 pass uses the insn argument to determine which
+      hard registers are available at that point. */
    printf ("     register rtx x0;\n     rtx insn ATTRIBUTE_UNUSED;\n");
    if (type == RECOG)
      printf ("     int *pnum_clobbers ATTRIBUTE_UNUSED;\n");
+   if (type == PEEPHOLE2)
+     printf ("     rtx *_last_insn ATTRIBUTE_UNUSED;\n");
  
    printf ("{\n");
    printf ("  register rtx *ro = &recog_operand[0];\n");
*************** write_subroutine (tree, type)
*** 1058,1066 ****
      printf ("x%d ATTRIBUTE_UNUSED, ", i);
  
    printf ("x%d ATTRIBUTE_UNUSED;\n", max_depth);
!   printf ("  %s tem ATTRIBUTE_UNUSED;\n", type == SPLIT ? "rtx" : "int");
    write_tree (tree, "", NULL_PTR, 1, type);
!   printf (" ret0: return %d;\n}\n\n", type == SPLIT ? 0 : -1);
  }
  
  /* This table is used to indent the recog_* functions when we are inside
--- 1116,1124 ----
      printf ("x%d ATTRIBUTE_UNUSED, ", i);
  
    printf ("x%d ATTRIBUTE_UNUSED;\n", max_depth);
!   printf ("  %s tem ATTRIBUTE_UNUSED;\n", IS_SPLIT (type) ? "rtx" : "int");
    write_tree (tree, "", NULL_PTR, 1, type);
!   printf (" ret0: return %d;\n}\n\n", IS_SPLIT (type) ? 0 : -1);
  }
  
  /* This table is used to indent the recog_* functions when we are inside
*************** write_tree_1 (tree, prevpos, afterward, 
*** 1145,1151 ****
  
    if (tree)
      {
!       change_state (prevpos, tree->position, 2);
        prevpos = tree->position;
      }
  
--- 1203,1209 ----
  
    if (tree)
      {
!       change_state (prevpos, tree->position, 2, afterward);
        prevpos = tree->position;
      }
  
*************** write_tree_1 (tree, prevpos, afterward, 
*** 1296,1302 ****
  	      if (afterward)
  		{
  		  printf ("    {\n");
! 		  change_state (p->position, afterward->position, 6);
  		  printf ("      goto L%d;\n    }\n", afterward->number);
  		}
  	      else
--- 1354,1361 ----
  	      if (afterward)
  		{
  		  printf ("    {\n");
! 		  change_state (p->position, afterward->position, 6,
! 				afterward);
  		  printf ("      goto L%d;\n    }\n", afterward->number);
  		}
  	      else
*************** write_tree_1 (tree, prevpos, afterward, 
*** 1316,1322 ****
  	      if (afterward)
  		{
  		  printf ("    {\n");
! 		  change_state (p->position, afterward->position, indent + 4);
  		  printf ("    goto L%d;\n    }\n", afterward->number);
  		}
  	      else
--- 1375,1382 ----
  	      if (afterward)
  		{
  		  printf ("    {\n");
! 		  change_state (p->position, afterward->position, indent + 4,
! 				afterward);
  		  printf ("    goto L%d;\n    }\n", afterward->number);
  		}
  	      else
*************** write_tree_1 (tree, prevpos, afterward, 
*** 1454,1463 ****
        if (p->insn_code_number >= 0)
  	{
  	  if (type == SPLIT)
- 	    printf ("%sreturn gen_split_%d (operands);\n",
- 		    indents[inner_indent], p->insn_code_number);
- 	  else
  	    {
  	      if (p->num_clobbers_to_add)
  		{
  		  if (need_bracket)
--- 1514,1543 ----
        if (p->insn_code_number >= 0)
  	{
  	  if (type == SPLIT)
  	    {
+ 	      printf ("%sreturn gen_split_%d (operands);\n",
+ 		      indents[inner_indent], p->insn_code_number);
+ 	    }
+ 	  else if (type == PEEPHOLE2)
+ 	    {
+ 	      /* We want to set *_last_insn to point to the last
+ 		 insn matched. */
+ 	      printf ("%s{\n", indents[inner_indent]);
+ 	      inner_indent += 2;
+ 	      for (i = depth - 1; i >= 0; i--)
+ 		{
+ 		  if (tree->position[i] >= 'A' && tree->position[i] <= 'Z')
+ 		    break;
+ 		}
+ 	      if (i == -1)
+ 		printf ("%s*_last_insn = insn;\n", indents[inner_indent]);
+ 	      printf ("%sreturn gen_peephole2_%d (insn, operands);\n",
+ 		      indents[inner_indent], p->insn_code_number);
+ 	      inner_indent -= 2;
+ 	      printf ("%s}\n", indents[inner_indent]);
+ 	    }
+ 	  else	    
+ 	    {
  	      if (p->num_clobbers_to_add)
  		{
  		  if (need_bracket)
*************** write_tree_1 (tree, prevpos, afterward, 
*** 1516,1522 ****
  
    if (afterward)
      {
!       change_state (prevpos, afterward->position, 2);
        printf ("  goto L%d;\n", afterward->number);
      }
    else
--- 1596,1602 ----
  
    if (afterward)
      {
!       change_state (prevpos, afterward->position, 2, afterward);
        printf ("  goto L%d;\n", afterward->number);
      }
    else
*************** write_tree (tree, prevpos, afterward, in
*** 1594,1602 ****
       enum routine_type type;
  {
    register struct decision *p;
!   const char *name_prefix = (type == SPLIT ? "split" : "recog");
!   const char *call_suffix = (type == SPLIT ? "" : ", pnum_clobbers");
  
    if (! initial && tree->subroutine_number > 0)
      {
        OUTPUT_LABEL (" ", tree->number);
--- 1674,1697 ----
       enum routine_type type;
  {
    register struct decision *p;
!   const char *name_prefix;
!   const char *call_suffix;
  
+   switch (type)
+     {
+     case SPLIT:
+       name_prefix = "split";
+       call_suffix = "";
+       break;
+     case PEEPHOLE2:
+       name_prefix = "peephole2";
+       call_suffix = ", _last_insn";
+       break;
+     case RECOG:
+       name_prefix = "recog";
+       call_suffix = ", pnum_clobbers";
+       break;
+     }
    if (! initial && tree->subroutine_number > 0)
      {
        OUTPUT_LABEL (" ", tree->number);
*************** write_tree (tree, prevpos, afterward, in
*** 1605,1615 ****
  	{
  	  printf ("  tem = %s_%d (x0, insn%s);\n",
  		  name_prefix, tree->subroutine_number, call_suffix);
! 	  if (type == SPLIT)
  	    printf ("  if (tem != 0) return tem;\n");
  	  else
  	    printf ("  if (tem >= 0) return tem;\n");
! 	  change_state (tree->position, afterward->position, 2);
  	  printf ("  goto L%d;\n", afterward->number);
  	}
        else
--- 1700,1710 ----
  	{
  	  printf ("  tem = %s_%d (x0, insn%s);\n",
  		  name_prefix, tree->subroutine_number, call_suffix);
! 	  if (IS_SPLIT (type))
  	    printf ("  if (tem != 0) return tem;\n");
  	  else
  	    printf ("  if (tem >= 0) return tem;\n");
! 	  change_state (tree->position, afterward->position, 2, afterward);
  	  printf ("  goto L%d;\n", afterward->number);
  	}
        else
*************** write_tree (tree, prevpos, afterward, in
*** 1628,1642 ****
  
  
  /* Assuming that the state of argument is denoted by OLDPOS, take whatever
!    actions are necessary to move to NEWPOS.
  
!    INDENT says how many blanks to place at the front of lines.  */
  
  static void
! change_state (oldpos, newpos, indent)
       const char *oldpos;
       const char *newpos;
       int indent;
  {
    int odepth = strlen (oldpos);
    int depth = odepth;
--- 1723,1743 ----
  
  
  /* Assuming that the state of argument is denoted by OLDPOS, take whatever
!    actions are necessary to move to NEWPOS. If we fail to move to the
!    new state, branch to node AFTERWARD if non-zero, otherwise return.
  
!    INDENT says how many blanks to place at the front of lines.  
  
+    Failure to move to the new state can only occur if we are trying to
+    match multiple insns and we try to step past the end of the
+    stream. */
+ 
  static void
! change_state (oldpos, newpos, indent, afterward)
       const char *oldpos;
       const char *newpos;
       int indent;
+      struct decision *afterward;
  {
    int odepth = strlen (oldpos);
    int depth = odepth;
*************** change_state (oldpos, newpos, indent)
*** 1651,1657 ****
  
    while (depth < ndepth)
      {
!       if (newpos[depth] >= 'a' && newpos[depth] <= 'z')
  	printf ("%sx%d = XVECEXP (x%d, 0, %d);\n",
  		indents[indent], depth + 1, depth, newpos[depth] - 'a');
        else
--- 1752,1775 ----
  
    while (depth < ndepth)
      {
!       /* It's a different insn from the first one. */
!       if (newpos[depth] >= 'A' && newpos[depth] <= 'Z')
! 	{
! 	  printf ("%sx%d = recog_next_insn (insn, %d, _last_insn);\n", 
! 		  indents[indent],
! 		  depth + 1,
! 		  newpos[depth] - 'A');
! 
! 	  printf ("%sif (x%d == NULL_RTX)\n",
! 		  indents[indent],
! 		  depth + 1);
! 
! 	  if (afterward)
! 	    printf ("%sgoto L%d;\n", indents[indent + 2], afterward->number);
! 	  else
! 	    printf ("%sgoto ret0;\n", indents[indent + 2]);
! 	}
!       else if (newpos[depth] >= 'a' && newpos[depth] <= 'z')
  	printf ("%sx%d = XVECEXP (x%d, 0, %d);\n",
  		indents[indent], depth + 1, depth, newpos[depth] - 'a');
        else
*************** main (argc, argv)
*** 1736,1746 ****
--- 1854,1866 ----
    rtx desc;
    struct decision_head recog_tree;
    struct decision_head split_tree;
+   struct decision_head peephole2_tree;
    FILE *infile;
    register int c;
  
    obstack_init (rtl_obstack);
    recog_tree.first = recog_tree.last = split_tree.first = split_tree.last = 0;
+   peephole2_tree.first = peephole2_tree.last = 0;
  
    if (argc <= 1)
      fatal ("No input file name.");
*************** from the machine description file `md'. 
*** 1785,1790 ****
--- 1905,1914 ----
        else if (GET_CODE (desc) == DEFINE_SPLIT)
  	split_tree = merge_trees (split_tree,
  				  make_insn_sequence (desc, SPLIT));
+       else if (GET_CODE (desc) == DEFINE_PEEPHOLE2)
+ 	peephole2_tree = merge_trees (peephole2_tree,
+ 				      make_insn_sequence (desc, PEEPHOLE2));
+ 	
        if (GET_CODE (desc) == DEFINE_PEEPHOLE
  	  || GET_CODE (desc) == DEFINE_EXPAND)
  	next_insn_code++;
*************** from the machine description file `md'. 
*** 1815,1820 ****
--- 1939,1949 ----
      printf ("\n\n   The function split_insns returns 0 if the rtl could not\n\
     be split or the split rtl in a SEQUENCE if it can be.");
  
+   if (peephole2_tree.first)
+     printf ("\n\n   The function peephole2_insns returns 0 if the rtl could not\n\
+    be matched. If there was a match, the new rtl is returned in a SEQUENCE,\n\
+    and LAST_INSN will point to the last recognized insn in the old sequence.");
+ 
    printf ("*/\n\n");
  
    printf ("#define operands recog_operand\n\n");
*************** from the machine description file `md'. 
*** 1826,1831 ****
--- 1955,1964 ----
    next_subroutine_number = 0;
    break_out_subroutines (split_tree, SPLIT, 1);
    write_subroutine (split_tree.first, SPLIT);
+ 
+   next_subroutine_number = 0;
+   break_out_subroutines (peephole2_tree, PEEPHOLE2, 1);
+   write_subroutine (peephole2_tree.first, PEEPHOLE2);
  
    fflush (stdout);
    exit (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
Index: recog.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/recog.c,v
retrieving revision 1.35
diff -c -p -d -r1.35 recog.c
*** recog.c	1999/08/09 13:59:47	1.35
--- recog.c	1999/08/10 03:58:53
*************** Boston, MA 02111-1307, USA.  */
*** 34,39 ****
--- 34,40 ----
  #include "real.h"
  #include "toplev.h"
  #include "basic-block.h"
+ #include "resource.h"
  
  #ifndef STACK_PUSH_CODE
  #ifdef STACK_GROWS_DOWNWARD
*************** split_block_insns (b, do_split)
*** 2688,2690 ****
--- 2689,2758 ----
  	break;
      }
  }
+ 
+ /* Return the pattern for the Nth non-note insn after INSN (and set
+    NEWINSN to point to the actual 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, newinsn)
+      rtx insn;
+      int n;
+      rtx *newinsn;
+ {
+   while (insn != NULL_RTX && n > 0)
+     {
+       insn = next_nonnote_insn (insn);
+       n--;
+     }
+   if (insn == NULL_RTX)
+     return insn;
+ 
+   if (GET_CODE (insn) != INSN && GET_CODE (insn) != JUMP_INSN)
+     return NULL_RTX;
+ 
+   *newinsn = insn;
+   return PATTERN (insn);
+ }
+ 
+ #ifdef HAVE_peephole2
+ /* Perform the peephole2 optimization pass. */
+ void
+ peephole2_optimize (dump_file)
+      FILE *dump_file ATTRIBUTE_UNUSED;
+ {
+   rtx insn;
+   rtx epilogue_insn = 0;
+ 
+   for (insn = get_last_insn (); insn != NULL_RTX; insn = PREV_INSN (insn))
+     {
+       if (GET_CODE (insn) == NOTE
+ 	  && NOTE_LINE_NUMBER (insn) == NOTE_INSN_EPILOGUE_BEG)
+ 	{
+ 	  epilogue_insn = insn;
+ 	  break;
+ 	}
+     }
+ 
+   init_resource_info (epilogue_insn);
+ 
+   for (insn = get_insns (); insn != NULL;
+        insn = next_nonnote_insn (insn))
+     {
+       if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN)
+ 	{
+ 	  rtx last_insn;
+ 	  rtx before = PREV_INSN (insn);
+ 
+ 	  rtx try = peephole2_insns (PATTERN (insn), insn, &last_insn);
+ 	  if (try != NULL)
+ 	    {
+ 	      replace_insns (insn, last_insn, try, NULL_RTX);
+ 	      insn = NEXT_INSN (before);
+ 	    }
+ 	}
+     }
+ 
+   free_resource_info ();
+ }
+ #endif
Index: recog.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/recog.h,v
retrieving revision 1.18
diff -c -p -d -r1.18 recog.h
*** recog.h	1999/03/28 17:33:19	1.18
--- recog.h	1999/08/10 03:58:53
*************** extern void add_clobbers		PROTO((rtx, in
*** 114,119 ****
--- 114,122 ----
  extern void insn_extract		PROTO((rtx));
  extern void extract_insn		PROTO((rtx));
  extern void preprocess_constraints	PROTO((void));
+ extern rtx recog_next_insn		PROTO((rtx, int, rtx *));
+ extern void peephole2_optimize		PROTO((FILE *));
+ extern rtx peephole2_insns		PROTO((rtx, rtx, rtx *));
  
  /* Nonzero means volatile operands are recognized.  */
  extern int volatile_ok;
Index: rtl.def
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/rtl.def,v
retrieving revision 1.18
diff -c -p -d -r1.18 rtl.def
*** rtl.def	1999/08/09 13:59:51	1.18
--- rtl.def	1999/08/10 03:58:54
*************** DEF_RTL_EXPR(DEFINE_PEEPHOLE, "define_pe
*** 207,212 ****
--- 207,216 ----
  	(`operands' is an alias here for `recog_operand').   */
  DEF_RTL_EXPR(DEFINE_SPLIT, "define_split", "EsES", 'x')
  
+ /* Definition of an RTL peephole operation.
+    Follows the same arguments as define_split.  */
+ DEF_RTL_EXPR(DEFINE_PEEPHOLE2, "define_peephole2", "EsES", 'x')
+ 
  /* Definition of a combiner pattern.
     Operands not defined yet.  */
  DEF_RTL_EXPR(DEFINE_COMBINE, "define_combine", "Ess", 'x')
Index: toplev.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/toplev.c,v
retrieving revision 1.190
diff -c -p -d -r1.190 toplev.c
*** toplev.c	1999/08/09 13:59:55	1.190
--- toplev.c	1999/08/10 03:58:54
*************** int sched_dump = 0;
*** 295,300 ****
--- 295,301 ----
  int local_reg_dump = 0;
  int global_reg_dump = 0;
  int flow2_dump = 0;
+ int peephole2_dump = 0;
  int sched2_dump = 0;
  int jump2_opt_dump = 0;
  #ifdef DELAY_SLOTS
*************** int flag_instrument_function_entry_exit 
*** 768,773 ****
--- 769,777 ----
  
  int flag_no_ident = 0;
  
+ /* This will perform a peephole pass before sched2. */
+ int flag_peephole2 = 0;
+ 
  /* Table of supported debugging formats.  */
  static struct
  {
*************** lang_independent_options f_options[] =
*** 975,981 ****
    {"leading-underscore", &flag_leading_underscore, 1,
     "External symbols have a leading underscore" },
    {"ident", &flag_no_ident, 0,
!    "Process #ident directives"}
  };
  
  #define NUM_ELEM(a)  (sizeof (a) / sizeof ((a)[0]))
--- 979,987 ----
    {"leading-underscore", &flag_leading_underscore, 1,
     "External symbols have a leading underscore" },
    {"ident", &flag_no_ident, 0,
!    "Process #ident directives"},
!   { "peephole2", &flag_peephole2, 1,
!     "Enables an rtl peephole pass run before sched2" }
  };
  
  #define NUM_ELEM(a)  (sizeof (a) / sizeof ((a)[0]))
*************** compile_file (name)
*** 3053,3058 ****
--- 3059,3070 ----
        if (graph_dump_format != no_graph)
  	clean_graph_dump_file (dump_base_name, ".flow2");
      }
+   if (peephole2_dump)
+     {
+       clean_dump_file (".peephole2");
+       if (graph_dump_format != no_graph)
+ 	clean_graph_dump_file (dump_base_name, ".peephole2");
+     }
    if (sched2_dump)
      {
        clean_dump_file (".sched2");
*************** rest_of_compilation (decl)
*** 4273,4278 ****
--- 4285,4307 ----
  	print_rtl_graph_with_bb (dump_base_name, ".flow2", insns);
      }
  
+ #ifdef HAVE_peephole2
+   if (optimize > 0 && flag_peephole2)
+     {
+       if (peephole2_dump)
+ 	open_dump_file (".peephole2", decl_printable_name (decl, 2));
+ 
+       peephole2_optimize (rtl_dump_file);
+ 
+       if (peephole2_dump)
+ 	{
+ 	  close_dump_file (print_rtl_with_bb, insns);
+ 	  if (graph_dump_format != no_graph)
+ 	    print_rtl_graph_with_bb (dump_base_name, ".peephole2", insns);
+ 	}
+     }
+ #endif
+ 
    if (optimize > 0 && flag_schedule_insns_after_reload)
      {
        if (sched2_dump)
*************** main (argc, argv)
*** 4866,4871 ****
--- 4895,4901 ----
        flag_rerun_loop_opt = 1;
        flag_caller_saves = 1;
        flag_force_mem = 1;
+       flag_peephole2 = 1;
  #ifdef INSN_SCHEDULING
        flag_schedule_insns = 1;
        flag_schedule_insns_after_reload = 1;
*************** main (argc, argv)
*** 5040,5050 ****
  		  case 'w':
  		    flow2_dump = 1;
  		    break;
  		  case 'y':
  		    set_yydebug (1);
  		    break;
! 		  case 'x':
! 		    rtl_dump_and_exit = 1;
  		    break;
  		  case 'D':	/* these are handled by the preprocessor */
  		  case 'I':
--- 5070,5083 ----
  		  case 'w':
  		    flow2_dump = 1;
  		    break;
+ 		  case 'x':
+ 		    rtl_dump_and_exit = 1;
+ 		    break;
  		  case 'y':
  		    set_yydebug (1);
  		    break;
! 		  case 'z':
! 		    peephole2_dump = 1;
  		    break;
  		  case 'D':	/* these are handled by the preprocessor */
  		  case 'I':


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