gensupport.c revision 117395
190075Sobrien/* Support routines for the various generation passes.
2117395Skan   Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
390075Sobrien
490075Sobrien   This file is part of GCC.
590075Sobrien
690075Sobrien   GCC is free software; you can redistribute it and/or modify it
790075Sobrien   under the terms of the GNU General Public License as published by
890075Sobrien   the Free Software Foundation; either version 2, or (at your option)
990075Sobrien   any later version.
1090075Sobrien
1190075Sobrien   GCC is distributed in the hope that it will be useful, but WITHOUT
1290075Sobrien   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
1390075Sobrien   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
1490075Sobrien   License for more details.
1590075Sobrien
1690075Sobrien   You should have received a copy of the GNU General Public License
1790075Sobrien   along with GCC; see the file COPYING.  If not, write to the Free
1890075Sobrien   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
1990075Sobrien   02111-1307, USA.  */
2090075Sobrien
2190075Sobrien#include "hconfig.h"
2290075Sobrien#include "system.h"
2390075Sobrien#include "rtl.h"
2490075Sobrien#include "obstack.h"
2590075Sobrien#include "errors.h"
26117395Skan#include "hashtab.h"
2790075Sobrien#include "gensupport.h"
2890075Sobrien
2990075Sobrien
3090075Sobrien/* In case some macros used by files we include need it, define this here.  */
3190075Sobrienint target_flags;
3290075Sobrien
33117395Skanint insn_elision = 1;
34117395Skan
3590075Sobrienstatic struct obstack obstack;
3690075Sobrienstruct obstack *rtl_obstack = &obstack;
3790075Sobrien
3890075Sobrienstatic int sequence_num;
3990075Sobrienstatic int errors;
4090075Sobrien
4190075Sobrienstatic int predicable_default;
4290075Sobrienstatic const char *predicable_true;
4390075Sobrienstatic const char *predicable_false;
4490075Sobrien
45117395Skanstatic htab_t condition_table;
46117395Skan
4790075Sobrienstatic char *base_dir = NULL;
4890075Sobrien
4990075Sobrien/* We initially queue all patterns, process the define_insn and
5090075Sobrien   define_cond_exec patterns, then return them one at a time.  */
5190075Sobrien
5290075Sobrienstruct queue_elem
5390075Sobrien{
5490075Sobrien  rtx data;
55117395Skan  const char *filename;
5690075Sobrien  int lineno;
5790075Sobrien  struct queue_elem *next;
5890075Sobrien};
5990075Sobrien
6090075Sobrienstatic struct queue_elem *define_attr_queue;
6190075Sobrienstatic struct queue_elem **define_attr_tail = &define_attr_queue;
6290075Sobrienstatic struct queue_elem *define_insn_queue;
6390075Sobrienstatic struct queue_elem **define_insn_tail = &define_insn_queue;
6490075Sobrienstatic struct queue_elem *define_cond_exec_queue;
6590075Sobrienstatic struct queue_elem **define_cond_exec_tail = &define_cond_exec_queue;
6690075Sobrienstatic struct queue_elem *other_queue;
6790075Sobrienstatic struct queue_elem **other_tail = &other_queue;
6890075Sobrien
69117395Skanstatic void queue_pattern PARAMS ((rtx, struct queue_elem ***,
70117395Skan				   const char *, int));
7190075Sobrien
7290075Sobrien/* Current maximum length of directory names in the search path
7390075Sobrien   for include files.  (Altered as we get more of them.)  */
7490075Sobrien
7590075Sobriensize_t max_include_len;
7690075Sobrien
7790075Sobrienstruct file_name_list
7890075Sobrien  {
7990075Sobrien    struct file_name_list *next;
8090075Sobrien    const char *fname;
8190075Sobrien  };
8290075Sobrien
83117395Skanstruct file_name_list *first_dir_md_include = 0;  /* First dir to search */
8490075Sobrien        /* First dir to search for <file> */
8590075Sobrienstruct file_name_list *first_bracket_include = 0;
86117395Skanstruct file_name_list *last_dir_md_include = 0;        /* Last in chain */
8790075Sobrien
8890075Sobrienstatic void remove_constraints PARAMS ((rtx));
8990075Sobrienstatic void process_rtx PARAMS ((rtx, int));
9090075Sobrien
9190075Sobrienstatic int is_predicable PARAMS ((struct queue_elem *));
9290075Sobrienstatic void identify_predicable_attribute PARAMS ((void));
9390075Sobrienstatic int n_alternatives PARAMS ((const char *));
9490075Sobrienstatic void collect_insn_data PARAMS ((rtx, int *, int *));
9590075Sobrienstatic rtx alter_predicate_for_insn PARAMS ((rtx, int, int, int));
9690075Sobrienstatic const char *alter_test_for_insn PARAMS ((struct queue_elem *,
9790075Sobrien						struct queue_elem *));
9890075Sobrienstatic char *shift_output_template PARAMS ((char *, const char *, int));
9990075Sobrienstatic const char *alter_output_for_insn PARAMS ((struct queue_elem *,
10090075Sobrien						  struct queue_elem *,
10190075Sobrien						  int, int));
10290075Sobrienstatic void process_one_cond_exec PARAMS ((struct queue_elem *));
10390075Sobrienstatic void process_define_cond_exec PARAMS ((void));
104117395Skanstatic void process_include PARAMS ((rtx, int));
10590075Sobrienstatic char *save_string PARAMS ((const char *, int));
10690075Sobrien
10790075Sobrienvoid
10890075Sobrienmessage_with_line VPARAMS ((int lineno, const char *msg, ...))
10990075Sobrien{
11090075Sobrien  VA_OPEN (ap, msg);
11190075Sobrien  VA_FIXEDARG (ap, int, lineno);
11290075Sobrien  VA_FIXEDARG (ap, const char *, msg);
11390075Sobrien
11490075Sobrien  fprintf (stderr, "%s:%d: ", read_rtx_filename, lineno);
11590075Sobrien  vfprintf (stderr, msg, ap);
11690075Sobrien  fputc ('\n', stderr);
11790075Sobrien
11890075Sobrien  VA_CLOSE (ap);
11990075Sobrien}
12090075Sobrien
12190075Sobrien/* Make a version of gen_rtx_CONST_INT so that GEN_INT can be used in
12290075Sobrien   the gensupport programs.  */
12390075Sobrien
12490075Sobrienrtx
12590075Sobriengen_rtx_CONST_INT (mode, arg)
12690075Sobrien     enum machine_mode mode ATTRIBUTE_UNUSED;
12790075Sobrien     HOST_WIDE_INT arg;
12890075Sobrien{
12990075Sobrien  rtx rt = rtx_alloc (CONST_INT);
13090075Sobrien
13190075Sobrien  XWINT (rt, 0) = arg;
13290075Sobrien  return rt;
13390075Sobrien}
13490075Sobrien
13590075Sobrien/* Queue PATTERN on LIST_TAIL.  */
13690075Sobrien
13790075Sobrienstatic void
138117395Skanqueue_pattern (pattern, list_tail, filename, lineno)
13990075Sobrien     rtx pattern;
14090075Sobrien     struct queue_elem ***list_tail;
141117395Skan     const char *filename;
14290075Sobrien     int lineno;
14390075Sobrien{
14490075Sobrien  struct queue_elem *e = (struct queue_elem *) xmalloc (sizeof (*e));
14590075Sobrien  e->data = pattern;
146117395Skan  e->filename = filename;
14790075Sobrien  e->lineno = lineno;
14890075Sobrien  e->next = NULL;
14990075Sobrien  **list_tail = e;
15090075Sobrien  *list_tail = &e->next;
15190075Sobrien}
15290075Sobrien
15390075Sobrien/* Recursively remove constraints from an rtx.  */
15490075Sobrien
15590075Sobrienstatic void
15690075Sobrienremove_constraints (part)
15790075Sobrien     rtx part;
15890075Sobrien{
15990075Sobrien  int i, j;
16090075Sobrien  const char *format_ptr;
16190075Sobrien
16290075Sobrien  if (part == 0)
16390075Sobrien    return;
16490075Sobrien
16590075Sobrien  if (GET_CODE (part) == MATCH_OPERAND)
16690075Sobrien    XSTR (part, 2) = "";
16790075Sobrien  else if (GET_CODE (part) == MATCH_SCRATCH)
16890075Sobrien    XSTR (part, 1) = "";
16990075Sobrien
17090075Sobrien  format_ptr = GET_RTX_FORMAT (GET_CODE (part));
17190075Sobrien
17290075Sobrien  for (i = 0; i < GET_RTX_LENGTH (GET_CODE (part)); i++)
17390075Sobrien    switch (*format_ptr++)
17490075Sobrien      {
17590075Sobrien      case 'e':
17690075Sobrien      case 'u':
17790075Sobrien	remove_constraints (XEXP (part, i));
17890075Sobrien	break;
17990075Sobrien      case 'E':
18090075Sobrien	if (XVEC (part, i) != NULL)
18190075Sobrien	  for (j = 0; j < XVECLEN (part, i); j++)
18290075Sobrien	    remove_constraints (XVECEXP (part, i, j));
18390075Sobrien	break;
18490075Sobrien      }
18590075Sobrien}
18690075Sobrien
187117395Skan/* Process an include file assuming that it lives in gcc/config/{target}/
188117395Skan   if the include looks like (include "file").  */
18990075Sobrien
190117395Skanstatic void
19190075Sobrienprocess_include (desc, lineno)
19290075Sobrien     rtx desc;
19390075Sobrien     int lineno;
19490075Sobrien{
19590075Sobrien  const char *filename = XSTR (desc, 0);
196117395Skan  const char *old_filename;
197117395Skan  int old_lineno;
198117395Skan  char *pathname;
19990075Sobrien  FILE *input_file;
20090075Sobrien
201117395Skan  /* If specified file name is absolute, skip the include stack.  */
202117395Skan  if (! IS_ABSOLUTE_PATHNAME (filename))
20390075Sobrien    {
204117395Skan      struct file_name_list *stackp;
20590075Sobrien
206117395Skan      /* Search directory path, trying to open the file.  */
207117395Skan      for (stackp = first_dir_md_include; stackp; stackp = stackp->next)
20890075Sobrien	{
209117395Skan	  static const char sep[2] = { DIR_SEPARATOR, '\0' };
210117395Skan
211117395Skan	  pathname = concat (stackp->fname, sep, filename, NULL);
212117395Skan	  input_file = fopen (pathname, "r");
213117395Skan	  if (input_file != NULL)
214117395Skan	    goto success;
215117395Skan	  free (pathname);
21690075Sobrien	}
21790075Sobrien    }
218117395Skan
219117395Skan  if (base_dir)
220117395Skan    pathname = concat (base_dir, filename, NULL);
221117395Skan  else
222117395Skan    pathname = xstrdup (filename);
223117395Skan  input_file = fopen (pathname, "r");
224117395Skan  if (input_file == NULL)
22590075Sobrien    {
226117395Skan      free (pathname);
227117395Skan      message_with_line (lineno, "include file `%s' not found", filename);
228117395Skan      errors = 1;
229117395Skan      return;
230117395Skan    }
231117395Skan success:
23290075Sobrien
233117395Skan  /* Save old cursor; setup new for the new file.  Note that "lineno" the
234117395Skan     argument to this function is the beginning of the include statement,
235117395Skan     while read_rtx_lineno has already been advanced.  */
236117395Skan  old_filename = read_rtx_filename;
237117395Skan  old_lineno = read_rtx_lineno;
238117395Skan  read_rtx_filename = pathname;
239117395Skan  read_rtx_lineno = 1;
24090075Sobrien
241117395Skan  /* Read the entire file.  */
242117395Skan  while (1)
243117395Skan    {
244117395Skan      rtx desc;
245117395Skan      int c;
24690075Sobrien
247117395Skan      c = read_skip_spaces (input_file);
248117395Skan      if (c == EOF)
249117395Skan	break;
25090075Sobrien
251117395Skan      ungetc (c, input_file);
252117395Skan      lineno = read_rtx_lineno;
253117395Skan      desc = read_rtx (input_file);
254117395Skan      process_rtx (desc, lineno);
255117395Skan    }
25690075Sobrien
257117395Skan  /* Do not free pathname.  It is attached to the various rtx queue
258117395Skan     elements.  */
25990075Sobrien
260117395Skan  read_rtx_filename = old_filename;
261117395Skan  read_rtx_lineno = old_lineno;
26290075Sobrien
263117395Skan  fclose (input_file);
26490075Sobrien}
26590075Sobrien
26690075Sobrien/* Process a top level rtx in some way, queueing as appropriate.  */
26790075Sobrien
26890075Sobrienstatic void
26990075Sobrienprocess_rtx (desc, lineno)
27090075Sobrien     rtx desc;
27190075Sobrien     int lineno;
27290075Sobrien{
27390075Sobrien  switch (GET_CODE (desc))
27490075Sobrien    {
27590075Sobrien    case DEFINE_INSN:
276117395Skan      queue_pattern (desc, &define_insn_tail, read_rtx_filename, lineno);
27790075Sobrien      break;
27890075Sobrien
27990075Sobrien    case DEFINE_COND_EXEC:
280117395Skan      queue_pattern (desc, &define_cond_exec_tail, read_rtx_filename, lineno);
28190075Sobrien      break;
28290075Sobrien
28390075Sobrien    case DEFINE_ATTR:
284117395Skan      queue_pattern (desc, &define_attr_tail, read_rtx_filename, lineno);
28590075Sobrien      break;
28690075Sobrien
28790075Sobrien    case INCLUDE:
288117395Skan      process_include (desc, lineno);
28990075Sobrien      break;
29090075Sobrien
29190075Sobrien    case DEFINE_INSN_AND_SPLIT:
29290075Sobrien      {
29390075Sobrien	const char *split_cond;
29490075Sobrien	rtx split;
29590075Sobrien	rtvec attr;
29690075Sobrien	int i;
29790075Sobrien
29890075Sobrien	/* Create a split with values from the insn_and_split.  */
29990075Sobrien	split = rtx_alloc (DEFINE_SPLIT);
30090075Sobrien
30190075Sobrien	i = XVECLEN (desc, 1);
30290075Sobrien	XVEC (split, 0) = rtvec_alloc (i);
30390075Sobrien	while (--i >= 0)
30490075Sobrien	  {
30590075Sobrien	    XVECEXP (split, 0, i) = copy_rtx (XVECEXP (desc, 1, i));
30690075Sobrien	    remove_constraints (XVECEXP (split, 0, i));
30790075Sobrien	  }
30890075Sobrien
30990075Sobrien	/* If the split condition starts with "&&", append it to the
31090075Sobrien	   insn condition to create the new split condition.  */
31190075Sobrien	split_cond = XSTR (desc, 4);
31290075Sobrien	if (split_cond[0] == '&' && split_cond[1] == '&')
313117395Skan	  split_cond = concat (XSTR (desc, 2), split_cond, NULL);
31490075Sobrien	XSTR (split, 1) = split_cond;
31590075Sobrien	XVEC (split, 2) = XVEC (desc, 5);
31690075Sobrien	XSTR (split, 3) = XSTR (desc, 6);
31790075Sobrien
31890075Sobrien	/* Fix up the DEFINE_INSN.  */
31990075Sobrien	attr = XVEC (desc, 7);
32090075Sobrien	PUT_CODE (desc, DEFINE_INSN);
32190075Sobrien	XVEC (desc, 4) = attr;
32290075Sobrien
32390075Sobrien	/* Queue them.  */
324117395Skan	queue_pattern (desc, &define_insn_tail, read_rtx_filename, lineno);
325117395Skan	queue_pattern (split, &other_tail, read_rtx_filename, lineno);
32690075Sobrien	break;
32790075Sobrien      }
32890075Sobrien
32990075Sobrien    default:
330117395Skan      queue_pattern (desc, &other_tail, read_rtx_filename, lineno);
33190075Sobrien      break;
33290075Sobrien    }
33390075Sobrien}
33490075Sobrien
33590075Sobrien/* Return true if attribute PREDICABLE is true for ELEM, which holds
33690075Sobrien   a DEFINE_INSN.  */
33790075Sobrien
33890075Sobrienstatic int
33990075Sobrienis_predicable (elem)
34090075Sobrien     struct queue_elem *elem;
34190075Sobrien{
34290075Sobrien  rtvec vec = XVEC (elem->data, 4);
34390075Sobrien  const char *value;
34490075Sobrien  int i;
34590075Sobrien
34690075Sobrien  if (! vec)
34790075Sobrien    return predicable_default;
34890075Sobrien
34990075Sobrien  for (i = GET_NUM_ELEM (vec) - 1; i >= 0; --i)
35090075Sobrien    {
35190075Sobrien      rtx sub = RTVEC_ELT (vec, i);
35290075Sobrien      switch (GET_CODE (sub))
35390075Sobrien	{
35490075Sobrien	case SET_ATTR:
35590075Sobrien	  if (strcmp (XSTR (sub, 0), "predicable") == 0)
35690075Sobrien	    {
35790075Sobrien	      value = XSTR (sub, 1);
35890075Sobrien	      goto found;
35990075Sobrien	    }
36090075Sobrien	  break;
36190075Sobrien
36290075Sobrien	case SET_ATTR_ALTERNATIVE:
36390075Sobrien	  if (strcmp (XSTR (sub, 0), "predicable") == 0)
36490075Sobrien	    {
36590075Sobrien	      message_with_line (elem->lineno,
36690075Sobrien				 "multiple alternatives for `predicable'");
36790075Sobrien	      errors = 1;
36890075Sobrien	      return 0;
36990075Sobrien	    }
37090075Sobrien	  break;
37190075Sobrien
37290075Sobrien	case SET:
37390075Sobrien	  if (GET_CODE (SET_DEST (sub)) != ATTR
37490075Sobrien	      || strcmp (XSTR (SET_DEST (sub), 0), "predicable") != 0)
37590075Sobrien	    break;
37690075Sobrien	  sub = SET_SRC (sub);
37790075Sobrien	  if (GET_CODE (sub) == CONST_STRING)
37890075Sobrien	    {
37990075Sobrien	      value = XSTR (sub, 0);
38090075Sobrien	      goto found;
38190075Sobrien	    }
38290075Sobrien
38390075Sobrien	  /* ??? It would be possible to handle this if we really tried.
38490075Sobrien	     It's not easy though, and I'm not going to bother until it
38590075Sobrien	     really proves necessary.  */
38690075Sobrien	  message_with_line (elem->lineno,
38790075Sobrien			     "non-constant value for `predicable'");
38890075Sobrien	  errors = 1;
38990075Sobrien	  return 0;
39090075Sobrien
39190075Sobrien	default:
39290075Sobrien	  abort ();
39390075Sobrien	}
39490075Sobrien    }
39590075Sobrien
39690075Sobrien  return predicable_default;
39790075Sobrien
39890075Sobrien found:
39990075Sobrien  /* Verify that predicability does not vary on the alternative.  */
40090075Sobrien  /* ??? It should be possible to handle this by simply eliminating
40190075Sobrien     the non-predicable alternatives from the insn.  FRV would like
40290075Sobrien     to do this.  Delay this until we've got the basics solid.  */
40390075Sobrien  if (strchr (value, ',') != NULL)
40490075Sobrien    {
40590075Sobrien      message_with_line (elem->lineno,
40690075Sobrien			 "multiple alternatives for `predicable'");
40790075Sobrien      errors = 1;
40890075Sobrien      return 0;
40990075Sobrien    }
41090075Sobrien
41190075Sobrien  /* Find out which value we're looking at.  */
41290075Sobrien  if (strcmp (value, predicable_true) == 0)
41390075Sobrien    return 1;
41490075Sobrien  if (strcmp (value, predicable_false) == 0)
41590075Sobrien    return 0;
41690075Sobrien
41790075Sobrien  message_with_line (elem->lineno,
41890075Sobrien		     "unknown value `%s' for `predicable' attribute",
41990075Sobrien		     value);
42090075Sobrien  errors = 1;
42190075Sobrien  return 0;
42290075Sobrien}
42390075Sobrien
42490075Sobrien/* Examine the attribute "predicable"; discover its boolean values
42590075Sobrien   and its default.  */
42690075Sobrien
42790075Sobrienstatic void
42890075Sobrienidentify_predicable_attribute ()
42990075Sobrien{
43090075Sobrien  struct queue_elem *elem;
43190075Sobrien  char *p_true, *p_false;
43290075Sobrien  const char *value;
43390075Sobrien
43490075Sobrien  /* Look for the DEFINE_ATTR for `predicable', which must exist.  */
43590075Sobrien  for (elem = define_attr_queue; elem ; elem = elem->next)
43690075Sobrien    if (strcmp (XSTR (elem->data, 0), "predicable") == 0)
43790075Sobrien      goto found;
43890075Sobrien
43990075Sobrien  message_with_line (define_cond_exec_queue->lineno,
44090075Sobrien		     "attribute `predicable' not defined");
44190075Sobrien  errors = 1;
44290075Sobrien  return;
44390075Sobrien
44490075Sobrien found:
44590075Sobrien  value = XSTR (elem->data, 1);
446117395Skan  p_false = xstrdup (value);
44790075Sobrien  p_true = strchr (p_false, ',');
44890075Sobrien  if (p_true == NULL || strchr (++p_true, ',') != NULL)
44990075Sobrien    {
45090075Sobrien      message_with_line (elem->lineno,
45190075Sobrien			 "attribute `predicable' is not a boolean");
45290075Sobrien      errors = 1;
45390075Sobrien      return;
45490075Sobrien    }
45590075Sobrien  p_true[-1] = '\0';
45690075Sobrien
45790075Sobrien  predicable_true = p_true;
45890075Sobrien  predicable_false = p_false;
45990075Sobrien
46090075Sobrien  switch (GET_CODE (XEXP (elem->data, 2)))
46190075Sobrien    {
46290075Sobrien    case CONST_STRING:
46390075Sobrien      value = XSTR (XEXP (elem->data, 2), 0);
46490075Sobrien      break;
46590075Sobrien
46690075Sobrien    case CONST:
46790075Sobrien      message_with_line (elem->lineno,
46890075Sobrien			 "attribute `predicable' cannot be const");
46990075Sobrien      errors = 1;
47090075Sobrien      return;
47190075Sobrien
47290075Sobrien    default:
47390075Sobrien      message_with_line (elem->lineno,
47490075Sobrien			 "attribute `predicable' must have a constant default");
47590075Sobrien      errors = 1;
47690075Sobrien      return;
47790075Sobrien    }
47890075Sobrien
47990075Sobrien  if (strcmp (value, p_true) == 0)
48090075Sobrien    predicable_default = 1;
48190075Sobrien  else if (strcmp (value, p_false) == 0)
48290075Sobrien    predicable_default = 0;
48390075Sobrien  else
48490075Sobrien    {
48590075Sobrien      message_with_line (elem->lineno,
48690075Sobrien			 "unknown value `%s' for `predicable' attribute",
48790075Sobrien			 value);
48890075Sobrien      errors = 1;
48990075Sobrien    }
49090075Sobrien}
49190075Sobrien
49290075Sobrien/* Return the number of alternatives in constraint S.  */
49390075Sobrien
49490075Sobrienstatic int
49590075Sobrienn_alternatives (s)
49690075Sobrien     const char *s;
49790075Sobrien{
49890075Sobrien  int n = 1;
49990075Sobrien
50090075Sobrien  if (s)
50190075Sobrien    while (*s)
50290075Sobrien      n += (*s++ == ',');
50390075Sobrien
50490075Sobrien  return n;
50590075Sobrien}
50690075Sobrien
50790075Sobrien/* Determine how many alternatives there are in INSN, and how many
50890075Sobrien   operands.  */
50990075Sobrien
51090075Sobrienstatic void
51190075Sobriencollect_insn_data (pattern, palt, pmax)
51290075Sobrien     rtx pattern;
51390075Sobrien     int *palt, *pmax;
51490075Sobrien{
51590075Sobrien  const char *fmt;
51690075Sobrien  enum rtx_code code;
51790075Sobrien  int i, j, len;
51890075Sobrien
51990075Sobrien  code = GET_CODE (pattern);
52090075Sobrien  switch (code)
52190075Sobrien    {
52290075Sobrien    case MATCH_OPERAND:
52390075Sobrien      i = n_alternatives (XSTR (pattern, 2));
52490075Sobrien      *palt = (i > *palt ? i : *palt);
52590075Sobrien      /* FALLTHRU */
52690075Sobrien
52790075Sobrien    case MATCH_OPERATOR:
52890075Sobrien    case MATCH_SCRATCH:
52990075Sobrien    case MATCH_PARALLEL:
53090075Sobrien    case MATCH_INSN:
53190075Sobrien      i = XINT (pattern, 0);
53290075Sobrien      if (i > *pmax)
53390075Sobrien	*pmax = i;
53490075Sobrien      break;
53590075Sobrien
53690075Sobrien    default:
53790075Sobrien      break;
53890075Sobrien    }
53990075Sobrien
54090075Sobrien  fmt = GET_RTX_FORMAT (code);
54190075Sobrien  len = GET_RTX_LENGTH (code);
54290075Sobrien  for (i = 0; i < len; i++)
54390075Sobrien    {
54490075Sobrien      switch (fmt[i])
54590075Sobrien	{
54690075Sobrien	case 'e': case 'u':
54790075Sobrien	  collect_insn_data (XEXP (pattern, i), palt, pmax);
54890075Sobrien	  break;
54990075Sobrien
55090075Sobrien	case 'V':
55190075Sobrien	  if (XVEC (pattern, i) == NULL)
55290075Sobrien	    break;
55390075Sobrien	  /* FALLTHRU */
55490075Sobrien	case 'E':
55590075Sobrien	  for (j = XVECLEN (pattern, i) - 1; j >= 0; --j)
55690075Sobrien	    collect_insn_data (XVECEXP (pattern, i, j), palt, pmax);
55790075Sobrien	  break;
55890075Sobrien
55990075Sobrien	case 'i': case 'w': case '0': case 's': case 'S': case 'T':
56090075Sobrien	  break;
56190075Sobrien
56290075Sobrien	default:
56390075Sobrien	  abort ();
56490075Sobrien	}
56590075Sobrien    }
56690075Sobrien}
56790075Sobrien
56890075Sobrienstatic rtx
56990075Sobrienalter_predicate_for_insn (pattern, alt, max_op, lineno)
57090075Sobrien     rtx pattern;
57190075Sobrien     int alt, max_op, lineno;
57290075Sobrien{
57390075Sobrien  const char *fmt;
57490075Sobrien  enum rtx_code code;
57590075Sobrien  int i, j, len;
57690075Sobrien
57790075Sobrien  code = GET_CODE (pattern);
57890075Sobrien  switch (code)
57990075Sobrien    {
58090075Sobrien    case MATCH_OPERAND:
58190075Sobrien      {
58290075Sobrien	const char *c = XSTR (pattern, 2);
58390075Sobrien
58490075Sobrien	if (n_alternatives (c) != 1)
58590075Sobrien	  {
58690075Sobrien	    message_with_line (lineno,
58790075Sobrien			       "too many alternatives for operand %d",
58890075Sobrien			       XINT (pattern, 0));
58990075Sobrien	    errors = 1;
59090075Sobrien	    return NULL;
59190075Sobrien	  }
59290075Sobrien
59390075Sobrien	/* Replicate C as needed to fill out ALT alternatives.  */
59490075Sobrien	if (c && *c && alt > 1)
59590075Sobrien	  {
59690075Sobrien	    size_t c_len = strlen (c);
59790075Sobrien	    size_t len = alt * (c_len + 1);
59890075Sobrien	    char *new_c = (char *) xmalloc (len);
59990075Sobrien
60090075Sobrien	    memcpy (new_c, c, c_len);
60190075Sobrien	    for (i = 1; i < alt; ++i)
60290075Sobrien	      {
60390075Sobrien		new_c[i * (c_len + 1) - 1] = ',';
60490075Sobrien		memcpy (&new_c[i * (c_len + 1)], c, c_len);
60590075Sobrien	      }
60690075Sobrien	    new_c[len - 1] = '\0';
60790075Sobrien	    XSTR (pattern, 2) = new_c;
60890075Sobrien	  }
60990075Sobrien      }
61090075Sobrien      /* FALLTHRU */
61190075Sobrien
61290075Sobrien    case MATCH_OPERATOR:
61390075Sobrien    case MATCH_SCRATCH:
61490075Sobrien    case MATCH_PARALLEL:
61590075Sobrien    case MATCH_INSN:
61690075Sobrien      XINT (pattern, 0) += max_op;
61790075Sobrien      break;
61890075Sobrien
61990075Sobrien    default:
62090075Sobrien      break;
62190075Sobrien    }
62290075Sobrien
62390075Sobrien  fmt = GET_RTX_FORMAT (code);
62490075Sobrien  len = GET_RTX_LENGTH (code);
62590075Sobrien  for (i = 0; i < len; i++)
62690075Sobrien    {
62790075Sobrien      rtx r;
62890075Sobrien
62990075Sobrien      switch (fmt[i])
63090075Sobrien	{
63190075Sobrien	case 'e': case 'u':
63290075Sobrien	  r = alter_predicate_for_insn (XEXP (pattern, i), alt,
63390075Sobrien					max_op, lineno);
63490075Sobrien	  if (r == NULL)
63590075Sobrien	    return r;
63690075Sobrien	  break;
63790075Sobrien
63890075Sobrien	case 'E':
63990075Sobrien	  for (j = XVECLEN (pattern, i) - 1; j >= 0; --j)
64090075Sobrien	    {
64190075Sobrien	      r = alter_predicate_for_insn (XVECEXP (pattern, i, j),
64290075Sobrien					    alt, max_op, lineno);
64390075Sobrien	      if (r == NULL)
64490075Sobrien		return r;
64590075Sobrien	    }
64690075Sobrien	  break;
64790075Sobrien
64890075Sobrien	case 'i': case 'w': case '0': case 's':
64990075Sobrien	  break;
65090075Sobrien
65190075Sobrien	default:
65290075Sobrien	  abort ();
65390075Sobrien	}
65490075Sobrien    }
65590075Sobrien
65690075Sobrien  return pattern;
65790075Sobrien}
65890075Sobrien
65990075Sobrienstatic const char *
66090075Sobrienalter_test_for_insn (ce_elem, insn_elem)
66190075Sobrien     struct queue_elem *ce_elem, *insn_elem;
66290075Sobrien{
66390075Sobrien  const char *ce_test, *insn_test;
66490075Sobrien
66590075Sobrien  ce_test = XSTR (ce_elem->data, 1);
66690075Sobrien  insn_test = XSTR (insn_elem->data, 2);
66790075Sobrien  if (!ce_test || *ce_test == '\0')
66890075Sobrien    return insn_test;
66990075Sobrien  if (!insn_test || *insn_test == '\0')
67090075Sobrien    return ce_test;
67190075Sobrien
672117395Skan  return concat ("(", ce_test, ") && (", insn_test, ")", NULL);
67390075Sobrien}
67490075Sobrien
67590075Sobrien/* Adjust all of the operand numbers in OLD to match the shift they'll
67690075Sobrien   get from an operand displacement of DISP.  Return a pointer after the
67790075Sobrien   adjusted string.  */
67890075Sobrien
67990075Sobrienstatic char *
68090075Sobrienshift_output_template (new, old, disp)
68190075Sobrien     char *new;
68290075Sobrien     const char *old;
68390075Sobrien     int disp;
68490075Sobrien{
68590075Sobrien  while (*old)
68690075Sobrien    {
68790075Sobrien      char c = *old++;
68890075Sobrien      *new++ = c;
68990075Sobrien      if (c == '%')
69090075Sobrien	{
69190075Sobrien	  c = *old++;
69290075Sobrien	  if (ISDIGIT ((unsigned char) c))
69390075Sobrien	    c += disp;
69490075Sobrien	  else if (ISALPHA (c))
69590075Sobrien	    {
69690075Sobrien	      *new++ = c;
69790075Sobrien	      c = *old++ + disp;
69890075Sobrien	    }
69990075Sobrien	  *new++ = c;
70090075Sobrien	}
70190075Sobrien    }
70290075Sobrien
70390075Sobrien  return new;
70490075Sobrien}
70590075Sobrien
70690075Sobrienstatic const char *
70790075Sobrienalter_output_for_insn (ce_elem, insn_elem, alt, max_op)
70890075Sobrien     struct queue_elem *ce_elem, *insn_elem;
70990075Sobrien     int alt, max_op;
71090075Sobrien{
71190075Sobrien  const char *ce_out, *insn_out;
71290075Sobrien  char *new, *p;
71390075Sobrien  size_t len, ce_len, insn_len;
71490075Sobrien
71590075Sobrien  /* ??? Could coordinate with genoutput to not duplicate code here.  */
71690075Sobrien
71790075Sobrien  ce_out = XSTR (ce_elem->data, 2);
71890075Sobrien  insn_out = XTMPL (insn_elem->data, 3);
71990075Sobrien  if (!ce_out || *ce_out == '\0')
72090075Sobrien    return insn_out;
72190075Sobrien
72290075Sobrien  ce_len = strlen (ce_out);
72390075Sobrien  insn_len = strlen (insn_out);
72490075Sobrien
72590075Sobrien  if (*insn_out == '*')
72690075Sobrien    /* You must take care of the predicate yourself.  */
72790075Sobrien    return insn_out;
72890075Sobrien
72990075Sobrien  if (*insn_out == '@')
73090075Sobrien    {
73190075Sobrien      len = (ce_len + 1) * alt + insn_len + 1;
73290075Sobrien      p = new = xmalloc (len);
73390075Sobrien
73490075Sobrien      do
73590075Sobrien	{
73690075Sobrien	  do
73790075Sobrien	    *p++ = *insn_out++;
73890075Sobrien	  while (ISSPACE ((unsigned char) *insn_out));
73990075Sobrien
74090075Sobrien	  if (*insn_out != '#')
74190075Sobrien	    {
74290075Sobrien	      p = shift_output_template (p, ce_out, max_op);
74390075Sobrien	      *p++ = ' ';
74490075Sobrien	    }
74590075Sobrien
74690075Sobrien	  do
74790075Sobrien	    *p++ = *insn_out++;
74890075Sobrien	  while (*insn_out && *insn_out != '\n');
74990075Sobrien	}
75090075Sobrien      while (*insn_out);
75190075Sobrien      *p = '\0';
75290075Sobrien    }
75390075Sobrien  else
75490075Sobrien    {
75590075Sobrien      len = ce_len + 1 + insn_len + 1;
75690075Sobrien      new = xmalloc (len);
75790075Sobrien
75890075Sobrien      p = shift_output_template (new, ce_out, max_op);
75990075Sobrien      *p++ = ' ';
76090075Sobrien      memcpy (p, insn_out, insn_len + 1);
76190075Sobrien    }
76290075Sobrien
76390075Sobrien  return new;
76490075Sobrien}
76590075Sobrien
76690075Sobrien/* Replicate insns as appropriate for the given DEFINE_COND_EXEC.  */
76790075Sobrien
76890075Sobrienstatic void
76990075Sobrienprocess_one_cond_exec (ce_elem)
77090075Sobrien     struct queue_elem *ce_elem;
77190075Sobrien{
77290075Sobrien  struct queue_elem *insn_elem;
77390075Sobrien  for (insn_elem = define_insn_queue; insn_elem ; insn_elem = insn_elem->next)
77490075Sobrien    {
77590075Sobrien      int alternatives, max_operand;
77690075Sobrien      rtx pred, insn, pattern;
77790075Sobrien
77890075Sobrien      if (! is_predicable (insn_elem))
77990075Sobrien	continue;
78090075Sobrien
78190075Sobrien      alternatives = 1;
78290075Sobrien      max_operand = -1;
78390075Sobrien      collect_insn_data (insn_elem->data, &alternatives, &max_operand);
78490075Sobrien      max_operand += 1;
78590075Sobrien
78690075Sobrien      if (XVECLEN (ce_elem->data, 0) != 1)
78790075Sobrien	{
78890075Sobrien	  message_with_line (ce_elem->lineno,
78990075Sobrien			     "too many patterns in predicate");
79090075Sobrien	  errors = 1;
79190075Sobrien	  return;
79290075Sobrien	}
79390075Sobrien
79490075Sobrien      pred = copy_rtx (XVECEXP (ce_elem->data, 0, 0));
79590075Sobrien      pred = alter_predicate_for_insn (pred, alternatives, max_operand,
79690075Sobrien				       ce_elem->lineno);
79790075Sobrien      if (pred == NULL)
79890075Sobrien	return;
79990075Sobrien
80090075Sobrien      /* Construct a new pattern for the new insn.  */
80190075Sobrien      insn = copy_rtx (insn_elem->data);
80290075Sobrien      XSTR (insn, 0) = "";
80390075Sobrien      pattern = rtx_alloc (COND_EXEC);
80490075Sobrien      XEXP (pattern, 0) = pred;
80590075Sobrien      if (XVECLEN (insn, 1) == 1)
80690075Sobrien	{
80790075Sobrien	  XEXP (pattern, 1) = XVECEXP (insn, 1, 0);
80890075Sobrien	  XVECEXP (insn, 1, 0) = pattern;
80990075Sobrien	  PUT_NUM_ELEM (XVEC (insn, 1), 1);
81090075Sobrien	}
81190075Sobrien      else
81290075Sobrien	{
81390075Sobrien	  XEXP (pattern, 1) = rtx_alloc (PARALLEL);
81490075Sobrien	  XVEC (XEXP (pattern, 1), 0) = XVEC (insn, 1);
81590075Sobrien	  XVEC (insn, 1) = rtvec_alloc (1);
81690075Sobrien	  XVECEXP (insn, 1, 0) = pattern;
81790075Sobrien	}
81890075Sobrien
81990075Sobrien      XSTR (insn, 2) = alter_test_for_insn (ce_elem, insn_elem);
82090075Sobrien      XTMPL (insn, 3) = alter_output_for_insn (ce_elem, insn_elem,
82190075Sobrien					      alternatives, max_operand);
82290075Sobrien
82390075Sobrien      /* ??? Set `predicable' to false.  Not crucial since it's really
82490075Sobrien         only used here, and we won't reprocess this new pattern.  */
82590075Sobrien
82690075Sobrien      /* Put the new pattern on the `other' list so that it
82790075Sobrien	 (a) is not reprocessed by other define_cond_exec patterns
82890075Sobrien	 (b) appears after all normal define_insn patterns.
82990075Sobrien
83090075Sobrien	 ??? B is debatable.  If one has normal insns that match
83190075Sobrien	 cond_exec patterns, they will be preferred over these
83290075Sobrien	 generated patterns.  Whether this matters in practice, or if
83390075Sobrien	 it's a good thing, or whether we should thread these new
83490075Sobrien	 patterns into the define_insn chain just after their generator
83590075Sobrien	 is something we'll have to experiment with.  */
83690075Sobrien
837117395Skan      queue_pattern (insn, &other_tail, insn_elem->filename,
838117395Skan		     insn_elem->lineno);
83990075Sobrien    }
84090075Sobrien}
84190075Sobrien
84290075Sobrien/* If we have any DEFINE_COND_EXEC patterns, expand the DEFINE_INSN
84390075Sobrien   patterns appropriately.  */
84490075Sobrien
84590075Sobrienstatic void
84690075Sobrienprocess_define_cond_exec ()
84790075Sobrien{
84890075Sobrien  struct queue_elem *elem;
84990075Sobrien
85090075Sobrien  identify_predicable_attribute ();
85190075Sobrien  if (errors)
85290075Sobrien    return;
85390075Sobrien
85490075Sobrien  for (elem = define_cond_exec_queue; elem ; elem = elem->next)
85590075Sobrien    process_one_cond_exec (elem);
85690075Sobrien}
85790075Sobrien
85890075Sobrienstatic char *
85990075Sobriensave_string (s, len)
86090075Sobrien     const char *s;
86190075Sobrien     int len;
86290075Sobrien{
86390075Sobrien  register char *result = xmalloc (len + 1);
86490075Sobrien
86590075Sobrien  memcpy (result, s, len);
86690075Sobrien  result[len] = 0;
86790075Sobrien  return result;
86890075Sobrien}
86990075Sobrien
87090075Sobrien
87190075Sobrien/* The entry point for initializing the reader.  */
87290075Sobrien
87390075Sobrienint
87490075Sobrieninit_md_reader_args (argc, argv)
87590075Sobrien     int argc;
87690075Sobrien     char **argv;
87790075Sobrien{
87890075Sobrien  int i;
87990075Sobrien  const char *in_fname;
88090075Sobrien
88190075Sobrien  max_include_len = 0;
88290075Sobrien  in_fname = NULL;
88390075Sobrien  for (i = 1; i < argc; i++)
88490075Sobrien    {
88590075Sobrien      if (argv[i][0] != '-')
88690075Sobrien	{
88790075Sobrien	  if (in_fname == NULL)
88890075Sobrien	    in_fname = argv[i];
88990075Sobrien	}
89090075Sobrien      else
89190075Sobrien	{
89290075Sobrien	  int c = argv[i][1];
89390075Sobrien	  switch (c)
89490075Sobrien	    {
89590075Sobrien	    case 'I':		/* Add directory to path for includes.  */
89690075Sobrien	      {
89790075Sobrien		struct file_name_list *dirtmp;
89890075Sobrien
89990075Sobrien		dirtmp = (struct file_name_list *)
90090075Sobrien		  xmalloc (sizeof (struct file_name_list));
90190075Sobrien		dirtmp->next = 0;	/* New one goes on the end */
902117395Skan		if (first_dir_md_include == 0)
903117395Skan		  first_dir_md_include = dirtmp;
90490075Sobrien		else
905117395Skan		  last_dir_md_include->next = dirtmp;
906117395Skan		last_dir_md_include = dirtmp;	/* Tail follows the last one */
90790075Sobrien		if (argv[i][1] == 'I' && argv[i][2] != 0)
90890075Sobrien		  dirtmp->fname = argv[i] + 2;
90990075Sobrien		else if (i + 1 == argc)
91090075Sobrien		  fatal ("directory name missing after -I option");
91190075Sobrien		else
91290075Sobrien		  dirtmp->fname = argv[++i];
91390075Sobrien		if (strlen (dirtmp->fname) > max_include_len)
91490075Sobrien		  max_include_len = strlen (dirtmp->fname);
91590075Sobrien	      }
91690075Sobrien	      break;
91790075Sobrien	    default:
91890075Sobrien	      fatal ("invalid option `%s'", argv[i]);
91990075Sobrien
92090075Sobrien	    }
92190075Sobrien	}
92290075Sobrien    }
92390075Sobrien    return init_md_reader (in_fname);
92490075Sobrien}
92590075Sobrien
92690075Sobrien/* The entry point for initializing the reader.  */
92790075Sobrien
92890075Sobrienint
92990075Sobrieninit_md_reader (filename)
93090075Sobrien     const char *filename;
93190075Sobrien{
93290075Sobrien  FILE *input_file;
93390075Sobrien  int c;
934117395Skan  size_t i;
93590075Sobrien  char *lastsl;
93690075Sobrien
937117395Skan  lastsl = strrchr (filename, '/');
938117395Skan  if (lastsl != NULL)
939117395Skan    base_dir = save_string (filename, lastsl - filename + 1 );
94090075Sobrien
94190075Sobrien  read_rtx_filename = filename;
94290075Sobrien  input_file = fopen (filename, "r");
94390075Sobrien  if (input_file == 0)
94490075Sobrien    {
94590075Sobrien      perror (filename);
94690075Sobrien      return FATAL_EXIT_CODE;
94790075Sobrien    }
94890075Sobrien
949117395Skan  /* Initialize the table of insn conditions.  */
950117395Skan  condition_table = htab_create (n_insn_conditions,
951117395Skan				 hash_c_test, cmp_c_test, NULL);
952117395Skan
953117395Skan  for (i = 0; i < n_insn_conditions; i++)
954117395Skan    *(htab_find_slot (condition_table, (PTR) &insn_conditions[i], INSERT))
955117395Skan      = (PTR) &insn_conditions[i];
956117395Skan
95790075Sobrien  obstack_init (rtl_obstack);
95890075Sobrien  errors = 0;
95990075Sobrien  sequence_num = 0;
96090075Sobrien
96190075Sobrien  /* Read the entire file.  */
96290075Sobrien  while (1)
96390075Sobrien    {
96490075Sobrien      rtx desc;
96590075Sobrien      int lineno;
96690075Sobrien
96790075Sobrien      c = read_skip_spaces (input_file);
96890075Sobrien      if (c == EOF)
96990075Sobrien        break;
97090075Sobrien
97190075Sobrien      ungetc (c, input_file);
97290075Sobrien      lineno = read_rtx_lineno;
97390075Sobrien      desc = read_rtx (input_file);
97490075Sobrien      process_rtx (desc, lineno);
97590075Sobrien    }
97690075Sobrien  fclose (input_file);
97790075Sobrien
97890075Sobrien  /* Process define_cond_exec patterns.  */
97990075Sobrien  if (define_cond_exec_queue != NULL)
98090075Sobrien    process_define_cond_exec ();
98190075Sobrien
98290075Sobrien  return errors ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
98390075Sobrien}
98490075Sobrien
98590075Sobrien/* The entry point for reading a single rtx from an md file.  */
98690075Sobrien
98790075Sobrienrtx
98890075Sobrienread_md_rtx (lineno, seqnr)
98990075Sobrien     int *lineno;
99090075Sobrien     int *seqnr;
99190075Sobrien{
99290075Sobrien  struct queue_elem **queue, *elem;
99390075Sobrien  rtx desc;
99490075Sobrien
995117395Skan discard:
996117395Skan
99790075Sobrien  /* Read all patterns from a given queue before moving on to the next.  */
99890075Sobrien  if (define_attr_queue != NULL)
99990075Sobrien    queue = &define_attr_queue;
100090075Sobrien  else if (define_insn_queue != NULL)
100190075Sobrien    queue = &define_insn_queue;
100290075Sobrien  else if (other_queue != NULL)
100390075Sobrien    queue = &other_queue;
100490075Sobrien  else
100590075Sobrien    return NULL_RTX;
100690075Sobrien
100790075Sobrien  elem = *queue;
100890075Sobrien  *queue = elem->next;
100990075Sobrien  desc = elem->data;
1010117395Skan  read_rtx_filename = elem->filename;
101190075Sobrien  *lineno = elem->lineno;
101290075Sobrien  *seqnr = sequence_num;
101390075Sobrien
101490075Sobrien  free (elem);
101590075Sobrien
1016117395Skan  /* Discard insn patterns which we know can never match (because
1017117395Skan     their C test is provably always false).  If insn_elision is
1018117395Skan     false, our caller needs to see all the patterns.  Note that the
1019117395Skan     elided patterns are never counted by the sequence numbering; it
1020117395Skan     it is the caller's responsibility, when insn_elision is false, not
1021117395Skan     to use elided pattern numbers for anything.  */
102290075Sobrien  switch (GET_CODE (desc))
102390075Sobrien    {
102490075Sobrien    case DEFINE_INSN:
102590075Sobrien    case DEFINE_EXPAND:
1026117395Skan      if (maybe_eval_c_test (XSTR (desc, 2)) != 0)
1027117395Skan	sequence_num++;
1028117395Skan      else if (insn_elision)
1029117395Skan	goto discard;
1030117395Skan      break;
1031117395Skan
103290075Sobrien    case DEFINE_SPLIT:
103390075Sobrien    case DEFINE_PEEPHOLE:
103490075Sobrien    case DEFINE_PEEPHOLE2:
1035117395Skan      if (maybe_eval_c_test (XSTR (desc, 1)) != 0)
1036117395Skan	sequence_num++;
1037117395Skan      else if (insn_elision)
1038117395Skan	    goto discard;
103990075Sobrien      break;
104090075Sobrien
104190075Sobrien    default:
104290075Sobrien      break;
104390075Sobrien    }
104490075Sobrien
104590075Sobrien  return desc;
104690075Sobrien}
1047117395Skan
1048117395Skan/* Helper functions for insn elision.  */
1049117395Skan
1050117395Skan/* Compute a hash function of a c_test structure, which is keyed
1051117395Skan   by its ->expr field.  */
1052117395Skanhashval_t
1053117395Skanhash_c_test (x)
1054117395Skan     const PTR x;
1055117395Skan{
1056117395Skan  const struct c_test *a = (const struct c_test *) x;
1057117395Skan  const unsigned char *base, *s = (const unsigned char *) a->expr;
1058117395Skan  hashval_t hash;
1059117395Skan  unsigned char c;
1060117395Skan  unsigned int len;
1061117395Skan
1062117395Skan  base = s;
1063117395Skan  hash = 0;
1064117395Skan
1065117395Skan  while ((c = *s++) != '\0')
1066117395Skan    {
1067117395Skan      hash += c + (c << 17);
1068117395Skan      hash ^= hash >> 2;
1069117395Skan    }
1070117395Skan
1071117395Skan  len = s - base;
1072117395Skan  hash += len + (len << 17);
1073117395Skan  hash ^= hash >> 2;
1074117395Skan
1075117395Skan  return hash;
1076117395Skan}
1077117395Skan
1078117395Skan/* Compare two c_test expression structures.  */
1079117395Skanint
1080117395Skancmp_c_test (x, y)
1081117395Skan     const PTR x;
1082117395Skan     const PTR y;
1083117395Skan{
1084117395Skan  const struct c_test *a = (const struct c_test *) x;
1085117395Skan  const struct c_test *b = (const struct c_test *) y;
1086117395Skan
1087117395Skan  return !strcmp (a->expr, b->expr);
1088117395Skan}
1089117395Skan
1090117395Skan/* Given a string representing a C test expression, look it up in the
1091117395Skan   condition_table and report whether or not its value is known
1092117395Skan   at compile time.  Returns a tristate: 1 for known true, 0 for
1093117395Skan   known false, -1 for unknown.  */
1094117395Skanint
1095117395Skanmaybe_eval_c_test (expr)
1096117395Skan     const char *expr;
1097117395Skan{
1098117395Skan  const struct c_test *test;
1099117395Skan  struct c_test dummy;
1100117395Skan
1101117395Skan  if (expr[0] == 0)
1102117395Skan    return 1;
1103117395Skan
1104117395Skan  if (insn_elision_unavailable)
1105117395Skan    return -1;
1106117395Skan
1107117395Skan  dummy.expr = expr;
1108117395Skan  test = (const struct c_test *) htab_find (condition_table, &dummy);
1109117395Skan  if (!test)
1110117395Skan    abort ();
1111117395Skan
1112117395Skan  return test->value;
1113117395Skan}
1114117395Skan
1115117395Skan/* Given a string, return the number of comma-separated elements in it.
1116117395Skan   Return 0 for the null string.  */
1117117395Skanint
1118117395Skann_comma_elts (s)
1119117395Skan     const char *s;
1120117395Skan{
1121117395Skan  int n;
1122117395Skan
1123117395Skan  if (*s == '\0')
1124117395Skan    return 0;
1125117395Skan
1126117395Skan  for (n = 1; *s; s++)
1127117395Skan    if (*s == ',')
1128117395Skan      n++;
1129117395Skan
1130117395Skan  return n;
1131117395Skan}
1132117395Skan
1133117395Skan/* Given a pointer to a (char *), return a pointer to the beginning of the
1134117395Skan   next comma-separated element in the string.  Advance the pointer given
1135117395Skan   to the end of that element.  Return NULL if at end of string.  Caller
1136117395Skan   is responsible for copying the string if necessary.  White space between
1137117395Skan   a comma and an element is ignored.  */
1138117395Skan
1139117395Skanconst char *
1140117395Skanscan_comma_elt (pstr)
1141117395Skan     const char **pstr;
1142117395Skan{
1143117395Skan  const char *start;
1144117395Skan  const char *p = *pstr;
1145117395Skan
1146117395Skan  if (*p == ',')
1147117395Skan    p++;
1148117395Skan  while (ISSPACE(*p))
1149117395Skan    p++;
1150117395Skan
1151117395Skan  if (*p == '\0')
1152117395Skan    return NULL;
1153117395Skan
1154117395Skan  start = p;
1155117395Skan
1156117395Skan  while (*p != ',' && *p != '\0')
1157117395Skan    p++;
1158117395Skan
1159117395Skan  *pstr = p;
1160117395Skan  return start;
1161117395Skan}
1162