mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			390 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			390 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			C
		
	
	
	
| /* Generate from machine description:
 | |
|    - some #define configuration flags.
 | |
|    Copyright (C) 1987-2019 Free Software Foundation, Inc.
 | |
| 
 | |
| This file is part of GCC.
 | |
| 
 | |
| GCC is free software; you can redistribute it and/or modify it under
 | |
| the terms of the GNU General Public License as published by the Free
 | |
| Software Foundation; either version 3, or (at your option) any later
 | |
| version.
 | |
| 
 | |
| GCC is distributed in the hope that it will be useful, but WITHOUT ANY
 | |
| WARRANTY; without even the implied warranty of MERCHANTABILITY or
 | |
| FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 | |
| for more details.
 | |
| 
 | |
| You should have received a copy of the GNU General Public License
 | |
| along with GCC; see the file COPYING3.  If not see
 | |
| <http://www.gnu.org/licenses/>.  */
 | |
| 
 | |
| 
 | |
| #include "bconfig.h"
 | |
| #include "system.h"
 | |
| #include "coretypes.h"
 | |
| #include "tm.h"
 | |
| #include "rtl.h"
 | |
| #include "errors.h"
 | |
| #include "gensupport.h"
 | |
| 
 | |
| 
 | |
| /* flags to determine output of machine description dependent #define's.  */
 | |
| static int max_recog_operands;  /* Largest operand number seen.  */
 | |
| static int max_dup_operands;    /* Largest number of match_dup in any insn.  */
 | |
| static int max_clobbers_per_insn;
 | |
| static int have_cc0_flag;
 | |
| static int have_cmove_flag;
 | |
| static int have_cond_exec_flag;
 | |
| static int have_lo_sum_flag;
 | |
| static int have_rotate_flag;
 | |
| static int have_rotatert_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;
 | |
| 
 | |
| /* 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;
 | |
| 
 | |
| static void walk_insn_part (rtx, int, int);
 | |
| 
 | |
| /* RECOG_P will be nonzero if this pattern was seen in a context where it will
 | |
|    be used to recognize, rather than just generate an insn.
 | |
| 
 | |
|    NON_PC_SET_SRC will be nonzero if this pattern was seen in a SET_SRC
 | |
|    of a SET whose destination is not (pc).  */
 | |
| 
 | |
| static void
 | |
| walk_insn_part (rtx part, int recog_p, int non_pc_set_src)
 | |
| {
 | |
|   int i, j;
 | |
|   RTX_CODE code;
 | |
|   const char *format_ptr;
 | |
| 
 | |
|   if (part == 0)
 | |
|     return;
 | |
| 
 | |
|   code = GET_CODE (part);
 | |
|   switch (code)
 | |
|     {
 | |
|     case CLOBBER:
 | |
|     case CLOBBER_HIGH:
 | |
|       clobbers_seen_this_insn++;
 | |
|       break;
 | |
| 
 | |
|     case MATCH_OPERAND:
 | |
|       if (XINT (part, 0) > max_recog_operands)
 | |
| 	max_recog_operands = XINT (part, 0);
 | |
|       return;
 | |
| 
 | |
|     case MATCH_OP_DUP:
 | |
|     case MATCH_PAR_DUP:
 | |
|       ++dup_operands_seen_this_insn;
 | |
|       /* FALLTHRU */
 | |
|     case MATCH_SCRATCH:
 | |
|     case MATCH_PARALLEL:
 | |
|     case MATCH_OPERATOR:
 | |
|       if (XINT (part, 0) > max_recog_operands)
 | |
| 	max_recog_operands = XINT (part, 0);
 | |
|       /* Now scan the rtl's in the vector inside the MATCH_OPERATOR or
 | |
| 	 MATCH_PARALLEL.  */
 | |
|       break;
 | |
| 
 | |
|     case LABEL_REF:
 | |
|       if (GET_CODE (XEXP (part, 0)) == MATCH_OPERAND
 | |
| 	  || GET_CODE (XEXP (part, 0)) == MATCH_DUP)
 | |
| 	break;
 | |
|       return;
 | |
| 
 | |
|     case MATCH_DUP:
 | |
|       ++dup_operands_seen_this_insn;
 | |
|       if (XINT (part, 0) > max_recog_operands)
 | |
| 	max_recog_operands = XINT (part, 0);
 | |
|       return;
 | |
| 
 | |
|     case CC0:
 | |
|       if (recog_p)
 | |
| 	have_cc0_flag = 1;
 | |
|       return;
 | |
| 
 | |
|     case LO_SUM:
 | |
|       if (recog_p)
 | |
| 	have_lo_sum_flag = 1;
 | |
|       return;
 | |
| 
 | |
|     case ROTATE:
 | |
|       if (recog_p)
 | |
| 	have_rotate_flag = 1;
 | |
|       return;
 | |
| 
 | |
|     case ROTATERT:
 | |
|       if (recog_p)
 | |
| 	have_rotatert_flag = 1;
 | |
|       return;
 | |
| 
 | |
|     case SET:
 | |
|       walk_insn_part (SET_DEST (part), 0, recog_p);
 | |
|       walk_insn_part (SET_SRC (part), recog_p,
 | |
| 		      GET_CODE (SET_DEST (part)) != PC);
 | |
|       return;
 | |
| 
 | |
|     case IF_THEN_ELSE:
 | |
|       /* Only consider this machine as having a conditional move if the
 | |
| 	 two arms of the IF_THEN_ELSE are both MATCH_OPERAND.  Otherwise,
 | |
| 	 we have some specific IF_THEN_ELSE construct (like the doz
 | |
| 	 instruction on the RS/6000) that can't be used in the general
 | |
| 	 context we want it for.  */
 | |
| 
 | |
|       if (recog_p && non_pc_set_src
 | |
| 	  && GET_CODE (XEXP (part, 1)) == MATCH_OPERAND
 | |
| 	  && GET_CODE (XEXP (part, 2)) == MATCH_OPERAND)
 | |
| 	have_cmove_flag = 1;
 | |
|       break;
 | |
| 
 | |
|     case COND_EXEC:
 | |
|       if (recog_p)
 | |
| 	have_cond_exec_flag = 1;
 | |
|       break;
 | |
| 
 | |
|     case REG: case CONST_INT: case SYMBOL_REF:
 | |
|     case PC:
 | |
|       return;
 | |
| 
 | |
|     default:
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|   format_ptr = GET_RTX_FORMAT (GET_CODE (part));
 | |
| 
 | |
|   for (i = 0; i < GET_RTX_LENGTH (GET_CODE (part)); i++)
 | |
|     switch (*format_ptr++)
 | |
|       {
 | |
|       case 'e':
 | |
|       case 'u':
 | |
| 	walk_insn_part (XEXP (part, i), recog_p, non_pc_set_src);
 | |
| 	break;
 | |
|       case 'E':
 | |
| 	if (XVEC (part, i) != NULL)
 | |
| 	  for (j = 0; j < XVECLEN (part, i); j++)
 | |
| 	    walk_insn_part (XVECEXP (part, i, j), recog_p, non_pc_set_src);
 | |
| 	break;
 | |
|       }
 | |
| }
 | |
| 
 | |
| static void
 | |
| gen_insn (md_rtx_info *info)
 | |
| {
 | |
|   int i;
 | |
| 
 | |
|   /* Walk the insn pattern to gather the #define's status.  */
 | |
|   rtx insn = info->def;
 | |
|   clobbers_seen_this_insn = 0;
 | |
|   dup_operands_seen_this_insn = 0;
 | |
|   if (XVEC (insn, 1) != 0)
 | |
|     for (i = 0; i < XVECLEN (insn, 1); i++)
 | |
|       walk_insn_part (XVECEXP (insn, 1, i), 1, 0);
 | |
| 
 | |
|   if (clobbers_seen_this_insn > max_clobbers_per_insn)
 | |
|     max_clobbers_per_insn = clobbers_seen_this_insn;
 | |
|   if (dup_operands_seen_this_insn > max_dup_operands)
 | |
|     max_dup_operands = dup_operands_seen_this_insn;
 | |
| }
 | |
| 
 | |
| /* Similar but scan a define_expand.  */
 | |
| 
 | |
| static void
 | |
| gen_expand (md_rtx_info *info)
 | |
| {
 | |
|   int i;
 | |
| 
 | |
|   /* Walk the insn pattern to gather the #define's status.  */
 | |
| 
 | |
|   /* Note that we don't bother recording the number of MATCH_DUPs
 | |
|      that occur in a gen_expand, because only reload cares about that.  */
 | |
|   rtx insn = info->def;
 | |
|   if (XVEC (insn, 1) != 0)
 | |
|     for (i = 0; i < XVECLEN (insn, 1); i++)
 | |
|       {
 | |
| 	/* Compute the maximum SETs and CLOBBERS
 | |
| 	   in any one of the sub-insns;
 | |
| 	   don't sum across all of them.  */
 | |
| 	clobbers_seen_this_insn = 0;
 | |
| 
 | |
| 	walk_insn_part (XVECEXP (insn, 1, i), 0, 0);
 | |
| 
 | |
| 	if (clobbers_seen_this_insn > max_clobbers_per_insn)
 | |
| 	  max_clobbers_per_insn = clobbers_seen_this_insn;
 | |
|       }
 | |
| }
 | |
| 
 | |
| /* Similar but scan a define_split.  */
 | |
| 
 | |
| static void
 | |
| gen_split (md_rtx_info *info)
 | |
| {
 | |
|   int i;
 | |
| 
 | |
|   /* Look through the patterns that are matched
 | |
|      to compute the maximum operand number.  */
 | |
|   rtx split = info->def;
 | |
|   for (i = 0; i < XVECLEN (split, 0); i++)
 | |
|     walk_insn_part (XVECEXP (split, 0, i), 1, 0);
 | |
|   /* Look at the number of insns this insn could split into.  */
 | |
|   if (XVECLEN (split, 2) > max_insns_per_split)
 | |
|     max_insns_per_split = XVECLEN (split, 2);
 | |
| }
 | |
| 
 | |
| static void
 | |
| gen_peephole (md_rtx_info *info)
 | |
| {
 | |
|   int i;
 | |
| 
 | |
|   /* Look through the patterns that are matched
 | |
|      to compute the maximum operand number.  */
 | |
|   rtx peep = info->def;
 | |
|   for (i = 0; i < XVECLEN (peep, 0); i++)
 | |
|     walk_insn_part (XVECEXP (peep, 0, i), 1, 0);
 | |
| }
 | |
| 
 | |
| static void
 | |
| gen_peephole2 (md_rtx_info *info)
 | |
| {
 | |
|   int i, n;
 | |
| 
 | |
|   /* Look through the patterns that are matched
 | |
|      to compute the maximum operand number.  */
 | |
|   rtx peep = info->def;
 | |
|   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;
 | |
| }
 | |
| 
 | |
| int
 | |
| main (int argc, const char **argv)
 | |
| {
 | |
|   progname = "genconfig";
 | |
| 
 | |
|   if (!init_rtx_reader_args (argc, argv))
 | |
|     return (FATAL_EXIT_CODE);
 | |
| 
 | |
|   puts ("/* Generated automatically by the program `genconfig'");
 | |
|   puts ("   from the machine description file `md'.  */\n");
 | |
|   puts ("#ifndef GCC_INSN_CONFIG_H");
 | |
|   puts ("#define GCC_INSN_CONFIG_H\n");
 | |
| 
 | |
|   /* Allow at least 30 operands for the sake of asm constructs.  */
 | |
|   /* ??? We *really* ought to reorganize things such that there
 | |
|      is no fixed upper bound.  */
 | |
|   max_recog_operands = 29;  /* We will add 1 later.  */
 | |
|   max_dup_operands = 1;
 | |
| 
 | |
|   /* Read the machine description.  */
 | |
| 
 | |
|   md_rtx_info info;
 | |
|   while (read_md_rtx (&info))
 | |
|     switch (GET_CODE (info.def))
 | |
|       {
 | |
|       case DEFINE_INSN:
 | |
| 	gen_insn (&info);
 | |
| 	break;
 | |
| 
 | |
|       case DEFINE_EXPAND:
 | |
| 	gen_expand (&info);
 | |
| 	break;
 | |
| 
 | |
|       case DEFINE_SPLIT:
 | |
| 	gen_split (&info);
 | |
| 	break;
 | |
| 
 | |
|       case DEFINE_PEEPHOLE2:
 | |
| 	have_peephole2_flag = 1;
 | |
| 	gen_peephole2 (&info);
 | |
| 	break;
 | |
| 
 | |
|       case DEFINE_PEEPHOLE:
 | |
| 	have_peephole_flag = 1;
 | |
| 	gen_peephole (&info);
 | |
| 	break;
 | |
| 
 | |
|       default:
 | |
| 	break;
 | |
|       }
 | |
| 
 | |
|   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).  */
 | |
|   printf ("#ifndef MAX_INSNS_PER_SPLIT\n");
 | |
|   printf ("#define MAX_INSNS_PER_SPLIT %d\n", max_insns_per_split);
 | |
|   printf ("#endif\n");
 | |
| 
 | |
|   if (have_cc0_flag)
 | |
|     {
 | |
|       printf ("#define HAVE_cc0 1\n");
 | |
|       printf ("#define CC0_P(X) ((X) == cc0_rtx)\n");
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       /* We output CC0_P this way to make sure that X is declared
 | |
| 	 somewhere.  */
 | |
|       printf ("#define HAVE_cc0 0\n");
 | |
|       printf ("#define CC0_P(X) ((X) ? 0 : 0)\n");
 | |
|     }
 | |
| 
 | |
|   if (have_cmove_flag)
 | |
|     printf ("#define HAVE_conditional_move 1\n");
 | |
|   else
 | |
|     printf ("#define HAVE_conditional_move 0\n");
 | |
| 
 | |
|   if (have_cond_exec_flag)
 | |
|     printf ("#define HAVE_conditional_execution 1\n");
 | |
|   else
 | |
|     printf ("#define HAVE_conditional_execution 0\n");
 | |
| 
 | |
|   if (have_lo_sum_flag)
 | |
|     printf ("#define HAVE_lo_sum 1\n");
 | |
|   else
 | |
|     printf ("#define HAVE_lo_sum 0\n");
 | |
| 
 | |
|   if (have_rotate_flag)
 | |
|     printf ("#define HAVE_rotate 1\n");
 | |
| 
 | |
|   if (have_rotatert_flag)
 | |
|     printf ("#define HAVE_rotatert 1\n");
 | |
| 
 | |
|   if (have_peephole_flag)
 | |
|     printf ("#define HAVE_peephole 1\n");
 | |
|   else
 | |
|     printf ("#define HAVE_peephole 0\n");
 | |
| 
 | |
|   if (have_peephole2_flag)
 | |
|     {
 | |
|       printf ("#define HAVE_peephole2 1\n");
 | |
|       printf ("#define MAX_INSNS_PER_PEEP2 %d\n", max_insns_per_peep2);
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       printf ("#define HAVE_peephole2 0\n");
 | |
|       printf ("#define MAX_INSNS_PER_PEEP2 0\n");
 | |
|     }
 | |
| 
 | |
|   puts ("\n#endif /* GCC_INSN_CONFIG_H */");
 | |
| 
 | |
|   if (ferror (stdout) || fflush (stdout) || fclose (stdout))
 | |
|     return FATAL_EXIT_CODE;
 | |
| 
 | |
|   return SUCCESS_EXIT_CODE;
 | |
| }
 |