gensupport.c revision 90075
190075Sobrien/* Support routines for the various generation passes.
290075Sobrien   Copyright (C) 2000, 2001 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"
2690075Sobrien#include "gensupport.h"
2790075Sobrien
2890075Sobrien
2990075Sobrien/* In case some macros used by files we include need it, define this here.  */
3090075Sobrienint target_flags;
3190075Sobrien
3290075Sobrienstatic struct obstack obstack;
3390075Sobrienstruct obstack *rtl_obstack = &obstack;
3490075Sobrien
3590075Sobrien#define obstack_chunk_alloc xmalloc
3690075Sobrien#define obstack_chunk_free free
3790075Sobrien
3890075Sobrienstatic int sequence_num;
3990075Sobrienstatic int errors;
4090075Sobrien
4190075Sobrienstatic int predicable_default;
4290075Sobrienstatic const char *predicable_true;
4390075Sobrienstatic const char *predicable_false;
4490075Sobrien
4590075Sobrienstatic char *base_dir = NULL;
4690075Sobrien
4790075Sobrien/* We initially queue all patterns, process the define_insn and
4890075Sobrien   define_cond_exec patterns, then return them one at a time.  */
4990075Sobrien
5090075Sobrienstruct queue_elem
5190075Sobrien{
5290075Sobrien  rtx data;
5390075Sobrien  int lineno;
5490075Sobrien  struct queue_elem *next;
5590075Sobrien};
5690075Sobrien
5790075Sobrienstatic struct queue_elem *define_attr_queue;
5890075Sobrienstatic struct queue_elem **define_attr_tail = &define_attr_queue;
5990075Sobrienstatic struct queue_elem *define_insn_queue;
6090075Sobrienstatic struct queue_elem **define_insn_tail = &define_insn_queue;
6190075Sobrienstatic struct queue_elem *define_cond_exec_queue;
6290075Sobrienstatic struct queue_elem **define_cond_exec_tail = &define_cond_exec_queue;
6390075Sobrienstatic struct queue_elem *other_queue;
6490075Sobrienstatic struct queue_elem **other_tail = &other_queue;
6590075Sobrien
6690075Sobrienstatic void queue_pattern PARAMS ((rtx, struct queue_elem ***, int));
6790075Sobrien
6890075Sobrien/* Current maximum length of directory names in the search path
6990075Sobrien   for include files.  (Altered as we get more of them.)  */
7090075Sobrien
7190075Sobriensize_t max_include_len;
7290075Sobrien
7390075Sobrienstruct file_name_list
7490075Sobrien  {
7590075Sobrien    struct file_name_list *next;
7690075Sobrien    const char *fname;
7790075Sobrien  };
7890075Sobrien
7990075Sobrienstruct file_name_list *include = 0;     /* First dir to search */
8090075Sobrien        /* First dir to search for <file> */
8190075Sobrienstruct file_name_list *first_bracket_include = 0;
8290075Sobrienstruct file_name_list *last_include = 0;        /* Last in chain */
8390075Sobrien
8490075Sobrienstatic void remove_constraints PARAMS ((rtx));
8590075Sobrienstatic void process_rtx PARAMS ((rtx, int));
8690075Sobrien
8790075Sobrienstatic int is_predicable PARAMS ((struct queue_elem *));
8890075Sobrienstatic void identify_predicable_attribute PARAMS ((void));
8990075Sobrienstatic int n_alternatives PARAMS ((const char *));
9090075Sobrienstatic void collect_insn_data PARAMS ((rtx, int *, int *));
9190075Sobrienstatic rtx alter_predicate_for_insn PARAMS ((rtx, int, int, int));
9290075Sobrienstatic const char *alter_test_for_insn PARAMS ((struct queue_elem *,
9390075Sobrien						struct queue_elem *));
9490075Sobrienstatic char *shift_output_template PARAMS ((char *, const char *, int));
9590075Sobrienstatic const char *alter_output_for_insn PARAMS ((struct queue_elem *,
9690075Sobrien						  struct queue_elem *,
9790075Sobrien						  int, int));
9890075Sobrienstatic void process_one_cond_exec PARAMS ((struct queue_elem *));
9990075Sobrienstatic void process_define_cond_exec PARAMS ((void));
10090075Sobrienstatic int process_include PARAMS ((rtx, int));
10190075Sobrienstatic char *save_string PARAMS ((const char *, int));
10290075Sobrienstatic int init_include_reader PARAMS ((FILE  *));
10390075Sobrien
10490075Sobrienvoid
10590075Sobrienmessage_with_line VPARAMS ((int lineno, const char *msg, ...))
10690075Sobrien{
10790075Sobrien  VA_OPEN (ap, msg);
10890075Sobrien  VA_FIXEDARG (ap, int, lineno);
10990075Sobrien  VA_FIXEDARG (ap, const char *, msg);
11090075Sobrien
11190075Sobrien  fprintf (stderr, "%s:%d: ", read_rtx_filename, lineno);
11290075Sobrien  vfprintf (stderr, msg, ap);
11390075Sobrien  fputc ('\n', stderr);
11490075Sobrien
11590075Sobrien  VA_CLOSE (ap);
11690075Sobrien}
11790075Sobrien
11890075Sobrien/* Make a version of gen_rtx_CONST_INT so that GEN_INT can be used in
11990075Sobrien   the gensupport programs.  */
12090075Sobrien
12190075Sobrienrtx
12290075Sobriengen_rtx_CONST_INT (mode, arg)
12390075Sobrien     enum machine_mode mode ATTRIBUTE_UNUSED;
12490075Sobrien     HOST_WIDE_INT arg;
12590075Sobrien{
12690075Sobrien  rtx rt = rtx_alloc (CONST_INT);
12790075Sobrien
12890075Sobrien  XWINT (rt, 0) = arg;
12990075Sobrien  return rt;
13090075Sobrien}
13190075Sobrien
13290075Sobrien/* Queue PATTERN on LIST_TAIL.  */
13390075Sobrien
13490075Sobrienstatic void
13590075Sobrienqueue_pattern (pattern, list_tail, lineno)
13690075Sobrien     rtx pattern;
13790075Sobrien     struct queue_elem ***list_tail;
13890075Sobrien     int lineno;
13990075Sobrien{
14090075Sobrien  struct queue_elem *e = (struct queue_elem *) xmalloc (sizeof (*e));
14190075Sobrien  e->data = pattern;
14290075Sobrien  e->lineno = lineno;
14390075Sobrien  e->next = NULL;
14490075Sobrien  **list_tail = e;
14590075Sobrien  *list_tail = &e->next;
14690075Sobrien}
14790075Sobrien
14890075Sobrien/* Recursively remove constraints from an rtx.  */
14990075Sobrien
15090075Sobrienstatic void
15190075Sobrienremove_constraints (part)
15290075Sobrien     rtx part;
15390075Sobrien{
15490075Sobrien  int i, j;
15590075Sobrien  const char *format_ptr;
15690075Sobrien
15790075Sobrien  if (part == 0)
15890075Sobrien    return;
15990075Sobrien
16090075Sobrien  if (GET_CODE (part) == MATCH_OPERAND)
16190075Sobrien    XSTR (part, 2) = "";
16290075Sobrien  else if (GET_CODE (part) == MATCH_SCRATCH)
16390075Sobrien    XSTR (part, 1) = "";
16490075Sobrien
16590075Sobrien  format_ptr = GET_RTX_FORMAT (GET_CODE (part));
16690075Sobrien
16790075Sobrien  for (i = 0; i < GET_RTX_LENGTH (GET_CODE (part)); i++)
16890075Sobrien    switch (*format_ptr++)
16990075Sobrien      {
17090075Sobrien      case 'e':
17190075Sobrien      case 'u':
17290075Sobrien	remove_constraints (XEXP (part, i));
17390075Sobrien	break;
17490075Sobrien      case 'E':
17590075Sobrien	if (XVEC (part, i) != NULL)
17690075Sobrien	  for (j = 0; j < XVECLEN (part, i); j++)
17790075Sobrien	    remove_constraints (XVECEXP (part, i, j));
17890075Sobrien	break;
17990075Sobrien      }
18090075Sobrien}
18190075Sobrien
18290075Sobrien/* The entry point for initializing the reader.  */
18390075Sobrien
18490075Sobrienstatic int
18590075Sobrieninit_include_reader (inf)
18690075Sobrien     FILE *inf;
18790075Sobrien{
18890075Sobrien  int c;
18990075Sobrien
19090075Sobrien  errors = 0;
19190075Sobrien
19290075Sobrien  /* Read the entire file.  */
19390075Sobrien  while (1)
19490075Sobrien    {
19590075Sobrien      rtx desc;
19690075Sobrien      int lineno;
19790075Sobrien
19890075Sobrien      c = read_skip_spaces (inf);
19990075Sobrien      if (c == EOF)
20090075Sobrien	break;
20190075Sobrien
20290075Sobrien      ungetc (c, inf);
20390075Sobrien      lineno = read_rtx_lineno;
20490075Sobrien      desc = read_rtx (inf);
20590075Sobrien      process_rtx (desc, lineno);
20690075Sobrien    }
20790075Sobrien  fclose (inf);
20890075Sobrien
20990075Sobrien  /* Process define_cond_exec patterns.  */
21090075Sobrien  if (define_cond_exec_queue != NULL)
21190075Sobrien    process_define_cond_exec ();
21290075Sobrien
21390075Sobrien  return errors ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
21490075Sobrien}
21590075Sobrien
21690075Sobrien/* Process an include file assuming that it lives in gcc/config/{target}/
21790075Sobrien   if the include looks line (include "file" )  */
21890075Sobrienstatic int
21990075Sobrienprocess_include (desc, lineno)
22090075Sobrien     rtx desc;
22190075Sobrien     int lineno;
22290075Sobrien{
22390075Sobrien  const char *filename = XSTR (desc, 0);
22490075Sobrien  char *pathname = NULL;
22590075Sobrien  FILE *input_file;
22690075Sobrien  char *fname = NULL;
22790075Sobrien  struct file_name_list *stackp;
22890075Sobrien  int flen;
22990075Sobrien
23090075Sobrien  stackp = include;
23190075Sobrien
23290075Sobrien  /* If specified file name is absolute, just open it.  */
23390075Sobrien  if (IS_ABSOLUTE_PATHNAME (filename) || !stackp)
23490075Sobrien    {
23590075Sobrien      if (base_dir)
23690075Sobrien        {
23790075Sobrien          pathname = xmalloc (strlen (base_dir) + strlen (filename) + 1);
23890075Sobrien          pathname = strcpy (pathname, base_dir);
23990075Sobrien          strcat (pathname, filename);
24090075Sobrien          strcat (pathname, "\0");
24190075Sobrien	}
24290075Sobrien      else
24390075Sobrien        {
24490075Sobrien	  pathname = xstrdup (filename);
24590075Sobrien        }
24690075Sobrien      read_rtx_filename = pathname;
24790075Sobrien      input_file = fopen (pathname, "r");
24890075Sobrien
24990075Sobrien      if (input_file == 0)
25090075Sobrien	{
25190075Sobrien	  perror (pathname);
25290075Sobrien	  return FATAL_EXIT_CODE;
25390075Sobrien	}
25490075Sobrien    }
25590075Sobrien  else if (stackp)
25690075Sobrien    {
25790075Sobrien
25890075Sobrien      flen = strlen (filename);
25990075Sobrien
26090075Sobrien      fname = (char *) xmalloc (max_include_len + flen + 2);
26190075Sobrien
26290075Sobrien      /* + 2 above for slash and terminating null.  */
26390075Sobrien
26490075Sobrien      /* Search directory path, trying to open the file.
26590075Sobrien         Copy each filename tried into FNAME.  */
26690075Sobrien
26790075Sobrien      for (; stackp; stackp = stackp->next)
26890075Sobrien	{
26990075Sobrien	  if (stackp->fname)
27090075Sobrien	    {
27190075Sobrien	      strcpy (fname, stackp->fname);
27290075Sobrien	      strcat (fname, "/");
27390075Sobrien	      fname[strlen (fname) + flen] = 0;
27490075Sobrien	    }
27590075Sobrien	  else
27690075Sobrien	    {
27790075Sobrien	      fname[0] = 0;
27890075Sobrien	    }
27990075Sobrien	  strncat (fname, (const char *) filename, flen);
28090075Sobrien	  read_rtx_filename = fname;
28190075Sobrien	  input_file = fopen (fname, "r");
28290075Sobrien	  if (input_file != NULL)
28390075Sobrien	    break;
28490075Sobrien	}
28590075Sobrien      if (stackp == NULL)
28690075Sobrien	{
28790075Sobrien	  if (strchr (fname, '/') == NULL || strchr (fname, '\\' ) || base_dir)
28890075Sobrien	    {
28990075Sobrien	      if (base_dir)
29090075Sobrien		{
29190075Sobrien		  pathname =
29290075Sobrien		    xmalloc (strlen (base_dir) + strlen (filename) + 1);
29390075Sobrien		  pathname = strcpy (pathname, base_dir);
29490075Sobrien		  strcat (pathname, filename);
29590075Sobrien		  strcat (pathname, "\0");
29690075Sobrien		}
29790075Sobrien	      else
29890075Sobrien		pathname = xstrdup (filename);
29990075Sobrien	    }
30090075Sobrien	  read_rtx_filename = pathname;
30190075Sobrien	  input_file = fopen (pathname, "r");
30290075Sobrien
30390075Sobrien	  if (input_file == 0)
30490075Sobrien	    {
30590075Sobrien	      perror (filename);
30690075Sobrien	      return FATAL_EXIT_CODE;
30790075Sobrien	    }
30890075Sobrien	}
30990075Sobrien
31090075Sobrien    }
31190075Sobrien
31290075Sobrien  if (init_include_reader (input_file) == FATAL_EXIT_CODE)
31390075Sobrien    message_with_line (lineno, "read errors found in include file  %s\n", pathname);
31490075Sobrien
31590075Sobrien  if (fname)
31690075Sobrien    free (fname);
31790075Sobrien  return SUCCESS_EXIT_CODE;
31890075Sobrien}
31990075Sobrien
32090075Sobrien/* Process a top level rtx in some way, queueing as appropriate.  */
32190075Sobrien
32290075Sobrienstatic void
32390075Sobrienprocess_rtx (desc, lineno)
32490075Sobrien     rtx desc;
32590075Sobrien     int lineno;
32690075Sobrien{
32790075Sobrien  switch (GET_CODE (desc))
32890075Sobrien    {
32990075Sobrien    case DEFINE_INSN:
33090075Sobrien      queue_pattern (desc, &define_insn_tail, lineno);
33190075Sobrien      break;
33290075Sobrien
33390075Sobrien    case DEFINE_COND_EXEC:
33490075Sobrien      queue_pattern (desc, &define_cond_exec_tail, lineno);
33590075Sobrien      break;
33690075Sobrien
33790075Sobrien    case DEFINE_ATTR:
33890075Sobrien      queue_pattern (desc, &define_attr_tail, lineno);
33990075Sobrien      break;
34090075Sobrien
34190075Sobrien    case INCLUDE:
34290075Sobrien      if (process_include (desc, lineno) == FATAL_EXIT_CODE)
34390075Sobrien	{
34490075Sobrien	  const char *filename = XSTR (desc, 0);
34590075Sobrien	  message_with_line (lineno, "include file at  %s not found\n",
34690075Sobrien			     filename);
34790075Sobrien	}
34890075Sobrien      break;
34990075Sobrien
35090075Sobrien    case DEFINE_INSN_AND_SPLIT:
35190075Sobrien      {
35290075Sobrien	const char *split_cond;
35390075Sobrien	rtx split;
35490075Sobrien	rtvec attr;
35590075Sobrien	int i;
35690075Sobrien
35790075Sobrien	/* Create a split with values from the insn_and_split.  */
35890075Sobrien	split = rtx_alloc (DEFINE_SPLIT);
35990075Sobrien
36090075Sobrien	i = XVECLEN (desc, 1);
36190075Sobrien	XVEC (split, 0) = rtvec_alloc (i);
36290075Sobrien	while (--i >= 0)
36390075Sobrien	  {
36490075Sobrien	    XVECEXP (split, 0, i) = copy_rtx (XVECEXP (desc, 1, i));
36590075Sobrien	    remove_constraints (XVECEXP (split, 0, i));
36690075Sobrien	  }
36790075Sobrien
36890075Sobrien	/* If the split condition starts with "&&", append it to the
36990075Sobrien	   insn condition to create the new split condition.  */
37090075Sobrien	split_cond = XSTR (desc, 4);
37190075Sobrien	if (split_cond[0] == '&' && split_cond[1] == '&')
37290075Sobrien	  {
37390075Sobrien	    const char *insn_cond = XSTR (desc, 2);
37490075Sobrien	    size_t insn_cond_len = strlen (insn_cond);
37590075Sobrien	    size_t split_cond_len = strlen (split_cond);
37690075Sobrien	    char *combined;
37790075Sobrien
37890075Sobrien	    combined = (char *) xmalloc (insn_cond_len + split_cond_len + 1);
37990075Sobrien	    memcpy (combined, insn_cond, insn_cond_len);
38090075Sobrien	    memcpy (combined + insn_cond_len, split_cond, split_cond_len + 1);
38190075Sobrien
38290075Sobrien	    split_cond = combined;
38390075Sobrien	  }
38490075Sobrien	XSTR (split, 1) = split_cond;
38590075Sobrien	XVEC (split, 2) = XVEC (desc, 5);
38690075Sobrien	XSTR (split, 3) = XSTR (desc, 6);
38790075Sobrien
38890075Sobrien	/* Fix up the DEFINE_INSN.  */
38990075Sobrien	attr = XVEC (desc, 7);
39090075Sobrien	PUT_CODE (desc, DEFINE_INSN);
39190075Sobrien	XVEC (desc, 4) = attr;
39290075Sobrien
39390075Sobrien	/* Queue them.  */
39490075Sobrien	queue_pattern (desc, &define_insn_tail, lineno);
39590075Sobrien	queue_pattern (split, &other_tail, lineno);
39690075Sobrien	break;
39790075Sobrien      }
39890075Sobrien
39990075Sobrien    default:
40090075Sobrien      queue_pattern (desc, &other_tail, lineno);
40190075Sobrien      break;
40290075Sobrien    }
40390075Sobrien}
40490075Sobrien
40590075Sobrien/* Return true if attribute PREDICABLE is true for ELEM, which holds
40690075Sobrien   a DEFINE_INSN.  */
40790075Sobrien
40890075Sobrienstatic int
40990075Sobrienis_predicable (elem)
41090075Sobrien     struct queue_elem *elem;
41190075Sobrien{
41290075Sobrien  rtvec vec = XVEC (elem->data, 4);
41390075Sobrien  const char *value;
41490075Sobrien  int i;
41590075Sobrien
41690075Sobrien  if (! vec)
41790075Sobrien    return predicable_default;
41890075Sobrien
41990075Sobrien  for (i = GET_NUM_ELEM (vec) - 1; i >= 0; --i)
42090075Sobrien    {
42190075Sobrien      rtx sub = RTVEC_ELT (vec, i);
42290075Sobrien      switch (GET_CODE (sub))
42390075Sobrien	{
42490075Sobrien	case SET_ATTR:
42590075Sobrien	  if (strcmp (XSTR (sub, 0), "predicable") == 0)
42690075Sobrien	    {
42790075Sobrien	      value = XSTR (sub, 1);
42890075Sobrien	      goto found;
42990075Sobrien	    }
43090075Sobrien	  break;
43190075Sobrien
43290075Sobrien	case SET_ATTR_ALTERNATIVE:
43390075Sobrien	  if (strcmp (XSTR (sub, 0), "predicable") == 0)
43490075Sobrien	    {
43590075Sobrien	      message_with_line (elem->lineno,
43690075Sobrien				 "multiple alternatives for `predicable'");
43790075Sobrien	      errors = 1;
43890075Sobrien	      return 0;
43990075Sobrien	    }
44090075Sobrien	  break;
44190075Sobrien
44290075Sobrien	case SET:
44390075Sobrien	  if (GET_CODE (SET_DEST (sub)) != ATTR
44490075Sobrien	      || strcmp (XSTR (SET_DEST (sub), 0), "predicable") != 0)
44590075Sobrien	    break;
44690075Sobrien	  sub = SET_SRC (sub);
44790075Sobrien	  if (GET_CODE (sub) == CONST_STRING)
44890075Sobrien	    {
44990075Sobrien	      value = XSTR (sub, 0);
45090075Sobrien	      goto found;
45190075Sobrien	    }
45290075Sobrien
45390075Sobrien	  /* ??? It would be possible to handle this if we really tried.
45490075Sobrien	     It's not easy though, and I'm not going to bother until it
45590075Sobrien	     really proves necessary.  */
45690075Sobrien	  message_with_line (elem->lineno,
45790075Sobrien			     "non-constant value for `predicable'");
45890075Sobrien	  errors = 1;
45990075Sobrien	  return 0;
46090075Sobrien
46190075Sobrien	default:
46290075Sobrien	  abort ();
46390075Sobrien	}
46490075Sobrien    }
46590075Sobrien
46690075Sobrien  return predicable_default;
46790075Sobrien
46890075Sobrien found:
46990075Sobrien  /* Verify that predicability does not vary on the alternative.  */
47090075Sobrien  /* ??? It should be possible to handle this by simply eliminating
47190075Sobrien     the non-predicable alternatives from the insn.  FRV would like
47290075Sobrien     to do this.  Delay this until we've got the basics solid.  */
47390075Sobrien  if (strchr (value, ',') != NULL)
47490075Sobrien    {
47590075Sobrien      message_with_line (elem->lineno,
47690075Sobrien			 "multiple alternatives for `predicable'");
47790075Sobrien      errors = 1;
47890075Sobrien      return 0;
47990075Sobrien    }
48090075Sobrien
48190075Sobrien  /* Find out which value we're looking at.  */
48290075Sobrien  if (strcmp (value, predicable_true) == 0)
48390075Sobrien    return 1;
48490075Sobrien  if (strcmp (value, predicable_false) == 0)
48590075Sobrien    return 0;
48690075Sobrien
48790075Sobrien  message_with_line (elem->lineno,
48890075Sobrien		     "unknown value `%s' for `predicable' attribute",
48990075Sobrien		     value);
49090075Sobrien  errors = 1;
49190075Sobrien  return 0;
49290075Sobrien}
49390075Sobrien
49490075Sobrien/* Examine the attribute "predicable"; discover its boolean values
49590075Sobrien   and its default.  */
49690075Sobrien
49790075Sobrienstatic void
49890075Sobrienidentify_predicable_attribute ()
49990075Sobrien{
50090075Sobrien  struct queue_elem *elem;
50190075Sobrien  char *p_true, *p_false;
50290075Sobrien  const char *value;
50390075Sobrien  size_t len;
50490075Sobrien
50590075Sobrien  /* Look for the DEFINE_ATTR for `predicable', which must exist.  */
50690075Sobrien  for (elem = define_attr_queue; elem ; elem = elem->next)
50790075Sobrien    if (strcmp (XSTR (elem->data, 0), "predicable") == 0)
50890075Sobrien      goto found;
50990075Sobrien
51090075Sobrien  message_with_line (define_cond_exec_queue->lineno,
51190075Sobrien		     "attribute `predicable' not defined");
51290075Sobrien  errors = 1;
51390075Sobrien  return;
51490075Sobrien
51590075Sobrien found:
51690075Sobrien  value = XSTR (elem->data, 1);
51790075Sobrien  len = strlen (value);
51890075Sobrien  p_false = (char *) xmalloc (len + 1);
51990075Sobrien  memcpy (p_false, value, len + 1);
52090075Sobrien
52190075Sobrien  p_true = strchr (p_false, ',');
52290075Sobrien  if (p_true == NULL || strchr (++p_true, ',') != NULL)
52390075Sobrien    {
52490075Sobrien      message_with_line (elem->lineno,
52590075Sobrien			 "attribute `predicable' is not a boolean");
52690075Sobrien      errors = 1;
52790075Sobrien      return;
52890075Sobrien    }
52990075Sobrien  p_true[-1] = '\0';
53090075Sobrien
53190075Sobrien  predicable_true = p_true;
53290075Sobrien  predicable_false = p_false;
53390075Sobrien
53490075Sobrien  switch (GET_CODE (XEXP (elem->data, 2)))
53590075Sobrien    {
53690075Sobrien    case CONST_STRING:
53790075Sobrien      value = XSTR (XEXP (elem->data, 2), 0);
53890075Sobrien      break;
53990075Sobrien
54090075Sobrien    case CONST:
54190075Sobrien      message_with_line (elem->lineno,
54290075Sobrien			 "attribute `predicable' cannot be const");
54390075Sobrien      errors = 1;
54490075Sobrien      return;
54590075Sobrien
54690075Sobrien    default:
54790075Sobrien      message_with_line (elem->lineno,
54890075Sobrien			 "attribute `predicable' must have a constant default");
54990075Sobrien      errors = 1;
55090075Sobrien      return;
55190075Sobrien    }
55290075Sobrien
55390075Sobrien  if (strcmp (value, p_true) == 0)
55490075Sobrien    predicable_default = 1;
55590075Sobrien  else if (strcmp (value, p_false) == 0)
55690075Sobrien    predicable_default = 0;
55790075Sobrien  else
55890075Sobrien    {
55990075Sobrien      message_with_line (elem->lineno,
56090075Sobrien			 "unknown value `%s' for `predicable' attribute",
56190075Sobrien			 value);
56290075Sobrien      errors = 1;
56390075Sobrien    }
56490075Sobrien}
56590075Sobrien
56690075Sobrien/* Return the number of alternatives in constraint S.  */
56790075Sobrien
56890075Sobrienstatic int
56990075Sobrienn_alternatives (s)
57090075Sobrien     const char *s;
57190075Sobrien{
57290075Sobrien  int n = 1;
57390075Sobrien
57490075Sobrien  if (s)
57590075Sobrien    while (*s)
57690075Sobrien      n += (*s++ == ',');
57790075Sobrien
57890075Sobrien  return n;
57990075Sobrien}
58090075Sobrien
58190075Sobrien/* Determine how many alternatives there are in INSN, and how many
58290075Sobrien   operands.  */
58390075Sobrien
58490075Sobrienstatic void
58590075Sobriencollect_insn_data (pattern, palt, pmax)
58690075Sobrien     rtx pattern;
58790075Sobrien     int *palt, *pmax;
58890075Sobrien{
58990075Sobrien  const char *fmt;
59090075Sobrien  enum rtx_code code;
59190075Sobrien  int i, j, len;
59290075Sobrien
59390075Sobrien  code = GET_CODE (pattern);
59490075Sobrien  switch (code)
59590075Sobrien    {
59690075Sobrien    case MATCH_OPERAND:
59790075Sobrien      i = n_alternatives (XSTR (pattern, 2));
59890075Sobrien      *palt = (i > *palt ? i : *palt);
59990075Sobrien      /* FALLTHRU */
60090075Sobrien
60190075Sobrien    case MATCH_OPERATOR:
60290075Sobrien    case MATCH_SCRATCH:
60390075Sobrien    case MATCH_PARALLEL:
60490075Sobrien    case MATCH_INSN:
60590075Sobrien      i = XINT (pattern, 0);
60690075Sobrien      if (i > *pmax)
60790075Sobrien	*pmax = i;
60890075Sobrien      break;
60990075Sobrien
61090075Sobrien    default:
61190075Sobrien      break;
61290075Sobrien    }
61390075Sobrien
61490075Sobrien  fmt = GET_RTX_FORMAT (code);
61590075Sobrien  len = GET_RTX_LENGTH (code);
61690075Sobrien  for (i = 0; i < len; i++)
61790075Sobrien    {
61890075Sobrien      switch (fmt[i])
61990075Sobrien	{
62090075Sobrien	case 'e': case 'u':
62190075Sobrien	  collect_insn_data (XEXP (pattern, i), palt, pmax);
62290075Sobrien	  break;
62390075Sobrien
62490075Sobrien	case 'V':
62590075Sobrien	  if (XVEC (pattern, i) == NULL)
62690075Sobrien	    break;
62790075Sobrien	  /* FALLTHRU */
62890075Sobrien	case 'E':
62990075Sobrien	  for (j = XVECLEN (pattern, i) - 1; j >= 0; --j)
63090075Sobrien	    collect_insn_data (XVECEXP (pattern, i, j), palt, pmax);
63190075Sobrien	  break;
63290075Sobrien
63390075Sobrien	case 'i': case 'w': case '0': case 's': case 'S': case 'T':
63490075Sobrien	  break;
63590075Sobrien
63690075Sobrien	default:
63790075Sobrien	  abort ();
63890075Sobrien	}
63990075Sobrien    }
64090075Sobrien}
64190075Sobrien
64290075Sobrienstatic rtx
64390075Sobrienalter_predicate_for_insn (pattern, alt, max_op, lineno)
64490075Sobrien     rtx pattern;
64590075Sobrien     int alt, max_op, lineno;
64690075Sobrien{
64790075Sobrien  const char *fmt;
64890075Sobrien  enum rtx_code code;
64990075Sobrien  int i, j, len;
65090075Sobrien
65190075Sobrien  code = GET_CODE (pattern);
65290075Sobrien  switch (code)
65390075Sobrien    {
65490075Sobrien    case MATCH_OPERAND:
65590075Sobrien      {
65690075Sobrien	const char *c = XSTR (pattern, 2);
65790075Sobrien
65890075Sobrien	if (n_alternatives (c) != 1)
65990075Sobrien	  {
66090075Sobrien	    message_with_line (lineno,
66190075Sobrien			       "too many alternatives for operand %d",
66290075Sobrien			       XINT (pattern, 0));
66390075Sobrien	    errors = 1;
66490075Sobrien	    return NULL;
66590075Sobrien	  }
66690075Sobrien
66790075Sobrien	/* Replicate C as needed to fill out ALT alternatives.  */
66890075Sobrien	if (c && *c && alt > 1)
66990075Sobrien	  {
67090075Sobrien	    size_t c_len = strlen (c);
67190075Sobrien	    size_t len = alt * (c_len + 1);
67290075Sobrien	    char *new_c = (char *) xmalloc (len);
67390075Sobrien
67490075Sobrien	    memcpy (new_c, c, c_len);
67590075Sobrien	    for (i = 1; i < alt; ++i)
67690075Sobrien	      {
67790075Sobrien		new_c[i * (c_len + 1) - 1] = ',';
67890075Sobrien		memcpy (&new_c[i * (c_len + 1)], c, c_len);
67990075Sobrien	      }
68090075Sobrien	    new_c[len - 1] = '\0';
68190075Sobrien	    XSTR (pattern, 2) = new_c;
68290075Sobrien	  }
68390075Sobrien      }
68490075Sobrien      /* FALLTHRU */
68590075Sobrien
68690075Sobrien    case MATCH_OPERATOR:
68790075Sobrien    case MATCH_SCRATCH:
68890075Sobrien    case MATCH_PARALLEL:
68990075Sobrien    case MATCH_INSN:
69090075Sobrien      XINT (pattern, 0) += max_op;
69190075Sobrien      break;
69290075Sobrien
69390075Sobrien    default:
69490075Sobrien      break;
69590075Sobrien    }
69690075Sobrien
69790075Sobrien  fmt = GET_RTX_FORMAT (code);
69890075Sobrien  len = GET_RTX_LENGTH (code);
69990075Sobrien  for (i = 0; i < len; i++)
70090075Sobrien    {
70190075Sobrien      rtx r;
70290075Sobrien
70390075Sobrien      switch (fmt[i])
70490075Sobrien	{
70590075Sobrien	case 'e': case 'u':
70690075Sobrien	  r = alter_predicate_for_insn (XEXP (pattern, i), alt,
70790075Sobrien					max_op, lineno);
70890075Sobrien	  if (r == NULL)
70990075Sobrien	    return r;
71090075Sobrien	  break;
71190075Sobrien
71290075Sobrien	case 'E':
71390075Sobrien	  for (j = XVECLEN (pattern, i) - 1; j >= 0; --j)
71490075Sobrien	    {
71590075Sobrien	      r = alter_predicate_for_insn (XVECEXP (pattern, i, j),
71690075Sobrien					    alt, max_op, lineno);
71790075Sobrien	      if (r == NULL)
71890075Sobrien		return r;
71990075Sobrien	    }
72090075Sobrien	  break;
72190075Sobrien
72290075Sobrien	case 'i': case 'w': case '0': case 's':
72390075Sobrien	  break;
72490075Sobrien
72590075Sobrien	default:
72690075Sobrien	  abort ();
72790075Sobrien	}
72890075Sobrien    }
72990075Sobrien
73090075Sobrien  return pattern;
73190075Sobrien}
73290075Sobrien
73390075Sobrienstatic const char *
73490075Sobrienalter_test_for_insn (ce_elem, insn_elem)
73590075Sobrien     struct queue_elem *ce_elem, *insn_elem;
73690075Sobrien{
73790075Sobrien  const char *ce_test, *insn_test;
73890075Sobrien  char *new_test;
73990075Sobrien  size_t len, ce_len, insn_len;
74090075Sobrien
74190075Sobrien  ce_test = XSTR (ce_elem->data, 1);
74290075Sobrien  insn_test = XSTR (insn_elem->data, 2);
74390075Sobrien  if (!ce_test || *ce_test == '\0')
74490075Sobrien    return insn_test;
74590075Sobrien  if (!insn_test || *insn_test == '\0')
74690075Sobrien    return ce_test;
74790075Sobrien
74890075Sobrien  ce_len = strlen (ce_test);
74990075Sobrien  insn_len = strlen (insn_test);
75090075Sobrien  len = 1 + ce_len + 1 + 4 + 1 + insn_len + 1 + 1;
75190075Sobrien  new_test = (char *) xmalloc (len);
75290075Sobrien
75390075Sobrien  sprintf (new_test, "(%s) && (%s)", ce_test, insn_test);
75490075Sobrien
75590075Sobrien  return new_test;
75690075Sobrien}
75790075Sobrien
75890075Sobrien/* Adjust all of the operand numbers in OLD to match the shift they'll
75990075Sobrien   get from an operand displacement of DISP.  Return a pointer after the
76090075Sobrien   adjusted string.  */
76190075Sobrien
76290075Sobrienstatic char *
76390075Sobrienshift_output_template (new, old, disp)
76490075Sobrien     char *new;
76590075Sobrien     const char *old;
76690075Sobrien     int disp;
76790075Sobrien{
76890075Sobrien  while (*old)
76990075Sobrien    {
77090075Sobrien      char c = *old++;
77190075Sobrien      *new++ = c;
77290075Sobrien      if (c == '%')
77390075Sobrien	{
77490075Sobrien	  c = *old++;
77590075Sobrien	  if (ISDIGIT ((unsigned char) c))
77690075Sobrien	    c += disp;
77790075Sobrien	  else if (ISALPHA (c))
77890075Sobrien	    {
77990075Sobrien	      *new++ = c;
78090075Sobrien	      c = *old++ + disp;
78190075Sobrien	    }
78290075Sobrien	  *new++ = c;
78390075Sobrien	}
78490075Sobrien    }
78590075Sobrien
78690075Sobrien  return new;
78790075Sobrien}
78890075Sobrien
78990075Sobrienstatic const char *
79090075Sobrienalter_output_for_insn (ce_elem, insn_elem, alt, max_op)
79190075Sobrien     struct queue_elem *ce_elem, *insn_elem;
79290075Sobrien     int alt, max_op;
79390075Sobrien{
79490075Sobrien  const char *ce_out, *insn_out;
79590075Sobrien  char *new, *p;
79690075Sobrien  size_t len, ce_len, insn_len;
79790075Sobrien
79890075Sobrien  /* ??? Could coordinate with genoutput to not duplicate code here.  */
79990075Sobrien
80090075Sobrien  ce_out = XSTR (ce_elem->data, 2);
80190075Sobrien  insn_out = XTMPL (insn_elem->data, 3);
80290075Sobrien  if (!ce_out || *ce_out == '\0')
80390075Sobrien    return insn_out;
80490075Sobrien
80590075Sobrien  ce_len = strlen (ce_out);
80690075Sobrien  insn_len = strlen (insn_out);
80790075Sobrien
80890075Sobrien  if (*insn_out == '*')
80990075Sobrien    /* You must take care of the predicate yourself.  */
81090075Sobrien    return insn_out;
81190075Sobrien
81290075Sobrien  if (*insn_out == '@')
81390075Sobrien    {
81490075Sobrien      len = (ce_len + 1) * alt + insn_len + 1;
81590075Sobrien      p = new = xmalloc (len);
81690075Sobrien
81790075Sobrien      do
81890075Sobrien	{
81990075Sobrien	  do
82090075Sobrien	    *p++ = *insn_out++;
82190075Sobrien	  while (ISSPACE ((unsigned char) *insn_out));
82290075Sobrien
82390075Sobrien	  if (*insn_out != '#')
82490075Sobrien	    {
82590075Sobrien	      p = shift_output_template (p, ce_out, max_op);
82690075Sobrien	      *p++ = ' ';
82790075Sobrien	    }
82890075Sobrien
82990075Sobrien	  do
83090075Sobrien	    *p++ = *insn_out++;
83190075Sobrien	  while (*insn_out && *insn_out != '\n');
83290075Sobrien	}
83390075Sobrien      while (*insn_out);
83490075Sobrien      *p = '\0';
83590075Sobrien    }
83690075Sobrien  else
83790075Sobrien    {
83890075Sobrien      len = ce_len + 1 + insn_len + 1;
83990075Sobrien      new = xmalloc (len);
84090075Sobrien
84190075Sobrien      p = shift_output_template (new, ce_out, max_op);
84290075Sobrien      *p++ = ' ';
84390075Sobrien      memcpy (p, insn_out, insn_len + 1);
84490075Sobrien    }
84590075Sobrien
84690075Sobrien  return new;
84790075Sobrien}
84890075Sobrien
84990075Sobrien/* Replicate insns as appropriate for the given DEFINE_COND_EXEC.  */
85090075Sobrien
85190075Sobrienstatic void
85290075Sobrienprocess_one_cond_exec (ce_elem)
85390075Sobrien     struct queue_elem *ce_elem;
85490075Sobrien{
85590075Sobrien  struct queue_elem *insn_elem;
85690075Sobrien  for (insn_elem = define_insn_queue; insn_elem ; insn_elem = insn_elem->next)
85790075Sobrien    {
85890075Sobrien      int alternatives, max_operand;
85990075Sobrien      rtx pred, insn, pattern;
86090075Sobrien
86190075Sobrien      if (! is_predicable (insn_elem))
86290075Sobrien	continue;
86390075Sobrien
86490075Sobrien      alternatives = 1;
86590075Sobrien      max_operand = -1;
86690075Sobrien      collect_insn_data (insn_elem->data, &alternatives, &max_operand);
86790075Sobrien      max_operand += 1;
86890075Sobrien
86990075Sobrien      if (XVECLEN (ce_elem->data, 0) != 1)
87090075Sobrien	{
87190075Sobrien	  message_with_line (ce_elem->lineno,
87290075Sobrien			     "too many patterns in predicate");
87390075Sobrien	  errors = 1;
87490075Sobrien	  return;
87590075Sobrien	}
87690075Sobrien
87790075Sobrien      pred = copy_rtx (XVECEXP (ce_elem->data, 0, 0));
87890075Sobrien      pred = alter_predicate_for_insn (pred, alternatives, max_operand,
87990075Sobrien				       ce_elem->lineno);
88090075Sobrien      if (pred == NULL)
88190075Sobrien	return;
88290075Sobrien
88390075Sobrien      /* Construct a new pattern for the new insn.  */
88490075Sobrien      insn = copy_rtx (insn_elem->data);
88590075Sobrien      XSTR (insn, 0) = "";
88690075Sobrien      pattern = rtx_alloc (COND_EXEC);
88790075Sobrien      XEXP (pattern, 0) = pred;
88890075Sobrien      if (XVECLEN (insn, 1) == 1)
88990075Sobrien	{
89090075Sobrien	  XEXP (pattern, 1) = XVECEXP (insn, 1, 0);
89190075Sobrien	  XVECEXP (insn, 1, 0) = pattern;
89290075Sobrien	  PUT_NUM_ELEM (XVEC (insn, 1), 1);
89390075Sobrien	}
89490075Sobrien      else
89590075Sobrien	{
89690075Sobrien	  XEXP (pattern, 1) = rtx_alloc (PARALLEL);
89790075Sobrien	  XVEC (XEXP (pattern, 1), 0) = XVEC (insn, 1);
89890075Sobrien	  XVEC (insn, 1) = rtvec_alloc (1);
89990075Sobrien	  XVECEXP (insn, 1, 0) = pattern;
90090075Sobrien	}
90190075Sobrien
90290075Sobrien      XSTR (insn, 2) = alter_test_for_insn (ce_elem, insn_elem);
90390075Sobrien      XTMPL (insn, 3) = alter_output_for_insn (ce_elem, insn_elem,
90490075Sobrien					      alternatives, max_operand);
90590075Sobrien
90690075Sobrien      /* ??? Set `predicable' to false.  Not crucial since it's really
90790075Sobrien         only used here, and we won't reprocess this new pattern.  */
90890075Sobrien
90990075Sobrien      /* Put the new pattern on the `other' list so that it
91090075Sobrien	 (a) is not reprocessed by other define_cond_exec patterns
91190075Sobrien	 (b) appears after all normal define_insn patterns.
91290075Sobrien
91390075Sobrien	 ??? B is debatable.  If one has normal insns that match
91490075Sobrien	 cond_exec patterns, they will be preferred over these
91590075Sobrien	 generated patterns.  Whether this matters in practice, or if
91690075Sobrien	 it's a good thing, or whether we should thread these new
91790075Sobrien	 patterns into the define_insn chain just after their generator
91890075Sobrien	 is something we'll have to experiment with.  */
91990075Sobrien
92090075Sobrien      queue_pattern (insn, &other_tail, insn_elem->lineno);
92190075Sobrien    }
92290075Sobrien}
92390075Sobrien
92490075Sobrien/* If we have any DEFINE_COND_EXEC patterns, expand the DEFINE_INSN
92590075Sobrien   patterns appropriately.  */
92690075Sobrien
92790075Sobrienstatic void
92890075Sobrienprocess_define_cond_exec ()
92990075Sobrien{
93090075Sobrien  struct queue_elem *elem;
93190075Sobrien
93290075Sobrien  identify_predicable_attribute ();
93390075Sobrien  if (errors)
93490075Sobrien    return;
93590075Sobrien
93690075Sobrien  for (elem = define_cond_exec_queue; elem ; elem = elem->next)
93790075Sobrien    process_one_cond_exec (elem);
93890075Sobrien}
93990075Sobrien
94090075Sobrienstatic char *
94190075Sobriensave_string (s, len)
94290075Sobrien     const char *s;
94390075Sobrien     int len;
94490075Sobrien{
94590075Sobrien  register char *result = xmalloc (len + 1);
94690075Sobrien
94790075Sobrien  memcpy (result, s, len);
94890075Sobrien  result[len] = 0;
94990075Sobrien  return result;
95090075Sobrien}
95190075Sobrien
95290075Sobrien
95390075Sobrien/* The entry point for initializing the reader.  */
95490075Sobrien
95590075Sobrienint
95690075Sobrieninit_md_reader_args (argc, argv)
95790075Sobrien     int argc;
95890075Sobrien     char **argv;
95990075Sobrien{
96090075Sobrien  int i;
96190075Sobrien  const char *in_fname;
96290075Sobrien
96390075Sobrien  max_include_len = 0;
96490075Sobrien  in_fname = NULL;
96590075Sobrien  for (i = 1; i < argc; i++)
96690075Sobrien    {
96790075Sobrien      if (argv[i][0] != '-')
96890075Sobrien	{
96990075Sobrien	  if (in_fname == NULL)
97090075Sobrien	    in_fname = argv[i];
97190075Sobrien	}
97290075Sobrien      else
97390075Sobrien	{
97490075Sobrien	  int c = argv[i][1];
97590075Sobrien	  switch (c)
97690075Sobrien	    {
97790075Sobrien	    case 'I':		/* Add directory to path for includes.  */
97890075Sobrien	      {
97990075Sobrien		struct file_name_list *dirtmp;
98090075Sobrien
98190075Sobrien		dirtmp = (struct file_name_list *)
98290075Sobrien		  xmalloc (sizeof (struct file_name_list));
98390075Sobrien		dirtmp->next = 0;	/* New one goes on the end */
98490075Sobrien		if (include == 0)
98590075Sobrien		  include = dirtmp;
98690075Sobrien		else
98790075Sobrien		  last_include->next = dirtmp;
98890075Sobrien		last_include = dirtmp;	/* Tail follows the last one */
98990075Sobrien		if (argv[i][1] == 'I' && argv[i][2] != 0)
99090075Sobrien		  dirtmp->fname = argv[i] + 2;
99190075Sobrien		else if (i + 1 == argc)
99290075Sobrien		  fatal ("directory name missing after -I option");
99390075Sobrien		else
99490075Sobrien		  dirtmp->fname = argv[++i];
99590075Sobrien		if (strlen (dirtmp->fname) > max_include_len)
99690075Sobrien		  max_include_len = strlen (dirtmp->fname);
99790075Sobrien	      }
99890075Sobrien	      break;
99990075Sobrien	    default:
100090075Sobrien	      fatal ("invalid option `%s'", argv[i]);
100190075Sobrien
100290075Sobrien	    }
100390075Sobrien	}
100490075Sobrien    }
100590075Sobrien    return init_md_reader (in_fname);
100690075Sobrien}
100790075Sobrien
100890075Sobrien/* The entry point for initializing the reader.  */
100990075Sobrien
101090075Sobrienint
101190075Sobrieninit_md_reader (filename)
101290075Sobrien     const char *filename;
101390075Sobrien{
101490075Sobrien  FILE *input_file;
101590075Sobrien  int c;
101690075Sobrien  char *lastsl;
101790075Sobrien
101890075Sobrien  if (!IS_ABSOLUTE_PATHNAME (filename))
101990075Sobrien    {
102090075Sobrien      lastsl = strrchr (filename, '/');
102190075Sobrien      if (lastsl != NULL)
102290075Sobrien	base_dir = save_string (filename, lastsl - filename + 1 );
102390075Sobrien    }
102490075Sobrien
102590075Sobrien  read_rtx_filename = filename;
102690075Sobrien  input_file = fopen (filename, "r");
102790075Sobrien  if (input_file == 0)
102890075Sobrien    {
102990075Sobrien      perror (filename);
103090075Sobrien      return FATAL_EXIT_CODE;
103190075Sobrien    }
103290075Sobrien
103390075Sobrien  obstack_init (rtl_obstack);
103490075Sobrien  errors = 0;
103590075Sobrien  sequence_num = 0;
103690075Sobrien
103790075Sobrien  /* Read the entire file.  */
103890075Sobrien  while (1)
103990075Sobrien    {
104090075Sobrien      rtx desc;
104190075Sobrien      int lineno;
104290075Sobrien
104390075Sobrien      c = read_skip_spaces (input_file);
104490075Sobrien      if (c == EOF)
104590075Sobrien        break;
104690075Sobrien
104790075Sobrien      ungetc (c, input_file);
104890075Sobrien      lineno = read_rtx_lineno;
104990075Sobrien      desc = read_rtx (input_file);
105090075Sobrien      process_rtx (desc, lineno);
105190075Sobrien    }
105290075Sobrien  fclose (input_file);
105390075Sobrien
105490075Sobrien  /* Process define_cond_exec patterns.  */
105590075Sobrien  if (define_cond_exec_queue != NULL)
105690075Sobrien    process_define_cond_exec ();
105790075Sobrien
105890075Sobrien  return errors ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
105990075Sobrien}
106090075Sobrien
106190075Sobrien/* The entry point for reading a single rtx from an md file.  */
106290075Sobrien
106390075Sobrienrtx
106490075Sobrienread_md_rtx (lineno, seqnr)
106590075Sobrien     int *lineno;
106690075Sobrien     int *seqnr;
106790075Sobrien{
106890075Sobrien  struct queue_elem **queue, *elem;
106990075Sobrien  rtx desc;
107090075Sobrien
107190075Sobrien  /* Read all patterns from a given queue before moving on to the next.  */
107290075Sobrien  if (define_attr_queue != NULL)
107390075Sobrien    queue = &define_attr_queue;
107490075Sobrien  else if (define_insn_queue != NULL)
107590075Sobrien    queue = &define_insn_queue;
107690075Sobrien  else if (other_queue != NULL)
107790075Sobrien    queue = &other_queue;
107890075Sobrien  else
107990075Sobrien    return NULL_RTX;
108090075Sobrien
108190075Sobrien  elem = *queue;
108290075Sobrien  *queue = elem->next;
108390075Sobrien  desc = elem->data;
108490075Sobrien  *lineno = elem->lineno;
108590075Sobrien  *seqnr = sequence_num;
108690075Sobrien
108790075Sobrien  free (elem);
108890075Sobrien
108990075Sobrien  switch (GET_CODE (desc))
109090075Sobrien    {
109190075Sobrien    case DEFINE_INSN:
109290075Sobrien    case DEFINE_EXPAND:
109390075Sobrien    case DEFINE_SPLIT:
109490075Sobrien    case DEFINE_PEEPHOLE:
109590075Sobrien    case DEFINE_PEEPHOLE2:
109690075Sobrien      sequence_num++;
109790075Sobrien      break;
109890075Sobrien
109990075Sobrien    default:
110090075Sobrien      break;
110190075Sobrien    }
110290075Sobrien
110390075Sobrien  return desc;
110490075Sobrien}
1105